@astryxdesign/cli 0.1.6-canary.eb23da7 → 0.1.6-canary.eba4f34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +9 -13
  2. package/src/api/template.mjs +27 -103
  3. package/src/api/validate-integration.mjs +8 -0
  4. package/src/lib/component-discovery.mjs +5 -15
  5. package/src/lib/component-loader.mjs +0 -53
  6. package/src/lib/config-schema.mjs +30 -0
  7. package/src/lib/xle/registry.mjs +5 -0
  8. package/templates/blocks/components/Avatar/AvatarGroup.tsx +7 -5
  9. package/templates/blocks/components/Avatar/AvatarShowcase.tsx +6 -4
  10. package/templates/blocks/components/Avatar/AvatarUserCard.tsx +5 -3
  11. package/templates/blocks/components/Avatar/AvatarWithImage.tsx +6 -8
  12. package/templates/blocks/components/Avatar/AvatarWithStatus.tsx +5 -3
  13. package/templates/blocks/components/ChatComposerInput/ChatComposerInputControlledInput.tsx +1 -1
  14. package/templates/blocks/components/ChatComposerInput/ChatComposerInputDisabled.tsx +1 -1
  15. package/templates/blocks/components/ChatComposerInput/ChatComposerInputMentionTrigger.tsx +1 -1
  16. package/templates/blocks/components/ChatComposerInput/ChatComposerInputMultipleTriggers.tsx +1 -1
  17. package/templates/blocks/components/ChatComposerInput/ChatComposerInputShowcase.tsx +1 -1
  18. package/templates/blocks/components/ChatComposerInput/ChatComposerInputSlashCommands.tsx +1 -1
  19. package/templates/pages/theme-showcase/page.tsx +7 -7
  20. package/templates/themes/neutral/neutralTheme.ts +32 -63
  21. package/docs/integration-authoring.md +0 -105
  22. package/docs/internationalization.doc.mjs +0 -243
  23. package/src/api/integration-block-exports.test.mjs +0 -240
  24. package/src/api/template-suffix.test.mjs +0 -246
  25. package/src/doc.mjs +0 -271
  26. package/src/doc.test.mjs +0 -383
  27. package/src/lib/component-discovery.importpath.test.mjs +0 -59
  28. package/src/types/doc.d.ts +0 -139
  29. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenLiveRegion.doc.mjs +0 -14
  30. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenLiveRegion.tsx +0 -41
  31. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenShowcase.doc.mjs +0 -13
  32. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenShowcase.tsx +0 -78
  33. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenStructuralHeading.doc.mjs +0 -14
  34. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenStructuralHeading.tsx +0 -38
  35. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenSupplementaryContext.doc.mjs +0 -14
  36. package/templates/blocks/components/VisuallyHidden/VisuallyHiddenSupplementaryContext.tsx +0 -47
