@moldable-ai/ui 0.2.29 → 0.2.32

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 (215) hide show
  1. package/dist/catalog/component-catalog.d.ts +9 -2
  2. package/dist/catalog/component-catalog.d.ts.map +1 -1
  3. package/dist/catalog/component-catalog.js +11 -7
  4. package/dist/catalog/core-control-stories.d.ts.map +1 -1
  5. package/dist/catalog/core-control-stories.js +1 -1
  6. package/dist/catalog/core-foundation-stories.d.ts.map +1 -1
  7. package/dist/catalog/core-foundation-stories.js +5 -5
  8. package/dist/components/app-error-boundary.d.ts +1 -1
  9. package/dist/components/chat/chat-image-lightbox.d.ts +8 -0
  10. package/dist/components/chat/chat-image-lightbox.d.ts.map +1 -1
  11. package/dist/components/chat/chat-image-lightbox.js +24 -2
  12. package/dist/components/chat/chat-input.d.ts +3 -2
  13. package/dist/components/chat/chat-input.d.ts.map +1 -1
  14. package/dist/components/chat/chat-input.js +3 -3
  15. package/dist/components/chat/chat-message.d.ts.map +1 -1
  16. package/dist/components/chat/chat-message.js +3 -1
  17. package/dist/components/chat/chat-panel.d.ts +3 -1
  18. package/dist/components/chat/chat-panel.d.ts.map +1 -1
  19. package/dist/components/chat/chat-panel.js +53 -39
  20. package/dist/components/chat/conversation-history.d.ts +4 -2
  21. package/dist/components/chat/conversation-history.d.ts.map +1 -1
  22. package/dist/components/chat/conversation-history.js +20 -15
  23. package/dist/components/ui/alert.d.ts +1 -1
  24. package/dist/components/ui/app-frame.d.ts +20 -1
  25. package/dist/components/ui/app-frame.d.ts.map +1 -1
  26. package/dist/components/ui/app-frame.js +37 -7
  27. package/dist/components/ui/badge.d.ts +1 -1
  28. package/dist/components/ui/badge.js +1 -1
  29. package/dist/components/ui/button.d.ts +5 -3
  30. package/dist/components/ui/button.d.ts.map +1 -1
  31. package/dist/components/ui/button.js +39 -11
  32. package/dist/components/ui/card.d.ts +12 -2
  33. package/dist/components/ui/card.d.ts.map +1 -1
  34. package/dist/components/ui/card.js +3 -2
  35. package/dist/components/ui/checkbox.d.ts +4 -1
  36. package/dist/components/ui/checkbox.d.ts.map +1 -1
  37. package/dist/components/ui/checkbox.js +4 -4
  38. package/dist/components/ui/context-menu.d.ts.map +1 -1
  39. package/dist/components/ui/context-menu.js +7 -6
  40. package/dist/components/ui/date-field.d.ts +1 -1
  41. package/dist/components/ui/dropdown-menu.d.ts +1 -0
  42. package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
  43. package/dist/components/ui/dropdown-menu.js +9 -8
  44. package/dist/components/ui/icon-button.d.ts +1 -1
  45. package/dist/components/ui/icon-button.d.ts.map +1 -1
  46. package/dist/components/ui/icon-button.js +1 -0
  47. package/dist/components/ui/input.d.ts +6 -2
  48. package/dist/components/ui/input.d.ts.map +1 -1
  49. package/dist/components/ui/input.js +2 -2
  50. package/dist/components/ui/material.d.ts +8 -3
  51. package/dist/components/ui/material.d.ts.map +1 -1
  52. package/dist/components/ui/material.js +2 -2
  53. package/dist/components/ui/menu-items.d.ts +2 -1
  54. package/dist/components/ui/menu-items.d.ts.map +1 -1
  55. package/dist/components/ui/menu-items.js +3 -2
  56. package/dist/components/ui/message-scroller-controller.d.ts +15 -17
  57. package/dist/components/ui/message-scroller-controller.d.ts.map +1 -1
  58. package/dist/components/ui/message-scroller-controller.js +106 -91
  59. package/dist/components/ui/message-scroller-primitive.d.ts +2 -0
  60. package/dist/components/ui/message-scroller-primitive.d.ts.map +1 -1
  61. package/dist/components/ui/message-scroller-primitive.js +2 -0
  62. package/dist/components/ui/message-scroller.d.ts.map +1 -1
  63. package/dist/components/ui/message-scroller.js +2 -2
  64. package/dist/components/ui/number-input.d.ts +1 -1
  65. package/dist/components/ui/popover.js +1 -1
  66. package/dist/components/ui/search-field.d.ts +4 -2
  67. package/dist/components/ui/search-field.d.ts.map +1 -1
  68. package/dist/components/ui/search-field.js +16 -6
  69. package/dist/components/ui/segmented-control.d.ts +3 -1
  70. package/dist/components/ui/segmented-control.d.ts.map +1 -1
  71. package/dist/components/ui/segmented-control.js +23 -17
  72. package/dist/components/ui/select.js +2 -2
  73. package/dist/components/ui/sidebar.d.ts +10 -4
  74. package/dist/components/ui/sidebar.d.ts.map +1 -1
  75. package/dist/components/ui/sidebar.js +74 -17
  76. package/dist/components/ui/status.d.ts +1 -1
  77. package/dist/components/ui/status.js +1 -1
  78. package/dist/components/ui/switch.d.ts +3 -1
  79. package/dist/components/ui/switch.d.ts.map +1 -1
  80. package/dist/components/ui/switch.js +3 -2
  81. package/dist/components/ui/toolbar-controls.d.ts +13 -3
  82. package/dist/components/ui/toolbar-controls.d.ts.map +1 -1
  83. package/dist/components/ui/toolbar-controls.js +35 -10
  84. package/dist/components/ui/toolbar.d.ts +5 -4
  85. package/dist/components/ui/toolbar.d.ts.map +1 -1
  86. package/dist/components/ui/toolbar.js +3 -3
  87. package/dist/index.d.ts +2 -1
  88. package/dist/index.d.ts.map +1 -1
  89. package/dist/index.js +3 -1
  90. package/dist/lib/frame-lifecycle.d.ts +1 -0
  91. package/dist/lib/frame-lifecycle.d.ts.map +1 -1
  92. package/dist/lib/frame-lifecycle.js +7 -0
  93. package/dist/lib/theme.d.ts +39 -5
  94. package/dist/lib/theme.d.ts.map +1 -1
  95. package/dist/lib/theme.js +105 -17
  96. package/dist/tokens/contracts.d.ts +79 -0
  97. package/dist/tokens/contracts.d.ts.map +1 -0
  98. package/dist/tokens/contracts.js +57 -0
  99. package/dist/tokens/index.d.ts +2 -0
  100. package/dist/tokens/index.d.ts.map +1 -0
  101. package/dist/tokens/index.js +1 -0
  102. package/docs/README.md +2 -0
  103. package/docs/adaptive-materials.md +14 -9
  104. package/docs/design-tokens.md +10 -6
  105. package/docs/foundations.md +3 -3
  106. package/docs/macos-design-audit.md +144 -0
  107. package/docs/native-integration.md +4 -4
  108. package/docs/platform-architecture.md +189 -0
  109. package/docs/standalone-app-windows.md +37 -0
  110. package/docs/visual-regression.md +6 -8
  111. package/package.json +13 -1
  112. package/src/components/ui/accordion.md +46 -0
  113. package/src/components/ui/alert.md +12 -4
  114. package/src/components/ui/app-frame.md +8 -5
  115. package/src/components/ui/aspect-ratio.md +37 -0
  116. package/src/components/ui/avatar.md +48 -0
  117. package/src/components/ui/breadcrumb.md +52 -0
  118. package/src/components/ui/button-group.md +43 -0
  119. package/src/components/ui/button.md +21 -4
  120. package/src/components/ui/calendar.md +42 -0
  121. package/src/components/ui/card.md +43 -0
  122. package/src/components/ui/carousel.md +47 -0
  123. package/src/components/ui/chart.md +52 -0
  124. package/src/components/ui/checkbox.md +36 -0
  125. package/src/components/ui/collapsible.md +2 -3
  126. package/src/components/ui/color-well.md +14 -4
  127. package/src/components/ui/combobox.md +3 -3
  128. package/src/components/ui/confirm-dialog.md +5 -4
  129. package/src/components/ui/context-menu.md +3 -2
  130. package/src/components/ui/date-field.md +6 -1
  131. package/src/components/ui/date-picker.md +6 -3
  132. package/src/components/ui/dialog.md +14 -12
  133. package/src/components/ui/drawer.md +58 -0
  134. package/src/components/ui/dropdown-menu.md +16 -14
  135. package/src/components/ui/error-boundary-view.md +1 -1
  136. package/src/components/ui/field.md +2 -1
  137. package/src/components/ui/form.md +71 -0
  138. package/src/components/ui/grid.md +4 -3
  139. package/src/components/ui/icon-button.md +4 -1
  140. package/src/components/ui/input-group.md +49 -0
  141. package/src/components/ui/input-otp.md +56 -0
  142. package/src/components/ui/input.md +40 -0
  143. package/src/components/ui/inspector.md +47 -7
  144. package/src/components/ui/item.md +5 -3
  145. package/src/components/ui/kbd.md +30 -0
  146. package/src/components/ui/label.md +29 -0
  147. package/src/components/ui/list.md +2 -2
  148. package/src/components/ui/material.md +25 -12
  149. package/src/components/ui/menu-items.md +62 -0
  150. package/src/components/ui/menubar.md +58 -0
  151. package/src/components/ui/message-scroller-primitive.md +70 -0
  152. package/src/components/ui/message-scroller.md +89 -0
  153. package/src/components/ui/navigation-button-group.md +4 -3
  154. package/src/components/ui/navigation-menu.md +52 -0
  155. package/src/components/ui/number-input.md +8 -0
  156. package/src/components/ui/pagination.md +51 -0
  157. package/src/components/ui/panel.md +6 -0
  158. package/src/components/ui/popover.md +10 -7
  159. package/src/components/ui/progress.md +31 -0
  160. package/src/components/ui/radio-group.md +36 -0
  161. package/src/components/ui/resizable.md +2 -1
  162. package/src/components/ui/scroll-area.md +3 -1
  163. package/src/components/ui/search-field.md +6 -1
  164. package/src/components/ui/segmented-control.md +6 -1
  165. package/src/components/ui/separator.md +35 -0
  166. package/src/components/ui/sidebar.md +29 -6
  167. package/src/components/ui/skeleton.md +36 -0
  168. package/src/components/ui/slider.md +58 -0
  169. package/src/components/ui/spinner.md +41 -0
  170. package/src/components/ui/split-view.md +8 -4
  171. package/src/components/ui/switch.md +44 -0
  172. package/src/components/ui/table.md +7 -7
  173. package/src/components/ui/tabs.md +3 -1
  174. package/src/components/ui/textarea.md +41 -0
  175. package/src/components/ui/toggle-group.md +2 -2
  176. package/src/components/ui/toggle.md +9 -9
  177. package/src/components/ui/toolbar-controls.md +24 -12
  178. package/src/components/ui/toolbar.md +6 -6
  179. package/src/styles/index.css +298 -117
  180. package/src/tokens/contracts.ts +131 -0
  181. package/src/tokens/index.css +6 -0
  182. package/src/tokens/index.ts +23 -0
  183. package/src/tokens/macos-26/README.md +37 -0
  184. package/src/tokens/macos-26/aliases.css +53 -0
  185. package/src/tokens/macos-26/compatibility.css +7 -0
  186. package/src/tokens/macos-26/index.css +3 -0
  187. package/src/tokens/macos-26/source/provenance.generated.json +28 -0
  188. package/src/tokens/macos-26/source/sidebar.generated.css +29 -0
  189. package/src/tokens/macos-26/source.css +7 -0
  190. package/src/tokens/macos-26/web-adaptations.json +25 -0
  191. package/src/tokens/macos-26/web-adaptations.md +15 -0
  192. package/src/tokens/macos-27/accessibility.css +11 -0
  193. package/src/tokens/macos-27/aliases.css +304 -0
  194. package/src/tokens/macos-27/compatibility.css +212 -0
  195. package/src/tokens/macos-27/index.css +15 -0
  196. package/src/tokens/macos-27/recipes.css +23 -0
  197. package/src/tokens/macos-27/source/chrome.generated.css +338 -0
  198. package/src/tokens/macos-27/source/colors.generated.css +140 -0
  199. package/src/tokens/macos-27/source/context.generated.css +18 -0
  200. package/src/tokens/macos-27/source/controls.generated.css +764 -0
  201. package/src/tokens/macos-27/source/effects.generated.css +68 -0
  202. package/src/tokens/macos-27/source/kit.generated.css +50 -0
  203. package/src/tokens/macos-27/source/overlays-status.generated.css +931 -0
  204. package/src/tokens/macos-27/source/paint-styles.generated.css +81 -0
  205. package/src/tokens/macos-27/source/provenance.generated.json +62 -0
  206. package/src/tokens/macos-27/source/sizes.generated.css +385 -0
  207. package/src/tokens/macos-27/source/source.generated.json +554 -0
  208. package/src/tokens/macos-27/source/text-styles.generated.css +116 -0
  209. package/src/tokens/macos-27/source.css +17 -0
  210. package/src/tokens/macos-27/web-adaptations.css +98 -0
  211. package/src/tokens/macos-27/web-adaptations.json +163 -0
  212. package/src/tokens/macos-27/web-adaptations.md +117 -0
  213. package/src/tokens/moldable/brand.css +165 -0
  214. package/src/tokens/moldable/index.css +1 -0
  215. package/src/tokens/platform-contract.test.ts +294 -0
