@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,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, LayoutHeader, LayoutContent} from '@astryxdesign/core/Layout';
8
7
  import {Text, Heading} from '@astryxdesign/core/Text';
9
8
  import {Card} from '@astryxdesign/core/Card';
@@ -320,21 +319,19 @@ const ITEMS: LibraryItem[] = [
320
319
  },
321
320
  ];
322
321
 
323
- const styles = stylex.create({
324
- thumbnailWrapper: {
325
- position: 'relative',
326
- aspectRatio: '16/9',
327
- overflow: 'clip',
328
- flexShrink: 0,
329
- },
330
- thumbnailImage: {
331
- position: 'absolute',
332
- inset: 0,
333
- width: '100%',
334
- height: '100%',
335
- objectFit: 'cover',
336
- },
337
- });
322
+ const thumbnailWrapper: CSSProperties = {
323
+ position: 'relative',
324
+ aspectRatio: '16/9',
325
+ overflow: 'clip',
326
+ flexShrink: 0,
327
+ };
328
+ const thumbnailImage: CSSProperties = {
329
+ position: 'absolute',
330
+ inset: 0,
331
+ width: '100%',
332
+ height: '100%',
333
+ objectFit: 'cover',
334
+ };
338
335
 
339
336
  // =============================================================================
340
337
  // Side Nav
