@astryxdesign/cli 0.1.1 → 0.1.2-canary.043f3fd

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 (185) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/docs/theme.doc.mjs +2 -2
  3. package/docs/working-with-ai.doc.mjs +6 -6
  4. package/package.json +31 -8
  5. package/src/api/component.mjs +253 -12
  6. package/src/api/discover.mjs +87 -28
  7. package/src/api/doctor.mjs +7 -22
  8. package/src/api/index.mjs +1 -0
  9. package/src/api/layout.mjs +302 -0
  10. package/src/api/layout.test.mjs +241 -0
  11. package/src/api/template-integration.test.mjs +225 -0
  12. package/src/api/template.mjs +421 -122
  13. package/src/api/template.test.mjs +2 -0
  14. package/src/api/theme-add.mjs +182 -0
  15. package/src/api/validate-integration.mjs +370 -0
  16. package/src/api/validate-integration.test.mjs +222 -0
  17. package/src/codemod.mjs +93 -0
  18. package/src/codemod.test.mjs +134 -0
  19. package/src/codemods/__tests__/registry.test.mjs +2 -0
  20. package/src/codemods/__tests__/runner.test.mjs +103 -0
  21. package/src/codemods/integration-discovery.mjs +168 -0
  22. package/src/codemods/integration-discovery.test.mjs +234 -0
  23. package/src/codemods/integration-runner.mjs +109 -0
  24. package/src/codemods/registry.mjs +2 -0
  25. package/src/codemods/run-codemod.mjs +207 -0
  26. package/src/codemods/runner.mjs +73 -96
  27. package/src/codemods/transforms/v0.0.15/index.mjs +0 -13
  28. package/src/codemods/transforms/v0.1.0/__tests__/v0.1.0-ordering.test.mjs +81 -0
  29. package/src/codemods/transforms/{v0.0.15 → v0.1.0}/drop-xds-prefix-imports.mjs +15 -4
  30. package/src/codemods/transforms/v0.1.0/index.mjs +15 -6
  31. package/src/codemods/transforms/v0.1.2/__tests__/rename-text-color-active-to-accent.test.mjs +120 -0
  32. package/src/codemods/transforms/v0.1.2/index.mjs +19 -0
  33. package/src/codemods/transforms/v0.1.2/rename-text-color-active-to-accent.mjs +136 -0
  34. package/src/codemods/transforms/v0.1.3/__tests__/migrate-layout-components-to-experimental.test.mjs +360 -0
  35. package/src/codemods/transforms/v0.1.3/index.mjs +19 -0
  36. package/src/codemods/transforms/v0.1.3/migrate-layout-components-to-experimental.mjs +260 -0
  37. package/src/commands/build-theme.import-path.test.mjs +22 -2
  38. package/src/commands/build-theme.mjs +185 -16
  39. package/src/commands/component/index.mjs +44 -10
  40. package/src/commands/component-ownership.test.mjs +227 -0
  41. package/src/commands/discover.mjs +5 -16
  42. package/src/commands/doctor.test.mjs +3 -3
  43. package/src/commands/init.mjs +34 -8
  44. package/src/commands/init.next-steps.test.mjs +46 -0
  45. package/src/commands/json-contract.test.mjs +0 -32
  46. package/src/commands/layout.mjs +139 -0
  47. package/src/commands/swizzle.mjs +241 -224
  48. package/src/commands/swizzle.path-safety.test.mjs +3 -3
  49. package/src/commands/swizzle.routing.test.mjs +279 -0
  50. package/src/commands/template.mjs +33 -37
  51. package/src/commands/upgrade.config-ordering.test.mjs +273 -0
  52. package/src/commands/upgrade.integration-policy.test.mjs +204 -0
  53. package/src/commands/upgrade.mjs +349 -239
  54. package/src/commands/validate-integration.mjs +110 -0
  55. package/src/commands/validate-integration.test.mjs +124 -0
  56. package/src/config.mjs +18 -0
  57. package/src/config.test.mjs +100 -0
  58. package/src/index.mjs +13 -3
  59. package/src/integration.mjs +19 -0
  60. package/src/lib/component-discovery.mjs +177 -0
  61. package/src/lib/config-cache.mjs +91 -0
  62. package/src/lib/config-cache.test.mjs +83 -0
  63. package/src/lib/config-schema.mjs +105 -0
  64. package/src/lib/error-codes.mjs +18 -12
  65. package/src/lib/integration-warnings.mjs +62 -0
  66. package/src/lib/integration-warnings.test.mjs +102 -0
  67. package/src/lib/integrations.mjs +132 -0
  68. package/src/lib/integrations.test.mjs +135 -0
  69. package/src/lib/levenshtein.mjs +29 -0
  70. package/src/lib/manifest.mjs +15 -2
  71. package/src/lib/module-loader.mjs +80 -0
  72. package/src/lib/module-loader.test.mjs +106 -0
  73. package/src/lib/package-scanner.mjs +31 -7
  74. package/src/lib/project.mjs +502 -0
  75. package/src/lib/project.test.mjs +308 -0
  76. package/src/lib/string-utils.mjs +5 -14
  77. package/src/lib/xle/browser.d.ts +100 -0
  78. package/src/lib/xle/browser.mjs +120 -0
  79. package/src/lib/xle/expand.mjs +622 -0
  80. package/src/lib/xle/parse.mjs +581 -0
  81. package/src/lib/xle/print.mjs +174 -0
  82. package/src/lib/xle/registry-core.mjs +170 -0
  83. package/src/lib/xle/registry.mjs +237 -0
  84. package/src/lib/xle/splice.mjs +137 -0
  85. package/src/lib/xle/validate.mjs +356 -0
  86. package/src/lib/xle/xle.test.mjs +333 -0
  87. package/src/template.mjs +73 -0
  88. package/src/template.test.mjs +127 -0
  89. package/src/types/api.d.ts +2 -6
  90. package/src/types/base.d.ts +3 -9
  91. package/src/types/codemod.d.ts +81 -0
  92. package/src/types/component.d.ts +27 -2
  93. package/src/types/config.d.ts +70 -0
  94. package/src/types/error-codes.d.ts +5 -3
  95. package/src/types/index.d.ts +0 -1
  96. package/src/types/integration.d.ts +29 -0
  97. package/src/types/swizzle.d.ts +9 -2
  98. package/src/types/template-api.d.ts +54 -0
  99. package/src/types/template.d.ts +10 -7
  100. package/src/types/upgrade.d.ts +29 -0
  101. package/src/types/validate-integration.d.ts +24 -0
  102. package/src/utils/github.mjs +0 -252
  103. package/src/utils/interactive.mjs +2 -2
  104. package/templates/blocks/components/Card/ClickableCardWithNestedButton.doc.mjs +1 -1
  105. package/templates/blocks/components/Card/SelectableCardMulti.doc.mjs +1 -1
  106. package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerWithProgress.tsx +1 -1
  107. package/templates/blocks/components/ChatDictationButton/ChatDictationButtonShowcase.tsx +3 -3
  108. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.doc.mjs +15 -0
  109. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.tsx +26 -0
  110. package/templates/blocks/components/DateInput/DateInputDateRange.doc.mjs +2 -2
  111. package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.doc.mjs +14 -0
  112. package/templates/blocks/components/DateRangeInput/DateRangeInputWithPresets.tsx +46 -0
  113. package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.doc.mjs +14 -0
  114. package/templates/blocks/components/DateRangeInput/DateRangeInputWithValidation.tsx +52 -0
  115. package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.doc.mjs +14 -0
  116. package/templates/blocks/components/DateTimeInput/DateTimeInputWithValidation.tsx +43 -0
  117. package/templates/blocks/components/FileInput/FileInputShowcase.tsx +4 -2
  118. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.doc.mjs +1 -1
  119. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +9 -4
  120. package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.doc.mjs +14 -0
  121. package/templates/blocks/components/LinkProvider/LinkProviderCustomLink.tsx +43 -0
  122. package/templates/blocks/components/MultiSelector/MultiSelectorShowcase.tsx +6 -2
  123. package/templates/blocks/components/NumberInput/NumberInputShowcase.tsx +6 -2
  124. package/templates/blocks/components/Outline/OutlineShowcase.doc.mjs +15 -0
  125. package/templates/blocks/components/Outline/OutlineShowcase.tsx +22 -0
  126. package/templates/blocks/components/RadioList/RadioListShowcase.tsx +8 -1
  127. package/templates/blocks/components/SegmentedControl/SegmentedControlShowcase.tsx +3 -1
  128. package/templates/blocks/components/Selector/SelectorShowcase.tsx +4 -1
  129. package/templates/blocks/components/Slider/SliderShowcase.tsx +10 -1
  130. package/templates/blocks/components/Tab/TabShowcase.tsx +3 -1
  131. package/templates/blocks/components/Tab/TabWithSelectedIcon.doc.mjs +13 -0
  132. package/templates/blocks/components/Tab/TabWithSelectedIcon.tsx +39 -0
  133. package/templates/blocks/components/TabList/TabListShowcase.tsx +3 -1
  134. package/templates/blocks/components/TabMenu/TabMenuShowcase.tsx +3 -1
  135. package/templates/blocks/components/Table/ColumnResizeHookUsage.doc.mjs +14 -0
  136. package/templates/blocks/components/Table/ColumnResizeHookUsage.tsx +59 -0
  137. package/templates/blocks/components/Table/StickyColumnsHookUsage.doc.mjs +14 -0
  138. package/templates/blocks/components/Table/StickyColumnsHookUsage.tsx +104 -0
  139. package/templates/blocks/components/Text/TextColors.tsx +20 -5
  140. package/templates/blocks/components/TextArea/TextAreaShowcase.tsx +4 -2
  141. package/templates/blocks/components/TextInput/TextInputShowcase.tsx +4 -2
  142. package/templates/blocks/components/Thumbnail/ThumbnailDisabled.tsx +11 -6
  143. package/templates/blocks/components/Thumbnail/ThumbnailGallery.tsx +43 -7
  144. package/templates/blocks/components/Thumbnail/ThumbnailRemovable.tsx +40 -3
  145. package/templates/blocks/components/Thumbnail/ThumbnailShowcase.tsx +6 -5
  146. package/templates/blocks/components/Thumbnail/ThumbnailStates.tsx +11 -6
  147. package/templates/blocks/components/Timestamp/TimestampColors.tsx +2 -2
  148. package/templates/blocks/components/ToggleButton/ToggleButtonGroup.doc.mjs +1 -1
  149. package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +8 -6
  150. package/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +2 -2
  151. package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +23 -14
  152. package/templates/blocks/components/Typeahead/TypeaheadShowcase.tsx +6 -2
  153. package/templates/pages/shell-nav/page.tsx +321 -0
  154. package/templates/pages/shell-nav/template.doc.mjs +12 -0
  155. package/templates/pages/shell-side-nav/page.tsx +242 -0
  156. package/templates/pages/shell-side-nav/template.doc.mjs +12 -0
  157. package/templates/pages/shell-top-nav/page.tsx +224 -0
  158. package/templates/pages/shell-top-nav/template.doc.mjs +12 -0
  159. package/templates/pages/theme-showcase/page.tsx +8 -19
  160. package/templates/themes/butter/butterTheme.ts +916 -0
  161. package/templates/themes/butter/icons.tsx +77 -0
  162. package/templates/themes/chocolate/chocolateTheme.ts +230 -0
  163. package/templates/themes/chocolate/icons.tsx +77 -0
  164. package/templates/themes/gothic/gothicTheme.ts +657 -0
  165. package/templates/themes/gothic/icons.tsx +77 -0
  166. package/templates/themes/manifest.json +90 -0
  167. package/templates/themes/matcha/icons.tsx +67 -0
  168. package/templates/themes/matcha/matchaTheme.ts +247 -0
  169. package/templates/themes/neutral/icons.tsx +77 -0
  170. package/templates/themes/neutral/neutralTheme.ts +603 -0
  171. package/templates/themes/stone/icons.tsx +77 -0
  172. package/templates/themes/stone/stoneTheme.ts +652 -0
  173. package/templates/themes/y2k/icons.tsx +67 -0
  174. package/templates/themes/y2k/y2kTheme.ts +617 -0
  175. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-config-surfaces.test.mjs +0 -116
  176. package/src/codemods/transforms/v0.1.0/migrate-xds-config-surfaces.mjs +0 -230
  177. package/src/commands/gap-report.mjs +0 -456
  178. package/src/commands/gap-report.test.mjs +0 -163
  179. package/src/commands/swizzle-gap-safety.test.mjs +0 -273
  180. package/src/lib/config.mjs +0 -86
  181. package/src/lib/config.test.mjs +0 -42
  182. package/src/types/gap-report.d.ts +0 -29
  183. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.doc.mjs +0 -14
  184. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +0 -57
  185. /package/src/codemods/transforms/{v0.0.15 → v0.1.0}/__tests__/drop-xds-prefix-imports.test.mjs +0 -0
