@astryxdesign/cli 0.1.0 → 0.1.1-canary.129bf0e

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 (144) 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 +43 -9
  39. package/src/commands/init.next-steps.test.mjs +46 -0
  40. package/src/commands/interactive-guard.test.mjs +1 -1
  41. package/src/commands/json-contract.test.mjs +10 -3
  42. package/src/commands/swizzle-gap-safety.test.mjs +1 -1
  43. package/src/commands/swizzle.path-safety.test.mjs +1 -1
  44. package/src/commands/template.path-safety.test.mjs +1 -1
  45. package/src/commands/template.test.mjs +1 -1
  46. package/src/commands/upgrade.mjs +353 -169
  47. package/src/commands/upgrade.test.mjs +41 -27
  48. package/src/index.mjs +1 -0
  49. package/src/lib/config.mjs +12 -0
  50. package/src/lib/config.test.mjs +42 -0
  51. package/src/lib/error-codes.mjs +3 -0
  52. package/src/types/error-codes.d.ts +1 -0
  53. package/src/utils/interactive.mjs +1 -1
  54. package/src/utils/interactive.test.mjs +2 -0
  55. package/src/utils/package-manager.mjs +1 -1
  56. package/src/utils/package-manager.test.mjs +1 -1
  57. package/src/utils/path-safety.test.mjs +1 -1
  58. package/src/utils/paths.test.mjs +8 -8
  59. package/src/utils/update-check.mjs +4 -26
  60. package/src/utils/update-check.test.mjs +2 -64
  61. package/templates/blocks/components/AppShell/AppShellContentOnly.tsx +1 -9
  62. package/templates/blocks/components/AppShell/AppShellShowcase.tsx +1 -10
  63. package/templates/blocks/components/AppShell/AppShellSideNavOnly.tsx +1 -9
  64. package/templates/blocks/components/AppShell/AppShellTopNavOnly.tsx +1 -9
  65. package/templates/blocks/components/AppShell/AppShellTopNavWithSideNav.tsx +1 -9
  66. package/templates/blocks/components/AppShell/AppShellWithBanner.tsx +1 -9
  67. package/templates/blocks/components/AspectRatio/AspectRatioShowcase.tsx +12 -19
  68. package/templates/blocks/components/Banner/BannerShowcase.tsx +1 -8
  69. package/templates/blocks/components/Blockquote/BlockquoteShowcase.tsx +1 -8
  70. package/templates/blocks/components/Carousel/CarouselShowcase.tsx +2 -12
  71. package/templates/blocks/components/ChatComposerDrawer/ChatComposerDrawerShowcase.tsx +6 -9
  72. package/templates/blocks/components/ChatLayout/ChatLayoutPanelChat.tsx +10 -12
  73. package/templates/blocks/components/ChatMessageList/ChatMessageListDensity.tsx +1 -9
  74. package/templates/blocks/components/ChatMessageList/ChatMessageListFullFeatured.tsx +1 -9
  75. package/templates/blocks/components/ChatMessageList/ChatMessageListShowcase.tsx +1 -9
  76. package/templates/blocks/components/ChatMessageMetadata/ChatMessageMetadataShowcase.tsx +1 -8
  77. package/templates/blocks/components/ChatSendButton/ChatSendButtonInComposer.tsx +1 -8
  78. package/templates/blocks/components/Citation/CitationInlineText.tsx +4 -4
  79. package/templates/blocks/components/Code/CodeInlineInParagraph.tsx +1 -8
  80. package/templates/blocks/components/CodeBlock/CodeBlockBashCommand.tsx +1 -1
  81. package/templates/blocks/components/CodeBlock/CodeBlockJSONConfig.tsx +1 -1
  82. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.doc.mjs +15 -0
  83. package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyShowcase.tsx +26 -0
  84. package/templates/blocks/components/CommandPaletteItem/CommandPaletteItemShowcase.tsx +9 -12
  85. package/templates/blocks/components/ContextMenu/ContextMenuShowcase.tsx +13 -15
  86. package/templates/blocks/components/Divider/DividerShowcase.tsx +1 -8
  87. package/templates/blocks/components/Divider/DividerVertical.tsx +7 -9
  88. package/templates/blocks/components/Field/FieldShowcase.tsx +1 -8
  89. package/templates/blocks/components/FormLayout/FormLayoutHorizontal.tsx +1 -6
  90. package/templates/blocks/components/Grid/GridResponsiveAutoFit.tsx +1 -9
  91. package/templates/blocks/components/HoverCard/HoverCardInlineTextHoverCard.tsx +4 -6
  92. package/templates/blocks/components/HoverCard/HoverCardInteractiveContent.tsx +1 -6
  93. package/templates/blocks/components/HoverCard/HoverCardProfileHoverCard.tsx +2 -8
  94. package/templates/blocks/components/HoverCard/HoverCardShowcase.tsx +1 -8
  95. package/templates/blocks/components/MoreMenu/MoreMenuInToolbar.tsx +2 -12
  96. package/templates/blocks/components/OverflowList/OverflowListOverflowBadges.tsx +8 -11
  97. package/templates/blocks/components/OverflowList/OverflowListOverflowDropdownActions.tsx +9 -12
  98. package/templates/blocks/components/Overlay/OverlayBottomStrip.tsx +4 -17
  99. package/templates/blocks/components/Overlay/OverlayHoverReveal.tsx +15 -16
  100. package/templates/blocks/components/Overlay/OverlayShowcase.tsx +5 -21
  101. package/templates/blocks/components/Pagination/PaginationDotsCarousel.tsx +2 -14
  102. package/templates/blocks/components/Pagination/PaginationPageSize.tsx +12 -14
  103. package/templates/blocks/components/Pagination/PaginationVariants.tsx +1 -8
  104. package/templates/blocks/components/Pagination/PaginationWithTable.tsx +2 -14
  105. package/templates/blocks/components/Tokenizer/TokenizerClear.tsx +1 -6
  106. package/templates/blocks/components/Tokenizer/TokenizerCreatable.tsx +2 -7
  107. package/templates/blocks/components/Tokenizer/TokenizerEndContent.tsx +1 -6
  108. package/templates/blocks/components/Tokenizer/TokenizerIcon.tsx +1 -6
  109. package/templates/blocks/components/Tokenizer/TokenizerMaxEntries.tsx +1 -6
  110. package/templates/blocks/components/Tokenizer/TokenizerOverflow.tsx +2 -7
  111. package/templates/blocks/components/Tokenizer/TokenizerShowcase.tsx +1 -6
  112. package/templates/blocks/components/Tokenizer/TokenizerStates.tsx +4 -9
  113. package/templates/blocks/components/Toolbar/ToolbarCardHeader.tsx +1 -10
  114. package/templates/blocks/components/Toolbar/ToolbarSizes.tsx +1 -8
  115. package/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +1 -8
  116. package/templates/blocks/components/Toolbar/ToolbarThreeSlot.tsx +1 -10
  117. package/templates/blocks/components/Toolbar/ToolbarWithTabs.tsx +8 -11
  118. package/templates/pages/ai-chat/page.tsx +71 -64
  119. package/templates/pages/ai-chat-landing/page.tsx +8 -12
  120. package/templates/pages/centered-hero/page.tsx +13 -15
  121. package/templates/pages/classic-gallery/page.tsx +27 -34
  122. package/templates/pages/detail-page/page.tsx +18 -18
  123. package/templates/pages/documentation/page.tsx +42 -58
  124. package/templates/pages/documentation-design/page.tsx +82 -60
  125. package/templates/pages/documentation-technical/page.tsx +101 -60
  126. package/templates/pages/editor/page.tsx +42 -54
  127. package/templates/pages/file-explorer/page.tsx +13 -16
  128. package/templates/pages/form-two-column/page.tsx +13 -17
  129. package/templates/pages/gallery-hero/page.tsx +13 -15
  130. package/templates/pages/ide/page.tsx +188 -264
  131. package/templates/pages/library/page.tsx +16 -23
  132. package/templates/pages/login/page.tsx +14 -18
  133. package/templates/pages/login-card/page.tsx +14 -18
  134. package/templates/pages/login-split/page.tsx +50 -48
  135. package/templates/pages/login-sso/page.tsx +9 -13
  136. package/templates/pages/mixed-gallery/page.tsx +51 -45
  137. package/templates/pages/payment-form/page.tsx +56 -70
  138. package/templates/pages/product-detail/page.tsx +27 -33
  139. package/templates/pages/product-gallery/page.tsx +7 -13
  140. package/templates/pages/settings-dialog/page.tsx +35 -43
  141. package/templates/pages/settings-sidebar/page.tsx +39 -47
  142. package/templates/pages/side-gallery/page.tsx +6 -9
  143. package/templates/pages/table-grouped/page.tsx +11 -15
  144. package/templates/pages/theme-showcase/page.tsx +33 -37
