@astryxdesign/cli 0.1.0 → 0.1.1-canary.13763f6

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 (141) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +117 -75
  3. package/bin/astryx.mjs +22 -7
  4. package/docs/getting-started.doc.mjs +11 -11
  5. package/docs/icons.doc.mjs +1 -1
  6. package/docs/migration.doc.mjs +2 -2
  7. package/docs/shape.doc.mjs +1 -1
  8. package/docs/styling.doc.mjs +3 -4
  9. package/docs/theme.doc.dense.mjs +2 -2
  10. package/docs/theme.doc.mjs +14 -0
  11. package/docs/theme.doc.zh.mjs +2 -2
  12. package/docs/working-with-ai.doc.mjs +4 -4
  13. package/package.json +8 -8
  14. package/src/api/doctor.mjs +3 -3
  15. package/src/api/search.mjs +207 -13
  16. package/src/api/template.mjs +62 -11
  17. package/src/api/template.test.mjs +2 -0
  18. package/src/codemods/__tests__/registry.test.mjs +1 -0
  19. package/src/codemods/registry.mjs +1 -0
  20. package/src/codemods/runner.mjs +105 -51
  21. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-config-surfaces.test.mjs +116 -0
  22. package/src/codemods/transforms/v0.1.0/__tests__/migrate-xds-module-specifiers.test.mjs +51 -0
  23. package/src/codemods/transforms/v0.1.0/index.mjs +28 -0
  24. package/src/codemods/transforms/v0.1.0/migrate-xds-config-surfaces.mjs +230 -0
  25. package/src/codemods/transforms/v0.1.0/migrate-xds-module-specifiers.mjs +84 -0
  26. package/src/commands/agent-docs.mjs +119 -66
  27. package/src/commands/agent-docs.path-safety.test.mjs +1 -1
  28. package/src/commands/agent-docs.test.mjs +87 -31
  29. package/src/commands/build-theme.import-path.test.mjs +1 -1
  30. package/src/commands/build-theme.path-safety.test.mjs +1 -1
  31. package/src/commands/build-theme.prose.test.mjs +1 -1
  32. package/src/commands/build.mjs +196 -0
  33. package/src/commands/component-package.test.mjs +1 -1
  34. package/src/commands/component.test.mjs +1 -1
  35. package/src/commands/docs.test.mjs +1 -1
  36. package/src/commands/doctor.test.mjs +1 -1
  37. package/src/commands/external-showcase.test.mjs +1 -1
  38. package/src/commands/init.mjs +10 -2
  39. package/src/commands/interactive-guard.test.mjs +1 -1
  40. package/src/commands/json-contract.test.mjs +10 -3
  41. package/src/commands/swizzle-gap-safety.test.mjs +1 -1
  42. package/src/commands/swizzle.path-safety.test.mjs +1 -1
  43. package/src/commands/template.path-safety.test.mjs +1 -1
  44. package/src/commands/template.test.mjs +1 -1
  45. package/src/commands/upgrade.mjs +353 -169
  46. package/src/commands/upgrade.test.mjs +41 -27
  47. package/src/index.mjs +1 -0
  48. package/src/lib/config.mjs +12 -0
  49. package/src/lib/config.test.mjs +42 -0
  50. package/src/lib/error-codes.mjs +3 -0
  51. package/src/types/error-codes.d.ts +1 -0
  52. package/src/utils/interactive.mjs +1 -1
  53. package/src/utils/interactive.test.mjs +2 -0
  54. package/src/utils/package-manager.mjs +1 -1
  55. package/src/utils/package-manager.test.mjs +1 -1
  56. package/src/utils/path-safety.test.mjs +1 -1
  57. package/src/utils/paths.test.mjs +8 -8
  58. package/src/utils/update-check.mjs +4 -26
  59. package/src/utils/update-check.test.mjs +2 -64
  60. package/templates/blocks/components/AppShell/AppShellContentOnly.tsx +1 -9
  61. package/templates/blocks/components/AppShell/AppShellShowcase.tsx +1 -10
  62. package/templates/blocks/components/AppShell/AppShellSideNavOnly.tsx +1 -9
  63. package/templates/blocks/components/AppShell/AppShellTopNavOnly.tsx +1 -9
  64. package/templates/blocks/components/AppShell/AppShellTopNavWithSideNav.tsx +1 -9
  65. package/templates/blocks/components/AppShell/AppShellWithBanner.tsx +1 -9
  66. package/templates/blocks/components/AspectRatio/AspectRatioShowcase.tsx +12 -19
  67. package/templates/blocks/components/Banner/BannerShowcase.tsx +1 -8
  68. package/templates/blocks/components/Blockquote/BlockquoteShowcase.tsx +1 -8
  69. package/templates/blocks/components/Carousel/CarouselShowcase.tsx +2 -12
  70. package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerShowcase.tsx +6 -9
  71. package/templates/blocks/components/ChatLayout/ChatLayoutPanelChat.tsx +10 -12
  72. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +1 -9
  73. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -9
  74. package/templates/blocks/components/ChatMessageList/ChatMessageListShowcase.tsx +1 -9
  75. package/templates/blocks/components/ChatMessageMetadata/ChatMessageMetadataShowcase.tsx +1 -8
  76. package/templates/blocks/components/ChatSendButton/ChatSendButtonInComposer.tsx +1 -8
  77. package/templates/blocks/components/Citation/CitationInlineText.tsx +4 -4
  78. package/templates/blocks/components/Code/CodeInlineInParagraph.tsx +1 -8
  79. package/templates/blocks/components/CodeBlock/CodeBlockBashCommand.tsx +1 -1
  80. package/templates/blocks/components/CodeBlock/CodeBlockJSONConfig.tsx +1 -1
  81. package/templates/blocks/components/CommandPaletteItem/CommandPaletteItemShowcase.tsx +9 -12
  82. package/templates/blocks/components/ContextMenu/ContextMenuShowcase.tsx +13 -15
  83. package/templates/blocks/components/Divider/DividerShowcase.tsx +1 -8
  84. package/templates/blocks/components/Divider/DividerVertical.tsx +7 -9
  85. package/templates/blocks/components/Field/FieldShowcase.tsx +1 -8
  86. package/templates/blocks/components/FormLayout/FormLayoutHorizontal.tsx +1 -6
  87. package/templates/blocks/components/Grid/GridResponsiveAutoFit.tsx +1 -9
  88. package/templates/blocks/components/HoverCard/HoverCardInlineTextHoverCard.tsx +4 -6
  89. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +1 -6
  90. package/templates/blocks/components/HoverCard/HoverCardProfileHoverCard.tsx +2 -8
  91. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -8
  92. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +2 -12
  93. package/templates/blocks/components/OverflowList/OverflowListOverflowBadges.tsx +8 -11
  94. package/templates/blocks/components/OverflowList/OverflowListOverflowDropdownActions.tsx +9 -12
  95. package/templates/blocks/components/Overlay/OverlayBottomStrip.tsx +4 -17
  96. package/templates/blocks/components/Overlay/OverlayHoverReveal.tsx +15 -16
  97. package/templates/blocks/components/Overlay/OverlayShowcase.tsx +5 -21
  98. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -14
  99. package/templates/blocks/components/Pagination/PaginationPageSize.tsx +12 -14
  100. package/templates/blocks/components/Pagination/PaginationVariants.tsx +1 -8
  101. package/templates/blocks/components/Pagination/PaginationWithTable.tsx +2 -14
  102. package/templates/blocks/components/Tokenizer/TokenizerClear.tsx +1 -6
  103. package/templates/blocks/components/Tokenizer/TokenizerCreatable.tsx +2 -7
  104. package/templates/blocks/components/Tokenizer/TokenizerEndContent.tsx +1 -6
  105. package/templates/blocks/components/Tokenizer/TokenizerIcon.tsx +1 -6
  106. package/templates/blocks/components/Tokenizer/TokenizerMaxEntries.tsx +1 -6
  107. package/templates/blocks/components/Tokenizer/TokenizerOverflow.tsx +2 -7
  108. package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +1 -6
  109. package/templates/blocks/components/Tokenizer/TokenizerStates.tsx +4 -9
  110. package/templates/blocks/components/Toolbar/ToolbarCardHeader.tsx +1 -10
  111. package/templates/blocks/components/Toolbar/ToolbarSizes.tsx +1 -8
  112. package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +1 -8
  113. package/templates/blocks/components/Toolbar/ToolbarThreeSlot.tsx +1 -10
  114. package/templates/blocks/components/Toolbar/ToolbarWithTabs.tsx +8 -11
  115. package/templates/pages/ai-chat/page.tsx +71 -64
  116. package/templates/pages/ai-chat-landing/page.tsx +8 -12
  117. package/templates/pages/centered-hero/page.tsx +13 -15
  118. package/templates/pages/classic-gallery/page.tsx +27 -34
  119. package/templates/pages/detail-page/page.tsx +18 -18
  120. package/templates/pages/documentation/page.tsx +42 -58
  121. package/templates/pages/documentation-design/page.tsx +82 -60
  122. package/templates/pages/documentation-technical/page.tsx +101 -60
  123. package/templates/pages/editor/page.tsx +42 -54
  124. package/templates/pages/file-explorer/page.tsx +13 -16
  125. package/templates/pages/form-two-column/page.tsx +13 -17
  126. package/templates/pages/gallery-hero/page.tsx +13 -15
  127. package/templates/pages/ide/page.tsx +188 -264
  128. package/templates/pages/library/page.tsx +16 -23
  129. package/templates/pages/login/page.tsx +14 -18
  130. package/templates/pages/login-card/page.tsx +14 -18
  131. package/templates/pages/login-split/page.tsx +50 -48
  132. package/templates/pages/login-sso/page.tsx +9 -13
  133. package/templates/pages/mixed-gallery/page.tsx +51 -45
  134. package/templates/pages/payment-form/page.tsx +56 -70
  135. package/templates/pages/product-detail/page.tsx +27 -33
  136. package/templates/pages/product-gallery/page.tsx +7 -13
  137. package/templates/pages/settings-dialog/page.tsx +35 -43
  138. package/templates/pages/settings-sidebar/page.tsx +39 -47
  139. package/templates/pages/side-gallery/page.tsx +6 -9
  140. package/templates/pages/table-grouped/page.tsx +11 -15
  141. package/templates/pages/theme-showcase/page.tsx +33 -37
