astryx-dracula 0.5.1 → 0.6.2

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 (108) hide show
  1. package/BRAND.md +3 -3
  2. package/README.md +7 -4
  3. package/USAGE.md +49 -49
  4. package/astryx-dracula.d.ts +2 -2
  5. package/astryx-dracula.js +25 -9
  6. package/astryx-dracula.variants.d.ts +2 -2
  7. package/icons.mjs +4 -0
  8. package/icons.tsx +8 -0
  9. package/package.json +22 -17
  10. package/shared/chaptered-doc.tsx +1 -2
  11. package/shared/chart-hues.ts +21 -6
  12. package/shared/chart-legend.tsx +2 -2
  13. package/shared/data-bar.tsx +2 -2
  14. package/shared/settings-data.ts +0 -6
  15. package/shared/settings-rows.tsx +1 -23
  16. package/templates/ai-chat-landing.template.mjs +1 -0
  17. package/templates/ai-chat-landing.tsx +24 -2
  18. package/templates/ai-chat.template.mjs +1 -0
  19. package/templates/ai-chat.tsx +4 -2
  20. package/templates/blank.template.mjs +1 -0
  21. package/templates/blank.tsx +4 -2
  22. package/templates/centered-hero.template.mjs +1 -0
  23. package/templates/centered-hero.tsx +5 -3
  24. package/templates/classic-gallery.template.mjs +1 -0
  25. package/templates/classic-gallery.tsx +4 -2
  26. package/templates/contact-form.template.mjs +1 -0
  27. package/templates/contact-form.tsx +4 -2
  28. package/templates/dashboard-portfolio.template.mjs +1 -0
  29. package/templates/dashboard-portfolio.tsx +4 -2
  30. package/templates/dashboard.template.mjs +1 -0
  31. package/templates/dashboard.tsx +4 -2
  32. package/templates/detail-page.template.mjs +1 -0
  33. package/templates/detail-page.tsx +16 -16
  34. package/templates/documentation-design.template.mjs +1 -0
  35. package/templates/documentation-design.tsx +5 -3
  36. package/templates/documentation-technical.template.mjs +1 -0
  37. package/templates/documentation-technical.tsx +4 -2
  38. package/templates/documentation.template.mjs +1 -0
  39. package/templates/documentation.tsx +4 -2
  40. package/templates/editor.template.mjs +1 -0
  41. package/templates/editor.tsx +4 -2
  42. package/templates/file-explorer.template.mjs +1 -0
  43. package/templates/file-explorer.tsx +4 -2
  44. package/templates/form-two-column.template.mjs +1 -0
  45. package/templates/form-two-column.tsx +8 -2
  46. package/templates/gallery-hero.template.mjs +1 -0
  47. package/templates/gallery-hero.tsx +4 -2
  48. package/templates/ide.template.mjs +1 -0
  49. package/templates/ide.tsx +11 -6
  50. package/templates/incident-console.template.mjs +1 -0
  51. package/templates/incident-console.tsx +122 -80
  52. package/templates/kanban-board.template.mjs +1 -0
  53. package/templates/kanban-board.tsx +6 -4
  54. package/templates/library.template.mjs +1 -0
  55. package/templates/library.tsx +4 -2
  56. package/templates/login-card.template.mjs +1 -0
  57. package/templates/login-card.tsx +4 -2
  58. package/templates/login-split.template.mjs +1 -0
  59. package/templates/login-split.tsx +5 -2
  60. package/templates/login-sso.template.mjs +1 -0
  61. package/templates/login-sso.tsx +4 -2
  62. package/templates/login.template.mjs +1 -0
  63. package/templates/login.tsx +4 -2
  64. package/templates/messaging-shell.template.mjs +1 -0
  65. package/templates/messaging-shell.tsx +6 -2
  66. package/templates/mixed-gallery.template.mjs +1 -0
  67. package/templates/mixed-gallery.tsx +4 -2
  68. package/templates/payment-form.template.mjs +1 -0
  69. package/templates/payment-form.tsx +5 -3
  70. package/templates/product-detail.template.mjs +1 -0
  71. package/templates/product-detail.tsx +9 -2
  72. package/templates/product-gallery.template.mjs +1 -0
  73. package/templates/product-gallery.tsx +4 -2
  74. package/templates/product-tour.template.mjs +1 -0
  75. package/templates/product-tour.tsx +13 -10
  76. package/templates/settings-dialog.template.mjs +1 -0
  77. package/templates/settings-dialog.tsx +5 -3
  78. package/templates/settings-sidebar.template.mjs +1 -0
  79. package/templates/settings-sidebar.tsx +6 -4
  80. package/templates/settings.template.mjs +1 -0
  81. package/templates/settings.tsx +6 -10
  82. package/templates/shell-nav.template.mjs +1 -0
  83. package/templates/shell-nav.tsx +24 -26
  84. package/templates/shell-side-nav.template.mjs +1 -0
  85. package/templates/shell-side-nav.tsx +23 -18
  86. package/templates/shell-top-nav.template.mjs +1 -0
  87. package/templates/shell-top-nav.tsx +4 -2
  88. package/templates/side-gallery.template.mjs +1 -0
  89. package/templates/side-gallery.tsx +4 -2
  90. package/templates/table-grouped.template.mjs +1 -0
  91. package/templates/table-grouped.tsx +5 -3
  92. package/templates/table-page-chart.template.mjs +1 -0
  93. package/templates/table-page-chart.tsx +4 -2
  94. package/templates/table-page-heatmap-status.template.mjs +1 -0
  95. package/templates/table-page-heatmap-status.tsx +4 -2
  96. package/templates/table-page-shoe-store-heatmap.template.mjs +1 -0
  97. package/templates/table-page-shoe-store-heatmap.tsx +4 -2
  98. package/templates/table-page.template.mjs +1 -0
  99. package/templates/table-page.tsx +4 -2
  100. package/templates/table.template.mjs +1 -0
  101. package/templates/table.tsx +4 -2
  102. package/templates/tech-report.template.mjs +1 -0
  103. package/templates/tech-report.tsx +10 -8
  104. package/templates/theme-showcase.template.mjs +1 -0
  105. package/templates/theme-showcase.tsx +23 -17
  106. package/theme.css +35 -77
  107. package/theme.css.d.ts +9 -0
  108. package/tokens.css +38 -42
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC > V[g=8 a=center] > (V[g=1] > (H[g=2 a=center] > Ic + Tx"Hi, Vlad"[t=body]) + Hd"Where should we start?"[level=1 type=display-2]) + ChC"Ask anything" + (V[g=6] > (TgG"Category" > H[g=1 wrap] > Tg"Writing"*4) + Hd"Suggested prompts"[level=2] + (G[c={min:280} g=3] > (CC[p=4] > V[g=0.5] > Hd"Draft"[level=3] + Tx"Compose"[t=body])*4))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill mw=720] > LC > V[g=8 a=center] > (V[g=1] > (H[g=2 a=center] > Ic + Tx"Hi, Vlad"[t=body]) + Hd"Where should we start?"[level=1 type=display-2]) + ChC"Ask anything" + (V[g=6] > (TgG"Category" > H[g=1 wrap] > Tg"Writing"*4) + VH"Suggested prompts"[as=h2] + (G[c={min:280} g=3] > (CC[p=4] > V[g=0.5] > Hd"Draft"[level=3] + Tx"Compose"[t=body])*4))
4
6
 