@@ -19,7 +19,7 @@ export default function ChatDictationButtonShowcase() {
19
19
  const dictation = useChatDictation({
20
20
  inputRef,
21
21
  hasSounds: true,
22
- onResult: (text) => {
22
+ onResult: text => {
23
23
  console.log('Dictation result:', text);
24
24
  },
25
25
  });
@@ -31,7 +31,7 @@ export default function ChatDictationButtonShowcase() {
31
31
  input.
32
32
  </Text>
33
33
  <ChatComposer
34
- onSubmit={(v) => console.log('Submit:', v)}
34
+ onSubmit={v => console.log('Submit:', v)}
35
35
  input={<ChatComposerInput handleRef={inputRef} />}
36
36
  sendActions={<ChatDictationButton dictation={dictation} />}
37
37
  />
@@ -63,7 +63,7 @@ export default function ChatDictationButtonShowcase() {
63
63
  </HStack>
64
64
  )}
65
65
  {!dictation.isSupported && (
66
- <Text type="supporting" color="active">
66
+ <Text type="supporting" color="accent">
67
67
  SpeechRecognition is not supported in this browser.
68
68
  </Text>
69
69
  )}
@@ -0,0 +1,15 @@
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: 'CommandPaletteEmpty',
7
+ name: 'CommandPaletteEmpty',
8
+ displayName: 'Command Palette Empty',
9
+ description:
10
+ 'Command palette empty state shown when no commands are available.',
11
+ isReady: true,
12
+ isShowcase: true,
13
+ aspectRatio: 4 / 3,
14
+ componentsUsed: ['CommandPalette', 'CommandPaletteEmpty', 'Text'],
15
+ };
@@ -0,0 +1,26 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useMemo} from 'react';
6
+ import {CommandPalette} from '@astryxdesign/core/CommandPalette';
7
+ import {Text} from '@astryxdesign/core/Text';
8
+ import {createStaticSource} from '@astryxdesign/core/Typeahead';
9
+
10
+ export default function CommandPaletteEmptyShowcase() {
11
+ const emptySource = useMemo(() => createStaticSource([]), []);
12
+
13
+ return (
14
+ <CommandPalette
15
+ isOpen
16
+ isInline
17
+ onOpenChange={() => {}}
18
+ searchSource={emptySource}
19
+ emptyBootstrapText={
20
+ <Text type="supporting" color="secondary">
21
+ No commands available yet
22
+ </Text>
23
+ }
24
+ />
25
+ );
26
+ }
@@ -4,8 +4,8 @@
4
4
  export const doc = {
5
5
  type: 'block',
6
6
  exampleFor: 'DateInput',
7
- name: 'DateInput — Date Range',
8
- displayName: 'DateInput — Date Range',
7
+ name: 'DateInput — Min/Max Constraints',
8
+ displayName: 'DateInput — Min/Max Constraints',
9
9
  description:
10
10
  'Date input constrained to a min/max window. Use when only certain dates are valid, like booking availability or a fiscal quarter.',
11
11
  isReady: true,
@@ -0,0 +1,14 @@
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: 'DateRangeInput',
7
+ name: 'DateRangeInput — With Presets',
8
+ displayName: 'DateRangeInput — With Presets',
9
+ description:
10
+ 'Date range picker with quick-select presets for common periods. Use for analytics dashboards, report filters, or any context where users frequently select standard time windows.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['DateRangeInput', 'Layout', 'Text'],
14
+ };
@@ -0,0 +1,46 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {DateRangeInput} from '@astryxdesign/core/DateRangeInput';
7
+ import type {DateRange} from '@astryxdesign/core/DateRangeInput';
8
+ import type {ISODateString} from '@astryxdesign/core/Calendar';
9
+ import {Stack} from '@astryxdesign/core/Layout';
10
+ import {Text} from '@astryxdesign/core/Text';
11
+
12
+ function daysAgo(n: number): ISODateString {
13
+ const d = new Date();
14
+ d.setDate(d.getDate() - n);
15
+ return d.toISOString().slice(0, 10) as ISODateString;
16
+ }
17
+
18
+ function today(): ISODateString {
19
+ return new Date().toISOString().slice(0, 10) as ISODateString;
20
+ }
21
+
22
+ const presets = [
23
+ {label: 'Last 7 days', getRange: () => ({start: daysAgo(7), end: today()})},
24
+ {label: 'Last 14 days', getRange: () => ({start: daysAgo(14), end: today()})},
25
+ {label: 'Last 30 days', getRange: () => ({start: daysAgo(30), end: today()})},
26
+ {label: 'Last 90 days', getRange: () => ({start: daysAgo(90), end: today()})},
27
+ ];
28
+
29
+ export default function DateRangeInputWithPresets() {
30
+ const [range, setRange] = useState<DateRange | null>(null);
31
+
32
+ return (
33
+ <Stack direction="vertical" gap={4} width="100%" style={{maxWidth: 400}}>
34
+ <Text type="supporting" color="secondary">
35
+ {range ? `${range.start} → ${range.end}` : 'No range selected'}
36
+ </Text>
37
+ <DateRangeInput
38
+ label="Report period"
39
+ description="Use a preset or pick a custom range"
40
+ value={range}
41
+ onChange={setRange}
42
+ presets={presets}
43
+ />
44
+ </Stack>
45
+ );
46
+ }
@@ -0,0 +1,14 @@
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: 'DateRangeInput',
7
+ name: 'DateRangeInput — Validation',
8
+ displayName: 'DateRangeInput — Validation',
9
+ description:
10
+ 'Date range input in all three status states: error, warning, and success. Use to surface booking conflicts, flag high-demand periods, or confirm an available range.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['DateRangeInput', 'Layout'],
14
+ };
@@ -0,0 +1,52 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {DateRangeInput} from '@astryxdesign/core/DateRangeInput';
7
+ import type {DateRange} from '@astryxdesign/core/DateRangeInput';
8
+ import {Stack} from '@astryxdesign/core/Layout';
9
+
10
+ export default function DateRangeInputWithValidation() {
11
+ const [errorRange, setErrorRange] = useState<DateRange | null>({
12
+ start: '2026-01-01',
13
+ end: '2026-01-31',
14
+ });
15
+ const [warningRange, setWarningRange] = useState<DateRange | null>({
16
+ start: '2026-06-01',
17
+ end: '2026-06-30',
18
+ });
19
+ const [successRange, setSuccessRange] = useState<DateRange | null>({
20
+ start: '2026-03-01',
21
+ end: '2026-03-31',
22
+ });
23
+
24
+ return (
25
+ <Stack direction="vertical" gap={4} width="100%" style={{maxWidth: 400}}>
26
+ <DateRangeInput
27
+ label="Booking period"
28
+ value={errorRange}
29
+ onChange={setErrorRange}
30
+ status={{
31
+ type: 'error',
32
+ message: 'Selected dates are no longer available',
33
+ }}
34
+ />
35
+ <DateRangeInput
36
+ label="Preferred period"
37
+ value={warningRange}
38
+ onChange={setWarningRange}
39
+ status={{
40
+ type: 'warning',
41
+ message: 'High demand — limited availability',
42
+ }}
43
+ />
44
+ <DateRangeInput
45
+ label="Confirmed period"
46
+ value={successRange}
47
+ onChange={setSuccessRange}
48
+ status={{type: 'success', message: 'Dates confirmed and available'}}
49
+ />
50
+ </Stack>
51
+ );
52
+ }
@@ -0,0 +1,14 @@
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: 'DateTimeInput',
7
+ name: 'DateTimeInput — Validation',
8
+ displayName: 'DateTimeInput — Validation',
9
+ description:
10
+ 'DateTimeInput in all three status states: error, warning, and success. Use to surface scheduling conflicts, caution the user about edge cases, or confirm a valid datetime.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['DateTimeInput', 'Layout'],
14
+ };
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {DateTimeInput} from '@astryxdesign/core/DateTimeInput';
7
+ import type {ISODateTimeString} from '@astryxdesign/core/DateTimeInput';
8
+ import {Stack} from '@astryxdesign/core/Layout';
9
+
10
+ export default function DateTimeInputWithValidation() {
11
+ const [errorVal, setErrorVal] = useState<ISODateTimeString | undefined>(
12
+ '2026-01-25T09:00' as ISODateTimeString,
13
+ );
14
+ const [warningVal, setWarningVal] = useState<ISODateTimeString | undefined>(
15
+ '2026-12-25T14:00' as ISODateTimeString,
16
+ );
17
+ const [successVal, setSuccessVal] = useState<ISODateTimeString | undefined>(
18
+ '2026-03-10T10:30' as ISODateTimeString,
19
+ );
20
+
21
+ return (
22
+ <Stack direction="vertical" gap={4} width="100%" style={{maxWidth: 400}}>
23
+ <DateTimeInput
24
+ label="Meeting time"
25
+ value={errorVal}
26
+ onChange={setErrorVal}
27
+ status={{type: 'error', message: 'This time slot is already booked'}}
28
+ />
29
+ <DateTimeInput
30
+ label="Preferred time"
31
+ value={warningVal}
32
+ onChange={setWarningVal}
33
+ status={{type: 'warning', message: 'This falls outside business hours'}}
34
+ />
35
+ <DateTimeInput
36
+ label="Start time"
37
+ value={successVal}
38
+ onChange={setSuccessVal}
39
+ status={{type: 'success', message: 'Time confirmed'}}
40
+ />
41
+ </Stack>
42
+ );
43
+ }
@@ -2,15 +2,17 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {FileInput} from '@astryxdesign/core/FileInput';
6
7
 