@@ -2,27 +2,23 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import * as stylex from '@stylexjs/stylex';
6
- import {
7
- SideNav,
8
- SideNavHeading,
9
- SideNavItem,
10
- SideNavSection,
11
- } from '@astryxdesign/core/SideNav';
12
- import {Text} from '@astryxdesign/core/Text';
5
+ import type {CSSProperties} from 'react';
6
+ import {Heading, Text} from '@astryxdesign/core/Text';
13
7
  import {Button} from '@astryxdesign/core/Button';
14
8
  import {Card} from '@astryxdesign/core/Card';
9
+ import {ClickableCard} from '@astryxdesign/core/ClickableCard';
15
10
  import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
16
- import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
11
+ import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
17
12
  import {Grid} from '@astryxdesign/core/Grid';
18
- import {radiusVars} from '@astryxdesign/core/theme/tokens.stylex';
19
13
 
20
- const styles = stylex.create({
21
- previewCard: {
22
- borderRadius: radiusVars['--radius-container'],
23
- cursor: 'pointer',
24
- },
25
- });
14
+ const previewCard: CSSProperties = {
15
+ borderRadius: 'var(--radius-element)',
16
+ };
17
+ // Negative margin offsets each card's 8px padding so the grid content stays
18
+ // visually aligned while giving every card a padded hover/click target.
19
+ const cardGrid: CSSProperties = {
20
+ margin: -8,
21
+ };
26
22
 
