From 14ffdeaa2d5de0405ce5aa3cf6bd5358f75d1937 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Thu, 13 Aug 2026 22:04:38 +1000 Subject: [PATCH] Refactor component entrypoints (#407) --- .../docs/components/actions/button.mdx | 2 +- .../docs/components/actions/icon-button.mdx | 2 +- .../content/docs/components/actions/link.mdx | 2 +- .../components/feedback/loading-skeleton.mdx | 2 +- .../components/feedback/loading-spinner.mdx | 2 +- .../docs/components/forms/checkbox.mdx | 2 +- .../docs/components/forms/combobox-field.mdx | 2 +- .../docs/components/forms/text-field.mdx | 2 +- .../content/docs/components/layout/box.mdx | 2 +- .../docs/components/primitives/button.mdx | 2 +- .../docs/components/primitives/checkbox.mdx | 8 +- .../docs/components/primitives/field.mdx | 2 +- .../components/primitives/input-group.mdx | 8 +- .../components/primitives/visually-hidden.mdx | 2 +- .../docs/components/typography/blockquote.mdx | 2 +- .../docs/components/typography/code.mdx | 2 +- .../content/docs/components/typography/em.mdx | 2 +- .../docs/components/typography/emoji.mdx | 2 +- .../docs/components/typography/heading.mdx | 2 +- .../docs/components/typography/kbd.mdx | 2 +- .../docs/components/typography/numeral.mdx | 2 +- .../docs/components/typography/quote.mdx | 2 +- .../docs/components/typography/strong.mdx | 2 +- .../docs/components/typography/text.mdx | 2 +- .../content/docs/components/visuals/icon.mdx | 2 +- apps/docs/source.config.ts | 2 +- .../docs/src/lib/generate-props-pages.test.ts | 10 +- docs/COMPONENTS.md | 3 + docs/CONVENTIONS.md | 2 +- knip.config.ts | 3 - packages/@luke-ui/react/AGENTS.md | 3 +- packages/@luke-ui/react/package.json | 2 +- .../blockquote/{index.tsx => blockquote.tsx} | 8 +- .../@luke-ui/react/src/blockquote/index.ts | 2 + .../react/src/box/{index.tsx => box.tsx} | 2 +- packages/@luke-ui/react/src/box/index.ts | 1 + .../src/button/{index.tsx => button.tsx} | 10 +- packages/@luke-ui/react/src/button/index.ts | 2 + .../src/checkbox/{index.tsx => checkbox.tsx} | 9 +- packages/@luke-ui/react/src/checkbox/index.ts | 2 + .../react/src/code/{index.tsx => code.tsx} | 3 +- packages/@luke-ui/react/src/code/index.ts | 2 + .../{index.tsx => combobox-field.tsx} | 8 +- .../react/src/combobox-field/index.ts | 1 + .../react/src/conformance/manifest.test.ts | 15 ++- .../react/src/em/{index.tsx => em.tsx} | 6 +- packages/@luke-ui/react/src/em/index.ts | 1 + .../react/src/emoji/{index.tsx => emoji.tsx} | 2 +- packages/@luke-ui/react/src/emoji/index.ts | 1 + .../src/heading/{index.tsx => heading.tsx} | 10 +- packages/@luke-ui/react/src/heading/index.ts | 9 ++ .../{index.tsx => icon-button.tsx} | 12 +- .../@luke-ui/react/src/icon-button/index.ts | 2 + .../react/src/icon-button/recipe.css.ts | 2 +- .../react/src/icon/{index.tsx => icon.tsx} | 4 +- packages/@luke-ui/react/src/icon/index.ts | 14 +++ packages/@luke-ui/react/src/kbd/index.ts | 2 + .../react/src/kbd/{index.tsx => kbd.tsx} | 4 +- packages/@luke-ui/react/src/link/index.ts | 2 + .../react/src/link/{index.tsx => link.tsx} | 4 +- .../react/src/loading-skeleton/index.ts | 6 + .../{index.tsx => loading-skeleton.tsx} | 2 +- .../react/src/loading-spinner/index.ts | 2 + .../{index.tsx => loading-spinner.tsx} | 4 +- .../react/src/loading-spinner/recipe.css.ts | 54 ++++----- packages/@luke-ui/react/src/numeral/index.ts | 7 ++ .../src/numeral/{index.tsx => numeral.tsx} | 4 +- .../react/src/numeral/numeral.visual.test.tsx | 2 +- .../react/src/overlays/mobile-overlay.tsx | 4 +- .../button/{index.tsx => button.tsx} | 4 +- .../react/src/primitives/button/index.ts | 2 + .../checkbox/{index.tsx => checkbox.tsx} | 2 - .../react/src/primitives/checkbox/index.ts | 11 ++ .../combobox/{index.tsx => index.ts} | 0 .../react/src/primitives/combobox/item.tsx | 2 +- .../react/src/primitives/combobox/popover.tsx | 4 +- .../primitives/field/{index.tsx => field.tsx} | 1 - .../react/src/primitives/field/index.ts | 12 ++ .../react/src/primitives/input-group/index.ts | 15 +++ .../{index.tsx => input-group.tsx} | 8 +- packages/@luke-ui/react/src/quote/index.ts | 1 + .../react/src/quote/{index.tsx => quote.tsx} | 4 +- packages/@luke-ui/react/src/strong/index.ts | 1 + .../src/strong/{index.tsx => strong.tsx} | 6 +- packages/@luke-ui/react/src/styles/recipe.ts | 2 +- .../@luke-ui/react/src/text-field/index.ts | 1 + .../text-field/{index.tsx => text-field.tsx} | 6 +- packages/@luke-ui/react/src/text/index.ts | 2 + .../react/src/text/{index.tsx => text.tsx} | 4 +- packages/@luke-ui/react/src/theme/index.ts | 16 +++ packages/@luke-ui/react/src/theme/index.tsx | 82 ------------- packages/@luke-ui/react/src/theme/theme.ts | 9 ++ .../@luke-ui/react/src/themes/paper/index.ts | 10 +- .../@luke-ui/react/src/themes/paper/theme.ts | 8 ++ .../react/src/themes/tactile/index.ts | 11 +- .../react/src/themes/tactile/theme.ts | 9 ++ packages/@luke-ui/react/src/utils/index.ts | 112 ++---------------- packages/@luke-ui/react/src/utils/utils.ts | 103 ++++++++++++++++ .../react/src/visually-hidden/index.ts | 2 + .../{index.tsx => visually-hidden.tsx} | 3 +- packages/@luke-ui/react/vite.config.ts | 4 +- packages/turbo-generators/README.md | 2 + .../src/apply-component-creation-plan.test.ts | 4 +- .../src/component-creation-plan.test.ts | 29 +++-- .../src/component-creation-plan.ts | 23 +++- 105 files changed, 440 insertions(+), 387 deletions(-) rename packages/@luke-ui/react/src/blockquote/{index.tsx => blockquote.tsx} (79%) create mode 100644 packages/@luke-ui/react/src/blockquote/index.ts rename packages/@luke-ui/react/src/box/{index.tsx => box.tsx} (98%) create mode 100644 packages/@luke-ui/react/src/box/index.ts rename packages/@luke-ui/react/src/button/{index.tsx => button.tsx} (92%) create mode 100644 packages/@luke-ui/react/src/button/index.ts rename packages/@luke-ui/react/src/checkbox/{index.tsx => checkbox.tsx} (92%) create mode 100644 packages/@luke-ui/react/src/checkbox/index.ts rename packages/@luke-ui/react/src/code/{index.tsx => code.tsx} (84%) create mode 100644 packages/@luke-ui/react/src/code/index.ts rename packages/@luke-ui/react/src/combobox-field/{index.tsx => combobox-field.tsx} (98%) create mode 100644 packages/@luke-ui/react/src/combobox-field/index.ts rename packages/@luke-ui/react/src/em/{index.tsx => em.tsx} (88%) create mode 100644 packages/@luke-ui/react/src/em/index.ts rename packages/@luke-ui/react/src/emoji/{index.tsx => emoji.tsx} (95%) create mode 100644 packages/@luke-ui/react/src/emoji/index.ts rename packages/@luke-ui/react/src/heading/{index.tsx => heading.tsx} (88%) create mode 100644 packages/@luke-ui/react/src/heading/index.ts rename packages/@luke-ui/react/src/icon-button/{index.tsx => icon-button.tsx} (84%) create mode 100644 packages/@luke-ui/react/src/icon-button/index.ts rename packages/@luke-ui/react/src/icon/{index.tsx => icon.tsx} (97%) create mode 100644 packages/@luke-ui/react/src/icon/index.ts create mode 100644 packages/@luke-ui/react/src/kbd/index.ts rename packages/@luke-ui/react/src/kbd/{index.tsx => kbd.tsx} (84%) create mode 100644 packages/@luke-ui/react/src/link/index.ts rename packages/@luke-ui/react/src/link/{index.tsx => link.tsx} (92%) create mode 100644 packages/@luke-ui/react/src/loading-skeleton/index.ts rename packages/@luke-ui/react/src/loading-skeleton/{index.tsx => loading-skeleton.tsx} (98%) create mode 100644 packages/@luke-ui/react/src/loading-spinner/index.ts rename packages/@luke-ui/react/src/loading-spinner/{index.tsx => loading-spinner.tsx} (95%) create mode 100644 packages/@luke-ui/react/src/numeral/index.ts rename packages/@luke-ui/react/src/numeral/{index.tsx => numeral.tsx} (98%) rename packages/@luke-ui/react/src/primitives/button/{index.tsx => button.tsx} (94%) create mode 100644 packages/@luke-ui/react/src/primitives/button/index.ts rename packages/@luke-ui/react/src/primitives/checkbox/{index.tsx => checkbox.tsx} (98%) create mode 100644 packages/@luke-ui/react/src/primitives/checkbox/index.ts rename packages/@luke-ui/react/src/primitives/combobox/{index.tsx => index.ts} (100%) rename packages/@luke-ui/react/src/primitives/field/{index.tsx => field.tsx} (95%) create mode 100644 packages/@luke-ui/react/src/primitives/field/index.ts create mode 100644 packages/@luke-ui/react/src/primitives/input-group/index.ts rename packages/@luke-ui/react/src/primitives/input-group/{index.tsx => input-group.tsx} (97%) create mode 100644 packages/@luke-ui/react/src/quote/index.ts rename packages/@luke-ui/react/src/quote/{index.tsx => quote.tsx} (91%) create mode 100644 packages/@luke-ui/react/src/strong/index.ts rename packages/@luke-ui/react/src/strong/{index.tsx => strong.tsx} (89%) create mode 100644 packages/@luke-ui/react/src/text-field/index.ts rename packages/@luke-ui/react/src/text-field/{index.tsx => text-field.tsx} (92%) create mode 100644 packages/@luke-ui/react/src/text/index.ts rename packages/@luke-ui/react/src/text/{index.tsx => text.tsx} (97%) create mode 100644 packages/@luke-ui/react/src/theme/index.ts delete mode 100644 packages/@luke-ui/react/src/theme/index.tsx create mode 100644 packages/@luke-ui/react/src/theme/theme.ts create mode 100644 packages/@luke-ui/react/src/themes/paper/theme.ts create mode 100644 packages/@luke-ui/react/src/themes/tactile/theme.ts create mode 100644 packages/@luke-ui/react/src/utils/utils.ts create mode 100644 packages/@luke-ui/react/src/visually-hidden/index.ts rename packages/@luke-ui/react/src/visually-hidden/{index.tsx => visually-hidden.tsx} (92%) diff --git a/apps/docs/content/docs/components/actions/button.mdx b/apps/docs/content/docs/components/actions/button.mdx index f8dd1b36..c7e0ec39 100644 --- a/apps/docs/content/docs/components/actions/button.mdx +++ b/apps/docs/content/docs/components/actions/button.mdx @@ -5,7 +5,7 @@ source: packages/@luke-ui/react/src/button reactAria: https://react-spectrum.adobe.com/react-aria/Button.html props: - name: ButtonProps - path: packages/@luke-ui/react/src/button/index.tsx + path: packages/@luke-ui/react/src/button/button.tsx --- `Button` triggers an action, such as saving a form, opening a dialog, or deleting an item. Use diff --git a/apps/docs/content/docs/components/actions/icon-button.mdx b/apps/docs/content/docs/components/actions/icon-button.mdx index 1846f151..09fd65e4 100644 --- a/apps/docs/content/docs/components/actions/icon-button.mdx +++ b/apps/docs/content/docs/components/actions/icon-button.mdx @@ -5,7 +5,7 @@ source: packages/@luke-ui/react/src/icon-button reactAria: https://react-spectrum.adobe.com/react-aria/Button.html props: - name: IconButtonProps - path: packages/@luke-ui/react/src/icon-button/index.tsx + path: packages/@luke-ui/react/src/icon-button/icon-button.tsx --- `IconButton` triggers a familiar compact action, such as closing a panel, deleting a row, or adding diff --git a/apps/docs/content/docs/components/actions/link.mdx b/apps/docs/content/docs/components/actions/link.mdx index 2703388e..45605c8d 100644 --- a/apps/docs/content/docs/components/actions/link.mdx +++ b/apps/docs/content/docs/components/actions/link.mdx @@ -5,7 +5,7 @@ source: packages/@luke-ui/react/src/link reactAria: https://react-spectrum.adobe.com/react-aria/Link.html props: - name: LinkProps - path: packages/@luke-ui/react/src/link/index.tsx + path: packages/@luke-ui/react/src/link/link.tsx --- `Link` navigates to another URL or route. Use [`Button`](/components/actions/button) for an action diff --git a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx index 5f03c6b1..9f806ca7 100644 --- a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx +++ b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx @@ -4,7 +4,7 @@ description: Replaces content with a placeholder that keeps its shape while it l source: packages/@luke-ui/react/src/loading-skeleton props: - name: LoadingSkeletonProps - path: packages/@luke-ui/react/src/loading-skeleton/index.tsx + path: packages/@luke-ui/react/src/loading-skeleton/loading-skeleton.tsx --- Use `LoadingSkeleton` when content is loading but its layout is known. Wrap the content that will diff --git a/apps/docs/content/docs/components/feedback/loading-spinner.mdx b/apps/docs/content/docs/components/feedback/loading-spinner.mdx index 4caacfb4..c3976b9d 100644 --- a/apps/docs/content/docs/components/feedback/loading-spinner.mdx +++ b/apps/docs/content/docs/components/feedback/loading-spinner.mdx @@ -4,7 +4,7 @@ description: Animated indicator for work that is still in progress. source: packages/@luke-ui/react/src/loading-spinner props: - name: LoadingSpinnerProps - path: packages/@luke-ui/react/src/loading-spinner/index.tsx + path: packages/@luke-ui/react/src/loading-spinner/loading-spinner.tsx --- `LoadingSpinner` shows that work is in progress. Use it on its own for a small loading region. Wrap diff --git a/apps/docs/content/docs/components/forms/checkbox.mdx b/apps/docs/content/docs/components/forms/checkbox.mdx index b15b0137..dc02a62c 100644 --- a/apps/docs/content/docs/components/forms/checkbox.mdx +++ b/apps/docs/content/docs/components/forms/checkbox.mdx @@ -6,7 +6,7 @@ source: packages/@luke-ui/react/src/checkbox reactAria: https://react-spectrum.adobe.com/react-aria/Checkbox.html props: - name: CheckboxProps - path: packages/@luke-ui/react/src/checkbox/index.tsx + path: packages/@luke-ui/react/src/checkbox/checkbox.tsx --- Use `Checkbox` when someone can choose an option independently of nearby controls. Pass diff --git a/apps/docs/content/docs/components/forms/combobox-field.mdx b/apps/docs/content/docs/components/forms/combobox-field.mdx index 0f7a38aa..d18e5b76 100644 --- a/apps/docs/content/docs/components/forms/combobox-field.mdx +++ b/apps/docs/content/docs/components/forms/combobox-field.mdx @@ -5,7 +5,7 @@ source: packages/@luke-ui/react/src/combobox-field reactAria: https://react-spectrum.adobe.com/react-aria/ComboBox.html props: - name: ComboboxFieldProps - path: packages/@luke-ui/react/src/combobox-field/index.tsx + path: packages/@luke-ui/react/src/combobox-field/combobox-field.tsx --- Use `ComboboxField` when someone needs to search for or choose one option from a list. It combines diff --git a/apps/docs/content/docs/components/forms/text-field.mdx b/apps/docs/content/docs/components/forms/text-field.mdx index 6d8e81b1..b411b09d 100644 --- a/apps/docs/content/docs/components/forms/text-field.mdx +++ b/apps/docs/content/docs/components/forms/text-field.mdx @@ -6,7 +6,7 @@ source: packages/@luke-ui/react/src/text-field reactAria: https://react-spectrum.adobe.com/react-aria/TextField.html props: - name: TextFieldProps - path: packages/@luke-ui/react/src/text-field/index.tsx + path: packages/@luke-ui/react/src/text-field/text-field.tsx --- Use `TextField` to collect a single line of text. It combines an input with a label, description, diff --git a/apps/docs/content/docs/components/layout/box.mdx b/apps/docs/content/docs/components/layout/box.mdx index 19e3b04d..e90a02f9 100644 --- a/apps/docs/content/docs/components/layout/box.mdx +++ b/apps/docs/content/docs/components/layout/box.mdx @@ -4,7 +4,7 @@ description: A layout element with responsive Luke UI layout properties. source: packages/@luke-ui/react/src/box props: - name: BoxProps - path: packages/@luke-ui/react/src/box/index.tsx + path: packages/@luke-ui/react/src/box/box.tsx --- `Box` accepts Luke UI layout properties and renders a `div` by default. It places content in a diff --git a/apps/docs/content/docs/components/primitives/button.mdx b/apps/docs/content/docs/components/primitives/button.mdx index b8dfaa88..aee51405 100644 --- a/apps/docs/content/docs/components/primitives/button.mdx +++ b/apps/docs/content/docs/components/primitives/button.mdx @@ -5,7 +5,7 @@ source: packages/@luke-ui/react/src/primitives/button reactAria: https://react-spectrum.adobe.com/react-aria/Button.html props: - name: ButtonProps - path: packages/@luke-ui/react/src/primitives/button/index.tsx + path: packages/@luke-ui/react/src/primitives/button/button.tsx --- Use the button primitive to build a custom button pattern. It provides Luke UI button styles and diff --git a/apps/docs/content/docs/components/primitives/checkbox.mdx b/apps/docs/content/docs/components/primitives/checkbox.mdx index c3097e4f..e4620f2d 100644 --- a/apps/docs/content/docs/components/primitives/checkbox.mdx +++ b/apps/docs/content/docs/components/primitives/checkbox.mdx @@ -5,16 +5,16 @@ source: packages/@luke-ui/react/src/primitives/checkbox reactAria: https://react-spectrum.adobe.com/react-aria/Checkbox.html props: - name: CheckboxProps - path: packages/@luke-ui/react/src/primitives/checkbox/index.tsx + path: packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx heading: Checkbox - name: CheckboxContentProps - path: packages/@luke-ui/react/src/primitives/checkbox/index.tsx + path: packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx heading: CheckboxContent - name: CheckboxControlProps - path: packages/@luke-ui/react/src/primitives/checkbox/index.tsx + path: packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx heading: CheckboxControl - name: CheckboxIndicatorProps - path: packages/@luke-ui/react/src/primitives/checkbox/index.tsx + path: packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx heading: CheckboxIndicator --- diff --git a/apps/docs/content/docs/components/primitives/field.mdx b/apps/docs/content/docs/components/primitives/field.mdx index 8ff625a8..0c54accc 100644 --- a/apps/docs/content/docs/components/primitives/field.mdx +++ b/apps/docs/content/docs/components/primitives/field.mdx @@ -4,7 +4,7 @@ description: Shared label, description, and validation parts for custom fields. source: packages/@luke-ui/react/src/primitives/field props: - name: FieldProps - path: packages/@luke-ui/react/src/primitives/field/index.tsx + path: packages/@luke-ui/react/src/primitives/field/field.tsx heading: Field - name: FieldLabelProps path: packages/@luke-ui/react/src/primitives/field/label.tsx diff --git a/apps/docs/content/docs/components/primitives/input-group.mdx b/apps/docs/content/docs/components/primitives/input-group.mdx index f82e70bb..f4f8bad7 100644 --- a/apps/docs/content/docs/components/primitives/input-group.mdx +++ b/apps/docs/content/docs/components/primitives/input-group.mdx @@ -4,16 +4,16 @@ description: Lower-level parts for composing a text input with content at either source: packages/@luke-ui/react/src/primitives/input-group props: - name: InputGroupProps - path: packages/@luke-ui/react/src/primitives/input-group/index.tsx + path: packages/@luke-ui/react/src/primitives/input-group/input-group.tsx heading: InputGroup - name: InputGroupInputProps - path: packages/@luke-ui/react/src/primitives/input-group/index.tsx + path: packages/@luke-ui/react/src/primitives/input-group/input-group.tsx heading: InputGroupInput - name: InputGroupPrefixProps - path: packages/@luke-ui/react/src/primitives/input-group/index.tsx + path: packages/@luke-ui/react/src/primitives/input-group/input-group.tsx heading: InputGroupPrefix - name: InputGroupSuffixProps - path: packages/@luke-ui/react/src/primitives/input-group/index.tsx + path: packages/@luke-ui/react/src/primitives/input-group/input-group.tsx heading: InputGroupSuffix --- diff --git a/apps/docs/content/docs/components/primitives/visually-hidden.mdx b/apps/docs/content/docs/components/primitives/visually-hidden.mdx index bf2311c5..8d77dcc3 100644 --- a/apps/docs/content/docs/components/primitives/visually-hidden.mdx +++ b/apps/docs/content/docs/components/primitives/visually-hidden.mdx @@ -4,7 +4,7 @@ description: Hide content visually and keep it available to assistive technology source: packages/@luke-ui/react/src/visually-hidden props: - name: VisuallyHiddenProps - path: packages/@luke-ui/react/src/visually-hidden/index.tsx + path: packages/@luke-ui/react/src/visually-hidden/visually-hidden.tsx --- Use `VisuallyHidden` to hide content from sight. The content stays in the accessibility tree and the diff --git a/apps/docs/content/docs/components/typography/blockquote.mdx b/apps/docs/content/docs/components/typography/blockquote.mdx index 21e21ac5..fedd1b61 100644 --- a/apps/docs/content/docs/components/typography/blockquote.mdx +++ b/apps/docs/content/docs/components/typography/blockquote.mdx @@ -4,7 +4,7 @@ description: Block-level quotation from another source. source: packages/@luke-ui/react/src/blockquote props: - name: BlockquoteProps - path: packages/@luke-ui/react/src/blockquote/index.tsx + path: packages/@luke-ui/react/src/blockquote/blockquote.tsx --- `Blockquote` quotes another source as a block. It renders a native `blockquote` element, which diff --git a/apps/docs/content/docs/components/typography/code.mdx b/apps/docs/content/docs/components/typography/code.mdx index db380841..1427f4e9 100644 --- a/apps/docs/content/docs/components/typography/code.mdx +++ b/apps/docs/content/docs/components/typography/code.mdx @@ -4,7 +4,7 @@ description: Marks text to signify a short fragment of computer code. source: packages/@luke-ui/react/src/code props: - name: CodeProps - path: packages/@luke-ui/react/src/code/index.tsx + path: packages/@luke-ui/react/src/code/code.tsx --- `Code` marks a short fragment of computer code. It renders a native `code` element, which conveys diff --git a/apps/docs/content/docs/components/typography/em.mdx b/apps/docs/content/docs/components/typography/em.mdx index ed7f5e38..2c29a588 100644 --- a/apps/docs/content/docs/components/typography/em.mdx +++ b/apps/docs/content/docs/components/typography/em.mdx @@ -4,7 +4,7 @@ description: Marks text to stress emphasis. source: packages/@luke-ui/react/src/em props: - name: EmProps - path: packages/@luke-ui/react/src/em/index.tsx + path: packages/@luke-ui/react/src/em/em.tsx --- `Em` stresses a word or phrase, changing how the sentence reads. It renders a native `em` element, diff --git a/apps/docs/content/docs/components/typography/emoji.mdx b/apps/docs/content/docs/components/typography/emoji.mdx index ff058da2..48df66bc 100644 --- a/apps/docs/content/docs/components/typography/emoji.mdx +++ b/apps/docs/content/docs/components/typography/emoji.mdx @@ -4,7 +4,7 @@ description: Emoji rendering with a reliable screen reader label. source: packages/@luke-ui/react/src/emoji props: - name: EmojiProps - path: packages/@luke-ui/react/src/emoji/index.tsx + path: packages/@luke-ui/react/src/emoji/emoji.tsx --- `Emoji` renders an emoji with a reliable accessible name. It inherits its size from the surrounding diff --git a/apps/docs/content/docs/components/typography/heading.mdx b/apps/docs/content/docs/components/typography/heading.mdx index 1af2d2f8..be7b4da0 100644 --- a/apps/docs/content/docs/components/typography/heading.mdx +++ b/apps/docs/content/docs/components/typography/heading.mdx @@ -4,7 +4,7 @@ description: Semantic heading with automatic level management. source: packages/@luke-ui/react/src/heading props: - name: HeadingProps - path: packages/@luke-ui/react/src/heading/index.tsx + path: packages/@luke-ui/react/src/heading/heading.tsx --- `Heading` renders a semantic section heading. It reads its level from `HeadingLevels` context. Set diff --git a/apps/docs/content/docs/components/typography/kbd.mdx b/apps/docs/content/docs/components/typography/kbd.mdx index 9621d611..f59cd580 100644 --- a/apps/docs/content/docs/components/typography/kbd.mdx +++ b/apps/docs/content/docs/components/typography/kbd.mdx @@ -4,7 +4,7 @@ description: Represents keyboard input or a hotkey. source: packages/@luke-ui/react/src/kbd props: - name: KbdProps - path: packages/@luke-ui/react/src/kbd/index.tsx + path: packages/@luke-ui/react/src/kbd/kbd.tsx --- `Kbd` marks keyboard input, such as a shortcut or a key name. It renders a native `kbd` element, diff --git a/apps/docs/content/docs/components/typography/numeral.mdx b/apps/docs/content/docs/components/typography/numeral.mdx index c9bb9333..dbb6ad1a 100644 --- a/apps/docs/content/docs/components/typography/numeral.mdx +++ b/apps/docs/content/docs/components/typography/numeral.mdx @@ -4,7 +4,7 @@ description: Locale-aware number formatting powered by Intl.NumberFormat. source: packages/@luke-ui/react/src/numeral props: - name: NumeralProps - path: packages/@luke-ui/react/src/numeral/index.tsx + path: packages/@luke-ui/react/src/numeral/numeral.tsx --- `Numeral` formats a number with `Intl.NumberFormat`. It reads the active locale from React Aria's diff --git a/apps/docs/content/docs/components/typography/quote.mdx b/apps/docs/content/docs/components/typography/quote.mdx index fb3f40b1..e66be4ab 100644 --- a/apps/docs/content/docs/components/typography/quote.mdx +++ b/apps/docs/content/docs/components/typography/quote.mdx @@ -4,7 +4,7 @@ description: Short inline quotation. source: packages/@luke-ui/react/src/quote props: - name: QuoteProps - path: packages/@luke-ui/react/src/quote/index.tsx + path: packages/@luke-ui/react/src/quote/quote.tsx --- `Quote` marks a short quotation inside a sentence. It renders a native `q` element, which conveys diff --git a/apps/docs/content/docs/components/typography/strong.mdx b/apps/docs/content/docs/components/typography/strong.mdx index 7b25f1d3..5ba01efd 100644 --- a/apps/docs/content/docs/components/typography/strong.mdx +++ b/apps/docs/content/docs/components/typography/strong.mdx @@ -4,7 +4,7 @@ description: Marks text to signify strong importance. source: packages/@luke-ui/react/src/strong props: - name: StrongProps - path: packages/@luke-ui/react/src/strong/index.tsx + path: packages/@luke-ui/react/src/strong/strong.tsx --- `Strong` marks text as important. It renders a native `strong` element, which conveys importance to diff --git a/apps/docs/content/docs/components/typography/text.mdx b/apps/docs/content/docs/components/typography/text.mdx index 3ca5f184..273d0f6c 100644 --- a/apps/docs/content/docs/components/typography/text.mdx +++ b/apps/docs/content/docs/components/typography/text.mdx @@ -4,7 +4,7 @@ description: Styled text with semantic typography styles and colour roles. source: packages/@luke-ui/react/src/text props: - name: TextProps - path: packages/@luke-ui/react/src/text/index.tsx + path: packages/@luke-ui/react/src/text/text.tsx --- `Text` applies Luke UI typography without adding heading semantics. It needs a Luke UI theme root. diff --git a/apps/docs/content/docs/components/visuals/icon.mdx b/apps/docs/content/docs/components/visuals/icon.mdx index 1b3027c3..a61b38ab 100644 --- a/apps/docs/content/docs/components/visuals/icon.mdx +++ b/apps/docs/content/docs/components/visuals/icon.mdx @@ -4,7 +4,7 @@ description: SVG icon component backed by the generated spritesheet. source: packages/@luke-ui/react/src/icon props: - name: IconProps - path: packages/@luke-ui/react/src/icon/index.tsx + path: packages/@luke-ui/react/src/icon/icon.tsx --- `Icon` renders a symbol from the generated Luke UI spritesheet. It needs an diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index 48010ccd..51f58447 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -28,7 +28,7 @@ export const docs = defineDocs({ heading: z.string().optional(), /** Exported type name to render, e.g. `ButtonProps`. */ name: z.string(), - /** Repo-relative path to the file exporting `name`, e.g. `packages/@luke-ui/react/src/button/index.tsx`. */ + /** Repo-relative path to the file exporting `name`, e.g. `packages/@luke-ui/react/src/button/button.tsx`. */ path: z.string(), }), ) diff --git a/apps/docs/src/lib/generate-props-pages.test.ts b/apps/docs/src/lib/generate-props-pages.test.ts index cb31554a..f64d6497 100644 --- a/apps/docs/src/lib/generate-props-pages.test.ts +++ b/apps/docs/src/lib/generate-props-pages.test.ts @@ -27,7 +27,7 @@ source: packages/@luke-ui/react/src/button reactAria: https://react-spectrum.adobe.com/react-aria/Button.html props: - name: ButtonProps - path: packages/@luke-ui/react/src/button/index.tsx + path: packages/@luke-ui/react/src/button/button.tsx --- `); @@ -42,7 +42,7 @@ reactAria: https://react-spectrum.adobe.com/react-aria/Button.html ## Props - + `); }); @@ -53,7 +53,7 @@ description: Shared label, description, and validation parts for custom fields. source: packages/@luke-ui/react/src/primitives/field props: - name: FieldProps - path: packages/@luke-ui/react/src/primitives/field/index.tsx + path: packages/@luke-ui/react/src/primitives/field/field.tsx heading: Field - name: FieldLabelProps path: packages/@luke-ui/react/src/primitives/field/label.tsx @@ -73,7 +73,7 @@ source: packages/@luke-ui/react/src/primitives/field ### Field - + ### FieldLabel @@ -151,7 +151,7 @@ const SCRATCH_GUIDE = `--- title: Button props: - name: ButtonProps - path: packages/@luke-ui/react/src/button/index.tsx + path: packages/@luke-ui/react/src/button/button.tsx --- Guide body. diff --git a/docs/COMPONENTS.md b/docs/COMPONENTS.md index 9f62cc16..a747992b 100644 --- a/docs/COMPONENTS.md +++ b/docs/COMPONENTS.md @@ -31,6 +31,9 @@ pnpm run generate:component --args Primitive scaffolding is not handled by the component generator. +Public subpath `index.ts` files are export-only. A component's implementation lives in a named +sibling file. Support modules and multi-part primitives each keep their own file. + The component creation rules live in `packages/turbo-generators/src/component-creation-plan.ts`. Turbo and Plop are adapters that apply the plan. Keep new creation rules in the plan module so dry-run tests can prove which files, exports, stories, docs, and checks a component needs. diff --git a/docs/CONVENTIONS.md b/docs/CONVENTIONS.md index 16f1d80a..1d32cf55 100644 --- a/docs/CONVENTIONS.md +++ b/docs/CONVENTIONS.md @@ -27,7 +27,7 @@ not as inline string constants. ## Naming -- Components: `PascalCase`, for example `Button.tsx`. +- Components: `PascalCase`, for example `IconButton`. - Props: `PascalCaseProps`, for example `ButtonProps`. - Files: `kebab-case`, for example `icon-button.tsx`. - CSS: `*.css.ts`. diff --git a/knip.config.ts b/knip.config.ts index 98de3b8e..60a4ff45 100644 --- a/knip.config.ts +++ b/knip.config.ts @@ -24,12 +24,9 @@ export default { 'packages/@luke-ui/react': { entry: [ 'src/**/*.stories.tsx', - 'src/**/index.tsx', 'src/**/index.ts', 'src/stylesheet.css.ts', 'src/styles/index.css.ts', - 'src/theme/index.tsx', - 'src/utils/index.ts', 'scripts/**/*.ts', ], project: ['src/**/*.{ts,tsx}'], diff --git a/packages/@luke-ui/react/AGENTS.md b/packages/@luke-ui/react/AGENTS.md index a51d633b..2563b2da 100644 --- a/packages/@luke-ui/react/AGENTS.md +++ b/packages/@luke-ui/react/AGENTS.md @@ -21,7 +21,8 @@ A component directory contains: - `[component].stories.tsx`: Storybook documentation and render/a11y fixtures - `[component].browser.test.tsx`: component behaviour, conformance, and the integration tripwire - `[component].visual.test.tsx`: visual regression captures when the component has a visual surface -- `index.tsx`: component implementation +- `.tsx`: component implementation +- `index.ts`: export-only public subpath barrel - `recipe.css.ts`: public recipe contract (scaffolded by the generator) - `styles.css.ts`: private implementation styling when needed diff --git a/packages/@luke-ui/react/package.json b/packages/@luke-ui/react/package.json index 6178b1b3..0c2064b6 100644 --- a/packages/@luke-ui/react/package.json +++ b/packages/@luke-ui/react/package.json @@ -63,7 +63,7 @@ "build": "pnpm run build:tsdown", "build:storybook": "storybook build", "build:tsdown": "vp pack", - "check:barrels": "unbarrelify --check --skip src/styles/index.ts --skip src/primitives/combobox/index.tsx", + "check:barrels": "unbarrelify --check --skip 'src/*/index.ts' --skip 'src/primitives/*/index.ts' --skip 'src/themes/*/index.ts'", "check:format": "vp fmt . --check", "check:lint": "vp lint . --type-aware", "check:story-plays": "tsx scripts/check-story-plays.ts", diff --git a/packages/@luke-ui/react/src/blockquote/index.tsx b/packages/@luke-ui/react/src/blockquote/blockquote.tsx similarity index 79% rename from packages/@luke-ui/react/src/blockquote/index.tsx rename to packages/@luke-ui/react/src/blockquote/blockquote.tsx index c5ba78a6..7a33c805 100644 --- a/packages/@luke-ui/react/src/blockquote/index.tsx +++ b/packages/@luke-ui/react/src/blockquote/blockquote.tsx @@ -1,12 +1,10 @@ -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { blockquoteRecipe } from './recipe.css.js'; -export { type BlockquoteRecipeVariants, blockquoteRecipe } from './recipe.css.js'; - type _BlockquoteOmit = DistributiveOmit; interface _BlockquoteProps extends _BlockquoteOmit {} diff --git a/packages/@luke-ui/react/src/blockquote/index.ts b/packages/@luke-ui/react/src/blockquote/index.ts new file mode 100644 index 00000000..0ecc08ac --- /dev/null +++ b/packages/@luke-ui/react/src/blockquote/index.ts @@ -0,0 +1,2 @@ +export { Blockquote, type BlockquoteProps } from './blockquote.js'; +export { type BlockquoteRecipeVariants, blockquoteRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/box/index.tsx b/packages/@luke-ui/react/src/box/box.tsx similarity index 98% rename from packages/@luke-ui/react/src/box/index.tsx rename to packages/@luke-ui/react/src/box/box.tsx index 2d9ee9b1..2b6cc959 100644 --- a/packages/@luke-ui/react/src/box/index.tsx +++ b/packages/@luke-ui/react/src/box/box.tsx @@ -3,7 +3,7 @@ import type { SprinklesProps } from '../styles/utilities.css.js'; import { createSprinkles } from '../styles/utilities.css.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { mergeProps } from '../utils/index.js'; +import { mergeProps } from '../utils/utils.js'; /** Props for `Box`. */ export type BoxProps = Prettify<_BoxElementProps | _BoxRenderProps>; diff --git a/packages/@luke-ui/react/src/box/index.ts b/packages/@luke-ui/react/src/box/index.ts new file mode 100644 index 00000000..4cc734ce --- /dev/null +++ b/packages/@luke-ui/react/src/box/index.ts @@ -0,0 +1 @@ +export { Box, type BoxProps } from './box.js'; diff --git a/packages/@luke-ui/react/src/button/index.tsx b/packages/@luke-ui/react/src/button/button.tsx similarity index 92% rename from packages/@luke-ui/react/src/button/index.tsx rename to packages/@luke-ui/react/src/button/button.tsx index fe5bae8c..f67b6c0c 100644 --- a/packages/@luke-ui/react/src/button/index.tsx +++ b/packages/@luke-ui/react/src/button/button.tsx @@ -1,11 +1,9 @@ -export { type ButtonRecipeVariants, buttonRecipe } from '../primitives/button/recipe.css.js'; - import type { JSX, ReactNode } from 'react'; -import { LoadingSpinner } from '../loading-spinner/index.js'; -import type { ButtonProps as PrimitiveButtonProps } from '../primitives/button/index.js'; -import { Button as PrimitiveButton } from '../primitives/button/index.js'; +import { LoadingSpinner } from '../loading-spinner/loading-spinner.js'; +import type { ButtonProps as PrimitiveButtonProps } from '../primitives/button/button.js'; +import { Button as PrimitiveButton } from '../primitives/button/button.js'; import type * as primitiveStyles from '../primitives/button/recipe.css.js'; -import { Text } from '../text/index.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { DocumentedPressProps } from '../types/documented-rac-props.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/button/index.ts b/packages/@luke-ui/react/src/button/index.ts new file mode 100644 index 00000000..58bbed93 --- /dev/null +++ b/packages/@luke-ui/react/src/button/index.ts @@ -0,0 +1,2 @@ +export { type ButtonRecipeVariants, buttonRecipe } from '../primitives/button/recipe.css.js'; +export { Button, type ButtonProps } from './button.js'; diff --git a/packages/@luke-ui/react/src/checkbox/index.tsx b/packages/@luke-ui/react/src/checkbox/checkbox.tsx similarity index 92% rename from packages/@luke-ui/react/src/checkbox/index.tsx rename to packages/@luke-ui/react/src/checkbox/checkbox.tsx index 33b54358..e51667eb 100644 --- a/packages/@luke-ui/react/src/checkbox/index.tsx +++ b/packages/@luke-ui/react/src/checkbox/checkbox.tsx @@ -1,16 +1,15 @@ -export { checkboxRecipe, type CheckboxRecipeVariants } from '../primitives/checkbox/recipe.css.js'; import { useObjectRef } from '@react-aria/utils'; import type { JSX, ReactNode, Ref } from 'react'; import type { CheckboxFieldProps as RacCheckboxFieldProps } from 'react-aria-components/Checkbox'; -import type { CheckboxProps as PrimitiveCheckboxProps } from '../primitives/checkbox/index.js'; +import type { CheckboxProps as PrimitiveCheckboxProps } from '../primitives/checkbox/checkbox.js'; import { CheckboxContent, CheckboxControl, CheckboxIndicator, Checkbox as PrimitiveCheckbox, -} from '../primitives/checkbox/index.js'; -import type { FieldErrorProps } from '../primitives/field/index.js'; -import { FieldDescription, FieldError } from '../primitives/field/index.js'; +} from '../primitives/checkbox/checkbox.js'; +import type { FieldErrorProps } from '../primitives/field/field.js'; +import { FieldDescription, FieldError } from '../primitives/field/field.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/checkbox/index.ts b/packages/@luke-ui/react/src/checkbox/index.ts new file mode 100644 index 00000000..8550f049 --- /dev/null +++ b/packages/@luke-ui/react/src/checkbox/index.ts @@ -0,0 +1,2 @@ +export { type CheckboxRecipeVariants, checkboxRecipe } from '../primitives/checkbox/recipe.css.js'; +export { Checkbox, type CheckboxProps } from './checkbox.js'; diff --git a/packages/@luke-ui/react/src/code/index.tsx b/packages/@luke-ui/react/src/code/code.tsx similarity index 84% rename from packages/@luke-ui/react/src/code/index.tsx rename to packages/@luke-ui/react/src/code/code.tsx index 534bf976..0ae31a3a 100644 --- a/packages/@luke-ui/react/src/code/index.tsx +++ b/packages/@luke-ui/react/src/code/code.tsx @@ -1,7 +1,6 @@ -export { codeRecipe, type CodeRecipeVariants } from './recipe.css.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { codeRecipe } from './recipe.css.js'; type _CodeOmit = DistributiveOmit, never>; diff --git a/packages/@luke-ui/react/src/code/index.ts b/packages/@luke-ui/react/src/code/index.ts new file mode 100644 index 00000000..52c9543c --- /dev/null +++ b/packages/@luke-ui/react/src/code/index.ts @@ -0,0 +1,2 @@ +export { Code, type CodeProps } from './code.js'; +export { type CodeRecipeVariants, codeRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/combobox-field/index.tsx b/packages/@luke-ui/react/src/combobox-field/combobox-field.tsx similarity index 98% rename from packages/@luke-ui/react/src/combobox-field/index.tsx rename to packages/@luke-ui/react/src/combobox-field/combobox-field.tsx index 2616a325..9b5011d1 100644 --- a/packages/@luke-ui/react/src/combobox-field/index.tsx +++ b/packages/@luke-ui/react/src/combobox-field/combobox-field.tsx @@ -12,8 +12,8 @@ import { useSlottedContext } from 'react-aria-components/slots'; import type { FieldSlotProps } from '../field/compose-field.js'; import { composeField } from '../field/compose-field.js'; import { IconSizeProvider } from '../icon/icon-size-context.js'; -import { Icon } from '../icon/index.js'; -import { LoadingSpinner } from '../loading-spinner/index.js'; +import { Icon } from '../icon/icon.js'; +import { LoadingSpinner } from '../loading-spinner/loading-spinner.js'; import { MobileOverlay } from '../overlays/mobile-overlay.js'; import { useIsMobileDevice } from '../overlays/use-is-mobile-device.js'; import { ComboboxClearButton } from '../primitives/combobox/clear-button.js'; @@ -30,11 +30,11 @@ import type { ComboboxRootProps, ComboboxSize } from '../primitives/combobox/roo import { ComboboxRoot } from '../primitives/combobox/root.js'; import { comboboxRecipe } from '../primitives/combobox/styles.css.js'; import { ComboboxTrigger } from '../primitives/combobox/trigger.js'; -import { Field } from '../primitives/field/index.js'; +import { Field } from '../primitives/field/field.js'; import { COMBOBOX_ICON_SIZE } from '../sizing/combobox-sizing.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; type ComboboxLoadingState = 'error' | 'filtering' | 'idle' | 'loading' | 'loadingMore' | 'sorting'; diff --git a/packages/@luke-ui/react/src/combobox-field/index.ts b/packages/@luke-ui/react/src/combobox-field/index.ts new file mode 100644 index 00000000..c66a32c6 --- /dev/null +++ b/packages/@luke-ui/react/src/combobox-field/index.ts @@ -0,0 +1 @@ +export { ComboboxField, type ComboboxFieldProps } from './combobox-field.js'; diff --git a/packages/@luke-ui/react/src/conformance/manifest.test.ts b/packages/@luke-ui/react/src/conformance/manifest.test.ts index 6cb86eee..cd36948d 100644 --- a/packages/@luke-ui/react/src/conformance/manifest.test.ts +++ b/packages/@luke-ui/react/src/conformance/manifest.test.ts @@ -6,6 +6,14 @@ import { componentTestManifest } from './manifest.js'; const sourceRoot = resolve(import.meta.dirname, '..'); const packageRoot = resolve(sourceRoot, '..'); +// Public subpaths that are not normal component entrypoints, so they are exempt from the +// conformance manifest. `theme` is deliberately absent from this set: it has its own manifest +// entry (conformance tier `none`), so it must keep flowing through the normal check below. Keep +// this list explicit and named rather than deriving it from the manifest itself, so a public +// component entrypoint missing from the manifest fails this test instead of being silently +// skipped. +const NON_COMPONENT_EXPORTS = new Set(['styles', 'themes/paper', 'themes/tactile', 'utils']); + function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null; } @@ -22,7 +30,10 @@ function getExportPaths() { for (const exportPath of Object.keys(packageJson.exports)) { if (!exportPath.startsWith('./') || exportPath.includes('*')) continue; const sourcePath = exportPath.slice(2); - if (existsSync(resolve(sourceRoot, sourcePath, 'index.tsx'))) paths.push(sourcePath); + if (NON_COMPONENT_EXPORTS.has(sourcePath)) continue; + if (existsSync(resolve(sourceRoot, sourcePath, 'index.ts'))) { + paths.push(sourcePath); + } } return paths.sort(); @@ -34,7 +45,7 @@ test('covers every public component entrypoint exactly once', () => { expect(new Set(paths).size).toBe(paths.length); expect([...paths].sort()).toEqual(getExportPaths()); for (const path of paths) { - expect(existsSync(resolve(sourceRoot, path, 'index.tsx'))).toBe(true); + expect(existsSync(resolve(sourceRoot, path, 'index.ts'))).toBe(true); } }); diff --git a/packages/@luke-ui/react/src/em/index.tsx b/packages/@luke-ui/react/src/em/em.tsx similarity index 88% rename from packages/@luke-ui/react/src/em/index.tsx rename to packages/@luke-ui/react/src/em/em.tsx index 9638393c..081c8e5f 100644 --- a/packages/@luke-ui/react/src/em/index.tsx +++ b/packages/@luke-ui/react/src/em/em.tsx @@ -1,8 +1,8 @@ -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { em } from './styles.css.js'; interface EmStyleProps { diff --git a/packages/@luke-ui/react/src/em/index.ts b/packages/@luke-ui/react/src/em/index.ts new file mode 100644 index 00000000..8f6e5d70 --- /dev/null +++ b/packages/@luke-ui/react/src/em/index.ts @@ -0,0 +1 @@ +export { Em, type EmProps } from './em.js'; diff --git a/packages/@luke-ui/react/src/emoji/index.tsx b/packages/@luke-ui/react/src/emoji/emoji.tsx similarity index 95% rename from packages/@luke-ui/react/src/emoji/index.tsx rename to packages/@luke-ui/react/src/emoji/emoji.tsx index 98c75015..049564bb 100644 --- a/packages/@luke-ui/react/src/emoji/index.tsx +++ b/packages/@luke-ui/react/src/emoji/emoji.tsx @@ -1,4 +1,4 @@ -import { Text } from '../text/index.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/emoji/index.ts b/packages/@luke-ui/react/src/emoji/index.ts new file mode 100644 index 00000000..4ceb9217 --- /dev/null +++ b/packages/@luke-ui/react/src/emoji/index.ts @@ -0,0 +1 @@ +export { Emoji, type EmojiProps } from './emoji.js'; diff --git a/packages/@luke-ui/react/src/heading/index.tsx b/packages/@luke-ui/react/src/heading/heading.tsx similarity index 88% rename from packages/@luke-ui/react/src/heading/index.tsx rename to packages/@luke-ui/react/src/heading/heading.tsx index 7d5455f1..9edb31d2 100644 --- a/packages/@luke-ui/react/src/heading/index.tsx +++ b/packages/@luke-ui/react/src/heading/heading.tsx @@ -1,14 +1,10 @@ -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { Prettify } from '../types/prettify.js'; import type { HeadingLevel, HeadingLevelsProps } from './heading-context.js'; import { HeadingLevels, HeadingPresenceProvider } from './heading-context.js'; -export type { - HeadingLevel, - HeadingLevelsProps, - HeadingLevelsRenderProps, -} from './heading-context.js'; +export type { HeadingLevel } from './heading-context.js'; export { HeadingLevels, useHeadingLevel } from './heading-context.js'; /** Valid heading tag name for Luke UI headings. */ export type HeadingTag = `h${HeadingLevel}`; diff --git a/packages/@luke-ui/react/src/heading/index.ts b/packages/@luke-ui/react/src/heading/index.ts new file mode 100644 index 00000000..71885e3a --- /dev/null +++ b/packages/@luke-ui/react/src/heading/index.ts @@ -0,0 +1,9 @@ +export { + Heading, + type HeadingLevel, + HeadingLevels, + type HeadingProps, + type HeadingTag, + useHeadingLevel, +} from './heading.js'; +export type { HeadingLevelsProps, HeadingLevelsRenderProps } from './heading-context.js'; diff --git a/packages/@luke-ui/react/src/icon-button/index.tsx b/packages/@luke-ui/react/src/icon-button/icon-button.tsx similarity index 84% rename from packages/@luke-ui/react/src/icon-button/index.tsx rename to packages/@luke-ui/react/src/icon-button/icon-button.tsx index c7f307ed..9a78d046 100644 --- a/packages/@luke-ui/react/src/icon-button/index.tsx +++ b/packages/@luke-ui/react/src/icon-button/icon-button.tsx @@ -1,15 +1,13 @@ -export { type IconButtonRecipeVariants, iconButtonRecipe } from './recipe.css.js'; - import type { JSX } from 'react'; import { composeRenderProps } from 'react-aria-components/composeRenderProps'; -import type { IconName } from '../icon/index.js'; -import { Icon } from '../icon/index.js'; -import type { ButtonProps as PrimitiveButtonProps } from '../primitives/button/index.js'; -import { Button } from '../primitives/button/index.js'; +import type { IconName } from '../icon/icon.js'; +import { Icon } from '../icon/icon.js'; +import type { ButtonProps as PrimitiveButtonProps } from '../primitives/button/button.js'; +import { Button } from '../primitives/button/button.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { DocumentedPressProps } from '../types/documented-rac-props.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import type { IconButtonRecipeVariants } from './recipe.css.js'; import { iconButtonIcon, iconButtonRecipe, iconButtonReset } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/icon-button/index.ts b/packages/@luke-ui/react/src/icon-button/index.ts new file mode 100644 index 00000000..d51997aa --- /dev/null +++ b/packages/@luke-ui/react/src/icon-button/index.ts @@ -0,0 +1,2 @@ +export { IconButton, type IconButtonProps } from './icon-button.js'; +export { type IconButtonRecipeVariants, iconButtonRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/icon-button/recipe.css.ts b/packages/@luke-ui/react/src/icon-button/recipe.css.ts index bf706d8a..0b4a4ca2 100644 --- a/packages/@luke-ui/react/src/icon-button/recipe.css.ts +++ b/packages/@luke-ui/react/src/icon-button/recipe.css.ts @@ -17,12 +17,12 @@ export const iconButtonReset = styleInLayer('recipes', { paddingInline: 0, selectors: { '&[data-pending="true"]::after': { + blockSize: vars.iconSize.xsmall, borderColor: 'currentColor', borderInlineEndColor: 'transparent', borderRadius: vars.radius.full, borderStyle: 'solid', borderWidth: '2px', - blockSize: vars.iconSize.xsmall, content: '', inlineSize: vars.iconSize.xsmall, position: 'absolute', diff --git a/packages/@luke-ui/react/src/icon/index.tsx b/packages/@luke-ui/react/src/icon/icon.tsx similarity index 97% rename from packages/@luke-ui/react/src/icon/index.tsx rename to packages/@luke-ui/react/src/icon/icon.tsx index 628e5307..6312515d 100644 --- a/packages/@luke-ui/react/src/icon/index.tsx +++ b/packages/@luke-ui/react/src/icon/icon.tsx @@ -1,12 +1,10 @@ -export { type IconRecipeVariants, iconRecipe } from './recipe.css.js'; - import type { JSX, ReactNode, SVGAttributes } from 'react'; import { createContext, useContext } from 'react'; import { iconNames, iconViewBoxes } from '../../.generated/icon-data.js'; import { ICON_VIEWBOX } from '../sizing/icon-sizing.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { useIconSizeContext } from './icon-size-context.js'; import type { IconRecipeVariants } from './recipe.css.js'; import { iconRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/icon/index.ts b/packages/@luke-ui/react/src/icon/index.ts new file mode 100644 index 00000000..2ffeb606 --- /dev/null +++ b/packages/@luke-ui/react/src/icon/index.ts @@ -0,0 +1,14 @@ +export { + type CreateIconOptions, + type CustomIconProps, + createIcon, + Icon, + type IconName, + type IconProps, + IconSizeProvider, + IconSpritesheetProvider, + type IconSpritesheetProviderProps, + iconNames, + iconViewBoxes, +} from './icon.js'; +export { type IconRecipeVariants, iconRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/kbd/index.ts b/packages/@luke-ui/react/src/kbd/index.ts new file mode 100644 index 00000000..f467185e --- /dev/null +++ b/packages/@luke-ui/react/src/kbd/index.ts @@ -0,0 +1,2 @@ +export { Kbd, type KbdProps } from './kbd.js'; +export { type KbdRecipeVariants, kbdRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/kbd/index.tsx b/packages/@luke-ui/react/src/kbd/kbd.tsx similarity index 84% rename from packages/@luke-ui/react/src/kbd/index.tsx rename to packages/@luke-ui/react/src/kbd/kbd.tsx index 2c11bbd0..13367f27 100644 --- a/packages/@luke-ui/react/src/kbd/index.tsx +++ b/packages/@luke-ui/react/src/kbd/kbd.tsx @@ -1,8 +1,6 @@ -export { type KbdRecipeVariants, kbdRecipe } from './recipe.css.js'; - import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { kbdRecipe } from './recipe.css.js'; type _KbdOmit = DistributiveOmit, never>; diff --git a/packages/@luke-ui/react/src/link/index.ts b/packages/@luke-ui/react/src/link/index.ts new file mode 100644 index 00000000..fd4b1850 --- /dev/null +++ b/packages/@luke-ui/react/src/link/index.ts @@ -0,0 +1,2 @@ +export { Link, type LinkProps } from './link.js'; +export { type LinkRecipeVariants, linkRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/link/index.tsx b/packages/@luke-ui/react/src/link/link.tsx similarity index 92% rename from packages/@luke-ui/react/src/link/index.tsx rename to packages/@luke-ui/react/src/link/link.tsx index fb67b4ea..b7da3642 100644 --- a/packages/@luke-ui/react/src/link/index.tsx +++ b/packages/@luke-ui/react/src/link/link.tsx @@ -1,5 +1,3 @@ -export { type LinkRecipeVariants, linkRecipe } from './recipe.css.js'; - import type { JSX } from 'react'; import type { LinkProps as RacLinkProps } from 'react-aria-components/Link'; import { Link as RacLink } from 'react-aria-components/Link'; @@ -7,7 +5,7 @@ import { composeRenderProps } from 'react-aria-components/composeRenderProps'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { DocumentedLinkProps } from '../types/documented-rac-props.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import type { LinkRecipeVariants } from './recipe.css.js'; import { linkRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/loading-skeleton/index.ts b/packages/@luke-ui/react/src/loading-skeleton/index.ts new file mode 100644 index 00000000..d117ff93 --- /dev/null +++ b/packages/@luke-ui/react/src/loading-skeleton/index.ts @@ -0,0 +1,6 @@ +export { + LoadingSkeleton, + type LoadingSkeletonProps, + LoadingSkeletonProvider, + type LoadingSkeletonProviderProps, +} from './loading-skeleton.js'; diff --git a/packages/@luke-ui/react/src/loading-skeleton/index.tsx b/packages/@luke-ui/react/src/loading-skeleton/loading-skeleton.tsx similarity index 98% rename from packages/@luke-ui/react/src/loading-skeleton/index.tsx rename to packages/@luke-ui/react/src/loading-skeleton/loading-skeleton.tsx index 3cd1209f..f677c2f0 100644 --- a/packages/@luke-ui/react/src/loading-skeleton/index.tsx +++ b/packages/@luke-ui/react/src/loading-skeleton/loading-skeleton.tsx @@ -3,7 +3,7 @@ import { createContext, isValidElement, useContext } from 'react'; import { vars } from '../theme/contract.css.js'; import type { Prettify } from '../types/prettify.js'; import { useSynchronizeAnimations } from '../use-synchronize-animations/use-synchronize-animations.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { loadingSkeletonClassName, skeletonAnimationName, diff --git a/packages/@luke-ui/react/src/loading-spinner/index.ts b/packages/@luke-ui/react/src/loading-spinner/index.ts new file mode 100644 index 00000000..a754ab79 --- /dev/null +++ b/packages/@luke-ui/react/src/loading-spinner/index.ts @@ -0,0 +1,2 @@ +export { LoadingSpinner, type LoadingSpinnerProps } from './loading-spinner.js'; +export { type LoadingSpinnerRecipeVariants, loadingSpinnerRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/loading-spinner/index.tsx b/packages/@luke-ui/react/src/loading-spinner/loading-spinner.tsx similarity index 95% rename from packages/@luke-ui/react/src/loading-spinner/index.tsx rename to packages/@luke-ui/react/src/loading-spinner/loading-spinner.tsx index a15761a1..d984b399 100644 --- a/packages/@luke-ui/react/src/loading-spinner/index.tsx +++ b/packages/@luke-ui/react/src/loading-spinner/loading-spinner.tsx @@ -1,5 +1,3 @@ -export { type LoadingSpinnerRecipeVariants, loadingSpinnerRecipe } from './recipe.css.js'; - import type { ComponentProps, ReactNode } from 'react'; import { useId } from 'react'; import { useIconSizeContext } from '../icon/icon-size-context.js'; @@ -12,7 +10,7 @@ import { import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; import { useSynchronizeAnimations } from '../use-synchronize-animations/use-synchronize-animations.js'; -import { VisuallyHidden } from '../visually-hidden/index.js'; +import { VisuallyHidden } from '../visually-hidden/visually-hidden.js'; import type { LoadingSpinnerRecipeVariants } from './recipe.css.js'; import { loadingSpinnerRecipe, rubberBandAnimationName, spinAnimationName } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/loading-spinner/recipe.css.ts b/packages/@luke-ui/react/src/loading-spinner/recipe.css.ts index 47c33bd0..6a82ab24 100644 --- a/packages/@luke-ui/react/src/loading-spinner/recipe.css.ts +++ b/packages/@luke-ui/react/src/loading-spinner/recipe.css.ts @@ -33,25 +33,19 @@ export const rubberBandAnimationName = keyframes({ * `hiddenChildren`, and `spinnerOverlay`. */ const loadingSpinnerConfig = { + defaultVariants: { + size: 'medium', + }, slots: { - root: { - '@media': { - '(forced-colors: active)': { animationName: 'none' }, - '(prefers-reduced-motion: reduce)': { animationName: 'none' }, - }, - animationDuration: rotationDuration, - animationIterationCount: 'infinite', - animationName: spinAnimationName, - animationTimingFunction: 'linear', - color: 'currentColor', + childrenWrapper: { + alignItems: 'center', display: 'inline-flex', - flexShrink: 0, + justifyContent: 'center', + position: 'relative', }, - svg: { - blockSize: '100%', - display: 'block', - inlineSize: '100%', - transform: 'rotate(-90deg)', + hiddenChildren: { + display: 'contents', + visibility: 'hidden', }, indicator: { '@media': { @@ -72,20 +66,26 @@ const loadingSpinnerConfig = { animationTimingFunction: rubberBandEasing, strokeDasharray: '100 100', }, - childrenWrapper: { - alignItems: 'center', + root: { + animationDuration: rotationDuration, + animationIterationCount: 'infinite', + animationName: spinAnimationName, + animationTimingFunction: 'linear', + color: 'currentColor', display: 'inline-flex', - justifyContent: 'center', - position: 'relative', - }, - hiddenChildren: { - display: 'contents', - visibility: 'hidden', + flexShrink: 0, + '@media': { + '(forced-colors: active)': { animationName: 'none' }, + '(prefers-reduced-motion: reduce)': { animationName: 'none' }, + }, }, spinnerOverlay: spinnerOverlayBase, - }, - defaultVariants: { - size: 'medium', + svg: { + blockSize: '100%', + display: 'block', + inlineSize: '100%', + transform: 'rotate(-90deg)', + }, }, variants: { color: { diff --git a/packages/@luke-ui/react/src/numeral/index.ts b/packages/@luke-ui/react/src/numeral/index.ts new file mode 100644 index 00000000..25a589f3 --- /dev/null +++ b/packages/@luke-ui/react/src/numeral/index.ts @@ -0,0 +1,7 @@ +export { + Numeral, + type NumeralAbbreviation, + type NumeralFormat, + type NumeralPrecision, + type NumeralProps, +} from './numeral.js'; diff --git a/packages/@luke-ui/react/src/numeral/index.tsx b/packages/@luke-ui/react/src/numeral/numeral.tsx similarity index 98% rename from packages/@luke-ui/react/src/numeral/index.tsx rename to packages/@luke-ui/react/src/numeral/numeral.tsx index 5505be0b..7c9daaa7 100644 --- a/packages/@luke-ui/react/src/numeral/index.tsx +++ b/packages/@luke-ui/react/src/numeral/numeral.tsx @@ -1,7 +1,7 @@ import { useLocale } from 'react-aria-components/I18nProvider'; import { useIsWithinHeading } from '../heading/heading-context.js'; -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/numeral/numeral.visual.test.tsx b/packages/@luke-ui/react/src/numeral/numeral.visual.test.tsx index bb967c54..3eda5620 100644 --- a/packages/@luke-ui/react/src/numeral/numeral.visual.test.tsx +++ b/packages/@luke-ui/react/src/numeral/numeral.visual.test.tsx @@ -27,8 +27,8 @@ for (const appearance of visualAppearances) { diff --git a/packages/@luke-ui/react/src/overlays/mobile-overlay.tsx b/packages/@luke-ui/react/src/overlays/mobile-overlay.tsx index 4da968ec..8de1967f 100644 --- a/packages/@luke-ui/react/src/overlays/mobile-overlay.tsx +++ b/packages/@luke-ui/react/src/overlays/mobile-overlay.tsx @@ -2,8 +2,8 @@ import type { JSX, ReactNode, Ref } from 'react'; import type { DialogProps } from 'react-aria-components/Dialog'; import { Dialog, OverlayTriggerStateContext } from 'react-aria-components/Dialog'; import { Modal, ModalOverlay } from 'react-aria-components/Modal'; -import { rootClassName } from '../theme/index.js'; -import { cx } from '../utils/index.js'; +import { rootClassName } from '../theme/theme.js'; +import { cx } from '../utils/utils.js'; import { mobileDialog, mobileModal, mobileOverlay } from './mobile-overlay.css.js'; interface MobileOverlayProps { diff --git a/packages/@luke-ui/react/src/primitives/button/index.tsx b/packages/@luke-ui/react/src/primitives/button/button.tsx similarity index 94% rename from packages/@luke-ui/react/src/primitives/button/index.tsx rename to packages/@luke-ui/react/src/primitives/button/button.tsx index 5106bb92..8a26ce62 100644 --- a/packages/@luke-ui/react/src/primitives/button/index.tsx +++ b/packages/@luke-ui/react/src/primitives/button/button.tsx @@ -1,5 +1,3 @@ -export { type ButtonRecipeVariants, buttonRecipe } from './recipe.css.js'; - import type { JSX } from 'react'; import type { ButtonProps as RacButtonProps } from 'react-aria-components/Button'; import { Button as RacButton } from 'react-aria-components/Button'; @@ -7,7 +5,7 @@ import { composeRenderProps } from 'react-aria-components/composeRenderProps'; import { IconSizeProvider } from '../../icon/icon-size-context.js'; import { BUTTON_ICON_SIZE } from '../../sizing/button-sizing.js'; import type { Prettify } from '../../types/prettify.js'; -import { cx } from '../../utils/index.js'; +import { cx } from '../../utils/utils.js'; import type { ButtonRecipeVariants } from './recipe.css.js'; import { buttonRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/primitives/button/index.ts b/packages/@luke-ui/react/src/primitives/button/index.ts new file mode 100644 index 00000000..fcc5457f --- /dev/null +++ b/packages/@luke-ui/react/src/primitives/button/index.ts @@ -0,0 +1,2 @@ +export { Button, type ButtonProps } from './button.js'; +export { type ButtonRecipeVariants, buttonRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/primitives/checkbox/index.tsx b/packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx similarity index 98% rename from packages/@luke-ui/react/src/primitives/checkbox/index.tsx rename to packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx index 6fe957d4..260b39be 100644 --- a/packages/@luke-ui/react/src/primitives/checkbox/index.tsx +++ b/packages/@luke-ui/react/src/primitives/checkbox/checkbox.tsx @@ -1,5 +1,3 @@ -export { type CheckboxRecipeVariants, checkboxRecipe } from './recipe.css.js'; - import type { ComponentProps, JSX } from 'react'; import type { CheckboxButtonProps as RacCheckboxButtonProps, diff --git a/packages/@luke-ui/react/src/primitives/checkbox/index.ts b/packages/@luke-ui/react/src/primitives/checkbox/index.ts new file mode 100644 index 00000000..ede3d0a0 --- /dev/null +++ b/packages/@luke-ui/react/src/primitives/checkbox/index.ts @@ -0,0 +1,11 @@ +export { + Checkbox, + CheckboxContent, + type CheckboxContentProps, + CheckboxControl, + type CheckboxControlProps, + CheckboxIndicator, + type CheckboxIndicatorProps, + type CheckboxProps, +} from './checkbox.js'; +export { type CheckboxRecipeVariants, checkboxRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/primitives/combobox/index.tsx b/packages/@luke-ui/react/src/primitives/combobox/index.ts similarity index 100% rename from packages/@luke-ui/react/src/primitives/combobox/index.tsx rename to packages/@luke-ui/react/src/primitives/combobox/index.ts diff --git a/packages/@luke-ui/react/src/primitives/combobox/item.tsx b/packages/@luke-ui/react/src/primitives/combobox/item.tsx index 1cfa581a..6eb0e73a 100644 --- a/packages/@luke-ui/react/src/primitives/combobox/item.tsx +++ b/packages/@luke-ui/react/src/primitives/combobox/item.tsx @@ -9,7 +9,7 @@ import { } from 'react-aria-components/ComboBox'; import { composeRenderProps } from 'react-aria-components/composeRenderProps'; import { IconSizeProvider } from '../../icon/icon-size-context.js'; -import { Icon } from '../../icon/index.js'; +import { Icon } from '../../icon/icon.js'; import { COMBOBOX_CHECK_ICON_SIZE, COMBOBOX_ICON_SIZE } from '../../sizing/combobox-sizing.js'; import type { DistributiveOmit } from '../../types/distributive-omit.js'; import type { Prettify } from '../../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/primitives/combobox/popover.tsx b/packages/@luke-ui/react/src/primitives/combobox/popover.tsx index 8f41ff54..5c9712f3 100644 --- a/packages/@luke-ui/react/src/primitives/combobox/popover.tsx +++ b/packages/@luke-ui/react/src/primitives/combobox/popover.tsx @@ -2,10 +2,10 @@ import type { JSX, Ref } from 'react'; import type { PopoverProps as RacPopoverProps } from 'react-aria-components/ComboBox'; import { Popover as RacPopover } from 'react-aria-components/ComboBox'; import { composeRenderProps } from 'react-aria-components/composeRenderProps'; -import { rootClassName } from '../../theme/index.js'; +import { rootClassName } from '../../theme/theme.js'; import type { DistributiveOmit } from '../../types/distributive-omit.js'; import type { Prettify } from '../../types/prettify.js'; -import { cx } from '../../utils/index.js'; +import { cx } from '../../utils/utils.js'; import { comboboxRecipe } from './styles.css.js'; type _ComboboxPopoverOmit = DistributiveOmit; diff --git a/packages/@luke-ui/react/src/primitives/field/index.tsx b/packages/@luke-ui/react/src/primitives/field/field.tsx similarity index 95% rename from packages/@luke-ui/react/src/primitives/field/index.tsx rename to packages/@luke-ui/react/src/primitives/field/field.tsx index 14d880d8..6c400d4c 100644 --- a/packages/@luke-ui/react/src/primitives/field/index.tsx +++ b/packages/@luke-ui/react/src/primitives/field/field.tsx @@ -1,4 +1,3 @@ -export { fieldRecipe, type FieldRecipeVariants } from './recipe.css.js'; import type { ComponentProps, JSX, ReactNode } from 'react'; import type { FieldSlotProps } from '../../field/compose-field.js'; import type { DistributiveOmit } from '../../types/distributive-omit.js'; diff --git a/packages/@luke-ui/react/src/primitives/field/index.ts b/packages/@luke-ui/react/src/primitives/field/index.ts new file mode 100644 index 00000000..9fd8ac64 --- /dev/null +++ b/packages/@luke-ui/react/src/primitives/field/index.ts @@ -0,0 +1,12 @@ +export { + Field, + FieldDescription, + type FieldDescriptionProps, + FieldError, + type FieldErrorProps, + FieldLabel, + type FieldLabelProps, + type FieldNecessityIndicator, + type FieldProps, +} from './field.js'; +export { type FieldRecipeVariants, fieldRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/primitives/input-group/index.ts b/packages/@luke-ui/react/src/primitives/input-group/index.ts new file mode 100644 index 00000000..3e9d7a59 --- /dev/null +++ b/packages/@luke-ui/react/src/primitives/input-group/index.ts @@ -0,0 +1,15 @@ +export { + InputGroup, + InputGroupInput, + type InputGroupInputProps, + InputGroupPrefix, + type InputGroupPrefixProps, + type InputGroupProps, + InputGroupSuffix, + type InputGroupSuffixProps, +} from './input-group.js'; +export { + type InputGroupRecipeVariants, + type InputGroupSize, + inputGroupRecipe, +} from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/primitives/input-group/index.tsx b/packages/@luke-ui/react/src/primitives/input-group/input-group.tsx similarity index 97% rename from packages/@luke-ui/react/src/primitives/input-group/index.tsx rename to packages/@luke-ui/react/src/primitives/input-group/input-group.tsx index 1b34f949..4bc48117 100644 --- a/packages/@luke-ui/react/src/primitives/input-group/index.tsx +++ b/packages/@luke-ui/react/src/primitives/input-group/input-group.tsx @@ -1,9 +1,3 @@ -export { - type InputGroupRecipeVariants, - type InputGroupSize, - inputGroupRecipe, -} from './recipe.css.js'; - import type { ComponentProps, JSX, Ref } from 'react'; import { createContext, use } from 'react'; import type { GroupProps as RacGroupProps } from 'react-aria-components/Group'; @@ -12,7 +6,7 @@ import type { InputProps as RacInputProps } from 'react-aria-components/Input'; import { Input as RacInput } from 'react-aria-components/Input'; import { composeRenderProps } from 'react-aria-components/composeRenderProps'; import { IconSizeProvider } from '../../icon/icon-size-context.js'; -import { Icon } from '../../icon/index.js'; +import { Icon } from '../../icon/icon.js'; import { INPUT_GROUP_ICON_SIZE } from '../../sizing/input-group-sizing.js'; import type { DistributiveOmit } from '../../types/distributive-omit.js'; import type { Prettify } from '../../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/quote/index.ts b/packages/@luke-ui/react/src/quote/index.ts new file mode 100644 index 00000000..99f84939 --- /dev/null +++ b/packages/@luke-ui/react/src/quote/index.ts @@ -0,0 +1 @@ +export { Quote, type QuoteProps } from './quote.js'; diff --git a/packages/@luke-ui/react/src/quote/index.tsx b/packages/@luke-ui/react/src/quote/quote.tsx similarity index 91% rename from packages/@luke-ui/react/src/quote/index.tsx rename to packages/@luke-ui/react/src/quote/quote.tsx index 0ef5883a..e00f579d 100644 --- a/packages/@luke-ui/react/src/quote/index.tsx +++ b/packages/@luke-ui/react/src/quote/quote.tsx @@ -1,5 +1,5 @@ -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/strong/index.ts b/packages/@luke-ui/react/src/strong/index.ts new file mode 100644 index 00000000..fa0dee63 --- /dev/null +++ b/packages/@luke-ui/react/src/strong/index.ts @@ -0,0 +1 @@ +export { Strong, type StrongProps } from './strong.js'; diff --git a/packages/@luke-ui/react/src/strong/index.tsx b/packages/@luke-ui/react/src/strong/strong.tsx similarity index 89% rename from packages/@luke-ui/react/src/strong/index.tsx rename to packages/@luke-ui/react/src/strong/strong.tsx index c29e99ee..0381f6c7 100644 --- a/packages/@luke-ui/react/src/strong/index.tsx +++ b/packages/@luke-ui/react/src/strong/strong.tsx @@ -1,8 +1,8 @@ -import type { TextProps } from '../text/index.js'; -import { Text } from '../text/index.js'; +import type { TextProps } from '../text/text.js'; +import { Text } from '../text/text.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { strong } from './styles.css.js'; interface StrongStyleProps { diff --git a/packages/@luke-ui/react/src/styles/recipe.ts b/packages/@luke-ui/react/src/styles/recipe.ts index 3dafa4d6..1745d566 100644 --- a/packages/@luke-ui/react/src/styles/recipe.ts +++ b/packages/@luke-ui/react/src/styles/recipe.ts @@ -2,7 +2,7 @@ import type { StyleRule } from '@vanilla-extract/css'; import { addFunctionSerializer } from '@vanilla-extract/css/functionSerializer'; import { recipe as vanillaRecipe } from '@vanilla-extract/recipes'; import type { DistributiveOmit } from '../types/distributive-omit.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; /** * `recipe()` styling helper for Vanilla Extract. diff --git a/packages/@luke-ui/react/src/text-field/index.ts b/packages/@luke-ui/react/src/text-field/index.ts new file mode 100644 index 00000000..80e7dede --- /dev/null +++ b/packages/@luke-ui/react/src/text-field/index.ts @@ -0,0 +1 @@ +export { TextField, type TextFieldProps } from './text-field.js'; diff --git a/packages/@luke-ui/react/src/text-field/index.tsx b/packages/@luke-ui/react/src/text-field/text-field.tsx similarity index 92% rename from packages/@luke-ui/react/src/text-field/index.tsx rename to packages/@luke-ui/react/src/text-field/text-field.tsx index a695dc86..6e92a926 100644 --- a/packages/@luke-ui/react/src/text-field/index.tsx +++ b/packages/@luke-ui/react/src/text-field/text-field.tsx @@ -6,14 +6,14 @@ import type { import { TextField as RacTextField } from 'react-aria-components/TextField'; import type { FieldSlotProps } from '../field/compose-field.js'; import { composeField } from '../field/compose-field.js'; -import { Field } from '../primitives/field/index.js'; -import type { InputGroupSize } from '../primitives/input-group/index.js'; +import { Field } from '../primitives/field/field.js'; import { InputGroup, InputGroupInput, InputGroupPrefix, InputGroupSuffix, -} from '../primitives/input-group/index.js'; +} from '../primitives/input-group/input-group.js'; +import type { InputGroupSize } from '../primitives/input-group/recipe.css.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { DocumentedInputProps } from '../types/documented-rac-props.js'; import type { Prettify } from '../types/prettify.js'; diff --git a/packages/@luke-ui/react/src/text/index.ts b/packages/@luke-ui/react/src/text/index.ts new file mode 100644 index 00000000..108b0153 --- /dev/null +++ b/packages/@luke-ui/react/src/text/index.ts @@ -0,0 +1,2 @@ +export { type TextRecipeVariants, textRecipe } from './recipe.css.js'; +export { Text, type TextProps } from './text.js'; diff --git a/packages/@luke-ui/react/src/text/index.tsx b/packages/@luke-ui/react/src/text/text.tsx similarity index 97% rename from packages/@luke-ui/react/src/text/index.tsx rename to packages/@luke-ui/react/src/text/text.tsx index 62be8e2f..1b92b00f 100644 --- a/packages/@luke-ui/react/src/text/index.tsx +++ b/packages/@luke-ui/react/src/text/text.tsx @@ -1,10 +1,8 @@ -export { type TextRecipeVariants, textRecipe } from './recipe.css.js'; - import { Text as RacText } from 'react-aria-components/Text'; import { typeStyleWeightRole } from '../theme/contract.js'; import type { DistributiveOmit } from '../types/distributive-omit.js'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import type { TextRecipeVariants } from './recipe.css.js'; import { textRecipe } from './recipe.css.js'; diff --git a/packages/@luke-ui/react/src/theme/index.ts b/packages/@luke-ui/react/src/theme/index.ts new file mode 100644 index 00000000..b2087744 --- /dev/null +++ b/packages/@luke-ui/react/src/theme/index.ts @@ -0,0 +1,16 @@ +export { ThemeContrastError, ThemeGenerationError } from './build-theme.js'; +export type { ThemeContrastFailure, ThemeInheritance } from './build-theme.js'; +export { vars } from './contract.css.js'; +export { spaceScale, typeStyles } from './contract.js'; +export type { FontWeightRole, SpaceStep, TypeStyle } from './contract.js'; +export { defaultControlFinish, defaultDepth, defaultScrim, defineTheme } from './define-theme.js'; +export type { + ColorInput, + ControlFinish, + DepthLadder, + ExtendingThemeInput, + ThemeInput, +} from './define-theme.js'; +export { deriveConcentricRadius, deriveNestedRadius } from './foundation.js'; +export { getThemeClassName } from './theme-class-name.js'; +export { rootClassName } from './theme.js'; diff --git a/packages/@luke-ui/react/src/theme/index.tsx b/packages/@luke-ui/react/src/theme/index.tsx deleted file mode 100644 index b05c9eb4..00000000 --- a/packages/@luke-ui/react/src/theme/index.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { lukeUiClassNames } from '../styles/class-names.js'; -import { cx } from '../utils/index.js'; - -/** - * Applies the descendant CSS reset and the base Luke UI typography and theme layer. It carries no - * theme identity of its own. Apply it to ``, `
`, an app shell, or any element you - * already own. - */ -export const rootClassName = cx(lukeUiClassNames.themeRoot, lukeUiClassNames.resetRoot); - -/** - * Typed access to the semantic theme custom properties. Each path resolves to a stable global - * `--luke-*` variable reference, for example `vars.color.background.danger.solid.hover`. - */ -export { vars } from './contract.css.js'; - -/** The fixed spacing steps shared by the built-in themes. */ -export { spaceScale } from './contract.js'; -export type { SpaceStep } from './contract.js'; - -/** Public semantic type style keys in ascending visual size. */ -export { typeStyles } from './contract.js'; - -/** A public semantic type style key. */ -export type { TypeStyle } from './contract.js'; - -/** Theme font-weight role keys used by typography defaults and weight overrides. */ -export type { FontWeightRole } from './contract.js'; - -/** - * `ThemeContrastError` is thrown by `defineTheme` when a hard-gated pair misses WCAG 2.2 AA: 4.5:1 - * for text/on-solid pairs, 3:1 for the focus ring and `border.control`. The six semantic - * `border.` pairs are measured but advisory only and cannot trigger this error. It carries - * every failing mode-and-pair in its `failures` array. For a theme built with `extends`, it also - * carries `inheritance`, naming the chain of themes and which colours came from a base. - * `ThemeGenerationError` is thrown when a role that must guarantee on-solid contrast (an - * inaccessible explicit per-mode accent, for example) cannot reach an accessible solid. It names the - * failing `role` and `mode`. - */ -export { ThemeContrastError, ThemeGenerationError } from './build-theme.js'; - -/** One WCAG contrast failure recorded on a {@link ThemeContrastError}. */ -export type { ThemeContrastFailure } from './build-theme.js'; - -/** The colour provenance a `ThemeContrastError` carries for a theme built with `extends`. */ -export type { ThemeInheritance } from './build-theme.js'; - -/** - * `defineTheme(input)` is the curated authoring entry point: it normalises a small {@link ThemeInput} - * (accent + neutral character, with everything else defaulting) into the per-mode foundation and - * compiles it through `buildTheme`. It adapts single-value accents and neutrals per mode, generates - * the radius scale, and merges optional materials over curated defaults. It also accepts an - * {@link ExtendingThemeInput} and resolves its `extends` chain first. It throws the same - * {@link ThemeContrastError} and {@link ThemeGenerationError} as `buildTheme`. - */ -export { defineTheme } from './define-theme.js'; - -/** The curated `defineTheme` authoring input plus its colour and material building blocks. */ -export type { - ColorInput, - ControlFinish, - DepthLadder, - ExtendingThemeInput, - ThemeInput, -} from './define-theme.js'; - -/** Curated defaults `defineTheme` applies for omitted materials and scrim. */ -export { defaultControlFinish, defaultDepth, defaultScrim } from './define-theme.js'; - -/** - * `getThemeClassName(name)` returns a theme's identity class, `luke-ui-theme-${name}`. Pass the same - * `name` the theme's {@link ThemeInput} declares. Apply the result to the theme root when one - * document loads more than one theme stylesheet, so the explicit identity outranks another theme's - * `:root` fallback. It throws when the name is not the kebab-case `defineTheme` requires. - */ -export { getThemeClassName } from './theme-class-name.js'; - -/** Derives a concentric outer corner from an inner radius plus the intervening gap. */ -export { deriveConcentricRadius } from './foundation.js'; - -/** Derives a concentric inner corner from an outer radius plus the intervening gap. */ -export { deriveNestedRadius } from './foundation.js'; diff --git a/packages/@luke-ui/react/src/theme/theme.ts b/packages/@luke-ui/react/src/theme/theme.ts new file mode 100644 index 00000000..0177dead --- /dev/null +++ b/packages/@luke-ui/react/src/theme/theme.ts @@ -0,0 +1,9 @@ +import { lukeUiClassNames } from '../styles/class-names.js'; +import { cx } from '../utils/utils.js'; + +/** + * Applies the descendant CSS reset and the base Luke UI typography and theme layer. It carries no + * theme identity of its own. Apply it to ``, `
`, an app shell, or any element you + * already own. + */ +export const rootClassName = cx(lukeUiClassNames.themeRoot, lukeUiClassNames.resetRoot); diff --git a/packages/@luke-ui/react/src/themes/paper/index.ts b/packages/@luke-ui/react/src/themes/paper/index.ts index fe570bcc..1f8bf36b 100644 --- a/packages/@luke-ui/react/src/themes/paper/index.ts +++ b/packages/@luke-ui/react/src/themes/paper/index.ts @@ -1,10 +1,2 @@ -import type { ThemeInput } from '../../theme/define-theme.js'; -import { paperTheme } from '../../theme/foundations/paper.js'; - +export { theme } from './theme.js'; export { themeClassName } from './theme-class-name.js'; - -/** - * Paper's `defineTheme` input, the materially minimal bundled theme: a flat, hairline-bordered - * look with a blue accent. Set it as `extends` on your own input to start from Paper. - */ -export const theme: ThemeInput = paperTheme; diff --git a/packages/@luke-ui/react/src/themes/paper/theme.ts b/packages/@luke-ui/react/src/themes/paper/theme.ts new file mode 100644 index 00000000..20b2a2a6 --- /dev/null +++ b/packages/@luke-ui/react/src/themes/paper/theme.ts @@ -0,0 +1,8 @@ +import type { ThemeInput } from '../../theme/define-theme.js'; +import { paperTheme } from '../../theme/foundations/paper.js'; + +/** + * Paper's `defineTheme` input, the materially minimal bundled theme: a flat, hairline-bordered + * look with a blue accent. Set it as `extends` on your own input to start from Paper. + */ +export const theme: ThemeInput = paperTheme; diff --git a/packages/@luke-ui/react/src/themes/tactile/index.ts b/packages/@luke-ui/react/src/themes/tactile/index.ts index a3c18ddf..1f8bf36b 100644 --- a/packages/@luke-ui/react/src/themes/tactile/index.ts +++ b/packages/@luke-ui/react/src/themes/tactile/index.ts @@ -1,11 +1,2 @@ -import type { ThemeInput } from '../../theme/define-theme.js'; -import { tactileTheme } from '../../theme/foundations/tactile.js'; - +export { theme } from './theme.js'; export { themeClassName } from './theme-class-name.js'; - -/** - * Tactile's `defineTheme` input, the Luke UI default: a teal accent, a neutral near-white light - * canvas, and a compact tactile material. Set it as `extends` on your own input to start from - * Tactile. - */ -export const theme: ThemeInput = tactileTheme; diff --git a/packages/@luke-ui/react/src/themes/tactile/theme.ts b/packages/@luke-ui/react/src/themes/tactile/theme.ts new file mode 100644 index 00000000..74a4bbaf --- /dev/null +++ b/packages/@luke-ui/react/src/themes/tactile/theme.ts @@ -0,0 +1,9 @@ +import type { ThemeInput } from '../../theme/define-theme.js'; +import { tactileTheme } from '../../theme/foundations/tactile.js'; + +/** + * Tactile's `defineTheme` input, the Luke UI default: a teal accent, a neutral near-white light + * canvas, and a compact tactile material. Set it as `extends` on your own input to start from + * Tactile. + */ +export const theme: ThemeInput = tactileTheme; diff --git a/packages/@luke-ui/react/src/utils/index.ts b/packages/@luke-ui/react/src/utils/index.ts index bb45b988..6ffde591 100644 --- a/packages/@luke-ui/react/src/utils/index.ts +++ b/packages/@luke-ui/react/src/utils/index.ts @@ -1,103 +1,9 @@ -/** - * Joins a space-separated token list, such as class names or an `aria-labelledby` ID list, and - * skips empty values. - */ -export function cx(...parts: Array): string { - let result = ''; - for (const part of parts) { - if (part) { - result = result ? `${result} ${part.trim()}` : part.trim(); - } - } - return result; -} - -type Merged = { - [K in keyof A | keyof B]: K extends 'className' - ? string - : K extends 'style' - ? Record - : K extends keyof B - ? B[K] - : K extends keyof A - ? A[K] - : never; -}; - -type MergeableProps = { - className?: unknown; - style?: unknown; -}; - -/** - * Merges two prop objects, concatenating `className` with `cx` and shallowly - * merging `style` objects (later props win). All other properties are overwritten - * by the later object. Useful for combining component props with `createSprinkles()` output. - */ -export function mergeProps(a: A, b: B): Merged { - const result = { ...a } as Record; - const aProps = a as MergeableProps; - const bProps = b as MergeableProps; - - result.className = cx( - typeof aProps.className === 'string' && aProps.className, - typeof bProps.className === 'string' && bProps.className, - ); - result.style = { - ...(typeof aProps.style === 'object' && aProps.style !== null ? aProps.style : {}), - ...(typeof bProps.style === 'object' && bProps.style !== null ? bProps.style : {}), - }; - - for (const key in b) { - if (key !== 'className' && key !== 'style') { - result[key] = b[key as keyof B]; - } - } - - return result as Merged; -} - -/** Converts a pixel value to rem. */ -export function pxToRem(px: number, base: number = 16): string { - return `${px / base}rem`; -} - -/** Typed key-value pair from an object. */ -export type ObjectEntry = { [K in keyof T]-?: [K, T[K]] }[keyof T]; - -/** - * An alternative to `Object.entries()` that avoids type widening. - * - * @example - * Object.entries({ foo: 1, bar: 2 }) // [string, number][] - * typedEntries({ foo: 1, bar: 2 }) // ["foo" | "bar", number][] - */ -export function typedEntries(value: T) { - return Object.entries(value) as Array>; -} - -/** - * An alternative to `Object.keys()` that avoids type widening. - * - * @example - * Object.keys({ foo: 1, bar: 2 }) // string[] - * typedKeys({ foo: 1, bar: 2 }) // ("foo" | "bar")[] - */ -export function typedKeys(value: T) { - return Object.keys(value) as Array; -} - -/** - * An alternative to `Object.fromEntries()` that avoids type widening. Must be - * used in conjunction with `typedEntries` or `typedKeys`. - * - * @example - * const obj = { name: 'Alice', age: 30 }; - * const rebuilt1 = Object.fromEntries(Object.entries(obj)); - * // ^? { [k: string]: string | number } - * const rebuilt2 = typedFromEntries(typedEntries(obj)); - * // ^? { name: string, age: number } - */ -export function typedFromEntries(entries: Array>) { - return Object.fromEntries(entries) as T; -} +export { + cx, + mergeProps, + type ObjectEntry, + pxToRem, + typedEntries, + typedFromEntries, + typedKeys, +} from './utils.js'; diff --git a/packages/@luke-ui/react/src/utils/utils.ts b/packages/@luke-ui/react/src/utils/utils.ts new file mode 100644 index 00000000..bb45b988 --- /dev/null +++ b/packages/@luke-ui/react/src/utils/utils.ts @@ -0,0 +1,103 @@ +/** + * Joins a space-separated token list, such as class names or an `aria-labelledby` ID list, and + * skips empty values. + */ +export function cx(...parts: Array): string { + let result = ''; + for (const part of parts) { + if (part) { + result = result ? `${result} ${part.trim()}` : part.trim(); + } + } + return result; +} + +type Merged = { + [K in keyof A | keyof B]: K extends 'className' + ? string + : K extends 'style' + ? Record + : K extends keyof B + ? B[K] + : K extends keyof A + ? A[K] + : never; +}; + +type MergeableProps = { + className?: unknown; + style?: unknown; +}; + +/** + * Merges two prop objects, concatenating `className` with `cx` and shallowly + * merging `style` objects (later props win). All other properties are overwritten + * by the later object. Useful for combining component props with `createSprinkles()` output. + */ +export function mergeProps(a: A, b: B): Merged { + const result = { ...a } as Record; + const aProps = a as MergeableProps; + const bProps = b as MergeableProps; + + result.className = cx( + typeof aProps.className === 'string' && aProps.className, + typeof bProps.className === 'string' && bProps.className, + ); + result.style = { + ...(typeof aProps.style === 'object' && aProps.style !== null ? aProps.style : {}), + ...(typeof bProps.style === 'object' && bProps.style !== null ? bProps.style : {}), + }; + + for (const key in b) { + if (key !== 'className' && key !== 'style') { + result[key] = b[key as keyof B]; + } + } + + return result as Merged; +} + +/** Converts a pixel value to rem. */ +export function pxToRem(px: number, base: number = 16): string { + return `${px / base}rem`; +} + +/** Typed key-value pair from an object. */ +export type ObjectEntry = { [K in keyof T]-?: [K, T[K]] }[keyof T]; + +/** + * An alternative to `Object.entries()` that avoids type widening. + * + * @example + * Object.entries({ foo: 1, bar: 2 }) // [string, number][] + * typedEntries({ foo: 1, bar: 2 }) // ["foo" | "bar", number][] + */ +export function typedEntries(value: T) { + return Object.entries(value) as Array>; +} + +/** + * An alternative to `Object.keys()` that avoids type widening. + * + * @example + * Object.keys({ foo: 1, bar: 2 }) // string[] + * typedKeys({ foo: 1, bar: 2 }) // ("foo" | "bar")[] + */ +export function typedKeys(value: T) { + return Object.keys(value) as Array; +} + +/** + * An alternative to `Object.fromEntries()` that avoids type widening. Must be + * used in conjunction with `typedEntries` or `typedKeys`. + * + * @example + * const obj = { name: 'Alice', age: 30 }; + * const rebuilt1 = Object.fromEntries(Object.entries(obj)); + * // ^? { [k: string]: string | number } + * const rebuilt2 = typedFromEntries(typedEntries(obj)); + * // ^? { name: string, age: number } + */ +export function typedFromEntries(entries: Array>) { + return Object.fromEntries(entries) as T; +} diff --git a/packages/@luke-ui/react/src/visually-hidden/index.ts b/packages/@luke-ui/react/src/visually-hidden/index.ts new file mode 100644 index 00000000..6a6b9b60 --- /dev/null +++ b/packages/@luke-ui/react/src/visually-hidden/index.ts @@ -0,0 +1,2 @@ +export { visuallyHiddenRecipe } from './recipe.css.js'; +export { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden.js'; diff --git a/packages/@luke-ui/react/src/visually-hidden/index.tsx b/packages/@luke-ui/react/src/visually-hidden/visually-hidden.tsx similarity index 92% rename from packages/@luke-ui/react/src/visually-hidden/index.tsx rename to packages/@luke-ui/react/src/visually-hidden/visually-hidden.tsx index 46cb3d4c..7b227a45 100644 --- a/packages/@luke-ui/react/src/visually-hidden/index.tsx +++ b/packages/@luke-ui/react/src/visually-hidden/visually-hidden.tsx @@ -1,8 +1,7 @@ -export { visuallyHiddenRecipe } from './recipe.css.js'; import type { ComponentPropsWithRef, JSX } from 'react'; import { Text as RacText } from 'react-aria-components/Text'; import type { Prettify } from '../types/prettify.js'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { visuallyHiddenRecipe } from './recipe.css.js'; type _VisuallyHiddenProps = ComponentPropsWithRef; diff --git a/packages/@luke-ui/react/vite.config.ts b/packages/@luke-ui/react/vite.config.ts index a9062e7d..d073da50 100644 --- a/packages/@luke-ui/react/vite.config.ts +++ b/packages/@luke-ui/react/vite.config.ts @@ -58,8 +58,8 @@ export default defineConfig({ dts: true, entry: { stylesheet: 'src/stylesheet.css.ts', - '*': ['src/*/index.tsx', 'src/*/index.ts'], - 'primitives/*': ['src/primitives/*/index.tsx', 'src/primitives/*/index.ts'], + '*': ['src/*/index.ts'], + 'primitives/*': ['src/primitives/*/index.ts'], 'themes/*': ['src/themes/*/index.ts'], }, exports: { diff --git a/packages/turbo-generators/README.md b/packages/turbo-generators/README.md index 27a8fbd1..a9549b7a 100644 --- a/packages/turbo-generators/README.md +++ b/packages/turbo-generators/README.md @@ -9,6 +9,8 @@ Custom generators for `turbo generate`. The component generator asks for name and docs group. Primitive scaffolding is tracked separately. +Generated component folders use a named implementation file and an export-only `index.ts` barrel. + ## Usage ```bash diff --git a/packages/turbo-generators/src/apply-component-creation-plan.test.ts b/packages/turbo-generators/src/apply-component-creation-plan.test.ts index 5eb59a03..71852b2d 100644 --- a/packages/turbo-generators/src/apply-component-creation-plan.test.ts +++ b/packages/turbo-generators/src/apply-component-creation-plan.test.ts @@ -28,7 +28,7 @@ describe('applyComponentCreationPlan', () => { files: [ { contents: 'export const StatusBadge = 1;\n', - path: 'packages/@luke-ui/react/src/status-badge/index.tsx', + path: 'packages/@luke-ui/react/src/status-badge/status-badge.tsx', }, ], jsonEdits: [ @@ -53,7 +53,7 @@ describe('applyComponentCreationPlan', () => { await applyComponentCreationPlan(root, plan); await expect( - readFile(join(root, 'packages/@luke-ui/react/src/status-badge/index.tsx'), 'utf8'), + readFile(join(root, 'packages/@luke-ui/react/src/status-badge/status-badge.tsx'), 'utf8'), ).resolves.toBe('export const StatusBadge = 1;\n'); await expect(readJson(root, 'apps/docs/content/docs/components/meta.json')).resolves.toEqual({ pages: ['feedback'], diff --git a/packages/turbo-generators/src/component-creation-plan.test.ts b/packages/turbo-generators/src/component-creation-plan.test.ts index a1d0ccfc..0da0846c 100644 --- a/packages/turbo-generators/src/component-creation-plan.test.ts +++ b/packages/turbo-generators/src/component-creation-plan.test.ts @@ -36,10 +36,11 @@ describe('createComponentPlan', () => { 'apps/docs/content/docs/components/feedback/status-badge.mdx', 'apps/docs/src/examples/status-badge/basic.tsx', 'packages/@luke-ui/react/src/status-badge/component-test-registration.ts', - 'packages/@luke-ui/react/src/status-badge/index.tsx', + 'packages/@luke-ui/react/src/status-badge/index.ts', 'packages/@luke-ui/react/src/status-badge/recipe.css.ts', 'packages/@luke-ui/react/src/status-badge/status-badge.browser.test.tsx', 'packages/@luke-ui/react/src/status-badge/status-badge.stories.tsx', + 'packages/@luke-ui/react/src/status-badge/status-badge.tsx', 'packages/@luke-ui/react/src/status-badge/status-badge.visual.test.tsx', ]); expect(plan.sortedImportEdits).toEqual([ @@ -53,14 +54,23 @@ describe('createComponentPlan', () => { "\t['StatusBadge', 'status-badge', 'universal', 'none', 'applicable'],", ]); - const indexSource = plan.files.find((file) => - file.path.endsWith('/status-badge/index.tsx'), - )?.contents; const recipeSource = plan.files.find((file) => file.path.endsWith('/status-badge/recipe.css.ts'), )?.contents; + const indexSource = plan.files.find((file) => + file.path.endsWith('/status-badge/status-badge.tsx'), + )?.contents; + const barrelSource = plan.files.find((file) => + file.path.endsWith('/status-badge/index.ts'), + )?.contents; - expect(indexSource).toContain('export { statusBadgeRecipe, type StatusBadgeRecipeVariants }'); + expect(indexSource).not.toContain('export { statusBadgeRecipe'); + expect(barrelSource).toContain( + "export { StatusBadge, type StatusBadgeProps } from './status-badge.js';", + ); + expect(barrelSource).toContain( + "export { statusBadgeRecipe, type StatusBadgeRecipeVariants } from './recipe.css.js';", + ); expect(recipeSource).toContain('export const statusBadgeRecipe = recipe({'); expect(recipeSource).toContain( 'export type StatusBadgeRecipeVariants = RecipeSelection;', @@ -137,11 +147,11 @@ describe('createComponentPlan', () => { { heading: undefined, name: 'StatusBadgeProps', - path: 'packages/@luke-ui/react/src/status-badge/index.tsx', + path: 'packages/@luke-ui/react/src/status-badge/status-badge.tsx', }, ]); expect(renderPropsPage(frontmatter)).toContain( - '', + '', ); }); @@ -159,9 +169,6 @@ describe('createComponentPlan', () => { await mkdir(componentDir, { recursive: true }); await mkdir(stylesDir, { recursive: true }); - const indexSource = plan.files.find((file) => - file.path.endsWith('/status-badge/index.tsx'), - )?.contents; const recipeSource = plan.files.find((file) => file.path.endsWith('/status-badge/recipe.css.ts'), )?.contents; @@ -169,8 +176,6 @@ describe('createComponentPlan', () => { throw new Error('Expected generated recipe source.'); } - expect(indexSource).toContain('export { statusBadgeRecipe, type StatusBadgeRecipeVariants }'); - await writeFile(join(componentDir, 'recipe.css.ts'), recipeSource, 'utf8'); await writeFile( join(stylesDir, 'recipe.ts'), diff --git a/packages/turbo-generators/src/component-creation-plan.ts b/packages/turbo-generators/src/component-creation-plan.ts index a129d667..ad346011 100644 --- a/packages/turbo-generators/src/component-creation-plan.ts +++ b/packages/turbo-generators/src/component-creation-plan.ts @@ -74,7 +74,11 @@ export function createComponentPlan(input: CreateComponentInput): ComponentCreat recipeName, variantsType, }), - path: `packages/@luke-ui/react/src/${name}/index.tsx`, + path: `packages/@luke-ui/react/src/${name}/${name}.tsx`, + }, + { + contents: renderComponentBarrel({ name, pascalName, recipeName, variantsType }), + path: `packages/@luke-ui/react/src/${name}/index.ts`, }, { contents: renderRecipe({ recipeName, variantsType }), @@ -215,11 +219,9 @@ function renderComponentSource(input: { variantsType: string; }): string { return `import type { ComponentProps, JSX } from 'react'; -import { cx } from '../utils/index.js'; +import { cx } from '../utils/utils.js'; import { ${input.recipeName} } from './recipe.css.js'; -export { ${input.recipeName}, type ${input.variantsType} } from './recipe.css.js'; - /** Props for \`${input.pascalName}\`. */ export interface ${input.pascalName}Props extends ComponentProps<'div'> {} @@ -231,6 +233,17 @@ export function ${input.pascalName}(props: ${input.pascalName}Props): JSX.Elemen `; } +function renderComponentBarrel(input: { + name: string; + pascalName: string; + recipeName: string; + variantsType: string; +}): string { + return `export { ${input.pascalName}, type ${input.pascalName}Props } from './${input.name}.js'; +export { ${input.recipeName}, type ${input.variantsType} } from './recipe.css.js'; +`; +} + function renderPackageStory(input: { docsGroup: string; name: string; @@ -388,7 +401,7 @@ title: ${input.displayName} source: packages/@luke-ui/react/src/${input.name} props: - name: ${input.pascalName}Props - path: packages/@luke-ui/react/src/${input.name}/index.tsx + path: packages/@luke-ui/react/src/${input.name}/${input.name}.tsx ---