@@ -0,0 +1,144 @@
1
+ # macOS design audit for Moldable UI
2
+
3
+ Status: active
4
+ Target: macOS desktop apps rendered in Moldable-owned Tauri windows
5
+ Scope: `@moldable-ai/ui`, app-owned titlebars, and the Moldable UI catalog
6
+
7
+ This audit treats macOS AppKit and SwiftUI behavior as the semantic reference
8
+ while allowing a React implementation. The goal is not to copy source pixels.
9
+ The goal is to preserve macOS hierarchy, density, control roles, window
10
+ behavior, input behavior, and accessibility expectations.
11
+
12
+ ## Reference baseline
13
+
14
+ - Foundations: Typography — Ensuring legibility, Conveying hierarchy, Using
15
+ system fonts, Platform considerations/macOS
16
+ - Foundations: Layout — Visual hierarchy, Adaptability, Platform
17
+ considerations/macOS
18
+ - Foundations: Materials — Liquid Glass, Standard materials, Platform
19
+ considerations/macOS
20
+ - Foundations: Color — Best practices, Inclusive color, System colors
21
+ - Foundations: Dark Mode — Best practices, Platform considerations/macOS
22
+ - Foundations: Accessibility — Vision, Mobility, Cognitive
23
+ - Foundations: Icons — Best practices, Platform considerations/macOS
24
+ - Foundations: Motion — Best practices, Providing feedback
25
+ - Platforms: Designing for macOS — Best practices
26
+ - Layout: Sidebars, Split views, Windows, Lists and tables
27
+ - Menus: Toolbars — Titles, Navigation, Actions, Item groupings,
28
+ Platform considerations/macOS
29
+ - Menus: Buttons — Style, Content, Role, Platform considerations/macOS
30
+ - Controls: Toggles, Segmented controls, Text fields
31
+ - Search: Search fields — Best practices, Platform considerations/iPadOS,
32
+ macOS
33
+
34
+ ## Severity-ranked findings
35
+
36
+ ### P0 — window and navigation semantics
37
+
38
+ 1. App-owned titlebars must preserve the native traffic-light exclusion area,
39
+ a draggable noninteractive region, double-click window behavior, and usable
40
+ interactive controls. `Toolbar`, the desktop host, and window metadata must
41
+ be tested together; CSS alone cannot guarantee this contract.
42
+ 2. Toolbar titles must identify the current view or document, not repeat the
43
+ application name. App identity belongs to the window and system surfaces.
44
+ 3. Back controls must call Moldable navigation and expose the same action to
45
+ keyboard and menu commands. A decorative chevron is not navigation.
46
+
47
+ ### P1 — hierarchy and control roles
48
+
49
+ 1. Use a sidebar or tab view for top-level destinations. A segmented control is
50
+ for a small set of closely related modes that affect one view, not primary
51
+ app navigation.
52
+ 2. Keep only frequent actions in a toolbar. Put infrequent actions in a More
53
+ menu and mirror every command in the macOS menu bar.
54
+ 3. Group only controls that are logically related. Standalone navigation
55
+ controls should usually be quiet; groups may own one shared capsule.
56
+ 4. Use the system appearance by default. An appearance selector is appropriate
57
+ in a component test harness, but not as persistent application chrome.
58
+ 5. Prefer compact macOS typography: 13 px body, 15–16 px titles, 18 px section
59
+ headings, and 24 px display headings. Avoid web-dashboard hero sizing in
60
+ ordinary desktop panes.
61
+ 6. Prefer flat content hierarchy, separators, and selection fills over nested
62
+ bordered cards and repeated shadows. Materials belong to navigation and
63
+ transient controls, not every content surface.
64
+ 7. Use switches for immediate, emphasized binary settings. Use checkboxes for
65
+ ordinary grouped preferences and radio buttons for mutually exclusive
66
+ choices.
67
+
68
+ ### P2 — desktop completeness
69
+
70
+ 1. Extend the existing resizable `SplitView` with a documented collapsible
71
+ recipe, restoration, and automatic narrow-window collapse.
72
+ 2. Add table column resizing, sorting, optional alternating row backgrounds,
73
+ keyboard range selection, and state restoration.
74
+ 3. Extend command metadata so toolbar items, menus, keyboard shortcuts,
75
+ accessibility labels, and disabled state can share one source of truth.
76
+ 4. Separate semantic action roles from visual button variants and cover
77
+ default, cancel, destructive, help, disclosure, toolbar, and icon-only
78
+ actions.
79
+ 5. Validate at increased contrast, reduced transparency, reduced motion,
80
+ keyboard-only input, 200% zoom, and light/dark appearances.
81
+
82
+ ## Current conformance
83
+
84
+ The shared package already provides:
85
+
86
+ - semantic light and dark colors instead of raw app-specific grays;
87
+ - a system-font stack and compact macOS-oriented type tokens;
88
+ - labeled icon buttons with visible keyboard focus;
89
+ - reduced-motion and reduced-transparency fallbacks;
90
+ - explicit status text in addition to color;
91
+ - titlebar insets and window drag handlers for app-owned top toolbars;
92
+ - compact, regular, and comfortable density tokens;
93
+ - a distinct accent-colored `prominent` button role for the single key action
94
+ in a view, without changing the appearance of existing default buttons.
95
+
96
+ The Moldable UI catalog now demonstrates:
97
+
98
+ - top-level source-list navigation in the sidebar;
99
+ - current-view toolbar titles;
100
+ - quiet standalone toolbar navigation;
101
+ - preview-only appearance and accessibility controls;
102
+ - flatter stages, fewer shadows, and smaller radii;
103
+ - package typography tokens instead of oversized page-specific values.
104
+
105
+ ## Component acceptance criteria
106
+
107
+ ### Toolbar
108
+
109
+ - Uses the current view or document title.
110
+ - Preserves native window-control clearance in app-owned windows.
111
+ - Dragging works from every noninteractive toolbar region.
112
+ - Interactive descendants never initiate a window drag.
113
+ - Frequent actions are visible; rare actions are in More.
114
+ - Related actions share a group; unrelated actions do not.
115
+ - Commands have labels, tooltips when helpful, shortcuts, menu equivalents,
116
+ disabled states, and tests.
117
+
118
+ ### Sidebar and split view
119
+
120
+ - Selection is persistent and visually unambiguous.
121
+ - Search filters the sidebar content it sits above.
122
+ - Sidebar width is resizable within reasonable minimum and maximum values.
123
+ - The sidebar can collapse automatically in a narrow window and manually at
124
+ any size.
125
+ - The divider remains subtle and the sidebar doesn’t compete with content.
126
+
127
+ ### Controls
128
+
129
+ - Labels describe outcomes, not implementation.
130
+ - The default action is visually prominent only when the context needs one.
131
+ - Destructive actions are explicit and separated from routine actions.
132
+ - Icons use familiar system metaphors and never carry meaning without an
133
+ accessible label.
134
+ - Controls remain operable with keyboard, pointer, VoiceOver, increased
135
+ contrast, reduced transparency, and reduced motion.
136
+
137
+ ## Review policy
138
+
139
+ Every new public visual primitive must include catalog stories for light and
140
+ dark appearance, compact and regular density, wide and narrow viewport,
141
+ rest/focus/disabled/invalid states where applicable, and accessible naming.
142
+ Every window-chrome change must be verified in a real Moldable-owned macOS
143
+ window because embedded browser rendering cannot validate traffic-light
144
+ placement or native dragging.
@@ -16,10 +16,10 @@ Do not create UI-only no-op stubs for native menus, share sheets, or date
16
16
  pickers. First define ownership, cancellation, errors, replay/reconnect
