diff --git a/.eslintignore b/.eslintignore index 5f9da3887be..3871e24b96c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,10 +1,3 @@ -node_modules -coverage -dist -reports -docs/public/assets/ -examples/extend-graphql-schema-nexus/nexus-types.ts -examples/framework-remix/build/index.js -tests/test-projects/live-reloading/schemas/syntax-error.js -__generated__ - +dist/ +node_modules/ +syntax-error.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 168b40e5923..00000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,115 +0,0 @@ -const reactComponentTypeMessage = { - message: - 'This type includes the children prop which is generally wrong, instead of using this type, type the props of the component', -}; - -module.exports = { - parser: '@typescript-eslint/parser', - env: { - browser: true, - es6: true, - node: true, - jest: true, - }, - plugins: ['react', 'react-hooks', 'jest', 'import', '@typescript-eslint'], - settings: { - react: { - version: 'detect', - }, - }, - rules: { - curly: ['error', 'multi-line'], - 'jsx-quotes': 'error', - 'no-trailing-spaces': 'error', - 'no-undef': 'error', - 'no-unused-expressions': 'error', - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'error', - '@typescript-eslint/no-unused-vars': 'off', - 'import/no-extraneous-dependencies': [ - 'error', - { - devDependencies: [ - '**/__tests__/**/*', - '**/*test.*', - '**/tests/**/*', - '**/build/**/*', - `packages/fields/src/**/filterTests.*`, - '**/test-fixtures.*', - ], - }, - ], - 'import/no-unresolved': 'error', - 'import/order': 'error', - 'jest/valid-describe': 'off', - 'jest/valid-expect': 'off', - 'jest/no-conditional-expect': 'off', - 'jest/no-standalone-expect': 'off', - 'jest/expect-expect': 'off', - 'jest/no-export': 'off', - 'jest/valid-title': 'off', - 'jest/no-try-expect': 'off', - 'jest/no-disabled-tests': 'error', - 'object-curly-spacing': ['error', 'always'], - quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }], - 'react/jsx-boolean-value': 'error', - 'react/jsx-no-undef': 'error', - 'react/jsx-uses-react': 'error', - 'react/jsx-uses-vars': 'error', - 'react/jsx-wrap-multilines': 'error', - 'react/react-in-jsx-scope': 'error', - 'react/self-closing-comp': 'error', - semi: 'off', - strict: 'off', - 'no-restricted-syntax': [ - 'error', - { - // Curious why we have this rule? - // - Enums only work for a subset of use cases that unions of string literals + objects work for and learning one language feature is easier than learning two language features - // - Enums are a new language feature which have runtime semantics which means they change TypeScript from JS + types to JS + types + extra language features which is harder to teach without clear advantages for this specific feature - selector: 'TSEnumDeclaration', - message: 'Use a union of string literals instead of an enum', - }, - ], - '@typescript-eslint/ban-types': [ - 'error', - { - extendDefaults: false, - types: { - Function: - '`Function` types are unsafe. Use more specific function types instead. e.g. (arg: number) => string', - String: { - message: - 'The `String` type refers to the String object which is probably not what you want, you probably want `string` instead which refers to the string primitive type.', - fixWith: 'string', - }, - ComponentType: reactComponentTypeMessage, - FC: reactComponentTypeMessage, - SFC: reactComponentTypeMessage, - 'React.ComponentType': reactComponentTypeMessage, - 'React.FC': reactComponentTypeMessage, - 'React.SFC': reactComponentTypeMessage, - }, - }, - ], - }, - extends: ['plugin:jest/recommended'], - - // Disable some rules for (code blocks within) Markdown docs - overrides: [ - { - files: ['**/*.{ts,tsx}'], - rules: { - // TypeScript already checks for the following things and they conflict with TypeScript - 'import/no-unresolved': 'off', - 'no-undef': 'off', - }, - }, - { - files: ['packages/core/src/scripts/tests/fixtures/**/*.{ts,tsx}'], - rules: { - 'import/no-extraneous-dependencies': 'off', - }, - }, - ], -}; diff --git a/.github/workflows/tests_ci.yml b/.github/workflows/tests_ci.yml index 0f72a698a23..f6ae1ff633c 100644 --- a/.github/workflows/tests_ci.yml +++ b/.github/workflows/tests_ci.yml @@ -19,20 +19,14 @@ jobs: - uses: actions/checkout@main - uses: ./.github/actions/ci-setup - - name: Prettier - run: pnpm lint:prettier - - name: TypeScript - run: pnpm lint:types - - - name: ESLint - run: pnpm lint:eslint + run: pnpm test:types - name: Preconstruct run: pnpm build - name: Prisma Filters - run: pnpm lint:filters + run: pnpm test:filters unit_tests: name: Package Unit Tests diff --git a/.github/workflows/tests_ci_windows.yml b/.github/workflows/tests_ci_windows.yml index bd162778fa7..07b932dc82b 100644 --- a/.github/workflows/tests_ci_windows.yml +++ b/.github/workflows/tests_ci_windows.yml @@ -8,16 +8,6 @@ concurrency: cancel-in-progress: true jobs: - linting: - name: Linting - runs-on: windows-latest - steps: - - uses: actions/checkout@main - - uses: ./.github/actions/ci-setup - - - name: TypeScript - run: pnpm lint:types - unit_tests: name: Package Unit Tests runs-on: windows-latest diff --git a/.gitignore b/.gitignore index c8e97b28dbe..9a1df743cce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,12 @@ -.env -.next -.keystone +.keystone/ +.next/ dist/ node_modules/ - -# sqlite databases *.db # ts-gql __generated__ -# OS +# system .DS_Store *.vscode diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index 209e3ef4b62..00000000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20 diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index e80b48597de..00000000000 --- a/.prettierignore +++ /dev/null @@ -1,18 +0,0 @@ -**/.keystone -**/.next -**/__generated__ -**/dist -**/*.graphql -*.vscode -.changeset/**/* -.keystone/tests -docs/**/*.md -docs/public/assets/*.js -examples/custom-output-paths/my-types.ts -examples/extend-graphql-schema-nexus/keystone-types.ts -examples/extend-graphql-schema-nexus/nexus-types.ts -nexus-typegen.ts -packages/icons/icons/* -pnpm-lock.yaml -prisma-utils/src/generated -tests/test-projects/live-reloading/schemas/syntax-error.js diff --git a/.remarkignore b/.remarkignore deleted file mode 100644 index 83b694704ba..00000000000 --- a/.remarkignore +++ /dev/null @@ -1 +0,0 @@ -CHANGELOG.md \ No newline at end of file diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md index a976a5d4269..26db7e00297 100644 --- a/CODE-OF-CONDUCT.md +++ b/CODE-OF-CONDUCT.md @@ -2,75 +2,133 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. ## Our Standards -Examples of behavior that contributes to creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -- Using welcoming and inclusive language -- Being respectful of other people -- Gracefully accepting constructive criticism -- Focusing on what is best for the community -- Showing empathy towards other community members +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community -Examples of unacceptable behavior by participants include: +Examples of unacceptable behavior include: -- The use of sexualized language or imagery and unwelcome sexual attention or - advances -- Trolling, insulting/derogatory comments, and personal or political attacks +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks - Public or private harassment -- Publishing others' private information, such as a physical or electronic - address, without explicit permission +- Publishing others' private information, such as a physical or email address, + without their explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. ## Scope -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at `codeofconduct@keystonejs.com`. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +reported to the community leaders responsible for enforcement at +[community@keystonejs.com](mailto:community@keystonejs.com). + +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, -available at +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. [homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations -For answers to common questions about this code of conduct, see - diff --git a/design-system/packages/button/src/Button.tsx b/design-system/packages/button/src/Button.tsx index 47449de6abb..03b33760799 100644 --- a/design-system/packages/button/src/Button.tsx +++ b/design-system/packages/button/src/Button.tsx @@ -1,51 +1,51 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { ReactNode, useContext } from 'react'; -import { forwardRefWithAs, jsx } from '@keystone-ui/core'; -import { LoadingDots } from '@keystone-ui/loading'; +import { type ReactNode, useContext } from 'react' +import { forwardRefWithAs, jsx } from '@keystone-ui/core' +import { LoadingDots } from '@keystone-ui/loading' -import { ButtonContext } from './context'; -import type { WeightKey, ToneKey, SizeKey } from './hooks/button'; +import { ButtonContext } from './context' +import type { WeightKey, ToneKey, SizeKey } from './hooks/button' type ButtonProps = { /** The Button label content. */ - children: ReactNode; + children: ReactNode /** Whether the Button should display as a block */ - isBlock?: boolean; + isBlock?: boolean /** Whether the Button should be disabled */ - isDisabled?: boolean; + isDisabled?: boolean /** Whether the Button should be in a loading state */ - isLoading?: boolean; + isLoading?: boolean /** The size of the Button. */ - size?: SizeKey; + size?: SizeKey /** The tone of the Button. */ - tone?: ToneKey; + tone?: ToneKey /** The weight of the Button. */ - weight?: WeightKey; -}; + weight?: WeightKey +} const loadingContainerStyles = { left: '50%', position: 'absolute', transform: 'translateX(-50%)', -} as const; +} as const export const Button = forwardRefWithAs<'button', ButtonProps>( ( { as: Tag = 'button', children, isDisabled, isLoading, size, tone, weight, ...otherProps }, ref ) => { - const { useButtonStyles, useButtonTokens, defaults } = useContext(ButtonContext); + const { useButtonStyles, useButtonTokens, defaults } = useContext(ButtonContext) const tokens = useButtonTokens({ size: size || defaults.size, tone: tone || defaults.tone, weight: weight || defaults.weight, - }); + }) const styles = useButtonStyles({ isDisabled, tokens, - }); + }) return ( @@ -56,6 +56,6 @@ export const Button = forwardRefWithAs<'button', ButtonProps>( )} - ); + ) } -); +) diff --git a/design-system/packages/button/src/context.tsx b/design-system/packages/button/src/context.tsx index 9785e91447b..87c04f851f2 100644 --- a/design-system/packages/button/src/context.tsx +++ b/design-system/packages/button/src/context.tsx @@ -1,49 +1,49 @@ -import React, { ReactNode, createContext, useContext, useMemo } from 'react'; +import React, { type ReactNode, createContext, useContext, useMemo } from 'react' import { buttonPropDefaults, useButtonStyles, useButtonTokens, - SizeKey, - ToneKey, - WeightKey, -} from './hooks/button'; + type SizeKey, + type ToneKey, + type WeightKey, +} from './hooks/button' export const ButtonContext = createContext<{ defaults: { - size: SizeKey; - tone: ToneKey; - weight: WeightKey; - }; - useButtonStyles: typeof useButtonStyles; - useButtonTokens: typeof useButtonTokens; + size: SizeKey + tone: ToneKey + weight: WeightKey + } + useButtonStyles: typeof useButtonStyles + useButtonTokens: typeof useButtonTokens }>({ defaults: buttonPropDefaults, useButtonStyles, useButtonTokens, -}); +}) // Note hooks are optional for the provider value, but not in the context created above; this is // because they will be merged with the existing context and always exist in the value type ProviderHooksProp = { - useButtonStyles?: typeof useButtonStyles; - useButtonTokens?: typeof useButtonTokens; -}; + useButtonStyles?: typeof useButtonStyles + useButtonTokens?: typeof useButtonTokens +} type ProviderDefaultsProp = { - size?: SizeKey; - tone?: ToneKey; - weight?: WeightKey; -}; + size?: SizeKey + tone?: ToneKey + weight?: WeightKey +} export const ButtonProvider = ({ defaults, hooks, children, }: { - defaults?: ProviderDefaultsProp; - hooks?: ProviderHooksProp; - children: ReactNode; + defaults?: ProviderDefaultsProp + hooks?: ProviderHooksProp + children: ReactNode }) => { - const parentContext = useContext(ButtonContext); + const parentContext = useContext(ButtonContext) const newContext = useMemo( () => ({ ...parentContext, @@ -54,6 +54,6 @@ export const ButtonProvider = ({ }, }), [parentContext, hooks, defaults] - ); - return {children}; -}; + ) + return {children} +} diff --git a/design-system/packages/button/src/hooks/button.ts b/design-system/packages/button/src/hooks/button.ts index d1c01bac213..a1599d3541e 100644 --- a/design-system/packages/button/src/hooks/button.ts +++ b/design-system/packages/button/src/hooks/button.ts @@ -1,9 +1,9 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { useTheme } from '@keystone-ui/core'; +import { useTheme } from '@keystone-ui/core' -export const buttonSizeValues = ['large', 'medium', 'small'] as const; +export const buttonSizeValues = ['large', 'medium', 'small'] as const export const buttonToneValues = [ 'active', 'passive', @@ -11,60 +11,60 @@ export const buttonToneValues = [ 'warning', 'negative', 'help', -] as const; -export const buttonWeightValues = ['bold', 'light', 'none', 'link'] as const; +] as const +export const buttonWeightValues = ['bold', 'light', 'none', 'link'] as const -export type SizeKey = (typeof buttonSizeValues)[number]; -export type ToneKey = (typeof buttonToneValues)[number]; -export type WeightKey = (typeof buttonWeightValues)[number]; +export type SizeKey = (typeof buttonSizeValues)[number] +export type ToneKey = (typeof buttonToneValues)[number] +export type WeightKey = (typeof buttonWeightValues)[number] export type ButtonPropDefaults = { - size: SizeKey; - tone: ToneKey; - weight: WeightKey; -}; + size: SizeKey + tone: ToneKey + weight: WeightKey +} export const buttonPropDefaults = { size: 'medium', tone: 'passive', weight: 'light', -} as const; +} as const type ButtonTokensProps = { - size: SizeKey; - tone: ToneKey; - weight: WeightKey; -}; + size: SizeKey + tone: ToneKey + weight: WeightKey +} type ButtonStateTokens = { - background?: string; - borderColor?: string; - foreground?: string; - shadow?: string; - textDecoration?: string; -}; + background?: string + borderColor?: string + foreground?: string + shadow?: string + textDecoration?: string +} export type ButtonTokens = { - borderRadius?: number; - borderWidth?: number; - disabledOpacity: number; - fontSize?: number | string; - fontWeight?: number; - height?: number; - paddingX?: number; - transition?: string; - focus: ButtonStateTokens; - hover: ButtonStateTokens; - pressed: ButtonStateTokens; -} & ButtonStateTokens; - -type Weight = ButtonStateTokens & Pick; - -export function useButtonTokens({ + borderRadius?: number + borderWidth?: number + disabledOpacity: number + fontSize?: number | string + fontWeight?: number + height?: number + paddingX?: number + transition?: string + focus: ButtonStateTokens + hover: ButtonStateTokens + pressed: ButtonStateTokens +} & ButtonStateTokens + +type Weight = ButtonStateTokens & Pick + +export function useButtonTokens ({ tone: toneKey, size: sizeKey, weight: weightKey, }: ButtonTokensProps): ButtonTokens { - const { animation, colors, tones, typography, controlSizes, opacity } = useTheme(); - const tone = tones[toneKey]; - const size = controlSizes[sizeKey]; + const { animation, colors, tones, typography, controlSizes, opacity } = useTheme() + const tone = tones[toneKey] + const size = controlSizes[sizeKey] const weights: { [key in WeightKey]: Weight } = { bold: { @@ -125,9 +125,9 @@ export function useButtonTokens({ textDecoration: 'underline', }, }, - }; + } - const weight = weights[weightKey]; + const weight = weights[weightKey] const tokens: ButtonTokens = { borderRadius: size.borderRadius, @@ -144,18 +144,18 @@ export function useButtonTokens({ opacity ${animation.duration100}, `, ...weight, - }; + } - return tokens; + return tokens } type ButtonStylesProps = { - isDisabled?: boolean; - isBlock?: boolean; - tokens: ButtonTokens; -}; + isDisabled?: boolean + isBlock?: boolean + tokens: ButtonTokens +} -export function useButtonStyles({ isDisabled, isBlock, tokens }: ButtonStylesProps) { +export function useButtonStyles ({ isDisabled, isBlock, tokens }: ButtonStylesProps) { const baseStyles = { alignItems: 'center', borderStyle: 'solid', @@ -172,7 +172,7 @@ export function useButtonStyles({ isDisabled, isBlock, tokens }: ButtonStylesPro userSelect: 'none', whiteSpace: 'nowrap', width: isBlock ? '100%' : undefined, - } as const; + } as const const tokenStyles = { backgroundColor: tokens.background || 'transparent', @@ -209,7 +209,7 @@ export function useButtonStyles({ isDisabled, isBlock, tokens }: ButtonStylesPro color: tokens.pressed.foreground, textDecoration: tokens.pressed.textDecoration, }, - }; + } - return { ...baseStyles, ...tokenStyles }; + return { ...baseStyles, ...tokenStyles } } diff --git a/design-system/packages/button/src/index.ts b/design-system/packages/button/src/index.ts index 52deb61bb86..51cfb43c647 100644 --- a/design-system/packages/button/src/index.ts +++ b/design-system/packages/button/src/index.ts @@ -1,3 +1,3 @@ -export * from './Button'; -export * from './context'; -export * from './hooks/button'; +export * from './Button' +export * from './context' +export * from './hooks/button' diff --git a/design-system/packages/core/src/a11y/VisuallyHidden.tsx b/design-system/packages/core/src/a11y/VisuallyHidden.tsx index c7899890941..7c18962bb46 100644 --- a/design-system/packages/core/src/a11y/VisuallyHidden.tsx +++ b/design-system/packages/core/src/a11y/VisuallyHidden.tsx @@ -1,19 +1,19 @@ -import React, { ReactNode } from 'react'; -import { forwardRefWithAs } from '../utils'; +import React, { type ReactNode } from 'react' +import { forwardRefWithAs } from '../utils' // Only display content to screen readers // ------------------------------ // See: https://a11yproject.com/posts/how-to-hide-content/ type Props = { - children?: ReactNode; -}; + children?: ReactNode +} export const VisuallyHidden = forwardRefWithAs<'span', Props>( ({ as: Tag = 'span', ...props }, ref) => { - return ; + return } -); +) export const visuallyHiddenStyles = { border: 0, @@ -24,4 +24,4 @@ export const visuallyHiddenStyles = { position: 'absolute', whiteSpace: 'nowrap', width: 1, -} as const; +} as const diff --git a/design-system/packages/core/src/components/Box.tsx b/design-system/packages/core/src/components/Box.tsx index 5ef4d7e44a0..68abdc3c192 100644 --- a/design-system/packages/core/src/components/Box.tsx +++ b/design-system/packages/core/src/components/Box.tsx @@ -1,88 +1,88 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; +import { jsx } from '../emotion' -import { useTheme } from '../theme'; -import { useMediaQuery } from '../hooks/useMediaQuery'; -import { forwardRefWithAs, mapResponsiveProp } from '../utils'; -import { ResponsiveProp, Theme } from '../types'; +import { useTheme } from '../theme' +import { useMediaQuery } from '../hooks/useMediaQuery' +import { forwardRefWithAs, mapResponsiveProp } from '../utils' +import { type ResponsiveProp, type Theme } from '../types' // Types // ----- -type DimensionType = number | string; +type DimensionType = number | string -type TextAlign = 'left' | 'right' | 'center' | 'justify' | 'start' | 'end'; -type TextAlignment = ResponsiveProp; +type TextAlign = 'left' | 'right' | 'center' | 'justify' | 'start' | 'end' +type TextAlignment = ResponsiveProp -type ColorType = ResponsiveProp; +type ColorType = ResponsiveProp export type ColorProps = { /** background-color */ - background?: ColorType; + background?: ColorType /** color */ - foreground?: ColorType; -}; + foreground?: ColorType +} -type RadiiType = ResponsiveProp; +type RadiiType = ResponsiveProp export type RadiiProps = { /** border-radius */ - rounding?: RadiiType; + rounding?: RadiiType /** border-bottom-left-radius and border-bottom-right-radius */ - roundingBottom?: RadiiType; + roundingBottom?: RadiiType /** border-bottom-left-radius and border-top-left-radius */ - roundingLeft?: RadiiType; + roundingLeft?: RadiiType /** border-bottom-right-radius and border-top-right-radius */ - roundingRight?: RadiiType; + roundingRight?: RadiiType /** border-bottom-left-radius and border-bottom-right-radius */ - roundingTop?: RadiiType; -}; + roundingTop?: RadiiType +} -type SpacingType = ResponsiveProp; +type SpacingType = ResponsiveProp export type MarginProps = { /** margin */ - margin?: SpacingType; + margin?: SpacingType /** margin-top */ - marginTop?: SpacingType; + marginTop?: SpacingType /** margin-right */ - marginRight?: SpacingType; + marginRight?: SpacingType /** margin-bottom */ - marginBottom?: SpacingType; + marginBottom?: SpacingType /** margin-left */ - marginLeft?: SpacingType; + marginLeft?: SpacingType /** margin-top and margin-bottom */ - marginY?: SpacingType; + marginY?: SpacingType /** margin-left and margin-right */ - marginX?: SpacingType; -}; + marginX?: SpacingType +} export type PaddingProps = { /** padding */ - padding?: SpacingType; + padding?: SpacingType /** padding-top */ - paddingTop?: SpacingType; + paddingTop?: SpacingType /** padding-right */ - paddingRight?: SpacingType; + paddingRight?: SpacingType /** padding-bottom */ - paddingBottom?: SpacingType; + paddingBottom?: SpacingType /** padding-left */ - paddingLeft?: SpacingType; + paddingLeft?: SpacingType /** padding-top and padding-bottom */ - paddingY?: SpacingType; + paddingY?: SpacingType /** padding-left and padding-right */ - paddingX?: SpacingType; -}; + paddingX?: SpacingType +} type BaseBoxProps = { /** text-align */ - textAlign?: TextAlignment; + textAlign?: TextAlignment /** height */ - height?: ResponsiveProp; + height?: ResponsiveProp /** width */ - width?: ResponsiveProp; -}; + width?: ResponsiveProp +} -export type BoxProps = ColorProps & RadiiProps & MarginProps & PaddingProps & BaseBoxProps; +export type BoxProps = ColorProps & RadiiProps & MarginProps & PaddingProps & BaseBoxProps // Style Functions // --------------- @@ -113,8 +113,8 @@ export const useBoxStyles = ({ textAlign, width, }: BoxProps) => { - const theme = useTheme(); - const { mq } = useMediaQuery(); + const theme = useTheme() + const { mq } = useMediaQuery() const resolvedColors = useColors( { @@ -122,7 +122,7 @@ export const useBoxStyles = ({ foreground, }, theme - ); + ) const resolvedMargin = useMargin( { @@ -135,7 +135,7 @@ export const useBoxStyles = ({ marginX, }, theme - ); + ) const resolvedPadding = usePadding( { @@ -148,12 +148,12 @@ export const useBoxStyles = ({ paddingX, }, theme - ); + ) const resolvedRounding = useRadii( { rounding, roundingTop, roundingRight, roundingBottom, roundingLeft }, theme - ); + ) return mq({ ...resolvedColors, @@ -164,27 +164,27 @@ export const useBoxStyles = ({ height: height, textAlign: textAlign, width: width, - }); -}; + }) +} // Utils // ------------------------------ -function useColors({ background, foreground }: ColorProps, { palette }: Theme) { +function useColors ({ background, foreground }: ColorProps, { palette }: Theme) { return { backgroundColor: background && mapResponsiveProp(background, palette), color: foreground && mapResponsiveProp(foreground, palette), - }; + } } -function useRadii( +function useRadii ( { rounding, roundingTop, roundingRight, roundingBottom, roundingLeft }: RadiiProps, { radii }: Theme ) { - let borderBottomLeftRadius = roundingBottom || roundingLeft || rounding; - let borderBottomRightRadius = roundingBottom || roundingRight || rounding; - let borderTopLeftRadius = roundingTop || roundingLeft || rounding; - let borderTopRightRadius = roundingTop || roundingRight || rounding; + let borderBottomLeftRadius = roundingBottom || roundingLeft || rounding + let borderBottomRightRadius = roundingBottom || roundingRight || rounding + let borderTopLeftRadius = roundingTop || roundingLeft || rounding + let borderTopRightRadius = roundingTop || roundingRight || rounding return { borderBottomLeftRadius: @@ -193,10 +193,10 @@ function useRadii( borderBottomRightRadius && mapResponsiveProp(borderBottomRightRadius, radii), borderTopLeftRadius: borderTopLeftRadius && mapResponsiveProp(borderTopLeftRadius, radii), borderTopRightRadius: borderTopRightRadius && mapResponsiveProp(borderTopRightRadius, radii), - }; + } } -function usePadding( +function usePadding ( { padding, paddingTop, @@ -208,34 +208,34 @@ function usePadding( }: PaddingProps, { spacing }: Theme ) { - let pb = paddingBottom || paddingY || padding; - let pt = paddingTop || paddingY || padding; - let pl = paddingLeft || paddingX || padding; - let pr = paddingRight || paddingX || padding; + let pb = paddingBottom || paddingY || padding + let pt = paddingTop || paddingY || padding + let pl = paddingLeft || paddingX || padding + let pr = paddingRight || paddingX || padding return { paddingBottom: pb && mapResponsiveProp(pb, spacing), paddingTop: pt && mapResponsiveProp(pt, spacing), paddingLeft: pl && mapResponsiveProp(pl, spacing), paddingRight: pr && mapResponsiveProp(pr, spacing), - }; + } } -function useMargin( +function useMargin ( { margin, marginTop, marginRight, marginBottom, marginLeft, marginY, marginX }: MarginProps, { spacing }: Theme ) { - let mb = marginBottom || marginY || margin; - let mt = marginTop || marginY || margin; - let ml = marginLeft || marginX || margin; - let mr = marginRight || marginX || margin; + let mb = marginBottom || marginY || margin + let mt = marginTop || marginY || margin + let ml = marginLeft || marginX || margin + let mr = marginRight || marginX || margin return { marginBottom: mb && mapResponsiveProp(mb, spacing), marginTop: mt && mapResponsiveProp(mt, spacing), marginLeft: ml && mapResponsiveProp(ml, spacing), marginRight: mr && mapResponsiveProp(mr, spacing), - }; + } } // Box Component @@ -268,7 +268,7 @@ export const Box = forwardRefWithAs<'div', BoxProps>(({ as: Tag = 'div', ...prop textAlign, width, ...attrs - } = props; + } = props const boxStyles = useBoxStyles({ background, @@ -295,7 +295,7 @@ export const Box = forwardRefWithAs<'div', BoxProps>(({ as: Tag = 'div', ...prop roundingTop, textAlign, width, - }); + }) - return ; -}); + return +}) diff --git a/design-system/packages/core/src/components/Center.tsx b/design-system/packages/core/src/components/Center.tsx index 9ccbf66b9ea..c68c2d4411a 100644 --- a/design-system/packages/core/src/components/Center.tsx +++ b/design-system/packages/core/src/components/Center.tsx @@ -1,14 +1,14 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; +import { jsx } from '../emotion' -import { forwardRefWithAs } from '../utils'; -import { Box, BoxProps } from './Box'; +import { forwardRefWithAs } from '../utils' +import { Box, type BoxProps } from './Box' type CenterProps = { - fillView?: boolean; -} & BoxProps; + fillView?: boolean +} & BoxProps export const Center = forwardRefWithAs<'div', CenterProps>( ({ fillView = false, ...props }, ref) => { @@ -24,6 +24,6 @@ export const Center = forwardRefWithAs<'div', CenterProps>( }} {...props} /> - ); + ) } -); +) diff --git a/design-system/packages/core/src/components/Core.tsx b/design-system/packages/core/src/components/Core.tsx index b24296eff34..94a5513b608 100644 --- a/design-system/packages/core/src/components/Core.tsx +++ b/design-system/packages/core/src/components/Core.tsx @@ -1,20 +1,20 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Fragment, ReactNode } from 'react'; -import { jsx, Global } from '../emotion'; +import { Fragment, type ReactNode } from 'react' +import { jsx, Global } from '../emotion' -import { normalize } from '../normalize'; -import { useTheme } from '../theme'; +import { normalize } from '../normalize' +import { useTheme } from '../theme' type CoreProps = { /** The app content. */ - children: ReactNode; + children: ReactNode /** Include styles to normalize element styles among browsers. */ - includeNormalize?: boolean; + includeNormalize?: boolean /** Optimize text rendering with CSS. */ - optimizeLegibility?: boolean; -}; + optimizeLegibility?: boolean +} export const Core = ({ children, @@ -26,16 +26,16 @@ export const Core = ({ {children} - ); -}; + ) +} // Base CSS // ------------------------------ -type BaseCSSProps = Omit; +type BaseCSSProps = Omit const BaseCSS = ({ includeNormalize, optimizeLegibility }: BaseCSSProps) => { - const { typography, colors } = useTheme(); + const { typography, colors } = useTheme() return ( @@ -81,5 +81,5 @@ const BaseCSS = ({ includeNormalize, optimizeLegibility }: BaseCSSProps) => { }} /> - ); -}; + ) +} diff --git a/design-system/packages/core/src/components/Divider.tsx b/design-system/packages/core/src/components/Divider.tsx index 5e477e735e4..f2afc948b0f 100644 --- a/design-system/packages/core/src/components/Divider.tsx +++ b/design-system/packages/core/src/components/Divider.tsx @@ -1,37 +1,37 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; +import { jsx } from '../emotion' -import { useTheme } from '../theme'; -import { ResponsiveProp, Theme } from '../types'; -import { Box, MarginProps } from './Box'; +import { useTheme } from '../theme' +import { type ResponsiveProp, type Theme } from '../types' +import { Box, type MarginProps } from './Box' -type ColorType = ResponsiveProp; +type ColorType = ResponsiveProp const orientationMap = { horizontal: 'width', vertical: 'height', -}; +} type DividerProps = { - children?: never; - color?: ColorType; - orientation?: keyof typeof orientationMap; - className?: string; -} & MarginProps; + children?: never + color?: ColorType + orientation?: keyof typeof orientationMap + className?: string +} & MarginProps export const Divider = ({ orientation = 'vertical', color, ...props }: DividerProps) => { - const { colors } = useTheme(); + const { colors } = useTheme() - const dimension = orientationMap[orientation]; + const dimension = orientationMap[orientation] const styles = { // default the background color to the theme border color backgroundColor: color ? undefined : colors.border, flexShrink: 0, [dimension]: 1, - }; + } // if the color prop is defined, pass it as the background to the box - return ; -}; + return +} diff --git a/design-system/packages/core/src/components/Heading.tsx b/design-system/packages/core/src/components/Heading.tsx index 63b022d7469..1338ceeef0e 100644 --- a/design-system/packages/core/src/components/Heading.tsx +++ b/design-system/packages/core/src/components/Heading.tsx @@ -1,24 +1,24 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; +import { jsx } from '../emotion' -import { forwardRefWithAs } from '../utils'; -import { useTheme } from '../theme'; -import { Box, BoxProps } from './Box'; +import { forwardRefWithAs } from '../utils' +import { useTheme } from '../theme' +import { Box, type BoxProps } from './Box' -export const HeadingTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const; -type HeadingType = (typeof HeadingTypes)[number]; +export const HeadingTypes = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'] as const +type HeadingType = (typeof HeadingTypes)[number] type HeadingProps = { /** The type of heading. */ - type?: HeadingType; -} & BoxProps; + type?: HeadingType +} & BoxProps export const Heading = forwardRefWithAs<'h1', HeadingProps>( ({ as = 'h1', type = 'h1', ...props }, ref) => { - const { headingStyles } = useTheme(); - const headingStyle = headingStyles[type]; + const { headingStyles } = useTheme() + const headingStyle = headingStyles[type] const styles = { color: headingStyle.color, fontFamily: headingStyle.family, @@ -26,31 +26,31 @@ export const Heading = forwardRefWithAs<'h1', HeadingProps>( fontWeight: headingStyle.weight, textTransform: headingStyle.transform, margin: 0, - } as const; - return ; + } as const + return } -); +) export const H1 = forwardRefWithAs<'h1', BoxProps>(({ as = 'h1', ...props }, ref) => { - return ; -}); + return +}) export const H2 = forwardRefWithAs<'h2', BoxProps>(({ as = 'h2', ...props }, ref) => { - return ; -}); + return +}) export const H3 = forwardRefWithAs<'h3', BoxProps>(({ as = 'h3', ...props }, ref) => { - return ; -}); + return +}) export const H4 = forwardRefWithAs<'h4', BoxProps>(({ as = 'h4', ...props }, ref) => { - return ; -}); + return +}) export const H5 = forwardRefWithAs<'h5', BoxProps>(({ as = 'h5', ...props }, ref) => { - return ; -}); + return +}) export const H6 = forwardRefWithAs<'h6', BoxProps>(({ as = 'h6', ...props }, ref) => { - return ; -}); + return +}) diff --git a/design-system/packages/core/src/components/Inline.tsx b/design-system/packages/core/src/components/Inline.tsx index 4b5a9cdaa67..dec2ac09217 100644 --- a/design-system/packages/core/src/components/Inline.tsx +++ b/design-system/packages/core/src/components/Inline.tsx @@ -1,36 +1,36 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Children, ReactNode } from 'react'; -import { jsx } from '../emotion'; +import { Children, type ReactNode } from 'react' +import { jsx } from '../emotion' -import { forwardRefWithAs, getChildTag } from '../utils'; -import { Theme } from '../types'; -import { useTheme } from '../theme'; -import { Box, BoxProps } from './Box'; +import { forwardRefWithAs, getChildTag } from '../utils' +import { type Theme } from '../types' +import { useTheme } from '../theme' +import { Box, type BoxProps } from './Box' const alignment = { center: 'center', end: 'flex-end', start: 'flex-start', stretch: 'stretch', -}; +} type InlineProps = { /** The value of the "align-items" property. */ - align?: keyof typeof alignment; + align?: keyof typeof alignment /** Each item in the container. */ - children: ReactNode; + children: ReactNode /** The size of the gap between each item. */ - gap?: keyof Theme['spacing']; -} & BoxProps; + gap?: keyof Theme['spacing'] +} & BoxProps export const Inline = forwardRefWithAs<'div', InlineProps>( ({ align = 'start', children, gap = 'none', ...props }, ref) => { - const { spacing } = useTheme(); - const resolvedAlign = alignment[align]; - const resolvedGap = spacing[gap]; - const ChildWrapper = getChildTag(props.as); + const { spacing } = useTheme() + const resolvedAlign = alignment[align] + const resolvedGap = spacing[gap] + const ChildWrapper = getChildTag(props.as) return ( ( ) : null )} - ); + ) } -); +) diff --git a/design-system/packages/core/src/components/Link.tsx b/design-system/packages/core/src/components/Link.tsx index 0f7b5e22b44..df3321ffb89 100644 --- a/design-system/packages/core/src/components/Link.tsx +++ b/design-system/packages/core/src/components/Link.tsx @@ -1,12 +1,12 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; -import { useTheme } from '../theme'; -import { forwardRefWithAs } from '../utils'; +import { jsx } from '../emotion' +import { useTheme } from '../theme' +import { forwardRefWithAs } from '../utils' export const Link = forwardRefWithAs<'a', {}>(({ as: Tag = 'a', ...props }, ref) => { - const { typography, colors } = useTheme(); + const { typography, colors } = useTheme() const styles = { color: colors.linkColor, @@ -18,7 +18,7 @@ export const Link = forwardRefWithAs<'a', {}>(({ as: Tag = 'a', ...props }, ref) color: colors.linkHoverColor, textDecoration: 'underline', }, - }; + } - return ; -}); + return +}) diff --git a/design-system/packages/core/src/components/Stack.tsx b/design-system/packages/core/src/components/Stack.tsx index ae06186d42a..b0644782a71 100644 --- a/design-system/packages/core/src/components/Stack.tsx +++ b/design-system/packages/core/src/components/Stack.tsx @@ -1,23 +1,23 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Children, Fragment, ReactNode, isValidElement } from 'react'; +import { Children, Fragment, type ReactNode, isValidElement } from 'react' -import { jsx } from '../emotion'; -import { useMediaQuery } from '../hooks/useMediaQuery'; -import { useTheme } from '../theme'; -import { Theme } from '../types'; -import { forwardRefWithAs, mapResponsiveProp, getChildTag } from '../utils'; +import { jsx } from '../emotion' +import { useMediaQuery } from '../hooks/useMediaQuery' +import { useTheme } from '../theme' +import { type Theme } from '../types' +import { forwardRefWithAs, mapResponsiveProp, getChildTag } from '../utils' -import { Box, BoxProps } from './Box'; -import { Divider } from './Divider'; +import { Box, type BoxProps } from './Box' +import { Divider } from './Divider' const alignment = { center: 'center', end: 'flex-end', start: 'flex-start', stretch: 'stretch', -}; +} const orientationMap = { horizontal: { @@ -30,29 +30,29 @@ const orientationMap = { marginProperty: 'marginTop', dimension: 'height', }, -} as const; +} as const export type StackProps = { /** The value of the "align-items" property. */ - align?: keyof typeof alignment; + align?: keyof typeof alignment /** Each element in the stack. */ - children: ReactNode; + children: ReactNode /** Causes items in the stack to be oriented horizontally, instead of vertically */ - across?: boolean; + across?: boolean /** The placement, if any, of the dividing elements. */ - dividers?: 'none' | 'around' | 'between' | 'start' | 'end'; + dividers?: 'none' | 'around' | 'between' | 'start' | 'end' /** The size of the gap between each element in the stack. */ - gap?: keyof Theme['spacing']; -} & BoxProps; + gap?: keyof Theme['spacing'] +} & BoxProps export const Stack = forwardRefWithAs<'div', StackProps>( ({ across, align = 'stretch', children, dividers = 'none', gap = 'none', ...props }, ref) => { - const { spacing } = useTheme(); - const { mq } = useMediaQuery(); + const { spacing } = useTheme() + const { mq } = useMediaQuery() - const orientation = across ? 'horizontal' : 'vertical'; - const { dimension, flexDirection, marginProperty } = orientationMap[orientation]; - const ChildWrapper = getChildTag(props.as); + const orientation = across ? 'horizontal' : 'vertical' + const { dimension, flexDirection, marginProperty } = orientationMap[orientation] + const ChildWrapper = getChildTag(props.as) return ( ( {/* wrap the child to avoid unwanted or unexpected "stretch" on things like buttons */} {child} - ); + ) })} {['around', 'end'].includes(dividers) && } - ); + ) } -); +) diff --git a/design-system/packages/core/src/components/Text.tsx b/design-system/packages/core/src/components/Text.tsx index 58eeb9bf126..fbb552b2776 100644 --- a/design-system/packages/core/src/components/Text.tsx +++ b/design-system/packages/core/src/components/Text.tsx @@ -1,35 +1,35 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx } from '../emotion'; +import { jsx } from '../emotion' -import { Theme } from '../types'; -import { forwardRefWithAs } from '../utils'; -import { useMediaQuery } from '../hooks/useMediaQuery'; -import { useTheme } from '../theme'; -import { Box, BoxProps } from './Box'; +import { type Theme } from '../types' +import { forwardRefWithAs } from '../utils' +import { useMediaQuery } from '../hooks/useMediaQuery' +import { useTheme } from '../theme' +import { Box, type BoxProps } from './Box' type TextProps = { /** The leading of the text. */ - leading?: keyof Theme['typography']['leading']; + leading?: keyof Theme['typography']['leading'] /** The size of the text. */ - size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge'; + size?: 'xsmall' | 'small' | 'medium' | 'large' | 'xlarge' /** The tracking of the text. */ - tracking?: keyof Theme['typography']['tracking']; + tracking?: keyof Theme['typography']['tracking'] /** The color of the text. */ - color?: keyof Theme['palette']; + color?: keyof Theme['palette'] /** The font-weight of the text. */ - weight?: keyof Theme['typography']['fontWeight']; -} & BoxProps; + weight?: keyof Theme['typography']['fontWeight'] +} & BoxProps export const Text = forwardRefWithAs<'div', TextProps>( ( { color, leading = 'base', size = 'medium', tracking = 'base', weight = 'regular', ...props }, ref ) => { - const { palette, typography } = useTheme(); + const { palette, typography } = useTheme() - const { mq } = useMediaQuery(); + const { mq } = useMediaQuery() const styles = mq({ color: color ? palette[color] : undefined, @@ -37,8 +37,8 @@ export const Text = forwardRefWithAs<'div', TextProps>( fontWeight: typography.fontWeight[weight], letterSpacing: typography.tracking[tracking], lineHeight: typography.leading[leading], - }); + }) - return ; + return } -); +) diff --git a/design-system/packages/core/src/emotion.ts b/design-system/packages/core/src/emotion.ts index 68ea6ecf5d4..5bb7522d5a6 100644 --- a/design-system/packages/core/src/emotion.ts +++ b/design-system/packages/core/src/emotion.ts @@ -1 +1 @@ -export { css, jsx, keyframes, Global, ClassNames } from '@emotion/react'; // ensure the same version of emotion +export { css, jsx, keyframes, Global, ClassNames } from '@emotion/react' // ensure the same version of emotion diff --git a/design-system/packages/core/src/hooks/useManagedState.ts b/design-system/packages/core/src/hooks/useManagedState.ts index 70c8fed2d5c..be9d5e9148a 100644 --- a/design-system/packages/core/src/hooks/useManagedState.ts +++ b/design-system/packages/core/src/hooks/useManagedState.ts @@ -1,38 +1,38 @@ -import { ChangeEvent, useRef, useState } from 'react'; +import { type ChangeEvent, useRef, useState } from 'react' -import { devWarning } from '../utils'; +import { devWarning } from '../utils' -export type ManagedChangeHandler = (value: V, event: E) => void; +export type ManagedChangeHandler = (value: V, event: E) => void -export function useManagedState( +export function useManagedState ( controlledValue: V | undefined, defaultValue: V, onChange: ManagedChangeHandler | undefined ): [V, ManagedChangeHandler] { - const { current: isControlled } = useRef(controlledValue !== undefined); - const [internalValue, setInternalValue] = useState(defaultValue); + const { current: isControlled } = useRef(controlledValue !== undefined) + const [internalValue, setInternalValue] = useState(defaultValue) // warn consumers when their component is switching from controlled to uncontrolled and vice versa devWarning( isControlled && controlledValue === undefined, 'A component is changing from controlled to uncontrolled. Check the `value` prop being passed in.' - ); + ) devWarning( !isControlled && controlledValue !== undefined, 'A component is changing from uncontrolled to controlled. Check the `value` prop being passed in.' - ); + ) // handle value changes (both internal, and controlled) const setValue = (v: V, e: E) => { if (typeof onChange === 'function') { - onChange(v, e); + onChange(v, e) } - setInternalValue(v); - }; + setInternalValue(v) + } // determine which value to pass on - const value = controlledValue !== undefined ? controlledValue : internalValue; + const value = controlledValue !== undefined ? controlledValue : internalValue - return [value, setValue]; + return [value, setValue] } diff --git a/design-system/packages/core/src/hooks/useMediaQuery.ts b/design-system/packages/core/src/hooks/useMediaQuery.ts index 97445b2813e..bd5c709ba08 100644 --- a/design-system/packages/core/src/hooks/useMediaQuery.ts +++ b/design-system/packages/core/src/hooks/useMediaQuery.ts @@ -1,10 +1,10 @@ -import facepaint from 'facepaint'; +import facepaint from 'facepaint' -import { Theme } from '../types'; -import { useTheme } from '../theme'; +import { type Theme } from '../types' +import { useTheme } from '../theme' -type BreakPoints = Theme['breakpoints']; -type BreakPoint = keyof BreakPoints; +type BreakPoints = Theme['breakpoints'] +type BreakPoint = keyof BreakPoints /* Facepaint lets you write properties as arrays e.g. @@ -14,28 +14,28 @@ type BreakPoint = keyof BreakPoints; More here: https://github.com/emotion-js/facepaint */ const makeMq = (breakpoints: BreakPoints) => - facepaint(Object.values(breakpoints).map(w => `@media (min-width: ${w}px)`)); + facepaint(Object.values(breakpoints).map(w => `@media (min-width: ${w}px)`)) // helper if array property declaration isn't appropriate const makeMinBreak = (breakpoints: BreakPoints) => (key: BreakPoint) => { - const width = breakpoints[key]; - return `@media (min-width: ${width}px)`; -}; + const width = breakpoints[key] + return `@media (min-width: ${width}px)` +} // the breakpoints are designed to go up i.e. min-width // if a max-width is necessary (hopefully rare) it's nice to provide a helper const makeMaxBreak = (breakpoints: BreakPoints) => (key: BreakPoint) => { - const width = breakpoints[key]; - return `@media (max-width: ${width - 1}px)`; -}; + const width = breakpoints[key] + return `@media (max-width: ${width - 1}px)` +} // FIXME: // Should this even be a hook? I think we can just export these utilities... export const useMediaQuery = () => { - const { breakpoints } = useTheme(); + const { breakpoints } = useTheme() return { mq: makeMq(breakpoints), maxBreak: makeMaxBreak(breakpoints), minBreak: makeMinBreak(breakpoints), - }; -}; + } +} diff --git a/design-system/packages/core/src/index.ts b/design-system/packages/core/src/index.ts index fabf4dfc241..3955c3bc283 100644 --- a/design-system/packages/core/src/index.ts +++ b/design-system/packages/core/src/index.ts @@ -1,17 +1,17 @@ -export * from './emotion'; -export { VisuallyHidden } from './a11y/VisuallyHidden'; -export { Box } from './components/Box'; -export type { BoxProps, ColorProps, RadiiProps, MarginProps, PaddingProps } from './components/Box'; -export { Core } from './components/Core'; -export { Center } from './components/Center'; -export { Divider } from './components/Divider'; -export { Heading, H1, H2, H3, H4, H5, H6 } from './components/Heading'; -export { Inline } from './components/Inline'; -export { Link } from './components/Link'; -export { Stack } from './components/Stack'; -export { Text } from './components/Text'; -export * from './hooks/useMediaQuery'; -export * from './hooks/useManagedState'; -export * from './theme'; -export * from './utils'; -export * from './types'; +export * from './emotion' +export { VisuallyHidden } from './a11y/VisuallyHidden' +export { Box } from './components/Box' +export type { BoxProps, ColorProps, RadiiProps, MarginProps, PaddingProps } from './components/Box' +export { Core } from './components/Core' +export { Center } from './components/Center' +export { Divider } from './components/Divider' +export { Heading, H1, H2, H3, H4, H5, H6 } from './components/Heading' +export { Inline } from './components/Inline' +export { Link } from './components/Link' +export { Stack } from './components/Stack' +export { Text } from './components/Text' +export * from './hooks/useMediaQuery' +export * from './hooks/useManagedState' +export * from './theme' +export * from './utils' +export * from './types' diff --git a/design-system/packages/core/src/normalize.ts b/design-system/packages/core/src/normalize.ts index 6aa108379dc..183ce2b7360 100644 --- a/design-system/packages/core/src/normalize.ts +++ b/design-system/packages/core/src/normalize.ts @@ -1,4 +1,4 @@ -import { css } from './emotion'; +import { css } from './emotion' export const normalize = css` /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ @@ -156,4 +156,4 @@ export const normalize = css` [hidden] { display: none; } -`; +` diff --git a/design-system/packages/core/src/theme.tsx b/design-system/packages/core/src/theme.tsx index 9887b4ca8b1..bdff75e08e3 100644 --- a/design-system/packages/core/src/theme.tsx +++ b/design-system/packages/core/src/theme.tsx @@ -1,20 +1,20 @@ -import React, { ReactNode, createContext, useContext } from 'react'; +import React, { type ReactNode, createContext, useContext } from 'react' -import type { Theme } from './types'; -import { theme } from './themes/default'; +import type { Theme } from './types' +import { theme } from './themes/default' export const ThemeContext = createContext<{ - theme: Theme; + theme: Theme }>({ theme, -}); +}) -export const ThemeProvider = ({ theme, children }: { theme: Theme; children: ReactNode }) => { - return {children}; -}; +export const ThemeProvider = ({ theme, children }: { theme: Theme, children: ReactNode }) => { + return {children} +} // TODO: return type required by pnpm :( export const useTheme = (): Theme => { - const { theme } = useContext(ThemeContext); - return theme; -}; + const { theme } = useContext(ThemeContext) + return theme +} diff --git a/design-system/packages/core/src/themes/colors.ts b/design-system/packages/core/src/themes/colors.ts index 97167b042d2..a3608a8aa59 100644 --- a/design-system/packages/core/src/themes/colors.ts +++ b/design-system/packages/core/src/themes/colors.ts @@ -224,4 +224,4 @@ export const palette = { // blueGray700: '#334155', // blueGray800: '#1e293b', // blueGray900: '#0f172a', -} as const; +} as const diff --git a/design-system/packages/core/src/themes/colors_old.ts b/design-system/packages/core/src/themes/colors_old.ts index ba4fb2bf386..2b8d5bb30d2 100644 --- a/design-system/packages/core/src/themes/colors_old.ts +++ b/design-system/packages/core/src/themes/colors_old.ts @@ -347,4 +347,4 @@ export const palette = { orange700: '#aa4709', orange800: '#7a3305', orange900: '#4b1d00', -}; +} diff --git a/design-system/packages/core/src/themes/default.ts b/design-system/packages/core/src/themes/default.ts index 082c39cd237..a548d4d2092 100644 --- a/design-system/packages/core/src/themes/default.ts +++ b/design-system/packages/core/src/themes/default.ts @@ -1,6 +1,6 @@ -import { CSSObject } from '@emotion/react'; -import { identityType } from '../utils'; -import { palette as basePalette } from './colors'; +import { type CSSObject } from '@emotion/react' +import { identityType } from '../utils' +import { palette as basePalette } from './colors' /** * Global Tokens @@ -49,7 +49,7 @@ const typography = { loose: '0.01em', looser: '0.02em', }, -}; +} const palette = { black: '#000000', @@ -68,14 +68,14 @@ const palette = { neutral900: '#111827', ...basePalette, -}; +} const breakpoints = { small: 576, medium: 768, large: 992, xlarge: 1200, -}; +} const elevation = { e100: 100, // Cards @@ -83,7 +83,7 @@ const elevation = { e300: 300, // Tooltip e400: 400, // Modals e500: 500, // Toasts (notifications) -}; +} const radii = { none: 0, @@ -92,7 +92,7 @@ const radii = { medium: 8, large: 12, full: 9999, -}; +} const sizing = { xxsmall: 16, @@ -102,7 +102,7 @@ const sizing = { large: 38, xlarge: 42, xxlarge: 48, -}; +} const spacing = { none: 0, @@ -113,7 +113,7 @@ const spacing = { large: 16, xlarge: 24, xxlarge: 32, -}; +} const shadow = { s100: `0px 1px 2px rgba(0, 0, 0, 0.2)`, // Cards @@ -121,7 +121,7 @@ const shadow = { s300: `0px 2px 8px rgba(0, 0, 0, 0.2)`, // Tooltip s400: `0px 4px 16px rgba(0, 0, 0, 0.2)`, // Modals s500: `-8px 8px 32px rgba(0, 0, 0, 0.2)`, // Toasts (notifications) -}; +} const animation = { duration0: '0ms', @@ -141,25 +141,25 @@ const animation = { easeIn: `cubic-bezier(0.2, 0, 0, 1)`, easeOut: `cubic-bezier(0.165, 0.840, 0.440, 1)`, linear: 'cubic-bezier(0, 0, 1, 1)', -}; +} const opacity = { full: 1, none: 0, disabled: 0.65, -}; +} /** * Alias Tokens */ type HeadingStyle = { - color: string; - family: string; - size: string; - transform: Extract; - weight: number; -}; + color: string + family: string + size: string + transform: Extract + weight: number +} const headingStyles: { [key: string]: HeadingStyle } = { h1: { @@ -204,20 +204,20 @@ const headingStyles: { [key: string]: HeadingStyle } = { transform: 'uppercase', weight: typography.fontWeight.bold, }, -}; +} type ControlSize = { - borderRadius: number; - borderWidth: number; - gutter: number; - paddingX: number; - paddingY: number; - height: number; - gap: number; - fontSize: number | string; - indicatorBoxSize: number | string; - indicatorFontSize: number | string; -}; + borderRadius: number + borderWidth: number + gutter: number + paddingX: number + paddingY: number + height: number + gap: number + fontSize: number | string + indicatorBoxSize: number | string + indicatorFontSize: number | string +} const controlSizes: { [key: string]: ControlSize } = { small: { @@ -256,7 +256,7 @@ const controlSizes: { [key: string]: ControlSize } = { indicatorBoxSize: sizing.medium, indicatorFontSize: typography.fontSize.small, }, -}; +} const colors = { background: 'white', @@ -276,7 +276,7 @@ const colors = { overlayBackground: 'rgba(18,18,18, 0.3)', // blanket behind modal dialogs loaderDark: palette.neutral500, loaderLight: palette.neutral200, -}; +} /** @@ -291,15 +291,15 @@ Tones have 2 foregrounds that should work on these backgrounds: */ -type ToneColor = [string, string, string]; +type ToneColor = [string, string, string] type Tone = { - focusRing: string; - border: ToneColor; - fill: ToneColor; - tint: ToneColor; - foreground: ToneColor; - fillForeground: ToneColor; -}; + focusRing: string + border: ToneColor + fill: ToneColor + tint: ToneColor + foreground: ToneColor + fillForeground: ToneColor +} const tones = identityType<{ [key: string]: Tone }>()({ active: { @@ -350,15 +350,15 @@ const tones = identityType<{ [key: string]: Tone }>()({ foreground: [palette.purple600, palette.purple700, palette.purple800], fillForeground: [palette.white, palette.white, palette.white], }, -}); +}) type SelectableColor = { - border: string; - fill: string; - fillForeground: string; - foreground: string; - tint: string; -}; + border: string + fill: string + fillForeground: string + foreground: string + tint: string +} const selectableColors = identityType<{ [key: string]: SelectableColor }>()({ silver: { @@ -403,42 +403,42 @@ const selectableColors = identityType<{ [key: string]: SelectableColor }>()({ foreground: palette.purple600, tint: palette.purple200, }, -}); +}) type SharedFieldStateTokens = { - labelColor?: string; - legendColor?: string; - shadow?: string; -}; + labelColor?: string + legendColor?: string + shadow?: string +} type ControlFieldStateTokens = { - controlBackground?: string; - controlBorderColor?: string; - controlBorderRadius?: number | string; - controlForeground?: string; -}; + controlBackground?: string + controlBorderColor?: string + controlBorderRadius?: number | string + controlForeground?: string +} type InputFieldStateTokens = { - inputBackground?: string; - inputBorderColor?: string; - inputBorderRadius?: number | string; - inputForeground?: string; - iconColor?: string; -}; + inputBackground?: string + inputBorderColor?: string + inputBorderRadius?: number | string + inputForeground?: string + iconColor?: string +} -type FieldStateTokens = SharedFieldStateTokens & ControlFieldStateTokens & InputFieldStateTokens; +type FieldStateTokens = SharedFieldStateTokens & ControlFieldStateTokens & InputFieldStateTokens type FieldTokens = FieldStateTokens & { - controlBorderWidth?: number | string; - inputBorderWidth?: number | string; - inputPlaceholder?: string; - switchForeground?: string; - disabled: FieldStateTokens; - focus: FieldStateTokens; - hover: FieldStateTokens; - invalid: FieldStateTokens; - selected: SharedFieldStateTokens & ControlFieldStateTokens; -}; + controlBorderWidth?: number | string + inputBorderWidth?: number | string + inputPlaceholder?: string + switchForeground?: string + disabled: FieldStateTokens + focus: FieldStateTokens + hover: FieldStateTokens + invalid: FieldStateTokens + selected: SharedFieldStateTokens & ControlFieldStateTokens +} const fields: FieldTokens = { controlBackground: 'white', @@ -486,7 +486,7 @@ const fields: FieldTokens = { controlBorderColor: palette.blue500, controlForeground: 'white', }, -}; +} /** * Export @@ -512,4 +512,4 @@ export const theme = { tones, selectableColors, fields, -}; +} diff --git a/design-system/packages/core/src/types.ts b/design-system/packages/core/src/types.ts index 15f37151b88..5a2cd5955dd 100644 --- a/design-system/packages/core/src/types.ts +++ b/design-system/packages/core/src/types.ts @@ -1,7 +1,7 @@ -import { theme } from './themes/default'; +import { type theme } from './themes/default' // Theme Types -export type Theme = typeof theme; +export type Theme = typeof theme -export type ResponsiveProp = T | readonly (T | null)[]; +export type ResponsiveProp = T | readonly (T | null)[] diff --git a/design-system/packages/core/src/utils.ts b/design-system/packages/core/src/utils.ts index ce54fe04bf8..9db5cfda3e3 100644 --- a/design-system/packages/core/src/utils.ts +++ b/design-system/packages/core/src/utils.ts @@ -1,15 +1,15 @@ import { - ComponentPropsWithoutRef, - ElementType, + type ComponentPropsWithoutRef, + type ElementType, forwardRef, - ReactElement, - ReactNode, - Ref, + type ReactElement, + type ReactNode, + type Ref, useEffect, useLayoutEffect, useState, -} from 'react'; -import { createPortal } from 'react-dom'; +} from 'react' +import { createPortal } from 'react-dom' /* Simple switch to return a child tag from a parent tag argument. @@ -19,20 +19,20 @@ export const getChildTag = (parentTag?: ElementType) => { switch (parentTag) { case 'ul': case 'ol': - return 'li'; + return 'li' default: - return 'div'; + return 'div' } -}; +} /* @johannes' one weird trick for fixing TypeScript autocomplete */ -export function identityType() { - function inner(u: U): U { - return u; +export function identityType () { + function inner (u: U): U { + return u } - return inner; + return inner } /* @@ -41,10 +41,10 @@ export function identityType() { export const devWarning = (condition: boolean, message: string) => { if (process.env.NODE_ENV !== 'production') { if (condition) { - console.error(message); + console.error(message) } } -}; +} /* forwardRefWithAs lets us forward refs while keeping the correct component type, @@ -52,24 +52,24 @@ export const devWarning = (condition: boolean, message: string) => { */ type ElementTagNameMap = HTMLElementTagNameMap & - Pick>; + Pick> type AsProp = { - as?: Comp; + as?: Comp ref?: Ref< Comp extends keyof ElementTagNameMap ? ElementTagNameMap[Comp] : Comp extends new (...args: any) => any ? InstanceType : undefined - >; -} & Omit, 'as' | keyof Props>; + > +} & Omit, 'as' | keyof Props> type CompWithAsProp = < Comp extends ElementType = DefaultElementType >( props: AsProp & Props -) => ReactElement; +) => ReactElement export const forwardRefWithAs = ( render: ( @@ -77,15 +77,15 @@ export const forwardRefWithAs = ) => Exclude ): CompWithAsProp => { - // @ts-ignore - return forwardRef(render); -}; + // @ts-expect-error + return forwardRef(render) +} /* A helper for making valid IDs from a set of inputs */ -export function makeId(...args: (string | number | null | undefined)[]) { - return args.filter(val => val != null).join('--'); +export function makeId (...args: (string | number | null | undefined)[]) { + return args.filter(val => val != null).join('--') } /* @@ -103,11 +103,11 @@ export const mapResponsiveProp = < valueMap: Map ) => { if (Array.isArray(value)) { - return value.map(k => (k == null ? null : valueMap[k])); + return value.map(k => (k == null ? null : valueMap[k])) } - // @ts-ignore - return valueMap[value]; -}; + // @ts-expect-error + return valueMap[value] +} /** * Utils below are ported with thanks from @reach-ui @@ -116,41 +116,41 @@ export const mapResponsiveProp = < // Autogenerate IDs to facilitate WAI-ARIA and server rendering. For reasoning, see // https://github.com/reach/reach-ui/blob/develop/packages/auto-id/src/index.tsx -let serverHandoffComplete = false; -let id = 0; -const genId = () => ++id; +let serverHandoffComplete = false +let id = 0 +const genId = () => ++id export const useId = (idFromProps?: string | null) => { - const initialId = idFromProps || (serverHandoffComplete ? genId() : null); + const initialId = idFromProps || (serverHandoffComplete ? genId() : null) - const [id, setId] = useState(initialId); + const [id, setId] = useState(initialId) useSafeLayoutEffect(() => { if (id === null) { - setId(genId()); + setId(genId()) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, []) useEffect(() => { if (serverHandoffComplete === false) { - serverHandoffComplete = true; + serverHandoffComplete = true } - }, []); - return id != null ? String(id) : undefined; -}; + }, []) + return id != null ? String(id) : undefined +} // Works around useLayoutEffect throwing a warning when used in SSR -export const useSafeLayoutEffect = typeof window === 'undefined' ? () => {} : useLayoutEffect; +export const useSafeLayoutEffect = typeof window === 'undefined' ? () => {} : useLayoutEffect type Props = { - children: ReactElement; -}; + children: ReactElement +} export const Portal = ({ children }: Props): React.ReactPortal | null => { if (typeof document === 'undefined') { - return null; + return null } - return createPortal(children, document.body); -}; + return createPortal(children, document.body) +} diff --git a/design-system/packages/fields/src/Checkbox.tsx b/design-system/packages/fields/src/Checkbox.tsx index 9a0625c90e0..cdcab8498e7 100644 --- a/design-system/packages/fields/src/Checkbox.tsx +++ b/design-system/packages/fields/src/Checkbox.tsx @@ -1,18 +1,18 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Fragment, InputHTMLAttributes, ReactNode, forwardRef } from 'react'; -import { jsx, VisuallyHidden } from '@keystone-ui/core'; +import { Fragment, type InputHTMLAttributes, type ReactNode, forwardRef } from 'react' +import { jsx, VisuallyHidden } from '@keystone-ui/core' -import { ControlLabel } from './components/ControlLabel'; -import { CheckIcon } from './components/Icons'; -import { useIndicatorStyles, useIndicatorTokens } from './hooks/indicators'; -import type { SizeType } from './types'; +import { ControlLabel } from './components/ControlLabel' +import { CheckIcon } from './components/Icons' +import { useIndicatorStyles, useIndicatorTokens } from './hooks/indicators' +import type { SizeType } from './types' type CheckboxProps = { /** The checkbox label content. */ - children: ReactNode; -} & CheckboxControlProps; + children: ReactNode +} & CheckboxControlProps export const Checkbox = forwardRef( ({ children, className, size, ...props }, ref) => { @@ -24,20 +24,20 @@ export const Checkbox = forwardRef( > {children} - ); + ) } -); +) type CheckboxControlProps = { /** When true, the checkbox will be checked. */ - checked?: boolean; + checked?: boolean /** When true, the checkbox will be disabled. */ - disabled?: boolean; + disabled?: boolean /** The size of the Checkbox */ - size?: SizeType; + size?: SizeType /** The value of the Checkbox. */ - value?: string; -} & Omit, 'size'>; + value?: string +} & Omit, 'size'> export const CheckboxControl = forwardRef( ({ className, size, ...props }, ref) => ( @@ -48,18 +48,18 @@ export const CheckboxControl = forwardRef ) -); +) const Indicator = ({ className, size, ...props }: { - size?: SizeType; - children?: ReactNode; - className?: string; + size?: SizeType + children?: ReactNode + className?: string }) => { - const tokens = useIndicatorTokens({ type: 'checkbox', size: size || 'medium' }); - const styles = useIndicatorStyles({ tokens }); - return
; -}; + const tokens = useIndicatorTokens({ type: 'checkbox', size: size || 'medium' }) + const styles = useIndicatorStyles({ tokens }) + return
+} diff --git a/design-system/packages/fields/src/DatePicker/Calendar.tsx b/design-system/packages/fields/src/DatePicker/Calendar.tsx index 2bae98cb515..6fe4a537f29 100644 --- a/design-system/packages/fields/src/DatePicker/Calendar.tsx +++ b/design-system/packages/fields/src/DatePicker/Calendar.tsx @@ -1,31 +1,31 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { DayPicker, DayPickerProps } from 'react-day-picker'; -import { jsx, useTheme } from '@keystone-ui/core'; -import { getContrastText } from './utils/getContrastText'; -import { hexToRgb } from './utils/hexToRgb'; +import { DayPicker, type DayPickerProps } from 'react-day-picker' +import { jsx, useTheme } from '@keystone-ui/core' +import { getContrastText } from './utils/getContrastText' +import { hexToRgb } from './utils/hexToRgb' export const Calendar = ({ modifiers, ...props }: DayPickerProps) => { - const styles = useCalendarStyles(); - const indexOfMonday = 1; + const styles = useCalendarStyles() + const indexOfMonday = 1 return (
- ); -}; + ) +} // Styles // ------------------------------ const useCalendarStyles = () => { - const { colors, palette } = useTheme(); - const cellSize = 40; // theme.sizing.base; - const navButtonSize = 24; // theme.sizing.xsmall; - const interactionColor = '#007AFF'; //theme.palette.actions.active; - const rangeBetweenColor = hexToRgb('#007AFF', 0.2); //hexToRgb(interactionColor, 0.2); + const { colors, palette } = useTheme() + const cellSize = 40 // theme.sizing.base; + const navButtonSize = 24 // theme.sizing.xsmall; + const interactionColor = '#007AFF' //theme.palette.actions.active; + const rangeBetweenColor = hexToRgb('#007AFF', 0.2) //hexToRgb(interactionColor, 0.2); return { padding: 8, //theme.spacing.small, @@ -254,5 +254,5 @@ const useCalendarStyles = () => { background: `linear-gradient(to right, ${rangeBetweenColor}, ${colors.overlayBackground})`, }, }, - } as const; -}; + } as const +} diff --git a/design-system/packages/fields/src/DatePicker/components/Adornments.tsx b/design-system/packages/fields/src/DatePicker/components/Adornments.tsx index ae90d451375..1f362a78263 100644 --- a/design-system/packages/fields/src/DatePicker/components/Adornments.tsx +++ b/design-system/packages/fields/src/DatePicker/components/Adornments.tsx @@ -1,12 +1,12 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { ElementType, ReactNode, createContext, useContext } from 'react'; -import { jsx, forwardRefWithAs, useTheme } from '@keystone-ui/core'; +import { type ElementType, type ReactNode, createContext, useContext } from 'react' +import { jsx, forwardRefWithAs, useTheme } from '@keystone-ui/core' // todo - these also exist at ../../types -export type SizeType = 'small' | 'medium'; -export type ShapeType = 'square' | 'round'; +export type SizeType = 'small' | 'medium' +export type ShapeType = 'square' | 'round' /** * What is this thing? @@ -16,20 +16,20 @@ export type ShapeType = 'square' | 'round'; * consolidate in one place. */ -const AdornmentContext = createContext<{ shape: ShapeType; size: SizeType }>({ +const AdornmentContext = createContext<{ shape: ShapeType, size: SizeType }>({ shape: 'square', size: 'medium', -}); -const useAdornmentContext = () => useContext(AdornmentContext); +}) +const useAdornmentContext = () => useContext(AdornmentContext) // Adornment Wrapper // ------------------------------ export type AdornmentWrapperProps = { - children: ReactNode; - shape: ShapeType; - size: SizeType; -}; + children: ReactNode + shape: ShapeType + size: SizeType +} export const AdornmentWrapper = ({ children, shape, size }: AdornmentWrapperProps) => { return ( @@ -45,8 +45,8 @@ export const AdornmentWrapper = ({ children, shape, size }: AdornmentWrapperProp {children}
- ); -}; + ) +} // Adornment Element // ------------------------------ @@ -54,18 +54,18 @@ export const AdornmentWrapper = ({ children, shape, size }: AdornmentWrapperProp const alignmentPaddingMap = { left: 'marginLeft', right: 'marginRight', -}; +} type AdornmentProps = { - align: 'left' | 'right'; - as?: ElementType; -}; + align: 'left' | 'right' + as?: ElementType +} export const Adornment = forwardRefWithAs<'div', AdornmentProps>( ({ align, as: Tag = 'div', ...props }, ref) => { - const { shape, size } = useAdornmentContext(); - const { controlSizes } = useTheme(); + const { shape, size } = useAdornmentContext() + const { controlSizes } = useTheme() - const { indicatorBoxSize, paddingX } = controlSizes[size]; + const { indicatorBoxSize, paddingX } = controlSizes[size] // optical alignment shifts towards the middle of the container with the large // border radius on "round" inputs. use padding rather than margin to optimise @@ -75,7 +75,7 @@ export const Adornment = forwardRefWithAs<'div', AdornmentProps>( ? { [alignmentPaddingMap[align]]: paddingX / 4, } - : null; + : null return ( ( }} {...props} /> - ); + ) } -); +) diff --git a/design-system/packages/fields/src/DatePicker/components/InputButton.tsx b/design-system/packages/fields/src/DatePicker/components/InputButton.tsx index b185cc6dfca..095117a8642 100644 --- a/design-system/packages/fields/src/DatePicker/components/InputButton.tsx +++ b/design-system/packages/fields/src/DatePicker/components/InputButton.tsx @@ -1,38 +1,38 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { ButtonHTMLAttributes, forwardRef } from 'react'; -import { jsx, useTheme, VisuallyHidden } from '@keystone-ui/core'; -import { XIcon } from '@keystone-ui/icons/icons/XIcon'; -import { CalendarIcon } from '@keystone-ui/icons/icons/CalendarIcon'; -import { useInputTokens, useInputStyles } from '../..'; -import { Adornment, AdornmentWrapper } from './Adornments'; +import { type ButtonHTMLAttributes, forwardRef } from 'react' +import { jsx, useTheme, VisuallyHidden } from '@keystone-ui/core' +import { XIcon } from '@keystone-ui/icons/icons/XIcon' +import { CalendarIcon } from '@keystone-ui/icons/icons/CalendarIcon' +import { useInputTokens, useInputStyles } from '../..' +import { Adornment, AdornmentWrapper } from './Adornments' type ButtonProps = { - invalid?: boolean; - isSelected?: boolean; - onClear?: () => void; -} & ButtonHTMLAttributes; + invalid?: boolean + isSelected?: boolean + onClear?: () => void +} & ButtonHTMLAttributes export const InputButton = forwardRef( ({ invalid = false, isSelected, onClear, ...props }, ref) => { - const { spacing } = useTheme(); - const inputTokens = useInputTokens({ size: 'medium' }); - const inputStyles = useInputStyles({ invalid, tokens: inputTokens }); + const { spacing } = useTheme() + const inputTokens = useInputTokens({ size: 'medium' }) + const inputStyles = useInputStyles({ invalid, tokens: inputTokens }) const focusStyles = isSelected ? { ...inputStyles[':focus'], ':hover': inputStyles[':focus'], ':focus': inputStyles[':focus'], } - : null; + : null const buttonStyles = { ...inputStyles, ...focusStyles, cursor: 'pointer', lineHeight: 'initial', // let the button vertically align its text; the have different native behaviour to inputs textAlign: 'left', - } as const; + } as const return ( @@ -42,12 +42,12 @@ export const InputButton = forwardRef( - ); + ) } -); +) const ClearButton = (props: ButtonHTMLAttributes) => { - const { colors } = useTheme(); + const { colors } = useTheme() return ( ) => { clear date value - ); -}; + ) +} diff --git a/design-system/packages/fields/src/DatePicker/index.tsx b/design-system/packages/fields/src/DatePicker/index.tsx index 74cc357c59b..608c56f269b 100644 --- a/design-system/packages/fields/src/DatePicker/index.tsx +++ b/design-system/packages/fields/src/DatePicker/index.tsx @@ -1,39 +1,39 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Fragment, useCallback, useEffect, useRef, useState } from 'react'; -import FocusLock from 'react-focus-lock'; -import { jsx } from '@keystone-ui/core'; -import { PopoverDialog, useControlledPopover } from '@keystone-ui/popover'; +import { Fragment, useCallback, useEffect, useRef, useState } from 'react' +import FocusLock from 'react-focus-lock' +import { jsx } from '@keystone-ui/core' +import { PopoverDialog, useControlledPopover } from '@keystone-ui/popover' import { deserializeDate, formatDate, formatDateType, dateFormatPlaceholder, -} from '../utils/dateFormatters'; -import { DateType } from '../types'; -import { Calendar } from './Calendar'; -import { InputButton } from './components/InputButton'; +} from '../utils/dateFormatters' +import { type DateType } from '../types' +import { Calendar } from './Calendar' +import { InputButton } from './components/InputButton' -export type DateInputValue = string | undefined; +export type DateInputValue = string | undefined export type DatePickerProps = { - onUpdate: (value: DateType) => void; - onClear: () => void; - onBlur?: () => void; - value: DateType; -}; + onUpdate: (value: DateType) => void + onClear: () => void + onBlur?: () => void + value: DateType +} export function useEventCallback any>(callback: Func): Func { - const callbackRef = useRef(callback); + const callbackRef = useRef(callback) const cb = useCallback((...args: any[]) => { - return callbackRef.current(...args); - }, []); + return callbackRef.current(...args) + }, []) useEffect(() => { - callbackRef.current = callback; - }); - return cb as any; + callbackRef.current = callback + }) + return cb as any } export const DatePicker = ({ @@ -43,24 +43,24 @@ export const DatePicker = ({ onBlur: _onBlur, ...props }: DatePickerProps) => { - const [isOpen, _setOpen] = useState(false); + const [isOpen, _setOpen] = useState(false) const onBlur = useEventCallback(() => { - _onBlur?.(); - }); + _onBlur?.() + }) const setOpen = useCallback( (val: boolean) => { - _setOpen(val); + _setOpen(val) if (!val) { - onBlur?.(); + onBlur?.() } }, [onBlur] - ); + ) const { dialog, trigger, arrow } = useControlledPopover( { isOpen, onClose: useCallback(() => { - setOpen(false); + setOpen(false) }, [setOpen]), }, { @@ -74,24 +74,24 @@ export const DatePicker = ({ }, ], } - ); + ) const handleDayClick = useCallback( (day: Date) => { - onUpdate(formatDateType(day)); + onUpdate(formatDateType(day)) // wait a moment so the user has time to see the day become selected setTimeout(() => { - setOpen(false); - }, 300); + setOpen(false) + }, 300) }, [onUpdate, setOpen] - ); + ) // We **can** memoize this, but its a trivial operation // and in the opinion of the author not really something to do // before other more important performance optimisations - const selectedDay = deserializeDate(value); - const formattedDate: DateInputValue = value ? formatDate(selectedDay) : undefined; + const selectedDay = deserializeDate(value) + const formattedDate: DateInputValue = value ? formatDate(selectedDay) : undefined return ( @@ -101,8 +101,8 @@ export const DatePicker = ({ onClear={ value ? () => { - onClear(); - onBlur?.(); + onClear() + onBlur?.() } : undefined } @@ -123,5 +123,5 @@ export const DatePicker = ({ )} - ); -}; + ) +} diff --git a/design-system/packages/fields/src/DatePicker/utils/getContrastText.ts b/design-system/packages/fields/src/DatePicker/utils/getContrastText.ts index ddfcbe385af..2ade99a3bf3 100644 --- a/design-system/packages/fields/src/DatePicker/utils/getContrastText.ts +++ b/design-system/packages/fields/src/DatePicker/utils/getContrastText.ts @@ -1,10 +1,10 @@ -import { hexToTriplet } from './hexToRgb'; +import { hexToTriplet } from './hexToRgb' -export function getContrastText(color: string) { - const [r, g, b] = hexToTriplet(color); +export function getContrastText (color: string) { + const [r, g, b] = hexToTriplet(color) // calculate contrast against grayscale - var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000; + var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000 - return contrast >= 128 ? 'black' : 'white'; + return contrast >= 128 ? 'black' : 'white' } diff --git a/design-system/packages/fields/src/DatePicker/utils/hexToRgb.ts b/design-system/packages/fields/src/DatePicker/utils/hexToRgb.ts index 21cb5761b30..2eae0c53a77 100644 --- a/design-system/packages/fields/src/DatePicker/utils/hexToRgb.ts +++ b/design-system/packages/fields/src/DatePicker/utils/hexToRgb.ts @@ -1,39 +1,39 @@ -function parseHex(hex: string) { - let result = hex; +function parseHex (hex: string) { + let result = hex // remove hash symbol if (result.startsWith('#')) { - result = result.slice(1); + result = result.slice(1) } // resolve hex shortcuts if (result.length === 3) { - result = result[0].repeat(2) + result[1].repeat(2) + result[2].repeat(2); + result = result[0].repeat(2) + result[1].repeat(2) + result[2].repeat(2) } - return result; + return result } // eslint-disable-next-line @typescript-eslint/no-unused-vars -export function hexToTriplet(dirtyHex: string, alpha?: number) { - const cleanHex = parseHex(dirtyHex); +export function hexToTriplet (dirtyHex: string, alpha?: number) { + const cleanHex = parseHex(dirtyHex) - const r = parseInt(cleanHex.slice(0, 2), 16); - const g = parseInt(cleanHex.slice(2, 4), 16); - const b = parseInt(cleanHex.slice(4, 6), 16); + const r = parseInt(cleanHex.slice(0, 2), 16) + const g = parseInt(cleanHex.slice(2, 4), 16) + const b = parseInt(cleanHex.slice(4, 6), 16) - return [r, g, b]; + return [r, g, b] } // values taken from contrast algorithms from w3 // https://www.w3.org/TR/AERT/#color-contrast -export function hexToRgb(dirtyHex: string, alpha?: number) { - const [r, g, b] = hexToTriplet(dirtyHex); - const value = `${r}, ${g}, ${b}`; +export function hexToRgb (dirtyHex: string, alpha?: number) { + const [r, g, b] = hexToTriplet(dirtyHex) + const value = `${r}, ${g}, ${b}` if (alpha) { - return `rgba(${value}, ${alpha})`; + return `rgba(${value}, ${alpha})` } - return `rgb(${value})`; + return `rgb(${value})` } diff --git a/design-system/packages/fields/src/FieldContainer.tsx b/design-system/packages/fields/src/FieldContainer.tsx index 1341139129c..a14e34b4061 100644 --- a/design-system/packages/fields/src/FieldContainer.tsx +++ b/design-system/packages/fields/src/FieldContainer.tsx @@ -1,7 +1,7 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx, forwardRefWithAs } from '@keystone-ui/core'; +import { jsx, forwardRefWithAs } from '@keystone-ui/core' export const FieldContainer = forwardRefWithAs<'div', {}>(({ as: Tag = 'div', ...props }, ref) => { - return ; -}); + return +}) diff --git a/design-system/packages/fields/src/FieldDescription.tsx b/design-system/packages/fields/src/FieldDescription.tsx index 7335d2007fd..f1c5bef77ee 100644 --- a/design-system/packages/fields/src/FieldDescription.tsx +++ b/design-system/packages/fields/src/FieldDescription.tsx @@ -1,17 +1,17 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx, useTheme } from '@keystone-ui/core'; +import { jsx, useTheme } from '@keystone-ui/core' type FieldDescriptionProps = { - id: string; - children: string | null; -}; + id: string + children: string | null +} export const FieldDescription = (props: FieldDescriptionProps) => { - const { spacing, palette } = useTheme(); + const { spacing, palette } = useTheme() if (props.children === null) { - return null; + return null } return (
{ }} {...props} /> - ); -}; + ) +} diff --git a/design-system/packages/fields/src/FieldLabel.tsx b/design-system/packages/fields/src/FieldLabel.tsx index 32a6a78b230..6d0627cfecd 100644 --- a/design-system/packages/fields/src/FieldLabel.tsx +++ b/design-system/packages/fields/src/FieldLabel.tsx @@ -1,16 +1,16 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { forwardRefWithAs, jsx, useTheme } from '@keystone-ui/core'; -import type { ReactNode } from 'react'; +import { forwardRefWithAs, jsx, useTheme } from '@keystone-ui/core' +import type { ReactNode } from 'react' type FieldLabelProps = { - children: ReactNode; -}; + children: ReactNode +} export const FieldLabel = forwardRefWithAs<'label', FieldLabelProps>( ({ as: Tag = 'label', children, ...props }, ref) => { - const { typography, fields, spacing } = useTheme(); + const { typography, fields, spacing } = useTheme() return ( ( > {children} - ); + ) } -); +) diff --git a/design-system/packages/fields/src/FieldLegend.tsx b/design-system/packages/fields/src/FieldLegend.tsx index 3c8fd7d5a71..4ad84cadeda 100644 --- a/design-system/packages/fields/src/FieldLegend.tsx +++ b/design-system/packages/fields/src/FieldLegend.tsx @@ -1,13 +1,13 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx, useTheme } from '@keystone-ui/core'; -import type { HTMLAttributes } from 'react'; +import { jsx, useTheme } from '@keystone-ui/core' +import type { HTMLAttributes } from 'react' -type FieldLegendProps = HTMLAttributes; +type FieldLegendProps = HTMLAttributes export const FieldLegend = (props: FieldLegendProps) => { - const { typography, fields, spacing } = useTheme(); + const { typography, fields, spacing } = useTheme() return ( { }} {...props} /> - ); -}; + ) +} diff --git a/design-system/packages/fields/src/Radio.tsx b/design-system/packages/fields/src/Radio.tsx index ec953acc128..9df7e0eaaf2 100644 --- a/design-system/packages/fields/src/Radio.tsx +++ b/design-system/packages/fields/src/Radio.tsx @@ -1,18 +1,18 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { Fragment, InputHTMLAttributes, ReactNode, forwardRef } from 'react'; -import { jsx, VisuallyHidden } from '@keystone-ui/core'; +import { Fragment, type InputHTMLAttributes, type ReactNode, forwardRef } from 'react' +import { jsx, VisuallyHidden } from '@keystone-ui/core' -import { ControlLabel } from './components/ControlLabel'; -import { DotIcon } from './components/Icons'; -import { useIndicatorStyles, useIndicatorTokens } from './hooks/indicators'; -import type { SizeType } from './types'; +import { ControlLabel } from './components/ControlLabel' +import { DotIcon } from './components/Icons' +import { useIndicatorStyles, useIndicatorTokens } from './hooks/indicators' +import type { SizeType } from './types' type RadioProps = { /** The radio label content. */ - children: ReactNode; -} & RadioControlProps; + children: ReactNode +} & RadioControlProps export const Radio = forwardRef( ({ children, className, size, ...props }, ref) => { @@ -24,20 +24,20 @@ export const Radio = forwardRef( > {children} - ); + ) } -); +) type RadioControlProps = { /** When true, the radio will be checked. */ - checked?: boolean; + checked?: boolean /** When true, the radio will be disabled. */ - disabled?: boolean; + disabled?: boolean /** The size of the Radio */ - size?: SizeType; + size?: SizeType /** The value of the Radio. */ - value?: string; -} & Omit, 'size'>; + value?: string +} & Omit, 'size'> export const RadioControl = forwardRef( ({ size, ...props }, ref) => ( @@ -48,10 +48,10 @@ export const RadioControl = forwardRef( ) -); +) -const Indicator = ({ size, ...props }: { size?: SizeType; children?: ReactNode }) => { - const tokens = useIndicatorTokens({ type: 'radio', size: size || 'medium' }); - const styles = useIndicatorStyles({ tokens }); - return
; -}; +const Indicator = ({ size, ...props }: { size?: SizeType, children?: ReactNode }) => { + const tokens = useIndicatorTokens({ type: 'radio', size: size || 'medium' }) + const styles = useIndicatorStyles({ tokens }) + return
+} diff --git a/design-system/packages/fields/src/Select.tsx b/design-system/packages/fields/src/Select.tsx index 5776fa56cb3..c643bfd7583 100644 --- a/design-system/packages/fields/src/Select.tsx +++ b/design-system/packages/fields/src/Select.tsx @@ -1,39 +1,39 @@ /** @jsxRuntime classic */ /** @jsx jsx */ -import { jsx, useTheme } from '@keystone-ui/core'; -import ReactSelect, { Options, mergeStyles, Props } from 'react-select'; -import { useInputTokens } from './hooks/inputs'; -import { WidthType } from './types'; +import { jsx, useTheme } from '@keystone-ui/core' +import ReactSelect, { type Options, mergeStyles, type Props } from 'react-select' +import { useInputTokens } from './hooks/inputs' +import { type WidthType } from './types' -type Option = { label: string; value: string; isDisabled?: boolean }; +type Option = { label: string, value: string, isDisabled?: boolean } type BaseSelectProps = Omit< Props, 'value' | 'onChange' | 'isMulti' | 'isOptionDisabled' -> & { width?: WidthType }; +> & { width?: WidthType } -export { components as selectComponents } from 'react-select'; +export { components as selectComponents } from 'react-select' type ControlState = { - isDisabled?: boolean; - isFocused: boolean; -}; + isDisabled?: boolean + isFocused: boolean +} const useStyles = ({ tokens, multi = false, }: { - tokens: ReturnType; - multi?: boolean; + tokens: ReturnType + multi?: boolean }) => { - const { palette } = useTheme(); + const { palette } = useTheme() const indicatorStyles = (provided: any, state: ControlState) => ({ ...provided, color: state.isFocused ? palette.neutral600 : palette.neutral500, ':hover': { color: state.isFocused ? palette.neutral800 : palette.neutral700, }, - }); + }) return { control: (provided: any, state: ControlState) => { const base = { @@ -45,7 +45,7 @@ const useStyles = ({ fontSize: tokens.fontSize, boxShadow: tokens.shadow, transition: tokens.transition, - }; + } const variant = state.isDisabled ? { backgroundColor: tokens.disabled.background || tokens.background, @@ -67,8 +67,8 @@ const useStyles = ({ boxShadow: tokens.hover.shadow, color: tokens.hover.foreground, }, - }; - return { ...provided, ...base, ...variant }; + } + return { ...provided, ...base, ...variant } }, clearIndicator: indicatorStyles, dropdownIndicator: indicatorStyles, @@ -102,12 +102,12 @@ const useStyles = ({ ...provided, padding: multi ? `0 4px` : `0 6px`, }), - }; -}; + } +} -const portalTarget = typeof document !== 'undefined' ? document.body : undefined; +const portalTarget = typeof document !== 'undefined' ? document.body : undefined -export function Select({ +export function Select ({ id, onChange, value, @@ -116,13 +116,13 @@ export function Select({ styles, ...props }: BaseSelectProps & { - value: Option | null; - portalMenu?: true; - onChange(value: Option | null): void; + value: Option | null + portalMenu?: true + onChange(value: Option | null): void }) { - const tokens = useInputTokens({ width: widthKey }); - const defaultStyles = useStyles({ tokens }); - const composedStyles = styles ? mergeStyles(defaultStyles, styles) : defaultStyles; + const tokens = useInputTokens({ width: widthKey }) + const defaultStyles = useStyles({ tokens }) + const composedStyles = styles ? mergeStyles(defaultStyles, styles) : defaultStyles return ( { if (!value) { - onChange(null); + onChange(null) } else { - onChange(value as any); + onChange(value as any) } }} {...props} isMulti={false} menuPortalTarget={portalMenu && portalTarget} /> - ); + ) } -export function MultiSelect({ +export function MultiSelect ({ id, onChange, value, @@ -153,13 +153,13 @@ export function MultiSelect({ styles, ...props }: BaseSelectProps & { - value: Options