5
7
  import {
6
8
  ChatComposer,
@@ -215,15 +217,23 @@ function makeTrigger<TAux>({
215
217
  items,
216
218
  getDescription,
217
219
  toToken,
220
+ hasMultiWordQuery,
221
+ emptySearchText,
218
222
  }: {
219
223
  character: string;
220
224
  items: SearchableItem<TAux>[];
221
225
  getDescription: (aux: TAux | undefined) => string | undefined;
222
226
  toToken: (item: SearchableItem<TAux>) => string | ChatComposerToken;
227
+ /** Continue the query past spaces, for names that contain them. */
228
+ hasMultiWordQuery?: boolean;
229
+ /** Shown when the query matched nothing. */
230
+ emptySearchText?: string;
223
231
  }): ChatComposerTrigger {
224
232
  return {
225
233
  character,
226
234
  searchSource: createStaticSource(items),
235
+ ...(hasMultiWordQuery ? { hasMultiWordQuery } : {}),
236
+ ...(emptySearchText ? { emptySearchText } : {}),
227
237
  renderItem: (item) => (
228
238
  <TypeaheadItem
229
239
  item={item}
@@ -238,6 +248,13 @@ const mentionTrigger = makeTrigger({
238
248
  character: "@",
239
249
  items: MENTION_ITEMS,
240
250
  getDescription: (aux) => aux?.role,
251
+ // The mention labels are full names ("Vesper Lin", "Alex Nocturne"), so
252
+ // the query has to survive the space: without this the menu closes at the
253
+ // first space and "@Vesper L" narrows to "Vesper" and then matches
254
+ // nothing. Core hides the menu on an unmatched multi-word query unless
255
+ // the trigger sets emptySearchText, so both go together.
256
+ hasMultiWordQuery: true,
257
+ emptySearchText: "No one by that name tonight.",
241
258
  toToken: (item) => ({
242
259
  value: `@${item.id}`,
243
260
  label: item.label,
@@ -257,6 +274,11 @@ const commandTrigger = makeTrigger({
257
274
  });
258
275
 
259
276
  const composerTriggers = [mentionTrigger, commandTrigger];
277
+ // The upstream `rename emptySearchResultsText to emptySearchText` codemod
278
+ // leaves a TODO on any ChatComposerInput whose `triggers` value it cannot
279
+ // attribute to a literal object — these are built by `makeTrigger`, so it
280
+ // cannot see inside them. The old key appears nowhere in this file, so that
281
+ // TODO would name a rename this template does not need.
260
282
 
261
283
  /** Composer attachment. The name is user-facing; the id is the React key, since
262
284
  * two dropped files can share a name. */
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "AI Chat",
4
4
  description: "Threaded assistant chat with design-doc artifact",
5
+ keywords: ["ai chat", "assistant", "conversation", "transcript", "chat", "artifact"],
5
6
  category: "tooling",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC[p=0] > H > (SI[fill] > ChL > ChML > (ChM > ChB)*4 + ChC"Ask a follow up...") + (C.transparent > Tbar + S.section > MD) ;; Dlg#artifact[variant=fullscreen] > L > (DH"JWT Token Refresh" + (LC[p=0] > S.section > MD))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L > LC[p=0] > H > (V > ChL > (VH"Night thread"[as=h1] + ChML > (ChSM"Today" + (ChM > ChBu)*8 + ChSM"Changes sealed in the crypt") + ChC"Ask the night anything...")) + (RH + C.transparent > Tbar + S.transparent > (V[g=2] > Hd"JWT Token Refresh: Design & Rollout"[level=2 t=display-2] + MD)) ;; Dlg#artifact[variant=fullscreen] > L > (DH"JWT Token Refresh" + (LC[p=0] > S.transparent > (V[g=2] > Hd"JWT Token Refresh: Design & Rollout"[level=2 t=display-2] + MD)))
4
6
 
5
7
  import { Avatar } from "@astryxdesign/core/Avatar";
6
8
  import { Button } from "@astryxdesign/core/Button";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Blank",
4
4
  description: "Empty layout shell for a new page",
5
+ keywords: ["blank", "empty", "starter", "minimal", "placeholder"],
5
6
  category: "tooling",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L[h=auto] > LC > Hd"A blank crypt awaits its story"[level=1]
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=auto] > LC > Hd"A blank crypt awaits its story"[level=1 t=display-2]
4
6
 
5
7
  import { Layout, LayoutContent } from "@astryxdesign/core/Layout";
6
8
  import { Heading } from "@astryxdesign/core/Text";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Centered Hero",
4
4
  description: "Headline, CTAs, and hero visual",
5
+ keywords: ["centered hero", "landing", "hero", "marketing", "cta", "splash"],
5
6
  category: "marketing",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC[p=6] > V[g=10] > ((V[g=6 a=center] > (V[g=3 a=center] > Hd"Small joys for creatures of the night"[level=1 t=display-2] + Tx"Sometimes all it takes is one small ritual to turn the whole night around."[t=body] + Tx"astryx-dracula v0.5.1"[t=supporting]) + (H[j=center g=3] > B.primary"Embrace the night" + B.secondary"Read the lore")) + (S.transparent[p=0] > AR[ratio=16/9]))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=auto] > LC[p=6] > V[g=10] > ((V[g=6 a=center] > (V[g=3 a=center] > Hd"Small joys for creatures of the night"[level=1 t=display-2] + Tx"Sometimes all it takes is one small ritual to turn the whole night around."[t=body] + Tx"astryx-dracula v0.6.2"[t=supporting]) + (H[j=center g=3] > B.primary"Embrace the night" + B.secondary"Read the lore")) + (S.transparent[p=0] > AR[ratio=16/9] > Scene{SceneCastle}))
4
6
 
5
7
  import { AspectRatio } from "@astryxdesign/core/AspectRatio";
6
8
  import { Button } from "@astryxdesign/core/Button";
@@ -39,7 +41,7 @@ export default function CenteredHero() {
39
41
  Sometimes all it takes is one small ritual to turn the whole night around.
40
42
  </Text>
41
43
  <Text type="supporting" color="secondary" justify="center" hasTabularNumbers>
42
- astryx-dracula v0.5.1
44
+ astryx-dracula v0.6.2
43
45
  </Text>
44
46
  </VStack>
45
47
  <HStack gap={3} wrap="wrap" justify="center">
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Classic Gallery",
4
4
  description: "Filterable image wall with category tabs",
5
+ keywords: ["gallery", "collection", "grid", "art", "images", "portfolio"],
5
6
  category: "marketing",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC[p=0] > Ctr > V[g=8] > ((Ctr > S.transparent > V[g=4 a=center] > (V[g=2 a=center] > Hd"Hung after dark"[level=1] + Tx"A coven-curated wall"[t=body]) + (TL > Tab"All"! + Tab"Lifestyle" + Tab"Scenery" + Tab"Home") + Tx"10 pieces on the wall"[t=body]) + (G[c={min:260} g=4] > (C[p=0] > AR[ratio=3/2])*10))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > LC[p=0] > Ctr > V[g=8] > ((Ctr > S.transparent[p=0 mw=680] > V[g=4 a=center] > (V[g=2 a=center] > Hd"Hung after dark"[level=1] + Tx"A coven-curated wall"[t=body]) + (TL > Tab"All"! + Tab"Lifestyle" + Tab"Scenery" + Tab"Home") + Tx"10 pieces on the wall"[t=body]) + (G[c={min:260} g=4] > (C[p=0] > AR[ratio=3/2] > Scene{SceneTile})*10))
4
6
 
5
7
  import { AspectRatio } from "@astryxdesign/core/AspectRatio";
6
8
  import { Card } from "@astryxdesign/core/Card";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Contact Form",
4
4
  description: "Lead capture form with goals and budget",
5
+ keywords: ["contact", "form", "enquiry", "get in touch", "support", "message"],
5
6
  category: "forms",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // Ctr > V[a=center] > S.transparent[p=6] > V[g=6] > (V[g=2 a=center] > Hd"Let's brew after dark"[level=1] + Tx"Tell us a bit"[t=body]) + (V[g=4] > Hd"Why work with us"[level=2] + (G[c={min:200} g=4] > (C > V[g=3] > Ic + (V[g=1] > Hd"Title"[level=3] + Tx"Desc"[t=body]))*3)) + (V[g=4] > Hd"Your details"[level=2] + (G[c={min:260} g=4] > TI"Full name" + TI"Email") + (G[c={min:260} g=4] > TI"Company" + TI"Phone")) + D + (V[g=4] > Hd"Your project"[level=2] + (Fd"Goals"[req] > (H[g=2] > Tk"Goal"*10)) + SE"Timeline" + SE"Budget" + (RL"Source" > RLI*5) + TA"Notes" + CB"Decision maker") + (V[g=3] > B.primary"Send it into the night" + (Tx[t=supporting] > Lk"Privacy Policy"))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // Ctr > V[a=center] > S.transparent[p=6] > V[g=6] > (V[g=2 a=center] > Hd"Let's brew after dark"[level=1 t=display-2] + Tx"Tell us a bit"[t=body]) + (V[g=4] > Hd"Why work with us"[level=2] + (G[c={min:200} g=4] > (C > V[g=3] > Ic + (V[g=1] > Hd"Title"[level=3] + Tx"Desc"[t=body]))*3)) + (V[g=4] > Hd"Your details"[level=2] + (G[c={min:260} g=4] > TI"Full name"[req] + TI"Email"[req]) + (G[c={min:260} g=4] > TI"Company"[req] + TI"Phone"[req])) + D + (V[g=4] > Hd"Your project"[level=2] + (Fd"What are you going for?"[req] > (H[g=2] > Tk"Goal"*10)) + SE{Selector}"When are you thinking?" + SE{Selector}"Ballpark budget?" + (RL"How did you hear about us?" > RLI*5) + TA"Anything else?" + CB"I'm a budget decision-maker") + (V[g=3] > B.primary"Send it into the night" + (Tx[t=supporting] > Lk"Privacy Policy"))
4
6
 
5
7
  import { Button } from "@astryxdesign/core/Button";
6
8
  import { Card } from "@astryxdesign/core/Card";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Portfolio Dashboard",
4
4
  description: "Holdings chart, market cards, and trending table",
5
+ keywords: ["portfolio", "holdings", "wealth", "investment", "positions", "dashboard"],
5
6
  category: "dashboard",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L[h=fill] > LC[p=6] > V[g=6] > (H[j=between a=center] > Hd"The night vault"[level=1] + Tx"1 year"[t=body]) + (G[c={min:280} g=4] > (C > V[g=2] > Tx"Total value"[t=supporting] + (H[g=2] > Tx"$294,200"[t=display-3] + Tx"+14.8%"[t=body]))*4) + (G[c={min:280} g=4] > (C > V[g=4] > (H[j=between] > Hd"Vault value"[level=2] + Lk"View details") + (C > V[g=3] > Tx"Weekly closes"[t=supporting])) + (V[g=4] > (H[j=between] > Hd"Top holdings"[level=2] + Lk"View all") + UL)) + D + (H[j=between a=start] > (V[g=1] > Hd"Market at midnight"[level=2] + Tx"Past 24 hours under moonlight"[t=body]) + B"View more") + (G[c={min:280} g=4] > (C > V[g=3] > Hd"Index"[level=3] + Tx"$5,200"[t=body])*8) + (C > V[g=4] > Hd"Trending stocks"[level=3] + T)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > LC[p=6] > V[g=6] > (H[j=between a=center] > Hd"The night vault"[level=1] + Tx"1 year"[t=body]) + (G[c={min:280} g=4] > (C > V[g=2] > Tx"Total value"[t=supporting] + (H[g=2 a=center] > Tx"$294,200"[t=display-3] + (H[g=1 a=center] > Ic + Tx"+14.8%"[t=body])) + Tx"Weekly closes · trailing 12 months"[t=supporting])*4) + (G[c={min:280} g=4] > (C > V[g=4] > (H[j=between a=center] > Hd"Vault value"[level=2] + Lk"View details") + (V[g=3] > C[p=4] + Tx"Weekly closes · trailing 12 months"[t=supporting])) + (V[g=4] > (H[j=between a=center] > Hd"Top holdings"[level=2] + Lk"View all") + (UL[density=spacious] > LI*5))) + D + (H[j=between a=start] > (V[g=1] > Hd"Market at midnight"[level=2] + Tx"Past 24 hours under moonlight"[t=body]) + B.secondary"View more") + (G[c={min:280} g=4] > (C > V[g=4] > (V[g=0] > Hd"Dow Jones"[level=3] + Tx"DJI"[t=supporting]) + Spl + (H[g=3 a=center] > Tx"43,821.67"[t=display-3] + (H[g=1 a=center] > Ic + Tx"+0.42%"[t=body])))*8) + (C > V[g=6] > (H[j=between a=center] > Hd"Trending stocks"[level=3]) + T[hover density=compact dv=rows])
4
6
 
5
7
  import { Avatar } from "@astryxdesign/core/Avatar";
6
8
  import { Button } from "@astryxdesign/core/Button";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Analytics Dashboard",
4
4
  description: "KPI cards, SVG chart strips, and data tables",
5
+ keywords: ["dashboard", "analytics", "kpi", "metrics", "charts", "overview"],
5
6
  category: "dashboard",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC[p=6] > V[g=6] > (Hd"The night shift"[level=1] + V[g=6] > (H[j=between a=center] > Hd"Awake after dark"[level=2] + B.secondary"Reload") + (V[g=3] > C[p=4] + Tx"Hourly intervals"[t=supporting] + (H[g=6] > (H[g=2 a=center] > Ic + Tx"Desktop"[t=supporting])*2))) + (G[c={min:280} g=4] > (C > V[g=2] > Tx"Moonlit visitors"[t=supporting] + (H[g=2] > Tx"27.3 k"[t=display-3] + Tx"+18.2%"[t=body]) + Tx"Last 30 days vs. Previous"[t=supporting])*4) + D + (H[j=between a=center] > Hd"Night denizens"[level=2] + B.secondary"View more") + (G[c={min:280} g=4] > (C > V[g=4] > Hd"Territory"[level=3] + (H[g=4 wrap] > (V[g=0] > (H[g=2 a=center] > Ic + Tx[t=supporting]) + Tx[t=supporting])*5))*2) + D + (H[j=between a=center] > Hd"Engagement"[level=2] + B.secondary"View more") + (G[c={min:280} g=4] > (C > V[g=6] > (H[j=between a=center] > Hd"Top pages"[level=3] + Lk"All pages") + T)*2)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > LC[p=6] > V[g=6] > (Hd"The night shift"[level=1] + V[g=6] > (H[j=between a=center] > Hd"Awake after dark"[level=2] + B.secondary"Reload") + (V[g=3] > C[p=4] + (V[g=1] > (H[g=4 a=center] > (H[g=1 a=center] > Sw + Tx"Desktop"[t=supporting])*2) + Tx"Hourly intervals"[t=supporting]))) + (G[c={min:280} g=4] > (C > V[g=2] > Tx"Moonlit visitors"[t=supporting] + (H[g=2 a=center] > Tx"27.3 k"[t=display-3] + (H[g=1 a=center] > Ic + Tx"+18.2%"[t=body])) + Tx"Last 30 days vs. Previous"[t=supporting] + Spl)*4) + D + (H[j=between a=center] > Hd"Night denizens"[level=2] + B.secondary"View more") + (G[c={min:280} g=4] > (C > V[g=4] > Hd"Territory"[level=3] + (H[g=4 wrap] > (V[g=1] > (H[g=2 a=center] > Ic + Tx[t=supporting]) + Tx[t=supporting])*5))*2) + D + (H[j=between a=center] > Hd"Engagement"[level=2] + B.secondary"View more") + (G[c={min:280} g=4] > (C > V[g=6] > (H[j=between a=center] > Hd"Top pages"[level=3] + Lk"All pages") + T[hover density=compact dv=rows])*2)
4
6
 
5
7
  /**
6
8
  * Analytics Dashboard — the night shift at a glance: live active users, four KPI tiles, audience breakdown strips, and engagement tables. (Frame/responsive/container: see XLE header above.)
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Order Detail",
4
4
  description: "Items, invoice, timeline, and side panel",
5
+ keywords: ["detail", "order", "invoice", "product", "purchase", "receipt", "transaction"],
5
6
  category: "commerce",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LH[divider] > V[g=3] > ((H[g=4 a=start] > (SI > V[g=0] > (Lk"All orders" + (V[g=0] > Hd"#1001"[level=1] + (H[g=1 a=center] > Tx"5 ordered items"[t=supporting] + Av"Vlad Dracul" + SD"Unfulfilled" + Tx"02/23/2026"[t=supporting] + Lk"See all")))) + (H[g=2] > B"Restock" + B"Edit")) + (H[g=3 a=center] > (SI > TL > Tab"Details"! + Tab"Invoices" + Tab"Timeline" + TabMenu"More") + B.ghost))) + (LC > V[g=4] > ((S > V[g=4] > ((H[g=2 a=center] > Hd"Items"[level=2] + SD"Unfulfilled") + UL)) + (S > V[g=4] > ((H[g=2 a=center] > Hd"Invoice"[level=2] + SD"Paid") + ML)) + (S > V[g=4] > ((H[g=2 a=center] > Hd"Timeline"[level=2] + B.ghost) + UL)))) + (LP[w=320 p=4] > V[g=4] > Col"Notes" + Col"Customer" + Col"Fraud analysis")
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill mw=1000] > (LH[divider p=6] > V[g=3] > ((H[g=4 a=start] > (SI[fill] > V[g=2] > (Lk"All orders" + (V[g=0] > Hd"#1001"[level=1] + (H[g=1 a=center wrap] > Tx"5 ordered items"[t=supporting] + (H[g=1 a=center] > Bu + Av"Vlad Dracul" + Tx"Vlad Dracul"[t=supporting]) + (H[g=1 a=center] > Bu + SD"Unfulfilled" + Tx"Unfulfilled"[t=supporting]) + (H[g=1 a=center] > Bu + Ic + Tx"02/23/2026"[t=supporting]) + (H[g=1 a=center] > Bu + Ic + Tx"Needs attention"[t=supporting]) + (H[g=1 a=center] > Bu + Lk"See all")))) + (H[g=2] > B.secondary"Restock" + B.secondary"Edit")) + (H[g=2] > (SI[fill] > V[a=stretch] > B.secondary"Restock") + (SI[fill] > V[a=stretch] > B.secondary"Edit")) + (H[a=center] > (SI[fill] > TL[size=lg] > (Tab"Details"! + Tab"Invoices" + Tab"Timeline" + TabMenu"More")) + B.ghost))) + (LC > V[g=4] > ((S > V[g=4] > ((H[g=2 a=center wrap] > (SI[fill] > (H[g=2 a=center] > Hd"Items"[level=2] + SD"Unfulfilled" + Tx"Unfulfilled"[t=supporting])) + (H[g=2] > B.ghost"Fulfill item" + B.secondary"Create label")) + (UL[density=spacious edge=outset] > LI*5)) + (S > V[g=4] > ((H[g=2 a=center wrap] > (SI[fill] > (H[g=2 a=center] > Hd"Invoice"[level=2] + SD"Paid" + Tx"Paid"[t=supporting])) + (H[g=2] > B.ghost"Refund" + B.secondary"Send Invoice")) + (ML > MLI*5) + D + (ML > MLI*1))) + (S > V[g=4] > ((H[g=2 a=center] > (SI[fill] > Hd"Timeline"[level=2]) + B.ghost"Filters") + (UL[density=spacious edge=outset] > LI*4)))) + (LP[w=320 p=4] > V[g=4] > Col"Notes" + Col"Customer" + Col"Fraud analysis")) ;; Dlg[variant=fullscreen] > L[h=auto] > (DH"Order details" + (LC[p=4] > V[g=4] > Col"Notes" + Col"Customer" + Col"Fraud analysis"))
4
6
 
5
7
  import { Avatar } from "@astryxdesign/core/Avatar";
6
8
  import { Button } from "@astryxdesign/core/Button";
@@ -50,16 +52,14 @@ import { useState } from "react";
50
52
 
51
53
  // Bleed the tab bar to the header's content edges so the active-tab underline
52
54
  // meets the header divider. No edge-dock prop on TabList (#2622).
55
+ //
56
+ // These are written as spacing-token arithmetic, not raw pixels: core's
57
+ // --spacing-* scale is `rem` since 0.7.0, so a literal -12px stops matching
58
+ // the padding it cancels at any root font size other than 16px.
53
59
  const tabsRow: CSSProperties = {
54
- marginInline: -12,
55
- marginBottom: -16,
56
- marginTop: 12,
57
- };
58
- // Pull the list items' inner padding back so their content optically aligns
59
- // with the section heading above (ListItem insets content by ~8px). No
60
- // edge/inset prop on List (#2626).
61
- const itemsList: CSSProperties = {
62
- marginInline: -8,
60
+ marginInline: "calc(var(--spacing-3) * -1)",
61
+ marginBottom: "calc(var(--spacing-4) * -1)",
62
+ marginTop: "var(--spacing-3)",
63
63
  };
64
64
 
65
65
  // ─── Product data ───────────────────────────────────────────────────────────
@@ -334,7 +334,7 @@ function ItemsCard() {
334
334
  </HStack>
335
335
  </HStack>
336
336
 
337
- <List density="spacious" style={itemsList}>
337
+ <List density="spacious" edge="outset">
338
338
  {PRODUCTS.map((product, i) => (
339
339
  <ListItem
340
340
  key={product.name}
@@ -482,7 +482,7 @@ function TimelineSection() {
482
482
  <Button label="Filters" variant="ghost" icon={<Icon icon={Filter} />} isIconOnly />
483
483
  </HStack>
484
484
 
485
- <List density="spacious" style={itemsList}>
485
+ <List density="spacious" edge="outset">
486
486
  {ACTIVITY.map((item) => (
487
487
  <ListItem
488
488
  key={`${item.user}-${item.time}`}
@@ -624,9 +624,9 @@ export default function DetailPage() {
624
624
  }
625
625
  end={!isNarrow && showSidePanel ? <RightPanel /> : undefined}
626
626
  />
627
- {/* Mobile: the side panel content opens as a full-screen dialog. (A
628
- side drawer/sheet would be more idiomatic, but Astryx has no Drawer
629
- component yet — #2575 — so we use the fullscreen Dialog variant.) */}
627
+ {/* Mobile: the side-panel content uses the full viewport so order details
628
+ are not squeezed beside narrow page chrome. Drawer remains available
629
+ for side-overlay flows that intentionally preserve page context. */}
630
630
  <Dialog
631
631
  variant="fullscreen"
632
632
  isOpen={isNarrow && isPanelDialogOpen}
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Design Documentation",
4
4
  description: "Live preview, usage guide, and code examples",
5
+ keywords: ["documentation", "docs", "design system", "reference", "guide", "spec"],
5
6
  category: "docs",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LC > V[g=8] > (V[g=2] > Hd"Button"[level=1] + Tx"March 30, 2026"[t=supporting]) + (C.muted[p=0] > Ctr[h=360]) + (V[g=4] > Hd"Usage"[level=2] + Tx"Usage"[t=body] + Hd"Best practices"[level=3] + T) + D + (V[g=4] > Hd"Examples"[level=2] + Tx"Explore"[t=body]) + (V[g=8] > (C[p=0] > (S[p=3] > Tx"Semantics"[t=body]) + Ctr[h=280] + (S.muted[p=3] > V[g=3] > (TL > Tab"Description"! + Tab"Code") + Tx"We have four"[t=body])) + (C[p=0] > (S[p=3] > Tx"Default button with badge"[t=body]) + Ctr[h=280] + (S.muted[p=3] > V[g=3] > (TL > Tab"Description"! + Tab"Code") + Tx"Buttons can include"[t=body])))) + (LP > Outline)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=auto mw=960] > (LC[p=8 !scroll] > V[g=8] > (V[g=2] > Hd"Button"[level=1 t=display-2] + Tx"March 30, 2026"[t=supporting] + SE{Selector}"On this page") + (C.muted[p=0] > Ctr[h=360]) + (V[g=4] > Hd"Usage"[level=2] + Tx"Usage"[t=body] + Hd"Best practices"[level=3] + T[hover density=spacious]) + D + (V[g=4] > Hd"Examples"[level=2] + Tx"Explore"[t=body]) + (V[g=8] > (C[p=0] > (S.transparent[p=3] > Tx"Semantics"[t=body]) + Ctr[h=280] + (S.muted[p=3 dv=[top]] > V[g=3] > (TL[size=sm] > (Tab"Description"! + Tab"Code")) + Tx"We have four"[t=body])) + (C[p=0] > (S.transparent[p=3] > Tx"Default button with badge"[t=body]) + Ctr[h=280] + (S.muted[p=3 dv=[top]] > V[g=3] > (TL[size=sm] > (Tab"Description"! + Tab"Code")) + Tx"Buttons can include"[t=body])))) + (LP[!scroll] > Outline)
4
6
 
5
7
  /**
6
8
  * Documentation detail — one component, its usage, its guidance and its live examples. (Frame/responsive/container: see XLE header above.)
@@ -89,7 +91,7 @@ const COMPONENT_DOCS: Record<
89
91
  },
90
92
  };
91
93
 
92
- const ACTIVE_DOCS = COMPONENT_DOCS["button"];
94
+ const ACTIVE_DOCS = COMPONENT_DOCS.button;
93
95
 
94
96
  // One preview node per example in ACTIVE_DOCS.examples, index-aligned. The
95
97
  // old EXAMPLE_PREVIEWS record carried only this key, so the record wrapper
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Technical Documentation",
4
4
  description: "Install steps, theming setup, and next steps",
5
+ keywords: ["documentation", "technical", "api reference", "spec", "manual", "reference"],
5
6
  category: "docs",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LC > V[g=8] > (V[g=2] > Hd"Getting started with Astryx Dracula"[level=1] + Tx"Last updated March 30, 2026"[t=supporting]) + (C > V[g=3] > (H[j=between] > (H[g=2] > Ic + Tx"AI Assistance"[t=body]) + B"Copy prompt") + Tx"Prompt description"[t=body]) + (V[g=4] > Hd"Prerequisites"[level=2] + UL) + D + (V[g=4] > Hd"Install the package"[level=2] + Tx"Description"[t=body] + (V[g=2] > Tx"Step"[t=body] + Cd)*3) + D + (V[g=4] > Hd"Configure theming"[level=2] + Tx"Description"[t=body] + Cd + Tx"Note"[t=body]) + D + (V[g=4] > Hd"Next steps"[level=2] + UL)) + (LP > Outline)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=auto mw=960] > (LC[p=8 !scroll] > V[g=8] > (V[g=2] > Hd"Getting started with Astryx Dracula"[level=1] + Tx"Last updated March 30, 2026"[t=supporting] + SE{Selector}"On this page") + (C > V[g=3] > (H[g=2 a=center] > (SI[fill] > (H[g=2 a=center] > Ic + Tx"AI Assistance"[t=body])) + B.ghost"Copy prompt") + Tx"Help me get set up"[t=body]) + (V[g=4] > Hd"Prerequisites"[level=2] + (UL[density=compact] > LI"Node.js 18+" + LI"React 18 or 19" + LI"A package manager")) + D + (V[g=4] > Hd"Install the package"[level=2] + Tx"Description"[t=body] + (V[g=2] > Tx"Step 1"[t=body] + Cd) + (V[g=2] > Tx"Step 2"[t=body] + Tx"Astryx ships precompiled CSS"[t=body] + Cd) + (V[g=2] > Tx"Step 3"[t=body] + Cd)) + D + (V[g=4] > Hd"Configure theming"[level=2] + Tx"Description"[t=body] + Cd + Tx"Note"[t=body]) + D + (V[g=4] > Hd"Next steps"[level=2] + (UL[density=compact] > LI"Fundamental concepts" + LI"Component API reference" + LI"Accessibility" + LI"CLI tools" + LI"Design tokens"))) + (LP[!scroll] > Outline)
4
6
 
5
7
  import { Button } from "@astryxdesign/core/Button";
6
8
  import { Card } from "@astryxdesign/core/Card";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Component Catalog",
4
4
  description: "Hero plus categorized component grid",
5
+ keywords: ["documentation", "docs", "guide", "manual", "reference", "handbook"],
5
6
  category: "docs",
6
7
  };
@@ -1,10 +1,12 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
3
5
  // Counts: 31 total, Core 18 / Layout 4 / Navigation 4 / Form 5. Derived at
4
6
  // render from COMPONENT_CATEGORIES, so these numerals must move together with
5
7
  // the array -- the gate in scripts/check.ts reads the rendered count, not this
6
8
  // comment.
7
- // L > LC > V[g=10] > (C[p=10] > (H[g=8 a=center] > (V[g=4] > Hd"The coven grimoire"[level=1 t=display-1] + Tx.lg"Every incantation in the Astryx spellbook"[t=large] + (H > B.primary"Enter the grimoire")))) + (V[g=4] > (H[j=between a=center] > Hd"Core"[level=2] + Tx"18 spells"[t=body]) + (H[j=between a=center] > Hd"Layout"[level=2] + Tx"4 spells"[t=body]) + (H[j=between a=center] > Hd"Navigation"[level=2] + Tx"4 spells"[t=body]) + (H[j=between a=center] > Hd"Form"[level=2] + Tx"5 spells"[t=body]) + (G[c={min:260} g=4] > (CC[p=4] > V[g=3] > C[p=0] + (V[g=1] > Tx"Avatar"[t=body] + Tx"Avatars represent"[t=body]))*4))
9
+ // L[h=fill mw=1200] > LC[p=8] > V[g=10] > (C.transparent[p=10] > (H[g=8 a=center] > (SI[fill] > V[g=4] > Hd"The coven grimoire"[level=1 t=display-1] + Tx.lg"Every incantation in the Astryx spellbook"[t=large] + (H > B.primary"Enter the grimoire")))) + (V[g=4] > (H[j=between a=center] > Hd"Core"[level=2] + Tx"18 spells"[t=body]) + (G[c={min:260} g=4] > (CC.transparent[p=4] > V[g=3] > (C.muted[p=0 h=160] > Scene{SceneTile}) + (V[g=1] > Tx"AppShell"[t=body] + Tx"AppShell provides"[t=body]))*18)) + (V[g=4] > (H[j=between a=center] > Hd"Layout"[level=2] + Tx"4 spells"[t=body]) + (G[c={min:260} g=4] > (CC.transparent[p=4] > V[g=3] > (C.muted[p=0 h=160] > Scene{SceneTile}) + (V[g=1] > Tx"Card"[t=body] + Tx"Cards group"[t=body]))*4)) + (V[g=4] > (H[j=between a=center] > Hd"Navigation"[level=2] + Tx"4 spells"[t=body]) + (G[c={min:260} g=4] > (CC.transparent[p=4] > V[g=3] > (C.muted[p=0 h=160] > Scene{SceneTile}) + (V[g=1] > Tx"Breadcrumbs"[t=body] + Tx"Breadcrumbs show"[t=body]))*4)) + (V[g=4] > (H[j=between a=center] > Hd"Form"[level=2] + Tx"5 spells"[t=body]) + (G[c={min:260} g=4] > (CC.transparent[p=4] > V[g=3] > (C.muted[p=0 h=160] > Scene{SceneTile}) + (V[g=1] > Tx"CheckboxInput"[t=body] + Tx"CheckboxInput renders"[t=body]))*5))
8
10
 
9
11
  /**
10
12
  * Documentation catalog — every component shelf in the grimoire. Frame-first layout (see `bunx astryx docs layout`): (Frame/responsive/container: see XLE header above.)
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Page Editor",
4
4
  description: "Block builder with sidebar config and preview",
5
+ keywords: ["editor", "ide", "code", "workspace", "files", "developer"],
5
6
  category: "tooling",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LP[w=320] > V[g=4] > (S[p=4] > V[g=4] > Hd"Page Editor"[level=1] + Tbar) + (V[g=4] > (TL > Tab"Blocks"! + Tab"Properties") + D + (S[p=4] > V[g=2] > Hd"Add Block"[level=3] + UL + Hd"Layers"[level=3] + UL))) + (LC > V[g=4] > C*3)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > (LP[w=320 p=0 divider] > V[g=4] > (S.transparent[p=4] > V[g=4] > (TI"Page title" + Hd"Page Editor"[level=1 t=display-2]) + Tbar) + (V[g=4] > (V[g=0] > (TL > Tab"Blocks"! + Tab"Properties") + D) + (S.transparent[p=4] > (V[g=2] > (V[g=1] > Hd"Add Block"[level=3] + UL) + (V[g=1] > Hd"Layers"[level=3] + UL)) + (V[g=4] > TI"Heading" + TA"Description")))) + (LC[p=8] > V[g=4] > SC*3) ;; Dlg[variant=fullscreen p=0] > L[h=fill] > (LH[divider] > (H[g=3 j=between a=center] > Hd"Customize"[level=3] + IB"Close")) + (LC[p=0] > (V[g=4] > (V[g=0] > (TL > Tab"Blocks"! + Tab"Properties") + D) + (S.transparent[p=4] > (V[g=2] > (V[g=1] > Hd"Add Block"[level=3] + UL) + (V[g=1] > Hd"Layers"[level=3] + UL)) + (V[g=4] > TI"Heading" + TA"Description")))))
4
6
 
5
7
  import { Button } from "@astryxdesign/core/Button";
6
8
  import { Center } from "@astryxdesign/core/Center";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "File Explorer",
4
4
  description: "Column-based file browser with preview",
5
+ keywords: ["file explorer", "files", "browser", "directories", "storage", "disk"],
5
6
  category: "tooling",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (Tbar[size=sm] > (H > IB"Go back" + IB"Go forward" + Tx"Folder"[t=label]) + (SG"View mode" > SGI*4) + (H > IB"Group" + IB"Share" + IB"Tags" + IB"More" + IB"Search")) + (LC[p=0 !scroll] > (Hd"File Explorer"[level=1] + H[h=fill] > (S.transparent[p=2 w=240 dv=[end]] > UL[density=compact !hasDividers] > (LI > Ic + Tx"Item"[t=body])*3)*3 + (S.transparent[p=6] > V[g=4 a=center] > Av[size=96] + (V[g=1 a=center] > Tx"Name"[t=body] + Tx"Kind"[t=supporting]) + (ML"Information" > MLI*3))))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > (Tbar[size=sm dv=[bottom]] > (IB"Go back" + IB"Go forward" + Tx"Folder"[t=label]) + (SG"View mode" > SGI*4) + (IB"Group" + IB"Share" + IB"Tags" + IB"More" + IB"Search")) + (LC[p=0 !scroll] > (VH"File Explorer" + H[h=100%] > (S.transparent[p=2 w=240 dv=[end]] > UL[density=compact !hasDividers] > (LI > Ic + Tx"Item"[t=body])*3)*3 + (S.transparent[p=4 w=320] > V[g=4 a=center] > Av[size=96] + (V[g=1 a=center] > Tx"Name"[t=body] + Tx"Kind"[t=supporting]) + (ML"Information" > MLI*3))))
4
6
 
5
7
  import { Avatar } from "@astryxdesign/core/Avatar";
6
8
  import { EmptyState } from "@astryxdesign/core/EmptyState";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Two-column Form",
4
4
  description: "Contact form with illustration and info strip",
5
+ keywords: ["form", "two column", "contact", "split", "signup", "lead"],
5
6
  category: "forms",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // Ctr > S.transparent[p=10] > V[g=10] > (G[c={min:280,max:2} g=10] > (V[g=6] > (V[g=3] > Hd"Let's conjure together"[level=1 t=display-1] + Tx"Tell us what you're brewing"[t=body]) + AR) + (C[p=4] > V[g=4] > Hd"Your details"[level=2] + TI"Full name"[req] + (G[c={min:180} g=3] > TI"Email"[req] + TI"Company") + (G[c={min:180} g=3] > TI"Job title" + TI"Phone") + (V[g=2] > Tx"Reason"[t=label] + (H[g=2] > Tk"Reason"*7)) + SE"Budget" + TA"Project details" + B.primary"Send it into the night")) + (V[g=6] > D + (G[c={min:200} g=6] > (V[g=1 a=center] > Tx"General"[t=supporting] + Lk"hello@castle.dracula")*3))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // Ctr > S.transparent[mw=1100 w=100% p=10] > V[g=10] > (G[c={min:280,max:2} g=10 a=center] > (V[g=6] > (V[g=3] > Hd"Let's conjure together"[level=1 t=display-1] + Tx"Tell us what you're brewing"[t=body]) + (AR[ratio=4/3] > Scene{SceneCastle})) + (C[p=4] > V[g=4] > Hd"Your details"[level=2] + TI"Full name"[req] + (G[c={min:180} g=3] > TI"Email"[req] + TI"Company name") + (G[c={min:180} g=3] > TI"Job title" + TI"Phone number") + (V[g=2] > Tx"What are you reaching out about?"[t=label] + (H[g=2] > Tk"Reason"*7)) + SE"Budget range" + TA"Project details" + Bn.success"Sent into the night" + (V[a=stretch] > B.primary"Send it into the night"))) + (V[g=6] > D + (G[c={min:200} g=6] > (V[g=1 a=center] > Tx"General"[t=supporting] + Lk"hello@castle.dracula")*3))
4
6
 
5
7
  import { AspectRatio } from "@astryxdesign/core/AspectRatio";
6
8
  import { Banner } from "@astryxdesign/core/Banner";
@@ -196,6 +198,10 @@ export default function TwoColumnForm() {
196
198
  {submitted && isValid && (
197
199
  <Banner
198
200
  status="success"
201
+ // Core 0.7.0 stopped deriving the live-region role from
202
+ // `status`, so this banner states its own. It mirrors the
203
+ // submit result, and a screen reader must hear it.
204
+ role="status"
199
205
  title="Sent into the night"
200
206
  description="The coven received your message and will answer after dark."
201
207
  />
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Gallery Hero",
4
4
  description: "Headline, CTAs, and three-image gallery",
5
+ keywords: ["gallery", "hero", "showcase", "carousel", "featured", "spotlight"],
5
6
  category: "marketing",
6
7
  };
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > LC[p=6] > V[g=10] > (V[g=6 a=center] > (V[g=3 a=center] > Hd"Little haunts, everywhere you roam"[level=1 t=display-2] + Tx"Sometimes all it takes"[t=body]) + (H[j=center g=3] > B.primary"Enter the gallery" + B.secondary"Read the lore")) + (G[c={min:200} g=4] > AR*3)
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=auto] > LC[p=6] > V[g=10] > (V[g=6 a=center] > (V[g=3 a=center] > Hd"Little haunts, everywhere you roam"[level=1 t=display-2] + Tx"Sometimes all it takes"[t=body]) + (H[j=center g=3] > B.primary"Enter the gallery" + B.secondary"Read the lore")) + (G[c={min:200} g=4] > AR[ratio=4/5] > Scene{SceneCastle}*3)
4
6
 
5
7
  import { AspectRatio } from "@astryxdesign/core/AspectRatio";
6
8
  import { Button } from "@astryxdesign/core/Button";
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "IDE Workspace",
4
4
  description: "Tabbed editor with terminal and properties",
5
+ keywords: ["ide", "editor", "terminal", "workspace", "code", "developer"],
5
6
  category: "tooling",
6
7
  };
package/templates/ide.tsx CHANGED
@@ -1,6 +1,8 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
- // XLE (canonical structure, validated with `bunx astryx layout check`):
3
- // L > (LP[p=4] > V[g=2] > TI"Search files" + TreeList) + (LC[p=0] > (Hd"Code editor"[level=1] + V > (SI[fill] > Cd) + (V > (TL > Tab"Terminal"! + Tab"Problems" + Tab"Output" + Tab"Debug") + Cd))) + (LP[p=4] > V[g=3] > (SG > SGI"Properties"! + SGI"History") + (V[g=3] > (V[g=1] > Hd"NightCounter.tsx"[level=3] + Tx"src/components/NightCounter.tsx"[t=supporting]) + ML + (V[g=2] > B.secondary"Format Document" + B.secondary"Go to Definition" + B.secondary"Find References")))
2
+ // XLE (canonical structure of the tree below; the CLI had no XLE validator
3
+ // after `astryx layout` was removed in 0.7.0, so this is a reading aid and a
4
+ // human drift check — update it with the file, never alone):
5
+ // L[h=fill] > LC[p=0] > (VH"Code editor" + L[h=fill] > (LP[w=256 p=4] > V[g=2] > TI"Search the night" + TrL) + RH + (LC[p=0] > L[h=fill] > (LC[p=0] > V > (SI[fill] > Cd) + RH + (V[h=300] > (TL[size=sm] > Tab"Terminal"! + Tab"Problems" + Tab"Output" + Tab"Debug") + (SI[fill] > Cd))) + (RH + (LP[w=320 p=4] > V[g=3] > (SG > SGI"Properties"! + SGI"History") + (V[g=3] > (V[g=1] > Hd"NightCounter.tsx"[level=3] + Tx"src/components/NightCounter.tsx"[t=supporting]) + ML + (V[g=2] > B.secondary"Format Document" + B.secondary"Go to Definition" + B.secondary"Find References")) + (V[g=1] > UL > LI*3)))))
4
6
 
5
7
  import { Button } from "@astryxdesign/core/Button";
6
8
  import { Center } from "@astryxdesign/core/Center";
@@ -34,11 +36,14 @@ const styles: Record<string, CSSProperties> = {
34
36
  },
35
37
  tabListPadding: {
36
38
  paddingTop: "var(--spacing-2)",
37
- // 4px inline = offset 2 + ring thickness 2, so the focus ring lands INSIDE
38
- // this box's clip instead of on its edge being cut in half. Deliberately
39
- // NOT applied to `terminalPanel`: that would inset the CodeBlock itself,
39
+ // The focus ring is a fixed 2px outline (core's defineTheme.ts), and the
40
+ // ring lands INSIDE this box's clip rather than on its edge being cut in
41
+ // half. The 2px of that is a PIXEL relationship, so it is written as
42
+ // pixels: --spacing-1 is rem since core 0.7.0, and at a 20px root it
43
+ // is 5px, which would clip the ring by a pixel. Deliberately NOT
44
+ // applied to `terminalPanel`: that would inset the CodeBlock itself,
40
45
  // moving the code rather than giving the ring somewhere to live.
41
- paddingInline: "var(--spacing-1)",
46
+ paddingInline: "calc(var(--spacing-1) + 2px)",
42
47
  },
43
48
  metadataCompact: {
44
49
  gap: "var(--spacing-1) var(--spacing-3)",
@@ -2,5 +2,6 @@ export default {
2
2
  type: "page",
3
3
  name: "Incident Console",
4
4
  description: "On-call incident rows with inspector timeline",
5
+ keywords: ["incident", "alert", "on-call", "outage", "ticket", "triage", "console"],
5
6
  category: "tooling",
6
7
  };