17
17
  behavior, and platform fallbacks.
18
18
 
19
- `DateField` is the portable renderer baseline. A future system date picker,
20
- share sheet, or native menu must only be selected after the host advertises the
21
- service through a versioned context. Requests must remain bound to the
22
- originating app window and user activation.
19
+ `DateField`, renderer menus, and browser file/share controls remain the
20
+ portable baselines. The package currently exposes host-advertised date/time
21
+ picker, share, native-menu, and file-dialog services with renderer fallbacks.
22
+ Requests remain bound to the originating app window and user activation.
23
23
 
24
24
  Standalone windows should remain host-owned surfaces around an app frame. Do
25
25
  not load arbitrary app URLs directly into a privileged native webview merely to
@@ -0,0 +1,189 @@
1
+ # Moldable UI platform architecture
2
+
3
+ ## Goal
4
+
5
+ Moldable applications use one stable UI contract while platform packs provide
6
+ versioned operating-system measurements and recipes.
7
+
8
+ ```text
9
+ immutable platform pack
10
+ → Moldable semantic adapter
11
+ → stable Moldable component API
12
+ → optional Moldable brand overrides
13
+ → app composition
14
+ ```
15
+
16
+ The current complete reference pack is `macos-27`. A partial `macos-26`
17
+ source module supplies the floating-sidebar recipe. Future packs can include
18
+ a newer macOS release, Windows, or a platform-neutral web fallback without
19
+ requiring apps to import version-specific tokens.
20
+
21
+ ## Immutable platform packs
22
+
23
+ A platform pack contains factual source data only:
24
+
25
+ - semantic colors and appearance modes;
26
+ - typography metrics;
27
+ - control sizes, geometry, and state recipes;
28
+ - window, toolbar, menu, sidebar, and overlay measurements;
29
+ - material recipes and capability requirements;
30
+ - accessibility and native-host adaptations.
31
+
32
+ Published pack values never change in place. Corrections create a package
33
+ patch with an audit note; a new operating-system release gets a new pack.
34
+ Platform packs contain no artwork, images, icon paths, screenshots, fonts, or
35
+ copied component implementations.
36
+
37
+ Private source variables use a versioned namespace such as
38
+ `--m27-source-*` or `--m26-source-*` and are scoped to the source version:
39
+
40
+ ```css
41
+ [data-ui-platform='macos'][data-ui-platform-version='27']
42
+ ```
43
+
44
+ This allows multiple packs to ship together without variable collisions.
45
+
46
+ Partial source modules do not become complete platform packs until they cover
47
+ the full stable contract. They can still contribute a deliberately versioned
48
+ component recipe, such as the macOS 26 floating sidebar.
49
+
50
+ ## Stable Moldable contract
51
+
52
+ Applications and universal components consume only `--m-ui-*` recipe tokens
53
+ and stable React props. They never read versioned `--m*-source-*` variables
54
+ directly.
55
+
56
+ Examples:
57
+
58
+ ```css
59
+ --m-ui-color-text-primary
60
+ --m-ui-color-accent
61
+ --m-ui-control-height
62
+ --m-ui-button-radius
63
+ --m-ui-toolbar-control-height
64
+ --m-ui-menu-item-height
65
+ ```
66
+
67
+ Each platform adapter maps its immutable source values to this contract. A
68
+ Moldable theme may then deliberately override a documented subset of semantic
69
+ roles, but cannot mutate the platform-pack source.
70
+
71
+ ## Runtime selection
72
+
73
+ `ThemeProvider` resolves independent axes:
74
+
75
+ ```ts
76
+ <ThemeProvider
77
+ platform="macos"
78
+ platformVersion="27"
79
+ uiTheme="moldable"
80
+ sidebarStyle="floating"
81
+ appearance="system"
82
+ controlSize="medium"
83
+ />
84
+ ```
85
+
86
+ The resolved document attributes are:
87
+
88
+ ```html
89
+ <html
90
+ data-ui-platform="macos"
91
+ data-ui-platform-version="27"
92
+ data-ui-platform-pack="macos-27"
93
+ data-ui-sidebar-style="floating"
94
+ data-ui-theme="moldable"
95
+ data-ui-appearance="dark"
96
+ data-control-size="medium"
97
+ ></html>
98
+ ```
99
+
100
+ Unsupported platform/version requests resolve to the explicit web fallback
101
+ pack rather than silently borrowing the latest macOS values.
102
+
103
+ ## Independently selectable component recipes
104
+
105
+ An application can use one base platform pack while opting a component family
106
+ into a different, compatible anatomy. Public API names describe the result,
107
+ not the source OS version:
108
+
109
+ | `sidebarStyle` | Anatomy | Immutable source |
110
+ | -------------- | ---------------------------------------------------- | ---------------------- |
111
+ | `platform` | Follow the selected base platform | Selected platform pack |
112
+ | `floating` | Inset glass shell with independent radius and shadow | macOS 26 |
113
+ | `edge-to-edge` | Sidebar joined to the window/content edge | macOS 27 |
114
+
115
+ The macOS 27 edge-to-edge anatomy does not draw a standalone divider or
116
+ material background around the sidebar. The sidebar reveals the app/window
117
+ canvas beneath it, so each app can choose a plain color, image, or other
118
+ background for the whole composition. The hairline follows only the outer
119
+ window perimeter.
120
+
121
+ For an app-wide choice:
122
+
123
+ ```tsx
124
+ <ThemeProvider platform="macos" platformVersion="27" sidebarStyle="floating" />
125
+ ```
126
+
127
+ For a single sidebar:
128
+
129
+ ```tsx
130
+ <Sidebar sidebarStyle="edge-to-edge">{/* … */}</Sidebar>
131
+ ```
132
+
133
+ `SIDEBAR_STYLES` is the registry boundary that records the source platform and
134
+ version for each semantic recipe. Components resolve stable
135
+ `--m-ui-sidebar-*` tokens and never branch on version numbers.
136
+
137
+ ## Component strategy
138
+
139
+ ### Universal components
140
+
141
+ Use one component when semantics and interaction behavior are shared:
142
+
143
+ - button, checkbox, radio group, switch;
144
+ - text, search, and number fields;
145
+ - slider, segmented control, progress;
146
+ - table, form, dialog, popover, tooltip;
147
+ - toolbar composition and command models.
148
+
149
+ Their DOM behavior remains accessible and platform-neutral. Platform recipes
150
+ control geometry and presentation.
151
+
152
+ ### Platform adapters
153
+
154
+ Use a thin adapter when native ownership or interaction differs:
155
+
156
+ - native menu-bar integration;
157
+ - window controls and draggable titlebar regions;
158
+ - system file, color, date, sharing, and permission dialogs;
159
+ - native materials and backdrop capabilities;
160
+ - platform keyboard shortcuts and pointer conventions.
161
+
162
+ The app imports the stable Moldable API. The provider/host selects the adapter.
163
+
164
+ ### Version-specific implementations
165
+
166
+ Only create a version-specific component when CSS recipe changes cannot express
167
+ the difference in semantics or anatomy. Keep the version branch at the
168
+ registry boundary:
169
+
170
+ ```ts
171
+ const windowChrome = platformRegistry.resolve({
172
+ platform: 'macos',
173
+ version: '27',
174
+ capability: 'windowChrome',
175
+ })
176
+ ```
177
+
178
+ Do not scatter checks such as `if (macOSVersion >= 27)` through components.
179
+
180
+ ## Catalog contract
181
+
182
+ The core component catalog shows resolved stable components and their state,
183
+ appearance, density, viewport, accessibility, and native-capability matrices.
184
+ The Moldable UI showcase owns raw platform-pack reference pages and
185
+ platform/version comparisons. Explicit Moldable overrides remain separately
186
+ identifiable in both surfaces.
187
+
188
+ Together these surfaces keep OS fidelity, Moldable design decisions, and
189
+ compatibility behavior independently reviewable.
@@ -50,6 +50,43 @@ leading window-control inset. A top `Toolbar` consumes those values, sends
50
50
  maximize as a cross-platform approximation of the macOS titlebar zoom action.