@@ -1,59 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /**
4
- * @file Verifies that `.ts`-authored sources (hooks and other functions) are
5
- * found by `findComponentSource`, so `resolveImportPath` derives a
6
- * tree-shakeable subpath instead of falling back to the bare package root.
7
- *
8
- * Runs against the real packages/core source, not mocks.
9
- */
10
-
11
- import {describe, it, expect} from 'vitest';
12
- import {
13
- findComponentSource,
14
- resolveImportPath,
15
- } from './component-discovery.mjs';
16
- import {findCoreDir} from '../utils/paths.mjs';
17
-
18
- describe('findComponentSource resolves .ts-authored sources', () => {
19
- const coreDir = findCoreDir();
20
-
21
- it('finds a hook authored as a .ts file (not just .tsx)', () => {
22
- const src = findComponentSource(coreDir, 'useMediaQuery');
23
- expect(src).toBeTruthy();
24
- expect(src.endsWith('useMediaQuery.ts')).toBe(true);
25
- });
26
-
27
- it('still finds a component authored as .tsx', () => {
28
- const src = findComponentSource(coreDir, 'Button');
29
- expect(src).toBeTruthy();
30
- expect(src.endsWith('.tsx')).toBe(true);
31
- });
32
- });
33
-
34
- describe('resolveImportPath reproduces authored hook importPaths', () => {
35
- const coreDir = findCoreDir();
36
-
37
- // Representative sample of core hooks whose sources are `.ts` files. Before
38
- // the `.ts` fix these fell back to bare `@astryxdesign/core`; the derived
39
- // subpath must now match the value each hook's doc currently authors.
40
- const cases = [
41
- ['useMediaQuery', '@astryxdesign/core/hooks'],
42
- ['useResizable', '@astryxdesign/core/Resizable'],
43
- ['useTheme', '@astryxdesign/core/theme'],
44
- ['useFocusTrap', '@astryxdesign/core/hooks'],
45
- ['useOverflow', '@astryxdesign/core/hooks'],
46
- ];
47
-
48
- for (const [name, expected] of cases) {
49
- it(`${name} derives ${expected}`, () => {
50
- expect(resolveImportPath(coreDir, name)).toBe(expected);
51
- });
52
- }
53
-
54
- it('never falls back to the bare package root for a .ts hook', () => {
55
- for (const [name] of cases) {
56
- expect(resolveImportPath(coreDir, name)).not.toBe('@astryxdesign/core');
57
- }
58
- });
59
- });
@@ -1,139 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /**
4
- * Authoring surface for Astryx docs, exported from `@astryxdesign/cli/doc`.
5
- *
6
- * A doc lives in a `{Name}.doc.{ts,mjs,js}` file. Authors default-export a
7
- * factory result (`createComponentDoc`/`createFunctionDoc`/`createDoc`) —
8
- * preferred — or, for the current loose docs, name-export `docs`. The doc's
9
- * shape is validated at the load boundary against `ComponentDocSchema` (see
10
- * `doc.mjs`), which accepts BOTH the new stamped formats and the legacy loose
11
- * shape.
12
- *
13
- * The factories inject the `type` discriminant, so authors never write it. The
14
- * inputs are kept as broad records so authoring never fails to typecheck when a
15
- * richer core type surface is not resolvable; the precise per-field guidance
16
- * lives on the doc types in `@astryxdesign/core/docs-types`.
17
- */
18
-
19
- /**
20
- * Fields shared by every doc kind (component + function + generic).
21
- *
22
- * `group` vs `parent` are distinct:
23
- * - `group` is a FLAT sidebar bucket label; many docs can share it and it is
24
- * NOT an inheritance key.
25
- * - `parent` is a DIRECTED inheritance/composition pointer — a doc naming the
26
- * doc it belongs to (e.g. a sub-component naming its parent component). The
27
- * legacy `subComponentOf` field is a synonym.
28
- *
29
- * `relatedDocs` is a single flat curated cross-reference list; it replaces the
30
- * legacy split `relatedComponents` + `relatedHooks`.
31
- */
32
- export interface AstryxBaseDocInput {
33
- /** Name of the documented unit, without any prefix, PascalCase. Required. */
34
- name: string;
35
- /** Human-readable display name for gallery/sidebar. */
36
- displayName?: string;
37
- /** Short description. */
38
- description?: string;
39
- /** Usage documentation (description, best practices, anatomy, slotElements). */
40
- usage?: unknown;
41
- /** Flat sidebar grouping label (not an inheritance key). */
42
- group?: string;
43
- /** Overview-page functional category. */
44
- category?: string;
45
- /** CLI fuzzy-search keywords. */
46
- keywords?: string[];
47
- /** Directed inheritance/composition pointer to the doc this belongs to. */
48
- parent?: string;
49
- /** Flat curated cross-reference list of related doc names. */
50
- relatedDocs?: string[];
51
- /** Hide the whole doc from human-facing UI (stays importable/discoverable). */
52
- hidden?: boolean;
53
- /** Exclude from the categorized overview page (kept in sidebar/CLI). */
54
- isHiddenFromOverview?: boolean;
55
- /** Any additional fields the rich doc surface carries. */
56
- [key: string]: unknown;
57
- }
58
-
59
- /** A single documented prop (mirrors `PropDoc` from core docs-types). */
60
- export interface AstryxPropInput {
61
- name: string;
62
- type: string;
63
- description: string;
64
- default?: string;
65
- required?: boolean;
66
- [key: string]: unknown;
67
- }
68
-
69
- /** A single documented param (mirrors `HookParamDoc`). */
70
- export interface AstryxParamInput {
71
- name: string;
72
- type: string;
73
- description: string;
74
- default?: string;
75
- required?: boolean;
76
- [key: string]: unknown;
77
- }
78
-
79
- /** A single documented return field (mirrors `HookReturnDoc`). */
80
- export interface AstryxReturnInput {
81
- name: string;
82
- type: string;
83
- description: string;
84
- [key: string]: unknown;
85
- }
86
-
87
- /**
88
- * Input accepted by {@link createComponentDoc}. A component (or a family). The
89
- * `type` discriminant is injected by the factory. `anatomy`/`slotElements` live
90
- * inside `usage`; `importPath` is DERIVED (never authored).
91
- */
92
- export interface AstryxComponentDocInput extends AstryxBaseDocInput {
93
- /** All public props for the component. */
94
- props: AstryxPropInput[];
95
- /** Theming/selector-surface metadata. */
96
- theming?: unknown;
97
- /** Interactive-preview playground configuration. */
98
- playground?: unknown;
99
- /** Short code examples rendered after the props table. */
100
- examples?: unknown[];
101
- }
102
-
103
- /**
104
- * Input accepted by {@link createFunctionDoc}. Covers any function, including
105
- * hooks: an inputs (`params`) + outputs (`returns`) surface. The `type`
106
- * discriminant is injected by the factory; `importPath` is DERIVED.
107
- */
108
- export interface AstryxFunctionDocInput extends AstryxBaseDocInput {
109
- /** Function/hook parameters or options-object fields. */
110
- params: AstryxParamInput[];
111
- /** Return value documentation. One entry per field (or a single primitive). */
112
- returns: AstryxReturnInput[];
113
- }
114
-
115
- /**
116
- * Input accepted by {@link createDoc}. A generic reference/topic doc — just the
117
- * shared base. The `type` discriminant is injected by the factory.
118
- */
119
- export type AstryxGenericDocInput = AstryxBaseDocInput;
120
-
121
- /**
122
- * Back-compat alias. Previously `createDoc` accepted a broad component-doc
123
- * record; the union of the three input kinds preserves that permissiveness for
124
- * any code referring to the old name.
125
- */
126
- export type AstryxComponentDoc =
127
- AstryxComponentDocInput | AstryxFunctionDocInput | AstryxGenericDocInput;
128
-
129
- export declare function createComponentDoc<T extends AstryxComponentDocInput>(
130
- def: T,
131
- ): T & {type: 'component'};
132
-
133
- export declare function createFunctionDoc<T extends AstryxFunctionDocInput>(
134
- def: T,
135
- ): T & {type: 'function'};
136
-
137
- export declare function createDoc<T extends AstryxGenericDocInput>(
138
- def: T,
139
- ): T & {type: 'generic'};
@@ -1,14 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
- export const doc = {
5
- type: 'block',
6
- exampleFor: 'VisuallyHidden',
7
- name: 'VisuallyHidden — Live Region',
8
- displayName: 'VisuallyHidden — Live Region',
9
- description:
10
- 'A polite aria-live region announces visual-only state changes to assistive technology.',
11
- isReady: true,
12
- aspectRatio: 4 / 3,
13
- componentsUsed: ['VisuallyHidden', 'Button', 'HStack', 'VStack', 'Text'],
14
- };
@@ -1,41 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- 'use client';
4
-
5
- import {useState} from 'react';
6
- import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
7
- import {Button} from '@astryxdesign/core/Button';
8
- import {HStack, VStack} from '@astryxdesign/core/Layout';
9
- import {Text} from '@astryxdesign/core/Text';
10
-
11
- const columns = ['Backlog', 'In progress', 'Done'] as const;
12
-
13
- export default function VisuallyHiddenLiveRegion() {
14
- const [column, setColumn] = useState(0);
15
- const current = columns[column];
16
-
17
- function move() {
18
- setColumn(c => (c + 1) % columns.length);
19
- }
20
-
21
- return (
22
- <VStack gap={4} hAlign="start">
23
- <Text type="supporting" color="secondary">
24
- Drag-and-drop and other visual-only changes are silent to screen
25
- readers. A live region narrates them.
26
- </Text>
27
- <HStack gap={3} vAlign="center">
28
- <Button label="Move task" variant="secondary" onClick={move} />
29
- <Text type="body">
30
- Task is in{' '}
31
- <Text as="span" weight="bold">
32
- {current}
33
- </Text>
34
- </Text>
35
- </HStack>
36
- <VisuallyHidden as="div" aria-live="polite">
37
- {`Task moved to ${current}`}
38
- </VisuallyHidden>
39
- </VStack>
40
- );
41
- }
@@ -1,13 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
- export const doc = {
5
- type: 'block',
6
- exampleFor: 'VisuallyHidden',
7
- name: 'VisuallyHidden',
8
- displayName: 'VisuallyHidden',
9
- isReady: true,
10
- aspectRatio: 16 / 9,
11
- isShowcase: true,
12
- componentsUsed: ['VisuallyHidden', 'IconButton', 'Card', 'HStack', 'VStack', 'Text', 'Icon'],
13
- };
@@ -1,78 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- 'use client';
4
-
5
- import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
6
- import {IconButton} from '@astryxdesign/core/IconButton';
7
- import {Card} from '@astryxdesign/core/Card';
8
- import {HStack, VStack} from '@astryxdesign/core/Layout';
9
- import {Text} from '@astryxdesign/core/Text';
10
- import {Icon} from '@astryxdesign/core/Icon';
11
- import {
12
- ArrowDownTrayIcon,
13
- ShareIcon,
14
- TrashIcon,
15
- } from '@heroicons/react/24/outline';
16
- import {SpeakerWaveIcon} from '@heroicons/react/24/solid';
17
-
18
- const actions = [
19
- {label: 'Download', icon: ArrowDownTrayIcon},
20
- {label: 'Share', icon: ShareIcon},
21
- {label: 'Delete', icon: TrashIcon},
22
- ] as const;
23
-
24
- /**
25
- * VisuallyHidden is invisible by design, so this hero teaches the concept by
26
- * contrast: the icon-only buttons are all a sighted user sees, while the
27
- * caption spells out the accessible name each one exposes. A live
28
- * <VisuallyHidden> region below announces the same names to assistive tech,
29
- * so the demo genuinely exercises the component it documents.
30
- */
31
- export default function VisuallyHiddenShowcase() {
32
- return (
33
- <VStack gap={5} hAlign="center">
34
- <HStack gap={6} vAlign="stretch" wrap="wrap" hAlign="center">
35
- <Card variant="muted">
36
- <VStack gap={4} hAlign="center">
37
- <Text type="supporting" color="secondary">
38
- What you see
39
- </Text>
40
- <HStack gap={2}>
41
- {actions.map(({label, icon}) => (
42
- <IconButton
43
- key={label}
44
- label={label}
45
- icon={<Icon icon={icon} />}
46
- variant="ghost"
47
- />
48
- ))}
49
- </HStack>
50
- </VStack>
51
- </Card>
52
-
53
- <Card variant="muted">
54
- <VStack gap={4} hAlign="start">
55
- <HStack gap={2} vAlign="center">
56
- <Icon icon={SpeakerWaveIcon} size="sm" />
57
- <Text type="supporting" color="secondary">
58
- What a screen reader hears
59
- </Text>
60
- </HStack>
61
- <VStack gap={2}>
62
- {actions.map(({label}) => (
63
- <Text key={label} type="body">
64
- {label}, button
65
- </Text>
66
- ))}
67
- </VStack>
68
- </VStack>
69
- </Card>
70
- </HStack>
71
-
72
- {/* A real live region: silent to sighted users, announced by AT. */}
73
- <VisuallyHidden as="div" aria-live="polite">
74
- Actions available: Download, Share, Delete.
75
- </VisuallyHidden>
76
- </VStack>
77
- );
78
- }
@@ -1,14 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
- export const doc = {
5
- type: 'block',
6
- exampleFor: 'VisuallyHidden',
7
- name: 'VisuallyHidden — Structural Heading',
8
- displayName: 'VisuallyHidden — Structural Heading',
9
- description:
10
- 'Give a visually implicit section an accessible name so screen-reader users can navigate to it.',
11
- isReady: true,
12
- aspectRatio: 4 / 3,
13
- componentsUsed: ['VisuallyHidden', 'Card', 'HStack', 'VStack', 'Text', 'Badge'],
14
- };
@@ -1,38 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- 'use client';
4
-
5
- import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
6
- import {Card} from '@astryxdesign/core/Card';
7
- import {HStack, VStack} from '@astryxdesign/core/Layout';
8
- import {Text} from '@astryxdesign/core/Text';
9
- import {Badge} from '@astryxdesign/core/Badge';
10
-
11
- const items = [
12
- {name: 'astryx-core', status: 'Passing', variant: 'success'},
13
- {name: 'astryx-charts', status: 'Failing', variant: 'error'},
14
- {name: 'astryx-cli', status: 'Passing', variant: 'success'},
15
- ] as const;
16
-
17
- export default function VisuallyHiddenStructuralHeading() {
18
- return (
19
- <VStack gap={3} hAlign="start">
20
- <Text type="supporting" color="secondary">
21
- The layout makes this group obvious to sighted users. A hidden heading
22
- gives screen-reader users the same landmark to jump to.
23
- </Text>
24
- {/* No visible heading is needed here, but AT users navigate by heading. */}
25
- <VisuallyHidden as="h2">Build status</VisuallyHidden>
26
- <VStack gap={2}>
27
- {items.map(({name, status, variant}) => (
28
- <Card key={name} variant="muted" padding={3}>
29
- <HStack gap={3} vAlign="center">
30
- <Text type="body">{name}</Text>
31
- <Badge label={status} variant={variant} />
32
- </HStack>
33
- </Card>
34
- ))}
35
- </VStack>
36
- </VStack>
37
- );
38
- }
@@ -1,14 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- /** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
4
- export const doc = {
5
- type: 'block',
6
- exampleFor: 'VisuallyHidden',
7
- name: 'VisuallyHidden — Supplementary Context',
8
- displayName: 'VisuallyHidden — Supplementary Context',
9
- description:
10
- 'Add screen-reader-only context to terse visual data, like spelling out what a trend arrow means.',
11
- isReady: true,
12
- aspectRatio: 4 / 3,
13
- componentsUsed: ['VisuallyHidden', 'Card', 'HStack', 'VStack', 'Text', 'Icon'],
14
- };
@@ -1,47 +0,0 @@
1
- // Copyright (c) Meta Platforms, Inc. and affiliates.
2
-
3
- 'use client';
4
-
5
- import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
6
- import {Card} from '@astryxdesign/core/Card';
7
- import {HStack, VStack} from '@astryxdesign/core/Layout';
8
- import {Text} from '@astryxdesign/core/Text';
9
- import {Icon} from '@astryxdesign/core/Icon';
10
- import {ArrowUpIcon, ArrowDownIcon} from '@heroicons/react/24/solid';
11
-
12
- const stats = [
13
- {label: 'Revenue', value: '$48.2k', delta: '+12%', direction: 'up'},
14
- {label: 'Churn', value: '2.1%', delta: '-4%', direction: 'down'},
15
- ] as const;
16
-
17
- export default function VisuallyHiddenSupplementaryContext() {
18
- return (
19
- <HStack gap={4} wrap="wrap">
20
- {stats.map(({label, value, delta, direction}) => (
21
- <Card key={label} variant="muted">
22
- <VStack gap={1}>
23
- <Text type="supporting" color="secondary">
24
- {label}
25
- </Text>
26
- <Text type="display-3">{value}</Text>
27
- <HStack gap={1} vAlign="center">
28
- <Icon
29
- icon={direction === 'up' ? ArrowUpIcon : ArrowDownIcon}
30
- size="sm"
31
- color={direction === 'up' ? 'accent' : 'secondary'}
32
- />
33
- <Text type="body">
34
- {delta}
35
- {/* The arrow is decorative; spell out the trend for AT. */}
36
- <VisuallyHidden>
37
- {direction === 'up' ? ' increase' : ' decrease'} from last
38
- month
39
- </VisuallyHidden>
40
- </Text>
41
- </HStack>
42
- </VStack>
43
- </Card>
44
- ))}
45
- </HStack>
46
- );
47
- }