@@ -343,12 +340,8 @@ const styles = stylex.create({
343
340
  function LibraryCard({item}: {item: LibraryItem}) {
344
341
  return (
345
342
  <Card padding={0}>
346
- <div {...stylex.props(styles.thumbnailWrapper)}>
347
- <img
348
- src={item.imageUrl}
349
- alt={item.name}
350
- {...stylex.props(styles.thumbnailImage)}
351
- />
343
+ <div style={thumbnailWrapper}>
344
+ <img src={item.imageUrl} alt={item.name} style={thumbnailImage} />
352
345
  </div>
353
346
  <Section variant="transparent" padding={4}>
354
347
  <VStack gap={1}>
@@ -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} from '@astryxdesign/core/Layout';
8
7
  import {Center} from '@astryxdesign/core/Center';
9
8
  import {Text, Heading} from '@astryxdesign/core/Text';
@@ -13,22 +12,19 @@ import {Card} from '@astryxdesign/core/Card';
13
12
  import {Icon} from '@astryxdesign/core/Icon';
14
13
  import {Banner} from '@astryxdesign/core/Banner';
15
14
  import {CubeIcon} from '@heroicons/react/24/outline';
16
- import {colorVars, spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
17
15
 
18
16
  // Standalone auth page paints its own body background (no host shell).
19
- const styles = stylex.create({
20
- page: {
21
- minHeight: '100%',
22
- backgroundColor: colorVars['--color-background-body'],
23
- padding: spacingVars['--spacing-6'],
24
- },
25
- // Cap the column at 400px but let it shrink to fit narrow screens (Stack
26
- // has no maxWidth prop, so it's set here).
27
- content: {
28
- width: '100%',
29
- maxWidth: 400,
30
- },
31
- });
17
+ const pageStyle: CSSProperties = {
18
+ minHeight: '100%',
19
+ backgroundColor: 'var(--color-background-body)',
20
+ padding: 'var(--spacing-6)',
21
+ };
22
+ // Cap the column at 400px but let it shrink to fit narrow screens (Stack
23
+ // has no maxWidth prop, so it's set here).
24
+ const contentStyle: CSSProperties = {
25
+ width: '100%',
26
+ maxWidth: 400,
27
+ };
32
28
 
33
29
  export default function LoginPage() {
34
30
  const [email, setEmail] = useState('');
@@ -47,8 +43,8 @@ export default function LoginPage() {
47
43
  };
48
44
 
49
45
  return (
50
- <Center axis="both" xstyle={styles.page}>
51
- <VStack gap={4} hAlign="center" xstyle={styles.content}>
46
+ <Center axis="both" style={pageStyle}>
47
+ <VStack gap={4} hAlign="center" style={contentStyle}>
52
48
  {/* Logo */}
53
49
  <VStack gap={2} hAlign="center">
54
50
  <Icon icon={CubeIcon} size="lg" />
@@ -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 {CubeIcon} from '@heroicons/react/24/outline';
8
7
  import {VStack} from '@astryxdesign/core/Layout';
9
8
  import {Center} from '@astryxdesign/core/Center';
@@ -14,7 +13,6 @@ import {Card} from '@astryxdesign/core/Card';
14
13
  import {Link} from '@astryxdesign/core/Link';
15
14
  import {Divider} from '@astryxdesign/core/Divider';
16
15
  import {Icon} from '@astryxdesign/core/Icon';
17
- import {colorVars, spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
18
16
 
19
17
  // Brand sign-in marks — no heroicons or template-assets equivalent.
20
18
  const AppleIcon = (props: React.SVGProps<SVGSVGElement>) => (
@@ -57,19 +55,17 @@ const GoogleIcon = (props: React.SVGProps<SVGSVGElement>) => (
57
55
  );
58
56
 
59
57
  // Standalone auth page paints its own body background (no host shell).
60
- const styles = stylex.create({
61
- page: {
62
- minHeight: '100%',
63
- backgroundColor: colorVars['--color-background-body'],
64
- padding: spacingVars['--spacing-6'],
65
- },
66
- // Cap the column at 400px but let it shrink to fit narrow screens (Stack
67
- // has no maxWidth prop, so it's set here).
68
- content: {
69
- width: '100%',
70
- maxWidth: 400,
71
- },
72
- });
58
+ const pageStyle: CSSProperties = {
59
+ minHeight: '100%',
60
+ backgroundColor: 'var(--color-background-body)',
61
+ padding: 'var(--spacing-6)',
62
+ };
63
+ // Cap the column at 400px but let it shrink to fit narrow screens (Stack
64
+ // has no maxWidth prop, so it's set here).
65
+ const contentStyle: CSSProperties = {
66
+ width: '100%',
67
+ maxWidth: 400,
68
+ };
73
69
 
74
70
  export default function LoginSimple() {
75
71
  const [email, setEmail] = useState('');
@@ -91,8 +87,8 @@ export default function LoginSimple() {
91
87
  };
92
88
 
93
89
  return (
94
- <Center axis="both" xstyle={styles.page}>
95
- <VStack gap={4} hAlign="center" xstyle={styles.content}>
90
+ <Center axis="both" style={pageStyle}>
91
+ <VStack gap={4} hAlign="center" style={contentStyle}>
96
92
  {/* Logo */}
97
93
  <VStack gap={2} hAlign="center">
98
94
  <Icon icon={CubeIcon} size="lg" />
@@ -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, StackItem} from '@astryxdesign/core/Layout';
8
7
  import {Grid} from '@astryxdesign/core/Grid';
9
8
  import {Center} from '@astryxdesign/core/Center';
@@ -17,7 +16,6 @@ import {TextInput} from '@astryxdesign/core/TextInput';
17
16
  import {Button} from '@astryxdesign/core/Button';
18
17
  import {Link} from '@astryxdesign/core/Link';
19
18
  import {Divider} from '@astryxdesign/core/Divider';
20
- import {colorVars, spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
21
19
 
22
20
  const COVER_IMAGE_URL =
23
21
  'https://lookaside.facebook.com/assets/astryx/light-working-vertical-1.png';
@@ -34,47 +32,50 @@ const COLUMN_MIN_WIDTH = 240;
34
32
  // below 2×MIN + 32(gap) = 512px. The container query reorders the image and
35
33
  // tightens the inset at that same point, keyed to the card width (not the
36
34
  // window) so it never desyncs.
37
- const STACK_QUERY = '@container login-split (max-width: 511px)';
35
+ // minHeight:100% fills the host so the centered card never leaves an unpainted
36
+ // band; padding keeps it off the surface edges.
37
+ const pageStyle: CSSProperties = {
38
+ minHeight: '100%',
39
+ backgroundColor: 'var(--color-background-body)',
40
+ padding: 'var(--spacing-6)',
41
+ };
42
+ const cardWrap: CSSProperties = {
43
+ width: '100%',
44
+ maxWidth: 1000,
45
+ marginInline: 'auto',
46
+ };
47
+ const coverImage: CSSProperties = {
48
+ width: '100%',
49
+ height: '100%',
50
+ objectFit: 'cover',
51
+ };
38
52
 
39
- const styles = stylex.create({
40
- // minHeight:100% fills the host so the centered card never leaves an unpainted
41
- // band; padding keeps it off the surface edges.
42
- page: {
43
- minHeight: '100%',
44
- backgroundColor: colorVars['--color-background-body'],
45
- padding: spacingVars['--spacing-6'],
46
- },
47
- cardWrap: {
48
- width: '100%',
49
- maxWidth: 1000,
50
- marginInline: 'auto',
51
- },
52
- // Pad the grid, not the Card: the form's Section escapes Card's
53
- // --container-padding-* vars, which would cancel the inset on the form side.
54
- // containerType makes this the query container for STACK_QUERY.
55
- splitGrid: {
56
- containerType: 'inline-size',
57
- containerName: 'login-split',
58
- padding: {
59
- default: spacingVars['--spacing-8'],
60
- [STACK_QUERY]: spacingVars['--spacing-4'],
61
- },
62
- },
63
- imageCell: {
64
- // Fill the track: the image's Card is content-width by default.
65
- width: '100%',
66
- // order:-1 moves the image above the form when stacked.
67
- order: {
68
- default: 0,
69
- [STACK_QUERY]: -1,
70
- },
71
- },
72
- coverImage: {
73
- width: '100%',
74
- height: '100%',
75
- objectFit: 'cover' as const,
76
- },
77
- });
53
+ // The container query lives in a plain <style> tag so it needs NO CSS compiler.
54
+ // - Pad the grid, not the Card: the form's Section escapes Card's
55
+ // --container-padding-* vars, which would cancel the inset on the form side.
56
+ // container-type makes the grid the query container for the stack point.
57
+ // - repeat:'fit' (auto-fit) collapses the two columns to one below 511px; the
58
+ // query reorders the image (order:-1) and tightens the inset at that point,
59
+ // keyed to the card width (not the window) so it never desyncs.
60
+ const LOGIN_SPLIT_CSS = `
61
+ .login-split-grid {
62
+ container-type: inline-size;
63
+ container-name: login-split;
64
+ padding: var(--spacing-8);
65
+ }
66
+ .login-split-image {
67
+ width: 100%;
68
+ order: 0;
69
+ }
70
+ @container login-split (max-width: 511px) {
71
+ .login-split-grid {
72
+ padding: var(--spacing-4);
73
+ }
74
+ .login-split-image {
75
+ order: -1;
76
+ }
77
+ }
78
+ `;
78
79
 
79
80
  export default function LoginTwoColumn() {
80
81
  const [email, setEmail] = useState('');
@@ -97,15 +98,16 @@ export default function LoginTwoColumn() {
97
98
  };
98
99
 
99
100
  return (
100
- <Center axis="both" xstyle={styles.page}>
101
+ <Center axis="both" style={pageStyle}>
102
+ <style>{LOGIN_SPLIT_CSS}</style>
101
103
  <VStack gap={4} width="100%">
102
- <div {...stylex.props(styles.cardWrap)}>
104
+ <div style={cardWrap}>
103
105
  <Card padding={0} width="100%">
104
106
  <Grid
105
107
  columns={{minWidth: COLUMN_MIN_WIDTH, repeat: 'fit'}}
106
108
  gap={8}
107
109
  align="stretch"
108
- xstyle={styles.splitGrid}>
110
+ className="login-split-grid">
109
111
  {/* Form */}
110
112
  <Section variant="transparent" padding={0} height="100%">
111
113
  <VStack gap={4} height="100%">
@@ -237,14 +239,14 @@ export default function LoginTwoColumn() {
237
239
 
238
240
  {/* Cover image — the transparent Card clips it to rounded
239
241
  corners (overflow:clip + radius), so the image needs no radius. */}
240
- <div {...stylex.props(styles.imageCell)}>
242
+ <div className="login-split-image">
241
243
  <Card
242
244
  variant="transparent"
243
245
  padding={0}
244
246
  width="100%"
245
247
  height="100%">
246
248
  <img
247
- {...stylex.props(styles.coverImage)}
249
+ style={coverImage}
248
250
  src={COVER_IMAGE_URL}
249
251
  alt="Two people working at a desk"
250
252
  />
@@ -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 {ShieldCheckIcon} from '@heroicons/react/24/outline';
8
7
  import {VStack, HStack} from '@astryxdesign/core/Layout';
9
8
  import {Center} from '@astryxdesign/core/Center';
@@ -16,7 +15,6 @@ import {Link} from '@astryxdesign/core/Link';
16
15
  import {Divider} from '@astryxdesign/core/Divider';
17
16
  import {Icon} from '@astryxdesign/core/Icon';
18
17
  import {Avatar} from '@astryxdesign/core/Avatar';
19
- import {spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
20
18
 
21
19
  // ---------------------------------------------------------------------------
22
20
  // Styles
@@ -24,15 +22,13 @@ import {spacingVars} from '@astryxdesign/core/theme/tokens.stylex';
24
22
 
25
23
  const BG_URL = 'https://lookaside.facebook.com/assets/astryx/building.png';
26
24
 
27
- const styles = stylex.create({
28
- page: {
29
- minHeight: '100%',
30
- backgroundImage: `url(${BG_URL})`,
31
- backgroundSize: 'cover',
32
- backgroundPosition: 'center',
33
- padding: spacingVars['--spacing-6'],
34
- },
35
- });
25
+ const pageStyle: CSSProperties = {
26
+ minHeight: '100%',
27
+ backgroundImage: `url(${BG_URL})`,
28
+ backgroundSize: 'cover',
29
+ backgroundPosition: 'center',
30
+ padding: 'var(--spacing-6)',
31
+ };
36
32
 
37
33
  type SSOProvider = {
38
34
  name: string;
@@ -102,7 +98,7 @@ export default function LoginSSO() {
102
98
  };
103
99
 
104
100
  return (
105
- <Center axis="both" xstyle={styles.page}>
101
+ <Center axis="both" style={pageStyle}>
106
102
  <Card padding={8} width="100%" maxWidth={400}>
107
103
  <VStack gap={4} hAlign="stretch">
108
104
  {/* ── Step 1: Email entry ── */}
@@ -2,54 +2,59 @@
2
2
 
3
3
  'use client';
4
4
 
5
+ import type {CSSProperties} from 'react';
5
6
  import {VStack, Layout, LayoutContent} from '@astryxdesign/core/Layout';
6
7
  import {Text, Heading} from '@astryxdesign/core/Text';
7
8
  import {AspectRatio} from '@astryxdesign/core/AspectRatio';
8
- import * as stylex from '@stylexjs/stylex';
9
9
 
10
10
  // ─── Styles ────────────────────────────────────────────────────────────────
11
11
  // The masonry needs a responsive column count AND a hero that spans 2 columns
12
12
  // on desktop but goes full-width on mobile. Grid forces grid-template-columns
13
13
  // inline, so a responsive span can't be expressed through its props — this is a
14
14
  // @container grid (the sanctioned Astryx pattern for container-responsive layout).
15
- // Image fill + radius are also custom because Astryx has no image primitive (#2582).
15
+ // The container query lives in a plain <style> tag below so it needs NO CSS
16
+ // compiler. Image fill + radius are custom because Astryx has no image
17
+ // primitive (#2582).
16
18
 
17
- const styles = stylex.create({
18
- // Named inline-size container on the page column so the grid responds to the
19
- // available content width (works inside the sandbox's resizable preview).
20
- container: {
21
- containerType: 'inline-size',
22
- containerName: 'gallery',
23
- },
24
- // 3 columns on desktop, dropping straight to 1 column below 720px (no 2-col
25
- // middle state). minmax(0, 1fr) (not 1fr) so tracks split evenly and ignore
26
- // the images' intrinsic min-width.
27
- grid: {
28
- display: 'grid',
29
- gap: 'var(--spacing-3)',
30
- gridTemplateColumns: {
31
- default: 'repeat(3, minmax(0, 1fr))',
32
- '@container gallery (max-width: 720px)': 'minmax(0, 1fr)',
33
- },
34
- },
35
- // Hero spans 2 columns on desktop, then fills the row once it's single-column.
36
- hero: {
37
- gridColumn: {
38
- default: 'span 2',
39
- '@container gallery (max-width: 720px)': '1 / -1',
40
- },
41
- },
42
- // Fills the AspectRatio box. No objectFit prop on AspectRatio (#2582).
43
- img: {
44
- width: '100%',
45
- height: '100%',
46
- objectFit: 'cover',
47
- },
48
- // Rounds the image corners. No radius prop on AspectRatio (#2582).
49
- clip: {
50
- borderRadius: 'var(--radius-element)',
51
- },
52
- });
19
+ // Named inline-size container on the page column so the grid responds to the
20
+ // available content width (works inside the sandbox's resizable preview).
21
+ const containerStyle: CSSProperties = {
22
+ containerType: 'inline-size',
23
+ containerName: 'gallery',
24
+ };
25
+ // Fills the AspectRatio box. No objectFit prop on AspectRatio (#2582).
26
+ const imgStyle: CSSProperties = {
27
+ width: '100%',
28
+ height: '100%',
29
+ objectFit: 'cover',
30
+ };
31
+ // Rounds the image corners. No radius prop on AspectRatio (#2582).
32
+ const clipStyle: CSSProperties = {
33
+ borderRadius: 'var(--radius-element)',
34
+ };
35
+
36
+ // 3 columns on desktop, dropping straight to 1 column below 720px (no 2-col
37
+ // middle state). minmax(0, 1fr) (not 1fr) so tracks split evenly and ignore the
38
+ // images' intrinsic min-width. The hero spans 2 columns on desktop, then fills
39
+ // the row once it's single-column.
40
+ const GALLERY_CSS = `
41
+ .mixed-gallery-grid {
42
+ display: grid;
43
+ gap: var(--spacing-3);
44
+ grid-template-columns: repeat(3, minmax(0, 1fr));
45
+ }
46
+ .mixed-gallery-hero {
47
+ grid-column: span 2;
48
+ }
49
+ @container gallery (max-width: 720px) {
50
+ .mixed-gallery-grid {
51
+ grid-template-columns: minmax(0, 1fr);
52
+ }
53
+ .mixed-gallery-hero {
54
+ grid-column: 1 / -1;
55
+ }
56
+ }
57
+ `;
53
58
 
54
59
  // ─── Gallery Data ───────────────────────────────────────────────────────────
55
60
 
@@ -89,15 +94,15 @@ const IMAGES: GalleryImage[] = [
89
94
  function GalleryCard({
90
95
  image,
91
96
  ratio,
92
- xstyle,
97
+ className,
93
98
  }: {
94
99
  image: GalleryImage;
95
100
  ratio: number;
96
- xstyle?: stylex.StyleXStyles;
101
+ className?: string;
97
102
  }) {
98
103
  return (
99
- <AspectRatio ratio={ratio} xstyle={[styles.clip, xstyle]}>
100
- <img src={image.src} alt={image.title} {...stylex.props(styles.img)} />
104
+ <AspectRatio ratio={ratio} className={className} style={clipStyle}>
105
+ <img src={image.src} alt={image.title} style={imgStyle} />
101
106
  </AspectRatio>
102
107
  );
103
108
  }
@@ -111,7 +116,8 @@ export default function MixedGalleryTemplate() {
111
116
  contentWidth={1400}
112
117
  content={
113
118
  <LayoutContent padding={6}>
114
- <VStack gap={6} xstyle={styles.container}>
119
+ <style>{GALLERY_CSS}</style>
120
+ <VStack gap={6} style={containerStyle}>
115
121
  {/* Header */}
116
122
  <VStack gap={2} hAlign="center">
117
123
  <Heading level={1} justify="center">
@@ -129,12 +135,12 @@ export default function MixedGalleryTemplate() {
129
135
  (being 2 columns wide) it matches the row height exactly. All
130
136
  rows are therefore the same height. Responsive via @container:
131
137
  3 columns → 1 column at ≤720px. */}
132
- <div {...stylex.props(styles.grid)}>
138
+ <div className="mixed-gallery-grid">
133
139
  {/* Hero — spans 2 columns; 3:1 keeps it level with the sidebar */}
134
140
  <GalleryCard
135
141
  image={IMAGES[0]}
136
142
  ratio={3 / 1}
137
- xstyle={styles.hero}
143
+ className="mixed-gallery-hero"
138
144
  />
139
145
 
140
146
  {/* Sidebar — same height as the hero */}