@uxelle/skills 0.2.0-beta.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 (117) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +58 -0
  3. package/dist/index.d.ts +26 -0
  4. package/dist/index.js +586 -0
  5. package/index.json +573 -0
  6. package/package.json +57 -0
  7. package/skills/uxelle-components/Accordion.md +51 -0
  8. package/skills/uxelle-components/AccordionGroup.md +39 -0
  9. package/skills/uxelle-components/Banner.md +73 -0
  10. package/skills/uxelle-components/BannerAnnouncement.md +63 -0
  11. package/skills/uxelle-components/Breadcrumb.md +38 -0
  12. package/skills/uxelle-components/Breadcrumbs.md +32 -0
  13. package/skills/uxelle-components/Bubble.md +34 -0
  14. package/skills/uxelle-components/Button.md +54 -0
  15. package/skills/uxelle-components/ButtonGroup.md +43 -0
  16. package/skills/uxelle-components/Card.md +35 -0
  17. package/skills/uxelle-components/Checkbox.md +57 -0
  18. package/skills/uxelle-components/CheckboxGroup.md +47 -0
  19. package/skills/uxelle-components/ChoiceChip.md +44 -0
  20. package/skills/uxelle-components/ChoiceChipGroup.md +50 -0
  21. package/skills/uxelle-components/DatePicker.md +59 -0
  22. package/skills/uxelle-components/DatePickerRange.md +73 -0
  23. package/skills/uxelle-components/Dialog.md +83 -0
  24. package/skills/uxelle-components/Divider.md +37 -0
  25. package/skills/uxelle-components/DynamicAngleLine.md +36 -0
  26. package/skills/uxelle-components/DynamicAngleLineCombo.md +30 -0
  27. package/skills/uxelle-components/DynamicAngleShape.md +32 -0
  28. package/skills/uxelle-components/DynamicAngleShapeSurface.md +35 -0
  29. package/skills/uxelle-components/DynamicAngleTexture.md +29 -0
  30. package/skills/uxelle-components/DynamicAngleTextureText.md +35 -0
  31. package/skills/uxelle-components/FieldMessage.md +31 -0
  32. package/skills/uxelle-components/FileUpload.md +53 -0
  33. package/skills/uxelle-components/FilterChip.md +35 -0
  34. package/skills/uxelle-components/FilterChipGroup.md +42 -0
  35. package/skills/uxelle-components/Footer.md +34 -0
  36. package/skills/uxelle-components/Hero.md +61 -0
  37. package/skills/uxelle-components/Icon.md +43 -0
  38. package/skills/uxelle-components/IconButton.md +44 -0
  39. package/skills/uxelle-components/Image.md +40 -0
  40. package/skills/uxelle-components/Label.md +35 -0
  41. package/skills/uxelle-components/LabelBadge.md +58 -0
  42. package/skills/uxelle-components/LanguageSelector.md +38 -0
  43. package/skills/uxelle-components/LanguageSelectorButton.md +34 -0
  44. package/skills/uxelle-components/Layout.md +81 -0
  45. package/skills/uxelle-components/LinearProgress.md +53 -0
  46. package/skills/uxelle-components/Link.md +52 -0
  47. package/skills/uxelle-components/List.md +35 -0
  48. package/skills/uxelle-components/ListControls.md +100 -0
  49. package/skills/uxelle-components/ListItem.md +69 -0
  50. package/skills/uxelle-components/Lockup.md +50 -0
  51. package/skills/uxelle-components/Logo.md +39 -0
  52. package/skills/uxelle-components/Menu.md +48 -0
  53. package/skills/uxelle-components/MultiSelect.md +54 -0
  54. package/skills/uxelle-components/NavLink.md +44 -0
  55. package/skills/uxelle-components/Navigation.md +61 -0
  56. package/skills/uxelle-components/NavigationSide.md +51 -0
  57. package/skills/uxelle-components/NavigationSideGroup.md +36 -0
  58. package/skills/uxelle-components/NavigationSideItem.md +56 -0
  59. package/skills/uxelle-components/NavigationSideSubItem.md +39 -0
  60. package/skills/uxelle-components/NotificationBadge.md +62 -0
  61. package/skills/uxelle-components/Pagination.md +49 -0
  62. package/skills/uxelle-components/PaginationComplex.md +51 -0
  63. package/skills/uxelle-components/PaginationSimple.md +44 -0
  64. package/skills/uxelle-components/ProductCard.md +46 -0
  65. package/skills/uxelle-components/Quantity.md +45 -0
  66. package/skills/uxelle-components/Radio.md +55 -0
  67. package/skills/uxelle-components/RadioGroup.md +49 -0
  68. package/skills/uxelle-components/SKILL.md +242 -0
  69. package/skills/uxelle-components/Scrim.md +28 -0
  70. package/skills/uxelle-components/SegmentedControl.md +118 -0
  71. package/skills/uxelle-components/Select.md +55 -0
  72. package/skills/uxelle-components/Sheet.md +31 -0
  73. package/skills/uxelle-components/Skeleton.md +35 -0
  74. package/skills/uxelle-components/Spinner.md +33 -0
  75. package/skills/uxelle-components/StatTile.md +150 -0
  76. package/skills/uxelle-components/Stepper.md +73 -0
  77. package/skills/uxelle-components/Switch.md +41 -0
  78. package/skills/uxelle-components/Tab.md +41 -0
  79. package/skills/uxelle-components/Table.md +55 -0
  80. package/skills/uxelle-components/TabsCompact.md +37 -0
  81. package/skills/uxelle-components/TabsStretch.md +35 -0
  82. package/skills/uxelle-components/Text.md +56 -0
  83. package/skills/uxelle-components/Textarea.md +77 -0
  84. package/skills/uxelle-components/Textfield.md +62 -0
  85. package/skills/uxelle-components/Tooltip.md +33 -0
  86. package/skills/uxelle-design-harness/SKILL.md +149 -0
  87. package/skills/uxelle-design-harness/a2ui.md +73 -0
  88. package/skills/uxelle-design-harness/how-to-accessibility.md +31 -0
  89. package/skills/uxelle-design-harness/how-to-color.md +82 -0
  90. package/skills/uxelle-design-harness/how-to-host.md +108 -0
  91. package/skills/uxelle-design-harness/how-to-page-layout.md +203 -0
  92. package/skills/uxelle-design-harness/principles.md +72 -0
  93. package/skills/uxelle-design-harness/recipe-app-chrome.md +168 -0
  94. package/skills/uxelle-design-harness/recipe-card-grid.md +104 -0
  95. package/skills/uxelle-design-harness/recipe-cta-band.md +91 -0
  96. package/skills/uxelle-design-harness/recipe-dashboard-overview.md +118 -0
  97. package/skills/uxelle-design-harness/recipe-data-table-page.md +323 -0
  98. package/skills/uxelle-design-harness/recipe-feature-section.md +96 -0
  99. package/skills/uxelle-design-harness/recipe-footer.md +156 -0
  100. package/skills/uxelle-design-harness/recipe-form-section.md +163 -0
  101. package/skills/uxelle-design-harness/recipe-hero.md +89 -0
  102. package/skills/uxelle-design-harness/recipe-landing-page.md +94 -0
  103. package/skills/uxelle-design-harness/recipe-logo-wall.md +80 -0
  104. package/skills/uxelle-design-harness/recipe-multi-step-flow.md +108 -0
  105. package/skills/uxelle-design-harness/recipe-page-header.md +102 -0
  106. package/skills/uxelle-design-harness/recipe-page-shell.md +82 -0
  107. package/skills/uxelle-design-harness/recipe-pricing.md +83 -0
  108. package/skills/uxelle-design-harness/recipe-query-bar.md +108 -0
  109. package/skills/uxelle-design-harness/recipe-record-detail.md +96 -0
  110. package/skills/uxelle-design-harness/recipe-settings-page.md +170 -0
  111. package/skills/uxelle-design-harness/recipe-stat-callouts.md +111 -0
  112. package/skills/uxelle-design-harness/recipe-states.md +119 -0
  113. package/skills/uxelle-design-harness/recipe-summary-list.md +88 -0
  114. package/skills/uxelle-design-harness/recipe-template.md +62 -0
  115. package/skills/uxelle-design-harness/recipe-testimonial.md +73 -0
  116. package/skills/uxelle-design-harness/spacing-steps.md +57 -0
  117. package/skills/uxelle-design-harness/tokens.md +101 -0
