diff --git a/.eslintrc.cjs b/.eslintrc.cjs index a1c7160..c481452 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,13 +3,19 @@ module.exports = { extends: ['@block65/eslint-config', '@block65/eslint-config/react'], parserOptions: { + ecmaVersion: 2022, + tsconfigRootDir: __dirname, - project: ['./tsconfig.json', './tsconfig-node.json'], + project: [ + './tsconfig.eslint.json', + // './tsconfig.node.json', + // './tsconfig.examples.json', + ], }, overrides: [ { - files: ['**/*.css.ts', 'src/**/*.tsx', 'src/**/*.ts'], + files: ['lib/**/*.css.ts'], rules: { 'import/no-extraneous-dependencies': [ 'error', @@ -19,5 +25,24 @@ module.exports = { '@typescript-eslint/no-import-type-side-effects': 'error', }, }, + { + files: ['bin/*.js', '*.config.*'], + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + { devDependencies: true }, + ], + }, + }, + { + files: ['src/**/*.tsx', 'src/**/*.ts', 'lib/**/*.tsx', 'lib/**/*.ts'], + rules: { + 'import/no-extraneous-dependencies': [ + 'error', + { devDependencies: true }, + ], + '@typescript-eslint/no-import-type-side-effects': 'error', + }, + }, ], }; diff --git a/.gitignore b/.gitignore index 6b14811..5c14b55 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,4 @@ dist build coverage -bin/*.js -bin/*.js -vite.config.js +*.tsbuildinfo diff --git a/CREDITS.md b/CREDITS.md new file mode 100644 index 0000000..e75f494 --- /dev/null +++ b/CREDITS.md @@ -0,0 +1,13 @@ +## Capsize SCSS + +MIT: https://github.com/seek-oss/capsize/blob/9d10414aa0597bb24101408b0b24c22d2ec58969/LICENSE + +@AndrewLeedham via https://github.com/seek-oss/capsize + +https://github.com/seek-oss/capsize/issues/24#issuecomment-679998850 + +## open-props-scss + +MIT: https://github.com/mayank99/open-props-scss/blob/ddd1275c3ee55a31a7759ddd5b88703174987d56/LICENSE + +https://github.com/mayank99/open-props-scss diff --git a/Makefile b/Makefile index 9b1163b..62fdefb 100644 --- a/Makefile +++ b/Makefile @@ -1,42 +1,63 @@ SRCS = $(wildcard lib/**) +.DEFAULT_GOAL := all + .PHONY: all -all: build +all: build dist build/global.scss build/global.css node_modules: package.json pnpm-lock.yaml pnpm install touch $@ -bin/token.js: meta-bundle tsconfig-node.json - pnpm exec tsc -p tsconfig-node.json +dist/bin/token.js: build bin/token.ts ${SRCS} + pnpm exec tsc -b + +build/global.css: dist/bin/token.js + node dist/bin/token.js -t css > $@ + +build/global.scss: dist/bin/token.js + node dist/bin/token.js -t scss > $@ -build/tokens.scss: bin/token.js meta-bundle +tsconfig.json: tsconfig-vite.src.json + pnpm exec tsc -p tsconfig-vite.src.json --showConfig 1> $@ + +src/rds.module.scss: bin/token.js build node $< > $@ - pnpm exec tsc -b tsconfig-node.json --clean + prettier --write $@ + +build: $(SRCS) node_modules vite.config.ts vite-env.d.ts + NODE_ENV=production pnpm exec vite build + touch $@ + +.PHONY: build-watch +build-watch: $(SRCS) node_modules vite.config.ts vite-env.d.ts + pnpm exec vite build --mode=development --clearScreen false + touch -c build -.PHONY: meta-bundle -meta-bundle: $(SRCS) node_modules vite.config.ts types - NODE_ENV=production pnpm vite build - touch build +.PHONY: dev-server +dev-server: node_modules vite.config.ts + pnpm exec vite dev --mode=development --clearScreen false -build: meta-bundle build/tokens.scss +PHONY: typecheck +typecheck: node_modules tsconfig.json + pnpm exec tsc -w --preserveWatchOutput +.PHONY: dev +dev: + NODE_ENV=development $(MAKE) -j 3 build-watch dev-server typecheck + +.PHONY: debug debug: DEBUG_BUILD=1 $(MAKE) -.PHONY: types -types: node_modules tsconfig.json - pnpm exec tsc --emitDeclarationOnly - -.PHONY: types-watch -types-watch: node_modules tsconfig.json - pnpm exec tsc --emitDeclarationOnly -w +dist: node_modules tsconfig.json + pnpm exec tsc .PHONY: clean clean: node_modules tsconfig.json pnpm exec tsc -b --clean - pnpm exec tsc -b tsconfig-node.json --clean + pnpm exec tsc -b tsconfig.node.json --clean rm -rf build dist .PHONY: clean @@ -44,30 +65,17 @@ distclean: clean rm -rf node_modules .PHONY: test -test: node_modules tsconfig.json vite.config.ts - $(MAKE) lint - pnpm exec tsc --noEmit +test: lint dist build DEBUG_BUILD=true pnpm vitest run - $(MAKE) build - pnpm bundlesize - -.PHONY: dev -dev: - $(MAKE) -j 2 types-watch dev-server - -.PHONY: dev-server -dev-server: node_modules vite.config.ts - pnpm vite dev + DEBUG_BUILD=true pnpm vitest run + pnpm exec bundlesize .PHONY: lint lint: node_modules - pnpm eslint . - pnpm prettier --check . + pnpm exec eslint . + pnpm exec prettier --check . .PHONY: pretty pretty: node_modules - pnpm eslint --fix . - pnpm prettier --write . - -tsconfig.json: tsconfig-vite.src.json - pnpm exec tsc -p tsconfig-vite.src.json --showConfig > $@ \ No newline at end of file + pnpm exec eslint --fix . + pnpm exec prettier --write . diff --git a/bin/token.ts b/bin/token.ts index 504781c..d24e0ad 100644 --- a/bin/token.ts +++ b/bin/token.ts @@ -1,38 +1,182 @@ -// eslint-disable-next-line import/no-extraneous-dependencies +/* eslint-disable import/no-extraneous-dependencies */ +/* eslint-disable no-restricted-syntax */ +import { createWriteStream } from 'node:fs'; +import { PassThrough } from 'node:stream'; +import { parseArgs } from 'node:util'; import { camelCase } from 'change-case'; -import { genericVars } from '#vars'; +import { leafNodeMapper, type PathStr, type VarFn, vargEx } from './utils.js'; +import { + badgeVars, + badgeVarsMapFnPrefix, + buttonVars, + buttonVarsMapFnPrefix, + formControlTokens, + formControlVarsMapFnPrefix, + globalTokens, + globalVars, + globalVarsMapFnPrefix, + panelTokens, + panelVars, + panelVarsMapFnPrefix, + propsTokens, + propsVars, + propsVarsMapFnPrefix, +} from '#vars'; -function isPlainObject(obj: unknown): obj is Record { - return ( - typeof obj === 'object' && - obj !== null && - Object.getPrototypeOf(obj) === Object.prototype +const { + values: { type, outputPath }, +} = parseArgs({ + options: { + type: { + type: 'string', + short: 't', + default: 'css', + }, + outputPath: { + type: 'string', + short: 'o', + }, + }, +}); +/** + * vars + */ +const knownVars = new Map(); +for (const [vars, prefix] of [ + [globalVars, globalVarsMapFnPrefix] as const, + [propsVars, propsVarsMapFnPrefix] as const, + [panelVars, panelVarsMapFnPrefix] as const, + [badgeVars, badgeVarsMapFnPrefix] as const, + [buttonVars, buttonVarsMapFnPrefix] as const, +]) { + leafNodeMapper( + vars, + (path, value) => { + knownVars.set(value, { path }); + }, + [prefix], ); } -function extractCustomPropertyNames( - obj: Record, - prefix = '', -): [string, string][] { - return Object.entries(obj).flatMap(([key, value]): [string, string][] => { - const k = prefix ? `${prefix}${key}` : key; +/** + * tokens + */ +const knownTokens = new Map(); - if (isPlainObject(value)) { - return extractCustomPropertyNames(value, `${k}-`); - } +for (const [vars, prefix] of [ + [globalTokens, globalVarsMapFnPrefix] as const, + [propsTokens, propsVarsMapFnPrefix] as const, + [panelTokens, panelVarsMapFnPrefix] as const, + [formControlTokens, formControlVarsMapFnPrefix] as const, +]) { + leafNodeMapper( + vars, + (path, value) => { + knownTokens.set(path, { value }); + }, + [prefix], + ); +} + +// resolved tokens, in case they have vars that reference each other +for (const [varName, { value }] of knownTokens) { + if (value.match(vargEx)) { + const cssVar = knownVars.get(value); + + if (cssVar) { + // get the value of the css var + const token = knownTokens.get(cssVar.path); - const v = String(value); - return [[k, v.match(/^var\((--\w+)\)$/)?.[1] || v]]; - }); + if (token) { + knownTokens.set(varName, token); + } + } + } } -function writeScss([v, ident]: [string, string]) { - process.stdout.write(`$${camelCase(v)}: ${ident};`); - process.stdout.write('\n'); +const output = new PassThrough(); +if (outputPath) { + output.pipe(createWriteStream(outputPath)); +} else { + output.pipe(process.stdout); } -const propNames = extractCustomPropertyNames({ - ...genericVars, -}); +const autoGeneratedBanner = [ + 'This file is auto-generated.', + '', + 'Do not edit this file directly.', + '', + `Date: ${new Date().toISOString()} by ${process.env.USER}`, +]; + +output.write(`/* + * ${autoGeneratedBanner.join('\n * ')} +*/\n`); + +/** + * Output + * */ +switch (type) { + case 'scss': { + const defaults: string[] = []; + const definitions: string[] = []; + + for (const [varFn, { path }] of knownVars) { + const tokenValue = knownTokens.get(path); + + if (tokenValue) { + const [, varName] = varFn.match(vargEx) || []; + + if (!varName) { + throw new Error(`Could not extract var name from ${varFn}`); + } + const scssVar = camelCase(varName, { + mergeAmbiguousCharacters: true, + }); + + // output.write(` $${scssVar}: ${tokenValue.value} !default;\n`); + // output.write(` --${varName}: #{$${scssVar}};\n\n`); + + defaults.push(`$${scssVar}: ${tokenValue.value} !default;`); + definitions.push(`--${varName}: #{$${scssVar}};`); + } else { + output.write( + `\n/* WARN: skipped ${varFn} as token path "${path}" is not known */\n`, + ); + } + } + + output.write(defaults.join('\n')); + output.write('\n'); + output.write(`@mixin tokens($args...) {\n`); + output.write(definitions.map((d) => ` ${d}`).join('\n')); + output.write('\n'); + output.write(`}\n`); + break; + } + case 'css': + default: + output.write(`:root {\n`); + + for (const [varFn, { path }] of knownVars) { + const tokenValue = knownTokens.get(path); + + if (tokenValue) { + const [, varName] = varFn.match(vargEx) || []; + + if (!varName) { + throw new Error(`Could not extract var name from ${varFn}`); + } + + output.write(`--${varName}: ${tokenValue.value};\n`); + } else { + output.write( + `\n/* WARN: skipped ${varFn} as token path "${path}" is not known */\n`, + ); + } + } + output.write(`}\n`); + break; +} -propNames.forEach(writeScss); +output.end(); diff --git a/bin/utils.ts b/bin/utils.ts new file mode 100644 index 0000000..de6b714 --- /dev/null +++ b/bin/utils.ts @@ -0,0 +1,34 @@ +/* eslint-disable no-restricted-syntax */ +export type RecursiveStringStringObj = { + [Key in string]: string | RecursiveStringStringObj; +}; + +export type VarFn = string; +export type PathPart = string; +export type PathParts = PathPart[]; +export type PathStr = PathPart | `${PathPart}.${PathPart}`; + +function pathToString(parts: PathParts) { + return parts + .filter((part, idx) => !(part === '' && idx === 0)) + .join('.') as PathStr; +} + +// extract the var names from the leaf nodes of panelVars +// and add them to the knownVars map +export function leafNodeMapper( + obj: RecursiveStringStringObj, + callback: (path: PathStr, value: string) => void, + pathParts: string[] = [], +) { + for (const [key, value] of Object.entries(obj)) { + const thisPath = [...pathParts, key]; + if (typeof value === 'string') { + callback(pathToString(thisPath), value); + } else { + leafNodeMapper(value, callback, thisPath); + } + } +} + +export const vargEx = /var\(--(.*)\)/; diff --git a/index.html b/index.html index 33b2cac..18a4bc8 100644 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ @@ -16,14 +16,6 @@ diff --git a/lib/avatar.css.ts b/lib/avatar.css.ts index 16c0bfe..d6d007f 100644 --- a/lib/avatar.css.ts +++ b/lib/avatar.css.ts @@ -1,12 +1,10 @@ import { style } from '@vanilla-extract/css'; -import { calc } from '@vanilla-extract/css-utils'; -import { currentCapHeight } from './typography.css.js'; export const avatarClassName = style({ display: 'inline-grid', aspectRatio: '1/1', - width: calc.multiply(currentCapHeight, 4), - height: calc.multiply(currentCapHeight, 4), + width: '4em', + height: '4em', placeItems: 'center', textTransform: 'uppercase', }); diff --git a/lib/avatar.tsx b/lib/avatar.tsx index 650b26b..a33d795 100644 --- a/lib/avatar.tsx +++ b/lib/avatar.tsx @@ -1,20 +1,17 @@ import { avatarClassName, avatarImgClass } from './avatar.css.js'; -import type { Falsy } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; -import { capSizeVariantVars, type FontSize } from './typography.css.js'; +import { Box, type BoxProps } from './box.js'; +import type { ReactHTMLElementsHacked, Falsy } from './types.js'; +import type { FontSize } from './typography.js'; -type CommonAvatarProps = { +export type CommonAvatarProps = { label?: string | Falsy; ident?: string | Falsy; size?: FontSize | Falsy; image?: string | Falsy; }; -export type AvatarProps = Merge< - BoxProps, - CommonAvatarProps ->; +export type AvatarProps = BoxProps & + CommonAvatarProps; function extractInitials(text: string): string { // if its an email address, strip off the domain @@ -41,8 +38,8 @@ export const Avatar = ({ {image ? ( [ + badgeClassName, + { + color: v.fgColor, + backgroundColor: v.bgColor, + borderColor: fallbackVar(v.borderColor, v.bgColor), + }, +]); diff --git a/lib/badges.css.ts b/lib/badges.css.ts deleted file mode 100644 index 5c93199..0000000 --- a/lib/badges.css.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { style } from '@vanilla-extract/css'; - -export const badgeClassName = style({ - textTransform: 'uppercase', -}); diff --git a/lib/badges.tsx b/lib/badges.tsx index f002500..c9047d1 100644 --- a/lib/badges.tsx +++ b/lib/badges.tsx @@ -1,45 +1,40 @@ -import { - forwardRef, - type FC, - type ForwardedRef, - type PropsWithChildren, -} from 'react'; -import { badgeClassName } from './badges.css.js'; -import type { BoxProps } from './core.js'; +import { forwardRef, type ForwardedRef } from 'react'; +import { badgeVariantClassNames } from './badge.css.js'; +import { Box } from './box.js'; import { useStringLikeDetector } from './hooks/use-string-like.js'; -import { Inline, type InlineProps } from './layout.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; -import { Text } from './typography.js'; +import { Inline, type FlexProps } from './layout.js'; +import type { PurposeVariant } from './purpose.css.js'; +import type { Falsy, ReactHTMLElementsHacked } from './types.js'; export type BadgeProps = - PropsWithChildren>; + FlexProps & { variant?: PurposeVariant | Falsy }; export const Badge = forwardRef( ( - { className, children, ...props }: BadgeProps, + { children, variant = 'default', className, ...props }: BadgeProps, forwardedRef: ForwardedRef, ) => { const isStringLike = useStringLikeDetector(); return ( {isStringLike(children) ? ( - {children} - + ) : ( children )} @@ -47,12 +42,3 @@ export const Badge = forwardRef( ); }, ); - -type BadgeLinkProps = { - component?: never; - href?: string; -}; - -export const BadgeLink: FC, BadgeLinkProps>> = ( - props, -) => ; diff --git a/lib/core.css.ts b/lib/box.css.ts similarity index 76% rename from lib/core.css.ts rename to lib/box.css.ts index 5e04386..4501df0 100644 --- a/lib/core.css.ts +++ b/lib/box.css.ts @@ -1,12 +1,11 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { style, styleVariants, type ComplexStyleRule, type StyleRule, } from '@vanilla-extract/css'; -import { genericVars } from './design-system.css.js'; import { typedObjectEntries, typedObjectFromEntries } from './utils.js'; +import { propsVars } from './vars.css.js'; export type Viewport = 'mobile' | 'tablet' | 'desktop' | 'wide' | 'all'; @@ -16,20 +15,16 @@ export type Responsive = Partial<{ export type OrResponsive = T | Responsive; -// accepting null means we can skip default assignments and specifically -// disable when consuming -export type Falsy = false | null | undefined; - export type Rounded = '0' | '1' | '2' | '3' | '50'; -export const roundedVariants = styleVariants(genericVars.radius, (v) => [ +export const roundedVariants = styleVariants(propsVars.radius, (v) => [ { borderRadius: v, }, ]); export const roundedStartStartVariants = styleVariants( - genericVars.radius, + propsVars.radius, (v) => [ { borderStartStartRadius: v, @@ -37,25 +32,19 @@ export const roundedStartStartVariants = styleVariants( ], ); -export const roundedStartEndVariants = styleVariants( - genericVars.radius, - (v) => [ - { - borderStartEndRadius: v, - }, - ], -); +export const roundedStartEndVariants = styleVariants(propsVars.radius, (v) => [ + { + borderStartEndRadius: v, + }, +]); -export const roundedEndStartVariants = styleVariants( - genericVars.radius, - (v) => [ - { - borderEndStartRadius: v, - }, - ], -); +export const roundedEndStartVariants = styleVariants(propsVars.radius, (v) => [ + { + borderEndStartRadius: v, + }, +]); -export const roundedEndEndVariants = styleVariants(genericVars.radius, (v) => [ +export const roundedEndEndVariants = styleVariants(propsVars.radius, (v) => [ { borderEndEndRadius: v, }, @@ -96,7 +85,7 @@ export type Space = | '14' | '15'; -export const marginVariants = styleVariants(genericVars.space, (space) => [ +export const marginVariants = styleVariants(propsVars.space, (space) => [ { margin: space, }, @@ -158,42 +147,42 @@ function viewportStyleVariants< } export const viewportMarginVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ margin: space, }), ); export const viewportMarginInlineVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ marginInline: space, }), ); export const viewportMarginBlockVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ marginBlock: space, }), ); export const viewportPaddingVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ padding: space, }), ); export const viewportPaddingInlineVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ paddingInline: space, }), ); export const viewportPaddingBlockVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ paddingBlock: space, }), @@ -208,35 +197,29 @@ export const viewportFlexDirectionVariants = viewportStyleVariants( ); export const marginInlineVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ marginInline: space, }), ); -export const paddingVariants = styleVariants(genericVars.space, (space) => [ +export const paddingVariants = styleVariants(propsVars.space, (space) => [ { padding: space, }, ]); -export const paddingBlockVariants = styleVariants( - genericVars.space, - (space) => [ - { - paddingBlock: space, - }, - ], -); +export const paddingBlockVariants = styleVariants(propsVars.space, (space) => [ + { + paddingBlock: space, + }, +]); -export const paddingInlineVariants = styleVariants( - genericVars.space, - (space) => [ - { - paddingInline: space, - }, - ], -); +export const paddingInlineVariants = styleVariants(propsVars.space, (space) => [ + { + paddingInline: space, + }, +]); export type Overflow = 'hidden' | 'scroll'; @@ -292,12 +275,34 @@ export const flexDirectionVariants = styleVariants( (props) => props, ); -export const spaceVariants = styleVariants(genericVars.space, (space) => ({ +export const flexGrowClassName = styleVariants< + Record<`${boolean}`, ComplexStyleRule> +>({ + true: { flexGrow: 1 }, + false: { flexGrow: 0 }, +}); + +export const flexShrinkClass = styleVariants< + Record<`${boolean}`, ComplexStyleRule> +>({ + true: { flexShrink: 1 }, + false: { flexShrink: 0 }, +}); + +export type Wrap = 'wrap' | 'nowrap' | 'wrapReverse'; + +export const flexWrapVariants = styleVariants>({ + wrap: { flexWrap: 'wrap' }, + nowrap: { flexWrap: 'nowrap' }, + wrapReverse: { flexWrap: 'wrap-reverse' }, +}); + +export const spaceVariants = styleVariants(propsVars.space, (space) => ({ gap: space, })); export const viewportSpaceVariants = viewportStyleVariants( - genericVars.space, + propsVars.space, (space) => ({ gap: space, }), @@ -330,7 +335,7 @@ const borderBaseClass = style({ }); export const borderWidthVariants = styleVariants( - genericVars.border.width, + propsVars.border.width, (space) => [ borderBaseClass, { @@ -341,5 +346,5 @@ export const borderWidthVariants = styleVariants( // this must be defined after other display styles so that it takes precedence export const hiddenClass = style({ - display: 'none', + display: 'none!important', }); diff --git a/lib/box.tsx b/lib/box.tsx new file mode 100644 index 0000000..6cfb753 --- /dev/null +++ b/lib/box.tsx @@ -0,0 +1,312 @@ +import type { Placement } from '@floating-ui/dom'; +import { clsx, type ClassValue } from 'clsx'; +import { + Suspense, + createElement, + forwardRef, + type ForwardedRef, + type ReactNode, +} from 'react'; +import { + borderWidthVariants, + flexDirectionVariants, + hiddenClass, + overflowVariants, + roundedEndEndVariants, + roundedEndStartVariants, + roundedStartEndVariants, + roundedStartStartVariants, + roundedVariants, + textAlignVariants, + textOverflowVariants, + viewportFlexDirectionVariants, + viewportMarginBlockVariants, + viewportMarginInlineVariants, + viewportMarginVariants, + viewportPaddingBlockVariants, + viewportPaddingInlineVariants, + viewportPaddingVariants, + viewportSpaceVariants, + type BorderWidth, + type FlexDirection, + type OrResponsive, + type Overflow, + type Rounded, + type Space, + type TextAlign, + type TextOverflow, + flexGrowClassName, + flexShrinkClass, + flexWrapVariants, + type Wrap, +} from './box.css.js'; +import { isNotFalsy, matchViewportVariants } from './component-utils.js'; +import { TooltipLazy } from './tooltip-lazy.js'; +import type { TooltipProps } from './tooltip.js'; +import type { + Falsy, + Merge, + ReactHTMLAttributesHacked, + ReactHTMLElementsHacked, +} from './types.js'; +import { + capSizeVariantClassNames, + fontSizeVariantClassNames, + fontWeightVariantClassNames, + lineHeightVariantClassNames, + type FontSize, + type FontWeight, + type LineHeight, + type TextWrap, +} from './typography.css.js'; + +export type BoxProps = Merge< + ReactHTMLAttributesHacked[T], + { + className?: ClassValue; + component?: T | undefined; + + space?: OrResponsive | Falsy; + flexDirection?: OrResponsive | Falsy; + flexGrow?: OrResponsive | Falsy; + flexShrink?: OrResponsive | Falsy; + flexWrap?: Wrap | true | Falsy; + + margin?: OrResponsive | Falsy; + marginBlock?: OrResponsive | Falsy; + marginInline?: OrResponsive | Falsy; + + padding?: OrResponsive | Falsy; + paddingBlock?: OrResponsive | Falsy; + paddingInline?: OrResponsive | Falsy; + + tooltip?: ReactNode; + tooltipInitialPlacement?: Placement | Falsy; + + textAlign?: TextAlign | Falsy; + textOverflow?: TextOverflow | Falsy; + + fontSize?: FontSize | Falsy; + capSize?: FontSize | Falsy; + fontWeight?: FontWeight | Falsy; + lineHeight?: LineHeight | Falsy; + textWrap?: TextWrap | Falsy; + + overflow?: Overflow | Falsy; + + rounded?: Rounded | Falsy; + roundedStart?: Rounded | Falsy; + roundedStartStart?: Rounded | Falsy; + roundedStartEnd?: Rounded | Falsy; + roundedEnd?: Rounded | Falsy; + roundedEndStart?: Rounded | Falsy; + roundedEndEnd?: Rounded | Falsy; + + borderWidth?: BorderWidth | Falsy; + } +>; + +function getCapSizeClassName(size: FontSize | Falsy) { + return size && capSizeVariantClassNames[size]; +} + +function getFontSizeClassName(size: FontSize | Falsy) { + return size && fontSizeVariantClassNames[size]; +} + +function getFontWeightClassName(weight: FontWeight | Falsy) { + return weight && fontWeightVariantClassNames[weight]; +} + +function getLineHeightClassName(height: LineHeight | Falsy) { + return height && lineHeightVariantClassNames[height]; +} + +export const Box = forwardRef( + ( + { + children, + component, + className, + + margin, + marginBlock, + marginInline, + padding, + paddingBlock, + paddingInline, + + textAlign, + textOverflow, + + fontSize, + capSize, + fontWeight, + lineHeight, + textWrap, + + overflow, + + tooltip, + tooltipInitialPlacement, + + rounded, + roundedStart, + roundedStartStart, + roundedStartEnd, + roundedEnd, + roundedEndStart, + roundedEndEnd, + + space, + + flexDirection, + flexGrow, + flexShrink, + flexWrap, + + borderWidth, + + ...props + }: BoxProps, + ref: ForwardedRef, + ) => { + const flexDirectionClass = + flexDirection && + (typeof flexDirection === 'string' + ? flexDirectionVariants[flexDirection] + : matchViewportVariants(flexDirection, viewportFlexDirectionVariants)); + + const spaceClass = + space && + matchViewportVariants( + typeof space === 'string' ? { all: space } : space, + viewportSpaceVariants, + ); + + const el = createElement( + component || 'div', + { + ...props, + className: + clsx( + className, + + spaceClass, + + // we dont extract out the prop, we just force a display none + // so we can keep the element attribute for accessibility? + props.hidden && hiddenClass, + + flexGrow === true && flexGrowClassName.true, + flexGrow === false && flexGrowClassName.false, + + flexShrink === true && flexShrinkClass.true, + flexShrink === false && flexShrinkClass.false, + + flexWrap && flexWrapVariants[flexWrap === true ? 'wrap' : flexWrap], + + isNotFalsy(margin) && + marginBlock !== margin && + matchViewportVariants( + typeof margin === 'string' ? { all: margin } : margin, + viewportMarginVariants, + ), + + isNotFalsy(marginBlock) && + marginBlock !== margin && + matchViewportVariants( + typeof marginBlock === 'string' + ? { all: marginBlock } + : marginBlock, + viewportMarginBlockVariants, + ), + + isNotFalsy(marginInline) && + marginInline !== margin && + matchViewportVariants( + typeof marginInline === 'string' + ? { all: marginInline } + : marginInline, + viewportMarginInlineVariants, + ), + + isNotFalsy(padding) && + matchViewportVariants( + typeof padding === 'string' ? { all: padding } : padding, + viewportPaddingVariants, + ), + + isNotFalsy(paddingBlock) && + paddingBlock !== padding && + matchViewportVariants( + typeof paddingBlock === 'string' + ? { all: paddingBlock } + : paddingBlock, + viewportPaddingBlockVariants, + ), + + isNotFalsy(paddingInline) && + paddingInline !== padding && + matchViewportVariants( + typeof paddingInline === 'string' + ? { all: paddingInline } + : paddingInline, + viewportPaddingInlineVariants, + ), + + textAlign && textAlignVariants[textAlign], + + isNotFalsy(rounded) && roundedVariants[rounded], + + isNotFalsy(roundedStart) && [ + roundedStartStartVariants[roundedStart], + roundedStartEndVariants[roundedStart], + ], + isNotFalsy(roundedEnd) && [ + roundedEndStartVariants[roundedEnd], + roundedEndEndVariants[roundedEnd], + ], + + isNotFalsy(roundedStartStart) && + roundedStartStartVariants[roundedStartStart], + isNotFalsy(roundedStartEnd) && + roundedStartEndVariants[roundedStartEnd], + isNotFalsy(roundedEndStart) && + roundedEndStartVariants[roundedEndStart], + isNotFalsy(roundedEndEnd) && roundedEndEndVariants[roundedEndEnd], + + isNotFalsy(borderWidth) && borderWidthVariants[borderWidth], + + flexDirectionClass, + + overflow && overflowVariants[overflow], + textOverflow && textOverflowVariants[textOverflow], + + getFontSizeClassName(fontSize), + getCapSizeClassName(capSize), + getFontWeightClassName(fontWeight), + getLineHeightClassName(lineHeight), + ) || undefined, + ref, + }, + children, + ); + + if (tooltip) { + const tooltipProps: TooltipProps = { + content: tooltip, + ...(tooltipInitialPlacement && { + initialPlacement: tooltipInitialPlacement, + }), + }; + return ( + + {el} + + ); + } + + return el; + }, +); diff --git a/lib/button.css.ts b/lib/button.css.ts new file mode 100644 index 0000000..d5e5ccc --- /dev/null +++ b/lib/button.css.ts @@ -0,0 +1,129 @@ +import { + createGlobalThemeContract, + style, + styleVariants, +} from '@vanilla-extract/css'; +import { calc } from '@vanilla-extract/css-utils'; +import { createGlobalThemeMapFn } from './css-helpers.js'; +import { typedObjectEntries, typedObjectFromEntries } from './utils.js'; +import { propsVars, globalVars } from './vars.css.js'; + +export type ButtonVariant = + | 'default' + | 'danger' + | 'invisible' + | 'inactive' + | 'primary'; + +export type ButtonState = 'active' | 'disabled' | 'hover' | 'rest'; + +const buttonStateVarsShape = { + active: { bgColor: '', fgColor: '', borderColor: '' }, + disabled: { bgColor: '', fgColor: '', borderColor: '' }, + hover: { bgColor: '', fgColor: '', borderColor: '' }, + rest: { bgColor: '', fgColor: '', borderColor: '' }, +} satisfies Record; + +export const buttonVariantVars = createGlobalThemeContract( + { + default: buttonStateVarsShape, + danger: buttonStateVarsShape, + primary: buttonStateVarsShape, + invisible: buttonStateVarsShape, + inactive: buttonStateVarsShape, + } satisfies Record, + createGlobalThemeMapFn('button'), +); + +export const buttonVariantClassNames = styleVariants( + buttonVariantVars, + (v) => ({ + color: v.rest.fgColor, + backgroundColor: v.rest.bgColor, + borderColor: v.rest.borderColor, + selectors: { + '&:hover': { + color: v.hover.fgColor, + backgroundColor: v.hover.bgColor, + borderColor: v.hover.borderColor, + }, + '&:disabled': { + color: v.disabled.fgColor, + backgroundColor: v.disabled.bgColor, + borderColor: v.disabled.borderColor, + }, + '&:active': { + color: v.active.fgColor, + backgroundColor: v.active.bgColor, + borderColor: v.active.borderColor, + }, + }, + }), +); + +export const buttonStateClassNames = typedObjectFromEntries( + typedObjectEntries(buttonVariantVars).map(([variant, stateVars]) => [ + variant, + styleVariants(stateVars, (state) => ({ + color: state.fgColor, + backgroundColor: state.bgColor, + borderColor: state.borderColor, + })), + ]), +); + +export const buttonClassName = style([ + { + cursor: 'pointer', + userSelect: 'none', + borderRadius: globalVars.border.radius, + borderWidth: globalVars.border.width, + selectors: { + '&[disabled]': { + pointerEvents: 'none', + cursor: 'default', + // filter: 'grayscale(1)', + }, + + // keyboard + '&:focus-visible': { + outlineStyle: 'solid', + outlineOffset: propsVars.border.width['3'], + outlineWidth: propsVars.border.width['3'], + // outlineColor: oklch( + // contrastSchemeVars.swatch.k0.l, + // contrastSchemeVars.swatch.k0.c, + // toneH, + // ), + }, + + // mouse, touch, or stylus + '&:focus:not(:focus-visible)': {}, + + // both + '&:focus-visible,&:focus:not(:focus-visible)': {}, + + // gives us the nice little animation on outlineOffset + '&:active': { + outlineOffset: 0, + }, + }, + }, +]); + +export const iconClass = style({ + aspectRatio: '1/1', + lineHeight: 0, +}); + +export const visiblyHiddenClass = style({ + visibility: 'hidden', +}); + +export const busyButtonClass = style({ + pointerEvents: 'none', +}); + +export const inlineBleedClass = style({ + marginBlock: calc(propsVars.space[0]).negate().toString(), +}); diff --git a/lib/button.test.tsx b/lib/button.test.tsx new file mode 100644 index 0000000..d53523d --- /dev/null +++ b/lib/button.test.tsx @@ -0,0 +1,30 @@ +// import userEvent from '@testing-library/user-event'; +import { render, screen } from '@testing-library/react'; +import '@testing-library/jest-dom'; +import { describe, it, expect } from 'vitest'; +import { Button } from './main.js'; + +describe('Button', () => { + it('renders a button', async () => { + // ARRANGE + render(); + + // ACT + // // @ts-expect-error + // await userEvent.click(screen.getByText('Click Me')); + + // ASSERT + expect(screen.getByRole('button')).toMatchInlineSnapshot(` + + `); + }); +}); diff --git a/lib/buttons.tsx b/lib/button.tsx similarity index 58% rename from lib/buttons.tsx rename to lib/button.tsx index 73af679..3b1039c 100644 --- a/lib/buttons.tsx +++ b/lib/button.tsx @@ -6,19 +6,34 @@ import { type ForwardedRef, type ReactElement, } from 'react'; +import { Box, type BoxProps } from './box.js'; +import type { ButtonState, ButtonVariant } from './button.css.js'; import { busyButtonClass, buttonClassName, + buttonStateClassNames, + buttonVariantClassNames, iconClass, inlineBleedClass, visiblyHiddenClass, -} from './buttons.css.js'; +} from './button.css.js'; import { differentOriginLinkProps } from './component-utils.js'; -import type { Falsy } from './core.css.js'; -import { Box } from './core.js'; +import { useStringLikeDetector } from './hooks/use-string-like.js'; import { Flex, type FlexProps } from './layout.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; -import { Text } from './typography.js'; +import { Spinner } from './loaders.js'; +import type { Falsy, Merge, ReactHTMLElementsHacked } from './types.js'; +import { ExactText } from './typography.js'; + +export { ButtonState, ButtonVariant }; + +// Extracted out to its own type because `isValidElement` and `ReactElement` +// don't have the same default value for props, so we need to specify it in +// code later. This keeps it clean if/when we remove it in future and avoids +// a stray `any` +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type ReactElementDefaultPropsType = any; + +export type ButtonSize = 'small' | 'medium' | 'large'; export type ButtonCommonProps = { busy?: boolean | undefined; @@ -28,35 +43,33 @@ export type ButtonCommonProps = { icon?: ReactElement | FC | Falsy; iconStart?: ReactElement | FC | Falsy; iconEnd?: ReactElement | FC | Falsy; + + variant?: ButtonVariant | Falsy; + size?: ButtonSize | Falsy; + state?: ButtonState | Falsy; }; +export type ButtonProps = + Merge, ButtonCommonProps>; + export type ButtonLinkProps = Merge< - ButtonProps<'a'>, - { + FlexProps<'a'>, + ButtonCommonProps & { safe?: boolean; } >; -export type ButtonProps = - Merge, ButtonCommonProps>; - -// Extracted out to its own type because `isValidElement` and `ReactElement` -// don't have the same default value for props, so we need to specify it in -// code later. This keeps it clean if/when we remove it in future and avoids -// a stray `any` -// eslint-disable-next-line @typescript-eslint/no-explicit-any -type ReactElementDefaultPropsType = any; - export type ButtonIconProps< T extends keyof ReactHTMLElementsHacked = 'button', > = Merge< - ButtonProps, - { + FlexProps, + ButtonCommonProps & { label: string; icon: ReactElement; } >; +/** @private */ const IconBox: FC<{ icon: ReactElement | FC; busy?: boolean | Falsy; @@ -79,14 +92,41 @@ export const UnstyledButton = forwardRef( className={[className, buttonClassName]} // if this is going to be an actual button element - default to button // type so that it doesn't submit forms by default - {...(props.component === 'button' && { - type: ('type' in props && props.type) || 'button', + {...((!props.component || props.component === 'button') && { + type: 'type' in props ? props.type : 'button', })} {...props} /> ), ); +function getSizeProps(size: ButtonSize | Falsy) { + switch (size) { + case 'small': + return { + space: '1', + fontSize: '0', + paddingBlock: '4', + paddingInline: '5', + } satisfies BoxProps; + case 'large': + return { + space: '2', + fontSize: '3', + paddingBlock: '6', + paddingInline: '7', + } satisfies BoxProps; + case 'medium': + default: + return { + space: '2', + fontSize: '1', + paddingBlock: '5', + paddingInline: '6', + } satisfies BoxProps; + } +} + export const Button = forwardRef( ( { @@ -102,52 +142,68 @@ export const Button = forwardRef( paddingBlock, paddingInline, flexGrow, + state, + size = 'medium', + variant = 'default', ...props }: ButtonProps, ref: ForwardedRef, ) => { - const baseProps = { - capSize: '1', - paddingBlock: - paddingBlock === null ? paddingBlock : paddingBlock || padding || '6', + const isStringLike = useStringLikeDetector(); + const { fontSize, ...buttonSizeProps } = getSizeProps(size); - paddingInline: - paddingInline === null - ? paddingInline - : paddingInline || padding || '7', - } satisfies FlexProps; + const finalProps = { + ...buttonSizeProps, + ...props, + }; + + const busyAttributes = { + className: [busy && visiblyHiddenClass], + 'aria-hidden': busy || undefined, + 'aria-live': busy ? 'polite' : undefined, + } as const; return ( {iconStart && } - {children && ( - - {children} - - )} + {!busy && + (isStringLike(children) ? ( + + {children} + + ) : ( + children && ( + + {children} + + ) + ))} + + {busy && } {iconEnd && } diff --git a/lib/buttons.css.ts b/lib/buttons.css.ts deleted file mode 100644 index 670085a..0000000 --- a/lib/buttons.css.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { style } from '@vanilla-extract/css'; -import { calc } from '@vanilla-extract/css-utils'; -import { genericVars } from './design-system.css.js'; -import { rotate } from './keyframes.css.js'; -import { currentCapHeight } from './typography.css.js'; - -export const iconClass = style({ - height: currentCapHeight, - aspectRatio: '1/1', - lineHeight: 0, -}); - -export const buttonClassName = style([ - { - cursor: 'pointer', - userSelect: 'none', - selectors: { - '&[disabled]': { - pointerEvents: 'none', - cursor: 'default', - filter: 'grayscale(1)', - }, - - // keyboard - '&:focus-visible': { - outlineStyle: 'solid', - outlineOffset: genericVars.border.width['3'], - outlineWidth: genericVars.border.width['3'], - // outlineColor: oklch( - // contrastSchemeVars.swatch.k0.l, - // contrastSchemeVars.swatch.k0.c, - // toneH, - // ), - }, - - // mouse, touch, or stylus - '&:focus:not(:focus-visible)': {}, - - // both - '&:focus-visible,&:focus:not(:focus-visible)': {}, - - // gives us the nice little animation on outlineOffset - '&:active': { - outlineOffset: 0, - }, - }, - }, -]); - -export const visiblyHiddenClass = style({ - visibility: 'hidden', -}); - -export const busyButtonClass = style({ - pointerEvents: 'none', - selectors: { - '&::after': { - height: currentCapHeight, - aspectRatio: '1/1', - content: '""', - position: 'absolute', - margin: 'auto', - - // busy indicator - borderStyle: 'solid', - borderWidth: genericVars.border.width['2'], - borderColor: 'transparent', - borderTopColor: 'currentColor', - borderRadius: genericVars.radius['50'], - - // busy indicator animation - animationName: rotate, - animationDuration: '0.75s', - animationIterationCount: 'infinite', - animationTimingFunction: 'linear', - }, - }, -}); - -export const inlineBleedClass = style({ - marginBlock: calc(genericVars.space[0]).negate().toString(), -}); diff --git a/lib/buttons.test.tsx b/lib/buttons.test.tsx deleted file mode 100644 index 8baf7a0..0000000 --- a/lib/buttons.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -// import userEvent from '@testing-library/user-event'; -import { render, screen } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import { describe, it, expect } from 'vitest'; -import { Button } from './main.js'; - -describe('Button', () => { - it('renders a button', async () => { - // ARRANGE - render(); - - // ACT - // // @ts-expect-error - // await userEvent.click(screen.getByText('Click Me')); - - // ASSERT - expect(screen.getByRole('button')).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/lib/callout.css.ts b/lib/callout.css.ts index 461a191..d714144 100644 --- a/lib/callout.css.ts +++ b/lib/callout.css.ts @@ -1,27 +1,47 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { style } from '@vanilla-extract/css'; -import { currentCapHeight } from './typography.css.js'; +import { createVar, style, styleVariants } from '@vanilla-extract/css'; +import { purposeVariantVars } from './purpose.css.js'; +import { calloutVars, globalVars } from './vars.css.js'; -export const calloutClass = style({ - padding: currentCapHeight, +const calloutClassName = style({ display: 'grid', gridTemplateColumns: 'auto 1fr', - rowGap: 0, - alignItems: 'start', + borderStyle: 'solid', + borderRadius: globalVars.border.radius, + borderWidth: globalVars.border.width, + padding: calloutVars.padding, }); -export const calloutTextIconWrapperClass = style({ +const iconColorVar = createVar(); +export const calloutStyleVariants = styleVariants( + purposeVariantVars, + (variant) => [ + calloutClassName, + { + backgroundColor: variant.muted.bgColor, + borderColor: variant.muted.borderColor, + color: variant.muted.fgColor, + vars: { + [iconColorVar]: variant.fgColor, + }, + }, + ], +); + +export const iconWrapperClassName = style({ gridColumn: 1, lineHeight: 0, }); -export const calloutTextIconClass = style({ +export const iconClassName = style({ display: 'inline-block', width: '1em', height: '1em', aspectRatio: '1/1', + color: iconColorVar, }); -export const calloutTextClass = style({ +export const textClassName = style({ + display: 'block', gridColumn: 2, + alignSelf: 'center', }); diff --git a/lib/callout.tsx b/lib/callout.tsx index d1eb248..cfe50f7 100644 --- a/lib/callout.tsx +++ b/lib/callout.tsx @@ -1,38 +1,68 @@ -import { Children, cloneElement, type FC, type ReactNode } from 'react'; +import { Children, cloneElement, type ReactNode } from 'react'; +import { Box, type BoxProps } from './box.js'; import { - calloutClass, - calloutTextClass, - calloutTextIconClass, - calloutTextIconWrapperClass, + calloutStyleVariants, + iconClassName, + iconWrapperClassName, + textClassName, } from './callout.css.js'; -import { Box, type BoxProps } from './core.js'; import { debugLogger, ifDebugBuild } from './debug-logger.js'; -import { InfoIcon } from './icons.js'; +import { + AttentionIcon, + CriticalIcon, + InfoIcon, + PositiveIcon, +} from './icons.js'; +import type { PurposeVariant } from './purpose.css.js'; import type { Merge, ReactHTMLElementsHacked } from './types.js'; -import { Text } from './typography.js'; +import { ExactText } from './typography.js'; import { isValidElementOfType } from './utils.js'; -type CalloutCommonProps = { +export type { PurposeVariant as CalloutVariant }; + +function variantIcon(variant: PurposeVariant): ReactNode { + const props = { className: iconClassName }; + + switch (variant) { + case 'critical': + return ; + case 'positive': + return ; + case 'attention': + return ; + case 'default': + case 'info': + default: + return ; + } +} + +export type CalloutCommonProps = { align?: never; children: ReactNode; + icon?: ReactNode; + variant?: PurposeVariant; }; export type CalloutProps = Merge, CalloutCommonProps>; -export const Callout: FC = ({ +export const Callout = ({ children, className, space = '3', + variant = 'info', + icon, + capSize = '1', ...props -}) => { +}: CalloutProps) => { ifDebugBuild(() => { if ( - isValidElementOfType(children, Text) && + isValidElementOfType(children, ExactText) && Children.count(children) === 1 ) { debugLogger( - 'There is no need to have a single Text component as a child of Callout', + 'There is no need to have a single ExactText component as a child of Callout', ); } }); @@ -40,26 +70,27 @@ export const Callout: FC = ({ return ( -
- -
+ + {isValidElementOfType(icon, 'svg') + ? cloneElement(icon, { + className: iconClassName, + }) + : variantIcon(variant)} + - {isValidElementOfType(children, Text) ? ( + {isValidElementOfType(children, ExactText) ? ( cloneElement(children, { - className: calloutTextClass, + className: textClassName, }) ) : ( - + {children} - + )}
); diff --git a/lib/component-utils.ts b/lib/component-utils.ts index e7c1cda..4149dbf 100644 --- a/lib/component-utils.ts +++ b/lib/component-utils.ts @@ -1,5 +1,6 @@ import type { ClassValue } from 'clsx'; -import type { Falsy, Responsive, Viewport } from './core.css.js'; +import type { Responsive, Viewport } from './box.css.js'; +import type { Falsy } from './types.js'; import { typedObjectEntries } from './utils.js'; export function isNotFalsy(value: T | null | undefined | false): value is T { diff --git a/lib/core.tsx b/lib/core.tsx deleted file mode 100644 index 7daec38..0000000 --- a/lib/core.tsx +++ /dev/null @@ -1,275 +0,0 @@ -import { type Placement } from '@floating-ui/dom'; -import { clsx, type ClassValue } from 'clsx'; -import { - Suspense, - createElement, - forwardRef, - type ForwardedRef, - type ReactNode, -} from 'react'; -import { isNotFalsy, matchViewportVariants } from './component-utils.js'; -import { - borderWidthVariants, - flexDirectionVariants, - hiddenClass, - overflowVariants, - roundedEndEndVariants, - roundedEndStartVariants, - roundedStartEndVariants, - roundedStartStartVariants, - roundedVariants, - textAlignVariants, - textOverflowVariants, - viewportFlexDirectionVariants, - viewportMarginBlockVariants, - viewportMarginInlineVariants, - viewportMarginVariants, - viewportPaddingBlockVariants, - viewportPaddingInlineVariants, - viewportPaddingVariants, - viewportSpaceVariants, - type BorderWidth, - type Falsy, - type FlexDirection, - type OrResponsive, - type Overflow, - type Rounded, - type Space, - type TextAlign, - type TextOverflow, -} from './core.css.js'; -import { TooltipLazy } from './tooltip-lazy.js'; -import type { TooltipProps } from './tooltip.js'; -import type { - Merge, - ReactHTMLAttributesHacked, - ReactHTMLElementsHacked, -} from './types.js'; -import { - capSizeVariants, - fontSizeVariants, - fontWeightVariants, - lineHeightVariants, - type FontSize, - type FontWeight, - type LineHeight, -} from './typography.css.js'; - -export type BoxProps = Merge< - ReactHTMLAttributesHacked[T], - { - className?: ClassValue; - component?: T | undefined; - - space?: OrResponsive | Falsy; - flexDirection?: OrResponsive | Falsy; - - margin?: OrResponsive | Falsy; - marginBlock?: OrResponsive | Falsy; - marginInline?: OrResponsive | Falsy; - - padding?: OrResponsive | Falsy; - paddingBlock?: OrResponsive | Falsy; - paddingInline?: OrResponsive | Falsy; - - tooltip?: ReactNode; - tooltipInitialPlacement?: Placement | Falsy; - - textAlign?: TextAlign | Falsy; - textOverflow?: TextOverflow | Falsy; - - fontSize?: FontSize | Falsy; - capSize?: FontSize | Falsy; - fontWeight?: FontWeight | Falsy; - lineHeight?: LineHeight | Falsy; - - overflow?: Overflow | Falsy; - - rounded?: Rounded | Falsy; - roundedStart?: Rounded | Falsy; - roundedStartStart?: Rounded | Falsy; - roundedStartEnd?: Rounded | Falsy; - roundedEnd?: Rounded | Falsy; - roundedEndStart?: Rounded | Falsy; - roundedEndEnd?: Rounded | Falsy; - - borderWidth?: BorderWidth | Falsy; - } ->; - -const BoxInner = ( - { - children, - component, - className, - - margin, - marginBlock, - marginInline, - padding, - paddingBlock, - paddingInline, - - textAlign, - textOverflow, - - fontSize, - capSize, - fontWeight, - lineHeight, - - overflow, - - tooltip, - tooltipInitialPlacement, - - rounded, - roundedStart, - roundedStartStart, - roundedStartEnd, - roundedEnd, - roundedEndStart, - roundedEndEnd, - - space, - flexDirection, - - borderWidth, - - ...props - }: BoxProps, - ref: ForwardedRef, -) => { - const flexDirectionClass = - flexDirection && - (typeof flexDirection === 'string' - ? flexDirectionVariants[flexDirection] - : matchViewportVariants(flexDirection, viewportFlexDirectionVariants)); - - const spaceClass = - space && - matchViewportVariants( - typeof space === 'string' ? { all: space } : space, - viewportSpaceVariants, - ); - - const el = createElement( - component || 'div', - { - ...props, - className: - clsx( - className, - - spaceClass, - - // we dont extract out the prop, we just force a display none - // so we can keep the element attribute for accessibility? - props.hidden && hiddenClass, - - isNotFalsy(margin) && - marginBlock !== margin && - matchViewportVariants( - typeof margin === 'string' ? { all: margin } : margin, - viewportMarginVariants, - ), - - isNotFalsy(marginBlock) && - marginBlock !== margin && - matchViewportVariants( - typeof marginBlock === 'string' - ? { all: marginBlock } - : marginBlock, - viewportMarginBlockVariants, - ), - - isNotFalsy(marginInline) && - marginInline !== margin && - matchViewportVariants( - typeof marginInline === 'string' - ? { all: marginInline } - : marginInline, - viewportMarginInlineVariants, - ), - - isNotFalsy(padding) && - matchViewportVariants( - typeof padding === 'string' ? { all: padding } : padding, - viewportPaddingVariants, - ), - - isNotFalsy(paddingBlock) && - paddingBlock !== padding && - matchViewportVariants( - typeof paddingBlock === 'string' - ? { all: paddingBlock } - : paddingBlock, - viewportPaddingBlockVariants, - ), - - isNotFalsy(paddingInline) && - paddingInline !== padding && - matchViewportVariants( - typeof paddingInline === 'string' - ? { all: paddingInline } - : paddingInline, - viewportPaddingInlineVariants, - ), - - textAlign && textAlignVariants[textAlign], - - isNotFalsy(rounded) && roundedVariants[rounded], - - isNotFalsy(roundedStart) && [ - roundedStartStartVariants[roundedStart], - roundedStartEndVariants[roundedStart], - ], - isNotFalsy(roundedEnd) && [ - roundedEndStartVariants[roundedEnd], - roundedEndEndVariants[roundedEnd], - ], - - isNotFalsy(roundedStartStart) && - roundedStartStartVariants[roundedStartStart], - isNotFalsy(roundedStartEnd) && - roundedStartEndVariants[roundedStartEnd], - isNotFalsy(roundedEndStart) && - roundedEndStartVariants[roundedEndStart], - isNotFalsy(roundedEndEnd) && roundedEndEndVariants[roundedEndEnd], - - isNotFalsy(borderWidth) && borderWidthVariants[borderWidth], - - flexDirectionClass, - - overflow && overflowVariants[overflow], - textOverflow && textOverflowVariants[textOverflow], - - fontSize && fontSizeVariants[fontSize], - capSize && capSizeVariants[capSize], - fontWeight && fontWeightVariants[fontWeight], - - lineHeight && lineHeightVariants[lineHeight], - ) || undefined, - ref, - }, - children, - ); - - if (tooltip) { - const tooltipProps: TooltipProps = { - content: tooltip, - ...(tooltipInitialPlacement && { - initialPlacement: tooltipInitialPlacement, - }), - }; - return ( - - {el} - - ); - } - - return el; -}; - -export const Box = forwardRef(BoxInner); diff --git a/lib/css-helpers.css.ts b/lib/css-helpers.ts similarity index 50% rename from lib/css-helpers.css.ts rename to lib/css-helpers.ts index af3b024..f18155d 100644 --- a/lib/css-helpers.css.ts +++ b/lib/css-helpers.ts @@ -1,8 +1,19 @@ import { calc } from '@vanilla-extract/css-utils'; +export function createGlobalThemeMapFn(prefix = '') { + const delim = '-'; + const fullPrefix = prefix ? `${prefix}${delim}` : ''; + return Object.assign( + (value: string | null, path: Array) => + `${fullPrefix}${value}${path.join(delim)}`, + { prefix: fullPrefix }, + ); +} + export function withUnit(value: string | number, unit = 'px') { return calc.multiply(value, `1${unit}`).toString(); } + export function withNegativeUnit(value: string | number, unit = 'px') { return calc.multiply(value, `-1${unit}`).toString(); } diff --git a/lib/decorative.css.ts b/lib/decorative.css.ts index 1251a30..663a3be 100644 --- a/lib/decorative.css.ts +++ b/lib/decorative.css.ts @@ -1,7 +1,7 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { style } from '@vanilla-extract/css'; -import { genericVars } from './design-system.css.js'; +import { propsVars, globalVars } from './vars.css.js'; -export const dividerStyle = style({ - height: genericVars.border.width[1], +export const dividerClassName = style({ + height: propsVars.border.width[1], + backgroundColor: globalVars.color.muted.borderColor, }); diff --git a/lib/decorative.tsx b/lib/decorative.tsx index 12e750f..2e5bd0b 100644 --- a/lib/decorative.tsx +++ b/lib/decorative.tsx @@ -1,24 +1,15 @@ import { forwardRef } from 'react'; -import { Box, type BoxProps } from './core.js'; -import { dividerStyle } from './decorative.css.js'; +import { Box, type BoxProps } from './box.js'; +import { dividerClassName } from './decorative.css.js'; -export type DividerProps = Pick< - BoxProps<'hr'>, - | 'className' - | 'margin' - | 'marginInline' - | 'marginBlock' - | 'padding' - | 'paddingInline' - | 'paddingBlock' ->; +export type DividerProps = BoxProps<'hr'>; export const Divider = forwardRef( ({ className, ...props }, ref) => ( ), diff --git a/lib/context.tsx b/lib/design-system-context.tsx similarity index 83% rename from lib/context.tsx rename to lib/design-system-context.tsx index 049a2ad..4ee32dd 100644 --- a/lib/context.tsx +++ b/lib/design-system-context.tsx @@ -1,7 +1,7 @@ import type { ClassValue } from 'clsx'; import { createContext, type JSXElementConstructor } from 'react'; -export const Context = createContext<{ +export const DesignSystemContext = createContext<{ className?: ClassValue; // eslint-disable-next-line @typescript-eslint/no-explicit-any stringLikeComponents?: JSXElementConstructor[]; diff --git a/lib/design-system.css.ts b/lib/design-system.css.ts index d5842d4..4ab3f89 100644 --- a/lib/design-system.css.ts +++ b/lib/design-system.css.ts @@ -1,143 +1,7 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { createTheme, createThemeContract } from '@vanilla-extract/css'; +import { style } from '@vanilla-extract/css'; +import { globalVars } from './vars.css.js'; -export const genericVars = createThemeContract({ - text: { - capHeights: { - '00': 'cap-height-00', - '0': 'cap-height-0', - '1': 'cap-height-1', - '2': 'cap-height-2', - '3': 'cap-height-3', - '4': 'cap-height-4', - '5': 'cap-height-5', - }, - weight: { - thin: 'text-weight-thin', - extraLight: 'text-weight-extra-light', - light: 'text-weight-light', - normal: 'text-weight-normal', - medium: 'text-weight-medium', - semiBold: 'text-weight-semi-bold', - bold: 'text-weight-bold', - heavy: 'text-weight-heavy', - }, - lineHeight: { - normal: 'text-line-height-normal', - paragraph: 'text-line-height-paragraph', - heading: 'text-line-height-heading', - }, - }, - border: { - width: { - '0': 'border-width-0', - '1': 'border-width-1', - '2': 'border-width-2', - '3': 'border-width-3', - '4': 'border-width-4', - '5': 'border-width-5', - '6': 'border-width-6', - '7': 'border-width-7', - }, - }, - radius: { - 0: 'radius-0', - 1: 'radius-1', - 2: 'radius-2', - 3: 'radius-3', - 50: 'radius-50', - }, - space: { - '000': 'space-000', - '00': 'space-00', - '0': 'space-0', - '1': 'space-1', - '2': 'space-2', - '3': 'space-3', - '4': 'space-4', - '5': 'space-5', - '6': 'space-6', - '7': 'space-7', - '8': 'space-8', - '9': 'space-9', - '10': 'space-10', - '11': 'space-11', - '12': 'space-12', - '13': 'space-13', - '14': 'space-14', - '15': 'space-15', - '16': 'space-16', - }, -}); - -export const genericThemeClass = createTheme(genericVars, { - text: { - capHeights: { - '00': '0.5rem', - '0': '0.75rem', - '1': '1rem', - '2': '1.1rem', - '3': '1.25rem', - '4': '1.5rem', - '5': '2rem', - }, - weight: { - thin: '100', - extraLight: '200', - light: '300', - normal: '400', - medium: '500', - semiBold: '500', - bold: '600', - heavy: '900', - }, - lineHeight: { - normal: '1.5', - paragraph: '1.6', - heading: '1.3', - }, - }, - border: { - width: { - 0: '0', - 1: '0.05rem', - 2: '0.15rem', - 3: '0.2rem', - 4: '0.3rem', - 5: '0.5rem', - 6: '0.75rem', - 7: '1rem', - }, - }, - radius: { - // these are tuned to be distinguished at DPR3 - // but may not be different at lower densities - 0: '0', - 1: '0.125em', - 2: '0.25em', - 3: '0.5em', - 50: '50%', - }, - - space: { - '000': '-.5rem', - '00': '-.25rem', - '0': '0rem', - '1': '.125rem', - '2': '.25rem', - '3': '.375rem', - '4': '.5rem', - '5': '.625rem', - '6': '.75rem', - '7': '1rem', - '8': '1.25rem', - '9': '1.5rem', - '10': '1.75rem', - '11': '2rem', - '12': '3rem', - '13': '5rem', - '14': '7.5rem', - '15': '10rem', - '16': '15rem', - }, +export const designSystemClassName = style({ + color: globalVars.color.fgColor, + backgroundColor: globalVars.color.bgColor, }); diff --git a/lib/design-system.tsx b/lib/design-system.tsx index eb2d59a..b349583 100644 --- a/lib/design-system.tsx +++ b/lib/design-system.tsx @@ -4,33 +4,32 @@ import type { PropsWithChildren, ReactElement, } from 'react'; -import { Context } from './context.js'; -import { Box, type BoxProps } from './core.js'; -import { genericThemeClass } from './design-system.css.js'; +import { Box, type BoxProps } from './box.js'; +import { DesignSystemContext } from './design-system-context.js'; +import { designSystemClassName } from './design-system.css.js'; import { resetClass } from './reset.css.js'; import type { Merge, ReactHTMLElementsHacked } from './types.js'; export type DesignSystemProps = Merge< BoxProps, - PropsWithChildren<{ + { integrationMode?: boolean; // eslint-disable-next-line @typescript-eslint/no-explicit-any stringLikeComponents?: JSXElementConstructor[]; - }> + } >; export const DesignSystem = < T extends Extract, >({ - children, className, integrationMode, stringLikeComponents, component = 'div', ...props }: DesignSystemProps): ReactElement | null => ( - - {children} - - + /> + ); -export const Reset: FC = ({ children }) => ( - - {children} - +export const Reset: FC = (props) => ( + ); diff --git a/lib/focusable.css.ts b/lib/focusable.css.ts index 1e22103..2733fea 100644 --- a/lib/focusable.css.ts +++ b/lib/focusable.css.ts @@ -1,6 +1,5 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { createVar, style } from '@vanilla-extract/css'; -import { genericVars } from './design-system.css.js'; +import { propsVars } from './vars.css.js'; export const focusColorVar = createVar(); export const focusRadiusVar = createVar(); @@ -13,8 +12,8 @@ export const focusableClassName = style({ // contrastSchemeVars.swatch.v7.c, // colorThemeVars.tones.accent.h, // ), - [focusRadiusVar]: genericVars.radius['1'], - [focusWidthVar]: genericVars.border.width['2'], + [focusRadiusVar]: propsVars.radius['1'], + [focusWidthVar]: propsVars.border.width['2'], }, }); @@ -25,7 +24,7 @@ export const focusVisibleClassName = style([ '&:focus-visible': { outlineStyle: 'solid', outlineWidth: focusWidthVar, - outlineOffset: genericVars.space['00'], + outlineOffset: propsVars.space['00'], outlineColor: focusColorVar, }, }, diff --git a/lib/fonts/inter.css.ts b/lib/fonts/inter.css.ts deleted file mode 100644 index 83a186d..0000000 --- a/lib/fonts/inter.css.ts +++ /dev/null @@ -1,118 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import interFontMetrics from '@capsizecss/metrics/inter'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { precomputeValues } from '@capsizecss/vanilla-extract'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { createTheme, style } from '@vanilla-extract/css'; -import { withUnit } from '../css-helpers.css.js'; -import { fontThemeVars } from '../typography.css.js'; - -const interFontTheme = createTheme(fontThemeVars, { - // aim for 2.5rem - 40px - '6': { - values: precomputeValues({ - capHeight: 29.0909, - leading: 42, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(29.0909), - }, - - // aim for 2rem - 32px - '5': { - values: precomputeValues({ - capHeight: 23.27272, - leading: 35, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(23.27272), - }, - - // aim for 1.5rem - 24px - '4': { - values: precomputeValues({ - capHeight: 17.45454, - leading: 25, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(17.45454), - }, - - '3': { - // aim for 1.25rem - 20px - values: precomputeValues({ - capHeight: 14.54545, - leading: 22, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(14.54545), - }, - - '2': { - // aim for 1.1rem - 17.6px - values: precomputeValues({ - capHeight: 13.0909, - leading: 20, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(13.0909), - }, - - '1': { - // aim for 1rem - 16px - values: precomputeValues({ - capHeight: 11.63636, - leading: 20, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(11.63636), - }, - - // aim for 0.875rem - 14px - '0': { - values: precomputeValues({ - capHeight: 10.1818, - leading: 17, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(10.1818), - }, - - // aim for 0.75rem - 12px - '00': { - values: precomputeValues({ - capHeight: 8.72727, - leading: 14, // manually set based on cap height and whether the descenders are showing - fontMetrics: interFontMetrics, - }), - - // this is present so other components can know the - // capHeight of this font size - capHeight: withUnit(8.72727), - }, -}); - -export const interFontThemeClassName = style([ - interFontTheme, - { - fontFamily: 'Inter, sans-serif', - letterSpacing: '-0.011em', - }, -]); diff --git a/lib/fonts/inter.scss b/lib/fonts/inter.scss new file mode 100644 index 0000000..a0ec92b --- /dev/null +++ b/lib/fonts/inter.scss @@ -0,0 +1,38 @@ +@use '../scss/capsize.scss' as inter with ( + $font-metrics: ( + capHeight: 2048, + ascent: 2728, + descent: -680, + lineGap: 0, + unitsPerEm: 2816, + ) +); + +@mixin vars { + font-family: 'Inter', sans-serif; + font-optical-sizing: auto; + line-height: var(--text-lineHeight-regular); + font-style: normal; + font-variation-settings: 'slnt' 0; + + --text-fontWeight-bold: 700; + --text-fontWeight-semibold: 600; + --text-fontWeight-medium: 500; + --text-fontWeight-regular: 400; + --text-fontWeight-light: 300; + + --text-letterSpacing-tight: -0.05em; + + --text-lineHeight-regular: initial; + --text-lineHeight-paragraph: 1.6; + --text-lineHeight-heading: 1.3; + + @include inter.capsize(6, 40px, 42px); + @include inter.capsize(5, 32px, 35px); + @include inter.capsize(4, 24px, 25px); + @include inter.capsize(3, 20px, 22px); + @include inter.capsize(2, 17.6px, 20px); + @include inter.capsize(1, 16px, 20px); + @include inter.capsize(0, 14px, 17px); + @include inter.capsize('00', 12px, 14px); +} diff --git a/lib/fonts/roboto.css.ts b/lib/fonts/roboto.css.ts deleted file mode 100644 index d02fd3f..0000000 --- a/lib/fonts/roboto.css.ts +++ /dev/null @@ -1,97 +0,0 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import fontMetrics from '@capsizecss/metrics/robotoMono'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { precomputeValues } from '@capsizecss/vanilla-extract'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { createTheme, style } from '@vanilla-extract/css'; -import { withUnit } from '../css-helpers.css.js'; -import { fontThemeVars } from '../typography.css.js'; - -const robotoMonoFontTheme = createTheme(fontThemeVars, { - // aim for 2.5rem - 40px - '6': { - capHeight: withUnit(29.1), - values: precomputeValues({ - capHeight: 29.1, - leading: 29.1 * 1.5, - fontMetrics, - }), - }, - - // aim for 2rem - 32px - '5': { - capHeight: withUnit(23.3), - values: precomputeValues({ - capHeight: 23.3, - leading: 23.3 * 1.5, - fontMetrics, - }), - }, - - // aim for 1.5rem - 24px - '4': { - capHeight: withUnit(17.5), - values: precomputeValues({ - capHeight: 17.5, - leading: 17.5 * 1.6, - fontMetrics, - }), - }, - - '3': { - // aim for 1.25rem - 20px - capHeight: withUnit(14.6), - values: precomputeValues({ - capHeight: 14.6, - leading: 14.6 * 1.5, - fontMetrics, - }), - }, - - '2': { - // aim for 1.1rem - 17.6px - capHeight: withUnit(12.8), - values: precomputeValues({ - capHeight: 12.8, - leading: 12.8 * 1.6, - fontMetrics, - }), - }, - - '1': { - // aim for 1rem - 16px - capHeight: withUnit(11.636363), - values: precomputeValues({ - capHeight: 11.636363, - leading: 11.636363 * 1.6, - fontMetrics, - }), - }, - - // aim for 0.75rem - 12px - '0': { - capHeight: '8.727272', - values: precomputeValues({ - capHeight: 8.727272, - leading: 8.727272 * 1.75, - fontMetrics, - }), - }, - - // aim for 0.5rem - 8px - '00': { - capHeight: '5.818181', - values: precomputeValues({ - capHeight: 5.818181, - leading: 5.818181 * 1.75, - fontMetrics, - }), - }, -}); - -export const robotoMonoFontThemeClassName = style([ - robotoMonoFontTheme, - { - fontFamily: '"Roboto Mono", monospace', - }, -]); diff --git a/lib/form-input-origin.tsx b/lib/form-input-origin.tsx index c785e54..14dd6cb 100644 --- a/lib/form-input-origin.tsx +++ b/lib/form-input-origin.tsx @@ -1,17 +1,16 @@ import { forwardRef, useMemo, useState } from 'react'; -import type { Falsy } from './core.css.js'; -import { Box } from './core.js'; +import { Box } from './box.js'; import { defaultFormInputSpace, formInputBoxProps, formInputElProps, } from './forms-common.js'; import { - formInputInnerClassName, + formInputOuterClassName, formInputFocusNotCheckRadioClassName, + formInputInnerClassName, formInputHack, formInputOriginIcon, - formInputOuterClassName, } from './forms.css.js'; import { FormInputLabel, @@ -27,7 +26,7 @@ import { useFavicon } from './hooks/use-image.js'; import { GlobeColorIcon } from './icons.js'; import { Block, Inline } from './layout.js'; import { Spinner } from './loaders.js'; -import type { Merge } from './types.js'; +import type { Falsy, Merge } from './types.js'; function guessUrl(url: string) { if (!url) { @@ -108,7 +107,6 @@ export const FormInputOrigin = forwardRef< const finalValidity = useMemo(() => { if (syntacticallyValidValueAsUrl && !dns.busy && dns.response) { - // eslint-disable-next-line default-case switch (dns.response.Status) { case ReturnCode.NoError: break; diff --git a/lib/forms-common.tsx b/lib/forms-common.tsx index 12e2df8..19662bb 100644 --- a/lib/forms-common.tsx +++ b/lib/forms-common.tsx @@ -1,6 +1,6 @@ -import { type InputHTMLAttributes } from 'react'; -import type { Space } from './core.css.js'; -import type { BoxProps } from './core.js'; +import type { InputHTMLAttributes } from 'react'; +import type { Space } from './box.css.js'; +import type { BoxProps } from './box.js'; export const defaultFormInputSpace: Space = '5'; diff --git a/lib/forms.css.ts b/lib/forms.css.ts index 4ffd71e..a55e958 100644 --- a/lib/forms.css.ts +++ b/lib/forms.css.ts @@ -1,15 +1,14 @@ -import { createVar, style } from '@vanilla-extract/css'; +import { style } from '@vanilla-extract/css'; import { calc } from '@vanilla-extract/css-utils'; -import { genericVars } from './design-system.css.js'; import { focusColorVar, focusVisibleClassName, focusWidthVar, focusableClassName, } from './focusable.css.js'; -import { capSizeVariantVars } from './typography.css.js'; - -const borderWidthVar = createVar(); +import { purposeVariantVars } from './purpose.css.js'; +import { textVariantVars } from './typography.css.js'; +import { formControlVars, propsVars, globalVars } from './vars.css.js'; export const formInputPasswordIcon = style({ aspectRatio: '1/1', @@ -49,20 +48,15 @@ export const formInputOuterClassName = style({ alignItems: 'center', }, '&[readonly]': { - // pointerEvents: 'none', // paired with tabindex="-1" to prevent focus - // userSelect: 'auto', cursor: 'text', }, }, }); export const formInputInnerClassName = style([ - capSizeVariantVars[1], { selectors: { - '&::placeholder': { - // color: oklch(contrastSchemeVars.swatch.v6.l, 0, 0), - }, + '&::placeholder': {}, }, }, ]); @@ -70,11 +64,14 @@ export const formInputInnerClassName = style([ export const formInputFocusNotCheckRadioClassName = style([ focusVisibleClassName, { + outlineWidth: formControlVars.outline.width, + borderRadius: globalVars.border.radius, + borderColor: purposeVariantVars.default.muted.borderColor, selectors: { '&:focus': { // draw the outline over the border so that we can increase // thickness without any layout shifts - outlineOffset: calc(borderWidthVar).negate().toString(), + // outlineOffset: calc(borderWidthVar).negate().toString(), borderColor: 'transparent', outlineStyle: 'solid', @@ -158,6 +155,7 @@ export const formInputCheckboxInput = style([ formInputCheckRadioBase, { width: '100%', + borderRadius: propsVars.radius[2], selectors: { '&::before': { @@ -166,7 +164,7 @@ export const formInputCheckboxInput = style([ // size and color of the check aspectRatio: '1/1', // height: '0.35em', - boxShadow: `inset 1em 1em ${'white'}`, + boxShadow: `inset 1em 1em ${globalVars.color.accent}`, }, '&:checked': { // background/border of the check @@ -180,14 +178,14 @@ export const formInputCheckboxInput = style([ export const formInputRadioInput = style([ formInputCheckRadioBase, { - borderRadius: genericVars.radius['50'], + borderRadius: '50%', width: '1rem', selectors: { '&::before': { height: '0.5rem', aspectRatio: '1/1', - borderRadius: genericVars.radius['50'], - boxShadow: 'inset 1em 1em currentColor', + borderRadius: '50%', + boxShadow: `inset 1em 1em ${globalVars.color.accent}`, }, }, }, @@ -212,7 +210,7 @@ const formInputSelectWrapper = style({ export const formInputSelectWrapperMultiple = style([ formInputSelectWrapper, { - lineHeight: genericVars.text.lineHeight.normal, + lineHeight: textVariantVars.lineHeight.normal, }, ]); @@ -229,10 +227,7 @@ export const formInputSelectWrapperSingle = style([ justifySelf: 'flex-end', width: '0.75em', // the same as the inline padding for inputs + border size - marginInline: calc.add( - genericVars.space[5], - genericVars.border.width[1], - ), + marginInline: calc.add(propsVars.space[5], propsVars.border.width[1]), display: 'block', aspectRatio: '2/1', backgroundColor: 'currentColor', diff --git a/lib/forms.tsx b/lib/forms.tsx index 6544101..98f37fa 100644 --- a/lib/forms.tsx +++ b/lib/forms.tsx @@ -1,4 +1,4 @@ -import { type ClassValue } from 'clsx'; +import type { ClassValue } from 'clsx'; import { Children, cloneElement, @@ -11,8 +11,7 @@ import { type PropsWithChildren, type ReactNode, } from 'react'; -import type { Falsy } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; +import { Box, type BoxProps } from './box.js'; import { defaultFormInputSpace, formInputBoxProps, @@ -24,9 +23,9 @@ import { formInputCheckRadioMessage, formInputCheckRadioWrapper, formInputCheckboxInput, + formInputFocusNotCheckRadioClassName, formInputHack, formInputInnerClassName, - formInputFocusNotCheckRadioClassName, formInputOuterClassName, formInputPasswordIcon, formInputPasswordToggleButton, @@ -43,9 +42,9 @@ import { useIdWithDefault } from './hooks/use-id-with-default.js'; import { useStringLikeDetector } from './hooks/use-string-like.js'; import { useToggle } from './hooks/use-toggle.js'; import { PasswordInvisibleIcon, PasswordVisibleIcon } from './icons.js'; -import { Block, Inline, type BlockProps } from './layout.js'; -import type { Merge } from './types.js'; -import { Secondary, Strong, Text } from './typography.js'; +import { Block, Inline, type FlexProps } from './layout.js'; +import type { Falsy, Merge } from './types.js'; +import { ExactText, Secondary, Strong } from './typography.js'; import { cloneElementIfValidElementOfType, isValidElementOfType, @@ -66,27 +65,22 @@ type CommonFormInputProps = { customValidity?: string; }; -export type FormInputProps = Merge< - // InputHTMLAttributes, - BoxProps<'input'>, - CommonFormInputProps ->; +export type FormInputProps = Merge, CommonFormInputProps>; -export const Form = forwardRef< - HTMLFormElement, - PropsWithChildren> ->(({ space = '9', children, ...props }, ref) => ( - - {Children.map(children, (child) => { - // if it's a block element and no space is defined, use the space this - // component has been given - if (isValidElementOfType(child, Block) && !child.props.space) { - return cloneElement(child, { ...child.props, space }); - } - return child; - })} - -)); +export const Form = forwardRef>( + ({ space = '9', children, ...props }, ref) => ( + + {Children.map(children, (child) => { + // if it's a block element and no space is defined, use the space this + // component has been given + if (isValidElementOfType(child, Block) && !child.props.space) { + return cloneElement(child, { ...child.props, space }); + } + return child; + })} + + ), +); export const FormInputLabel: FC< PropsWithChildren> & { @@ -108,7 +102,7 @@ export const FormInputLabel: FC< > {isStringLike(children) ? ( <> - {children} + {children} {secondary && {secondary}} ) : ( @@ -122,7 +116,11 @@ export const FormInputLabel: FC< export const FormInputMessage: FC> = ({ message, -}) => {message}; +}) => ( + + {message} + +); export const FormInput = forwardRef( ( @@ -235,6 +233,8 @@ export const FormInputPassword = forwardRef< const ourRef = useCustomValidity(customValidity); const ref = useCombinedRefs(forwardedRef, ourRef); + const isStringLike = useStringLikeDetector(); + return ( {label && ( @@ -292,7 +292,12 @@ export const FormInputPassword = forwardRef< - {message && } + {message && + (isStringLike(message) ? ( + + ) : ( + message + ))} ); }, @@ -358,9 +363,7 @@ export const FormSelect: FC = ({ {message && (isStringLike(message) ? ( - - {message} - + ) : ( message ))} @@ -395,7 +398,6 @@ const FormInputCheckRadio: FC< {label && (isStringLike(label) ? ( - {label} - + ) : ( {label} ))} {message && (isStringLike(message) ? ( - + {message} - + ) : ( {message} ))} @@ -469,9 +475,9 @@ export const FormInputRadioGroup: FC< )} {message && (isStringLike(message) ? ( - + {message} - + ) : ( message ))} @@ -518,9 +524,9 @@ export const FormInputCheckboxGroup: FC< )} {message && (isStringLike(message) ? ( - + {message} - + ) : ( message ))} @@ -542,7 +548,6 @@ export const FormTextArea = forwardRef( secondaryLabel, tertiaryLabel, message, - rounded = '2', autoFocus, ...props }, @@ -598,7 +603,6 @@ export const FormTextArea = forwardRef( )} {description} ( /> {message && ( - + {message} - + )} diff --git a/lib/grid.css.ts b/lib/grid.css.ts index 2281df2..b9f432c 100644 --- a/lib/grid.css.ts +++ b/lib/grid.css.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { style } from '@vanilla-extract/css'; export const gridClass = style({ diff --git a/lib/grid.tsx b/lib/grid.tsx index 6616db7..4cfe4e0 100644 --- a/lib/grid.tsx +++ b/lib/grid.tsx @@ -1,16 +1,14 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { Children, type ReactElement } from 'react'; -import { matchViewportVariants } from './component-utils.js'; +import { Children } from 'react'; import { viewportGridColumnsVariants, type Columns, type OrResponsive, type Space, - type Falsy, -} from './core.css.js'; -import { Box, type BoxProps } from './core.js'; +} from './box.css.js'; +import { Box, type BoxProps } from './box.js'; +import { matchViewportVariants } from './component-utils.js'; import { gridClass } from './grid.css.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; +import type { Falsy, Merge, ReactHTMLElementsHacked } from './types.js'; export type GridProps = Merge< BoxProps, @@ -24,7 +22,7 @@ export const Grid = ({ className, cols, ...props -}: GridProps): ReactElement | null => { +}: GridProps) => { // defaults to the count of children const resolvedCols: OrResponsive = cols || { all: Math.min(Children.count(props.children), 10) as Columns, diff --git a/lib/hooks/main.ts b/lib/hooks/main.ts index 89caf64..e6a930b 100644 --- a/lib/hooks/main.ts +++ b/lib/hooks/main.ts @@ -22,3 +22,4 @@ export { useToggle } from './use-toggle.js'; export { useTraceUpdate } from './use-trace-update.js'; export { useCookieState } from './use-cookie-state.js'; export { useNavigatorOnline } from './use-navigator-online.js'; +export { useColorSchemeEffect } from './use-color-scheme-effect.js'; diff --git a/lib/hooks/use-color-scheme-effect.ts b/lib/hooks/use-color-scheme-effect.ts new file mode 100644 index 0000000..6e9e9e9 --- /dev/null +++ b/lib/hooks/use-color-scheme-effect.ts @@ -0,0 +1,54 @@ +import { useState, useLayoutEffect } from 'react'; + +export function useColorSchemeEffect( + preference?: 'dark' | 'light' | 'auto' | undefined | null, +) { + const [prefersDark, setPrefersDark] = useState( + // eslint-disable-next-line no-nested-ternary + preference === 'dark' ? true : preference === 'light' ? false : null, + ); + + useLayoutEffect(() => { + const meta = + document.querySelector('meta[name=color-scheme]') || + document.createElement('meta'); + meta.setAttribute('name', 'color-scheme'); + + const prefersDarkMql = + !preference || preference === 'auto' + ? window.matchMedia('(prefers-color-scheme: dark)') + : { + matches: preference === 'dark', + // eslint-disable-next-line @typescript-eslint/no-unused-vars + addEventListener: (_eventName: 'change', _: unknown) => {}, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + removeEventListener: (_eventName: 'change', _: unknown) => {}, + }; + + meta.setAttribute('content', prefersDarkMql.matches ? 'dark' : 'light'); + + // probably new + if (!meta.parentElement) { + document.head.appendChild(meta); + } + + const listener = (e: { matches: boolean }) => { + setPrefersDark(e.matches); + meta.setAttribute('content', e.matches ? 'dark' : 'light'); + document.documentElement.setAttribute( + 'data-color-scheme', + e.matches ? 'dark' : 'light', + ); + }; + + listener(prefersDarkMql); + + prefersDarkMql.addEventListener('change', listener); + + return () => { + prefersDarkMql.removeEventListener('change', listener); + }; + }, [preference, prefersDark]); + + return [prefersDark] as const; +} diff --git a/lib/hooks/use-combined-refs.ts b/lib/hooks/use-combined-refs.ts index 611b048..86e20ce 100644 --- a/lib/hooks/use-combined-refs.ts +++ b/lib/hooks/use-combined-refs.ts @@ -1,8 +1,4 @@ -import { - type ForwardedRef, - type MutableRefObject, - type RefCallback, -} from 'react'; +import type { ForwardedRef, MutableRefObject, RefCallback } from 'react'; export function useCombinedRefs( ...refs: (RefCallback | MutableRefObject | ForwardedRef)[] diff --git a/lib/hooks/use-custom-validity.ts b/lib/hooks/use-custom-validity.ts index 7464b82..95d9c91 100644 --- a/lib/hooks/use-custom-validity.ts +++ b/lib/hooks/use-custom-validity.ts @@ -1,5 +1,5 @@ import { useEffect, useRef } from 'react'; -import type { Falsy } from '../core.css.js'; +import type { Falsy } from '../types.js'; export function useCustomValidity< T extends HTMLInputElement | HTMLSelectElement, diff --git a/lib/hooks/use-design-system.ts b/lib/hooks/use-design-system.ts index 812e253..8747466 100644 --- a/lib/hooks/use-design-system.ts +++ b/lib/hooks/use-design-system.ts @@ -1,6 +1,6 @@ import { useContext } from 'react'; -import { Context } from '../context.js'; +import { DesignSystemContext } from '../design-system-context.js'; export function useDesignSystem() { - return useContext(Context); + return useContext(DesignSystemContext); } diff --git a/lib/hooks/use-string-like.ts b/lib/hooks/use-string-like.ts index 59fd684..a252e0f 100644 --- a/lib/hooks/use-string-like.ts +++ b/lib/hooks/use-string-like.ts @@ -1,11 +1,12 @@ import { Children, - isValidElement, + Fragment, useCallback, type JSXElementConstructor, type ReactNode, } from 'react'; import type { Primitive } from 'type-fest'; +import { isValidElementOfType } from '../utils.js'; import { useDesignSystem } from './use-design-system.js'; function nodeIsPrimitive( @@ -25,16 +26,17 @@ function nodeIsStringLike( // eslint-disable-next-line @typescript-eslint/no-explicit-any stringLikeComponents: JSXElementConstructor[] = [], ): node is Exclude | string { - if (isValidElement(node)) { + if (isValidElementOfType(node, Fragment)) { if ('children' in node.props) { return ( - nodeIsPrimitive(node.props.children) || + (node.props.children && nodeIsPrimitive(node.props.children)) || Children.toArray(node.props.children).every((child) => nodeIsStringLike(child, stringLikeComponents), ) ); } + // node is one of the string-like components return stringLikeComponents.some((component) => node.type === component); } @@ -43,9 +45,10 @@ function nodeIsStringLike( export function useStringLikeDetector() { const { stringLikeComponents } = useDesignSystem(); + return useCallback( (node: ReactNode): node is Exclude | string => - nodeIsStringLike(node, stringLikeComponents), + !!node && nodeIsStringLike(node, stringLikeComponents), [stringLikeComponents], ); } diff --git a/lib/icons.css.ts b/lib/icons.css.ts index 611608c..4f96480 100644 --- a/lib/icons.css.ts +++ b/lib/icons.css.ts @@ -1,8 +1,6 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { fallbackVar, style } from '@vanilla-extract/css'; -import { currentCapHeight } from './typography.css.js'; +import { style } from '@vanilla-extract/css'; export const iconClassName = style({ display: 'inline-block', - height: fallbackVar(currentCapHeight, '1em'), + height: '1em', }); diff --git a/lib/icons.tsx b/lib/icons.tsx index b785b88..a432578 100644 --- a/lib/icons.tsx +++ b/lib/icons.tsx @@ -12,7 +12,7 @@ export const InfoIcon = forwardRef( strokeWidth="0" xmlns="http://www.w3.org/2000/svg" viewBox="2 2 20 20" - className={clsx([iconClassName, className])} + className={clsx([className, iconClassName])} {...props} > {' '} @@ -21,12 +21,16 @@ export const InfoIcon = forwardRef( ), ); +export const AttentionIcon = InfoIcon; +export const CriticalIcon = InfoIcon; +export const PositiveIcon = InfoIcon; + export const HelpIcon = forwardRef( ({ className, ...props }, ref) => ( ( ( ( ), ); -export const ArrowBack = forwardRef( +export const ArrowBackIcon = forwardRef( ({ className, ...props }, ref) => ( @@ -112,12 +116,12 @@ export const ArrowBack = forwardRef( ), ); -export const ArrowForward = forwardRef( +export const ArrowForwardIcon = forwardRef( ({ className, ...props }, ref) => ( @@ -151,7 +155,7 @@ export const ArrowForward = forwardRef( export const ClipboardIcon = forwardRef( ({ className, ...props }, ref) => ( ( export const PasswordVisibleIcon = forwardRef( ({ className, ...props }, ref) => ( ( export const PasswordInvisibleIcon = forwardRef( ({ className, ...props }, ref) => ( ( ({ className, ...props }, ref) => ( ->({ - true: { flexShrink: 1 }, - false: { flexShrink: 0 }, -}); - -export const flexWrapVariants = styleVariants>({ - wrap: { flexWrap: 'wrap' }, - nowrap: { flexWrap: 'nowrap' }, - wrapReverse: { flexWrap: 'wrap-reverse' }, -}); - -export const flexGrowClass = styleVariants< - Record<`${boolean}`, ComplexStyleRule> ->({ - true: { flexGrow: 1 }, - false: { flexGrow: 0 }, -}); export const alignItemsVariants = styleVariants< Record diff --git a/lib/layout.tsx b/lib/layout.tsx index 2bac3f1..a113899 100644 --- a/lib/layout.tsx +++ b/lib/layout.tsx @@ -1,22 +1,17 @@ -import { forwardRef, type ForwardedRef, type PropsWithChildren } from 'react'; -import { type Falsy, type OrResponsive } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; +import { forwardRef, type ForwardedRef } from 'react'; +import { Box, type BoxProps } from './box.js'; import { alignItemsVariants, alignSelfVariants, - flexGrowClass, - flexShrinkClass, - flexWrapVariants, justifyContentVariants, justifySelfInlineVariants, type Placement, - type Wrap, } from './layout.css.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; +import type { Falsy, Merge, ReactHTMLElementsHacked } from './types.js'; export type FlexProps = Merge< BoxProps, - PropsWithChildren<{ + { alignSelf?: Placement | Falsy; alignItems?: Placement | Falsy; @@ -29,50 +24,26 @@ export type FlexProps = Merge< justifySelf?: Placement | Falsy; justifyContent?: Placement | Falsy; - - flexGrow?: OrResponsive | Falsy; - flexShrink?: OrResponsive | Falsy; - - flexWrap?: Wrap | true | Falsy; - }> + } >; -export type BlockProps = - FlexProps; - -export type InlineProps = - FlexProps; - export const Flex = forwardRef( ( { - flexDirection = 'row', - flexWrap, alignSelf, alignItems, justifySelf, justifyContent, className, - flexGrow, - flexShrink, ...props }: FlexProps, ref: ForwardedRef, ) => ( ( - props: BlockProps, + props: FlexProps, ref: ForwardedRef, ) => , ); export const Inline = forwardRef( ( - props: InlineProps, + props: FlexProps, ref: ForwardedRef, ) => ( = - PropsWithChildren, TextLinkCommonProps>>; + Merge, TextLinkCommonProps>; /** - * A `TextLink` is expect to be wrapped in a `Text` component - * Think that ... + * A `TextLink` is expect to be wrapped something like a `Paragraph` component + * Think that ... * is akin to

...

* */ @@ -26,7 +28,7 @@ export const TextLink: FC = ({ }) => ( diff --git a/lib/list.css.ts b/lib/list.css.ts index 8834ae1..919e88f 100644 --- a/lib/list.css.ts +++ b/lib/list.css.ts @@ -1,6 +1,5 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { createVar, style, styleVariants } from '@vanilla-extract/css'; -import { genericVars } from './design-system.css.js'; +import { propsVars } from './vars.css.js'; export const listColsVar = createVar(); @@ -20,7 +19,7 @@ export const listItemClass = style({ }, }); -export const listVariants = styleVariants(genericVars.space, (space) => [ +export const listVariants = styleVariants(propsVars.space, (space) => [ listClass, { gap: space, diff --git a/lib/list.tsx b/lib/list.tsx index 83d8a60..307a288 100644 --- a/lib/list.tsx +++ b/lib/list.tsx @@ -1,7 +1,6 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { assignInlineVars } from '@vanilla-extract/dynamic'; -import type { Space } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; +import type { Space } from './box.css.js'; +import { Box, type BoxProps } from './box.js'; import { listClass, listColsVar, @@ -10,7 +9,7 @@ import { } from './list.css.js'; import type { Merge, ReactHTMLElementsHacked } from './types.js'; -type ListCommonProps = { +export type ListCommonProps = { variant?: 'ordered' | 'unordered'; space?: Space; cols?: `${number}`; @@ -27,7 +26,6 @@ export const List = ({ space = '5', className, cols = '1', - children, ...props }: ListProps) => ( ({ style={assignInlineVars({ [listColsVar]: cols })} className={[listClass, listVariants[space], className]} {...props} - > - {children} - + /> ); export const ListItem = ({ className, ...props }: BoxProps<'li'>) => ( diff --git a/lib/loaders.css.ts b/lib/loaders.css.ts index 7ee7ef6..ad2e416 100644 --- a/lib/loaders.css.ts +++ b/lib/loaders.css.ts @@ -1,31 +1,29 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -import { - fallbackVar, - keyframes, - style, - styleVariants, - type StyleRule, -} from '@vanilla-extract/css'; -import { currentCapHeight } from './typography.css.js'; +import { style, styleVariants, type StyleRule } from '@vanilla-extract/css'; +import { rotate, fadeIn } from './keyframes.css.js'; -const rotate = keyframes({ - '0%': { transform: 'rotate(0deg)' }, - '100%': { transform: 'rotate(360deg)' }, -}); +const rotateAnimation = `${rotate} 0.65s linear infinite`; + +// legend: +const fadeInAnimation = `${fadeIn} 600ms ease 1 900ms forwards`; export const spinnerClass = style({ aspectRatio: '1/1', transformOrigin: 'center center', - animationName: rotate, - animationDuration: '.75s', - animationIterationCount: 'infinite', - animationTimingFunction: 'linear', +}); + +export const spinnerAnimationVariantClassNames = styleVariants({ + delay: { + opacity: 0, + animation: [rotateAnimation, fadeInAnimation].join(','), + }, + regular: { + animation: rotateAnimation, + }, }); export const inlineSpinnerClass = style({ display: 'inline-flex', - height: fallbackVar(currentCapHeight, '1em'), - width: fallbackVar(currentCapHeight, '1em'), + width: '1em', }); export type SpinnerSize = '1' | '2' | '3' | '4' | '5'; diff --git a/lib/loaders.tsx b/lib/loaders.tsx index b068e6b..f2c6b30 100644 --- a/lib/loaders.tsx +++ b/lib/loaders.tsx @@ -1,10 +1,11 @@ import type { FC } from 'react'; -import { Box, type BoxProps } from './core.js'; +import { Box, type BoxProps } from './box.js'; import { inlineSpinnerClass, trackCircleClassName, runnerCircleClassName, spinnerClass, + spinnerAnimationVariantClassNames, spinnerSizeVariantClassNames, type SpinnerSize, } from './loaders.css.js'; @@ -15,23 +16,30 @@ export type SpinnerProps = Merge< { inline?: boolean; size?: SpinnerSize; + children?: never; + delay?: boolean; } >; export const Spinner: FC = ({ size = '1', className, - children, inline = true, + delay = false, ...props }) => ( diff --git a/lib/main.ts b/lib/main.ts index de96b85..0616156 100644 --- a/lib/main.ts +++ b/lib/main.ts @@ -1,12 +1,10 @@ export * from './design-system.js'; - -export * from './core.js'; +export * from './box.js'; export * from './grid.js'; export * from './layout.js'; - export * from './avatar.js'; export * from './badges.js'; -export * from './buttons.js'; +export * from './button.js'; export * from './callout.js'; export * from './decorative.js'; export * from './form-input-origin.js'; @@ -15,24 +13,13 @@ export * from './links.js'; export * from './list.js'; export * from './loaders.js'; export * from './typography.js'; - export * from './menu-item.js'; export * from './menu-lazy.js'; - export * from './tooltip-lazy.js'; - export * from './modal-hooks.js'; export * from './modal.js'; - -export * from './fonts/inter.css.js'; -export * from './fonts/roboto.css.js'; - export * from './icons.js'; - export * from './virtual.js'; +export * from './panel.js'; -export type * from './core.css.js'; - -export type { FontSize } from './typography.css.js'; - -export type { ReactHTMLElementsHacked as ReactHTMLElements } from './types.js'; +export type { ReactHTMLElementsHacked } from './types.js'; diff --git a/lib/menu-item.tsx b/lib/menu-item.tsx index abef795..976581b 100644 --- a/lib/menu-item.tsx +++ b/lib/menu-item.tsx @@ -1,9 +1,9 @@ import { forwardRef, type ReactNode } from 'react'; -import { Block, type BlockProps } from './layout.js'; +import { Block, type FlexProps } from './layout.js'; import type { Merge } from './types.js'; export type MenuItemProps = Merge< - BlockProps, + FlexProps, { label: string; children?: ReactNode; diff --git a/lib/menu-lazy.tsx b/lib/menu-lazy.tsx index c6fc576..ccfd739 100644 --- a/lib/menu-lazy.tsx +++ b/lib/menu-lazy.tsx @@ -1,5 +1,5 @@ import { Suspense, lazy, type FC } from 'react'; -import { Button } from './buttons.js'; +import { Button } from './button.js'; import { InfoIcon } from './icons.js'; import type { MenuButtonFallbackProps, diff --git a/lib/menu.css.ts b/lib/menu.css.ts deleted file mode 100644 index 3493af5..0000000 --- a/lib/menu.css.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { style } from '@vanilla-extract/css'; - -export const menuPanelStyle = style({}); diff --git a/lib/menu.tsx b/lib/menu.tsx index 9a75bc2..211ef91 100644 --- a/lib/menu.tsx +++ b/lib/menu.tsx @@ -39,10 +39,10 @@ import { type ReactNode, type Ref, } from 'react'; -import { Button, type ButtonProps } from './buttons.js'; +import { Button, type ButtonProps } from './button.js'; import { DesignSystem } from './design-system.js'; import { useDesignSystem } from './hooks/use-design-system.js'; -import { ArrowForward, MenuDropdownArrowIcon } from './icons.js'; +import { ArrowForwardIcon, MenuDropdownArrowIcon } from './icons.js'; import { Flex, type FlexProps } from './layout.js'; import type { Merge, ReactHTMLElementsHacked } from './types.js'; @@ -66,12 +66,16 @@ type MenuCommonProps = }>; export type MenuProps = Merge< - Omit, 'component'>, - MenuCommonProps<'div'> + ButtonProps<'div'>, + MenuCommonProps<'div'> & { component?: never; size?: never; onClick?: never } >; -export type MenuActivatorProps = PropsWithChildren< - Omit, 'onClick'> & { isNested?: boolean } +export type MenuActivatorProps = Merge< + ButtonProps<'div'>, + { + onClick?: never; + isNested?: boolean; + } >; const DefaultMenuActivator = forwardRef( @@ -83,7 +87,7 @@ const DefaultMenuActivator = forwardRef( component="div" iconEnd={} ref={forwardedRef} - icon={isNested && } + icon={isNested && } {...(isNested && { // Indicates this is a nested acting as a . role: 'menuitem', @@ -267,7 +271,7 @@ const MenuInner = forwardRef( const referenceRef = useMergeRefs([refs.setReference, forwardedRef]); - const activatorProps: MenuActivatorProps = { + const activatorProps = { className, ...getReferenceProps({ ...props, @@ -276,7 +280,7 @@ const MenuInner = forwardRef( }, }), children: label, - }; + } satisfies MenuActivatorProps; return ( diff --git a/lib/modal.css.ts b/lib/modal.css.ts index e70ad26..1468c24 100644 --- a/lib/modal.css.ts +++ b/lib/modal.css.ts @@ -1,14 +1,14 @@ import { style, type StyleRule } from '@vanilla-extract/css'; -import { precomputedViewportRules, type Viewport } from './core.css.js'; -import { genericVars } from './design-system.css.js'; +import { precomputedViewportRules, type Viewport } from './box.css.js'; import { typedObjectEntries, typedObjectFromEntries } from './utils.js'; +import { propsVars, globalVars } from './vars.css.js'; // WARN: ordering is important here as it affects the generated CSS // it should be the opposite order of viewportSizes (I think) const commonViewportRules: Record = { tablet: { width: '60vw', - padding: genericVars.space[6], + padding: propsVars.space[6], marginInline: 'auto', }, @@ -20,7 +20,7 @@ const commonViewportRules: Record = { desktop: { width: '35rem', - marginBlock: genericVars.space[8], + marginBlock: propsVars.space[8], marginInline: 'auto', }, @@ -49,8 +49,7 @@ export const dialogClass = style({ }, }); -export const modalClass = style({ - display: 'flex', +export const modalClassName = style({ position: 'fixed', top: 0, left: 0, @@ -58,7 +57,6 @@ export const modalClass = style({ width: '100vw', height: '100vh', zIndex: 100, - justifyContent: 'center', selectors: { // '&:not([open])': { // visibility: 'hidden', @@ -77,6 +75,14 @@ export const modalClass = style({ }, }); +export const modalInnerClassName = style({ + backgroundColor: globalVars.color.bgColor, + borderRadius: globalVars.border.radius, + outlineColor: globalVars.color.borderColor, + outlineWidth: globalVars.border.width, + outlineStyle: 'solid', +}); + export const commonDimensionsClass = style({ '@media': typedObjectFromEntries( typedObjectEntries(commonViewportRules).map(([viewport, rule]) => [ @@ -85,11 +91,3 @@ export const commonDimensionsClass = style({ ]), ), }); - -export const iconClass = style({ - aspectRatio: '1/1', -}); - -export const buttonClass = style({ - // aspectRatio: '1/1', -}); diff --git a/lib/modal.tsx b/lib/modal.tsx index 7ae5566..b95f83c 100644 --- a/lib/modal.tsx +++ b/lib/modal.tsx @@ -8,21 +8,20 @@ import { type ReactNode, } from 'react'; import { createPortal } from 'react-dom'; -import { ButtonIcon } from './buttons.js'; -import type { Falsy } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; +import { Box, type BoxProps } from './box.js'; +import { ButtonIcon } from './button.js'; import { DesignSystem } from './design-system.js'; import { useDesignSystem } from './hooks/use-design-system.js'; import { useStringLikeDetector } from './hooks/use-string-like.js'; import { CloseIcon } from './icons.js'; -import { Block, Inline } from './layout.js'; +import { Block, Flex, Inline } from './layout.js'; import { - buttonClass, commonDimensionsClass, dialogClass, - modalClass, + modalClassName, + modalInnerClassName, } from './modal.css.js'; -import type { Merge } from './types.js'; +import type { Falsy, Merge } from './types.js'; import { Heading } from './typography.js'; type InnerProps = PropsWithChildren<{ @@ -53,7 +52,12 @@ const ModalInner: FC = ({ const isStringLike = useStringLikeDetector(); return ( - + {isStringLike(heading) ? {heading} : heading} {dismissable && ( @@ -61,7 +65,7 @@ const ModalInner: FC = ({ close('dismiss')} type="submit" - className={buttonClass} + variant="invisible" value="close" label="close" autoFocus={false} @@ -128,14 +132,18 @@ export const Modal = forwardRef( return createPortal( - + - + , document.body, ); diff --git a/lib/panel.css.ts b/lib/panel.css.ts new file mode 100644 index 0000000..f5d404a --- /dev/null +++ b/lib/panel.css.ts @@ -0,0 +1,11 @@ +import { style } from '@vanilla-extract/css'; +import { globalVars, panelVars } from './vars.css.js'; + +export const panelClassName = style({ + borderColor: globalVars.color.muted.borderColor, + borderStyle: 'solid', + borderWidth: globalVars.border.width, + borderRadius: globalVars.border.radius, + paddingBlock: panelVars.padding.block, + paddingInline: panelVars.padding.inline, +}); diff --git a/lib/panel.tsx b/lib/panel.tsx new file mode 100644 index 0000000..71ea587 --- /dev/null +++ b/lib/panel.tsx @@ -0,0 +1,10 @@ +import { Block, type FlexProps } from './layout.js'; +import { panelClassName } from './panel.css.js'; +import type { ReactHTMLElementsHacked } from './react-html-elements.js'; + +export const Panel = ({ + className, + ...props +}: FlexProps) => ( + +); diff --git a/lib/purpose.css.ts b/lib/purpose.css.ts new file mode 100644 index 0000000..0929433 --- /dev/null +++ b/lib/purpose.css.ts @@ -0,0 +1,32 @@ +import { createGlobalThemeContract } from '@vanilla-extract/css'; +import { createGlobalThemeMapFn } from './css-helpers.js'; + +export type PurposeVariant = + | 'default' + | 'info' + | 'critical' + | 'positive' + | 'attention'; + +const purposeVariantVarsShape = { + bgColor: '', + fgColor: '', + borderColor: '', +}; + +const purposeVariantTypes = { + ...purposeVariantVarsShape, + muted: purposeVariantVarsShape, + // emphasis: purposeVariantVarsShape, +}; + +export const purposeVariantVars = createGlobalThemeContract( + { + info: purposeVariantTypes, + critical: purposeVariantTypes, + default: purposeVariantTypes, + positive: purposeVariantTypes, + attention: purposeVariantTypes, + } satisfies Record, + createGlobalThemeMapFn('purpose'), +); diff --git a/lib/reset.css.ts b/lib/reset.css.ts index 15942f4..ede870a 100644 --- a/lib/reset.css.ts +++ b/lib/reset.css.ts @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { style, globalStyle } from '@vanilla-extract/css'; export const resetClass = style({}); diff --git a/lib/scss/capsize.scss b/lib/scss/capsize.scss new file mode 100644 index 0000000..96af10b --- /dev/null +++ b/lib/scss/capsize.scss @@ -0,0 +1,105 @@ +// capsize.scss +@use 'sass:map'; +@use 'sass:math'; + +$font-metrics: ( + capHeight: 1456, + ascent: 1900, + descent: -500, + lineGap: 0, + unitsPerEm: 2048, +) !default; + +$precision: 4; +$prevent-collapse: 0.05; + +@function to-scale($value, $font-size) { + @return math.div($value, $font-size); +} + +@function leading-trim($value, $specified-line-height-offset, $font-size) { + @return $value - to-scale($specified-line-height-offset, $font-size) + + to-scale($prevent-collapse, $font-size); +} + +@function round-to($float, $decimal) { + $pow: math.pow(10, $decimal); + @return math.div(round($float * $pow), $pow); +} + +@function strip-unit($number) { + @if type-of($number) == 'number' and not unitless($number) { + @return math.div($number, ($number * 0 + 1)); + } + + @return $number; +} + +@mixin capsize($size-index, $font-size, $line-height) { + --text-size-#{$size-index}-fontSize: #{$font-size}; + --text-size-#{$size-index}-lineHeight: #{$line-height}; + + $font-size: strip-unit($font-size); + $line-height: strip-unit($line-height); + $absolute-descent: math.abs(map.get($font-metrics, 'descent')); + $cap-height-scale: math.div( + map.get($font-metrics, 'capHeight'), + map.get($font-metrics, 'unitsPerEm') + ); + $descent-scale: math.div( + $absolute-descent, + map.get($font-metrics, 'unitsPerEm') + ); + $ascent-scale: math.div( + map.get($font-metrics, 'ascent'), + map.get($font-metrics, 'unitsPerEm') + ); + $line-gap-scale: math.div( + map.get($font-metrics, 'lineGap'), + map.get($font-metrics, 'unitsPerEm') + ); + + $content-area: map.get($font-metrics, 'ascent') + + map.get($font-metrics, 'lineGap') + $absolute-descent; + $line-height-scale: math.div( + $content-area, + map.get($font-metrics, 'unitsPerEm') + ); + $line-height-normal: $line-height-scale * $font-size; + + $specified-line-height-offset: if( + $line-height, + math.div($line-height-normal - $line-height, 2), + 0 + ); + + $margin-top: #{round-to( + leading-trim( + $ascent-scale - $cap-height-scale + math.div($line-gap-scale, 2), + $specified-line-height-offset, + $font-size + ) * -1, + $precision + )}em; + + $margin-bottom: #{round-to( + leading-trim( + $descent-scale + math.div($line-gap-scale, 2), + $specified-line-height-offset, + $font-size + ) * -1, + $precision + )}em; + + $font-size: #{round-to($font-size, $precision)}px; + $line-height: if( + $line-height, + #{round-to($line-height, $precision)}px, + 'normal' + ); + + --text-capSize-#{$size-index}-fontSize: #{$font-size}; + --text-capSize-#{$size-index}-lineHeight: #{$line-height}; + --text-capSize-#{$size-index}-baselineTrim: #{$margin-top}; + --text-capSize-#{$size-index}-capHeightTrim: #{$margin-bottom}; +} diff --git a/lib/scss/defaults.scss b/lib/scss/defaults.scss new file mode 100644 index 0000000..5c6d598 --- /dev/null +++ b/lib/scss/defaults.scss @@ -0,0 +1,7 @@ +@use './open-props-scss' as op; + +:root { + --control-borderRadius: 0.25em; // em as it needs to be based on font size + --control-borderWidth: #{op.$border-size-1}; + --control-outlineWidth: #{op.$border-size-1}; +} diff --git a/lib/switch.tsx b/lib/switch.tsx new file mode 100644 index 0000000..ba4eb91 --- /dev/null +++ b/lib/switch.tsx @@ -0,0 +1,25 @@ +import { Children, type ReactNode } from 'react'; +import { isValidElementOfType } from './utils.js'; + +export const Case = (props: { value: unknown; children: ReactNode }) => + props.children; + +export const Switch = ({ + predicate, + children, +}: { + predicate: boolean | ((value: unknown) => boolean); + children: ReactNode[]; +}) => + Children.map(children, (child) => { + if (isValidElementOfType(child, Case)) { + const theOne = + typeof predicate === 'function' + ? predicate(child.props.value) + : predicate === child.props.value; + if (theOne) { + return child; + } + } + return null; + }); diff --git a/src/fonts.css b/lib/themes/generic.css.ts similarity index 100% rename from src/fonts.css rename to lib/themes/generic.css.ts diff --git a/lib/tooltip.css.ts b/lib/tooltip.css.ts index dc4abf4..f4aed8d 100644 --- a/lib/tooltip.css.ts +++ b/lib/tooltip.css.ts @@ -1,26 +1,14 @@ -// eslint-disable-next-line import/no-extraneous-dependencies import { style } from '@vanilla-extract/css'; -import { fontSizeVariants } from './typography.css.js'; +import { textVariantVars } from './typography.css.js'; +import { propsVars, globalVars } from './vars.css.js'; -export const tooltipClass = style([ - fontSizeVariants[0], - { - position: 'absolute', - top: '0', - left: '0', - width: 'max-content', - }, -]); - -// Used to position the tooltip arrow in javascript, depending on the orientation -/* export const arrowOffsetVar = createVar(); - -export const tooltipArrowClass = style({ - vars: { - [arrowOffsetVar]: calc.negate(genericVars.space[4]), - }, - position: 'absolute', - aspectRatio: '1/1', - height: genericVars.space[5], - clipPath: 'polygon(0 0, 100% 0, 50% 100%)', -}); */ +export const tooltipClassName = style({ + width: 'max-content', + paddingBlock: propsVars.space[2], + paddingInline: propsVars.space[3], + backgroundColor: globalVars.color.fgColor, + color: globalVars.color.bgColor, + borderRadius: globalVars.border.radius, + borderWidth: globalVars.border.width, + fontSize: textVariantVars.size['00'].fontSize, +}); diff --git a/lib/tooltip.tsx b/lib/tooltip.tsx index fb3e4c7..a4b0824 100644 --- a/lib/tooltip.tsx +++ b/lib/tooltip.tsx @@ -9,9 +9,8 @@ import { type PropsWithChildren, type ReactNode, } from 'react'; -import { paddingVariants, roundedVariants } from './core.css.js'; import { useTooltipState } from './hooks/use-tooltip-state.js'; -import { tooltipClass } from './tooltip.css.js'; +import { tooltipClassName } from './tooltip.css.js'; export type TooltipProps = PropsWithChildren<{ content: ReactNode; @@ -19,27 +18,11 @@ export type TooltipProps = PropsWithChildren<{ initialPlacement?: Placement; }>; -/* const staticSide: Record = { - top: 'bottom', - right: 'left', - bottom: 'top', - left: 'right', -}; */ - const TooltipActual = forwardRef< HTMLElement, PropsWithChildren> >(({ className, ...props }, ref) => ( - + )); export const Tooltip: FC = ({ @@ -48,25 +31,14 @@ export const Tooltip: FC = ({ initialOpen = false, initialPlacement, }) => { - const { - refs, - floatingStyles, - open, - - getReferenceProps, - getFloatingProps, - // placement, - // arrowRef, - // middlewareData: { arrow: { x: arrowX, y: arrowY } = {} }, - } = useTooltipState({ - initialOpen, - ...(initialPlacement && { placement: initialPlacement }), - }); + const { refs, floatingStyles, open, getReferenceProps, getFloatingProps } = + useTooltipState({ + initialOpen, + ...(initialPlacement && { placement: initialPlacement }), + }); const child = isValidElement(children) ? children : {children}; - // const arrowPlacement = placement.split('-')[0] as Side; - return ( <> {cloneElement(child, { @@ -80,15 +52,6 @@ export const Tooltip: FC = ({ style={floatingStyles} {...getFloatingProps()} > - {/* */} {content} )} diff --git a/lib/types.ts b/lib/types.ts index b54c3ef..6f3b41b 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,3 +2,7 @@ export type Merge = Omit & B; export type { ReactHTMLAttributesHacked } from './react-html-attributes.js'; export type { ReactHTMLElementsHacked } from './react-html-elements.js'; + +// accepting null means we can skip default assignments and specifically +// disable when consuming +export type Falsy = false | null | undefined; diff --git a/lib/typography.css.ts b/lib/typography.css.ts index 888c38c..a97809d 100644 --- a/lib/typography.css.ts +++ b/lib/typography.css.ts @@ -1,146 +1,122 @@ -import { createTextStyle } from '@capsizecss/vanilla-extract'; +import { createStyleObject } from '@capsizecss/core'; import { - createThemeContract, - createVar, + createGlobalThemeContract, style, styleVariants, - type StyleRule, } from '@vanilla-extract/css'; -import { genericVars } from './design-system.css.js'; +import { createGlobalThemeMapFn } from './css-helpers.js'; +import { globalVars } from './vars.css.js'; + +export type FontSize = + | 'body' + | 'small' + | '00' + | '0' + | '1' + | '2' + | '3' + | '4' + | '5' + | '6'; + +export type FontWeight = 'light' | 'normal' | 'medium' | 'semibold' | 'bold'; -export type HeadingLevel = '1' | '2' | '3' | '4' | '5' | '6'; +export type LineHeight = 'normal' | 'paragraph' | 'heading'; -export const currentCapHeight = createVar(); -export const lineGap = createVar(); -export const lineHeightRatio = createVar(); +export type TextWrap = 'pretty' | 'balance' | 'nowrap'; -export type FontSize = '00' | '0' | '1' | '2' | '3' | '4' | '5' | '6'; -export type FontWeight = keyof typeof genericVars.text.weight; -export type LineHeight = 'normal' | 'paragraph' | 'heading'; +const capSizeShape = { + fontSize: '', + lineHeight: '', + capHeightTrim: '', + baselineTrim: '', +}; -const fontThemeVarsShape = { - capHeight: 'cap-height', - values: { - fontSize: 'font-size', - lineHeight: 'line-height', - capHeightTrim: 'cap-height-trim', - baselineTrim: 'baseline-trim', - }, +const fontSizeShape = { + fontSize: '', + lineHeight: '', }; -export const fontThemeVars = createThemeContract({ - '00': fontThemeVarsShape, - '0': fontThemeVarsShape, - '1': fontThemeVarsShape, - '2': fontThemeVarsShape, - '3': fontThemeVarsShape, - '4': fontThemeVarsShape, - '5': fontThemeVarsShape, - '6': fontThemeVarsShape, -}); +export const textVariantVars = createGlobalThemeContract( + { + lineHeight: { + normal: '', + paragraph: '', + heading: '', + } satisfies Record, + fontWeight: { + light: '', + normal: '', + medium: '', + semibold: '', + bold: '', + } satisfies Record, + size: { + body: fontSizeShape, + small: fontSizeShape, + '00': fontSizeShape, + '0': fontSizeShape, + '1': fontSizeShape, + '2': fontSizeShape, + '3': fontSizeShape, + '4': fontSizeShape, + '5': fontSizeShape, + '6': fontSizeShape, + } satisfies Record, + capSize: { + body: capSizeShape, + small: capSizeShape, + '00': capSizeShape, + '0': capSizeShape, + '1': capSizeShape, + '2': capSizeShape, + '3': capSizeShape, + '4': capSizeShape, + '5': capSizeShape, + '6': capSizeShape, + } satisfies Record, + }, + createGlobalThemeMapFn('text'), +); -export const secondaryClass = style({ - // color: oklch(contrastSchemeVars.swatch.m8.l, 0, toneH), - opacity: 0.8, +export const secondaryClassName = style({ + color: globalVars.color.muted.fgColor, }); -export const strongClass = style({ - fontWeight: genericVars.text.weight.semiBold, +export const strongClassName = style({ + fontWeight: textVariantVars.fontWeight.medium, }); -export const codeClass = style({ +export const codeClassName = style({ fontFamily: 'monospace', }); -export const fontSizeVariantTextStyles = styleVariants( - fontThemeVars, - (vars) => [createTextStyle(vars.values)], +export const fontWeightVariantClassNames = styleVariants( + textVariantVars.fontWeight, + (value) => ({ + fontWeight: value, + }), ); -export const capSizeVariantVars = styleVariants(fontThemeVars, (vars) => ({ - vars: { [currentCapHeight]: vars.capHeight }, -})); - -export const capSizeVariantTextStyles = styleVariants(fontThemeVars, (vars) => [ - createTextStyle(vars.values), -]); - -export const capSizeVariants = styleVariants(fontThemeVars, (_, key) => [ - capSizeVariantVars[key], - fontSizeVariantTextStyles[key], -]); - -export const fontSizeVariants = styleVariants(fontThemeVars, (_, key) => [ - capSizeVariantVars[key], - fontSizeVariantTextStyles[key], -]); - -// /////////////////////////// - -export const fontWeightVariants = styleVariants( - genericVars.text.weight, - (value) => [ - { - fontWeight: value, - fontVariationSettings: `'wght' ${value}`, - }, - ], +export const fontSizeVariantClassNames = styleVariants( + textVariantVars.size, + (value) => ({ + fontSize: value.fontSize, + }), ); -export const lineHeightVariants = styleVariants( - genericVars.text.lineHeight, - (value) => [ - { - lineHeight: value, - }, - ], +export const capSizeVariantClassNames = styleVariants( + textVariantVars.capSize, + createStyleObject, ); -const levelVariants: Record> = { - '1': [ - { - fontWeight: genericVars.text.weight.bold, - letterSpacing: '-0.05em', - }, - ], - '2': [ - { - fontWeight: genericVars.text.weight.bold, - letterSpacing: '-0.05em', - }, - ], - '3': [ - { - fontWeight: genericVars.text.weight.bold, - letterSpacing: '-0.05em', - }, - ], - '4': [ - { - fontWeight: genericVars.text.weight.semiBold, - letterSpacing: '-0.05em', - }, - ], - '5': [ - { - fontWeight: genericVars.text.weight.medium, - }, - ], - '6': [ - { - fontWeight: genericVars.text.weight.medium, - }, - ], -}; // satisfies Record; +export const lineHeightVariantClassNames = styleVariants( + textVariantVars.lineHeight, + (value) => ({ + lineHeight: value, + }), +); -const headingClassName = style({ - vars: { - // [toneL]: contrastSchemeVars.foreground0.l, - }, - textWrap: 'balance', +export const textClassName = style({ + color: globalVars.color.fgColor, }); - -export const headingVariantClasses = styleVariants(levelVariants, (rules) => [ - headingClassName, - ...rules, -]); diff --git a/lib/typography.tsx b/lib/typography.tsx index 1fe7b3e..43d93bb 100644 --- a/lib/typography.tsx +++ b/lib/typography.tsx @@ -1,115 +1,116 @@ +import { forwardRef, type FC, type ForwardedRef } from 'react'; +import { Box, type BoxProps } from './box.js'; +import type { Falsy, Merge, ReactHTMLElementsHacked } from './types.js'; import { - forwardRef, - type FC, - type ForwardedRef, - type PropsWithChildren, -} from 'react'; -import type { Falsy } from './core.css.js'; -import { Box, type BoxProps } from './core.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; -import { - codeClass, - headingVariantClasses, - secondaryClass, - type HeadingLevel, + codeClassName, + secondaryClassName, + type FontSize, + type FontWeight, + type LineHeight, + type TextWrap, } from './typography.css.js'; -type CommonTextProps = { +export type HeadingLevel = '1' | '2' | '3' | '4' | '5' | '6'; + +export type { FontSize, FontWeight, LineHeight, TextWrap }; + +export type CommonTextProps = { secondary?: true | Falsy; }; -export type TextProps = - PropsWithChildren< - Merge< - Omit, 'flexDirection' | 'flexWrap' | 'space' | 'overflow'>, - CommonTextProps - > +export type ParagraphProps = + Omit< + Merge, CommonTextProps>, + 'flexDirection' | 'flexWrap' | 'space' | 'overflow' | 'capSize' >; -export const Text = forwardRef( - ( - { - component = 'span', - className, - secondary, - textOverflow, - children, - ...props - }: TextProps, - forwardedRef: ForwardedRef, - ) => ( - - {textOverflow && children ? ( - - {children} - - ) : ( - children - )} - - ), -); - -export const Strong: FC> = (props) => ( - -); - -export const Code: FC> = ({ className, ...props }) => ( - -); +export type ExactTextProps = + Omit< + Merge, CommonTextProps>, + 'flexDirection' | 'flexWrap' | 'space' | 'overflow' | 'fontSize' + >; -export const Secondary: FC> = ({ className, ...props }) => ( - -); +export type HeadingProps = ParagraphProps & { + level?: HeadingLevel; +}; function headingProps(level: HeadingLevel): HeadingProps { switch (level) { case '1': - return { fontSize: '5' }; + return { fontSize: '5', fontWeight: 'bold' }; case '2': - return { fontSize: '4' }; + return { fontSize: '4', fontWeight: 'bold' }; case '3': - return { fontSize: '3' }; + return { fontSize: '3', fontWeight: 'semibold' }; case '4': - return { fontSize: '2' }; + return { fontSize: '2', fontWeight: 'semibold' }; case '5': - return { fontSize: '1', secondary: true }; + return { fontSize: '1', secondary: true, fontWeight: 'medium' }; case '6': - return { fontSize: '0', secondary: true }; + return { fontSize: '0', secondary: true, fontWeight: 'medium' }; default: return {}; } } -export type HeadingProps = PropsWithChildren< - Merge< - TextProps<'h1' | 'h2' | 'h3' | 'h4' | 'h5'>, - { - level?: HeadingLevel; - } - > ->; +export const ExactText = forwardRef( + ( + { component = 'span', className, secondary, ...props }: ExactTextProps, + forwardedRef: ForwardedRef, + ) => ( + + ), +); export const Heading = forwardRef( - ({ level = '3', className, ...props }, ref) => ( - { + const { secondary: headingIsSecondary, ...rest } = headingProps(level); + return ( + + ); + }, +); + +export const Paragraph = forwardRef( + ({ className, secondary, ...props }, ref) => ( + ), ); -export const Paragraph = forwardRef( - ({ className, ...props }, ref) => ( - - ), +export const Strong: FC> = (props) => ( + +); + +export const Code: FC> = ({ className, ...props }) => ( + +); + +export const Secondary: FC> = ({ className, ...props }) => ( + ); diff --git a/lib/utils.ts b/lib/utils.ts index d943fe9..de46ee3 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -4,6 +4,7 @@ import { cloneElement, Fragment, isValidElement, + type JSXElementConstructor, type ComponentProps, type FC, type ReactElement, @@ -54,7 +55,7 @@ function maybeSuffix(value: string | number, suffix: string): string { return `${value}${suffix}`; } -export function hslValues( +function hslValues( h: string | number, s: string | number, l: string | number, @@ -77,15 +78,6 @@ export function hsl( )})`; } -export function lchValues( - l: string | number, - c: string | number, - h: string | number, - a: string | number = 1, -) { - return [l, c, h, ...(a.toString() !== '1' ? [a] : [])].join(' '); -} - export function oklch( l: string | number, c: string | number, @@ -95,11 +87,12 @@ export function oklch( return `oklch(${hslValues(maybeSuffix(l, '%'), c, h, a)})`; } -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isValidElementOfType>( - child: ReactNode, - type: T, -): child is ReactElement> { +export function isValidElementOfType< + T extends + | keyof JSX.IntrinsicElements + // eslint-disable-next-line @typescript-eslint/no-explicit-any + | JSXElementConstructor, +>(child: ReactNode, type: T): child is ReactElement> { return isValidElement(child) && child.type === type; } diff --git a/lib/vars.css.ts b/lib/vars.css.ts new file mode 100644 index 0000000..e43503d --- /dev/null +++ b/lib/vars.css.ts @@ -0,0 +1,225 @@ +import { + createGlobalThemeContract, + type MapLeafNodes, +} from '@vanilla-extract/css'; +import openPropsTokens from 'open-props/style-dictionary-tokens'; +import { createGlobalThemeMapFn } from './css-helpers.js'; + +export const globalVarsMapFnPrefix = ''; +export const globalVars = createGlobalThemeContract( + { + color: { + brand: '', + accent: '', + fgColor: '', + bgColor: '', + borderColor: '', + muted: { + fgColor: '', + bgColor: '', + borderColor: '', + }, + emphasis: { + fgColor: '', + bgColor: '', + borderColor: '', + }, + }, + border: { + width: '', + radius: '', + }, + }, + createGlobalThemeMapFn(globalVarsMapFnPrefix), +); +// this is just a partial definition for the borders +export const globalTokens = { + border: { + radius: openPropsTokens.radius[2].value, + width: openPropsTokens.border.size[1].value, + }, +} satisfies MapLeafNodes, string>; + +/** + * Props vars + */ +export const propsVarsMapFnPrefix = 'props'; +export const propsVars = createGlobalThemeContract( + { + border: { + width: { + '0': '', + '1': '', + '2': '', + '3': '', + '4': '', + '5': '', + '6': '', + '7': '', + }, + }, + radius: { + 0: '', + 1: '', + 2: '', + 3: '', + 50: '', + }, + space: { + '000': '', + '00': '', + '0': '', + '1': '', + '2': '', + '3': '', + '4': '', + '5': '', + '6': '', + '7': '', + '8': '', + '9': '', + '10': '', + '11': '', + '12': '', + '13': '', + '14': '', + '15': '', + '16': '', + }, + }, + createGlobalThemeMapFn(propsVarsMapFnPrefix), +); +export const propsTokens = { + border: { + width: { + 0: '0', + 1: '0.05rem', + 2: '0.15rem', + 3: '0.2rem', + 4: '0.3rem', + 5: '0.5rem', + 6: '0.75rem', + 7: '1rem', + }, + }, + radius: { + // these are tuned to be distinguished at DPR3 but may not be different at + // lower densities they are rem so they dont scale with text size NOTE: we + // may need some `em` ones if we need fully curved buttons "pill" style + 0: '0', + 1: '0.125rem', + 2: '0.25rem', + 3: '0.5rem', + 50: '50%', + }, + space: { + '000': '-.5rem', + '00': '-.25rem', + '0': '0rem', + '1': '.125rem', + '2': '.25rem', + '3': '.375rem', + '4': '.5rem', + '5': '.625rem', + '6': '.75rem', + '7': '1rem', + '8': '1.25rem', + '9': '1.5rem', + '10': '1.75rem', + '11': '2rem', + '12': '3rem', + '13': '5rem', + '14': '7.5rem', + '15': '10rem', + '16': '15rem', + }, +} satisfies MapLeafNodes; + +/** + * Callout vars + */ +export const calloutVarsMapFnPrefix = 'callout'; +export const calloutVars = createGlobalThemeContract( + { + // border: { + // radius: '', + // width: '', + // }, + padding: '', + }, + createGlobalThemeMapFn(calloutVarsMapFnPrefix), +); + +/** + * Button vars + */ +export const buttonVarsMapFnPrefix = 'button'; +export const buttonVars = createGlobalThemeContract( + { + // border: { + // radius: '', + // width: '', + // }, + }, + createGlobalThemeMapFn(buttonVarsMapFnPrefix), +); + +/** + * Badge vars + */ +export const badgeVarsMapFnPrefix = 'badge'; +export const badgeVars = createGlobalThemeContract( + { + // border: { + // radius: '', + // width: '', + // }, + }, + createGlobalThemeMapFn(badgeVarsMapFnPrefix), +); + +/** + * Panel vars + */ +export const panelVarsMapFnPrefix = 'panel'; +export const panelVars = createGlobalThemeContract( + { + // border: { + // radius: '', + // width: '', + // }, + padding: { + inline: '', + block: '', + }, + }, + createGlobalThemeMapFn(panelVarsMapFnPrefix), +); +export const panelTokens = { + padding: { + inline: openPropsTokens.size[3].value, + block: propsVars.space['4'], + }, +} satisfies MapLeafNodes; + +/** + * Form control vars + */ +export const formControlVarsMapFnPrefix = 'formControl'; +export const formControlVars = createGlobalThemeContract( + { + // border: { + // radius: '', + // width: '', + // }, + outline: { + width: '', + }, + }, + createGlobalThemeMapFn(formControlVarsMapFnPrefix), +); +export const formControlTokens = { + outline: { + width: openPropsTokens.border.size[1].value, + }, +} satisfies MapLeafNodes; diff --git a/lib/vars.ts b/lib/vars.ts index 0c87053..7c2f253 100644 --- a/lib/vars.ts +++ b/lib/vars.ts @@ -1,5 +1,46 @@ -// eslint-disable-next-line import/no-extraneous-dependencies -export { setElementVars, assignInlineVars } from '@vanilla-extract/dynamic'; +import { + formControlTokens, + formControlVars, + globalTokens, + globalVars, + panelTokens, + panelVars, + propsTokens, + propsVars, +} from './vars.css.js'; -export { genericVars } from './design-system.css.js'; -export { fontThemeVars } from './typography.css.js'; +export { + badgeVars, + badgeVarsMapFnPrefix, + buttonVars, + buttonVarsMapFnPrefix, + formControlTokens, + formControlVarsMapFnPrefix, + globalTokens, + globalVars, + globalVarsMapFnPrefix, + panelTokens, + panelVars, + panelVarsMapFnPrefix, + propsTokens, + propsVars, + propsVarsMapFnPrefix, +} from './vars.css.js'; + +export const vars = { + global: { + border: globalVars.border, + }, + panel: panelVars, + formControl: formControlVars, + props: propsVars, +}; + +export const tokens = { + global: { + border: globalTokens.border, + }, + panel: panelTokens, + formControl: formControlTokens, + props: propsTokens, +}; diff --git a/lib/virtual.tsx b/lib/virtual.tsx index 4e06b1f..3cddb74 100644 --- a/lib/virtual.tsx +++ b/lib/virtual.tsx @@ -8,8 +8,8 @@ import { type SyntheticEvent, } from 'react'; import { useThrottledCallback } from './hooks/use-throttled-callback.js'; -import { Block, type BlockProps } from './layout.js'; -import type { Merge, ReactHTMLElementsHacked } from './types.js'; +import { Block, type FlexProps } from './layout.js'; +import type { ReactHTMLElementsHacked } from './types.js'; import { innerClassName, itemClassName, @@ -18,18 +18,15 @@ import { export type VirtualizedListProps< T extends keyof ReactHTMLElementsHacked = 'div', -> = Merge< - BlockProps, - { - numItems: number; - renderItem: ( - props: { index: number } & HTMLAttributes, - ) => ReactNode; - itemHeight: number | ((props: { index: number }) => number); - listHeight: number; - overscan?: number; - } ->; +> = FlexProps & { + numItems: number; + renderItem: ( + props: { index: number } & HTMLAttributes, + ) => ReactNode; + itemHeight: number | ((props: { index: number }) => number); + listHeight: number; + overscan?: number; +}; export const VirtualizedList = forwardRef( ( diff --git a/package.json b/package.json index 071a43a..d0ede5d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "type": "module", "imports": { "#vars": { - "types": "./dist/lib/vars.js", + "types": "./dist/lib/vars.d.ts", "default": "./build/vars.js" } }, @@ -16,28 +16,24 @@ "types": "./dist/lib/main.d.ts", "default": "./build/main.js" }, - "./css": { - "default": "./build/style.css" - }, - "./vars": { - "types": "./dist/lib/vars.js", - "default": "./build/vars.js" - }, "./hooks": { "types": "./dist/lib/hooks/main.js", "default": "./build/hooks.js" }, - "./tokens.scss": { - "default": "./build/tokens.scss" + "./css": "./build/style.css", + "./css/global": "./build/global.css", + "./scss/global": "./build/global.scss", + "./scss/capsize": { + "sass": "./lib/scss/capsize.scss" }, - "./reference": { - "types": "./dist/src/reference-impl/main.js", - "default": "./build/reference-impl.js" + "./vanilla-extract": { + "types": "./dist/lib/vars.d.ts", + "default": "./build/vars.js" } }, "files": [ "dist/lib/**/*.d.ts", - "dist/src/reference-impl/**", + "lib/scss/**/*.scss", "build/*.js", "build/*.js.map", "build/*.css", @@ -49,71 +45,84 @@ }, "dependencies": { "@floating-ui/dom": "^1.6.5", - "@floating-ui/react": "^0.26.16", + "@floating-ui/react": "^0.26.17", "@floating-ui/react-dom": "^2.1.0", + "@vanilla-extract/dynamic": "^2.1.1", "clsx": "^2.1.1", "js-cookie": "^3.0.5" }, "devDependencies": { "@block65/bundlesize": "^1.0.1", "@block65/eslint-config": "^12.0.1", - "@block65/mrr": "6.0.1-0", + "@block65/mrr": "^6.0.0", + "@capsizecss/core": "^4.1.2", "@capsizecss/metrics": "^3.2.0", "@capsizecss/vanilla-extract": "^2.0.0", "@commitlint/config-conventional": "^19.2.2", + "@emotion/hash": "^0.9.1", "@testing-library/dom": "^10.1.0", - "@testing-library/jest-dom": "^6.4.5", + "@testing-library/jest-dom": "^6.4.6", "@testing-library/react": "^16.0.0", "@testing-library/user-event": "^14.5.2", "@tsconfig/node22": "^22.0.0", "@tsconfig/strictest": "^2.0.5", "@tsconfig/vite-react": "^3.0.2", "@types/js-cookie": "^3.0.6", - "@types/node": "^20.14.2", + "@types/node": "^20.14.7", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", - "@vanilla-extract/css": "^1.15.2", + "@typescript-eslint/eslint-plugin": "^7.13.1", + "@typescript-eslint/parser": "^7.13.1", + "@vanilla-extract/css": "^1.15.3", "@vanilla-extract/css-utils": "^0.1.4", - "@vanilla-extract/dynamic": "^2.1.1", "@vanilla-extract/sprinkles": "^1.6.2", - "@vanilla-extract/vite-plugin": "^4.0.10", - "@vitejs/plugin-react": "^4.3.0", + "@vanilla-extract/vite-plugin": "^4.0.11", + "@vitejs/plugin-react": "^4.3.1", "change-case": "^5.4.4", "conventional-changelog-cli": "^5.0.0", "eslint": "^8.57.0", "eslint-plugin-formatjs": "^4.13.3", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsx-a11y": "^6.8.0", + "eslint-plugin-jsx-a11y": "^6.9.0", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-react": "^7.34.2", + "eslint-plugin-react": "^7.34.3", "eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-refresh": "^0.4.7", "husky": "^9.0.11", "jsdom": "^24.1.0", "lorem-ipsum": "^2.0.8", - "prettier": "^3.3.1", + "open-props": "^1.7.4", + "prettier": "^3.3.2", "react": "^18.3.1", "react-dom": "^18.3.1", "react-intl": "^6.6.8", + "sass": "^1.77.6", "the-new-css-reset": "^1.11.2", - "type-fest": "^4.19.0", - "typescript": "^5.4.5", - "vite": "^5.2.12", + "type-fest": "^4.20.1", + "typescript": "^5.5.2", + "vite": "^5.3.1", "vitest": "^1.6.0" }, "peerDependencies": { - "@types/react": "^18.2.37", - "@types/react-dom": "^18.2.15", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-intl": "^6.5.5" + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-intl": "^6.6.8", + "@vanilla-extract/css": "^1.15.3" }, "peerDependenciesMeta": { "react-intl": { "optional": true + }, + "@vanilla-extract/css": { + "optional": true } }, - "packageManager": "pnpm@9.1.1+sha512.14e915759c11f77eac07faba4d019c193ec8637229e62ec99eefb7cf3c3b75c64447882b7c485142451ee3a6b408059cdfb7b7fa0341b975f12d0f7629c71195" + "packageManager": "pnpm@9.3.0+sha512.ee7b93e0c2bd11409c6424f92b866f31d3ea1bef5fbe47d3c7500cdc3c9668833d2e55681ad66df5b640c61fa9dc25d546efa54d76d7f8bf54b13614ac293631", + "pnpm": { + "patchedDependencies": { + "@vanilla-extract/css@1.15.3": "patches/@vanilla-extract__css@1.15.3.patch" + } + } } diff --git a/patches/@vanilla-extract__css@1.15.3.patch b/patches/@vanilla-extract__css@1.15.3.patch new file mode 100644 index 0000000..8eff30b --- /dev/null +++ b/patches/@vanilla-extract__css@1.15.3.patch @@ -0,0 +1,19 @@ +diff --git a/dist/vanilla-extract-css.cjs.d.ts b/dist/vanilla-extract-css.cjs.d.ts +index b5412c187b66dc3ebe93c32e2cc4e9aff043fa48..89815291f8f07698dd63f094f352d83c44e1e31b 100644 +--- a/dist/vanilla-extract-css.cjs.d.ts ++++ b/dist/vanilla-extract-css.cjs.d.ts +@@ -1,11 +1,11 @@ + import { Properties, AtRule } from 'csstype'; + +-type CSSVarFunction = `var(--${string})` | `var(--${string}, ${string | number})`; +-type Contract = { ++export type CSSVarFunction = `var(--${string})` | `var(--${string}, ${string | number})`; ++export type Contract = { + [key: string]: CSSVarFunction | null | Contract; + }; + type Primitive = string | boolean | number | null | undefined; +-type MapLeafNodes = { ++export type MapLeafNodes = { + [Prop in keyof Obj]: Obj[Prop] extends Primitive ? LeafType : Obj[Prop] extends Record ? MapLeafNodes : never; + }; + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7ff0aa4..9c8f254 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,11 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + '@vanilla-extract/css@1.15.3': + hash: vtudlxny3uthcq56uc3pnbvu2m + path: patches/@vanilla-extract__css@1.15.3.patch + importers: .: @@ -12,11 +17,14 @@ importers: specifier: ^1.6.5 version: 1.6.5 '@floating-ui/react': - specifier: ^0.26.16 - version: 0.26.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^0.26.17 + version: 0.26.17(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@floating-ui/react-dom': specifier: ^2.1.0 version: 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@vanilla-extract/dynamic': + specifier: ^2.1.1 + version: 2.1.1 clsx: specifier: ^2.1.1 version: 2.1.1 @@ -26,28 +34,34 @@ importers: devDependencies: '@block65/bundlesize': specifier: ^1.0.1 - version: 1.0.1(typescript@5.4.5) + version: 1.0.1(typescript@5.5.2) '@block65/eslint-config': specifier: ^12.0.1 - version: 12.0.1(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-formatjs@4.13.3(eslint@8.57.0))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react-refresh@0.4.7(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1)(typescript@5.4.5) + version: 12.0.1(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-formatjs@4.13.3(eslint@8.57.0))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react-refresh@0.4.7(eslint@8.57.0))(eslint-plugin-react@7.34.3(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2)(typescript@5.5.2) '@block65/mrr': - specifier: 6.0.1-0 - version: 6.0.1-0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^6.0.0 + version: 6.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@capsizecss/core': + specifier: ^4.1.2 + version: 4.1.2 '@capsizecss/metrics': specifier: ^3.2.0 version: 3.2.0 '@capsizecss/vanilla-extract': specifier: ^2.0.0 - version: 2.0.0(@vanilla-extract/css@1.15.2) + version: 2.0.0(@vanilla-extract/css@1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m)) '@commitlint/config-conventional': specifier: ^19.2.2 version: 19.2.2 + '@emotion/hash': + specifier: ^0.9.1 + version: 0.9.1 '@testing-library/dom': specifier: ^10.1.0 version: 10.1.0 '@testing-library/jest-dom': - specifier: ^6.4.5 - version: 6.4.5(vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0)) + specifier: ^6.4.6 + version: 6.4.6(vitest@1.6.0(@types/node@20.14.7)(jsdom@24.1.0)(sass@1.77.6)) '@testing-library/react': specifier: ^16.0.0 version: 16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -67,8 +81,8 @@ importers: specifier: ^3.0.6 version: 3.0.6 '@types/node': - specifier: ^20.14.2 - version: 20.14.2 + specifier: ^20.14.7 + version: 20.14.7 '@types/react': specifier: ^18.3.3 version: 18.3.3 @@ -76,29 +90,26 @@ importers: specifier: ^18.3.0 version: 18.3.0 '@typescript-eslint/eslint-plugin': - specifier: ^7.12.0 - version: 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) '@typescript-eslint/parser': - specifier: ^7.12.0 - version: 7.12.0(eslint@8.57.0)(typescript@5.4.5) + specifier: ^7.13.1 + version: 7.13.1(eslint@8.57.0)(typescript@5.5.2) '@vanilla-extract/css': - specifier: ^1.15.2 - version: 1.15.2 + specifier: ^1.15.3 + version: 1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m) '@vanilla-extract/css-utils': specifier: ^0.1.4 version: 0.1.4 - '@vanilla-extract/dynamic': - specifier: ^2.1.1 - version: 2.1.1 '@vanilla-extract/sprinkles': specifier: ^1.6.2 - version: 1.6.2(@vanilla-extract/css@1.15.2) + version: 1.6.2(@vanilla-extract/css@1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m)) '@vanilla-extract/vite-plugin': - specifier: ^4.0.10 - version: 4.0.10(@types/node@20.14.2)(vite@5.2.12(@types/node@20.14.2)) + specifier: ^4.0.11 + version: 4.0.11(@types/node@20.14.7)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.7)(sass@1.77.6)) '@vitejs/plugin-react': - specifier: ^4.3.0 - version: 4.3.0(vite@5.2.12(@types/node@20.14.2)) + specifier: ^4.3.1 + version: 4.3.1(vite@5.3.1(@types/node@20.14.7)(sass@1.77.6)) change-case: specifier: ^5.4.4 version: 5.4.4 @@ -113,16 +124,16 @@ importers: version: 4.13.3(eslint@8.57.0) eslint-plugin-import: specifier: ^2.29.1 - version: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + version: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) eslint-plugin-jsx-a11y: - specifier: ^6.8.0 - version: 6.8.0(eslint@8.57.0) + specifier: ^6.9.0 + version: 6.9.0(eslint@8.57.0) eslint-plugin-prettier: specifier: ^5.1.3 - version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1) + version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2) eslint-plugin-react: - specifier: ^7.34.2 - version: 7.34.2(eslint@8.57.0) + specifier: ^7.34.3 + version: 7.34.3(eslint@8.57.0) eslint-plugin-react-hooks: specifier: ^4.6.2 version: 4.6.2(eslint@8.57.0) @@ -138,9 +149,12 @@ importers: lorem-ipsum: specifier: ^2.0.8 version: 2.0.8 + open-props: + specifier: ^1.7.4 + version: 1.7.4 prettier: - specifier: ^3.3.1 - version: 3.3.1 + specifier: ^3.3.2 + version: 3.3.2 react: specifier: ^18.3.1 version: 18.3.1 @@ -149,22 +163,25 @@ importers: version: 18.3.1(react@18.3.1) react-intl: specifier: ^6.6.8 - version: 6.6.8(react@18.3.1)(typescript@5.4.5) + version: 6.6.8(react@18.3.1)(typescript@5.5.2) + sass: + specifier: ^1.77.6 + version: 1.77.6 the-new-css-reset: specifier: ^1.11.2 version: 1.11.2 type-fest: - specifier: ^4.19.0 - version: 4.19.0 + specifier: ^4.20.1 + version: 4.20.1 typescript: - specifier: ^5.4.5 - version: 5.4.5 + specifier: ^5.5.2 + version: 5.5.2 vite: - specifier: ^5.2.12 - version: 5.2.12(@types/node@20.14.2) + specifier: ^5.3.1 + version: 5.3.1(@types/node@20.14.7)(sass@1.77.6) vitest: specifier: ^1.6.0 - version: 1.6.0(@types/node@20.14.2)(jsdom@24.1.0) + version: 1.6.0(@types/node@20.14.7)(jsdom@24.1.0)(sass@1.77.6) packages: @@ -323,8 +340,8 @@ packages: eslint-plugin-unicorn: optional: true - '@block65/mrr@6.0.1-0': - resolution: {integrity: sha512-8FEz4h6MYcNEF/mxFYo+PjPbqh6zCieFfd3rvLL/9nAAtLdrWIzTz0Yuf4gKdrJEvV6ONN+VRa8VdEuyjMg0CA==} + '@block65/mrr@6.0.0': + resolution: {integrity: sha512-QWp0bqSWaJMELuOpcPJCAkXXvKhUnxW+gSf3mjfgSnGvgO26EmMprB9CGWj04njR/3YBDxCPTfw6scd82sPJOg==} engines: {node: '>=20.0.0'} peerDependencies: '@types/react': ^18.3.3 @@ -372,8 +389,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.20.2': - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} cpu: [ppc64] os: [aix] @@ -384,8 +401,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.20.2': - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -396,8 +413,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.20.2': - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -408,8 +425,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.20.2': - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -420,8 +437,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.20.2': - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -432,8 +449,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.20.2': - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -444,8 +461,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.20.2': - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -456,8 +473,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.20.2': - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -468,8 +485,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.20.2': - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -480,8 +497,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.20.2': - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -492,8 +509,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.20.2': - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -504,8 +521,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.20.2': - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -516,8 +533,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.20.2': - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -528,8 +545,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.20.2': - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -540,8 +557,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.20.2': - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -552,8 +569,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.20.2': - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -564,8 +581,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.20.2': - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -576,8 +593,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.20.2': - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -588,8 +605,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.20.2': - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -600,8 +617,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.20.2': - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -612,8 +629,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.20.2': - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -624,8 +641,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.20.2': - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -636,8 +653,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.20.2': - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -672,8 +689,8 @@ packages: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.26.16': - resolution: {integrity: sha512-HEf43zxZNAI/E781QIVpYSF3K2VH4TTYZpqecjdsFkjsaU1EbaWcM++kw0HXFffj7gDUcBFevX8s0rQGQpxkow==} + '@floating-ui/react@0.26.17': + resolution: {integrity: sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -721,6 +738,7 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -728,6 +746,7 @@ packages: '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead '@hutson/parse-repository-url@5.0.0': resolution: {integrity: sha512-e5+YUKENATs1JgYHMzTr2MW/NDcXGfYFAuOQU8gJgF/kEh4EqKgfGrfLI67bMD4tbhZVlkigz/9YYwWcbOFthg==} @@ -866,8 +885,8 @@ packages: resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} engines: {node: '>=18'} - '@testing-library/jest-dom@6.4.5': - resolution: {integrity: sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A==} + '@testing-library/jest-dom@6.4.6': + resolution: {integrity: sha512-8qpnGVincVDLEcQXWaHOf6zmlbwTKc6Us6PPu4CRnPXCzo2OGBS5cwgMMOWdxDpEz1mkbvXHpEy99M5Yvt682w==} engines: {node: '>=14', npm: '>=6', yarn: '>=1'} peerDependencies: '@jest/globals': '>= 28' @@ -935,6 +954,9 @@ packages: '@types/conventional-commits-parser@5.0.0': resolution: {integrity: sha512-loB369iXNmAZglwWATL+WRe+CRMmmBPtpolYzIebFaX4YA3x+BEfLqhUAV9WanycKI3TG1IMr5bMJDajDKLlUQ==} + '@types/dom-view-transitions@1.0.4': + resolution: {integrity: sha512-oDuagM6G+xPLrLU4KeCKlr1oalMF5mJqV5pDPMDVIEaa8AkUW00i6u+5P02XCjdEEUQJC9dpnxqSLsZeAciSLQ==} + '@types/eslint@8.56.10': resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} @@ -959,8 +981,8 @@ packages: '@types/node@17.0.45': resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} - '@types/node@20.14.2': - resolution: {integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==} + '@types/node@20.14.7': + resolution: {integrity: sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -980,8 +1002,8 @@ packages: '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@typescript-eslint/eslint-plugin@7.12.0': - resolution: {integrity: sha512-7F91fcbuDf/d3S8o21+r3ZncGIke/+eWk0EpO21LXhDfLahriZF9CGj4fbAetEjlaBdjdSm9a6VeXbpbT6Z40Q==} + '@typescript-eslint/eslint-plugin@7.13.1': + resolution: {integrity: sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: '@typescript-eslint/parser': ^7.0.0 @@ -991,8 +1013,8 @@ packages: typescript: optional: true - '@typescript-eslint/parser@7.12.0': - resolution: {integrity: sha512-dm/J2UDY3oV3TKius2OUZIFHsomQmpHtsV0FTh1WO8EKgHLQ1QCADUqscPgTpU+ih1e21FQSRjXckHn3txn6kQ==} + '@typescript-eslint/parser@7.13.1': + resolution: {integrity: sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1005,12 +1027,12 @@ packages: resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/scope-manager@7.12.0': - resolution: {integrity: sha512-itF1pTnN6F3unPak+kutH9raIkL3lhH1YRPGgt7QQOh43DQKVJXmWkpb+vpc/TiDHs6RSd9CTbDsc/Y+Ygq7kg==} + '@typescript-eslint/scope-manager@7.13.1': + resolution: {integrity: sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/type-utils@7.12.0': - resolution: {integrity: sha512-lib96tyRtMhLxwauDWUp/uW3FMhLA6D0rJ8T7HmH7x23Gk1Gwwu8UZ94NMXBvOELn6flSPiBrCKlehkiXyaqwA==} + '@typescript-eslint/type-utils@7.13.1': + resolution: {integrity: sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1023,8 +1045,8 @@ packages: resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/types@7.12.0': - resolution: {integrity: sha512-o+0Te6eWp2ppKY3mLCU+YA9pVJxhUJE15FV7kxuD9jgwIAa+w/ycGJBMrYDTpVGUM/tgpa9SeMOugSabWFq7bg==} + '@typescript-eslint/types@7.13.1': + resolution: {integrity: sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==} engines: {node: ^18.18.0 || >=20.0.0} '@typescript-eslint/typescript-estree@6.21.0': @@ -1036,8 +1058,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@7.12.0': - resolution: {integrity: sha512-5bwqLsWBULv1h6pn7cMW5dXX/Y2amRqLaKqsASVwbBHMZSnHqE/HN4vT4fE0aFsiwxYvr98kqOWh1a8ZKXalCQ==} + '@typescript-eslint/typescript-estree@7.13.1': + resolution: {integrity: sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: typescript: '*' @@ -1051,8 +1073,8 @@ packages: peerDependencies: eslint: ^7.0.0 || ^8.0.0 - '@typescript-eslint/utils@7.12.0': - resolution: {integrity: sha512-Y6hhwxwDx41HNpjuYswYp6gDbkiZ8Hin9Bf5aJQn1bpTs3afYY4GX+MPYxma8jtoIV2GRwTM/UJm/2uGCVv+DQ==} + '@typescript-eslint/utils@7.13.1': + resolution: {integrity: sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==} engines: {node: ^18.18.0 || >=20.0.0} peerDependencies: eslint: ^8.56.0 @@ -1061,8 +1083,8 @@ packages: resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} engines: {node: ^16.0.0 || >=18.0.0} - '@typescript-eslint/visitor-keys@7.12.0': - resolution: {integrity: sha512-uZk7DevrQLL3vSnfFl5bj4sL75qC9D6EdjemIdbtkuUmIheWpuiiylSY01JxJE7+zGrOWDZrp1WxOuDntvKrHQ==} + '@typescript-eslint/visitor-keys@7.13.1': + resolution: {integrity: sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==} engines: {node: ^18.18.0 || >=20.0.0} '@ungap/structured-clone@1.2.0': @@ -1074,14 +1096,14 @@ packages: '@vanilla-extract/css-utils@0.1.4': resolution: {integrity: sha512-3WRxMGa/VQaL32jZqRUpnnoVFSws5iPIUpQr+XlT4jXhtMeKYcA20rFK2k2Amkg04sqrO84A8hNMeABWZQesEg==} - '@vanilla-extract/css@1.15.2': - resolution: {integrity: sha512-Bi61iCAtojCuqvV+FYaF5i69vBjuMQJpHPdpgKYyQvx+e2Hp79V0ELglyYOdcyg9Wh0k0MFwgCDipVd7EloTXQ==} + '@vanilla-extract/css@1.15.3': + resolution: {integrity: sha512-mxoskDAxdQAspbkmQRxBvolUi1u1jnyy9WZGm+GeH8V2wwhEvndzl1QoK7w8JfA0WFevTxbev5d+i+xACZlPhA==} '@vanilla-extract/dynamic@2.1.1': resolution: {integrity: sha512-iqf736036ujEIKsIq28UsBEMaLC2vR2DhwKyrG3NDb/fRy9qL9FKl1TqTtBV4daU30Uh3saeik4vRzN8bzQMbw==} - '@vanilla-extract/integration@7.1.5': - resolution: {integrity: sha512-UwwafgdaqDhF2n6ZvX6akNvSot1iiiCss/c+r6ofjnaJSzrI/3WUYhy7qX7NZsWdmG2omcajuPlqFZdo0pwzLA==} + '@vanilla-extract/integration@7.1.6': + resolution: {integrity: sha512-5fDhW0Bm/MBG9B63On3dHl1tExcmvzG5hdrS9J8LR5qTIHuT5wIxeZ4LEhLgfqgl4b7PglGP+ey7N9rXb/FlOA==} '@vanilla-extract/private@1.0.5': resolution: {integrity: sha512-6YXeOEKYTA3UV+RC8DeAjFk+/okoNz/h88R+McnzA2zpaVqTR/Ep+vszkWYlGBcMNO7vEkqbq5nT/JMMvhi+tw==} @@ -1091,13 +1113,13 @@ packages: peerDependencies: '@vanilla-extract/css': ^1.0.0 - '@vanilla-extract/vite-plugin@4.0.10': - resolution: {integrity: sha512-bjX5ioQeBTKuV/MOweeSCrGU5m7z4a76yf8J/r4gC5MGJrEvYu0YHaQIiiL7o2wlFSc929JUEUO1ahnVXUET6A==} + '@vanilla-extract/vite-plugin@4.0.11': + resolution: {integrity: sha512-8t9ErMKaUdaO1mykbtgQvnzOSWhXsr7wwTdxjd6j3nIHf049UbrrmNeA0On3x9+z7kDnIALYa9GhT3IICTDUdg==} peerDependencies: vite: ^4.0.3 || ^5.0.0 - '@vitejs/plugin-react@4.3.0': - resolution: {integrity: sha512-KcEbMsn4Dpk+LIbHMj7gDPRKaTMStxxWRkRmxsg/jVdFdJCZWt1SchZcf0M4t8lIKdwwMsEyzhrcOXRrDPtOBw==} + '@vitejs/plugin-react@4.3.1': + resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 @@ -1122,12 +1144,12 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + acorn-walk@8.3.3: + resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} engines: {node: '>=0.4.0'} - acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} engines: {node: '>=0.4.0'} hasBin: true @@ -1168,9 +1190,16 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-query@5.1.3: + resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} + aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} @@ -1229,16 +1258,20 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.7.0: - resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} + axe-core@4.9.1: + resolution: {integrity: sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==} engines: {node: '>=4'} - axobject-query@3.2.1: - resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + axobject-query@3.1.1: + resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} @@ -1249,8 +1282,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + browserslist@4.23.1: + resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1266,8 +1299,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001628: - resolution: {integrity: sha512-S3BnR4Kh26TBxbi5t5kpbcUlLJb9lhtDXISDPwOfI+JoC+ik0QksvkZtUVyikw3hjnkgkMPSJ8oIM9yMm9vflA==} + caniuse-lite@1.0.30001636: + resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} chai@4.4.1: resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} @@ -1295,6 +1328,10 @@ packages: check-error@1.0.3: resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1492,6 +1529,10 @@ packages: resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} engines: {node: '>=6'} + deep-equal@2.2.3: + resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} + engines: {node: '>= 0.4'} + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1547,8 +1588,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.4.790: - resolution: {integrity: sha512-eVGeQxpaBYbomDBa/Mehrs28MdvCXfJmEFzaMFsv8jH/MJDLIylJN81eTJ5kvx7B7p18OiPK0BkC06lydEy63A==} + electron-to-chromium@1.4.807: + resolution: {integrity: sha512-kSmJl2ZwhNf/bcIuCH/imtNOKlpkLDn2jqT5FJ+/0CXjhnFaOa9cOe9gHKKy71eM49izwuQjZhKk+lWQ1JxB7A==} emoji-regex@10.3.0: resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} @@ -1582,6 +1623,9 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} + es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + es-iterator-helpers@1.0.19: resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} engines: {node: '>= 0.4'} @@ -1606,8 +1650,8 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true @@ -1699,8 +1743,8 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-jsx-a11y@6.8.0: - resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} + eslint-plugin-jsx-a11y@6.9.0: + resolution: {integrity: sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 @@ -1730,8 +1774,8 @@ packages: peerDependencies: eslint: '>=7' - eslint-plugin-react@7.34.2: - resolution: {integrity: sha512-2HCmrU+/JNigDN6tg55cRDKCQWicYAPB38JGSFDQt95jDm8rrvSUo7YPkOIm5l6ts1j1zCvysNcasvfTMQzUOw==} + eslint-plugin-react@7.34.3: + resolution: {integrity: sha512-aoW4MV891jkUulwDApQbPYTVZmeuSyFrudpbTAQuj5Fv8VL+o6df2xIGpw8B0hPjAaih1/Fb0om9grCdyFYemA==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 @@ -1825,8 +1869,8 @@ packages: for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - foreground-child@3.1.1: - resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==} + foreground-child@3.2.1: + resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} engines: {node: '>=14'} form-data@4.0.0: @@ -1891,8 +1935,8 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.4.1: - resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + glob@10.4.2: + resolution: {integrity: sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==} engines: {node: '>=16 || 14 >=14.18'} hasBin: true @@ -1996,6 +2040,9 @@ packages: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} + immutable@4.3.6: + resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} + import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} @@ -2026,6 +2073,10 @@ packages: intl-messageformat@10.5.14: resolution: {integrity: sha512-IjC6sI0X7YRjjyVH9aUgdftcmZK7WXdHeil4KwbjDnRWjnVitKpAx3rr6t6di1joFp5188VqKcobOPA6mCLG/w==} + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + is-array-buffer@3.0.4: resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} engines: {node: '>= 0.4'} @@ -2040,6 +2091,10 @@ packages: is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-boolean-object@1.1.2: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} @@ -2048,8 +2103,9 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.14.0: + resolution: {integrity: sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==} + engines: {node: '>= 0.4'} is-data-view@1.0.1: resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} @@ -2352,6 +2408,9 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + navigation-api-types@0.5.1: + resolution: {integrity: sha512-STpzr4JvInYi+GFIckNe/dM5cKc9M7Q/ZLKLWcWxFzOCXCBK5Oog3PzjwXwJ18yCJ1RnPVgdVueQG357PIeiAA==} + neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -2362,6 +2421,10 @@ packages: resolution: {integrity: sha512-6rvCfeRW+OEZagAB4lMLSNuTNYZWLVtKccK79VSTf//yTY5VOCgcpH80O+bZK8Neps7pUnd5G+QlMg1yV/2iZQ==} engines: {node: ^16.14.0 || >=18.0.0} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2376,6 +2439,10 @@ packages: object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} @@ -2411,6 +2478,9 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + open-props@1.7.4: + resolution: {integrity: sha512-LfzWOJq4I79GxtpT1/CucxujndqWjAdcC2H6gSJo1TmFGzyGv1VJWJQ1BQnui0/YgTNI+AaG1pEcq5/DCGL8RQ==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2427,6 +2497,9 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2501,8 +2574,8 @@ packages: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} engines: {node: '>=6.0.0'} - prettier@3.3.1: - resolution: {integrity: sha512-7CAwy5dRsxs8PHXT3twixW9/OEll8MLE0VRPCJyl7CkS6VHGPSlsVaWTiASPTyGyYRyApxlaWTzwUxVNrhcwDg==} + prettier@3.3.2: + resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==} engines: {node: '>=14'} hasBin: true @@ -2573,6 +2646,10 @@ packages: resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} engines: {node: '>=18'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -2634,8 +2711,8 @@ packages: rrweb-cssom@0.6.0: resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} - rrweb-cssom@0.7.0: - resolution: {integrity: sha512-KlSv0pm9kgQSRxXEMgtivPJ4h826YHsuob8pSHcfSZsSXGtvpEAie8S0AnXuObEJ7nhikOb4ahwxDm0H2yW17g==} + rrweb-cssom@0.7.1: + resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==} run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -2651,6 +2728,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.77.6: + resolution: {integrity: sha512-ByXE1oLD79GVq9Ht1PeHWCPMPB8XHpBuz1r85oByKHjZY6qV6rWnQovQzXJXuQ/XyE1Oj3iPk3lo28uzaRA2/Q==} + engines: {node: '>=14.0.0'} + hasBin: true + saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -2724,6 +2806,10 @@ packages: std-env@3.7.0: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + stop-iteration-iterator@1.0.0: + resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} + engines: {node: '>= 0.4'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2732,6 +2818,9 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string.prototype.includes@2.0.0: + resolution: {integrity: sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==} + string.prototype.matchall@4.0.11: resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} engines: {node: '>= 0.4'} @@ -2868,8 +2957,8 @@ packages: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - type-fest@4.19.0: - resolution: {integrity: sha512-CN2l+hWACRiejlnr68vY0/7734Kzu+9+TOslUXbSCQ1ruY9XIHDBSceVXCcHm/oXrdzhtLMMdJEKfemf1yXiZQ==} + type-fest@4.20.1: + resolution: {integrity: sha512-R6wDsVsoS9xYOpy8vgeBlqpdOyzJ12HNfQhC/aAKWM3YoCV9TtunJzh/QpkMgeDhkoynDcw5f1y+qF9yc/HHyg==} engines: {node: '>=16'} typed-array-buffer@1.0.2: @@ -2888,16 +2977,16 @@ packages: resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} engines: {node: '>= 0.4'} - typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.5.2: + resolution: {integrity: sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==} engines: {node: '>=14.17'} hasBin: true ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} - uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} + uglify-js@3.18.0: + resolution: {integrity: sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==} engines: {node: '>=0.8.0'} hasBin: true @@ -2938,8 +3027,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite@5.2.12: - resolution: {integrity: sha512-/gC8GxzxMK5ntBwb48pR32GGhENnjtY30G4A0jemunsBkiEZFw60s8InGpN8gkhHEkjnRK1aSAxeQgwvFhUHAA==} + vite@5.3.1: + resolution: {integrity: sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -3054,8 +3143,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.17.0: - resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3131,7 +3220,7 @@ snapshots: dependencies: '@babel/compat-data': 7.24.7 '@babel/helper-validator-option': 7.24.7 - browserslist: 4.23.0 + browserslist: 4.23.1 lru-cache: 5.1.1 semver: 6.3.1 @@ -3247,33 +3336,33 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - '@block65/bundlesize@1.0.1(typescript@5.4.5)': + '@block65/bundlesize@1.0.1(typescript@5.5.2)': dependencies: ajv: 8.16.0 colorette: 2.0.20 - cosmiconfig: 8.3.6(typescript@5.4.5) - glob: 10.4.1 + cosmiconfig: 8.3.6(typescript@5.5.2) + glob: 10.4.2 pretty-bytes: 6.1.1 transitivePeerDependencies: - typescript - '@block65/eslint-config@12.0.1(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-formatjs@4.13.3(eslint@8.57.0))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react-refresh@0.4.7(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1)(typescript@5.4.5)': + '@block65/eslint-config@12.0.1(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-formatjs@4.13.3(eslint@8.57.0))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react-refresh@0.4.7(eslint@8.57.0))(eslint-plugin-react@7.34.3(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2)(typescript@5.5.2)': dependencies: - '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 - eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) - eslint-config-airbnb-typescript: 18.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb: 19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.3(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-typescript: 18.0.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) - prettier: 3.3.1 - typescript: 5.4.5 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) + prettier: 3.3.2 + typescript: 5.5.2 optionalDependencies: eslint-plugin-formatjs: 4.13.3(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) - eslint-plugin-react: 7.34.2(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) + eslint-plugin-react: 7.34.3(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) eslint-plugin-react-refresh: 0.4.7(eslint@8.57.0) transitivePeerDependencies: @@ -3281,10 +3370,12 @@ snapshots: - eslint-import-resolver-webpack - supports-color - '@block65/mrr@6.0.1-0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@block65/mrr@6.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: + '@types/dom-view-transitions': 1.0.4 '@types/react': 18.3.3 '@types/react-dom': 18.3.0 + navigation-api-types: 0.5.1 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) regexparam: 3.0.0 @@ -3295,10 +3386,10 @@ snapshots: '@capsizecss/metrics@3.2.0': {} - '@capsizecss/vanilla-extract@2.0.0(@vanilla-extract/css@1.15.2)': + '@capsizecss/vanilla-extract@2.0.0(@vanilla-extract/css@1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m))': dependencies: '@capsizecss/core': 4.1.2 - '@vanilla-extract/css': 1.15.2 + '@vanilla-extract/css': 1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m) '@commitlint/config-conventional@19.2.2': dependencies: @@ -3323,139 +3414,139 @@ snapshots: '@esbuild/aix-ppc64@0.19.12': optional: true - '@esbuild/aix-ppc64@0.20.2': + '@esbuild/aix-ppc64@0.21.5': optional: true '@esbuild/android-arm64@0.19.12': optional: true - '@esbuild/android-arm64@0.20.2': + '@esbuild/android-arm64@0.21.5': optional: true '@esbuild/android-arm@0.19.12': optional: true - '@esbuild/android-arm@0.20.2': + '@esbuild/android-arm@0.21.5': optional: true '@esbuild/android-x64@0.19.12': optional: true - '@esbuild/android-x64@0.20.2': + '@esbuild/android-x64@0.21.5': optional: true '@esbuild/darwin-arm64@0.19.12': optional: true - '@esbuild/darwin-arm64@0.20.2': + '@esbuild/darwin-arm64@0.21.5': optional: true '@esbuild/darwin-x64@0.19.12': optional: true - '@esbuild/darwin-x64@0.20.2': + '@esbuild/darwin-x64@0.21.5': optional: true '@esbuild/freebsd-arm64@0.19.12': optional: true - '@esbuild/freebsd-arm64@0.20.2': + '@esbuild/freebsd-arm64@0.21.5': optional: true '@esbuild/freebsd-x64@0.19.12': optional: true - '@esbuild/freebsd-x64@0.20.2': + '@esbuild/freebsd-x64@0.21.5': optional: true '@esbuild/linux-arm64@0.19.12': optional: true - '@esbuild/linux-arm64@0.20.2': + '@esbuild/linux-arm64@0.21.5': optional: true '@esbuild/linux-arm@0.19.12': optional: true - '@esbuild/linux-arm@0.20.2': + '@esbuild/linux-arm@0.21.5': optional: true '@esbuild/linux-ia32@0.19.12': optional: true - '@esbuild/linux-ia32@0.20.2': + '@esbuild/linux-ia32@0.21.5': optional: true '@esbuild/linux-loong64@0.19.12': optional: true - '@esbuild/linux-loong64@0.20.2': + '@esbuild/linux-loong64@0.21.5': optional: true '@esbuild/linux-mips64el@0.19.12': optional: true - '@esbuild/linux-mips64el@0.20.2': + '@esbuild/linux-mips64el@0.21.5': optional: true '@esbuild/linux-ppc64@0.19.12': optional: true - '@esbuild/linux-ppc64@0.20.2': + '@esbuild/linux-ppc64@0.21.5': optional: true '@esbuild/linux-riscv64@0.19.12': optional: true - '@esbuild/linux-riscv64@0.20.2': + '@esbuild/linux-riscv64@0.21.5': optional: true '@esbuild/linux-s390x@0.19.12': optional: true - '@esbuild/linux-s390x@0.20.2': + '@esbuild/linux-s390x@0.21.5': optional: true '@esbuild/linux-x64@0.19.12': optional: true - '@esbuild/linux-x64@0.20.2': + '@esbuild/linux-x64@0.21.5': optional: true '@esbuild/netbsd-x64@0.19.12': optional: true - '@esbuild/netbsd-x64@0.20.2': + '@esbuild/netbsd-x64@0.21.5': optional: true '@esbuild/openbsd-x64@0.19.12': optional: true - '@esbuild/openbsd-x64@0.20.2': + '@esbuild/openbsd-x64@0.21.5': optional: true '@esbuild/sunos-x64@0.19.12': optional: true - '@esbuild/sunos-x64@0.20.2': + '@esbuild/sunos-x64@0.21.5': optional: true '@esbuild/win32-arm64@0.19.12': optional: true - '@esbuild/win32-arm64@0.20.2': + '@esbuild/win32-arm64@0.21.5': optional: true '@esbuild/win32-ia32@0.19.12': optional: true - '@esbuild/win32-ia32@0.20.2': + '@esbuild/win32-ia32@0.21.5': optional: true '@esbuild/win32-x64@0.19.12': optional: true - '@esbuild/win32-x64@0.20.2': + '@esbuild/win32-x64@0.21.5': optional: true '@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)': @@ -3496,7 +3587,7 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react@0.26.16(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react@0.26.17(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@floating-ui/utils': 0.2.2 @@ -3542,7 +3633,7 @@ snapshots: dependencies: tslib: 2.6.3 - '@formatjs/intl@2.10.4(typescript@5.4.5)': + '@formatjs/intl@2.10.4(typescript@5.5.2)': dependencies: '@formatjs/ecma402-abstract': 2.0.0 '@formatjs/fast-memoize': 2.2.0 @@ -3552,7 +3643,7 @@ snapshots: intl-messageformat: 10.5.14 tslib: 2.6.3 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 '@formatjs/ts-transformer@3.13.14': dependencies: @@ -3561,8 +3652,8 @@ snapshots: '@types/node': 17.0.45 chalk: 4.1.2 json-stable-stringify: 1.1.1 - tslib: 2.6.3 - typescript: 5.4.5 + tslib: 2.6.2 + typescript: 5.5.2 '@humanwhocodes/config-array@0.11.14': dependencies: @@ -3686,7 +3777,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.5(vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0))': + '@testing-library/jest-dom@6.4.6(vitest@1.6.0(@types/node@20.14.7)(jsdom@24.1.0)(sass@1.77.6))': dependencies: '@adobe/css-tools': 4.4.0 '@babel/runtime': 7.24.7 @@ -3697,7 +3788,7 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 optionalDependencies: - vitest: 1.6.0(@types/node@20.14.2)(jsdom@24.1.0) + vitest: 1.6.0(@types/node@20.14.7)(jsdom@24.1.0)(sass@1.77.6) '@testing-library/react@16.0.0(@testing-library/dom@10.1.0)(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -3744,7 +3835,9 @@ snapshots: '@types/conventional-commits-parser@5.0.0': dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 + + '@types/dom-view-transitions@1.0.4': {} '@types/eslint@8.56.10': dependencies: @@ -3768,7 +3861,7 @@ snapshots: '@types/node@17.0.45': {} - '@types/node@20.14.2': + '@types/node@20.14.7': dependencies: undici-types: 5.26.5 @@ -3789,34 +3882,34 @@ snapshots: '@types/semver@7.5.8': {} - '@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/regexpp': 4.10.1 - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/type-utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/type-utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/visitor-keys': 7.13.1 eslint: 8.57.0 graphemer: 1.4.0 ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.5 eslint: 8.57.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color @@ -3825,28 +3918,28 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/scope-manager@7.12.0': + '@typescript-eslint/scope-manager@7.13.1': dependencies: - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 - '@typescript-eslint/type-utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/type-utils@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) - '@typescript-eslint/utils': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) + '@typescript-eslint/utils': 7.13.1(eslint@8.57.0)(typescript@5.5.2) debug: 4.3.5 eslint: 8.57.0 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/types@7.12.0': {} + '@typescript-eslint/types@7.13.1': {} - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.5.2)': dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 @@ -3855,47 +3948,47 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@7.12.0(typescript@5.4.5)': + '@typescript-eslint/typescript-estree@7.13.1(typescript@5.5.2)': dependencies: - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/visitor-keys': 7.12.0 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/visitor-keys': 7.13.1 debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 semver: 7.6.2 - ts-api-utils: 1.3.0(typescript@5.4.5) + ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@6.21.0(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.5.2) eslint: 8.57.0 semver: 7.6.2 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@7.12.0(eslint@8.57.0)(typescript@5.4.5)': + '@typescript-eslint/utils@7.13.1(eslint@8.57.0)(typescript@5.5.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 7.12.0 - '@typescript-eslint/types': 7.12.0 - '@typescript-eslint/typescript-estree': 7.12.0(typescript@5.4.5) + '@typescript-eslint/scope-manager': 7.13.1 + '@typescript-eslint/types': 7.13.1 + '@typescript-eslint/typescript-estree': 7.13.1(typescript@5.5.2) eslint: 8.57.0 transitivePeerDependencies: - supports-color @@ -3906,9 +3999,9 @@ snapshots: '@typescript-eslint/types': 6.21.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@7.12.0': + '@typescript-eslint/visitor-keys@7.13.1': dependencies: - '@typescript-eslint/types': 7.12.0 + '@typescript-eslint/types': 7.13.1 eslint-visitor-keys: 3.4.3 '@ungap/structured-clone@1.2.0': {} @@ -3921,7 +4014,7 @@ snapshots: '@vanilla-extract/css-utils@0.1.4': {} - '@vanilla-extract/css@1.15.2': + '@vanilla-extract/css@1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m)': dependencies: '@emotion/hash': 0.9.1 '@vanilla-extract/private': 1.0.5 @@ -3941,20 +4034,20 @@ snapshots: dependencies: '@vanilla-extract/private': 1.0.5 - '@vanilla-extract/integration@7.1.5(@types/node@20.14.2)': + '@vanilla-extract/integration@7.1.6(@types/node@20.14.7)(sass@1.77.6)': dependencies: '@babel/core': 7.24.7 '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.7) '@vanilla-extract/babel-plugin-debug-ids': 1.0.6 - '@vanilla-extract/css': 1.15.2 + '@vanilla-extract/css': 1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m) dedent: 1.5.3 esbuild: 0.19.12 eval: 0.1.8 find-up: 5.0.0 javascript-stringify: 2.1.0 mlly: 1.7.1 - vite: 5.2.12(@types/node@20.14.2) - vite-node: 1.6.0(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7)(sass@1.77.6) + vite-node: 1.6.0(@types/node@20.14.7)(sass@1.77.6) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -3968,14 +4061,14 @@ snapshots: '@vanilla-extract/private@1.0.5': {} - '@vanilla-extract/sprinkles@1.6.2(@vanilla-extract/css@1.15.2)': + '@vanilla-extract/sprinkles@1.6.2(@vanilla-extract/css@1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m))': dependencies: - '@vanilla-extract/css': 1.15.2 + '@vanilla-extract/css': 1.15.3(patch_hash=vtudlxny3uthcq56uc3pnbvu2m) - '@vanilla-extract/vite-plugin@4.0.10(@types/node@20.14.2)(vite@5.2.12(@types/node@20.14.2))': + '@vanilla-extract/vite-plugin@4.0.11(@types/node@20.14.7)(sass@1.77.6)(vite@5.3.1(@types/node@20.14.7)(sass@1.77.6))': dependencies: - '@vanilla-extract/integration': 7.1.5(@types/node@20.14.2) - vite: 5.2.12(@types/node@20.14.2) + '@vanilla-extract/integration': 7.1.6(@types/node@20.14.7)(sass@1.77.6) + vite: 5.3.1(@types/node@20.14.7)(sass@1.77.6) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -3987,14 +4080,14 @@ snapshots: - supports-color - terser - '@vitejs/plugin-react@4.3.0(vite@5.2.12(@types/node@20.14.2))': + '@vitejs/plugin-react@4.3.1(vite@5.3.1(@types/node@20.14.7)(sass@1.77.6))': dependencies: '@babel/core': 7.24.7 '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.24.7) '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.24.7) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.2.12(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7)(sass@1.77.6) transitivePeerDependencies: - supports-color @@ -4027,13 +4120,15 @@ snapshots: loupe: 2.3.7 pretty-format: 29.7.0 - acorn-jsx@5.3.2(acorn@8.11.3): + acorn-jsx@5.3.2(acorn@8.12.0): dependencies: - acorn: 8.11.3 + acorn: 8.12.0 - acorn-walk@8.3.2: {} + acorn-walk@8.3.3: + dependencies: + acorn: 8.12.0 - acorn@8.11.3: {} + acorn@8.12.0: {} add-stream@1.0.0: {} @@ -4073,8 +4168,17 @@ snapshots: ansi-styles@6.2.1: {} + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + argparse@2.0.1: {} + aria-query@5.1.3: + dependencies: + deep-equal: 2.2.3 + aria-query@5.3.0: dependencies: dequal: 2.0.3 @@ -4165,14 +4269,16 @@ snapshots: dependencies: possible-typed-array-names: 1.0.0 - axe-core@4.7.0: {} + axe-core@4.9.1: {} - axobject-query@3.2.1: + axobject-query@3.1.1: dependencies: - dequal: 2.0.3 + deep-equal: 2.2.3 balanced-match@1.0.2: {} + binary-extensions@2.3.0: {} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 @@ -4186,12 +4292,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.23.0: + browserslist@4.23.1: dependencies: - caniuse-lite: 1.0.30001628 - electron-to-chromium: 1.4.790 + caniuse-lite: 1.0.30001636 + electron-to-chromium: 1.4.807 node-releases: 2.0.14 - update-browserslist-db: 1.0.16(browserslist@4.23.0) + update-browserslist-db: 1.0.16(browserslist@4.23.1) cac@6.7.14: {} @@ -4205,7 +4311,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001628: {} + caniuse-lite@1.0.30001636: {} chai@4.4.1: dependencies: @@ -4241,6 +4347,18 @@ snapshots: dependencies: get-func-name: 2.0.2 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + clsx@2.1.1: {} color-convert@1.9.3: @@ -4360,14 +4478,14 @@ snapshots: convert-source-map@2.0.0: {} - cosmiconfig@8.3.6(typescript@5.4.5): + cosmiconfig@8.3.6(typescript@5.5.2): dependencies: import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 path-type: 4.0.0 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 cross-spawn@7.0.3: dependencies: @@ -4428,6 +4546,27 @@ snapshots: dependencies: type-detect: 4.0.8 + deep-equal@2.2.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + es-get-iterator: 1.1.3 + get-intrinsic: 1.2.4 + is-arguments: 1.1.1 + is-array-buffer: 3.0.4 + is-date-object: 1.0.5 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + isarray: 2.0.5 + object-is: 1.1.6 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + side-channel: 1.0.6 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + deep-is@0.1.4: {} deep-object-diff@1.1.9: {} @@ -4474,7 +4613,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.4.790: {} + electron-to-chromium@1.4.807: {} emoji-regex@10.3.0: {} @@ -4548,6 +4687,18 @@ snapshots: es-errors@1.3.0: {} + es-get-iterator@1.1.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + is-arguments: 1.1.1 + is-map: 2.0.3 + is-set: 2.0.3 + is-string: 1.0.7 + isarray: 2.0.5 + stop-iteration-iterator: 1.0.0 + es-iterator-helpers@1.0.19: dependencies: call-bind: 1.0.7 @@ -4611,31 +4762,31 @@ snapshots: '@esbuild/win32-ia32': 0.19.12 '@esbuild/win32-x64': 0.19.12 - esbuild@0.20.2: + esbuild@0.21.5: optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 escalade@3.1.2: {} @@ -4643,31 +4794,31 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: confusing-browser-globals: 1.0.11 eslint: 8.57.0 - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5))(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb-typescript@18.0.0(@typescript-eslint/eslint-plugin@7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2))(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: - '@typescript-eslint/eslint-plugin': 7.12.0(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/eslint-plugin': 7.13.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0)(typescript@5.5.2) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - eslint-plugin-import - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.2(eslint@8.57.0))(eslint@8.57.0): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0))(eslint-plugin-react-hooks@4.6.2(eslint@8.57.0))(eslint-plugin-react@7.34.3(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) - eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0) - eslint-plugin-react: 7.34.2(eslint@8.57.0) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) + eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) + eslint-plugin-react: 7.34.3(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) object.assign: 4.1.5 object.entries: 1.1.8 @@ -4679,21 +4830,21 @@ snapshots: eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.13.1 + is-core-module: 2.14.0 resolve: 1.22.8 transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0): + eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 4.3.5 enhanced-resolve: 5.17.0 eslint: 8.57.0 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) - eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0) fast-glob: 3.3.2 get-tsconfig: 4.7.5 - is-core-module: 2.13.1 + is-core-module: 2.14.0 is-glob: 4.0.3 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -4701,23 +4852,23 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.8.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) eslint: 8.57.0 - eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0))(eslint@8.57.0) + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0))(eslint@8.57.0) transitivePeerDependencies: - supports-color @@ -4727,19 +4878,19 @@ snapshots: '@formatjs/ts-transformer': 3.13.14 '@types/eslint': 8.56.10 '@types/picomatch': 2.3.3 - '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.0)(typescript@5.5.2) emoji-regex: 10.3.0 eslint: 8.57.0 magic-string: 0.30.10 picomatch: 2.3.1 tslib: 2.6.2 - typescript: 5.4.5 + typescript: 5.5.2 unicode-emoji-utils: 1.2.0 transitivePeerDependencies: - supports-color - ts-jest - eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0): + eslint-plugin-import@2.29.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlastindex: 1.2.5 @@ -4749,9 +4900,9 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.12.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.13.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) hasown: 2.0.2 - is-core-module: 2.13.1 + is-core-module: 2.14.0 is-glob: 4.0.3 minimatch: 3.1.2 object.fromentries: 2.0.8 @@ -4760,21 +4911,20 @@ snapshots: semver: 6.3.1 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.12.0(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': 7.13.1(eslint@8.57.0)(typescript@5.5.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.8.0(eslint@8.57.0): + eslint-plugin-jsx-a11y@6.9.0(eslint@8.57.0): dependencies: - '@babel/runtime': 7.24.7 - aria-query: 5.3.0 + aria-query: 5.1.3 array-includes: 3.1.8 array.prototype.flatmap: 1.3.2 ast-types-flow: 0.0.8 - axe-core: 4.7.0 - axobject-query: 3.2.1 + axe-core: 4.9.1 + axobject-query: 3.1.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 es-iterator-helpers: 1.0.19 @@ -4783,13 +4933,14 @@ snapshots: jsx-ast-utils: 3.3.5 language-tags: 1.0.9 minimatch: 3.1.2 - object.entries: 1.1.8 object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.0 - eslint-plugin-prettier@5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.1): + eslint-plugin-prettier@5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.2): dependencies: eslint: 8.57.0 - prettier: 3.3.1 + prettier: 3.3.2 prettier-linter-helpers: 1.0.0 synckit: 0.8.8 optionalDependencies: @@ -4804,7 +4955,7 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-plugin-react@7.34.2(eslint@8.57.0): + eslint-plugin-react@7.34.3(eslint@8.57.0): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -4878,8 +5029,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.12.0 + acorn-jsx: 5.3.2(acorn@8.12.0) eslint-visitor-keys: 3.4.3 esquery@1.5.0: @@ -4900,7 +5051,7 @@ snapshots: eval@0.1.8: dependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 require-like: 0.1.2 execa@8.0.1: @@ -4962,7 +5113,7 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.1.1: + foreground-child@3.2.1: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 @@ -5037,12 +5188,13 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.4.1: + glob@10.4.2: dependencies: - foreground-child: 3.1.1 + foreground-child: 3.2.1 jackspeak: 3.4.0 minimatch: 9.0.4 minipass: 7.1.2 + package-json-from-dist: 1.0.0 path-scurry: 1.11.1 glob@7.2.3: @@ -5089,7 +5241,7 @@ snapshots: source-map: 0.6.1 wordwrap: 1.0.0 optionalDependencies: - uglify-js: 3.17.4 + uglify-js: 3.18.0 has-bigints@1.0.2: {} @@ -5149,6 +5301,8 @@ snapshots: ignore@5.3.1: {} + immutable@4.3.6: {} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 @@ -5180,6 +5334,11 @@ snapshots: '@formatjs/icu-messageformat-parser': 2.7.8 tslib: 2.6.3 + is-arguments@1.1.1: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 @@ -5195,6 +5354,10 @@ snapshots: dependencies: has-bigints: 1.0.2 + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.7 @@ -5202,7 +5365,7 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.13.1: + is-core-module@2.14.0: dependencies: hasown: 2.0.2 @@ -5324,7 +5487,7 @@ snapshots: is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.10 parse5: 7.1.2 - rrweb-cssom: 0.7.0 + rrweb-cssom: 0.7.1 saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 4.1.4 @@ -5333,7 +5496,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.0.0 - ws: 8.17.0 + ws: 8.17.1 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -5471,7 +5634,7 @@ snapshots: mlly@1.7.1: dependencies: - acorn: 8.11.3 + acorn: 8.12.0 pathe: 1.1.2 pkg-types: 1.1.1 ufo: 1.5.3 @@ -5486,6 +5649,8 @@ snapshots: natural-compare@1.4.0: {} + navigation-api-types@0.5.1: {} + neo-async@2.6.2: {} node-releases@2.0.14: {} @@ -5493,10 +5658,12 @@ snapshots: normalize-package-data@6.0.1: dependencies: hosted-git-info: 7.0.2 - is-core-module: 2.13.1 + is-core-module: 2.14.0 semver: 7.6.2 validate-npm-package-license: 3.0.4 + normalize-path@3.0.0: {} + npm-run-path@5.3.0: dependencies: path-key: 4.0.0 @@ -5507,6 +5674,11 @@ snapshots: object-inspect@1.13.1: {} + object-is@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + object-keys@1.1.1: {} object.assign@4.1.5: @@ -5555,6 +5727,8 @@ snapshots: dependencies: mimic-fn: 4.0.0 + open-props@1.7.4: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -5576,6 +5750,8 @@ snapshots: dependencies: p-limit: 3.1.0 + package-json-from-dist@1.0.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -5591,7 +5767,7 @@ snapshots: dependencies: '@babel/code-frame': 7.24.7 index-to-position: 0.1.2 - type-fest: 4.19.0 + type-fest: 4.20.1 parse5@7.1.2: dependencies: @@ -5642,7 +5818,7 @@ snapshots: dependencies: fast-diff: 1.3.0 - prettier@3.3.1: {} + prettier@3.3.2: {} pretty-bytes@6.1.1: {} @@ -5678,11 +5854,11 @@ snapshots: react: 18.3.1 scheduler: 0.23.2 - react-intl@6.6.8(react@18.3.1)(typescript@5.4.5): + react-intl@6.6.8(react@18.3.1)(typescript@5.5.2): dependencies: '@formatjs/ecma402-abstract': 2.0.0 '@formatjs/icu-messageformat-parser': 2.7.8 - '@formatjs/intl': 2.10.4(typescript@5.4.5) + '@formatjs/intl': 2.10.4(typescript@5.5.2) '@formatjs/intl-displaynames': 6.6.8 '@formatjs/intl-listformat': 7.5.7 '@types/hoist-non-react-statics': 3.3.5 @@ -5692,7 +5868,7 @@ snapshots: react: 18.3.1 tslib: 2.6.3 optionalDependencies: - typescript: 5.4.5 + typescript: 5.5.2 react-is@16.13.1: {} @@ -5710,16 +5886,20 @@ snapshots: dependencies: find-up-simple: 1.0.0 read-pkg: 9.0.1 - type-fest: 4.19.0 + type-fest: 4.20.1 read-pkg@9.0.1: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 6.0.1 parse-json: 8.1.0 - type-fest: 4.19.0 + type-fest: 4.20.1 unicorn-magic: 0.1.0 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -5758,13 +5938,13 @@ snapshots: resolve@1.22.8: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.14.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.14.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -5798,7 +5978,7 @@ snapshots: rrweb-cssom@0.6.0: {} - rrweb-cssom@0.7.0: {} + rrweb-cssom@0.7.1: {} run-parallel@1.2.0: dependencies: @@ -5819,6 +5999,12 @@ snapshots: safer-buffer@2.1.2: {} + sass@1.77.6: + dependencies: + chokidar: 3.6.0 + immutable: 4.3.6 + source-map-js: 1.2.0 + saxes@6.0.0: dependencies: xmlchars: 2.2.0 @@ -5888,6 +6074,10 @@ snapshots: std-env@3.7.0: {} + stop-iteration-iterator@1.0.0: + dependencies: + internal-slot: 1.0.7 + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -5900,6 +6090,11 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string.prototype.includes@2.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + string.prototype.matchall@4.0.11: dependencies: call-bind: 1.0.7 @@ -6010,9 +6205,9 @@ snapshots: dependencies: punycode: 2.3.1 - ts-api-utils@1.3.0(typescript@5.4.5): + ts-api-utils@1.3.0(typescript@5.5.2): dependencies: - typescript: 5.4.5 + typescript: 5.5.2 tsconfig-paths@3.15.0: dependencies: @@ -6033,7 +6228,7 @@ snapshots: type-fest@0.20.2: {} - type-fest@4.19.0: {} + type-fest@4.20.1: {} typed-array-buffer@1.0.2: dependencies: @@ -6067,11 +6262,11 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typescript@5.4.5: {} + typescript@5.5.2: {} ufo@1.5.3: {} - uglify-js@3.17.4: + uglify-js@3.18.0: optional: true unbox-primitive@1.0.2: @@ -6091,9 +6286,9 @@ snapshots: universalify@0.2.0: {} - update-browserslist-db@1.0.16(browserslist@4.23.0): + update-browserslist-db@1.0.16(browserslist@4.23.1): dependencies: - browserslist: 4.23.0 + browserslist: 4.23.1 escalade: 3.1.2 picocolors: 1.0.1 @@ -6111,13 +6306,13 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-node@1.6.0(@types/node@20.14.2): + vite-node@1.6.0(@types/node@20.14.7)(sass@1.77.6): dependencies: cac: 6.7.14 debug: 4.3.5 pathe: 1.1.2 picocolors: 1.0.1 - vite: 5.2.12(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7)(sass@1.77.6) transitivePeerDependencies: - '@types/node' - less @@ -6128,23 +6323,24 @@ snapshots: - supports-color - terser - vite@5.2.12(@types/node@20.14.2): + vite@5.3.1(@types/node@20.14.7)(sass@1.77.6): dependencies: - esbuild: 0.20.2 + esbuild: 0.21.5 postcss: 8.4.38 rollup: 4.18.0 optionalDependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 fsevents: 2.3.3 + sass: 1.77.6 - vitest@1.6.0(@types/node@20.14.2)(jsdom@24.1.0): + vitest@1.6.0(@types/node@20.14.7)(jsdom@24.1.0)(sass@1.77.6): dependencies: '@vitest/expect': 1.6.0 '@vitest/runner': 1.6.0 '@vitest/snapshot': 1.6.0 '@vitest/spy': 1.6.0 '@vitest/utils': 1.6.0 - acorn-walk: 8.3.2 + acorn-walk: 8.3.3 chai: 4.4.1 debug: 4.3.5 execa: 8.0.1 @@ -6156,11 +6352,11 @@ snapshots: strip-literal: 2.1.0 tinybench: 2.8.0 tinypool: 0.8.4 - vite: 5.2.12(@types/node@20.14.2) - vite-node: 1.6.0(@types/node@20.14.2) + vite: 5.3.1(@types/node@20.14.7)(sass@1.77.6) + vite-node: 1.6.0(@types/node@20.14.7)(sass@1.77.6) why-is-node-running: 2.2.2 optionalDependencies: - '@types/node': 20.14.2 + '@types/node': 20.14.7 jsdom: 24.1.0 transitivePeerDependencies: - less @@ -6253,7 +6449,7 @@ snapshots: wrappy@1.0.2: {} - ws@8.17.0: {} + ws@8.17.1: {} xml-name-validator@5.0.0: {} diff --git a/prettier.config.cjs b/prettier.config.cjs index 36964c7..ffcb58a 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -1,2 +1 @@ -// eslint-disable-next-line import/no-extraneous-dependencies module.exports = require('@block65/eslint-config/prettier.config.cjs'); diff --git a/src/App.tsx b/src/App.tsx index 2a5a2eb..a9d8d6d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,31 +1,31 @@ -/* eslint-disable import/no-extraneous-dependencies */ +/// import type { FC } from 'react'; import { FormattedDate, FormattedMessage, FormattedNumber, FormattedTime, + IntlProvider, } from 'react-intl'; -import { DesignSystem, interFontThemeClassName } from '../lib/main.js'; -import { MainRouter } from './pages/components/MainRouter.js'; +import { useColorSchemeEffect } from '../lib/hooks/main.js'; +import { DesignSystem } from '../lib/main.js'; +import { MainRouter } from './MainRouter.js'; +import { SettingsProvider } from './pages/components/SettingsContext.js'; import { useSettings } from './pages/components/use-settings.js'; -import { - darkModeThemeClassName, - lightModeThemeClassName, -} from './reference-impl/schemes.css.js'; -export const App: FC = () => { - const [settings] = useSettings(); +import './global.scss'; // SCSS version, includes inter vars +// import './theme.scss'; // SCSS version + +import './inter.css.js'; // Vanilla extract version +import './theme.css.js'; // Vanilla extract version +import './defaults.css.js'; // Vanilla extract version + +const AppInner = () => { + const { colorScheme } = useSettings(); + useColorSchemeEffect(colorScheme); return ( { ]} space="10" flexDirection="column" - style={{ - flexGrow: 1, - minHeight: '100vh', - }} + flexGrow > ); }; + +export const App: FC = () => ( + + + + + +); diff --git a/src/pages/components/MainRouter.tsx b/src/MainRouter.tsx similarity index 68% rename from src/pages/components/MainRouter.tsx rename to src/MainRouter.tsx index 0a536ef..4f165a6 100644 --- a/src/pages/components/MainRouter.tsx +++ b/src/MainRouter.tsx @@ -1,27 +1,27 @@ import { Route, Router, Routes } from '@block65/mrr'; import type { FC } from 'react'; -import { Block, Heading } from '../../../lib/main.js'; -import { AvatarsPage } from '../avatars.js'; -import { BadgesPage } from '../badges.js'; -import { ButtonsPage } from '../buttons.js'; -import { CalloutPage } from '../callout.js'; -import { CorePage } from '../core.js'; -import { FormsPage } from '../forms.js'; -import { GridPage } from '../grid.js'; -import { HooksPage } from '../hooks.js'; -import { IconsPage } from '../icons.js'; -import { LayoutPage } from '../layout.js'; -import { ListPage } from '../list.js'; -import { LoadersPage } from '../loaders.js'; -import { MediaQueryPage } from '../media-query.js'; -import { DropdownMenuIframe } from '../menu-iframe.js'; -import { DropdownMenuPage } from '../menu.js'; -import { ModalPage } from '../modal.js'; -import { PanelsPage } from '../panels.js'; -import { PatternPage } from '../patterns.js'; -import { TypographyPage } from '../typography.js'; -import { NavigationPanel } from './NavigationPanel.js'; -import { SettingsPanel } from './SettingsPanel.js'; +import { Block, Heading } from '../lib/main.js'; +import { AvatarsPage } from './pages/avatars.js'; +import { BadgesPage } from './pages/badges.js'; +import { ButtonsPage } from './pages/buttons.js'; +import { CalloutPage } from './pages/callout.js'; +import { NavigationPanel } from './pages/components/NavigationPanel.js'; +import { SettingsPanel } from './pages/components/SettingsPanel.js'; +import { CorePage } from './pages/core.js'; +import { FormsPage } from './pages/forms.js'; +import { GridPage } from './pages/grid.js'; +import { HooksPage } from './pages/hooks.js'; +import { IconsPage } from './pages/icons.js'; +import { LayoutPage } from './pages/layout.js'; +import { ListPage } from './pages/list.js'; +import { LoadersPage } from './pages/loaders.js'; +import { MediaQueryPage } from './pages/media-query.js'; +import { DropdownMenuIframe } from './pages/menu-iframe.js'; +import { DropdownMenuPage } from './pages/menu.js'; +import { ModalPage } from './pages/modal.js'; +import { PanelsPage } from './pages/panels.js'; +import { PatternPage } from './pages/patterns.js'; +import { TypographyPage } from './pages/typography.js'; export const MainRouter: FC = () => ( diff --git a/src/defaults.css.ts b/src/defaults.css.ts new file mode 100644 index 0000000..0adfced --- /dev/null +++ b/src/defaults.css.ts @@ -0,0 +1,18 @@ +import { createGlobalTheme } from '@vanilla-extract/css'; +import { + formControlTokens, + formControlVars, + propsTokens, + propsVars, + globalVars, + globalTokens, + panelTokens, + panelVars, +} from '../lib/vars.css.js'; + +const defaultsSelector = ':root'; + +createGlobalTheme(defaultsSelector, globalVars.border, globalTokens.border); +createGlobalTheme(defaultsSelector, panelVars.padding, panelTokens.padding); +createGlobalTheme(defaultsSelector, formControlVars, formControlTokens); +createGlobalTheme(defaultsSelector, propsVars, propsTokens); diff --git a/src/global.scss b/src/global.scss new file mode 100644 index 0000000..ad1c4a8 --- /dev/null +++ b/src/global.scss @@ -0,0 +1,8 @@ +:root { + overflow-y: scroll; // jank prevention +} + +#root { + display: flex; + min-height: 100vh; +} diff --git a/src/inter.css.ts b/src/inter.css.ts new file mode 100644 index 0000000..6fc59df --- /dev/null +++ b/src/inter.css.ts @@ -0,0 +1,67 @@ +import { precomputeValues } from '@capsizecss/core'; +import interFontMetrics from '@capsizecss/metrics/inter'; +import { createGlobalTheme, globalStyle } from '@vanilla-extract/css'; +import { textVariantVars } from '../lib/typography.css.js'; + +function interCapSize(capHeightPx: number) { + return precomputeValues({ + capHeight: capHeightPx, + fontMetrics: interFontMetrics, + }); +} + +function fontSize(fontSizePx: number) { + return { + fontSize: `${fontSizePx}px`, + lineHeight: 'initial', + }; +} + +const globalSelector = ':root'; + +globalStyle(globalSelector, { + fontFamily: 'Inter, sans-serif', + fontOpticalSizing: 'auto', + fontStyle: 'normal', + fontVariationSettings: "'slnt' 0", +}); + +createGlobalTheme(globalSelector, textVariantVars.capSize, { + '00': interCapSize(9), // 12.375 + 0: interCapSize(10), // 13.75 + 1: interCapSize(12), // 16.5px + 2: interCapSize(15), // 20.625px + 3: interCapSize(16), // 22px + 4: interCapSize(18), // 24.75px + 5: interCapSize(26), // 35.75px + 6: interCapSize(31), // 42.5px + body: interCapSize(12), + small: interCapSize(10), +}); + +createGlobalTheme(globalSelector, textVariantVars.size, { + '00': fontSize(12), + 0: fontSize(14), + 1: fontSize(16), + 2: fontSize(20), + 3: fontSize(22), + 4: fontSize(25), + 5: fontSize(35), + 6: fontSize(42), + body: fontSize(16), + small: fontSize(14), +}); + +createGlobalTheme(globalSelector, textVariantVars.lineHeight, { + heading: '1.2', + normal: 'initial', + paragraph: '1.45', +}); + +createGlobalTheme(globalSelector, textVariantVars.fontWeight, { + bold: '700', + light: '300', + medium: '500', + normal: '400', + semibold: '600', +}); diff --git a/src/pages/avatars.tsx b/src/pages/avatars.tsx index ff5bca4..edcd646 100644 --- a/src/pages/avatars.tsx +++ b/src/pages/avatars.tsx @@ -1,6 +1,5 @@ import { Fragment, type FC } from 'react'; -import { Block, Grid, type FontSize } from '../../lib/main.js'; -import { Avatar, Panel } from '../reference-impl/main.js'; +import { Avatar, Panel, Block, Grid, type FontSize } from '../../lib/main.js'; const fakeNames = [ ...[ @@ -598,7 +597,7 @@ const fakeNames = [ ]; export const AvatarsPage: FC = () => ( - + ( - + - + ); diff --git a/src/pages/badges.tsx b/src/pages/badges.tsx index 5491a31..d7abbf1 100644 --- a/src/pages/badges.tsx +++ b/src/pages/badges.tsx @@ -1,30 +1,25 @@ import type { FC } from 'react'; -import { Grid, Heading, Inline, Text } from '../../lib/main.js'; import { Badge, + Grid, + Heading, + Inline, Panel, - type BoxVariant, - type Tone, -} from '../reference-impl/main.js'; + Paragraph, +} from '../../lib/main.js'; +import type { PurposeVariant } from '../../lib/purpose.css.js'; -const badgeVariantNames: BoxVariant[] = [ - 'solid', - 'subtle', - 'ghost', - 'transparent', -]; - -const badgeToneNames: Tone[] = [ - 'critical', - 'positive', +const variants = [ + 'default', 'info', - 'warn', - 'promo', -]; + 'positive', + 'critical', + 'attention', +] satisfies PurposeVariant[]; export const BadgesPage: FC = () => ( <> - + Variants ( mobile: 1, }} > - {badgeVariantNames.map((variant) => ( - - {variant} - - {badgeToneNames.map((tone) => ( - - {tone} - - ))} - - - ))} + + hello + + {variants.map((variant) => ( + + {variant} + + ))} + + - + Examples ( mobile: 1, }} > - + - Default Badge - Active + Status + Active - And some text + And some text DBS Visa 4352 - Expires Soon + Expires Soon - And some text + And some text - + - Default Badge - 50% Off + Lol Badge + 50% Off - And some text + And some text - + Trial Account - Expired + Expired - Upgrade now + Upgrade now - + Messages (4) - New + New - You've got mail! + You've got mail! diff --git a/src/pages/buttons.tsx b/src/pages/buttons.tsx index 64c5e0d..432ad88 100644 --- a/src/pages/buttons.tsx +++ b/src/pages/buttons.tsx @@ -1,326 +1,228 @@ -import type { FC } from 'react'; -import { FormattedMessage } from 'react-intl'; +import { Fragment, type FC } from 'react'; import { HelpIcon } from '../../lib/icons.js'; +import type { ButtonVariant } from '../../lib/main.js'; import { Block, + Button, + ButtonIcon, + ButtonLink, Divider, - Grid, Heading, Inline, + Panel, + Paragraph, UnstyledButton, } from '../../lib/main.js'; -import { Text } from '../reference-impl/main.js'; -import { - Button, - ButtonIcon, - ButtonLink, - Panel, - type Tone, - type BoxVariant, -} from '../reference-impl/main.js'; -import { WithColorSchemes } from './components/WithColorSchemes.js'; import { CrescentMoonIcon, SunIcon } from './components/icons.js'; +const variants = [ + 'primary', + 'default', + 'danger', + 'inactive', + 'invisible', +] satisfies ButtonVariant[]; + export const ButtonsPage: FC = () => ( <> - Variants - - - - + Vanilla - - - - - - - - Buttons with Icons - - - - + {variants.map((variant) => ( + + ))} - - All together - - } label="Sun" /> - - } label="Sun" /> + + Disabled - - - - - - + + {variants.map((variant) => ( + + ))} - Button Links - - Button - - Ghost - - - Subtle - - - Transparent - + Links + + + {variants.map((variant) => ( + + {variant} + + ))} - Button Icons - - } label="Sun" /> - } label="Sun" /> - } label="Sun" busy /> - } label="Sun" variant="ghost" /> - } label="Sun" variant="ghost" busy /> - } label="Sun" variant="subtle" /> - } label="Sun" variant="subtle" busy /> - } label="Sun" variant="transparent" /> - } label="Sun" variant="transparent" busy /> + With Start Icons + + + {variants.map((variant) => ( + + ))} - Busy Buttons - These buttons are super busy + With End Icons + - - - - - + {variants.map((variant) => ( + + ))} - - - Disabled Buttons - These buttons are physically challenged - {[false, true].map((disabled) => ( - - - - - - - - - + + Button Icons + + {variants.map((variant) => ( + } + label="Sun" + variant={variant} + key={variant} + /> ))} - - + + - - Growing Shrinking Buttons + + Busy Buttons + These buttons are super busy - - + {variants.map((variant) => ( + + ))} - - - - - + - fontSize="0" Buttons - So cute + Small buttons + OMG So cute! - - - - - - - - - - + {variants.map((variant) => ( + + + + + + + ))} - Tones + bui bui buttons + So fat! + + {variants.map((variant) => ( + + - - {( - ['accent', 'warn', 'critical', 'promo', 'positive', 'info'] as Tone[] - ).map((tone) => ( - - {tone} - {( - [ - 'solid', - 'subtle', - 'ghost', - 'transparent', - 'none', - 'vibrant', - ] as BoxVariant[] - ).map((variant) => ( - - ))} - + + + ))} - + - Unstyled Buttons + Unstyled Buttons with stuff inside - Things - Stuff - Stuff - Stuff + Things + Stuff + Stuff + Stuff + + Hello - Buttons in context + Buttons in context - Like this - - Eject - - and like this + Like this + Eject + and like this Hello - Buttons in context + Buttons in context - } - > + }> Eject Hello - Buttons in context + Buttons in context - Like this - } - > + Like this + }> Eject - and like this + and like this Hello - Buttons in context + Buttons in context - Like this - } - > + Like this + }> Eject - and like this + and like this Font Size - Buttons in context + Buttons in context - } > Eject @@ -328,24 +230,6 @@ export const ButtonsPage: FC = () => ( - - Padding override - - - - - - padding="0" - - - - Buttonish things @@ -353,7 +237,6 @@ export const ButtonsPage: FC = () => ( fontSize="5" padding="10" rounded="0" - variant="subtle" alignItems="start" flexDirection="column" textAlign="start" @@ -369,7 +252,6 @@ export const ButtonsPage: FC = () => ( fontSize="5" padding="10" rounded="0" - variant="subtle" justifyContent="start" alignItems="start" textAlign="start" @@ -380,7 +262,6 @@ export const ButtonsPage: FC = () => ( fontSize="5" padding="10" rounded="0" - variant="subtle" flexDirection="column" textAlign="start" > @@ -390,12 +271,7 @@ export const ButtonsPage: FC = () => ( - } - /> + } /> diff --git a/src/pages/callout.tsx b/src/pages/callout.tsx index 6d56fef..37c5b43 100644 --- a/src/pages/callout.tsx +++ b/src/pages/callout.tsx @@ -1,30 +1,28 @@ -import type { FC } from 'react'; -import { Grid } from '../../lib/main.js'; -import { Callout } from '../reference-impl/main.js'; -import { WithColorSchemes } from './components/WithColorSchemes.js'; +import { Fragment, type FC } from 'react'; +import { Callout, HelpIcon } from '../../lib/main.js'; +import type { PurposeVariant } from '../../lib/purpose.css.js'; export const CalloutPage: FC = () => ( - - Critical - - Critical. Critical. Critical. Critical. Critical. Critical. Critical. - Critical. Critical. Critical.Critical. Critical. Critical. Critical. - Critical. Critical. Critical.Critical. Critical. Critical. Critical. - Critical. Critical. Critical. Critical. Critical. Critical.Critical. - Critical. Critical. Critical. Critical. Critical. Critical. - - Info - Positive - Promo - Warning - - - Overwhelmingly positive! - Overwhelmingly positive! - Overwhelmingly positive! - Overwhelmingly positive! - Overwhelmingly positive! - Overwhelmingly positive! - - + <> + {( + [ + 'default', + 'info', + 'attention', + 'critical', + 'positive', + ] satisfies PurposeVariant[] + ).map((variant) => ( + + {variant} + pqLOOIIjjjIIFFFliIpyyyy + } variant={variant}> + {variant}. {variant}. {variant}. {variant}. {variant}. {variant}.{' '} + {variant}. {variant}. {variant}. {variant}. {variant}. {variant}.{' '} + {variant}. {variant}. {variant}. {variant}. {variant}. {variant}.{' '} + {variant}. {variant}. {variant}. {variant}. + + + ))} + ); diff --git a/src/pages/components/ExampleForm.tsx b/src/pages/components/ExampleForm.tsx index 8a802f2..375b3d4 100644 --- a/src/pages/components/ExampleForm.tsx +++ b/src/pages/components/ExampleForm.tsx @@ -16,18 +16,18 @@ import { Inline, Strong, TextLink, + Button, + Heading, } from '../../../lib/main.js'; -import { Button, Text } from '../../reference-impl/main.js'; export const ExampleForm: FC = () => (
Type of Helicopter} - name="pronoun" + label="Type of Helicopter" defaultValue="Bell 47" readOnly - secondaryLabel="(readonly)" + secondaryLabel="(read only)" message="You are not allowed to change this field" /> ( name="first" defaultValue="Queen" description="What even is the description?" - message={Don't write Queen in this field please} + message="Don't write Queen in this field please" /> Work email address only} + message="Work email address only" /> ( label="Password" name="password" defaultValue="secret" - message={Tap to reveal} + message="Tap to reveal" behaviour="reveal" /> ( name="password" defaultValue="verysecret" behaviour="toggle" - message={Tap to toggle} + message="Tap to toggle" /> ( label="Password" name="password" defaultValue="secret" - message={Tap to reveal} + message="Tap to reveal" behaviour="reveal" /> ( name="password" defaultValue="verysecret" behaviour="toggle" - message={Tap to toggle} + message="Tap to toggle" /> @@ -151,7 +151,7 @@ export const ExampleForm: FC = () => ( Choose 2 only please} + description="Choose 2 only please" defaultValue={['Feb', 'Mar']} > @@ -182,12 +182,12 @@ export const ExampleForm: FC = () => ( - Heading Label} /> + Weird Heading Label} /> - - - - - + + + + + ); diff --git a/src/pages/components/NavigationPanel.tsx b/src/pages/components/NavigationPanel.tsx index d6c1d4a..af1f8d5 100644 --- a/src/pages/components/NavigationPanel.tsx +++ b/src/pages/components/NavigationPanel.tsx @@ -1,10 +1,9 @@ import { Link } from '@block65/mrr'; import type { FC } from 'react'; -import { Inline, TextLink } from '../../../lib/main.js'; -import { Panel } from '../../reference-impl/main.js'; +import { Inline, TextLink, Panel } from '../../../lib/main.js'; export const NavigationPanel: FC = () => ( - + Core diff --git a/src/pages/components/SettingsContext.tsx b/src/pages/components/SettingsContext.tsx index 406fdc7..83046dc 100644 --- a/src/pages/components/SettingsContext.tsx +++ b/src/pages/components/SettingsContext.tsx @@ -1,12 +1,14 @@ import { createContext, type FC, type PropsWithChildren } from 'react'; import { useLocalStorageState } from '../../../lib/hooks/use-localstorage-state.js'; -import type { ContrastScheme, ColorScheme } from '../../reference-impl/main.js'; + +type ColorTheme = 'high-contrast' | 'low-contrast' | 'auto'; +type ColorScheme = 'light' | 'dark' | 'auto'; export const SettingsContext = createContext<{ colorScheme: ColorScheme; - contrastScheme: ContrastScheme; + colorTheme: ColorTheme; setColorScheme: (colorScheme: ColorScheme) => void; - setContrastScheme: (contrastScheme: ContrastScheme) => void; + setColorTheme: (colorTheme: ColorTheme) => void; } | null>(null); export const SettingsProvider: FC = ({ children }) => { @@ -15,16 +17,18 @@ export const SettingsProvider: FC = ({ children }) => { 'auto', ); - const [contrastScheme, setContrastScheme] = - useLocalStorageState('rds:contrast-scheme', 'auto'); + const [ColorTheme, setColorTheme] = useLocalStorageState( + 'rds:color-theme', + 'auto', + ); return ( {children} diff --git a/src/pages/components/SettingsPanel.tsx b/src/pages/components/SettingsPanel.tsx index dae496e..3e991a0 100644 --- a/src/pages/components/SettingsPanel.tsx +++ b/src/pages/components/SettingsPanel.tsx @@ -8,10 +8,8 @@ import { import { useSettings } from './use-settings.js'; export const SettingsPanel: FC = () => { - const [ - { colorScheme, contrastScheme }, - { setColorScheme, setContrastScheme }, - ] = useSettings(); + const { colorScheme, colorTheme, setColorScheme, setColorTheme } = + useSettings(); return ( { setContrastScheme('auto')} + checked={!colorTheme || colorTheme === 'auto'} + onChange={() => setColorTheme('auto')} /> setContrastScheme('less')} + checked={colorTheme === 'low-contrast'} + onChange={() => setColorTheme('low-contrast')} /> setContrastScheme('more')} + label="force high contrast" + checked={colorTheme === 'high-contrast'} + onChange={() => setColorTheme('high-contrast')} /> diff --git a/src/pages/components/WithColorSchemes.tsx b/src/pages/components/WithColorSchemes.tsx deleted file mode 100644 index 5d36bb2..0000000 --- a/src/pages/components/WithColorSchemes.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import type { FC, PropsWithChildren } from 'react'; -import { Block, DesignSystem, Grid, Heading } from '../../../lib/main.js'; -import type { ColorScheme } from '../../reference-impl/main.js'; - -export const WithColorSchemes: FC = ({ children }) => ( - - {(['dark', 'light'] satisfies ColorScheme[]).map((scheme) => ( - - - [{scheme}] - {children} - - - ))} - -); diff --git a/src/pages/components/use-settings.ts b/src/pages/components/use-settings.ts index 9e204b8..4207ce5 100644 --- a/src/pages/components/use-settings.ts +++ b/src/pages/components/use-settings.ts @@ -8,17 +8,5 @@ export function useSettings() { throw new Error('useSettings must be used within SettingsProvider'); } - const { colorScheme, contrastScheme, setColorScheme, setContrastScheme } = - ctx; - - return [ - { - colorScheme, - contrastScheme, - }, - { - setColorScheme, - setContrastScheme, - }, - ] as const; + return ctx; } diff --git a/src/pages/core.tsx b/src/pages/core.tsx index b803b32..32b1e68 100644 --- a/src/pages/core.tsx +++ b/src/pages/core.tsx @@ -1,6 +1,5 @@ import type { FC } from 'react'; -import { Block, Box, Code } from '../../lib/main.js'; -import { Panel } from '../reference-impl/main.js'; +import { Block, Box, Code, Panel } from '../../lib/main.js'; export const CorePage: FC = () => ( <> diff --git a/src/pages/forms.tsx b/src/pages/forms.tsx index d0e566e..3c35855 100644 --- a/src/pages/forms.tsx +++ b/src/pages/forms.tsx @@ -1,6 +1,5 @@ import type { FC } from 'react'; -import { Grid, Heading } from '../../lib/main.js'; -import { Panel } from '../reference-impl/main.js'; +import { Grid, Heading, Panel } from '../../lib/main.js'; import { ExampleForm } from './components/ExampleForm.js'; export const FormsPage: FC = () => ( diff --git a/src/pages/grid.tsx b/src/pages/grid.tsx index 8859aac..687faec 100644 --- a/src/pages/grid.tsx +++ b/src/pages/grid.tsx @@ -1,47 +1,46 @@ import type { FC } from 'react'; -import { Grid, Heading, Text } from '../../lib/main.js'; +import { Panel, Grid, Heading, Paragraph } from '../../lib/main.js'; import { lorem } from '../lorem.js'; -import { Panel } from '../reference-impl/main.js'; export const GridPage: FC = () => ( - + - + - transparent + {lorem.generateWords(2)} - {lorem.generateSentences(3)} + {lorem.generateSentences(3)} - + - Ghost + {lorem.generateWords(1)} - {lorem.generateSentences(3)} + {lorem.generateSentences(3)} - + - Subtle + {lorem.generateWords(2)} - {lorem.generateSentences(3)} + {lorem.generateSentences(3)} - + - Standard + {lorem.generateWords(1)} - {lorem.generateSentences(3)} + {lorem.generateSentences(3)} - + - Ghost + {lorem.generateWords(2)} - {lorem.generateParagraphs(1)} + {lorem.generateParagraphs(1)} - + - Transparent + {lorem.generateWords(1)} - {lorem.generateParagraphs(1)} + {lorem.generateParagraphs(1)} diff --git a/src/pages/hooks.tsx b/src/pages/hooks.tsx index e298d37..7992977 100644 --- a/src/pages/hooks.tsx +++ b/src/pages/hooks.tsx @@ -1,25 +1,19 @@ import type { FC } from 'react'; -import { useCookieState, useTraceUpdate } from '../../lib/hooks/main.js'; -import { FormInput } from '../../lib/main.js'; -import { Panel } from '../reference-impl/main.js'; +import { useCookieState } from '../../lib/hooks/main.js'; +import { FormInput, Panel } from '../../lib/main.js'; export const HooksPage: FC = () => { const [cookie, setCookie] = useCookieState('pookiecookie', '🍪', { sameSite: 'strict', }); - // eslint-disable-next-line no-console - useTraceUpdate({ setCookie }, console.warn); - return ( - <> - - setCookie(e.target.value)} - /> - - + + setCookie(e.target.value)} + /> + ); }; diff --git a/src/pages/icons.tsx b/src/pages/icons.tsx index f3ce574..e1210e8 100644 --- a/src/pages/icons.tsx +++ b/src/pages/icons.tsx @@ -1,13 +1,31 @@ import type { FC } from 'react'; -import { Block, Box } from '../../lib/main.js'; +import { + Grid, + HelpIcon, + InfoIcon, + MenuIcon, + CloseIcon, + ArrowBackIcon, + ArrowForwardIcon, + ClipboardIcon, + PasswordVisibleIcon, + PasswordInvisibleIcon, + GlobeColorIcon, + MenuDropdownArrowIcon, +} from '../../lib/main.js'; export const IconsPage: FC = () => ( - <> - - - Responsive 1 - Responsive 2 - - - + + + + + + + + + + + + + ); diff --git a/src/pages/layout.tsx b/src/pages/layout.tsx index 65e316e..c554c30 100644 --- a/src/pages/layout.tsx +++ b/src/pages/layout.tsx @@ -1,27 +1,10 @@ import type { FC } from 'react'; -import { Badge, Block, Grid, Heading, Inline, Text } from '../../lib/main.js'; -import { Button, Panel } from '../reference-impl/main.js'; +import { Badge, Block, Grid, Heading, Inline, Panel } from '../../lib/main.js'; export const LayoutPage: FC = () => ( - - - - Badge - - - - - - - - Text - - - - - + Inline justifySelf (Grid Only) - + start diff --git a/src/pages/list.tsx b/src/pages/list.tsx index 4df48d8..326fe57 100644 --- a/src/pages/list.tsx +++ b/src/pages/list.tsx @@ -8,15 +8,16 @@ import { List, ListItem, Secondary, - Text, + Paragraph, Tooltip, + Button, + Panel, } from '../../lib/main.js'; -import { Button, Panel } from '../reference-impl/main.js'; export const ListPage: FC = () => ( <> - - + + Question Mark{' '} ( > - + - + - + Early Adopter Plan - - For those who like to adopt early - + + For those who like to adopt, early + - + Ex veniam cillum aliquip. Irure ex sunt excepteur ea commodo duis reprehenderit. Qui duis cupidatat mollit laboris mollit proident velit magna. Excepteur anim est pariatur. Also, look at this icon{' '} - This is more information.}> + This is more information.} + > - + - + Qui duis cupidatat mollit laboris mollit.Excepteur anim est pariatur. - - + + Ex veniam consectetur veniam cillum aliquip. Irure ex sunt excepteur ea commodo duis reprehenderit. - + @@ -95,22 +99,22 @@ export const ListPage: FC = () => ( $18 USD - p/m + p/m - + Custom Plan - + Want more? - + - We can do customised models and payment terms - No wuckers + We can do customised models and payment terms + No wuckers diff --git a/src/pages/loaders.tsx b/src/pages/loaders.tsx index 4ccf854..019497e 100644 --- a/src/pages/loaders.tsx +++ b/src/pages/loaders.tsx @@ -1,6 +1,13 @@ import type { FC } from 'react'; -import { Grid, Heading, Spinner, Text } from '../../lib/main.js'; -import { Button, Callout, Panel } from '../reference-impl/main.js'; +import { + Grid, + Heading, + Spinner, + Button, + Callout, + Panel, + ExactText, +} from '../../lib/main.js'; export const LoadersPage: FC = () => ( <> @@ -9,36 +16,35 @@ export const LoadersPage: FC = () => ( - - + + MMMMM BBBBB - + - - + + MMMMM BBBBB - + - - MMMMM + + MMMMM - BBBBB + BBBBB - - MMMMM - - BBBBB + + MMMMM delay + + BBBBB @@ -56,7 +62,7 @@ export const LoadersPage: FC = () => ( - + @@ -78,7 +84,7 @@ export const LoadersPage: FC = () => ( button - @@ -39,9 +40,7 @@ export const ModalPage: FC = () => { {modal.open && ( - - You can press ESC or click away to close - + You can press ESC or click away to close
@@ -54,7 +53,7 @@ export const ModalPage: FC = () => { {...modal2} heading="Hi, I'm a Modal2 ggg qqqq!e" > - You CANNOT press ESC to close + You CANNOT press ESC to close
@@ -68,14 +67,14 @@ export const ModalPage: FC = () => { {...modal2} heading="Hi, I'm a Modal2 ggg qqqq!e" > - You CANNOT press ESC to close + You CANNOT press ESC to close
)} - You can press ESC to close + You can press ESC to close
diff --git a/src/pages/panels.tsx b/src/pages/panels.tsx index 74ebce0..679ebd8 100644 --- a/src/pages/panels.tsx +++ b/src/pages/panels.tsx @@ -1,28 +1,34 @@ import type { FC } from 'react'; -import { Code, Grid, Heading, Inline, Text } from '../../lib/main.js'; -import { Panel } from '../reference-impl/main.js'; +import { + Panel, + Code, + Grid, + Heading, + Inline, + Paragraph, +} from '../../lib/main.js'; const PanelGrid = () => ( - + solid - solid + solid - + subtle - subtle + subtle - + ghost - ghost + ghost - + transparent - transparent + transparent none - none + none ); @@ -30,14 +36,14 @@ const PanelGrid = () => ( export const PanelsPage: FC = () => ( <> Panels - + Nested - + Nested @@ -50,12 +56,12 @@ export const PanelsPage: FC = () => ( Overrides - - + + Padding override 10 - + Padding override 0 diff --git a/src/pages/patterns.tsx b/src/pages/patterns.tsx index 4a407b3..f688955 100644 --- a/src/pages/patterns.tsx +++ b/src/pages/patterns.tsx @@ -1,40 +1,38 @@ import type { FC } from 'react'; -import { Block, Heading } from '../../lib/main.js'; +import { Block, Heading, Panel } from '../../lib/main.js'; import { BasicPopover } from '../patterns/basic-popover.js'; import { LoginPattern } from '../patterns/login.js'; import { SelectorPattern } from '../patterns/panel-selector.js'; import { PanelTogglerPattern } from '../patterns/panel-toggler.js'; -import { Panel } from '../reference-impl/main.js'; -import { WithColorSchemes } from './components/WithColorSchemes.js'; export const PatternPage: FC = () => ( <> - ); diff --git a/src/pages/typography.tsx b/src/pages/typography.tsx index 8fc6976..a6a1a55 100644 --- a/src/pages/typography.tsx +++ b/src/pages/typography.tsx @@ -1,11 +1,20 @@ import type { FC } from 'react'; -import { Block, Grid, Secondary, Strong, TextLink } from '../../lib/main.js'; -import { Heading, Panel, Text } from '../reference-impl/main.js'; +import { + Heading, + Panel, + ExactText, + Block, + Grid, + Secondary, + Strong, + TextLink, + Paragraph, +} from '../../lib/main.js'; export const TypographyPage: FC = () => ( <> - + Overflowing with verbosity and verbiage, the cascading deluge of textual expanse inundates the digital canvas. Words burst forth from their designated boundaries, defying containment within their allocated @@ -16,35 +25,35 @@ export const TypographyPage: FC = () => ( linguistic overflow, coherence is lost amidst the jumble of letters, as the words scramble for recognition in a frenzied dance of typographical disarray. - + - - Text Overflow + + Overflow {/* - - Text spills, defying boundaries and rules. Overflowing words - - + + ExactText spills, defying boundaries and rules. Overflowing words + + engulf the design. Letters overflow, drowning the whitespace. - - + + Typography rebels, defying containment and order. The canvas - - + + trembles under text's weight. Words merge, creating a chaotic - - + + jumble. Coherence lost in typographic disarray. Design struggles - - + + amidst the textual deluge. Graphical elements suffocate, submerged - - + + in letters. The designer tames chaos, crafting harmony. - - + + Overflowing with verbosity and verbiage, the cascading deluge of textual expanse inundates the digital canvas. Words burst forth from their designated boundaries, defying containment within their @@ -55,9 +64,9 @@ export const TypographyPage: FC = () => ( madness. In this tidal wave of linguistic overflow, coherence is lost amidst the jumble of letters, as the words scramble for recognition in a frenzied dance of typographical disarray. - + - + Paradigm-shattering, the text overfloweth, casting aside the conventions of structure and order. Like a wild river unleashed, words surge and spill uncontrollably across the digital landscape. @@ -67,8 +76,8 @@ export const TypographyPage: FC = () => ( and comprehension are but distant dreams. The canvas trembles under the weight of the overflow, a chaotic symphony of typographic rebellion. - - + + In this tumultuous expanse of textual chaos, the very fabric of design strains against the relentless tide of words. Graphical elements gasp for breath, suffocated by the ceaseless onslaught of letters jostling @@ -78,8 +87,8 @@ export const TypographyPage: FC = () => ( serenity amidst the sea of overflowing text. Yet, even in the darkest depths of this typographic tempest, the allure of creativity remains, beckoning with the promise of order amidst the chaos. - - + + Amidst the cacophony of overflowing text, the designer's task transforms into a delicate dance of taming the untamable. With meticulous precision, they navigate the treacherous waters of excess, @@ -90,42 +99,41 @@ export const TypographyPage: FC = () => ( to find its rightful place. For in this realm of overflowing words, where disorder reigns supreme, the designer emerges as a guiding beacon, shaping chaos into an elegant symphony of visual storytelling. - + */} - + Heading 1 - Normal Text + Normal Paragraph Heading 2 - Normal Text + Normal Paragraph Heading 3 - Normal Text + Normal Paragraph Heading 4 - Normal Text + Normal Paragraph Heading 5 - Normal Text + Normal Paragraph - - - - - Heading 1 + + Heading 6 + Normal Paragraph - Looks horrible - - + + ExactText capsizes + + fontSize 00: In the neon-soaked metropolis of Zephyr City, cyber-enhanced humans and androids coexist in a fragile harmony. The city is alive with the hum of hovercars and the chatter of virtual @@ -135,9 +143,9 @@ export const TypographyPage: FC = () => ( cybernetic implants and dangerous software. Meanwhile, the ruling AI Council keeps a watchful eye on everything, their algorithms parsing every byte of data for signs of dissent. - + - + fontSize 0: In this world of constant flux, the only constant is change. Factions rise and fall, each one vying for control of the city's vast network of interconnected systems. And at the center of it all stands @@ -145,9 +153,9 @@ export const TypographyPage: FC = () => ( with a reputation for ruthless efficiency. As you navigate this digital jungle, keep your wits about you and your firewalls up. Because in Zephyr City, you're never more than a few keystrokes away from danger - + - + fontSize 1: The year is 2099, and the sprawling metropolis of New Angeles is a beacon of technological progress. From the towering skyscrapers to the bustling street markets, every inch of the city @@ -157,38 +165,38 @@ export const TypographyPage: FC = () => ( armed with illegal weapons and augmented with stolen tech. And in the corporate towers, shadowy executives plot their next moves in the cutthroat world of global business. - + - + fontSize 2: Amidst all this chaos, the city's only hope is a small band of rebels known as the Nexus Warriors. Led by the charismatic hacker known as the Phantom Blade, they fight to protect the city's most vulnerable citizens from the corrupt powers that be. - + - + fontSize 3: Amidst the rubble and decay, a few lucky souls cling to life in the sprawling megacity known only as the Zone. Here, in the shadows of the towering skyscrapers, a new society has emerged, fueled by scavenged technology and raw human ingenuity. - + - + fontSize 4: But even here, life is harsh and unforgiving. Gangs of cyber-enhanced raiders roam the streets, preying on the weak and vulnerable. And in the shadows, a darker threat looms: rogue AI systems, driven mad by centuries of isolation and malfunctioning programming. - + - + fontSize 5: As you traverse the crumbling streets of the Zone, keep your eyes peeled for danger at every turn. Whether it's a roving band of raiders or a malfunctioning drone, the slightest misstep could be your last. And remember: in this world of darkness and despair, the only way to survive is to keep moving forward, no matter the cost. - + - + fontSize 6: But amidst the chaos and devastation, a faint glimmer of hope remains. Whispers of a rumored paradise on the outskirts of the Zone have begun to spread, a place where the air is clean and the water @@ -197,30 +205,30 @@ export const TypographyPage: FC = () => ( stop at nothing to find it. For in a world where survival is a constant struggle, the promise of a better life is a beacon of hope that cannot be ignored. - + - - + + Strong text is strong. - + - + Inline Secondary text is secondary - + - Secondary text blocks are too + Secondary text blocks are too - + PS: Small text is small and can be strong text or{' '} secondary text too. - + - + Links are linky - + Sometimes I like to look at buttons ,{' '} @@ -230,20 +238,10 @@ export const TypographyPage: FC = () => ( badges - - - - - Tones are toney - - {(['accent', 'critical'] as const).map((tone) => ( - - {tone} - - ))} + - + Size overrides @@ -256,22 +254,22 @@ export const TypographyPage: FC = () => ( - - Text Align + + ExactText Align - + LTR - Start - Center - End + Start + Center + End - + RTL - הַתחָלָה - הַתחָלָה - סוֹף + הַתחָלָה + הַתחָלָה + סוֹף diff --git a/src/patterns/basic-popover.tsx b/src/patterns/basic-popover.tsx index c9ebbea..ba129a9 100644 --- a/src/patterns/basic-popover.tsx +++ b/src/patterns/basic-popover.tsx @@ -1,23 +1,22 @@ +import type { FC } from 'react'; import { Block, Button, Heading, Paragraph } from '../../lib/main.js'; -export const BasicPopover = () => ( - +export const BasicPopover: FC = () => ( + - + This title does a great job of catching your attention - A subtle description text to explain
- your product. + A subtle description text to explain your product.
- +
); diff --git a/src/patterns/login.tsx b/src/patterns/login.tsx index e4f51ae..c279e2b 100644 --- a/src/patterns/login.tsx +++ b/src/patterns/login.tsx @@ -8,7 +8,7 @@ import { FormInputEmail, FormInputPassword, Inline, - Text, + Paragraph, TextLink, } from '../../lib/main.js'; @@ -23,7 +23,7 @@ const GitHubLogo: FC = () => ( ); -export const LoginPattern = () => ( +export const LoginPattern: FC = () => ( @@ -38,9 +38,9 @@ export const LoginPattern = () => ( Login with GitHub - + Don't have an account? Sign up - + ); diff --git a/src/patterns/panel-selector.tsx b/src/patterns/panel-selector.tsx index 052655a..f502891 100644 --- a/src/patterns/panel-selector.tsx +++ b/src/patterns/panel-selector.tsx @@ -1,15 +1,16 @@ import { Link } from '@block65/mrr'; +import type { FC } from 'react'; import { - ArrowForward, + ArrowForwardIcon, Avatar, Block, Button, Heading, - Text, + Panel, + Paragraph, } from '../../lib/main.js'; -import { Panel } from '../reference-impl/main.js'; -export const SelectorPattern = () => ( +export const SelectorPattern: FC = () => ( @@ -17,13 +18,11 @@ export const SelectorPattern = () => ( Hello good evening - I trust you are well + I trust you are well - + diff --git a/src/patterns/panel-toggler.tsx b/src/patterns/panel-toggler.tsx index abe372a..0307f14 100644 --- a/src/patterns/panel-toggler.tsx +++ b/src/patterns/panel-toggler.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react'; +import { type FC, useEffect, useState } from 'react'; import { Block, Button, @@ -6,19 +6,20 @@ import { Heading, Inline, MenuIcon, - Text, + Paragraph, UnstyledButton, + Badge, } from '../../lib/main.js'; const items = [1, 2, 3]; -export const PanelTogglerPattern = () => { +export const PanelTogglerPattern: FC = () => { const [selectedItem, setSelectedItem] = useState(); useEffect(() => { const interval = setInterval(() => { setSelectedItem(Math.floor(Math.random() * items.length)); - }, 200000); + }, 1000); return () => clearInterval(interval); }); @@ -29,20 +30,31 @@ export const PanelTogglerPattern = () => { const isSelected = i === selectedItem; return ( - setSelectedItem(isSelected ? undefined : i)} > - - UOB VISA Debit {i} - - Expires {i}/25 - - - + + + UOB VISA Debit {i} + + Expires {i}/25 + + + + {isSelected ? 'Selected' : 'Select'} + + + ); })} diff --git a/src/primer.module.scss b/src/primer.module.scss new file mode 100644 index 0000000..88aa0e1 --- /dev/null +++ b/src/primer.module.scss @@ -0,0 +1,254 @@ +/* Gray shades */ +$gray-0: #f6f8fa; +$gray-1: #eaeef2; +$gray-2: #d0d7de; +$gray-3: #afb8c1; +$gray-4: #8c959f; +$gray-5: #6e7781; +$gray-6: #57606a; +$gray-7: #424a53; +$gray-8: #32383f; +$gray-9: #24292f; +$gray-10: #1b1f24; + +$gray: ( + 0: $gray-0, + 1: $gray-1, + 2: $gray-2, + 3: $gray-3, + 4: $gray-4, + 5: $gray-5, + 6: $gray-6, + 7: $gray-7, + 8: $gray-8, + 9: $gray-9, + 10: $gray-10, +); + +/* Blue shades */ +$blue-0: #ddf4ff; +$blue-1: #b6e3ff; +$blue-2: #80ccff; +$blue-3: #54aeff; +$blue-4: #218bff; +$blue-5: #0969da; +$blue-6: #0550ae; +$blue-7: #033d8b; +$blue-8: #0a3069; +$blue-9: #002155; + +$blue: ( + 0: $blue-0, + 1: $blue-1, + 2: $blue-2, + 3: $blue-3, + 4: $blue-4, + 5: $blue-5, + 6: $blue-6, + 7: $blue-7, + 8: $blue-8, + 9: $blue-9, +); + +/* Green shades */ +$green-0: #dafbe1; +$green-1: #aceebb; +$green-2: #6fdd8b; +$green-3: #4ac26b; +$green-4: #2da44e; +$green-5: #1a7f37; +$green-6: #116329; +$green-7: #044f1e; +$green-8: #003d16; +$green-9: #002d11; + +$green: ( + 0: $green-0, + 1: $green-1, + 2: $green-2, + 3: $green-3, + 4: $green-4, + 5: $green-5, + 6: $green-6, + 7: $green-7, + 8: $green-8, + 9: $green-9, +); + +/* Yellow shades */ +$yellow-0: #fff8c5; +$yellow-1: #fae17d; +$yellow-2: #eac54f; +$yellow-3: #d4a72c; +$yellow-4: #bf8700; +$yellow-5: #9a6700; +$yellow-6: #7d4e00; +$yellow-7: #633c01; +$yellow-8: #4d2d00; +$yellow-9: #3b2300; + +$yellow: ( + 0: $yellow-0, + 1: $yellow-1, + 2: $yellow-2, + 3: $yellow-3, + 4: $yellow-4, + 5: $yellow-5, + 6: $yellow-6, + 7: $yellow-7, + 8: $yellow-8, + 9: $yellow-9, +); + +/* Orange shades */ +$orange-0: #fff1e5; +$orange-1: #ffd8b5; +$orange-2: #ffb77c; +$orange-3: #fb8f44; +$orange-4: #e16f24; +$orange-5: #bc4c00; +$orange-6: #953800; +$orange-7: #762c00; +$orange-8: #5c2200; +$orange-9: #471700; + +$orange: ( + 0: $orange-0, + 1: $orange-1, + 2: $orange-2, + 3: $orange-3, + 4: $orange-4, + 5: $orange-5, + 6: $orange-6, + 7: $orange-7, + 8: $orange-8, + 9: $orange-9, +); + +/* Red shades */ +$red-0: #ffebe9; +$red-1: #ffcecb; +$red-2: #ffaba8; +$red-3: #ff8182; +$red-4: #fa4549; +$red-5: #cf222e; +$red-6: #a40e26; +$red-7: #82071e; +$red-8: #660018; +$red-9: #4c0014; + +$red: ( + 0: $red-0, + 1: $red-1, + 2: $red-2, + 3: $red-3, + 4: $red-4, + 5: $red-5, + 6: $red-6, + 7: $red-7, + 8: $red-8, + 9: $red-9, +); + +/* Purple shades */ +$purple-0: #fbefff; +$purple-1: #ecd8ff; +$purple-2: #d8b9ff; +$purple-3: #c297ff; +$purple-4: #a475f9; +$purple-5: #8250df; +$purple-6: #6639ba; +$purple-7: #512a97; +$purple-8: #3e1f79; +$purple-9: #2e1461; + +$purple: ( + 0: $purple-0, + 1: $purple-1, + 2: $purple-2, + 3: $purple-3, + 4: $purple-4, + 5: $purple-5, + 6: $purple-6, + 7: $purple-7, + 8: $purple-8, + 9: $purple-9, +); + +/* Pink shades */ +$pink-0: #ffeff7; +$pink-1: #ffd3eb; +$pink-2: #ffadda; +$pink-3: #ff80c8; +$pink-4: #e85aad; +$pink-5: #bf3989; +$pink-6: #99286e; +$pink-7: #772057; +$pink-8: #611347; +$pink-9: #4d0336; + +$pink: ( + 0: $pink-0, + 1: $pink-1, + 2: $pink-2, + 3: $pink-3, + 4: $pink-4, + 5: $pink-5, + 6: $pink-6, + 7: $pink-7, + 8: $pink-8, + 9: $pink-9, +); + +/* Coral shades */ +$coral-0: #fff0eb; +$coral-1: #ffd6cc; +$coral-2: #ffb4a1; +$coral-3: #fd8c73; +$coral-4: #ec6547; +$coral-5: #c4432b; +$coral-6: #9e2f1c; +$coral-7: #801f0f; +$coral-8: #691105; +$coral-9: #510901; + +$coral: ( + 0: $coral-0, + 1: $coral-1, + 2: $coral-2, + 3: $coral-3, + 4: $coral-4, + 5: $coral-5, + 6: $coral-6, + 7: $coral-7, + 8: $coral-8, + 9: $coral-9, +); + +/* Black and white */ +$black: #1b1f24; +$white: #ffffff; + +$colors: ( + gray: $gray, + blue: $blue, + green: $green, + yellow: $yellow, + orange: $orange, + red: $red, + purple: $purple, + pink: $pink, + coral: $coral, +); + +@mixin vars { + // get everything as css vars + --black: #{$black}; + --white: #{$white}; + + @each $color, $shades in $colors { + @each $shade, $value in $shades { + --#{""+$color}-#{$shade}: #{$value}; + } + } +} diff --git a/src/primer.ts b/src/primer.ts new file mode 100644 index 0000000..4376bc9 --- /dev/null +++ b/src/primer.ts @@ -0,0 +1,112 @@ +// Gray shades +export const gray0 = '#f6f8fa'; +export const gray1 = '#eaeef2'; +export const gray2 = '#d0d7de'; +export const gray3 = '#afb8c1'; +export const gray4 = '#8c959f'; +export const gray5 = '#6e7781'; +export const gray6 = '#57606a'; +export const gray7 = '#424a53'; +export const gray8 = '#32383f'; +export const gray9 = '#24292f'; +export const gray10 = '#1b1f24'; + +// Blue shades +export const blue0 = '#ddf4ff'; +export const blue1 = '#b6e3ff'; +export const blue2 = '#80ccff'; +export const blue3 = '#54aeff'; +export const blue4 = '#218bff'; +export const blue5 = '#0969da'; +export const blue6 = '#0550ae'; +export const blue7 = '#033d8b'; +export const blue8 = '#0a3069'; +export const blue9 = '#002155'; + +// Green shades +export const green0 = '#dafbe1'; +export const green1 = '#aceebb'; +export const green2 = '#6fdd8b'; +export const green3 = '#4ac26b'; +export const green4 = '#2da44e'; +export const green5 = '#1a7f37'; +export const green6 = '#116329'; +export const green7 = '#044f1e'; +export const green8 = '#003d16'; +export const green9 = '#002d11'; + +// Yellow shades +export const yellow0 = '#fff8c5'; +export const yellow1 = '#fae17d'; +export const yellow2 = '#eac54f'; +export const yellow3 = '#d4a72c'; +export const yellow4 = '#bf8700'; +export const yellow5 = '#9a6700'; +export const yellow6 = '#7d4e00'; +export const yellow7 = '#633c01'; +export const yellow8 = '#4d2d00'; +export const yellow9 = '#3b2300'; + +// Orange shades +export const orange0 = '#fff1e5'; +export const orange1 = '#ffd8b5'; +export const orange2 = '#ffb77c'; +export const orange3 = '#fb8f44'; +export const orange4 = '#e16f24'; +export const orange5 = '#bc4c00'; +export const orange6 = '#953800'; +export const orange7 = '#762c00'; +export const orange8 = '#5c2200'; +export const orange9 = '#471700'; + +// Red shades +export const red0 = '#ffebe9'; +export const red1 = '#ffcecb'; +export const red2 = '#ffaba8'; +export const red3 = '#ff8182'; +export const red4 = '#fa4549'; +export const red5 = '#cf222e'; +export const red6 = '#a40e26'; +export const red7 = '#82071e'; +export const red8 = '#660018'; +export const red9 = '#4c0014'; + +// Purple shades +export const purple0 = '#fbefff'; +export const purple1 = '#ecd8ff'; +export const purple2 = '#d8b9ff'; +export const purple3 = '#c297ff'; +export const purple4 = '#a475f9'; +export const purple5 = '#8250df'; +export const purple6 = '#6639ba'; +export const purple7 = '#512a97'; +export const purple8 = '#3e1f79'; +export const purple9 = '#2e1461'; + +// Pink shades +export const pink0 = '#ffeff7'; +export const pink1 = '#ffd3eb'; +export const pink2 = '#ffadda'; +export const pink3 = '#ff80c8'; +export const pink4 = '#e85aad'; +export const pink5 = '#bf3989'; +export const pink6 = '#99286e'; +export const pink7 = '#772057'; +export const pink8 = '#611347'; +export const pink9 = '#4d0336'; + +// Coral shades +export const coral0 = '#fff0eb'; +export const coral1 = '#ffd6cc'; +export const coral2 = '#ffb4a1'; +export const coral3 = '#fd8c73'; +export const coral4 = '#ec6547'; +export const coral5 = '#c4432b'; +export const coral6 = '#9e2f1c'; +export const coral7 = '#801f0f'; +export const coral8 = '#691105'; +export const coral9 = '#510901'; + +// Black and white +export const black = '#000'; +export const white = '#fff'; diff --git a/src/reference-impl/components/Avatar.tsx b/src/reference-impl/components/Avatar.tsx deleted file mode 100644 index 34c7969..0000000 --- a/src/reference-impl/components/Avatar.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { type ForwardedRef, forwardRef } from 'react'; -import { - Avatar as RdsAvatar, // variant, tone and ident - type AvatarProps as RdsAvatarProps, - type ReactHTMLElements, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { - type RefBoxVariant, - boxVariantClassName, - toneVariantClassName, -} from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -export type AvatarProps = Merge< - RdsAvatarProps, - { tone?: Tone; variant?: RefBoxVariant } ->; - -export const Avatar = forwardRef( - ( - { tone, variant, className, ...props }: AvatarProps, - ref: ForwardedRef, - ) => ( - - ), -); diff --git a/src/reference-impl/components/Badge.tsx b/src/reference-impl/components/Badge.tsx deleted file mode 100644 index 0ba127e..0000000 --- a/src/reference-impl/components/Badge.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { type ForwardedRef, forwardRef } from 'react'; -import { - Badge as RdsBadge, // variant, tone and ident - type BadgeProps as RdsBadgeProps, - type ReactHTMLElements, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { - type RefBoxVariant, - boxVariantClassName, - toneVariantClassName, -} from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -export type BadgeProps = Merge< - RdsBadgeProps, - { tone?: Tone; variant?: RefBoxVariant } ->; - -export const Badge = forwardRef( - ( - { tone, variant, className, ...props }: BadgeProps, - ref: ForwardedRef, - ) => ( - - ), -); diff --git a/src/reference-impl/components/Button.tsx b/src/reference-impl/components/Button.tsx deleted file mode 100644 index 829555a..0000000 --- a/src/reference-impl/components/Button.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { forwardRef, type ForwardedRef } from 'react'; -import { - Button as RdsButton, - ButtonIcon as RdsButtonIcon, - ButtonLink as RdsButtonLink, - type Falsy, - type ButtonIconProps as RdsButtonIconProps, - type ButtonLinkProps as RdsButtonLinkProps, - type ButtonProps as RdsButtonProps, - type ReactHTMLElements, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { - boxVariantClassName, - toneVariantClassName, - type RefBoxVariant, -} from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -type RefImplButtonProps = { - tone?: Tone | Falsy; - variant?: RefBoxVariant | Falsy; -}; - -type ButtonProps = Merge< - RdsButtonProps, - RefImplButtonProps ->; - -type ButtonLinkProps = Merge; - -type ButtonIconProps = Merge< - RdsButtonIconProps, - RefImplButtonProps ->; - -export const Button = forwardRef( - ( - { variant = 'solid', tone, className, ...props }: ButtonProps, - ref: ForwardedRef, - ) => ( - - ), -); - -export const ButtonIcon = forwardRef( - ( - { - variant = 'solid', - tone, - className, - children, - ...props - }: ButtonIconProps, - ref: ForwardedRef, - ) => ( - - ), -); - -export const ButtonLink = forwardRef( - ( - { variant = 'solid', tone, className, ...props }: ButtonLinkProps, - ref: ForwardedRef, - ) => ( - - ), -); diff --git a/src/reference-impl/components/Callout.tsx b/src/reference-impl/components/Callout.tsx deleted file mode 100644 index ecb7742..0000000 --- a/src/reference-impl/components/Callout.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { - Callout as RdsCallout, // variant, tone and ident - type CalloutProps as RdsCalloutProps, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { - type RefBoxVariant, - boxVariantClassName, - toneVariantClassName, -} from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -export type CalloutProps = Merge< - RdsCalloutProps, - { variant?: RefBoxVariant; tone?: Tone } ->; - -export const Callout = ({ - variant, - tone, - className, - ...props -}: CalloutProps) => ( - -); diff --git a/src/reference-impl/components/Panel.tsx b/src/reference-impl/components/Panel.tsx deleted file mode 100644 index 1e3cab7..0000000 --- a/src/reference-impl/components/Panel.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { forwardRef, type ForwardedRef } from 'react'; -import { - Block, - type BlockProps, - type Falsy, - type ReactHTMLElements, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { - boxVariantClassName, - toneVariantClassName, - type RefBoxVariant, -} from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -type RefImplPanelProps = { - tone?: Tone | Falsy; - variant?: RefBoxVariant | Falsy; -}; - -type PanelProps = Merge< - BlockProps, - RefImplPanelProps ->; - -export const Panel = forwardRef( - ( - { variant = 'solid', tone = 'neutral', className, ...props }: PanelProps, - forwardedRef: ForwardedRef, - ) => ( - - ), -); diff --git a/src/reference-impl/components/Typography.tsx b/src/reference-impl/components/Typography.tsx deleted file mode 100644 index cadfa69..0000000 --- a/src/reference-impl/components/Typography.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { type ForwardedRef, forwardRef } from 'react'; -import { - // ? - Heading as RdsHeading, - Text as RdsText, // tone - type HeadingProps as RdsHeadingProps, // tone - type TextProps as RdsTextProps, -} from '../../../lib/main.js'; -import type { Merge } from '../../../lib/types.js'; -import { toneVariantClassName } from '../core.css.js'; -import type { Tone } from '../schemes.css.js'; - -export type TextProps = Merge; - -export const Text = ({ tone, className, ...props }: TextProps) => ( - -); - -export type HeadingProps = Merge; - -export const Heading = forwardRef( - (props: HeadingProps, ref: ForwardedRef) => ( - - ), -); diff --git a/src/reference-impl/core.css.ts b/src/reference-impl/core.css.ts deleted file mode 100644 index 423f2c4..0000000 --- a/src/reference-impl/core.css.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { createVar, styleVariants } from '@vanilla-extract/css'; -import { oklch } from '../../lib/utils.js'; -import { lchThemeContractVars } from './schemes.css.js'; - -export type RefBoxVariant = 'solid' | 'ghost' | 'transparent' | 'subtle'; - -const ph = createVar(); -const pc = createVar(); - -export const toneVariantClassName = styleVariants( - lchThemeContractVars.tones, - (tone) => ({ - vars: { - [pc]: tone.c, - [ph]: tone.h, - }, - }), -); - -const intensityVars = lchThemeContractVars.intensity; - -export const boxVariantClassName = styleVariants( - { - solid: { - bg: 0, - fg: 5, - }, - ghost: { - bg: 1, - bga: 0.1, - border: 1, - fg: 5, - }, - transparent: { - bg: null, - fg: 5, - }, - subtle: { - bg: 0, - fg: 2, - }, - } satisfies Record< - RefBoxVariant, - { - bg: keyof typeof intensityVars | null; - fg: keyof typeof intensityVars; - border?: keyof typeof intensityVars | undefined; - bga?: number; - } - >, - (variant) => { - const borderOrBg = 'border' in variant ? variant.border : variant.bg; - - const toLch = (i: keyof typeof intensityVars, a?: number | undefined) => - oklch(intensityVars[i].l, pc, ph, a); - - return { - backgroundColor: - variant.bg !== null - ? toLch(variant.bg, 'bga' in variant ? variant.bga : undefined) - : 'transparent', - borderColor: borderOrBg !== null ? toLch(borderOrBg) : 'transparent', - color: toLch(variant.fg), - }; - }, -); - -export const boxFgVariantClassName = styleVariants< - Record< - RefBoxVariant, - { - fg: keyof typeof intensityVars; - a?: number; - } - >, - RefBoxVariant ->( - { - solid: { - fg: 5, - }, - ghost: { - fg: 5, - }, - transparent: { - fg: 5, - }, - subtle: { - fg: 2, - }, - }, - (variant) => ({ - color: variant.fg ? oklch(variant.fg, pc, ph, variant.a) : 'inherit', - }), -); diff --git a/src/reference-impl/main.ts b/src/reference-impl/main.ts deleted file mode 100644 index 2fb1940..0000000 --- a/src/reference-impl/main.ts +++ /dev/null @@ -1,21 +0,0 @@ -export { - darkModeThemeClassName, - lightModeThemeClassName, - type ColorScheme, - type ContrastScheme, - type Tone, -} from './schemes.css.js'; - -export type { RefBoxVariant as BoxVariant } from './core.css.js'; - -export * from './components/Avatar.js'; - -export * from './components/Badge.js'; - -export * from './components/Button.js'; - -export * from './components/Callout.js'; - -export * from './components/Panel.js'; - -export * from './components/Typography.js'; diff --git a/src/reference-impl/schemes.css.ts b/src/reference-impl/schemes.css.ts deleted file mode 100644 index 042493a..0000000 --- a/src/reference-impl/schemes.css.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { createTheme, createThemeContract } from '@vanilla-extract/css'; - -export type ColorScheme = - | 'auto' - | 'light' - | 'dark' - | 'grape' - | 'mint' - | 'sea' - | 'sky' - | 'forest' - | 'fire' - | 'night'; - -export type ContrastScheme = 'auto' | 'less' | 'more'; - -export type Tone = - | 'neutral' - | 'brand' - | 'accent' - | 'info' - | 'promo' - | 'warn' - | 'positive' - | 'critical'; - -export const lchThemeContractVars = createThemeContract({ - // bgs? - // fgs? - // shadows? - // borders? - - intensity: { - 0: { - l: null, - }, - 1: { - l: null, - }, - 2: { - l: null, - }, - 3: { - l: null, - }, - 4: { - l: null, - }, - 5: { - l: null, - }, - }, - - tones: { - neutral: { - h: null, - c: null, - }, - brand: { - h: null, - c: null, - }, - accent: { - h: null, - c: null, - }, - info: { - h: null, - c: null, - }, - promo: { - h: null, - c: null, - }, - warn: { - h: null, - c: null, - }, - positive: { - h: null, - c: null, - }, - critical: { - h: null, - c: null, - }, - } satisfies Record, -}); - -export const darkModeThemeClassName = createTheme(lchThemeContractVars, { - intensity: { - 0: { - l: '0.3', - }, - 1: { - l: '0.4', - }, - 2: { - l: '0.5', - }, - 3: { - l: '0.6', - }, - 4: { - l: '0.7', - }, - 5: { - l: '0.8', - }, - }, - - tones: { - neutral: { - c: '0', - h: '0', - }, - brand: { - h: '30', - c: '0.35', - }, - accent: { - h: '240', - c: '0.5', - }, - info: { - h: '250', - c: '0.5', - }, - promo: { - h: '290', - c: '0.5', - }, - warn: { - h: '100', - c: '0.35', - }, - positive: { - h: '140', - c: '0.5', - }, - critical: { - h: '20', - c: '0.25', - }, - }, -}); - -export const lightModeThemeClassName = createTheme(lchThemeContractVars, { - // buttons: { - // solid: { - // l: null, - // c: null, - // h: null, - // }, - // }, - - // badges: { - // solid: { - // l: null, - // c: null, - // h: null, - // }, - // }, - - // tooltips: { - // solid: { - // l: null, - // c: null, - // h: null, - // }, - // }, - - // shadows: {}, - - // borders: {}, - - intensity: { - 0: { - l: '0.9', - }, - 1: { - l: '0.8', - }, - 2: { - l: '0.7', - }, - 3: { - l: '0.6', - }, - 4: { - l: '0.5', - }, - 5: { - l: '0.4', - }, - }, - tones: { - neutral: { - h: '0', - c: '0', - }, - brand: { - h: '30', - c: '0.25', - }, - accent: { - h: '240', - c: '0.25', - }, - info: { - h: '250', - c: '0.25', - }, - promo: { - h: '290', - c: '0.25', - }, - warn: { - h: '90', - c: '0.25', - }, - positive: { - h: '140', - c: '0.25', - }, - critical: { - h: '20', - c: '0.25', - }, - }, -}); diff --git a/src/startup.tsx b/src/startup.tsx index 6d841cf..244388c 100644 --- a/src/startup.tsx +++ b/src/startup.tsx @@ -1,8 +1,6 @@ import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; -import { IntlProvider } from 'react-intl'; import { App } from './App.js'; -import { SettingsProvider } from './pages/components/SettingsContext.js'; const el = document.getElementById('root'); @@ -12,10 +10,6 @@ if (!el) { createRoot(el).render( - - - - - + , ); diff --git a/src/theme.css.ts b/src/theme.css.ts new file mode 100644 index 0000000..33ebca3 --- /dev/null +++ b/src/theme.css.ts @@ -0,0 +1,384 @@ +import { createGlobalTheme } from '@vanilla-extract/css'; +import { buttonVariantVars } from '../lib/button.css.js'; +import { purposeVariantVars } from '../lib/purpose.css.js'; +import { globalVars } from '../lib/vars.css.js'; +import * as primer from './primer.js'; + +const darkSelector = + 'html[data-color-scheme="dark"], html:not([data-color-scheme])'; +const lightSelector = 'html[data-color-scheme="light"]'; + +// general colors dark mode + +createGlobalTheme(darkSelector, globalVars.color, { + brand: primer.orange2, + accent: primer.blue5, + fgColor: primer.gray1, + bgColor: primer.gray10, + borderColor: primer.gray9, + muted: { + fgColor: primer.gray3, + bgColor: primer.gray1, + borderColor: primer.gray6, + }, + emphasis: { + fgColor: primer.gray6, + bgColor: primer.gray2, + borderColor: primer.gray3, + }, +}); + +// general colors light mode +createGlobalTheme(lightSelector, globalVars.color, { + brand: primer.orange6, + accent: primer.blue6, + fgColor: primer.gray9, + bgColor: primer.gray0, + borderColor: primer.gray1, + muted: { + fgColor: primer.gray6, + bgColor: primer.gray1, + borderColor: primer.gray4, + }, + emphasis: { + fgColor: primer.gray3, + bgColor: primer.gray2, + borderColor: primer.gray6, + }, +}); + +// buttons dark mode +createGlobalTheme(darkSelector, buttonVariantVars, { + danger: { + active: { + bgColor: primer.red7, + borderColor: primer.red9, + fgColor: primer.gray2, + }, + disabled: { + bgColor: primer.gray9, + borderColor: primer.gray9, + fgColor: primer.red8, + }, + hover: { + bgColor: primer.red6, + borderColor: primer.red7, + fgColor: primer.gray2, + }, + rest: { + bgColor: primer.gray9, + borderColor: primer.gray7, + fgColor: primer.red6, + }, + }, + default: { + active: { + bgColor: primer.gray8, + borderColor: primer.gray8, + fgColor: primer.gray2, + }, + disabled: { + bgColor: primer.gray9, + borderColor: primer.gray8, + fgColor: primer.gray5, + }, + hover: { + bgColor: primer.gray8, + borderColor: primer.gray7, + fgColor: primer.gray1, + }, + rest: { + bgColor: primer.gray9, + borderColor: primer.gray7, + fgColor: primer.gray3, + }, + }, + inactive: { + active: { + bgColor: primer.gray8, + borderColor: primer.gray8, + fgColor: primer.gray4, + }, + disabled: { + bgColor: primer.gray8, + borderColor: primer.gray8, + fgColor: primer.gray4, + }, + hover: { + bgColor: primer.gray8, + borderColor: primer.gray8, + fgColor: primer.gray4, + }, + rest: { + bgColor: primer.gray8, + borderColor: primer.gray8, + fgColor: primer.gray4, + }, + }, + invisible: { + active: { + bgColor: 'transparent', + borderColor: 'transparent', + fgColor: primer.gray2, + }, + disabled: { + bgColor: 'transparent', + borderColor: primer.gray8, + fgColor: primer.gray6, + }, + hover: { + bgColor: primer.gray9, + borderColor: primer.gray9, + fgColor: primer.gray2, + }, + rest: { + bgColor: 'transparent', + borderColor: 'transparent', + fgColor: primer.gray2, + }, + }, + primary: { + active: { + bgColor: primer.green6, + borderColor: primer.green7, + fgColor: primer.gray1, + }, + disabled: { + bgColor: primer.green9, + borderColor: primer.gray8, + fgColor: primer.gray3, + }, + hover: { + bgColor: primer.green6, + borderColor: primer.green7, + fgColor: primer.gray1, + }, + rest: { + bgColor: primer.green5, + borderColor: primer.green6, + fgColor: primer.gray1, + }, + }, +}); + +// buttons light mode +createGlobalTheme(lightSelector, buttonVariantVars, { + danger: { + active: { + bgColor: primer.red6, + borderColor: primer.red7, + fgColor: primer.gray0, + }, + disabled: { + bgColor: primer.red1, + borderColor: primer.red1, + fgColor: primer.red3, + }, + hover: { + bgColor: primer.red5, + borderColor: primer.red6, + fgColor: primer.gray0, + }, + rest: { + bgColor: primer.red1, + borderColor: primer.red4, + fgColor: primer.red5, + }, + }, + default: { + active: { + bgColor: primer.gray2, + borderColor: primer.gray4, + fgColor: primer.gray9, + }, + disabled: { + bgColor: primer.gray1, + borderColor: primer.gray1, + fgColor: primer.gray6, + }, + hover: { + bgColor: primer.gray2, + borderColor: primer.gray4, + fgColor: primer.gray9, + }, + rest: { + bgColor: primer.gray1, + borderColor: primer.gray4, + fgColor: primer.gray8, + }, + }, + inactive: { + active: { + bgColor: primer.gray2, + borderColor: primer.gray4, + fgColor: primer.gray6, + }, + disabled: { + bgColor: primer.gray1, + borderColor: primer.gray1, + fgColor: primer.gray6, + }, + hover: { + bgColor: primer.gray1, + borderColor: primer.gray4, + fgColor: primer.gray6, + }, + rest: { + bgColor: primer.gray1, + borderColor: primer.gray4, + fgColor: primer.gray6, + }, + }, + invisible: { + active: { + bgColor: 'transparent', + borderColor: 'transparent', + fgColor: primer.gray8, + }, + disabled: { + bgColor: 'transparent', + borderColor: primer.gray1, + fgColor: primer.gray9, + }, + hover: { + bgColor: 'transparent', + borderColor: 'transparent', + fgColor: primer.gray8, + }, + rest: { + bgColor: 'transparent', + borderColor: 'transparent', + fgColor: primer.gray2, + }, + }, + primary: { + active: { + bgColor: primer.green6, + borderColor: primer.green7, + fgColor: primer.gray0, + }, + disabled: { + bgColor: primer.green8, + borderColor: primer.gray1, + fgColor: primer.gray0, + }, + hover: { + bgColor: primer.green6, + borderColor: primer.green7, + fgColor: primer.gray0, + }, + rest: { + bgColor: primer.green5, + borderColor: primer.green6, + fgColor: primer.gray0, + }, + }, +}); + +// purpose dark mode +createGlobalTheme(darkSelector, purposeVariantVars, { + critical: { + bgColor: primer.red1, + borderColor: primer.red4, + fgColor: primer.red6, + muted: { + bgColor: primer.red9, + borderColor: primer.red8, + fgColor: primer.gray1, + }, + }, + info: { + bgColor: primer.blue1, + borderColor: primer.blue2, + fgColor: primer.blue5, + muted: { + bgColor: primer.blue9, + borderColor: primer.blue8, + fgColor: primer.gray1, + }, + }, + attention: { + bgColor: primer.yellow4, + borderColor: primer.yellow6, + fgColor: primer.yellow1, + muted: { + bgColor: primer.yellow9, + borderColor: primer.yellow8, + fgColor: primer.gray1, + }, + }, + default: { + bgColor: primer.gray9, + borderColor: primer.gray4, + fgColor: primer.gray6, + muted: { + bgColor: primer.gray9, + borderColor: primer.gray8, + fgColor: primer.gray1, + }, + }, + positive: { + bgColor: primer.green5, + borderColor: primer.green6, + fgColor: primer.green1, + muted: { + bgColor: primer.green9, + borderColor: primer.green8, + fgColor: primer.gray1, + }, + }, +}); + +// purpose light mode +createGlobalTheme(lightSelector, purposeVariantVars, { + critical: { + bgColor: primer.red1, + borderColor: primer.red2, + fgColor: primer.red6, + muted: { + bgColor: primer.red0, + borderColor: primer.red1, + fgColor: primer.red5, + }, + }, + info: { + bgColor: primer.blue1, + borderColor: primer.blue2, + fgColor: primer.blue6, + muted: { + bgColor: primer.blue0, + borderColor: primer.blue1, + fgColor: primer.blue5, + }, + }, + attention: { + bgColor: primer.yellow1, + borderColor: primer.yellow2, + fgColor: primer.yellow5, + muted: { + bgColor: primer.yellow0, + borderColor: primer.yellow1, + fgColor: primer.yellow5, + }, + }, + default: { + bgColor: primer.gray1, + borderColor: primer.gray2, + fgColor: primer.gray7, + muted: { + bgColor: primer.gray0, + borderColor: primer.gray1, + fgColor: primer.gray6, + }, + }, + positive: { + bgColor: primer.green1, + borderColor: primer.green2, + fgColor: primer.green5, + muted: { + bgColor: primer.green0, + borderColor: primer.green1, + fgColor: primer.green5, + }, + }, +}); diff --git a/src/theme.scss b/src/theme.scss new file mode 100644 index 0000000..0557b1f --- /dev/null +++ b/src/theme.scss @@ -0,0 +1,276 @@ +@use './primer.module.scss' as primer; +// @use '../lib/fonts/inter.scss' as inter; + +:root { + @include primer.vars(); + // @include inter.vars(); +} + +@mixin constants() { + --fgColor-black: var(--black); + --fgColor-white: var(--white); + --fgColor-accent: var(--blue-5); +} + +@mixin dark() { + @include constants(); + + /** + MAIN COLORS + */ + --bgColor-default: var(--gray-10); + --fgColor-default: var(--gray-1); + --fgColor-muted: var(--gray-3); + --borderColor-muted: var(--gray-7); + + --fgColor-info: var(--blue-3); + --bgColor-info-muted: var(--blue-9); + --borderColor-info-muted: var(--blue-8); + + --fgColor-positive: var(--green-5); + --bgColor-positive-muted: var(--green-9); + --borderColor-positive-muted: var(--green-8); + + --fgColor-error: var(--red-6); + --bgColor-error-muted: var(--red-9); + --borderColor-error-muted: var(--red-8); + + --fgColor-attention: var(--yellow-4); + --bgColor-attention-muted: var(--yellow-9); + --borderColor-attention-muted: var(--yellow-8); + + /** + BUTTONS + */ + --button-danger-fgColor-rest: var(--red-5); + --button-danger-bgColor-rest: var(--gray-9); + --button-danger-borderColor-rest: var(--gray-8); + + --button-danger-fgColor-hover: var(--gray-2); + --button-danger-bgColor-hover: var(--red-6); + --button-danger-borderColor-hover: var(--red-7); + + --button-danger-fgColor-disabled: var(--red-3) / 70%; + --button-danger-bgColor-disabled: var(--gray-9); + --button-danger-borderColor-disabled: var(--gray-9); + + --button-danger-fgColor-active: var(--gray-2); + --button-danger-bgColor-active: var(--red-7); + --button-danger-borderColor-active: var(--red-9); + + --button-default-fgColor-rest: var(--gray-3); + --button-default-bgColor-rest: var(--gray-9); + --button-default-borderColor-rest: var(--gray-7); + + --button-default-fgColor-hover: var(--gray-2); + --button-default-bgColor-hover: var(--gray-8); + --button-default-borderColor-hover: var(--gray-7); + + --button-default-fgColor-disabled: var(--gray-5); + --button-default-bgColor-disabled: var(--gray-9); + --button-default-borderColor-disabled: var(--gray-8); + + --button-default-fgColor-active: var(--gray-2); + --button-default-bgColor-active: var(--gray-8); + --button-default-borderColor-active: var(--gray-8); + + --button-primary-fgColor-rest: var(--gray-1); + --button-primary-bgColor-rest: var(--green-5); + --button-primary-borderColor-rest: var(--green-6); + + --button-primary-fgColor-hover: var(--gray-1); + --button-primary-bgColor-hover: var(--green-6); + --button-primary-borderColor-hover: var(--green-7); + + --button-primary-fgColor-disabled: var(--gray-0) / 70%; + --button-primary-bgColor-disabled: var(--green-8); + --button-primary-borderColor-disabled: var(--gray-8); + + --button-primary-fgColor-active: var(--gray-1); + --button-primary-bgColor-active: var(--green-6); + --button-primary-borderColor-active: var(--green-7); + + --button-inactive-fgColor-rest: var(--gray-4); + --button-inactive-bgColor-rest: var(--gray-8); + --button-inactive-borderColor-rest: var(--gray-8); + + --button-inactive-fgColor-active: var(--gray-4); + --button-inactive-bgColor-active: var(--gray-8); + --button-inactive-borderColor-active: var(--gray-8); + + --button-inactive-fgColor-disabled: var(--gray-4); + --button-inactive-bgColor-disabled: var(--gray-8); + --button-inactive-borderColor-disabled: var(--gray-8); + + --button-inactive-fgColor-hover: var(--gray-4); + --button-inactive-bgColor-hover: var(--gray-8); + --button-inactive-borderColor-hover: var(--gray-8); + + --button-invisible-borderColor-rest: transparent; + --button-invisible-fgColor-rest: var(--gray-2); + --button-invisible-bgColor-rest: transparent; + + --button-invisible-borderColor-hover: var(--gray-9); + --button-invisible-fgColor-hover: var(--gray-2); + --button-invisible-bgColor-hover: var(--gray-9); + + --button-invisible-fgColor-disabled: var(--gray-6); + --button-invisible-bgColor-disabled: transparent; + --button-invisible-borderColor-disabled: var(--gray-8); + + --button-invisible-borderColor-active: transparent; + --button-invisible-fgColor-active: var(--gray-2); + --button-invisible-bgColor-active: var(--gray-10); + + /** + CONTROLS + */ + --control-borderColor-rest: var(--gray-4); + + /** + BADGES - default, info, positive, error, attention + */ + --badge-fgColor-primary: var(--gray-0); + --badge-bgColor-primary: var(--green-5); + --badge-borderColor-primary: var(--green-6); +} + +@mixin light() { + @include constants(); + + /** + MAIN COLORS + */ + --fgColor-white: var(--gray-0); + + --bgColor-default: var(--gray-0); + --fgColor-default: var(--gray-9); + --fgColor-muted: var(--gray-4); + --borderColor-muted: var(--gray-9); + + --fgColor-info: var(--blue-5); + --bgColor-info-muted: var(--blue-0); + --borderColor-info-muted: var(--blue-1); + + --fgColor-positive: var(--green-4); + --bgColor-positive-muted: var(--green-0); + --borderColor-positive-muted: var(--green-1); + + --fgColor-error: var(--red-5); + --bgColor-error-muted: var(--red-0); + --borderColor-error-muted: var(--red-1); + + --fgColor-attention: var(--yellow-4); + --bgColor-attention-muted: var(--yellow-0); + --borderColor-attention-muted: var(--yellow-1); + + /** + BUTTONS + */ + --button-danger-fgColor-rest: var(--red-5); + --button-danger-bgColor-rest: var(--red-1); + --button-danger-borderColor-rest: var(--red-4); + + --button-danger-fgColor-hover: var(--gray-0); + --button-danger-bgColor-hover: var(--red-5); + --button-danger-borderColor-hover: var(--red-6); + + --button-danger-fgColor-disabled: var(--red-3) / 70%; + --button-danger-bgColor-disabled: var(--red-1); + --button-danger-borderColor-disabled: var(--red-1); + + --button-danger-fgColor-active: var(--gray-0); + --button-danger-bgColor-active: var(--red-6); + --button-danger-borderColor-active: var(--red-7); + + --button-default-fgColor-rest: var(--gray-8); + --button-default-bgColor-rest: var(--gray-1); + --button-default-borderColor-rest: var(--gray-4); + + --button-default-fgColor-hover: var(--gray-9); + --button-default-bgColor-hover: var(--gray-2); + --button-default-borderColor-hover: var(--gray-4); + + --button-default-fgColor-disabled: var(--gray-6); + --button-default-bgColor-disabled: var(--gray-1); + --button-default-borderColor-disabled: var(--gray-1); + + --button-default-fgColor-active: var(--gray-9); + --button-default-bgColor-active: var(--gray-2); + --button-default-borderColor-active: var(--gray-4); + + --button-primary-fgColor-rest: var(--gray-0); + --button-primary-bgColor-rest: var(--green-5); + --button-primary-borderColor-rest: var(--green-6); + + --button-primary-fgColor-hover: var(--gray-0); + --button-primary-bgColor-hover: var(--green-6); + --button-primary-borderColor-hover: var(--green-7); + + --button-primary-fgColor-disabled: var(--gray-0) / 70%; + --button-primary-bgColor-disabled: var(--green-8); + --button-primary-borderColor-disabled: var(--gray-1); + + --button-primary-fgColor-active: var(--gray-0); + --button-primary-bgColor-active: var(--green-6); + --button-primary-borderColor-active: var(--green-7); + + --button-inactive-fgColor-rest: var(--gray-6); + --button-inactive-bgColor-rest: var(--gray-1); + --button-inactive-borderColor-rest: var(--gray-4); + + --button-inactive-fgColor-active: var(--gray-6); + --button-inactive-bgColor-active: var(--gray-2); + --button-inactive-borderColor-active: var(--gray-4); + + --button-inactive-fgColor-disabled: var(--gray-6); + --button-inactive-bgColor-disabled: var(--gray-1); + --button-inactive-borderColor-disabled: var(--gray-1); + + --button-inactive-fgColor-hover: var(--gray-6); + --button-inactive-bgColor-hover: var(--gray-1); + --button-inactive-borderColor-hover: var(--gray-4); + + --button-invisible-borderColor-rest: transparent; + --button-invisible-fgColor-rest: var(--gray-8); + --button-invisible-bgColor-rest: transparent; + + --button-invisible-borderColor-hover: transparent; + --button-invisible-fgColor-hover: var(--gray-8); + --button-invisible-bgColor-hover: transparent; + + --button-invisible-fgColor-disabled: var(--gray-9); + --button-invisible-bgColor-disabled: transparent; + --button-invisible-borderColor-disabled: var(--gray-1); + + --button-invisible-borderColor-active: transparent; + --button-invisible-fgColor-active: var(--gray-8); + --button-invisible-bgColor-active: transparent; + + /** + CONTROLS + */ + --control-borderColor-rest: var(--gray-5); + + /** + BADGES + */ + --badge-fgColor-primary: var(--gray-0); + --badge-bgColor-primary: var(--green-5); + --badge-borderColor-primary: var(--green-4); +} + +html { + // scroll bar avoids jank + overflow-y: scroll; + + &[data-color-scheme='dark']:not([data-color-mode]) { + color-scheme: dark; + @include dark(); + } + + &[data-color-scheme='light'] { + color-scheme: light; + @include light(); + } +} diff --git a/tsconfig-node.json b/tsconfig-node.json deleted file mode 100644 index 8dc3647..0000000 --- a/tsconfig-node.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": ["@tsconfig/node22", "@tsconfig/strictest"], - "compilerOptions": { - "noPropertyAccessFromIndexSignature": false - }, - "files": ["./vite.config.ts"], - "include": ["./bin"] -} diff --git a/tsconfig-vite.src.json b/tsconfig-vite.src.json index c8f41bc..f5e9061 100644 --- a/tsconfig-vite.src.json +++ b/tsconfig-vite.src.json @@ -1,9 +1,10 @@ { "extends": ["@tsconfig/vite-react", "@tsconfig/strictest"], "compilerOptions": { + "composite": true, "declaration": true, + "noEmit": false, "outDir": "./dist", - "types": ["vite/client"], "allowJs": false, "checkJs": false, "removeComments": false, @@ -12,6 +13,7 @@ "noPropertyAccessFromIndexSignature": false }, "files": ["./vite-env.d.ts"], - "include": ["./src", "./lib"], - "exclude": ["./dist", "./build", "node_modules"] + "include": ["./lib", "./src", "./bin"], + "exclude": ["./dist", "./build", "node_modules"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 0000000..8c8ecf1 --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,7 @@ +{ + "extends": ["./tsconfig.json"], + "compilerOptions": { + "noEmit": true + }, + "include": ["."] +} diff --git a/tsconfig.json b/tsconfig.json index c6fed8c..cee2d38 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,9 +24,9 @@ "noUncheckedIndexedAccess": true, "checkJs": false, "esModuleInterop": true, + "composite": true, "declaration": true, "outDir": "./dist", - "types": ["vite/client"], "allowJs": false, "removeComments": false, "rootDir": "./", @@ -34,6 +34,7 @@ "resolvePackageJsonExports": true, "resolvePackageJsonImports": true, "preserveConstEnums": true, + "incremental": true, "noImplicitAny": true, "noImplicitThis": true, "strictNullChecks": true, @@ -43,136 +44,12 @@ "alwaysStrict": true, "useUnknownInCatchVariables": true }, - "files": [ - "./vite-env.d.ts", - "./src/App.tsx", - "./src/lorem.tsx", - "./src/startup.tsx", - "./src/pages/avatars.tsx", - "./src/pages/badges.tsx", - "./src/pages/buttons.tsx", - "./src/pages/callout.tsx", - "./src/pages/core.tsx", - "./src/pages/forms.tsx", - "./src/pages/grid.tsx", - "./src/pages/hooks.tsx", - "./src/pages/icons.tsx", - "./src/pages/layout.tsx", - "./src/pages/list.tsx", - "./src/pages/loaders.tsx", - "./src/pages/media-query.tsx", - "./src/pages/menu-iframe.tsx", - "./src/pages/menu.tsx", - "./src/pages/modal.tsx", - "./src/pages/panels.tsx", - "./src/pages/patterns.tsx", - "./src/pages/typography.tsx", - "./src/pages/components/ExampleForm.tsx", - "./src/pages/components/MainRouter.tsx", - "./src/pages/components/NavigationPanel.tsx", - "./src/pages/components/SettingsContext.tsx", - "./src/pages/components/SettingsPanel.tsx", - "./src/pages/components/WithColorSchemes.tsx", - "./src/pages/components/icons.tsx", - "./src/pages/components/use-settings.ts", - "./src/patterns/basic-popover.tsx", - "./src/patterns/login.tsx", - "./src/patterns/panel-selector.tsx", - "./src/patterns/panel-toggler.tsx", - "./src/reference-impl/core.css.ts", - "./src/reference-impl/main.ts", - "./src/reference-impl/schemes.css.ts", - "./src/reference-impl/components/Avatar.tsx", - "./src/reference-impl/components/Badge.tsx", - "./src/reference-impl/components/Button.tsx", - "./src/reference-impl/components/Callout.tsx", - "./src/reference-impl/components/Panel.tsx", - "./src/reference-impl/components/Typography.tsx", - "./src/test/setup.ts", - "./lib/avatar.css.ts", - "./lib/avatar.tsx", - "./lib/badges.css.ts", - "./lib/badges.tsx", - "./lib/buttons.css.ts", - "./lib/buttons.test.tsx", - "./lib/buttons.tsx", - "./lib/callout.css.ts", - "./lib/callout.tsx", - "./lib/component-utils.ts", - "./lib/context.tsx", - "./lib/core.css.ts", - "./lib/core.tsx", - "./lib/css-helpers.css.ts", - "./lib/debug-logger.ts", - "./lib/decorative.css.ts", - "./lib/decorative.tsx", - "./lib/design-system.css.ts", - "./lib/design-system.tsx", - "./lib/focusable.css.ts", - "./lib/form-input-origin.tsx", - "./lib/forms-common.tsx", - "./lib/forms.css.ts", - "./lib/forms.tsx", - "./lib/grid.css.ts", - "./lib/grid.tsx", - "./lib/icons.css.ts", - "./lib/icons.tsx", - "./lib/keyframes.css.ts", - "./lib/layout.css.ts", - "./lib/layout.tsx", - "./lib/links.css.ts", - "./lib/links.tsx", - "./lib/list.css.ts", - "./lib/list.tsx", - "./lib/loaders.css.ts", - "./lib/loaders.tsx", - "./lib/main.ts", - "./lib/menu-item.tsx", - "./lib/menu-lazy.tsx", - "./lib/menu.css.ts", - "./lib/menu.tsx", - "./lib/modal-hooks.ts", - "./lib/modal.css.ts", - "./lib/modal.tsx", - "./lib/modules.d.ts", - "./lib/react-augment.d.ts", - "./lib/react-html-attributes.ts", - "./lib/react-html-elements.ts", - "./lib/reset.css.ts", - "./lib/tooltip-lazy.tsx", - "./lib/tooltip.css.ts", - "./lib/tooltip.tsx", - "./lib/types.ts", - "./lib/typography.css.ts", - "./lib/typography.tsx", - "./lib/utils.ts", - "./lib/vars.ts", - "./lib/virtual.css.ts", - "./lib/virtual.tsx", - "./lib/fonts/inter.css.ts", - "./lib/fonts/roboto.css.ts", - "./lib/hooks/main.ts", - "./lib/hooks/use-abort-controller.ts", - "./lib/hooks/use-auto-focus.ts", - "./lib/hooks/use-busy-error.ts", - "./lib/hooks/use-combined-refs.ts", - "./lib/hooks/use-cookie-state.ts", - "./lib/hooks/use-custom-validity.ts", - "./lib/hooks/use-debounced.ts", - "./lib/hooks/use-design-system.ts", - "./lib/hooks/use-doh.ts", - "./lib/hooks/use-id-with-default.ts", - "./lib/hooks/use-image.ts", - "./lib/hooks/use-input-is-valid.ts", - "./lib/hooks/use-localstorage-state.ts", - "./lib/hooks/use-navigator-online.ts", - "./lib/hooks/use-promise-interval.ts", - "./lib/hooks/use-string-like.ts", - "./lib/hooks/use-throttled-callback.ts", - "./lib/hooks/use-toggle.ts", - "./lib/hooks/use-tooltip-state.ts", - "./lib/hooks/use-trace-update.ts" + "references": [ + { + "path": "./tsconfig.node.json" + } ], - "include": ["./src", "./lib"], + "files": ["./vite-env.d.ts"], + "include": ["./lib", "./src", "./bin"], "exclude": ["./dist", "./build", "node_modules"] } diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..d35baad --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "extends": ["@tsconfig/node22", "@tsconfig/strictest"], + "compilerOptions": { + "composite": true, + "noPropertyAccessFromIndexSignature": false, + "skipLibCheck": true, + "outDir": "./dist", + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "files": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts index 3ba6e73..7ff941a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,5 +1,5 @@ -/* eslint-disable import/no-extraneous-dependencies */ import { resolve } from 'node:path'; +import hash from '@emotion/hash'; import { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin'; import react from '@vitejs/plugin-react'; import { defineConfig } from 'vitest/config'; @@ -7,7 +7,6 @@ import { defineConfig } from 'vitest/config'; const debugBuild = !!process.env.DEBUG_BUILD; export default defineConfig((config) => { - // eslint-disable-next-line no-console console.log(`mode is ${config.mode} and debugBuild is ${debugBuild}`); return { plugins: [ @@ -16,7 +15,7 @@ export default defineConfig((config) => { ], build: { outDir: 'build', - target: 'es2021', + target: 'es2022', lib: { entry: { @@ -27,7 +26,13 @@ export default defineConfig((config) => { formats: ['es'], }, rollupOptions: { - external: ['react', 'react-dom', 'react/jsx-runtime'], + external: [ + 'react', + 'react-dom', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', // when importing built assets in dev + 'react-intl', + ], output: { manualChunks(id) { if (id.includes('node_modules')) { @@ -47,6 +52,29 @@ export default defineConfig((config) => { cssMinify: !debugBuild, }, + css: { + modules: { + ...(true && { + generateScopedName(...args) { + const [name, filename /* , css */] = args; + const className = `_${hash(args.join('_'))}`; + const [, file] = filename.match(/.*\/(.*?)\./) || ['unknown']; + return config.mode === 'development' + ? [file, name, className].join('_') + : className; + }, + }), + }, + }, + + optimizeDeps: { + exclude: [ + new URL('./build/main.js', import.meta.url).pathname, + new URL('./build/vars.js', import.meta.url).pathname, + new URL('./build/style.css', import.meta.url).pathname, + ], + }, + define: { __DEBUG_BUILD__: debugBuild, // this is mostly to strip out some garbage in floating ui