51
51
  Interactive descendants are automatically excluded from dragging.
52
52
 
53
+ Native behind-window material is also app-scoped and default-off. The native
54
+ host must know about background, titlebar, and sidebar requests before creating
55
+ the window, so apps declare them in `moldable.json`:
56
+
57
+ ```json
58
+ {
59
+ "window": {
60
+ "titlebar": "host",
61
+ "nativeMaterial": {
62
+ "background": true,
63
+ "titlebar": true,
64
+ "sidebar": true
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ For renderer-owned background and sidebar material, the shared frame must opt
71
+ in too:
72
+
73
+ ```tsx
74
+ <AppFrame nativeMaterial={{ background: true, sidebar: true }}>
75
+ <SidebarProvider>
76
+ <Sidebar>{/* navigation */}</Sidebar>
77
+ <AppFrameContent>{/* primary canvas */}</AppFrameContent>
78
+ </SidebarProvider>
79
+ </AppFrame>
80
+ ```
81
+
82
+ The manifest allows the host to build the native window correctly. The
83
+ `AppFrame` option yields the portable canvas fill to the host's frosted
84
+ `UnderWindowBackground` material and allows the shared `Sidebar` to declare its
85
+ measured region. These options are independent: apps may opt into any
86
+ combination of background, titlebar, and sidebar. If either side of an opt-in is
87
+ absent, or the platform or accessibility settings do not support sampling, the
88
+ corresponding surface keeps its portable semantic fill.
89
+
53
90
  Window appearance roles are `--window-chrome-background`,
54
91
  `--window-chrome-foreground`, `--window-chrome-muted-foreground`,
55
92
  `--window-border`, and `--material-shadow-window`. The host may update the
@@ -1,7 +1,7 @@
1
1
  # Visual and accessibility regression
2
2
 
3
- The phase 1 runner exercises every authored story in the core component
4
- catalog. It does not start the desktop shell or any Moldable-managed app.
3
+ The runner exercises every authored story in the core component catalog. It
4
+ does not start the desktop shell or any Moldable-managed app.
5
5
 
6
6
  ## What runs
7
7
 
@@ -32,8 +32,7 @@ one element:
32
32
  ```