27
23
  // ---------------------------------------------------------------------------
28
24
  // Data
@@ -213,30 +209,12 @@ const COMPONENT_CATEGORIES = [
213
209
  export default function DocumentationOverviewPage() {
214
210
  return (
215
211
  <Layout
216
- height="fill"
212
+ height="auto"
217
213
  contentWidth={1200}
218
- start={
219
- <LayoutPanel hasDivider padding={0}>
220
- <SideNav header={<SideNavHeading heading="Product Name" />}>
221
- <SideNavSection title="Navigation" isHeaderHidden>
222
- <SideNavItem label="Home" isSelected />
223
- <SideNavItem label="Getting started" />
224
- </SideNavSection>
225
-
226
- {COMPONENT_CATEGORIES.map(category => (
227
- <SideNavSection key={category.label} title={category.label}>
228
- {category.items.map(item => (
229
- <SideNavItem key={item.key} label={item.name} />
230
- ))}
231
- </SideNavSection>
232
- ))}
233
- </SideNav>
234
- </LayoutPanel>
235
- }
236
214
  content={
237
215
  <LayoutContent padding={8}>
238
216
  <VStack gap={10}>
239
- <Card variant="cyan" padding={10}>
217
+ <Card variant="gray" padding={10}>
240
218
  <HStack gap={8} vAlign="center">
241
219
  <StackItem size="fill">
242
220
  <VStack gap={4}>
@@ -246,11 +224,7 @@ export default function DocumentationOverviewPage() {
246
224
  beautiful, accessible products.
247
225
  </Text>
248
226
  <HStack>
249
- <Button
250
- label="Get started"
251
- variant="primary"
252
- size="lg"
253
- />
227
+ <Button label="Get started" variant="primary" size="lg" />
254
228
  </HStack>
255
229
  </VStack>
256
230
  </StackItem>
@@ -260,25 +234,35 @@ export default function DocumentationOverviewPage() {
260
234
 
261
235
  {COMPONENT_CATEGORIES.map(category => (
262
236
  <VStack key={category.label} gap={4}>
263
- <Text type="display-2">{category.label}</Text>
264
- <Grid columns={{minWidth: 260}} gap={8}>
237
+ <Heading level={2}>{category.label}</Heading>
238
+ <Grid
239
+ columns={{minWidth: 260}}
240
+ gap={2}
241
+ style={cardGrid}>
265
242
  {category.items.map(item => (
266
- <VStack key={item.key} gap={3}>
267
- <Card
268
- variant="muted"
269
- padding={0}
270
- minHeight={160}
271
- xstyle={styles.previewCard}
272
- />
273
- <VStack gap={0.5}>
274
- <Text type="body" weight="bold">
275
- {item.name}
276
- </Text>
277
- <Text type="body" color="secondary">
278
- {item.desc}
279
- </Text>
243
+ <ClickableCard
244
+ key={item.key}
245
+ label={`Open ${item.name}`}
246
+ onClick={() => {}}
247
+ variant="transparent"
248
+ padding={2}>
249
+ <VStack gap={3}>
250
+ <Card
251
+ variant="muted"
252
+ padding={0}
253
+ minHeight={160}
254
+ style={previewCard}
255
+ />
256
+ <VStack gap={0.5}>
257
+ <Text type="body" weight="bold">
258
+ {item.name}
259
+ </Text>
260
+ <Text type="body" color="secondary" maxLines={3}>
261
+ {item.desc}
262
+ </Text>
263
+ </VStack>
280
264
  </VStack>
281
- </VStack>
265
+ </ClickableCard>
282
266
  ))}
283
267
  </Grid>
284
268
  </VStack>
@@ -2,14 +2,7 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {useState, useMemo} from 'react';
6
- import * as stylex from '@stylexjs/stylex';
7
- import {
8
- SideNav,
9
- SideNavHeading,
10
- SideNavItem,
11
- SideNavSection,
12
- } from '@astryxdesign/core/SideNav';
5
+ import {useCallback, useState, useMemo, type CSSProperties} from 'react';
13
6
  import {Heading, Text} from '@astryxdesign/core/Text';
14
7
  import {Button} from '@astryxdesign/core/Button';
15
8
  import {IconButton} from '@astryxdesign/core/IconButton';
@@ -20,8 +13,10 @@ import {Token} from '@astryxdesign/core/Token';
20
13
  import {Banner} from '@astryxdesign/core/Banner';
21
14
  import {CodeBlock} from '@astryxdesign/core/CodeBlock';
22
15
  import {TabList, Tab} from '@astryxdesign/core/TabList';
16
+ import {Selector} from '@astryxdesign/core/Selector';
23
17
  import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
24
18
  import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
19
+ import {useMediaQuery} from '@astryxdesign/core/hooks';
25
20
  import {Dialog, DialogHeader} from '@astryxdesign/core/Dialog';
26
21
  import {Divider} from '@astryxdesign/core/Divider';
27
22
  import {Tooltip} from '@astryxdesign/core/Tooltip';
@@ -29,15 +24,31 @@ import {Table, pixel} from '@astryxdesign/core/Table';
29
24
  import {Icon} from '@astryxdesign/core/Icon';
30
25
  import {Section} from '@astryxdesign/core/Section';
31
26
  import {Center} from '@astryxdesign/core/Center';
27
+ import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
32
28
  import {
33
29
  ArrowTopRightOnSquareIcon,
34
30
  ArrowsPointingOutIcon,
35
31
  PlusIcon,
36
32
  } from '@heroicons/react/24/outline';
37
33
 
38
- const styles = stylex.create({
39
- tabListFlush: {marginInlineStart: '-12px'},
40
- });
34
+ const tabListFlush: CSSProperties = {marginInlineStart: '-12px'};
35
+ const outlinePanel: CSSProperties = {
36
+ position: 'sticky',
37
+ top: 24,
38
+ alignSelf: 'start',
39
+ paddingBlockStart: 120,
40
+ };
41
+
42
+ const COMPONENT_OUTLINE_ITEMS: OutlineItem[] = [
43
+ {id: 'usage', label: 'Usage', level: 2},
44
+ {id: 'best-practices', label: 'Best practices', level: 3},
45
+ {id: 'examples', label: 'Examples', level: 2},
46
+ ];
47
+
48
+ const COMPONENT_OUTLINE_OPTIONS = COMPONENT_OUTLINE_ITEMS.map(item => ({
49
+ value: item.id,
50
+ label: item.label,
51
+ }));
41
52
 
42
53
  // ---------------------------------------------------------------------------
43
54
  // DialogPreview — stateful dialog preview for component previews
@@ -493,14 +504,21 @@ function getComponentDocs(key: string) {
493
504
  // ComponentDetailView
494
505
  // ---------------------------------------------------------------------------
495
506
 
496
- function ComponentDetailView({
497
- activeNav,
498
- nav,
499
- }: {
500
- activeNav: string;
501
- nav: React.ReactNode;
502
- }) {
507
+ function ComponentDetailView({activeNav}: {activeNav: string}) {
503
508
  const [exampleTabs, setExampleTabs] = useState<Record<string, string>>({});
509
+ const [activeId, setActiveId] = useState<string | undefined>(
510
+ COMPONENT_OUTLINE_ITEMS[0]?.id,
511
+ );
512
+ const isMobile = useMediaQuery('(max-width: 768px)');
513
+
514
+ const scrollToId = useCallback((id: string) => {
515
+ setActiveId(id);
516
+ const target = document.getElementById(id);
517
+ if (target != null) {
518
+ target.scrollIntoView({behavior: 'smooth', block: 'start'});
519
+ window.history.pushState(null, '', `#${id}`);
520
+ }
521
+ }, []);
504
522
 
505
523
  const EXAMPLE_PREVIEWS: Record<string, React.ReactNode[]> = {
506
524
  button: [
@@ -556,25 +574,42 @@ function ComponentDetailView({
556
574
 
557
575
  return (
558
576
  <Layout
559
- height="fill"
577
+ height="auto"
560
578
  contentWidth={960}
561
- start={
562
- <LayoutPanel hasDivider padding={0}>
563
- {nav}
564
- </LayoutPanel>
579
+ end={
580
+ isMobile ? undefined : (
581
+ <LayoutPanel
582
+ isScrollable={false}
583
+ label="On this page"
584
+ role="complementary"
585
+ style={outlinePanel}>
586
+ <Outline
587
+ items={COMPONENT_OUTLINE_ITEMS}
588
+ onActiveIdChange={setActiveId}
589
+ />
590
+ </LayoutPanel>
591
+ )
565
592
  }
566
593
  content={
567
- <LayoutContent padding={8}>
594
+ <LayoutContent isScrollable={false} padding={8}>
568
595
  <VStack gap={8}>
569
596
  <VStack gap={2}>
570
597
  <Text type="display-1">{getComponentName(activeNav)}</Text>
571
598
  <Text type="supporting" color="secondary">
572
599
  March 30, 2026 · Updated 5:40 p.m. PST
573
600
  </Text>
601
+ {isMobile && (
602
+ <Selector
603
+ label="On this page"
604
+ isLabelHidden
605
+ options={COMPONENT_OUTLINE_OPTIONS}
606
+ value={activeId}
607
+ onChange={scrollToId}
608
+ width="100%"
609
+ />
610
+ )}
574
611
  </VStack>
575
612
 
576
- <Divider />
577
-
578
613
  <Card variant="muted" padding={0}>
579
614
  <Center height={360}>
580
615
  {COMPONENT_PREVIEWS[activeNav] ?? (
@@ -586,13 +621,18 @@ function ComponentDetailView({
586
621
  </Card>
587
622
 
588
623
  <VStack gap={4}>
589
- <Heading level={2}>Usage</Heading>
624
+ <Heading id="usage" level={2}>
625
+ Usage
626
+ </Heading>
590
627
  <Text type="large" weight="normal">
591
628
  {docs.usage}
592
629
  </Text>
593
- <Heading level={3}>Best practices</Heading>
630
+ <Heading id="best-practices" level={3}>
631
+ Best practices
632
+ </Heading>
594
633
  <Table
595
634
  data={docs.bestPractices as Record<string, unknown>[]}
635
+ dividers="none"
596
636
  columns={[
597
637
  {
598
638
  key: 'type',
@@ -616,14 +656,15 @@ function ComponentDetailView({
616
656
  },
617
657
  ]}
618
658
  density="spacious"
619
- dividers="rows"
620
659
  />
621
660
  </VStack>
622
661
 
623
662
  <Divider />
624
663
 
625
664
  <VStack gap={4}>
626
- <Heading level={2}>Examples</Heading>
665
+ <Heading id="examples" level={2}>
666
+ Examples
667
+ </Heading>
627
668
  <Text type="large" weight="normal">
628
669
  Explore common configurations, variations, and states for this
629
670
  component.
@@ -675,17 +716,24 @@ function ComponentDetailView({
675
716
  <TabList
676
717
  value={activeTab}
677
718
  onChange={value =>
678
- setExampleTabs(prev => ({...prev, [tabKey]: value}))
719
+ setExampleTabs(prev => ({
720
+ ...prev,
721
+ [tabKey]: value,
722
+ }))
679
723
  }
680
724
  size="sm"
681
- xstyle={styles.tabListFlush}>
725
+ style={tabListFlush}>
682
726
  <Tab value="description" label="Description" />
683
727
  <Tab value="code" label="Code" />
684
728
  </TabList>
685
729
  {activeTab === 'description' ? (
686
730
  <Text type="body">{example.description}</Text>
687
731
  ) : (
688
- <CodeBlock code={example.code} language="tsx" />
732
+ <CodeBlock
733
+ code={example.code}
734
+ language="tsx"
735
+ width="100%"
736
+ />
689
737
  )}
690
738
  </VStack>
691
739
  </Section>
@@ -705,31 +753,5 @@ function ComponentDetailView({
705
753
  // ---------------------------------------------------------------------------
706
754
 
707
755
  export default function DesignDocumentationPage() {
708
- const [activePage, setActivePage] = useState<string>('button');
709
-
710
- return (
711
- <ComponentDetailView
712
- activeNav={activePage}
713
- nav={
714
- <SideNav header={<SideNavHeading heading="Product Name" />}>
715
- {COMPONENT_CATEGORIES.map(category => (
716
- <SideNavSection key={category.label} title={category.label}>
717
- {category.items.map(item => (
718
- <SideNavItem
719
- key={item.key}
720
- label={item.name}
721
- isSelected={activePage === item.key}
722
- onClick={
723
- item.key === 'button'
724
- ? () => setActivePage(item.key)
725
- : undefined
726
- }
727
- />
728
- ))}
729
- </SideNavSection>
730
- ))}
731
- </SideNav>
732
- }
733
- />
734
- );
756
+ return <ComponentDetailView activeNav="button" />;
735
757
  }
@@ -2,22 +2,20 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {
6
- SideNav,
7
- SideNavHeading,
8
- SideNavItem,
9
- SideNavSection,
10
- } from '@astryxdesign/core/SideNav';
5
+ import {useCallback, useState, type CSSProperties} from 'react';
11
6
  import {Heading, Text} from '@astryxdesign/core/Text';
12
7
  import {Button} from '@astryxdesign/core/Button';
13
8
  import {Card} from '@astryxdesign/core/Card';
14
9
  import {DropdownMenu} from '@astryxdesign/core/DropdownMenu';
15
10
  import {List, ListItem} from '@astryxdesign/core/List';
16
11
  import {CodeBlock} from '@astryxdesign/core/CodeBlock';
12
+ import {Selector} from '@astryxdesign/core/Selector';
17
13
  import {HStack, VStack, StackItem} from '@astryxdesign/core/Stack';
18
14
  import {Layout, LayoutContent, LayoutPanel} from '@astryxdesign/core/Layout';
19
15
  import {Divider} from '@astryxdesign/core/Divider';
20
16
  import {Icon} from '@astryxdesign/core/Icon';
17
+ import {Outline, type OutlineItem} from '@astryxdesign/core/Outline';
18
+ import {useMediaQuery} from '@astryxdesign/core/hooks';
21
19
  import {
22
20
  SparklesIcon,
23
21
  ClipboardDocumentIcon,
@@ -28,35 +26,73 @@ import {
28
26
  // Main component
29
27
  // ---------------------------------------------------------------------------
30
28
 
29
+ const OUTLINE_ITEMS: OutlineItem[] = [
30
+ {id: 'prerequisites', label: 'Prerequisites', level: 2},
31
+ {id: 'install-package', label: 'Install the package', level: 2},
32
+ {id: 'configure-theming', label: 'Configure theming', level: 2},
33
+ {id: 'next-steps', label: 'Next steps', level: 2},
34
+ ];
35
+
36
+ const OUTLINE_OPTIONS = OUTLINE_ITEMS.map(item => ({
37
+ value: item.id,
38
+ label: item.label,
39
+ }));
40
+
41
+ const outlinePanel: CSSProperties = {
42
+ position: 'sticky',
43
+ top: 24,
44
+ alignSelf: 'start',
45
+ paddingBlockStart: 120,
46
+ };
47
+
31
48
  export default function TechnicalDocumentationPage() {
49
+ const [activeId, setActiveId] = useState<string | undefined>(
50
+ OUTLINE_ITEMS[0]?.id,
51
+ );
52
+ const isMobile = useMediaQuery('(max-width: 768px)');
53
+
54
+ const scrollToId = useCallback((id: string) => {
55
+ setActiveId(id);
56
+ const target = document.getElementById(id);
57
+ if (target != null) {
58
+ target.scrollIntoView({behavior: 'smooth', block: 'start'});
59
+ window.history.pushState(null, '', `#${id}`);
60
+ }
61
+ }, []);
62
+
32
63
  return (
33
64
  <Layout
34
- height="fill"
65
+ height="auto"
35
66
  contentWidth={960}
36
- start={
37
- <LayoutPanel hasDivider padding={0}>
38
- <SideNav header={<SideNavHeading heading="Product Name" />}>
39
- <SideNavSection title="Navigation" isHeaderHidden>
40
- <SideNavItem label="Home" />
41
- <SideNavItem label="Getting started" isSelected />
42
- </SideNavSection>
43
- </SideNav>
44
- </LayoutPanel>
67
+ end={
68
+ isMobile ? undefined : (
69
+ <LayoutPanel
70
+ isScrollable={false}
71
+ label="On this page"
72
+ role="complementary"
73
+ style={outlinePanel}>
74
+ <Outline items={OUTLINE_ITEMS} onActiveIdChange={setActiveId} />
75
+ </LayoutPanel>
76
+ )
45
77
  }
46
78
  content={
47
- <LayoutContent padding={8}>
79
+ <LayoutContent isScrollable={false} padding={8}>
48
80
  <VStack gap={8}>
49
81
  <VStack gap={2}>
50
- <Text type="display-1">
51
- Getting started with Product Name
52
- </Text>
82
+ <Text type="display-1">Getting started with Product Name</Text>
53
83
  <Text type="supporting" color="secondary">
54
84
  Last updated March 30, 2026
55
85
  </Text>
56
- <Text type="body">
57
- Install the package, configure your theme, and build your first
58
- component in three steps.
59
- </Text>
86
+ {isMobile && (
87
+ <Selector
88
+ label="On this page"
89
+ isLabelHidden
90
+ options={OUTLINE_OPTIONS}
91
+ value={activeId}
92
+ onChange={scrollToId}
93
+ width="100%"
94
+ />
95
+ )}
60
96
  </VStack>
61
97
 
62
98
  <Card>
@@ -64,11 +100,7 @@ export default function TechnicalDocumentationPage() {
64
100
  <HStack gap={2} vAlign="center">
65
101
  <StackItem size="fill">
66
102
  <HStack gap={2} vAlign="center">
67
- <Icon
68
- icon={SparklesIcon}
69
- size="sm"
70
- color="secondary"
71
- />
103
+ <Icon icon={SparklesIcon} size="sm" color="secondary" />
72
104
  <Text type="body" weight="semibold">
73
105
  AI Assistance
74
106
  </Text>
@@ -103,15 +135,17 @@ export default function TechnicalDocumentationPage() {
103
135
  </HStack>
104
136
  <Text type="body" color="secondary">
105
137
  Help me get set up with Product Name. Based on my project, do
106
- the following: 1. Install @astryxdesign/core and the StyleX compiler.
107
- 2. Wrap my app in ThemeProvider. 3. Replace one existing
108
- component with an Astryx equivalent.
138
+ the following: 1. Install @astryxdesign/core and the StyleX
139
+ compiler. 2. Wrap my app in ThemeProvider. 3. Replace one
140
+ existing component with an Astryx equivalent.
109
141
  </Text>
110
142
  </VStack>
111
143
  </Card>
112
144
 
113
145
  <VStack gap={4}>
114
- <Heading level={2}>Prerequisites</Heading>
146
+ <Heading id="prerequisites" level={2}>
147
+ Prerequisites
148
+ </Heading>
115
149
  <List density="compact" listStyle="disc">
116
150
  <ListItem label="Node.js 18+" />
117
151
  <ListItem label="React 18 or 19" />
@@ -122,7 +156,9 @@ export default function TechnicalDocumentationPage() {
122
156
  <Divider />
123
157
 
124
158
  <VStack gap={4}>
125
- <Heading level={2}>Install the package</Heading>
159
+ <Heading id="install-package" level={2}>
160
+ Install the package
161
+ </Heading>
126
162
  <Text type="body">
127
163
  Every project starts with installing the core package. This
128
164
  gives you access to all components, tokens, and utilities.
@@ -131,54 +167,57 @@ export default function TechnicalDocumentationPage() {
131
167
  <Text type="body" weight="bold">
132
168
  Step 1: Install the core package
133
169
  </Text>
134
- <Card padding={0}>
135
- <CodeBlock code="npm install @astryxdesign/core" language="bash" />
136
- </Card>
170
+ <CodeBlock
171
+ code="npm install @astryxdesign/core"
172
+ language="bash"
173
+ width="100%"
174
+ />
137
175
  </VStack>
138
176
  <VStack gap={2}>
139
177
  <Text type="body" weight="bold">
140
- Step 2: Add the StyleX compiler
178
+ Step 2: Import the precompiled styles
141
179
  </Text>
142
180
  <Text type="body" color="secondary">
143
- Astryx uses StyleX for styling. Add the compiler plugin to your
144
- build configuration.
181
+ Astryx ships precompiled CSS, so there is no build plugin to
182
+ configure. Import the reset and component stylesheets once at
183
+ your app entry point.
145
184
  </Text>
146
- <Card padding={0}>
147
- <CodeBlock
148
- code="npm install @stylexjs/babel-plugin"
149
- language="bash"
150
- />
151
- </Card>
185
+ <CodeBlock
186
+ code={`import '@astryxdesign/core/reset.css';
187
+ import '@astryxdesign/core/astryx.css';`}
188
+ language="tsx"
189
+ width="100%"
190
+ />
152
191
  </VStack>
153
192
  <VStack gap={2}>
154
193
  <Text type="body" weight="bold">
155
194
  Step 3: Import your first component
156
195
  </Text>
157
- <Card padding={0}>
158
- <CodeBlock
159
- code={`import { Button } from '@astryxdesign/core/Button';
196
+ <CodeBlock
197
+ code={`import { Button } from '@astryxdesign/core/Button';
160
198
 
161
199
  export default function App() {
162
200
  return <Button label="Hello Astryx" variant="primary" />;
163
201
  }`}
164
- language="tsx"
165
- />
166
- </Card>
202
+ language="tsx"
203
+ width="100%"
204
+ />
167
205
  </VStack>
168
206
  </VStack>
169
207
 
170
208
  <Divider />
171
209
 
172
210
  <VStack gap={4}>
173
- <Heading level={2}>Configure theming</Heading>
211
+ <Heading id="configure-theming" level={2}>
212
+ Configure theming
213
+ </Heading>
174
214
  <Text type="body">
175
215
  Astryx ships with a default theme that works out of the box. To
176
216
  customize colors, typography, and spacing, wrap your app in a
177
217
  theme provider.
178
218
  </Text>
179
- <Card padding={0}>
180
- <CodeBlock
181
- code={`import { ThemeProvider } from '@astryxdesign/core/Theme';
219
+ <CodeBlock
220
+ code={`import { ThemeProvider } from '@astryxdesign/core/Theme';
182
221
 
183
222
  export default function App({ children }) {
184
223
  return (
@@ -187,9 +226,9 @@ export default function App({ children }) {
187
226
  </ThemeProvider>
188
227
  );
189
228
  }`}
190
- language="tsx"
191
- />
192
- </Card>
229
+ language="tsx"
230
+ width="100%"
231
+ />
193
232
  <Text type="body" color="secondary">
194
233
  See the theming guide for the full list of customizable tokens.
195
234
  </Text>
@@ -198,7 +237,9 @@ export default function App({ children }) {
198
237
  <Divider />
199
238
 
200
239
  <VStack gap={4}>
201
- <Heading level={2}>Next steps</Heading>
240
+ <Heading id="next-steps" level={2}>
241
+ Next steps
242
+ </Heading>
202
243
  <List density="compact" listStyle="disc">
203
244
  <ListItem label="Fundamental concepts — How theming, layout, and composition work" />
204
245
  <ListItem label="Component API reference — Props, variants, and examples for every component" />