@@ -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" />
@@ -2,9 +2,7 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {useState, useCallback} from 'react';
6
- import * as stylex from '@stylexjs/stylex';
7
- import {colorVars} from '@astryxdesign/core/theme/tokens.stylex';
5
+ import {useState, useCallback, type CSSProperties} from 'react';
8
6
  import {useMediaQuery} from '@astryxdesign/core/hooks';
9
7
  import {Button} from '@astryxdesign/core/Button';
10
8
  import {Card} from '@astryxdesign/core/Card';
@@ -307,42 +305,32 @@ function defaultProps(type: BlockType): Record<string, unknown> {
307
305
  // the responsive canvas max-width, a selection ring on the active block card,
308
306
  // and the circular icon chip's surface.
309
307
 
310
- const editorStyles = stylex.create({
311
- // Fill the window. Layout height="fill" is height:100%, which only resolves
312
- // against a definite height and the host's <html>/<body> don't set one, so
313
- // the layout anchors a definite viewport height itself. No background; the
314
- // host owns the page surface.
315
- page: {height: '100dvh'},
316
- // Pin the panel to a fixed 320px on desktop (so it doesn't resize to its
317
- // content when switching tabs) and full width on mobile, where it moves into
318
- // the header slot. LayoutPanel width is a single fixed value with no
319
- // responsive form, and this xstyle wins over the width prop.
320
- panelWidth: {
321
- width: {default: 320, '@media (max-width: 768px)': '100%'},
322
- flexShrink: 0,
323
- },
324
- // Canvas reflows to the chosen viewport width; VStack has no maxWidth prop.
325
- canvas: (maxWidth: number) => ({
326
- maxWidth,
327
- width: '100%',
328
- marginInline: 'auto',
329
- }),
330
- clickable: {
331
- cursor: 'pointer',
332
- },
333
- // Selection ring on the active block — Card has no `isSelected` state.
334
- selectedCard: {
335
- outline: '2px solid',
336
- outlineColor: colorVars['--color-border-blue'],
337
- outlineOffset: -2,
338
- },
339
- // Circular muted chip behind the CTA icon — Center handles the centering
340
- // and sizing; only the surface (radius + fill) needs custom CSS.
341
- iconCircle: {
342
- borderRadius: '50%',
343
- backgroundColor: colorVars['--color-background-muted'],
344
- },
308
+ // Fill the window. Layout height="fill" is height:100%, which only resolves
309
+ // against a definite height and the host's <html>/<body> don't set one, so
310
+ // the layout anchors a definite viewport height itself. No background; the
311
+ // host owns the page surface.
312
+ const pageStyle: CSSProperties = {height: '100dvh'};
313
+ // Canvas reflows to the chosen viewport width; VStack has no maxWidth prop.
314
+ const canvasStyle = (maxWidth: number): CSSProperties => ({
315
+ maxWidth,
316
+ width: '100%',
317
+ marginInline: 'auto',
345
318
  });
319
+ const clickable: CSSProperties = {
320
+ cursor: 'pointer',
321
+ };
322
+ // Selection ring on the active block — Card has no `isSelected` state.
323
+ const selectedCard: CSSProperties = {
324
+ outline: '2px solid',
325
+ outlineColor: 'var(--color-border-blue)',
326
+ outlineOffset: -2,
327
+ };
328
+ // Circular muted chip behind the CTA icon — Center handles the centering
329
+ // and sizing; only the surface (radius + fill) needs custom CSS.
330
+ const iconCircle: CSSProperties = {
331
+ borderRadius: '50%',
332
+ backgroundColor: 'var(--color-background-muted)',
333
+ };
346
334
 
347
335
  // ---------------------------------------------------------------------------
348
336
  // Properties Form
@@ -477,15 +465,15 @@ function BlockPreview({
477
465
  onSelect: () => void;
478
466
  }) {
479
467
  const {type, props} = block;
480
- const cardXstyle = [
481
- editorStyles.clickable,
482
- isSelected && editorStyles.selectedCard,
483
- ];
468
+ const cardStyle: CSSProperties = {
469
+ ...clickable,
470
+ ...(isSelected ? selectedCard : null),
471
+ };
484
472
 
485
473
  switch (type) {
486
474
  case 'hero':
487
475
  return (
488
- <Card padding={6} xstyle={cardXstyle} onClick={onSelect}>
476
+ <Card padding={6} style={cardStyle} onClick={onSelect}>
489
477
  <VStack gap={4}>
490
478
  <Heading level={2}>
491
479
  {(props.heading as string) || 'Hero Heading'}
@@ -503,7 +491,7 @@ function BlockPreview({
503
491
  case 'text':
504
492
  if (props.heading) {
505
493
  return (
506
- <Card padding={6} xstyle={cardXstyle} onClick={onSelect}>
494
+ <Card padding={6} style={cardStyle} onClick={onSelect}>
507
495
  <EmptyState
508
496
  title={props.heading as string}
509
497
  description={props.description as string}
@@ -521,7 +509,7 @@ function BlockPreview({
521
509
  );
522
510
  }
523
511
  return (
524
- <Card xstyle={cardXstyle} onClick={onSelect}>
512
+ <Card style={cardStyle} onClick={onSelect}>
525
513
  <Text type="body">
526
514
  {(props.content as string) || 'Text content goes here'}
527
515
  </Text>
@@ -530,7 +518,7 @@ function BlockPreview({
530
518
 
531
519
  case 'image':
532
520
  return (
533
- <Card xstyle={cardXstyle} onClick={onSelect}>
521
+ <Card style={cardStyle} onClick={onSelect}>
534
522
  <EmptyState
535
523
  title="Image Block"
536
524
  description="Drop an image or enter a URL"
@@ -542,7 +530,7 @@ function BlockPreview({
542
530
 
543
531
  case 'button':
544
532
  return (
545
- <Card padding={6} xstyle={cardXstyle} onClick={onSelect}>
533
+ <Card padding={6} style={cardStyle} onClick={onSelect}>
546
534
  <Center>
547
535
  <Button
548
536
  label={(props.label as string) || 'Button'}
@@ -559,7 +547,7 @@ function BlockPreview({
559
547
  case 'features': {
560
548
  const items = (props.items as Transaction[]) || [];
561
549
  return (
562
- <Card padding={6} xstyle={cardXstyle} onClick={onSelect}>
550
+ <Card padding={6} style={cardStyle} onClick={onSelect}>
563
551
  <VStack gap={4}>
564
552
  <HStack gap={3} vAlign="start" hAlign="between">
565
553
  <VStack gap={1}>
@@ -589,7 +577,7 @@ function BlockPreview({
589
577
  const cardItems =
590
578
  (props.cards as Array<{title: string; description: string}>) || [];
591
579
  return (
592
- <Card xstyle={cardXstyle} onClick={onSelect}>
580
+ <Card style={cardStyle} onClick={onSelect}>
593
581
  <VStack gap={4}>
594
582
  <Heading level={3}>Cards</Heading>
595
583
  <Divider />
@@ -609,9 +597,9 @@ function BlockPreview({
609
597
 
610
598
  case 'cta':
611
599
  return (
612
- <Card padding={6} xstyle={cardXstyle} onClick={onSelect}>
600
+ <Card padding={6} style={cardStyle} onClick={onSelect}>
613
601
  <HStack gap={4} vAlign="start">
614
- <Center width={40} height={40} xstyle={editorStyles.iconCircle}>
602
+ <Center width={40} height={40} style={iconCircle}>
615
603
  <Icon icon={LockClosedIcon} color="secondary" />
616
604
  </Center>
617
605
  <VStack gap={1}>
@@ -828,7 +816,7 @@ export default function EditorPage() {
828
816
  <LayoutPanel
829
817
  hasDivider={!isMobile}
830
818
  padding={0}
831
- xstyle={editorStyles.panelWidth}>
819
+ style={{width: isMobile ? '100%' : 320, flexShrink: 0}}>
832
820
  <VStack gap={4}>
833
821
  {/* Panel Header */}
834
822
  <Section variant="transparent" padding={4}>
@@ -919,7 +907,7 @@ export default function EditorPage() {
919
907
  return (
920
908
  <>
921
909
  <Layout
922
- xstyle={editorStyles.page}
910
+ style={pageStyle}
923
911
  height="fill"
924
912
  header={isMobile ? sidebar : undefined}
925
913
  start={isMobile ? undefined : sidebar}
@@ -927,7 +915,7 @@ export default function EditorPage() {
927
915
  <LayoutContent padding={8}>
928
916
  <VStack
929
917
  gap={4}
930
- xstyle={editorStyles.canvas(VIEWPORT_MAX[viewport])}>
918
+ style={canvasStyle(VIEWPORT_MAX[viewport])}>
931
919
  {blocks.length > 0 ? (
932
920
  blocks.map(block => (
933
921
  <BlockPreview
@@ -2,8 +2,7 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {useState, useMemo} from 'react';
6
- import * as stylex from '@stylexjs/stylex';
5
+ import {useState, useMemo, type CSSProperties} from 'react';
7
6
  import {Layout, LayoutContent} from '@astryxdesign/core/Layout';
8
7
  import {Toolbar} from '@astryxdesign/core/Toolbar';
9
8
  import {List, ListItem} from '@astryxdesign/core/List';
@@ -145,10 +144,10 @@ const FILESYSTEM: FileSystemItem[] = [
145
144
  children: [{id: 'react-index', name: 'index.js', type: 'file'}],
146
145
  },
147
146
  {
148
- id: 'stylex',
149
- name: '@stylexjs',
147
+ id: 'react-dom',
148
+ name: 'react-dom',
150
149
  type: 'folder',
151
- children: [{id: 'stylex-index', name: 'stylex.js', type: 'file'}],
150
+ children: [{id: 'react-dom-index', name: 'index.js', type: 'file'}],
152
151
  },
153
152
  ],
154
153
  },
@@ -260,13 +259,11 @@ const FILESYSTEM: FileSystemItem[] = [
260
259
  },
261
260
  ];
262
261
 
263
- const styles = stylex.create({
264
- page: {height: '100dvh'},
265
- columnRow: {overflowX: 'auto', overflowY: 'hidden'},
266
- scrollable: {overflowY: 'auto'},
267
- fixedColumn: {flexShrink: 0},
268
- detailColumn: {flexGrow: 1, flexShrink: 0, flexBasis: 320},
269
- });
262
+ const page: CSSProperties = {height: '100dvh'};
263
+ const columnRow: CSSProperties = {overflowX: 'auto', overflowY: 'hidden'};
264
+ const scrollable: CSSProperties = {overflowY: 'auto'};
265
+ const fixedColumn: CSSProperties = {flexShrink: 0};
266
+ const detailColumn: CSSProperties = {flexGrow: 1, flexShrink: 0, flexBasis: 320};
270
267
 
271
268
  function findItem(items: FileSystemItem[], id: string): FileSystemItem | null {
272
269
  for (const item of items) {
@@ -348,7 +345,7 @@ export default function FileExplorerPage() {
348
345
 
349
346
  return (
350
347
  <Layout
351
- xstyle={styles.page}
348
+ style={page}
352
349
  height="fill"
353
350
  header={
354
351
  <Toolbar
@@ -448,7 +445,7 @@ export default function FileExplorerPage() {
448
445
  }
449
446
  content={
450
447
  <LayoutContent padding={0} isScrollable={false}>
451
- <HStack height="100%" xstyle={styles.columnRow}>
448
+ <HStack height="100%" style={columnRow}>
452
449
  {columns.map((col, colIndex) => {
453
450
  const showDivider =
454
451
  colIndex < columns.length - 1 || selectedFile != null;
@@ -459,7 +456,7 @@ export default function FileExplorerPage() {
459
456
  padding={2}
460
457
  variant="transparent"
461
458
  dividers={showDivider ? ['end'] : undefined}
462
- xstyle={[styles.scrollable, styles.fixedColumn]}>
459
+ style={{...scrollable, ...fixedColumn}}>
463
460
  <List density="compact" hasDividers={false}>
464
461
  {col.items.map(item => {
465
462
  const isSelected = col.selectedId === item.id;
@@ -506,7 +503,7 @@ export default function FileExplorerPage() {
506
503
  <Section
507
504
  padding={6}
508
505
  variant="transparent"
509
- xstyle={[styles.scrollable, styles.detailColumn]}>
506
+ style={{...scrollable, ...detailColumn}}>
510
507
  <VStack gap={4} hAlign="center">
511
508
  <Avatar name={selectedFile.name} size={96} />
512
509
  <VStack gap={1} hAlign="center">
@@ -2,8 +2,7 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import {useState} from 'react';
6
- import * as stylex from '@stylexjs/stylex';
5
+ import {useState, type CSSProperties} from 'react';
7
6
  import {VStack, HStack} from '@astryxdesign/core/Layout';
8
7
  import {Center} from '@astryxdesign/core/Center';
9
8
  import {Section} from '@astryxdesign/core/Section';
@@ -18,7 +17,6 @@ import {Link} from '@astryxdesign/core/Link';
18
17
  import {Divider} from '@astryxdesign/core/Divider';
19
18
  import {Card} from '@astryxdesign/core/Card';
20
19
  import {Selector} from '@astryxdesign/core/Selector';
21
- import {radiusVars} from '@astryxdesign/core/theme/tokens.stylex';
22
20
 
23
21
  const ILLUSTRATION_URL =
24
22
  'https://lookaside.facebook.com/assets/astryx/light-working-vertical-2.png';
@@ -51,18 +49,16 @@ const CONTACT_COLUMNS = [
51
49
  // AspectRatio has no objectFit/radius prop and there's no Image primitive
52
50
  // (#2582), so the cover photo is styled directly. overflow:hidden masks the
53
51
  // cover crop to the rounded corners.
54
- const styles = stylex.create({
55
- page: {
56
- minHeight: '100%',
57
- },
58
- illustrationImg: {
59
- width: '100%',
60
- height: '100%',
61
- objectFit: 'cover',
62
- borderRadius: radiusVars['--radius-container'],
63
- overflow: 'hidden',
64
- },
65
- });
52
+ const pageStyle: CSSProperties = {
53
+ minHeight: '100%',
54
+ };
55
+ const illustrationImg: CSSProperties = {
56
+ width: '100%',
57
+ height: '100%',
58
+ objectFit: 'cover',
59
+ borderRadius: 'var(--radius-container)',
60
+ overflow: 'hidden',
61
+ };
66
62
 
67
63
  /**
68
64
  * Form (Two-column) — marketing contact form template.
@@ -95,7 +91,7 @@ export default function FormTwoColumnPage() {
95
91
  const handleSubmit = () => setSubmitted(true);
96
92
 
97
93
  return (
98
- <Center xstyle={styles.page}>
94
+ <Center style={pageStyle}>
99
95
  <Section maxWidth={1100} width="100%" padding={10} variant="transparent">
100
96
  <VStack gap={10}>
101
97
  {/* Two-column; stacks to one column below ~520px. */}
@@ -114,7 +110,7 @@ export default function FormTwoColumnPage() {
114
110
  <img
115
111
  src={ILLUSTRATION_URL}
116
112
  alt="Two people working at a desk"
117
- {...stylex.props(styles.illustrationImg)}
113
+ style={illustrationImg}
118
114
  />
119
115
  </AspectRatio>
120
116
  </VStack>
@@ -2,7 +2,7 @@
2
2
 
3
3
  'use client';
4
4
 
5
- import * as stylex from '@stylexjs/stylex';
5
+ import type {CSSProperties} from 'react';
6
6
  import {
7
7
  VStack,
8
8
  HStack,
@@ -35,18 +35,16 @@ const IMAGES = [
35
35
  // because Astryx has no image primitive — AspectRatio exposes no objectFit or
36
36
  // radius props and there's no Image. Tracked in issue #2582; replace these
37
37
  // with component props once it lands.
38
- const styles = stylex.create({
39
- // Fills the AspectRatio box. No objectFit prop on AspectRatio (#2582).
40
- galleryImage: {
41
- width: '100%',
42
- height: '100%',
43
- objectFit: 'cover',
44
- },
45
- // Rounds the image corners. No radius prop on AspectRatio (#2582).
46
- galleryImageClip: {
47
- borderRadius: 'var(--radius-container)',
48
- },
49
- });
38
+ // Fills the AspectRatio box. No objectFit prop on AspectRatio (#2582).
39
+ const galleryImage: CSSProperties = {
40
+ width: '100%',
41
+ height: '100%',
42
+ objectFit: 'cover',
43
+ };
44
+ // Rounds the image corners. No radius prop on AspectRatio (#2582).
45
+ const galleryImageClip: CSSProperties = {
46
+ borderRadius: 'var(--radius-container)',
47
+ };
50
48
 
51
49
  export default function GalleryHero() {
52
50
  return (
@@ -88,9 +86,9 @@ export default function GalleryHero() {
88
86
  <AspectRatio
89
87
  key={image.src}
90
88
  ratio={4 / 5}
91
- xstyle={styles.galleryImageClip}>
89
+ style={galleryImageClip}>
92
90
  <img
93
- {...stylex.props(styles.galleryImage)}
91
+ style={galleryImage}
94
92
  src={image.src}
95
93
  alt={image.alt}
96
94
  />