33
33
 
34
34
  Playwright performs real hover, focus, and held-pointer interactions on that
35
- element. Button, segmented control, and toggle stories are the phase 1
36
- exemplars.
35
+ element for every story that declares those live states.
37
36
 
38
37
  Every captured case also receives an axe WCAG 2 A/AA and WCAG 2.1 A/AA scan.
39
38
  Serious and critical violations fail. Per-story suppressions belong in
@@ -67,10 +66,9 @@ directory.
67
66
  ## Determinism and skips
68
67
 
69
68
  Stories must use fixed inputs and no live data, network, wall-clock timers, or
70
- unseeded randomness. Add an unavoidable phase 1 skip to
71
- `deterministicStorySkips` in `visual-tests/visual-matrix.ts` with a specific
72
- reason. Skips are reported in the runner summary; silent conditional skips
73
- are not allowed.
69
+ unseeded randomness. Add an unavoidable skip to `deterministicStorySkips` in
70
+ `visual-tests/visual-matrix.ts` with a specific reason. Skips are reported in
71
+ the runner summary; silent conditional skips are not allowed.
74
72
 
75
73
  ## CI
76
74
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moldable-ai/ui",
3
- "version": "0.2.29",
3
+ "version": "0.2.32",
4
4
  "description": "Shared UI components for Moldable applications",