@@ -0,0 +1,62 @@
1
+ # Textfield
2
+
3
+ Import: `import { Textfield } from "@uxelle/components";`
4
+
5
+ Single-line text input with design tokens, optional `Label`, icon slots, and `FieldMessage`.
6
+
7
+ ## Props
8
+
9
+ <!-- prettier-ignore-start -->
10
+
11
+ | Prop | Type | Default | Description |
12
+ |------|------|---------|-------------|
13
+ | label | `boolean` | `true` | When false, the label row is not rendered; pass `aria-label` so the input keeps an accessible name. |
14
+ | labelText | `string` | `"Label"` | Visible label text, rendered as Body Medium Alt inside `Label`; ignored when `labelSlot` is set, and an empty string hides the label row. |
15
+ | labelSlot | `ReactNode` | `—` | Replaces `labelText` with custom content inside `Label`, which keeps `htmlFor` and the required asterisk. Pass `id` on `Textfield` for a stable label association. |
16
+ | fieldMessage | `boolean` | `false` | Renders a `FieldMessage` row below the input; `validation` set to `success` or `error` shows the row as well, so use this flag for neutral helper copy. |
17
+ | fieldMessageContent | `string` | `""` | Content for the `FieldMessage` row; when omitted, the row falls back to built-in copy for the current `validation` state. |
18
+ | validation | `"none" \| "success" \| "error"` | `"none"` | Validation state: `success` and `error` restyle the field message and force the row; `error` also sets `aria-invalid` and links the message via `aria-errormessage`. |
19
+ | leadingIcon | `boolean` | `false` | When true, renders the built-in leading `Icon` from `leadingIconName`; `leadingSlot` is the identical alias and `leading` overrides both. |
20
+ | leadingSlot | `boolean` | `false` | Alias of `leadingIcon`: either flag turns the leading region on, matching the `ListItem` slot naming. |
21
+ | leadingIconName | `string` | `"add"` | Material Symbol rendered in the leading region; used only when `leadingIcon` (or `leadingSlot`) is true and `leading` is unset. An empty string falls back to `add`. |
22
+ | leadingIconVariant | `"sharpFilled" \| "sharpUnfilled"` | `—` | Icon style for the built-in leading icon — `sharpUnfilled` (outlined) or `sharpFilled` (solid); ignored when `leading` supplies its own icon. |
23
+ | leading | `ReactNode` | `—` | Custom node rendered in the leading region instead of the built-in icon, with no need for `leadingIcon`. Buttons and links here keep their own click target. |
24
+ | trailingIcon | `boolean` | `false` | When true, renders the built-in trailing `Icon` from `trailingIconName`; `trailingSlot` is the identical alias, while `trailing` and `passwordVisibilityToggle` take the region over. |
25
+ | trailingSlot | `boolean` | `false` | Alias of `trailingIcon`: either flag turns the trailing region on, matching the `ListItem` slot naming. |
26
+ | trailingIconName | `string` | `"visibility_off"` | Material Symbol rendered in the trailing region; an empty string falls back to `visibility_off`. Used only when `trailingIcon` (or `trailingSlot`) is true and neither `trailing` nor `passwordVisibilityToggle` owns the region. |
27
+ | trailingIconVariant | `"sharpFilled" \| "sharpUnfilled"` | `—` | Icon style — `sharpUnfilled` (outlined) or `sharpFilled` (solid) — for the built-in trailing icon and for the `passwordVisibilityToggle` button icon. |
28
+ | trailing | `ReactNode` | `—` | Custom node rendered in the trailing region, taking precedence over `passwordVisibilityToggle` and the built-in trailing icon. Use it for actions such as a clear or search `IconButton`. |
29
+ | passwordVisibilityToggle | `boolean` | `false` | Adds a trailing `IconButton` that swaps the input between `password` and `text`, overriding `type` while it is on. Ignored when `trailing` is set; pair it with `autoComplete` (`current-password` or `new-password`). |
30
+ | showPasswordAriaLabel | `string` | `"Show password"` | `aria-label` on the password toggle while the value is masked; localize it together with `hidePasswordAriaLabel`. |
31
+ | hidePasswordAriaLabel | `string` | `"Hide password"` | `aria-label` on the password toggle while the value is visible; localize it together with `showPasswordAriaLabel`. |
32
+ | placeholder | `string` | `""` | Hint text shown inside the input while it is empty; it disappears on typing, so it is not a substitute for `labelText` or `aria-label`. |
33
+ | disabled | `boolean` | `false` | Blocks typing, removes the input from the tab order, and applies disabled styling; disabled inputs are not submitted with the form. |
34
+ | readOnly | `boolean` | `false` | Read-only state (token background, no hover; focus uses the focus stroke) |
35
+
36
+ <!-- prettier-ignore-end -->
37
+
38
+ ## Usage
39
+
40
+ ```tsx
41
+ <Textfield labelText="Email" placeholder="e.g. name@example.com" leadingIcon fieldMessage />
42
+ ```
43
+
44
+ ```tsx
45
+ <Textfield
46
+ labelText="Password"
47
+ type="password"
48
+ passwordVisibilityToggle
49
+ autoComplete="current-password"
50
+ name="password"
51
+ />
52
+ ```
53
+
54
+
55
+ ## Notes
56
+
57
+ - Associates label and field message with the input for accessibility.
58
+ - **Simple API** — `labelText`, `leadingIcon` / `trailingIcon`, and icon names.
59
+ - **Composable API** — `labelSlot`, `leading`, and `trailing` (same idea as `ListItem` slots). Use `leadingIcon` / `trailingIcon` or the equivalent `leadingSlot` / `trailingSlot` flags to show the side regions.
60
+ - **Password visibility** — `passwordVisibilityToggle` renders an accessible trailing toggle (unless `trailing` is set).
61
+ - **Multi-line** — Use `Textarea` for comments, notes, bios, and other multi-line copy. `Textfield` is single-line only.
62
+ - **Accessibility** — Pass `id` for stable `label` association; use `autoComplete` for known field types; pass `aria-label` when `label={false}`.
@@ -0,0 +1,33 @@
1
+ # Tooltip
2
+
3
+ Import: `import { Tooltip } from "@uxelle/components";`
4
+
5
+ Hover/focus supplementary disclosure (`role="tooltip"`).
6
+
7
+ ## Props
8
+
9
+ <!-- prettier-ignore-start -->
10
+
11
+ | Prop | Type | Default | Description |
12
+ |------|------|---------|-------------|
13
+ | children (required) | `ReactElement` | `—` | The trigger the tooltip attaches to and describes — usually a button, link, or icon. Must be a single React element (not a fragment or bare string): it is cloned to receive `aria-describedby` pointing at the panel while open, and hovering or focusing it is what reveals the panel. |
14
+ | content (required) | `ReactNode` | `—` | Supplementary text rendered inside the floating panel. Keep it short and non-interactive — the panel is `role="tooltip"` and cannot be tabbed into. |
15
+ | direction | `"Top Right" \| "Top Center" \| "Top Left" \| "Right Top" \| "Right Center" \| "Right Bottom" \| "Bottom Right" \| "Bottom Center" \| "Bottom Left" \| "Left Bottom" \| "Left Center" \| "Left Top"` | `"Top Right"` | Preferred panel position: the first word is the trigger edge the panel sits on, the second is its alignment along that edge. Flips to the opposite edge when the viewport lacks room. |
16
+ | open | `boolean` | `false` | Controlled visibility of the panel. Pass it with `onOpenChange`; omit it to let hover, focus, and Escape drive visibility internally. |
17
+ | onOpenChange | `(open: boolean) => void` | `—` | Called with the requested visibility whenever hover, focus, blur, or Escape asks to change it. Required when `open` is passed, since the component then keeps no visibility state of its own. |
18
+ | tooltipId | `string` | `""` | Id put on the panel and referenced by the trigger's `aria-describedby` while open. Leave empty to auto-generate a unique id. |
19
+ | tooltipLabel | `string` | `""` | Sets `aria-label` on the panel, replacing `content` as its accessible name when the visible text alone reads poorly. Leave empty to let `content` name the panel. |
20
+
21
+ <!-- prettier-ignore-end -->
22
+
23
+ ## Usage
24
+
25
+ ```tsx
26
+ <Tooltip content={/* ReactNode */}>
27
+ {/* ReactElement */}
28
+ </Tooltip>
29
+ ```
30
+
31
+ ## Notes
32
+
33
+ - Use non-interactive `content` and theme tokens for color/contrast. Omit `open` for hover/focus-driven visibility. Pass `open` (with `onOpenChange`) to control visibility, including design/docs previews.
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: uxelle-design-harness
3
+ description: >-
4
+ The single home for building on-brand, enterprise uxElle experiences: Swiss
5
+ design principles, the --uxl-* variable foundation (layout spacing, page
6
+ chrome, color-switcher palettes, radius, elevation, type), first-class mobile
7
+ responsiveness, WCAG AA, and composition recipes for product and marketing
8
+ surfaces (app chrome, dashboards, data tables, record detail, settings,
9
+ multi-step flows, states, landing pages, heroes, pricing, CTAs) across React
10
+ (@uxelle/components) and A2UI (@uxelle/a2ui). Use when generating pages, apps,
11
+ forms, layouts, dashboards, marketing/landing pages, greenfield React, or A2UI
12
+ surfaces, or when writing CSS / inline styles that need --uxl-* tokens.
13
+ ---
14
+
15
+ # uxElle design harness
16
+
17
+ The home for generating on-brand uxElle experiences. It carries the design
18
+ **principles**, the **variable foundation** (tokens), the **layout and
19
+ responsiveness** rules, and the **recipes** that compose components into whole
20
+ experiences and reusable pieces.
21
+
22
+ One approach, two projections: **React** (`@uxelle/components`) for IDE agents
23
+ and **A2UI** (`getUxelleRecipe` from `@uxelle/a2ui`) for runtime hosts. Write the
24
+ design once; [a2ui.md](a2ui.md) maps it to the runtime track.
25
+
26
+ ## Philosophy
27
+
28
+ Design like the International Typographic (Swiss) school: a clear grid, strong
29
+ typographic hierarchy, generous whitespace, restraint, and objective, content-first
30
+ layouts. Restraint is **context-aware** — product surfaces are maximally calm;
31
+ marketing surfaces are expressive within the *same* grid, hierarchy, and limited
32
+ palette. The full mapping of principles to uxElle mechanisms lives in
33
+ [principles.md](principles.md).
34
+
35
+ ## Use the harness
36
+
37
+ 1. Load this `SKILL.md`. The foundations below always apply.
38
+ 2. Read the variable foundation once: [tokens.md](tokens.md) and
39
+ [spacing-steps.md](spacing-steps.md).
40
+ 3. Creating an app shell? [how-to-host.md](how-to-host.md). Building a page body?
41
+ [how-to-page-layout.md](how-to-page-layout.md) (layout **and** responsiveness),
42
+ [how-to-color.md](how-to-color.md), and [how-to-accessibility.md](how-to-accessibility.md).
43
+ 4. Prefer an existing component. Link its doc at point of use, e.g.
44
+ `Table` -> `../uxelle-components/Table.md`. Import from `@uxelle/components`.
45
+ 5. Otherwise follow a recipe (see the index). If nothing fits, compose `Layout` +
46
+ `Text` + primitives on the grid.
47
+ 6. Building a runtime surface? Read [a2ui.md](a2ui.md) and each recipe's **A2UI** note.
48
+ 7. Before you finish, run the quality checklist below.
49
+
50
+ ## Decision tree
51
+
52
+ - **New app/host** (loads theme CSS, `data-*`, skip link, `main`) -> [how-to-host.md](how-to-host.md).
53
+ Composing inside an existing host -> skip host setup; do not set theme `data-*` on `<html>`.
54
+ - **Product experience** (signed-in app):
55
+ app frame -> [recipe-app-chrome.md](recipe-app-chrome.md);
56
+ landing/overview -> [recipe-dashboard-overview.md](recipe-dashboard-overview.md);
57
+ records list -> [recipe-data-table-page.md](recipe-data-table-page.md);
58
+ one record -> [recipe-record-detail.md](recipe-record-detail.md);
59
+ settings -> [recipe-settings-page.md](recipe-settings-page.md);
60
+ wizard/checkout -> [recipe-multi-step-flow.md](recipe-multi-step-flow.md);
61
+ generic body -> [recipe-page-shell.md](recipe-page-shell.md).
62
+ - **Marketing experience** (public): whole page -> [recipe-landing-page.md](recipe-landing-page.md),
63
+ composed from the marketing pieces below.
64
+ - **A piece** (part of an experience): page intro -> [recipe-page-header.md](recipe-page-header.md);
65
+ filter/search toolbar -> [recipe-query-bar.md](recipe-query-bar.md);
66
+ form block -> [recipe-form-section.md](recipe-form-section.md);
67
+ key/value summary -> [recipe-summary-list.md](recipe-summary-list.md);
68
+ card row -> [recipe-card-grid.md](recipe-card-grid.md);
69
+ metrics -> [recipe-stat-callouts.md](recipe-stat-callouts.md);
70
+ empty/loading/error -> [recipe-states.md](recipe-states.md);
71
+ page footer -> [recipe-footer.md](recipe-footer.md);
72
+ hero -> [recipe-hero.md](recipe-hero.md); feature -> [recipe-feature-section.md](recipe-feature-section.md);
73
+ trust bar -> [recipe-logo-wall.md](recipe-logo-wall.md); testimonial -> [recipe-testimonial.md](recipe-testimonial.md);
74
+ pricing -> [recipe-pricing.md](recipe-pricing.md); closing CTA -> [recipe-cta-band.md](recipe-cta-band.md).
75
+
76
+ ## Core rules
77
+
78
+ - **Spacing**: stacks use `0` or `var(--uxl-theme-layout-spacing-*)` on `gap` /
79
+ padding / margin. Page chrome (inset, column cap, `fr` gaps) uses
80
+ `--uxl-breakpoints-margin` / `-max-container-width` / `-gutter`. See
81
+ [spacing-steps.md](spacing-steps.md) and [how-to-page-layout.md](how-to-page-layout.md).
82
+ - **Color**: style via `--uxl-color-switcher-*` roles; apply a palette with
83
+ `data-color-switcher` on a **region** (never invent switcher names). See
84
+ [how-to-color.md](how-to-color.md).
85
+ - **No fabrication**: never invent `--uxl-*` names, never `var(--token, fallback)`,
86
+ never use `--uxl-component-*` in app/recipe CSS (those belong inside components).
87
+ - **No hardcoded values**: no hex, no font-family, no breakpoint px. Read
88
+ breakpoint bounds from theme variables when JS is unavoidable
89
+ ([how-to-page-layout.md](how-to-page-layout.md)). Exception: one-column reading
90
+ content (a form/settings page, or a form / FAQ / prose section on a wider page)
91
+ may cap at the `maxWidth="600px"` **reading measure** — always centered with
92
+ `mh="auto"` ([how-to-page-layout.md](how-to-page-layout.md#reading-measure)).
93
+ - **Components first**: prefer a catalog component over bespoke markup; link its
94
+ doc at point of use (`../uxelle-components/<Name>.md`); do not open package source.
95
+ - **Recipes are patterns, not exports**: never add `PageShell` / `AppChrome` /
96
+ `FormSection` to `@uxelle/components`, and never author new recipes in the
97
+ customer app — contribute them back to uxElle ([recipe-template.md](recipe-template.md)).
98
+ - **A2UI**: catalog adapters only — no `className` / `style`, layout-spacing only,
99
+ `import { getUxelleRecipe } from "@uxelle/a2ui"`. See [a2ui.md](a2ui.md).
100
+
101
+ ## Quality checklist (run before you finish)
102
+
103
+ Every generated screen must pass this. It is the definition of done.
104
+
105
+ - **Grid & rhythm**: content sits on the grid; one capped content column via
106
+ `--uxl-breakpoints-max-container-width` / `-gutter` / `-margin`; section spacing
107
+ from the ramp (page sections use `medium-12`). One-column reading sections
108
+ (form / FAQ / prose) share the `600px` reading measure and are centered
109
+ (`mh="auto"`); a decision cluster (form actions) is separated from its fields by
110
+ `medium-12`, not the field gap.
111
+ - **Tokens only**: spacing from `--uxl-theme-layout-spacing-*`; color from
112
+ `--uxl-color-switcher-*`; no hardcoded hex or px, no invented `--uxl-*`, no
113
+ `--uxl-component-*` in app CSS, no `var(--x, fallback)`.
114
+ - **Hierarchy**: exactly one `h1`; heading ranks unbroken; few `Text` type roles.
115
+ - **Responsive**: reflows mobile -> up with no px literals; clusters stack, `Table`
116
+ scrolls, nav collapses; touch targets stay >= 24 CSS px.
117
+ - **Color discipline**: at most one dominant brand band per view; status palettes
118
+ only for semantic status, never color-alone (paired with text or icon).
119
+ - **Accessibility**: skip link + one `main`; landmarks named; focus visible; every
120
+ control has an accessible name; async regions announced.
121
+ - **Components first**: composed existing components (linked at point of use) over
122
+ bespoke markup; no recipe exported as a component; package source not opened.
123
+ - **A2UI (if used)**: catalog adapters only; no `className` / `style`; layout-spacing only.
124
+
125
+ ## Index
126
+
127
+ **Foundations** (always apply): [principles.md](principles.md) ·
128
+ [tokens.md](tokens.md) · [spacing-steps.md](spacing-steps.md) ·
129
+ [how-to-page-layout.md](how-to-page-layout.md) · [how-to-color.md](how-to-color.md) ·
130
+ [how-to-accessibility.md](how-to-accessibility.md) · [how-to-host.md](how-to-host.md) ·
131
+ [a2ui.md](a2ui.md)
132
+
133
+ **Experiences** — product: [app-chrome](recipe-app-chrome.md) ·
134
+ [page-shell](recipe-page-shell.md) · [dashboard-overview](recipe-dashboard-overview.md) ·
135
+ [data-table-page](recipe-data-table-page.md) · [record-detail](recipe-record-detail.md) ·
136
+ [settings-page](recipe-settings-page.md) · [multi-step-flow](recipe-multi-step-flow.md).
137
+ Marketing: [landing-page](recipe-landing-page.md).
138
+
139
+ **Pieces** — shared: [page-header](recipe-page-header.md) ·
140
+ [form-section](recipe-form-section.md) · [query-bar](recipe-query-bar.md) ·
141
+ [card-grid](recipe-card-grid.md) · [summary-list](recipe-summary-list.md) ·
142
+ [states](recipe-states.md) · [stat-callouts](recipe-stat-callouts.md) ·
143
+ [logo-wall](recipe-logo-wall.md) · [footer](recipe-footer.md). Marketing: [hero](recipe-hero.md) ·
144
+ [feature-section](recipe-feature-section.md) · [testimonial](recipe-testimonial.md) ·
145
+ [pricing](recipe-pricing.md) · [cta-band](recipe-cta-band.md).
146
+
147
+ **Component APIs**: link each at point of use — [uxelle-components](../uxelle-components/SKILL.md).
148
+
149
+ **Contributing** a recipe: [recipe-template.md](recipe-template.md).
@@ -0,0 +1,73 @@
1
+ # A2UI: the runtime translation layer
2
+
3
+ A2UI is the runtime-host projection of the same designs. Instead of React JSX, a
4
+ host renders uxElle components from catalog **adapters** driven by JSON messages.
5
+ Design the experience once with the principles, tokens, and recipes here; this file
6
+ maps it to A2UI. Each recipe also carries a short **A2UI** note with its specifics.
7
+
8
+ ```ts
9
+ import { getUxelleRecipe, uxelleCatalogSchema } from "@uxelle/a2ui";
10
+ ```
11
+
12
+ Hosts inject `uxelleCatalogSchema` (and optionally a recipe's messages) into the
13
+ agent prompt and render the result. Do not open package source to "discover" props —
14
+ use the catalog schema the host provides.
15
+
16
+ ## Hard constraints
17
+
18
+ - **Catalog adapters only.** No raw HTML, no custom components.
19
+ - **No `className` / `style`.** Styling comes from the theme and adapter props.
20
+ - **Layout-spacing tokens only.** `A2uiLayout` accepts `0` or
21
+ `var(--uxl-theme-layout-spacing-*)`; never emit page-chrome breakpoint tokens.
22
+ - **No responsive JS.** There is no `matchMedia`. Default to a single, narrow
23
+ column (chat is mobile-like) and stack action clusters (`"direction": "column"`).
24
+ - **Host owns theme.** Never set theme `data-*` or a skip link from adapters; the
25
+ host wraps content in its theme scope.
26
+ - **Bind, don't hold state.** Wire values through the host data model (bindings),
27
+ not React state.
28
+
29
+ ## Prebuilt recipes
30
+
31
+ Registered runtime recipes today:
32
+
33
+ - `getUxelleRecipe("page-shell")`
34
+ - `getUxelleRecipe("form-section")`
35
+ - `getUxelleRecipe("navigation-side")` — side rail; Overview trailing
36
+ `A2uiLabelBadge` uses `"emphasis": "high"`; account row is `A2uiList` +
37
+ `A2uiListItem` (`label` plus optional `bottomText`)
38
+
39
+ Every other recipe in this harness has **no `getUxelleRecipe` yet** — compose it
40
+ from adapters following the recipe's regions and its A2UI note. Do not duplicate
41
+ recipe JSON into the customer app.
42
+
43
+ ## Adapter map
44
+
45
+ Most catalog components map 1:1 to an `A2ui<Name>` adapter (e.g. `Button` ->
46
+ `A2uiButton`, `Textfield` -> `A2uiTextfield`, `Textarea` -> `A2uiTextarea`,
47
+ `Table` -> `A2uiTable`, `Sheet` -> `A2uiSheet`, `Hero` -> `A2uiHero`,
48
+ `Stepper` -> `A2uiStepper` + `A2uiStepperItem`, `ListControls` -> `A2uiListControls`,
49
+ `Banner` -> `A2uiBanner`, `LabelBadge` -> `A2uiLabelBadge`, `StatTile` -> `A2uiStatTile`,
50
+ `DynamicAngle*` -> `A2uiDynamicAngle*`). `Table` has the full family (`A2uiTableGrid`,
51
+ `A2uiTableHead`, `A2uiTableBody`, `A2uiTableRow`, `A2uiTableCell`,
52
+ `A2uiTableHeaderCell`, `A2uiTableColumnSizingProvider`).
53
+
54
+ Known gaps — substitute rather than invent:
55
+
56
+ | React | A2UI |
57
+ |-------|------|
58
+ | `Lockup` | no adapter — stack `A2uiText` (eyebrow / title / body) |
59
+ | `TabsCompact` / `TabsStretch` | `A2uiTabGroup` + `A2uiTab` |
60
+ | `Pagination` / `PaginationSimple` / `PaginationComplex` | no adapter yet — omit or use a bound prev/next with `A2uiButton` |
61
+ | `SkeletonGroup` | no adapter — repeat `A2uiSkeleton` |
62
+ | `Quantity` | no adapter — use `A2uiTextfield` (numeric) |
63
+
64
+ If a design needs a gap component as its backbone, say so in the recipe's
65
+ **when-not** and pick the closest supported composition.
66
+
67
+ ## Translating a React recipe
68
+
69
+ 1. Keep the same region order and layout-spacing values.
70
+ 2. Swap each component for its adapter; expand `Lockup` to stacked `A2uiText`.
71
+ 3. Replace `useBreakpointUp` switches with a single narrow column.
72
+ 4. Replace React state with host bindings.
73
+ 5. Drop skip link and theme `data-*` (host-owned).
@@ -0,0 +1,31 @@
1
+ # How to: accessibility (generated UI)
2
+
3
+ WCAG 2.x **Level AA** for pages and composed experiences. Prefer catalog components (`Button`, `Textfield`, `Textarea`, `Dialog`, …) so keyboard, focus rings, and field associations come for free. Contrast is theme-owned — use `--uxl-color-switcher-*`.
4
+
5
+ ## Baseline
6
+
7
+ - One `h1`, then `h2`… with no skipped ranks (`Text as="h1"` / `as="h2"`).
8
+ - One `main`. If nav/chrome exists, put a skip link first in the DOM (`href="#main-content"`). CSS: [how-to-host.md](how-to-host.md).
9
+ - Landmarks: `Layout as="main"|"nav"|"section"`. Name a region with a visible heading (`aria-labelledby`) or `aria-label` when there is no heading. `NavigationSide` is chrome (`<aside>`, or `<header>` when `mobile`) — not a `nav`. When `mobile`, the menu opens a right `Sheet` that already contains the same `NavigationSideGroup` landmarks. `NavigationSideGroup` is already a named `<nav>` — do not wrap it in another `nav`. Pass `aria-label` when more than one group is on the page. SSR hosts must pass `mobile` on `NavigationSide` (`true` or `false`); omitting it hydrates the rail on the server and can swap to the top bar on the client.
10
+ - Native controls: `Button`, `Link`, catalog fields — not clickable `div`s.
11
+ - Visible label first. `aria-label` only when there is no visible name (icon-only `IconButton`, unlabeled `ButtonGroup`).
12
+ - Decorative `Icon` stays default-hidden. Meaningful icons: `role="img"` + `aria-label`.
13
+ - Color is not the only status signal (pair with text or icon).
14
+ - Keyboard: no custom traps (`Dialog` / `Sheet` already trap). DOM order = tab order. No positive `tabindex`. Do not remove or restyle catalog `:focus-visible` rings.
15
+ - Pointer targets: use catalog controls (they meet 24×24 CSS px). Do not shrink hit areas with custom CSS.
16
+ - Decorative motion (`DynamicAngle*`, transitions) is muted under `prefers-reduced-motion: reduce`. Do not add app animation that ignores it.
17
+ - Injected status: `role="status"` or `aria-live="polite"`. Field errors: `FieldMessage` `Danger` (catalog fields wire `aria-invalid` / `aria-errormessage`).
18
+ - `ButtonGroup` / `RadioGroup` / `CheckboxGroup`: visible legend or `aria-label`.
19
+
20
+ ## ARIA helpers
21
+
22
+ - `aria-label` — accessible name when no visible text (keep short; do not duplicate visible copy).
23
+ - `aria-labelledby` — id(s) of a visible heading/label that name this region or control.
24
+ - `aria-describedby` — extra help, not the name (`fieldDescription`, instructions).
25
+ - `aria-hidden="true"` — decorative / redundant graphics (default `Icon`).
26
+ - `aria-live="polite"` — status that appears without moving focus. `assertive` only for urgent interruptions.
27
+ - `aria-current="page"` — current item in nav (`NavLink`, or `activated` on `NavigationSideItem` / `NavigationSideSubItem` destinations — not accordion parents).
28
+ - `aria-expanded` — only on a real disclosure control, not on every section.
29
+ - `aria-pressed` — toggle buttons (`IconButton` `activated`); `Switch` uses `checked` instead.
30
+
31
+ Do not invent roles on `Layout` when `as` already maps (`main`, `nav`, `section`). Do not `aria-label` headings or buttons that already have visible text.
@@ -0,0 +1,82 @@
1
+ # How to: color and the color switcher
2
+
3
+ uxElle color is applied by **palette**, not by hardcoded values. Style every
4
+ themeable surface with the `--uxl-color-switcher-*` role tokens (the role table is
5
+ in [tokens.md](tokens.md)); choose which palette those roles resolve to with
6
+ `data-color-switcher`.
7
+
8
+ ## Mechanism
9
+
10
+ `data-color-switcher="<palette>"` on a region remaps the `--uxl-color-switcher-*`
11
+ roles for that subtree; nested components inherit from the nearest ancestor.
12
+
13
+ - Set it on a **region** — a nav band, hero, section band, banner, or badge — not
14
+ on `<html>`. The host owns the page-level default (`default`).
15
+ - Some components take a `dataColorSwitcher` prop *or* the `data-color-switcher`
16
+ attribute (e.g. `LabelBadge`, `BannerAnnouncement`, `Button`, `DynamicAngle*`).
17
+ The attribute wins when both are set; for buttons rendered into another
18
+ component's slot, pass the prop so the palette reaches the DOM.
19
+ - Always style with role tokens inside the region. Never hardcode hex — the palette
20
+ guarantees text/headline contrast on its own surface.
21
+
22
+ ```tsx
23
+ // A brand band: one region, one palette, role tokens throughout.
24
+ <Layout
25
+ as="section"
26
+ data-color-switcher="brand-1"
27
+ p="var(--uxl-theme-layout-spacing-large-13)"
28
+ style={{
29
+ backgroundColor: "var(--uxl-color-switcher-background)",
30
+ color: "var(--uxl-color-switcher-text)",
31
+ }}
32
+ >
33
+ {/* Text + Button inside inherit this palette */}
34
+ </Layout>
35
+ ```
36
+
37
+ ## Palette catalog
38
+
39
+ - **`default`** — the page baseline: neutral surface and text. The default look
40
+ for product surfaces.
41
+ - **`default-subtle`** — a low-contrast neutral fill to separate a section, well,
42
+ or sidebar *without* introducing brand color (alternating sections, cards on a
43
+ neutral page).
44
+ - **`neutral`** — an internal subtle neutral used by some components (e.g. file
45
+ lists). Component-owned; you rarely set it by hand.
46
+ - **`success` / `warning` / `danger` / `info`** — semantic **status** only, on
47
+ `Banner`, `BannerAnnouncement`, `LabelBadge`, and inline feedback (`Textarea`
48
+ `softOverflow` uses `data-color-switcher="warning"` on the counter; pass
49
+ `softOverflowMessage` for a warning `FieldMessage`). Never
50
+ decorative, and never the only signal: pair the color with text or an icon.
51
+ - **`brand-1` / `brand-2` / `brand-3` / `brand-4`** — the expressive, high-impact
52
+ palettes. See below.
53
+
54
+ ## Choosing a brand palette
55
+
56
+ `brand-1..4` are the high-impact set, meant for high-impact components — heroes,
57
+ CTA bands, and loud statements in general. They have **no priority order and no
58
+ fixed per-index meaning**: which hue each maps to is theme-owned and differs across
59
+ platforms and themes, so never assume "brand-1 = red / primary" or
60
+ "brand-2 = informational."
61
+
62
+ To choose:
63
+
64
+ - Reach for a brand palette when a region should make a statement (hero, CTA,
65
+ standout feature band); keep product task surfaces on `default` / `default-subtle`.
66
+ - Pick whichever palette **renders** the look you want, and confirm the rendered
67
+ output (e.g. in Storybook) rather than assuming a color.
68
+ - Use **one dominant brand band per view** and let `default` / `default-subtle`
69
+ carry the calmer regions, so the loud band stays loud.
70
+
71
+ ## Do / don't
72
+
73
+ - Do apply a palette on the region, and style children with role tokens.
74
+ - Do keep status palettes for real status, paired with text or an icon.
75
+ - Don't set `data-color-switcher` on `<html>` or invent palette names.
76
+ - Don't hardcode hex/rgb, and don't stack multiple loud brand bands in one view.
77
+
78
+ ## A2UI
79
+
80
+ Set the palette through the adapter where a prop exists (e.g. `A2uiBanner` status,
81
+ `A2uiLabelBadge`); otherwise wrap the region in one `A2uiLayout` with the switcher.
82
+ One palette per region, same rules as above.
@@ -0,0 +1,108 @@
1
+ # How to: host (React app entry)
2
+
3
+ Use this when **creating** a React app shell — the same shell serves product and
4
+ marketing surfaces. If the host (an MCP runtime or existing app) already loads
5
+ theme CSS, component CSS, and `data-*` on `<html>`, skip this file and compose
6
+ pages inside it.
7
+
8
+ Agents consume **published packages**, not repo filesystem paths. Do not import
9
+ `packages/themes/build/…` or invent Vite aliases to source.
10
+
11
+ ## Load CSS
12
+
13
+ Theme CSS is a **placeholder import** — use the theme id the host documents.
14
+ Open-source example:
15
+
16
+ ```ts
17
+ import "@uxelle/themes/open-source";
18
+ import "@uxelle/components/styles.css";
19
+ ```
20
+
21
+ Until `@uxelle/components/styles.css` is the full bundle, also load extracted
22
+ component CSS:
23
+
24
+ ```ts
25
+ import "@uxelle/components/index.css";
26
+ ```
27
+
28
+ Enterprise hosts swap the theme module (`@uxelle/themes/<theme-id>`) and the root
29
+ data attribute. Do not set `font-family` in app CSS — `Text` uses theme tokens.
30
+ Load the typeface the theme expects (open-source: Open Sans).
31
+
32
+ On `<html>`:
33
+
34
+ - Theme mode (host-owned): `data-open-source="light" | "dark"` (other themes use
35
+ `data-<theme-id>`).
36
+ - Color switcher default: `data-color-switcher="default"` on `<html>`. Apply other
37
+ palettes per region, not here ([how-to-color.md](how-to-color.md)).
38
+
39
+ Optional: `UXelleThemeProvider` from `@uxelle/themes/react` with
40
+ `theme="open-source"` keeps those attributes in sync.
41
+
42
+ ## Skip link
43
+
44
+ First focusable node in the DOM, targeting `id="main-content"` on `<main>`:
45
+
46
+ ```css
47
+ .uxl-skip-link {
48
+ position: absolute;
49
+ z-index: 100;
50
+ inset-inline-start: var(--uxl-theme-layout-spacing-small-4);
51
+ inset-block-start: var(--uxl-theme-layout-spacing-small-4);
52
+ padding: var(--uxl-theme-layout-spacing-small-4);
53
+ background-color: var(--uxl-color-switcher-background);
54
+ color: var(--uxl-color-switcher-text);
55
+ text-decoration: underline;
56
+ }
57
+
58
+ .uxl-skip-link:not(:focus-visible) {
59
+ width: 1px;
60
+ height: 1px;
61
+ padding: 0;
62
+ margin: -1px;
63
+ overflow: hidden;
64
+ clip: rect(0, 0, 0, 0);
65
+ white-space: nowrap;
66
+ border: 0;
67
+ }
68
+
69
+ .uxl-skip-link:focus-visible {
70
+ outline: 2px solid var(--uxl-color-switcher-interactive-icon);
71
+ outline-offset: 2px;
72
+ }
73
+ ```
74
+
75
+ ## React entry
76
+
77
+ ```tsx
78
+ <html data-open-source="light" data-color-switcher="default">
79
+ ```
80
+
81
+ ```tsx
82
+ <Layout
83
+ display="flex"
84
+ flexDirection="column"
85
+ height="100%"
86
+ style={{
87
+ backgroundColor: "var(--uxl-color-switcher-background)",
88
+ overflow: "hidden",
89
+ }}
90
+ >
91
+ <a className="uxl-skip-link" href="#main-content">
92
+ Skip to main content
93
+ </a>
94
+ {/* Navigation — recipe-app-chrome.md */}
95
+ <main id="main-content" tabIndex={-1} style={{ flexGrow: 1, minHeight: 0, overflow: "auto" }}>
96
+ {/* page column — how-to-page-layout.md */}
97
+ {/* Footer — inside this scrollport; recipe-app-chrome.md */}
98
+ </main>
99
+ </Layout>
100
+ ```
101
+
102
+ Set `html, body, #root { height: 100%; margin: 0; }` so the column can fill the
103
+ viewport.
104
+
105
+ ## A2UI hosts
106
+
107
+ A2UI runtimes load the same theme CSS and wrap content in `A2uiThemeScope`; they do
108
+ **not** emit skip-link CSS or theme `data-*` from adapters. See [a2ui.md](a2ui.md).