7
8
  export default function FileInputShowcase() {
9
+ const [value, setValue] = useState<File | File[] | null>(null);
8
10
  return (
9
11
  <div style={{width: 350}}>
10
12
  <FileInput
11
13
  label="Upload file"
12
- value={null}
13
- onChange={() => {}}
14
+ value={value}
15
+ onChange={setValue}
14
16
  placeholder="Drag files here or click to browse"
15
17
  />
16
18
  </div>
@@ -10,5 +10,5 @@ export const doc = {
10
10
  'Shows a page summary when hovering a link: title, description, and URL. Use for documentation links, article references, or any URL where a preview helps the user decide whether to click.',
11
11
  isReady: true,
12
12
  aspectRatio: 16 / 9,
13
- componentsUsed: ['HoverCard', 'Icon', 'Layout', 'Text'],
13
+ componentsUsed: ['HoverCard', 'Icon', 'Layout', 'Link', 'Text'],
14
14
  };
@@ -5,12 +5,14 @@
5
5
  import {HoverCard} from '@astryxdesign/core/HoverCard';
6
6
  import {Icon} from '@astryxdesign/core/Icon';
7
7
  import {VStack, HStack} from '@astryxdesign/core/Layout';
8
+ import {Link} from '@astryxdesign/core/Link';
8
9
  import {Text} from '@astryxdesign/core/Text';
9
10
  import {LinkIcon} from '@heroicons/react/24/outline';
10
11
 
11
12
  export default function HoverCardInteractiveContent() {
12
13
  return (
13
- <Text type="body">Read more in the{' '}
14
+ <Text type="body">
15
+ Read more in the{' '}
14
16
  <HoverCard
15
17
  placement="below"
16
18
  content={
@@ -30,8 +32,11 @@ export default function HoverCardInteractiveContent() {
30
32
  </HStack>
31
33
  </VStack>
32
34
  }>
33
- Getting Started Guide
34
- </HoverCard>.
35
- </Text>
35
+ <Link href="#" hasUnderline>
36
+ Getting Started Guide
37
+ </Link>
38
+ </HoverCard>
39
+ .
40
+ </Text>
36
41
  );
37
42
  }
@@ -0,0 +1,14 @@
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: 'LinkProvider',
7
+ name: 'Link Provider — Custom Link Component',
8
+ displayName: 'Link Provider — Custom Link Component',
9
+ description:
10
+ 'Routes every Astryx link through a custom component that intercepts the click, the hook frameworks like Next.js use for client-side navigation. Click the link to see the custom handler fire instead of a full-page load.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['LinkProvider', 'Link'],
14
+ };
@@ -0,0 +1,43 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import type {AnchorHTMLAttributes} from 'react';
6
+ import {Link, LinkProvider} from '@astryxdesign/core/Link';
7
+
8
+ /**
9
+ * A stand-in for a framework router link (e.g. Next.js `Link` or React
10
+ * Router `Link`). Instead of letting the browser do a full-page navigation,
11
+ * it intercepts the click and hands the destination to a custom handler —
12
+ * the same hook real routers use for client-side navigation. Here it just
13
+ * announces the target so the behavior swap is observable in the preview.
14
+ */
15
+ function RouterLink({
16
+ href,
17
+ onClick,
18
+ children,
19
+ ...props
20
+ }: AnchorHTMLAttributes<HTMLAnchorElement>) {
21
+ return (
22
+ <a
23
+ href={href}
24
+ onClick={e => {
25
+ e.preventDefault();
26
+ onClick?.(e);
27
+ alert(`RouterLink intercepted navigation to: ${href}`);
28
+ }}
29
+ {...props}>
30
+ {children}
31
+ </a>
32
+ );
33
+ }
34
+
35
+ export default function LinkProviderCustomLink() {
36
+ return (
37
+ <LinkProvider component={RouterLink}>
38
+ <Link href="/dashboard" isStandalone>
39
+ Go to dashboard
40
+ </Link>
41
+ </LinkProvider>
42
+ );
43
+ }
@@ -1,15 +1,19 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
3
6
  import {MultiSelector} from '@astryxdesign/core/MultiSelector';
4
7
 
5
8
  export default function MultiSelectorShowcase() {
9
+ const [value, setValue] = useState<string[]>([]);
6
10
  return (
7
11
  <div style={{width: 300}}>
8
12
  <MultiSelector
9
13
  label="Columns"
10
14
  options={['Name', 'Email', 'Role', 'Status', 'Created']}
11
- value={[]}
12
- onChange={() => {}}
15
+ value={value}
16
+ onChange={setValue}
13
17
  placeholder="Select columns..."
14
18
  />
15
19
  </div>
@@ -1,15 +1,19 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
3
6
  import {NumberInput} from '@astryxdesign/core/NumberInput';
4
7
 
5
8
  export default function NumberInputShowcase() {
9
+ const [value, setValue] = useState<number | null>(0);
6
10
  return (
7
11
  <div style={{width: 300}}>
8
12
  <NumberInput
9
13
  label="Quantity"
10
14
  placeholder="Enter quantity"
11
- value={0}
12
- onChange={() => {}}
15
+ value={value}
16
+ onChange={setValue}
13
17
  />
14
18
  </div>
15
19
  );
@@ -0,0 +1,15 @@
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: 'Outline',
7
+ name: 'Outline',
8
+ displayName: 'Outline',
9
+ description:
10
+ 'A document outline with the active section highlighted by the sliding indicator track.',
11
+ isReady: true,
12
+ aspectRatio: 16 / 9,
13
+ isShowcase: true,
14
+ componentsUsed: ['Outline'],
15
+ };
@@ -0,0 +1,22 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {Outline} from '@astryxdesign/core/Outline';
6
+ import type {OutlineItem} from '@astryxdesign/core/Outline';
7
+
8
+ const items: OutlineItem[] = [
9
+ {id: 'showcase-overview', label: 'Overview', level: 2},
10
+ {id: 'showcase-installation', label: 'Installation', level: 2},
11
+ {id: 'showcase-theming', label: 'Theming', level: 2},
12
+ {id: 'showcase-tokens', label: 'Tokens', level: 3},
13
+ {id: 'showcase-accessibility', label: 'Accessibility', level: 2},
14
+ ];
15
+
16
+ export default function OutlineShowcase() {
17
+ return (
18
+ <div style={{width: 240}}>
19
+ <Outline items={items} activeId="showcase-theming" />
20
+ </div>
21
+ );
22
+ }
@@ -1,10 +1,17 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
3
6
  import {RadioList, RadioListItem} from '@astryxdesign/core/RadioList';
4
7
 
5
8
  export default function RadioListShowcase() {
9
+ const [value, setValue] = useState('');
6
10
  return (
7
- <RadioList label="Notification preference" value="" onChange={() => {}}>
11
+ <RadioList
12
+ label="Notification preference"
13
+ value={value}
14
+ onChange={setValue}>
8
15
  <RadioListItem label="Email" value="email" />
9
16
  <RadioListItem label="SMS" value="sms" />
10
17
  <RadioListItem label="Push notification" value="push" />
@@ -2,14 +2,16 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {
6
7
  SegmentedControl,
7
8
  SegmentedControlItem,
8
9
  } from '@astryxdesign/core/SegmentedControl';
9
10
 
10
11
  export default function SegmentedControlShowcase() {
12
+ const [value, setValue] = useState('grid');
11
13
  return (
12
- <SegmentedControl value="grid" onChange={() => {}} label="View mode">
14
+ <SegmentedControl value={value} onChange={setValue} label="View mode">
13
15
  <SegmentedControlItem value="grid" label="Grid" />
14
16
  <SegmentedControlItem value="list" label="List" />
15
17
  <SegmentedControlItem value="table" label="Table" />
@@ -2,16 +2,19 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {Selector} from '@astryxdesign/core/Selector';
6
7
 
7
8
  export default function SelectorShowcase() {
9
+ const [value, setValue] = useState<string | undefined>();
8
10
  return (
9
11
  <Selector
10
12
  style={{width: 300}}
11
13
  label="Fruit"
12
14
  options={['Apple', 'Banana', 'Orange', 'Mango', 'Pineapple']}
13
15
  placeholder="Select a fruit..."
14
- onChange={() => {}}
16
+ value={value}
17
+ onChange={setValue}
15
18
  />
16
19
  );
17
20
  }
@@ -2,8 +2,17 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {Slider} from '@astryxdesign/core/Slider';
6
7
 
7
8
  export default function SliderShowcase() {
8
- return <Slider label="Volume" value={50} style={{width: 300}} />;
9
+ const [value, setValue] = useState(50);
10
+ return (
11
+ <Slider
12
+ label="Volume"
13
+ value={value}
14
+ onChange={setValue}
15
+ style={{width: 300}}
16
+ />
17
+ );
9
18
  }
@@ -2,12 +2,14 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {TabList, Tab} from '@astryxdesign/core/TabList';
6
7
  import {Badge} from '@astryxdesign/core/Badge';
7
8
 
8
9
  export default function TabShowcase() {
10
+ const [value, setValue] = useState('inbox');
9
11
  return (
10
- <TabList value="inbox" onChange={() => {}}>
12
+ <TabList value={value} onChange={setValue}>
11
13
  <Tab
12
14
  value="inbox"
13
15
  label="Inbox"
@@ -0,0 +1,13 @@
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: 'Tab',
7
+ name: 'Tab — Selected Icon',
8
+ displayName: 'Tab — Selected Icon',
9
+ description: 'A tab that changes its icon when selected.',
10
+ isReady: true,
11
+ aspectRatio: 4 / 3,
12
+ componentsUsed: ['TabList', 'Tab'],
13
+ };
@@ -0,0 +1,39 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {TabList, Tab} from '@astryxdesign/core/TabList';
7
+
8
+ const StarIcon = (
9
+ <svg
10
+ viewBox="0 0 16 16"
11
+ fill="none"
12
+ stroke="currentColor"
13
+ width="100%"
14
+ height="100%">
15
+ <path d="m8 1.5 2 4.1 4.5.7-3.3 3.2.8 4.5-4-2.1L4 14l.8-4.5-3.3-3.2 4.5-.7L8 1.5Z" />
16
+ </svg>
17
+ );
18
+
19
+ const SelectedStarIcon = (
20
+ <svg viewBox="0 0 16 16" fill="currentColor" width="100%" height="100%">
21
+ <path d="m8 1.5 2 4.1 4.5.7-3.3 3.2.8 4.5-4-2.1L4 14l.8-4.5-3.3-3.2 4.5-.7L8 1.5Z" />
22
+ </svg>
23
+ );
24
+
25
+ export default function TabWithSelectedIcon() {
26
+ const [value, setValue] = useState('favorites');
27
+
28
+ return (
29
+ <TabList value={value} onChange={setValue}>
30
+ <Tab
31
+ value="favorites"
32
+ label="Favorites"
33
+ icon={StarIcon}
34
+ selectedIcon={SelectedStarIcon}
35
+ />
36
+ <Tab value="recent" label="Recent" />
37
+ </TabList>
38
+ );
39
+ }
@@ -2,11 +2,13 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {TabList, Tab} from '@astryxdesign/core/TabList';
6
7
 
7
8
  export default function TabListShowcase() {
9
+ const [value, setValue] = useState('home');
8
10
  return (
9
- <TabList value="home" onChange={() => {}}>
11
+ <TabList value={value} onChange={setValue}>
10
12
  <Tab value="home" label="Home" />
11
13
  <Tab value="projects" label="Projects" />
12
14
  <Tab value="settings" label="Settings" />
@@ -2,11 +2,13 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import {useState} from 'react';
5
6
  import {TabList, Tab, TabMenu} from '@astryxdesign/core/TabList';
6
7
 
7
8
  export default function TabMenuShowcase() {
9
+ const [value, setValue] = useState('settings');
8
10
  return (
9
- <TabList value="settings" onChange={() => {}}>
11
+ <TabList value={value} onChange={setValue}>
10
12
  <Tab value="overview" label="Overview" />
11
13
  <Tab value="activity" label="Activity" />
12
14
  <TabMenu