5
5
  "author": "Desiderata LLC",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -31,6 +31,17 @@
31
31
  "import": "./dist/catalog/index.js",
32
32
  "require": "./dist/catalog/index.js"
33
33
  },
34
+ "./tokens": {
35
+ "types": "./dist/tokens/index.d.ts",
36
+ "import": "./dist/tokens/index.js",
37
+ "require": "./dist/tokens/index.js"
38
+ },
39
+ "./tokens/macos-27": "./src/tokens/macos-27/index.css",
40
+ "./platforms/macos-27": "./src/tokens/macos-27/index.css",
41
+ "./platforms/macos-27/source": "./src/tokens/macos-27/source.css",
42
+ "./tokens/macos-26": "./src/tokens/macos-26/index.css",
43
+ "./platforms/macos-26": "./src/tokens/macos-26/index.css",
44
+ "./platforms/macos-26/source": "./src/tokens/macos-26/source.css",
34
45
  "./styles": "./src/styles/index.css"
35
46
  },
36
47
  "files": [
@@ -39,6 +50,7 @@
39
50
  "src/components/ui/*.md",
40
51
  "src/lib/*.md",
41
52
  "src/styles",
53
+ "src/tokens",
42
54
  "LICENSE"
43
55
  ],
44
56
  "scripts": {
@@ -0,0 +1,46 @@
1
+ # Accordion
2
+
3
+ ## Purpose
4
+
5
+ `Accordion` organizes related sections into independently expandable items. Use
6
+ it when several peer sections should share one disclosure pattern; use
7
+ `Collapsible` for a single disclosed region.
8
+
9
+ ## Usage
10
+
11
+ ```tsx
12
+ import {
13
+ Accordion,
14
+ AccordionContent,
15
+ AccordionItem,
16
+ AccordionTrigger,
17
+ } from '@moldable-ai/ui'
18
+
19
+ ;<Accordion type="single" collapsible>
20
+ <AccordionItem value="storage">
21
+ <AccordionTrigger>Storage</AccordionTrigger>
22
+ <AccordionContent>
23
+ Files remain in the current Moldable workspace.
24
+ </AccordionContent>
25
+ </AccordionItem>
26
+ </Accordion>
27
+ ```
28
+
29
+ ## API
30
+
31
+ - `Accordion` exposes the Radix root props, including `type="single"` or
32
+ `type="multiple"`, controlled state, and orientation.
33
+ - `AccordionItem` requires the Radix item `value` and adds a dividing border.
34
+ - `AccordionTrigger` renders a full-width trigger with a state-aware chevron.
35
+ - `AccordionContent` provides the open and close animation. Its `className`
36
+ styles the inner content wrapper; remaining props apply to the Radix content
37
+ element.
38
+ - Radix manages trigger relationships, expanded state, and keyboard behavior.
39
+
40
+ ## Quality bar
41
+
42
+ - Keep trigger labels short and make each section understandable when closed.
43
+ - Choose single or multiple expansion based on the task, not visual density.
44
+ - Do not put another interactive control inside a trigger.
45
+ - Do not hide required validation errors or the only primary action in a closed
46
+ item.
@@ -11,8 +11,15 @@ Use `AlertDialog` when the user must confirm an action. Use `Empty` for the norm
11
11
  ## Usage patterns
12
12
 
13
13
  ```tsx
14
- import { CircleAlert } from 'lucide-react'
15
- import { Alert, AlertDescription, AlertTitle } from '@moldable-ai/ui'
14
+ import { CircleAlert, InfoIcon } from 'lucide-react'
15
+ import {
16
+ Alert,
17
+ AlertActions,
18
+ AlertDescription,
19
+ AlertDismiss,
20
+ AlertTitle,
21
+ Button,
22
+ } from '@moldable-ai/ui'
16
23
 
17
24
  ;<Alert tone="danger">
18
25
  <CircleAlert />
@@ -40,8 +47,9 @@ owned by the caller:
40
47
 
41
48
  ## API summary
42
49
 
43
- - `tone`: `neutral`, `info`, `success`, `warning`, or `danger`.
44
- - `density`: `compact` or `default`.
50
+ - `tone`: `neutral`, `info`, `success`, `warning`, or `danger`; defaults to
51
+ `neutral`.
52
+ - `density`: `compact` or `default`; defaults to `default`.
45
53
  - Neutral through warning tones default to `role="status"`; danger defaults to
46
54
  `role="alert"`. The native `role` prop can override that choice.
47
55
  - `variant="default"` and `variant="destructive"` remain compatibility aliases.
@@ -4,7 +4,7 @@ The top-level shell for an app that can run in its own window or inside a host
4
4
  surface.
5
5
 
6
6
  ```tsx
7
- <AppFrame>
7
+ <AppFrame nativeMaterial={{ background: true, sidebar: true }}>
8
8
  <Toolbar position="top">
9
9
  <ToolbarTitle>Today</ToolbarTitle>
10
10
  <ToolbarActions>{/* compact actions */}</ToolbarActions>
@@ -29,8 +29,11 @@ surface.
29
29
  - `AppFrameContent` applies the shared chat-safe padding by default. The value is
30
30
  zero in a standalone window and is updated by the embedded host lifecycle.
31
31
  - Use `mode="embedded"` or `mode="window"` only for deterministic previews and
32
- tests. Runtime apps should normally use `mode="auto"`; a future host context
33
- may set `data-moldable-display-mode` before render when a window still uses an
34
- app iframe.
32
+ tests. Runtime apps should normally use `mode="auto"`; the host may set
33
+ `data-moldable-display-mode` when a window still uses an app iframe.
35
34
  - Material samples only renderer content. Native behind-window material remains
36
- host-owned.
35
+ host-owned. `nativeMaterial={{ background: true }}` reveals the host's
36
+ frosted full-window material, while `nativeMaterial={{ sidebar: true }}`
37
+ allows a compatible sidebar to declare its region. Declare each matching
38
+ `window.nativeMaterial` option in `moldable.json`. Every option defaults off,
39
+ and portable semantic fills remain in unsupported environments.
@@ -0,0 +1,37 @@
1
+ # AspectRatio
2
+
3
+ ## Purpose
4
+
5
+ `AspectRatio` reserves a stable rectangular area for media whose width and
6
+ height should scale together. Use it for previews, thumbnails, video, and other
7
+ content where layout shift would be distracting.
8
+
9
+ ## Usage
10
+
11
+ ```tsx
12
+ import { AspectRatio } from '@moldable-ai/ui'
13
+
14
+ ;<AspectRatio ratio={16 / 9} className="rounded-control overflow-hidden">
15
+ <img
16
+ src={previewUrl}
17
+ alt="Workspace preview"
18
+ className="size-full object-cover"
19
+ />
20
+ </AspectRatio>
21
+ ```
22
+
23
+ ## API
24
+
25
+ - Accepts the Radix aspect-ratio root props.
26
+ - `ratio` is the desired width divided by height, such as `16 / 9` or `1`.
27
+ - The component adds `data-slot="aspect-ratio"` and otherwise leaves content
28
+ rendering to the caller.
29
+
30
+ ## Quality bar
31
+
32
+ - Set an explicit ratio that matches the expected media.
33
+ - Give images useful alternative text, or an empty `alt` when decorative.
34
+ - Choose `object-cover` or `object-contain` deliberately; the component does
35
+ not crop or fit its child.
36
+ - Do not use an aspect ratio wrapper when the content must determine its own
37
+ height.
@@ -0,0 +1,48 @@
1
+ # Avatar
2
+
3
+ ## Purpose
4
+
5
+ `Avatar` presents a person, account, or other recognizable identity in a
6
+ compact circular frame. It includes image, fallback, badge, and overlapping
7
+ group primitives.
8
+
9
+ ## Usage
10
+
11
+ ```tsx
12
+ import {
13
+ Avatar,
14
+ AvatarFallback,
15
+ AvatarGroup,
16
+ AvatarGroupCount,
17
+ AvatarImage,
18
+ } from '@moldable-ai/ui'
19
+
20
+ ;<AvatarGroup>
21
+ <Avatar size="sm">
22
+ <AvatarImage src={owner.photoUrl} alt={owner.name} />
23
+ <AvatarFallback>RM</AvatarFallback>
24
+ </Avatar>
25
+ <AvatarGroupCount>+3</AvatarGroupCount>
26
+ </AvatarGroup>
27
+ ```
28
+
29
+ ## API
30
+
31
+ - `Avatar`: Radix root props plus `size="sm"`, `"default"`, or `"lg"`;
32
+ defaults to `default`.
33
+ - `AvatarImage`: Radix image props.
34
+ - `AvatarFallback`: Radix fallback props, including delayed fallback behavior.
35
+ - `AvatarBadge`: native `span` props for a compact corner marker.
36
+ - `AvatarGroup` and `AvatarGroupCount`: native `div` props for an overlapping
37
+ group and its remaining count.
38
+
39
+ ## Quality bar
40
+
41
+ - Provide a stable fallback, usually initials or a short recognizable mark.
42
+ - Use meaningful image `alt` text, or empty `alt` when adjacent text already
43
+ names the same identity.
44
+ - Keep one size across an avatar group.
45
+ - Give a badge additional accessible context when its color or icon conveys
46
+ status.
47
+ - Do not use an avatar as an unlabeled action; wrap it in the appropriate
48
+ button or link when interactive.