diff --git a/apps/docs/content/docs/components/actions/button.mdx b/apps/docs/content/docs/components/actions/button.mdx index f5b8c97c..1783d327 100644 --- a/apps/docs/content/docs/components/actions/button.mdx +++ b/apps/docs/content/docs/components/actions/button.mdx @@ -24,8 +24,7 @@ description: Action button with tone, size, icon, pending, and disabled states. `Button` has four tones: `primary` (default), `neutral`, `critical`, and `ghost`. @@ -35,8 +34,7 @@ description: Action button with tone, size, icon, pending, and disabled states. `Button` has two sizes: `medium` (default) and `small`. @@ -66,8 +64,7 @@ Set `isPending` while an action is in flight. A spinner overlays the label and t non-interactive. diff --git a/apps/docs/content/docs/components/actions/icon-button.mdx b/apps/docs/content/docs/components/actions/icon-button.mdx index 1dfba081..3ba5e451 100644 --- a/apps/docs/content/docs/components/actions/icon-button.mdx +++ b/apps/docs/content/docs/components/actions/icon-button.mdx @@ -20,8 +20,7 @@ accessible label. ## Tone @@ -29,8 +28,7 @@ accessible label. ## Size diff --git a/apps/docs/content/docs/components/actions/link.mdx b/apps/docs/content/docs/components/actions/link.mdx index 66de690a..9fa51de4 100644 --- a/apps/docs/content/docs/components/actions/link.mdx +++ b/apps/docs/content/docs/components/actions/link.mdx @@ -23,8 +23,7 @@ description: Link component for inline and standalone navigation. subtle link. Use `inverted` on dark backgrounds. @@ -37,8 +36,7 @@ Use `isStandalone` when a link stands on its own. Leave it `false` for links ins - `isStandalone={false}`: underlined inline link style. @@ -46,8 +44,7 @@ Use `isStandalone` when a link stands on its own. Leave it `false` for links ins ## Disabled diff --git a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx index 1dafb722..1b7554a4 100644 --- a/apps/docs/content/docs/components/feedback/loading-skeleton.mdx +++ b/apps/docs/content/docs/components/feedback/loading-skeleton.mdx @@ -10,8 +10,7 @@ Use it when loading content should keep the same footprint as the loaded state. inline skeleton. Elements keep their layout while the skeleton surface is painted over them. @@ -45,8 +44,7 @@ Wrap text directly when the copy spans more than one line. Each line gets its ow element. @@ -57,8 +55,7 @@ Use `LoadingSkeletonProvider` when one loading state controls a group of skeleto value overrides descendant `isLoading` props. @@ -68,8 +65,7 @@ value overrides descendant `isLoading` props. Use `borderRadius` when the wrapped child has no radius, but the visible control inside it does. @@ -80,8 +76,7 @@ Wrap an element with explicit dimensions when you need a placeholder for a fixed avatar. diff --git a/apps/docs/content/docs/components/feedback/loading-spinner.mdx b/apps/docs/content/docs/components/feedback/loading-spinner.mdx index dd885aca..60a80bbc 100644 --- a/apps/docs/content/docs/components/feedback/loading-spinner.mdx +++ b/apps/docs/content/docs/components/feedback/loading-spinner.mdx @@ -7,8 +7,7 @@ description: Spinner for indeterminate and determinate progress. [Getting Started](/docs/getting-started). @@ -21,8 +20,7 @@ times. Omit `value` for indeterminate progress. Pass `value` for determinate progress. @@ -30,8 +28,7 @@ Omit `value` for indeterminate progress. Pass `value` for determinate progress. ## Size @@ -39,8 +36,7 @@ Omit `value` for indeterminate progress. Pass `value` for determinate progress. ## Color diff --git a/apps/docs/content/docs/components/forms/combobox-field.mdx b/apps/docs/content/docs/components/forms/combobox-field.mdx index e7c9d075..a4258b4c 100644 --- a/apps/docs/content/docs/components/forms/combobox-field.mdx +++ b/apps/docs/content/docs/components/forms/combobox-field.mdx @@ -7,8 +7,7 @@ Use `ComboboxField` for a single-select combobox with label, description, error, and optional async loading built in. @@ -46,8 +45,7 @@ The clear button is omitted when the field is disabled or read-only. Use `isRequired` with `necessityIndicator` to show that the field is mandatory. @@ -76,8 +74,7 @@ import { Form } from 'react-aria-components'; Use `ComboboxSection` to group related options inside the listbox. diff --git a/apps/docs/content/docs/components/forms/text-field.mdx b/apps/docs/content/docs/components/forms/text-field.mdx index d4c1552d..03e66a66 100644 --- a/apps/docs/content/docs/components/forms/text-field.mdx +++ b/apps/docs/content/docs/components/forms/text-field.mdx @@ -7,8 +7,7 @@ Use `TextField` for a single text input with label, description, validation, and built in. @@ -26,8 +25,7 @@ Use `isRequired` and `necessityIndicator` to communicate mandatory fields. `'ico required marker. `'label'` appends "(required)" to the label text. @@ -56,8 +54,7 @@ Adornments accept any `ReactNode`. If an adornment is interactive, you are respo semantics. @@ -73,8 +70,7 @@ omitted because `size` is reserved for the design-system variant. | `'medium'` | Default input height. | diff --git a/apps/docs/content/docs/components/typography/emoji.mdx b/apps/docs/content/docs/components/typography/emoji.mdx index cb7bc3c8..d6023382 100644 --- a/apps/docs/content/docs/components/typography/emoji.mdx +++ b/apps/docs/content/docs/components/typography/emoji.mdx @@ -6,8 +6,7 @@ description: Emoji rendering with a reliable screen reader label. Use `Emoji` when an emoji needs a reliable accessible label. diff --git a/apps/docs/content/docs/components/typography/heading.mdx b/apps/docs/content/docs/components/typography/heading.mdx index 17ae27c7..d062a225 100644 --- a/apps/docs/content/docs/components/typography/heading.mdx +++ b/apps/docs/content/docs/components/typography/heading.mdx @@ -27,8 +27,7 @@ can pass `level` directly. `HeadingLevels` advances the next heading level. @@ -42,8 +41,7 @@ or children. default it applies `fontWeight="bold"` and `lineHeight="tight"`. diff --git a/apps/docs/content/docs/components/typography/numeral.mdx b/apps/docs/content/docs/components/typography/numeral.mdx index 3d8558b3..be790dc3 100644 --- a/apps/docs/content/docs/components/typography/numeral.mdx +++ b/apps/docs/content/docs/components/typography/numeral.mdx @@ -7,8 +7,7 @@ description: Locale-aware number formatting powered by Intl.NumberFormat. `I18nProvider`. @@ -19,8 +18,7 @@ description: Locale-aware number formatting powered by Intl.NumberFormat. `'percent'` or `'decimal'`, or when you want to be direct about currency and unit formatting. @@ -30,8 +28,7 @@ description: Locale-aware number formatting powered by Intl.NumberFormat. Use `abbreviate` for compact notation. @@ -41,8 +38,7 @@ Use `abbreviate` for compact notation. Pass a number for fixed fraction digits, or a `[min, max]` tuple for a range. diff --git a/apps/docs/content/docs/components/typography/text.mdx b/apps/docs/content/docs/components/typography/text.mdx index 8e442eaf..4f562e18 100644 --- a/apps/docs/content/docs/components/typography/text.mdx +++ b/apps/docs/content/docs/components/typography/text.mdx @@ -22,8 +22,7 @@ Use `Text` for styled text that should not create heading semantics. ## Typography @@ -34,8 +33,7 @@ See the token reference below for valid `color`, `fontFamily`, `fontSize`, `line ## Text transform and decoration @@ -43,8 +41,7 @@ See the token reference below for valid `color`, `fontFamily`, `fontSize`, `line ## Truncation @@ -52,8 +49,7 @@ See the token reference below for valid `color`, `fontFamily`, `fontSize`, `line ## Alignment and numeric glyphs diff --git a/apps/docs/content/docs/components/visuals/icon.mdx b/apps/docs/content/docs/components/visuals/icon.mdx index 5a88238a..4dab304f 100644 --- a/apps/docs/content/docs/components/visuals/icon.mdx +++ b/apps/docs/content/docs/components/visuals/icon.mdx @@ -7,8 +7,7 @@ description: SVG icon component backed by the generated spritesheet. ancestor. See Setup below. @@ -71,8 +70,7 @@ pnpm --dir packages/@luke-ui/react run generate:icons Use `createIcon` for a one-off icon that is not in the generated spritesheet. diff --git a/apps/docs/package.json b/apps/docs/package.json index 4925e16c..f49c6878 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -54,6 +54,7 @@ "serve": "catalog:", "tailwindcss": "catalog:", "typescript": "catalog:", + "unist-util-visit": "catalog:", "vite-plus": "catalog:", "vitest": "catalog:" } diff --git a/apps/docs/source.config.ts b/apps/docs/source.config.ts index 3dff4b1c..cad978e5 100644 --- a/apps/docs/source.config.ts +++ b/apps/docs/source.config.ts @@ -1,10 +1,11 @@ import { fileURLToPath } from 'node:url'; import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; import { - remarkAutoTypeTable, - createGenerator, createFileSystemGeneratorCache, + createGenerator, + remarkAutoTypeTable, } from 'fumadocs-typescript'; +import { remarkValidateExamples } from './src/lib/remark-validate-examples'; export const docs = defineDocs({ dir: 'content/docs', @@ -26,6 +27,7 @@ export default defineConfig({ remarkPlugins: (v) => [ ...v, [remarkAutoTypeTable, { generator, options: { basePath: repoRoot } }], + remarkValidateExamples, ], }, }); diff --git a/apps/docs/src/components/example-block.tsx b/apps/docs/src/components/example-block.tsx index b503a286..c028375b 100644 --- a/apps/docs/src/components/example-block.tsx +++ b/apps/docs/src/components/example-block.tsx @@ -1,14 +1,13 @@ import { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock'; import { buttonVariants } from 'fumadocs-ui/components/ui/button'; import { CodeIcon } from 'lucide-react'; -import { Suspense, use, useId, useState } from 'react'; import type { ComponentType, JSX } from 'react'; +import { Suspense, use, useId, useState } from 'react'; import { StoryWrapper } from '../lib/story-wrapper'; type ExampleProps = { - component: string; + src: string; description: string; - name: string; title: string; }; @@ -27,7 +26,10 @@ const _modules = import.meta.glob('../examples/*/*.tsx', { import: 'default', }); -function ExampleContent({ component, name, title }: ExampleProps): JSX.Element { +function ExampleContent({ src, title }: ExampleProps): JSX.Element { + const slashIndex = src.indexOf('/'); + const component = src.slice(0, slashIndex); + const name = src.slice(slashIndex + 1); const result = use(loadExample(component, name)); const [showCode, setShowCode] = useState(false); const codeId = useId(); @@ -75,8 +77,8 @@ function ExampleContent({ component, name, title }: ExampleProps): JSX.Element { const _sources = import.meta.glob('../examples/*/*.tsx', { eager: false, - query: '?raw', import: 'default', + query: '?raw', }); type ExampleTuple = [ComponentType, string]; @@ -114,8 +116,8 @@ function loadExample(component: string, name: string): Promise { const match = findExample(component, name); if (!match) { const promise = Promise.resolve({ - ok: false, error: new Error(`Example not found: ${component}/${name}`), + ok: false, } satisfies ExampleResult); exampleCache.set(key, promise); return promise; @@ -125,14 +127,14 @@ function loadExample(component: string, name: string): Promise { const promise = Promise.all([loadModule(), loadSource()]) .then( ([loadedComponent, loadedSource]): ExampleResult => ({ - ok: true, data: [loadedComponent, loadedSource], + ok: true, }), ) .catch( (err): ExampleResult => ({ - ok: false, error: err instanceof Error ? err : new Error(String(err)), + ok: false, }), ); diff --git a/apps/docs/src/examples/button/pending.tsx b/apps/docs/src/examples/button/pending.tsx index 94c2f2c8..529cbfe5 100644 --- a/apps/docs/src/examples/button/pending.tsx +++ b/apps/docs/src/examples/button/pending.tsx @@ -1,7 +1,6 @@ import { Button } from '@luke-ui/react/button'; -import type { JSX } from 'react'; -export default function Pending(): JSX.Element { +export default function Pending() { return (
diff --git a/apps/docs/src/examples/button/sizes.tsx b/apps/docs/src/examples/button/sizes.tsx index 14dc468b..55781e32 100644 --- a/apps/docs/src/examples/button/sizes.tsx +++ b/apps/docs/src/examples/button/sizes.tsx @@ -1,7 +1,6 @@ import { Button } from '@luke-ui/react/button'; -import type { JSX } from 'react'; -export default function Sizes(): JSX.Element { +export default function Sizes() { return (
diff --git a/apps/docs/src/examples/button/tones.tsx b/apps/docs/src/examples/button/tones.tsx index 9a27f0d3..1f068787 100644 --- a/apps/docs/src/examples/button/tones.tsx +++ b/apps/docs/src/examples/button/tones.tsx @@ -1,7 +1,6 @@ import { Button } from '@luke-ui/react/button'; -import type { JSX } from 'react'; -export default function Tones(): JSX.Element { +export default function Tones() { return (
diff --git a/apps/docs/src/examples/combobox-field/basic.tsx b/apps/docs/src/examples/combobox-field/basic.tsx index 9b5c18bd..0fd9ece7 100644 --- a/apps/docs/src/examples/combobox-field/basic.tsx +++ b/apps/docs/src/examples/combobox-field/basic.tsx @@ -1,6 +1,5 @@ import { ComboboxField } from '@luke-ui/react/combobox-field'; import { ComboboxItem } from '@luke-ui/react/combobox-field/primitive'; -import type { JSX } from 'react'; type Country = { id: string; label: string }; @@ -11,13 +10,13 @@ const countries: Array = [ { id: 'us', label: 'United States' }, ]; -export default function Basic(): JSX.Element { +export default function Basic() { return ( {(item) => {item.label}} diff --git a/apps/docs/src/examples/combobox-field/grouped.tsx b/apps/docs/src/examples/combobox-field/grouped.tsx index 022109e1..86bff84a 100644 --- a/apps/docs/src/examples/combobox-field/grouped.tsx +++ b/apps/docs/src/examples/combobox-field/grouped.tsx @@ -1,8 +1,7 @@ import { ComboboxField } from '@luke-ui/react/combobox-field'; import { ComboboxItem, ComboboxSection } from '@luke-ui/react/combobox-field/primitive'; -import type { JSX } from 'react'; -export default function Grouped(): JSX.Element { +export default function Grouped() { return ( diff --git a/apps/docs/src/examples/combobox-field/required.tsx b/apps/docs/src/examples/combobox-field/required.tsx index aba251c5..51036f61 100644 --- a/apps/docs/src/examples/combobox-field/required.tsx +++ b/apps/docs/src/examples/combobox-field/required.tsx @@ -1,6 +1,5 @@ import { ComboboxField } from '@luke-ui/react/combobox-field'; import { ComboboxItem } from '@luke-ui/react/combobox-field/primitive'; -import type { JSX } from 'react'; const items = [ { id: 'au', label: 'Australia' }, @@ -9,14 +8,14 @@ const items = [ { id: 'us', label: 'United States' }, ]; -export default function Required(): JSX.Element { +export default function Required() { return ( {(item) => {item.label}} diff --git a/apps/docs/src/examples/emoji/basic.tsx b/apps/docs/src/examples/emoji/basic.tsx index cd31c118..ad86e200 100644 --- a/apps/docs/src/examples/emoji/basic.tsx +++ b/apps/docs/src/examples/emoji/basic.tsx @@ -1,11 +1,10 @@ import { Emoji } from '@luke-ui/react/emoji'; -import type { JSX } from 'react'; -export default function Basic(): JSX.Element { +export default function Basic() { return (
- +
); } diff --git a/apps/docs/src/examples/heading/automatic-leveling.tsx b/apps/docs/src/examples/heading/automatic-leveling.tsx index cd66c5d8..289e9bfd 100644 --- a/apps/docs/src/examples/heading/automatic-leveling.tsx +++ b/apps/docs/src/examples/heading/automatic-leveling.tsx @@ -1,8 +1,7 @@ import { Heading } from '@luke-ui/react/heading'; import { HeadingLevels } from '@luke-ui/react/heading-context'; -import type { JSX } from 'react'; -export default function AutomaticLeveling(): JSX.Element { +export default function AutomaticLeveling() { return ( h1 diff --git a/apps/docs/src/examples/heading/typography.tsx b/apps/docs/src/examples/heading/typography.tsx index 60b6ad2d..3ffd885a 100644 --- a/apps/docs/src/examples/heading/typography.tsx +++ b/apps/docs/src/examples/heading/typography.tsx @@ -1,13 +1,12 @@ import { Heading } from '@luke-ui/react/heading'; -import type { JSX } from 'react'; -export default function Typography(): JSX.Element { +export default function Typography() { return (
- + Informative heading - + Light-weight heading
diff --git a/apps/docs/src/examples/icon-button/size.tsx b/apps/docs/src/examples/icon-button/size.tsx index 240e534e..eb176648 100644 --- a/apps/docs/src/examples/icon-button/size.tsx +++ b/apps/docs/src/examples/icon-button/size.tsx @@ -1,11 +1,10 @@ import { IconButton } from '@luke-ui/react/icon-button'; -import type { JSX } from 'react'; -export default function Size(): JSX.Element { +export default function Size() { return ( -
- - +
+ +
); } diff --git a/apps/docs/src/examples/icon-button/tones.tsx b/apps/docs/src/examples/icon-button/tones.tsx index 342f6dc6..45e1e524 100644 --- a/apps/docs/src/examples/icon-button/tones.tsx +++ b/apps/docs/src/examples/icon-button/tones.tsx @@ -1,11 +1,10 @@ import { IconButton } from '@luke-ui/react/icon-button'; -import type { JSX } from 'react'; -export default function Tone(): JSX.Element { +export default function Tone() { return (
- - + +
); } diff --git a/apps/docs/src/examples/icon/basic.tsx b/apps/docs/src/examples/icon/basic.tsx index 02ae3622..7183bfc8 100644 --- a/apps/docs/src/examples/icon/basic.tsx +++ b/apps/docs/src/examples/icon/basic.tsx @@ -1,11 +1,10 @@ import { Icon } from '@luke-ui/react/icon'; -import type { JSX } from 'react'; -export default function Basic(): JSX.Element { +export default function Basic() { return (
- - + +
); } diff --git a/apps/docs/src/examples/icon/custom.tsx b/apps/docs/src/examples/icon/custom.tsx index 249dc00b..77d5bc3b 100644 --- a/apps/docs/src/examples/icon/custom.tsx +++ b/apps/docs/src/examples/icon/custom.tsx @@ -1,5 +1,4 @@ import { createIcon } from '@luke-ui/react/icon'; -import type { JSX } from 'react'; const HeartIcon = createIcon({ path: ( @@ -7,6 +6,6 @@ const HeartIcon = createIcon({ ), }); -export default function Custom(): JSX.Element { - return ; +export default function Custom() { + return ; } diff --git a/apps/docs/src/examples/link/disabled.tsx b/apps/docs/src/examples/link/disabled.tsx index c9fc251b..92a5d92c 100644 --- a/apps/docs/src/examples/link/disabled.tsx +++ b/apps/docs/src/examples/link/disabled.tsx @@ -1,7 +1,6 @@ import { Link } from '@luke-ui/react/link'; -import type { JSX } from 'react'; -export default function Disabled(): JSX.Element { +export default function Disabled() { return ( Archived report diff --git a/apps/docs/src/examples/link/standalone.tsx b/apps/docs/src/examples/link/standalone.tsx index 55fb0c6f..813edc0f 100644 --- a/apps/docs/src/examples/link/standalone.tsx +++ b/apps/docs/src/examples/link/standalone.tsx @@ -1,7 +1,6 @@ import { Link } from '@luke-ui/react/link'; -import type { JSX } from 'react'; -export default function Standalone(): JSX.Element { +export default function Standalone() { return (
diff --git a/apps/docs/src/examples/link/tones.tsx b/apps/docs/src/examples/link/tones.tsx index 67e70005..b36e7348 100644 --- a/apps/docs/src/examples/link/tones.tsx +++ b/apps/docs/src/examples/link/tones.tsx @@ -1,7 +1,6 @@ import { Link } from '@luke-ui/react/link'; -import type { JSX } from 'react'; -export default function Tones(): JSX.Element { +export default function Tones() { return (
Brand diff --git a/apps/docs/src/examples/loading-skeleton/border-radius.tsx b/apps/docs/src/examples/loading-skeleton/border-radius.tsx index caf411e6..5d911a3b 100644 --- a/apps/docs/src/examples/loading-skeleton/border-radius.tsx +++ b/apps/docs/src/examples/loading-skeleton/border-radius.tsx @@ -1,9 +1,8 @@ import { LoadingSkeleton } from '@luke-ui/react/loading-skeleton'; import { TextField } from '@luke-ui/react/text-field'; -import type { JSX } from 'react'; import { useState } from 'react'; -export default function BorderRadius(): JSX.Element { +export default function BorderRadius() { const [isLoading, setIsLoading] = useState(true); return ( diff --git a/apps/docs/src/examples/loading-skeleton/custom-dimensions.tsx b/apps/docs/src/examples/loading-skeleton/custom-dimensions.tsx index 608c34b9..54c65479 100644 --- a/apps/docs/src/examples/loading-skeleton/custom-dimensions.tsx +++ b/apps/docs/src/examples/loading-skeleton/custom-dimensions.tsx @@ -1,8 +1,7 @@ import { LoadingSkeleton } from '@luke-ui/react/loading-skeleton'; -import type { JSX } from 'react'; import { useState } from 'react'; -export default function CustomDimensions(): JSX.Element { +export default function CustomDimensions() { const [isLoading, setIsLoading] = useState(true); return ( diff --git a/apps/docs/src/examples/loading-skeleton/element.tsx b/apps/docs/src/examples/loading-skeleton/element.tsx index 0b68a84f..65e5d37d 100644 --- a/apps/docs/src/examples/loading-skeleton/element.tsx +++ b/apps/docs/src/examples/loading-skeleton/element.tsx @@ -1,8 +1,7 @@ import { LoadingSkeleton } from '@luke-ui/react/loading-skeleton'; -import type { JSX } from 'react'; import { useState } from 'react'; -export default function ElementSkeleton(): JSX.Element { +export default function ElementSkeleton() { const [isLoading, setIsLoading] = useState(true); return ( diff --git a/apps/docs/src/examples/loading-skeleton/provider.tsx b/apps/docs/src/examples/loading-skeleton/provider.tsx index b7c7642f..d6f6be49 100644 --- a/apps/docs/src/examples/loading-skeleton/provider.tsx +++ b/apps/docs/src/examples/loading-skeleton/provider.tsx @@ -1,10 +1,9 @@ import { Button } from '@luke-ui/react/button'; import { LoadingSkeleton, LoadingSkeletonProvider } from '@luke-ui/react/loading-skeleton'; import { Text } from '@luke-ui/react/text'; -import type { JSX } from 'react'; import { useState } from 'react'; -export default function ProviderSkeleton(): JSX.Element { +export default function ProviderSkeleton() { const [isLoading, setIsLoading] = useState(true); return ( diff --git a/apps/docs/src/examples/loading-skeleton/text.tsx b/apps/docs/src/examples/loading-skeleton/text.tsx index 79f32ca9..fb29a1d3 100644 --- a/apps/docs/src/examples/loading-skeleton/text.tsx +++ b/apps/docs/src/examples/loading-skeleton/text.tsx @@ -1,8 +1,7 @@ import { LoadingSkeleton } from '@luke-ui/react/loading-skeleton'; -import type { JSX } from 'react'; import { useState } from 'react'; -export default function TextSkeleton(): JSX.Element { +export default function TextSkeleton() { const [isLoading, setIsLoading] = useState(true); return ( diff --git a/apps/docs/src/examples/loading-spinner/basic.tsx b/apps/docs/src/examples/loading-spinner/basic.tsx index 4caffc1c..1b094088 100644 --- a/apps/docs/src/examples/loading-spinner/basic.tsx +++ b/apps/docs/src/examples/loading-spinner/basic.tsx @@ -1,6 +1,5 @@ import { LoadingSpinner } from '@luke-ui/react/loading-spinner'; -import type { JSX } from 'react'; -export default function Basic(): JSX.Element { +export default function Basic() { return ; } diff --git a/apps/docs/src/examples/loading-spinner/colors.tsx b/apps/docs/src/examples/loading-spinner/colors.tsx index 49b6dfa8..2f717f9c 100644 --- a/apps/docs/src/examples/loading-spinner/colors.tsx +++ b/apps/docs/src/examples/loading-spinner/colors.tsx @@ -1,7 +1,6 @@ import { LoadingSpinner } from '@luke-ui/react/loading-spinner'; -import type { JSX } from 'react'; -export default function Colors(): JSX.Element { +export default function Colors() { return (
diff --git a/apps/docs/src/examples/loading-spinner/progress.tsx b/apps/docs/src/examples/loading-spinner/progress.tsx index 97918512..1dc50b52 100644 --- a/apps/docs/src/examples/loading-spinner/progress.tsx +++ b/apps/docs/src/examples/loading-spinner/progress.tsx @@ -1,7 +1,6 @@ import { LoadingSpinner } from '@luke-ui/react/loading-spinner'; -import type { JSX } from 'react'; -export default function Progress(): JSX.Element { +export default function Progress() { return (
diff --git a/apps/docs/src/examples/loading-spinner/sizes.tsx b/apps/docs/src/examples/loading-spinner/sizes.tsx index 4569af47..e35f85b7 100644 --- a/apps/docs/src/examples/loading-spinner/sizes.tsx +++ b/apps/docs/src/examples/loading-spinner/sizes.tsx @@ -1,7 +1,6 @@ import { LoadingSpinner } from '@luke-ui/react/loading-spinner'; -import type { JSX } from 'react'; -export default function Sizes(): JSX.Element { +export default function Sizes() { return (
diff --git a/apps/docs/src/examples/numeral/basic.tsx b/apps/docs/src/examples/numeral/basic.tsx index 376a4fb4..0f5056fc 100644 --- a/apps/docs/src/examples/numeral/basic.tsx +++ b/apps/docs/src/examples/numeral/basic.tsx @@ -1,6 +1,5 @@ import { Numeral } from '@luke-ui/react/numeral'; -import type { JSX } from 'react'; -export default function Basic(): JSX.Element { +export default function Basic() { return ; } diff --git a/apps/docs/src/examples/numeral/compact.tsx b/apps/docs/src/examples/numeral/compact.tsx index b8d020a3..005f121f 100644 --- a/apps/docs/src/examples/numeral/compact.tsx +++ b/apps/docs/src/examples/numeral/compact.tsx @@ -1,11 +1,10 @@ import { Numeral } from '@luke-ui/react/numeral'; -import type { JSX } from 'react'; -export default function Compact(): JSX.Element { +export default function Compact() { return (
- - + +
); } diff --git a/apps/docs/src/examples/numeral/formats.tsx b/apps/docs/src/examples/numeral/formats.tsx index 560e3e7b..af99ecb9 100644 --- a/apps/docs/src/examples/numeral/formats.tsx +++ b/apps/docs/src/examples/numeral/formats.tsx @@ -1,13 +1,12 @@ import { Numeral } from '@luke-ui/react/numeral'; -import type { JSX } from 'react'; -export default function Formats(): JSX.Element { +export default function Formats() { return (
- - - - + + + +
); } diff --git a/apps/docs/src/examples/numeral/precision.tsx b/apps/docs/src/examples/numeral/precision.tsx index ae1d9064..1c1fe84e 100644 --- a/apps/docs/src/examples/numeral/precision.tsx +++ b/apps/docs/src/examples/numeral/precision.tsx @@ -1,11 +1,10 @@ import { Numeral } from '@luke-ui/react/numeral'; -import type { JSX } from 'react'; -export default function Precision(): JSX.Element { +export default function Precision() { return (
- - + +
); } diff --git a/apps/docs/src/examples/text-field/adornments.tsx b/apps/docs/src/examples/text-field/adornments.tsx index 3fa6a34c..52a9868a 100644 --- a/apps/docs/src/examples/text-field/adornments.tsx +++ b/apps/docs/src/examples/text-field/adornments.tsx @@ -1,17 +1,16 @@ import { Icon } from '@luke-ui/react/icon'; import { TextField } from '@luke-ui/react/text-field'; -import type { JSX } from 'react'; -export default function Adornments(): JSX.Element { +export default function Adornments() { return (
} label="Search" - adornmentStart={} + name="search" /> - - + +
); } diff --git a/apps/docs/src/examples/text-field/basic.tsx b/apps/docs/src/examples/text-field/basic.tsx index bd4d0a95..ec82f24d 100644 --- a/apps/docs/src/examples/text-field/basic.tsx +++ b/apps/docs/src/examples/text-field/basic.tsx @@ -1,12 +1,11 @@ import { TextField } from '@luke-ui/react/text-field'; -import type { JSX } from 'react'; -export default function Basic(): JSX.Element { +export default function Basic() { return ( ); diff --git a/apps/docs/src/examples/text-field/required.tsx b/apps/docs/src/examples/text-field/required.tsx index 278ca85c..6273004b 100644 --- a/apps/docs/src/examples/text-field/required.tsx +++ b/apps/docs/src/examples/text-field/required.tsx @@ -1,11 +1,10 @@ import { TextField } from '@luke-ui/react/text-field'; -import type { JSX } from 'react'; -export default function Required(): JSX.Element { +export default function Required() { return (
- - + +
); } diff --git a/apps/docs/src/examples/text-field/sizes.tsx b/apps/docs/src/examples/text-field/sizes.tsx index a04e83a7..35789690 100644 --- a/apps/docs/src/examples/text-field/sizes.tsx +++ b/apps/docs/src/examples/text-field/sizes.tsx @@ -1,11 +1,10 @@ import { TextField } from '@luke-ui/react/text-field'; -import type { JSX } from 'react'; -export default function Sizes(): JSX.Element { +export default function Sizes() { return (
- - + +
); } diff --git a/apps/docs/src/examples/text/alignment.tsx b/apps/docs/src/examples/text/alignment.tsx index d30791a4..07e295ea 100644 --- a/apps/docs/src/examples/text/alignment.tsx +++ b/apps/docs/src/examples/text/alignment.tsx @@ -1,9 +1,8 @@ import { Text } from '@luke-ui/react/text'; -import type { JSX } from 'react'; -export default function Alignment(): JSX.Element { +export default function Alignment() { return ( - + 12121.21 ); diff --git a/apps/docs/src/examples/text/transform.tsx b/apps/docs/src/examples/text/transform.tsx index c66696ad..f77b5698 100644 --- a/apps/docs/src/examples/text/transform.tsx +++ b/apps/docs/src/examples/text/transform.tsx @@ -1,9 +1,8 @@ import { Text } from '@luke-ui/react/text'; -import type { JSX } from 'react'; -export default function Transform(): JSX.Element { +export default function Transform() { return ( - + Emphasized text ); diff --git a/apps/docs/src/examples/text/truncation.tsx b/apps/docs/src/examples/text/truncation.tsx index a25d698b..f9c14f4c 100644 --- a/apps/docs/src/examples/text/truncation.tsx +++ b/apps/docs/src/examples/text/truncation.tsx @@ -1,7 +1,6 @@ import { Text } from '@luke-ui/react/text'; -import type { JSX } from 'react'; -export default function Truncation(): JSX.Element { +export default function Truncation() { return (
Long content that should be line clamped to two lines. diff --git a/apps/docs/src/examples/text/typography.tsx b/apps/docs/src/examples/text/typography.tsx index 125c8adf..d6209716 100644 --- a/apps/docs/src/examples/text/typography.tsx +++ b/apps/docs/src/examples/text/typography.tsx @@ -1,7 +1,6 @@ import { Text } from '@luke-ui/react/text'; -import type { JSX } from 'react'; -export default function Typography(): JSX.Element { +export default function Typography() { return (
diff --git a/apps/docs/src/lib/remark-validate-examples.ts b/apps/docs/src/lib/remark-validate-examples.ts new file mode 100644 index 00000000..3f511499 --- /dev/null +++ b/apps/docs/src/lib/remark-validate-examples.ts @@ -0,0 +1,50 @@ +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; +import { visit } from 'unist-util-visit'; + +interface Position { + start: { line: number; column: number }; +} + +interface MdxJsxAttribute { + name: string; + type: 'mdxJsxAttribute'; + value: string | { type: 'mdxJsxAttributeValueExpression'; value: string }; +} + +interface MdxJsxFlowElement { + attributes: Array; + name: string; + position?: Position; + type: string; +} + +export function remarkValidateExamples() { + return (tree: unknown, file: { cwd?: string; path?: string }) => { + const examplesDir = resolve(file.cwd ?? process.cwd(), 'src/examples'); + + visit(tree as never, 'mdxJsxFlowElement', (node: MdxJsxFlowElement) => { + if (node.name !== 'ExampleBlock') return; + + const srcAttr = node.attributes.find( + (attr: MdxJsxAttribute | { type: 'mdxJsxExpressionAttribute'; value: string }) => + attr.type === 'mdxJsxAttribute' && attr.name === 'src', + ) as MdxJsxAttribute | undefined; + + if (!srcAttr || typeof srcAttr.value !== 'string') { + const location = node.position ? `${file.path}:${node.position.start.line}` : file.path; + throw new Error(`${location}: requires a string \`src\` prop`); + } + + const { value: src } = srcAttr; + const examplePath = resolve(examplesDir, `${src}.tsx`); + + if (!existsSync(examplePath)) { + const location = node.position ? `${file.path}:${node.position.start.line}` : file.path; + throw new Error( + `${location}: does not match any file at src/examples/${src}.tsx`, + ); + } + }); + }; +} diff --git a/apps/docs/src/routes/docs/$.tsx b/apps/docs/src/routes/docs/$.tsx index b09bc0a3..916f4d3f 100644 --- a/apps/docs/src/routes/docs/$.tsx +++ b/apps/docs/src/routes/docs/$.tsx @@ -18,7 +18,7 @@ import { getStorybookStoryUrl, withBasePath } from '../../lib/storybook'; const GITHUB_DOCS_URL = 'https://github.com/lukebennett88/luke-ui/blob/main/apps/docs/content/docs'; -const mdxComponents = { ...defaultMdxComponents, AutoTypeTable, TypeTable, ExampleBlock }; +const mdxComponents = { ...defaultMdxComponents, AutoTypeTable, ExampleBlock, TypeTable }; export const Route = createFileRoute('/docs/$')({ component: Page, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 38e84ce2..546ed943 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -165,6 +165,9 @@ catalogs: typescript: specifier: ^6.0.3 version: 6.0.3 + unist-util-visit: + specifier: ^5.1.0 + version: 5.1.0 vite-plus: specifier: 0.2.2 version: 0.2.2 @@ -292,6 +295,9 @@ importers: typescript: specifier: 'catalog:' version: 6.0.3 + unist-util-visit: + specifier: 'catalog:' + version: 5.1.0 vite-plus: specifier: 'catalog:' version: 0.2.2(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(@voidzero-dev/vite-plus-core@0.2.2(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0))(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0) @@ -9111,9 +9117,9 @@ snapshots: obug: 2.1.3 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.9(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/browser-preview@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(vite@8.1.3(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + vitest: 4.1.9(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/browser-preview@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(@voidzero-dev/vite-plus-core@0.2.2(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0)) optionalDependencies: - '@vitest/browser': 4.1.9(vite@8.1.3(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0))(vitest@4.1.9) + '@vitest/browser': 4.1.9(@voidzero-dev/vite-plus-core@0.2.2(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0))(vitest@4.1.9) '@vitest/expect@3.2.4': dependencies: @@ -9183,7 +9189,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.17 tinyrainbow: 3.1.0 - vitest: 4.1.9(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/browser-preview@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(vite@8.1.3(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + vitest: 4.1.9(@types/node@26.0.1)(@vitest/browser-playwright@4.1.9)(@vitest/browser-preview@4.1.9)(@vitest/coverage-v8@4.1.9)(@vitest/ui@4.1.9)(@voidzero-dev/vite-plus-core@0.2.2(@arethetypeswrong/core@0.18.4)(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)(publint@0.3.21)(tsx@4.22.4)(typescript@6.0.3)(unrun@0.2.37)(yaml@2.9.0)) '@vitest/utils@3.2.4': dependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index ec22e483..f91f16aa 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -65,6 +65,7 @@ catalog: vite: npm:@voidzero-dev/vite-plus-core@0.2.2 vitest: 4.1.9 vite-plus: 0.2.2 + unist-util-visit: ^5.1.0 catalogMode: prefer