@moldable-ai/ui 0.2.29 → 0.2.31
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.
- package/dist/catalog/component-catalog.d.ts +9 -2
- package/dist/catalog/component-catalog.d.ts.map +1 -1
- package/dist/catalog/component-catalog.js +11 -7
- package/dist/catalog/core-control-stories.d.ts.map +1 -1
- package/dist/catalog/core-control-stories.js +1 -1
- package/dist/catalog/core-foundation-stories.d.ts.map +1 -1
- package/dist/catalog/core-foundation-stories.js +5 -5
- package/dist/components/ui/app-frame.d.ts +20 -1
- package/dist/components/ui/app-frame.d.ts.map +1 -1
- package/dist/components/ui/app-frame.js +37 -7
- package/dist/components/ui/badge.d.ts +1 -1
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/button.d.ts +5 -3
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.js +39 -11
- package/dist/components/ui/card.d.ts +12 -2
- package/dist/components/ui/card.d.ts.map +1 -1
- package/dist/components/ui/card.js +3 -2
- package/dist/components/ui/checkbox.d.ts +4 -1
- package/dist/components/ui/checkbox.d.ts.map +1 -1
- package/dist/components/ui/checkbox.js +4 -4
- package/dist/components/ui/context-menu.js +6 -6
- package/dist/components/ui/dropdown-menu.js +6 -6
- package/dist/components/ui/icon-button.d.ts +1 -1
- package/dist/components/ui/icon-button.d.ts.map +1 -1
- package/dist/components/ui/icon-button.js +1 -0
- package/dist/components/ui/input.d.ts +6 -2
- package/dist/components/ui/input.d.ts.map +1 -1
- package/dist/components/ui/input.js +2 -2
- package/dist/components/ui/material.d.ts +8 -3
- package/dist/components/ui/material.d.ts.map +1 -1
- package/dist/components/ui/material.js +2 -2
- package/dist/components/ui/search-field.d.ts +3 -1
- package/dist/components/ui/search-field.d.ts.map +1 -1
- package/dist/components/ui/search-field.js +16 -6
- package/dist/components/ui/segmented-control.d.ts +3 -1
- package/dist/components/ui/segmented-control.d.ts.map +1 -1
- package/dist/components/ui/segmented-control.js +23 -17
- package/dist/components/ui/select.js +2 -2
- package/dist/components/ui/sidebar.d.ts +5 -3
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/sidebar.js +53 -15
- package/dist/components/ui/status.d.ts +1 -1
- package/dist/components/ui/status.js +1 -1
- package/dist/components/ui/switch.d.ts +3 -1
- package/dist/components/ui/switch.d.ts.map +1 -1
- package/dist/components/ui/switch.js +3 -2
- package/dist/components/ui/toolbar-controls.d.ts +3 -1
- package/dist/components/ui/toolbar-controls.d.ts.map +1 -1
- package/dist/components/ui/toolbar-controls.js +14 -7
- package/dist/components/ui/toolbar.d.ts +5 -4
- package/dist/components/ui/toolbar.d.ts.map +1 -1
- package/dist/components/ui/toolbar.js +3 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/lib/frame-lifecycle.d.ts +1 -0
- package/dist/lib/frame-lifecycle.d.ts.map +1 -1
- package/dist/lib/frame-lifecycle.js +7 -0
- package/dist/lib/theme.d.ts +39 -5
- package/dist/lib/theme.d.ts.map +1 -1
- package/dist/lib/theme.js +105 -17
- package/dist/tokens/contracts.d.ts +79 -0
- package/dist/tokens/contracts.d.ts.map +1 -0
- package/dist/tokens/contracts.js +57 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +1 -0
- package/docs/README.md +2 -0
- package/docs/adaptive-materials.md +14 -9
- package/docs/design-tokens.md +10 -6
- package/docs/foundations.md +3 -3
- package/docs/macos-design-audit.md +144 -0
- package/docs/native-integration.md +4 -4
- package/docs/platform-architecture.md +189 -0
- package/docs/standalone-app-windows.md +37 -0
- package/docs/visual-regression.md +6 -8
- package/package.json +13 -1
- package/src/components/ui/accordion.md +46 -0
- package/src/components/ui/alert.md +12 -4
- package/src/components/ui/app-frame.md +8 -5
- package/src/components/ui/aspect-ratio.md +37 -0
- package/src/components/ui/avatar.md +48 -0
- package/src/components/ui/breadcrumb.md +52 -0
- package/src/components/ui/button-group.md +43 -0
- package/src/components/ui/button.md +20 -4
- package/src/components/ui/calendar.md +42 -0
- package/src/components/ui/card.md +43 -0
- package/src/components/ui/carousel.md +47 -0
- package/src/components/ui/chart.md +52 -0
- package/src/components/ui/checkbox.md +36 -0
- package/src/components/ui/collapsible.md +2 -3
- package/src/components/ui/color-well.md +14 -4
- package/src/components/ui/combobox.md +3 -3
- package/src/components/ui/confirm-dialog.md +5 -4
- package/src/components/ui/context-menu.md +3 -2
- package/src/components/ui/date-field.md +6 -1
- package/src/components/ui/date-picker.md +6 -3
- package/src/components/ui/dialog.md +14 -12
- package/src/components/ui/drawer.md +58 -0
- package/src/components/ui/error-boundary-view.md +1 -1
- package/src/components/ui/field.md +2 -1
- package/src/components/ui/form.md +71 -0
- package/src/components/ui/grid.md +4 -3
- package/src/components/ui/icon-button.md +4 -1
- package/src/components/ui/input-group.md +49 -0
- package/src/components/ui/input-otp.md +56 -0
- package/src/components/ui/input.md +40 -0
- package/src/components/ui/inspector.md +47 -7
- package/src/components/ui/item.md +5 -3
- package/src/components/ui/kbd.md +30 -0
- package/src/components/ui/label.md +29 -0
- package/src/components/ui/list.md +2 -2
- package/src/components/ui/material.md +25 -12
- package/src/components/ui/menu-items.md +60 -0
- package/src/components/ui/menubar.md +58 -0
- package/src/components/ui/message-scroller-primitive.md +70 -0
- package/src/components/ui/message-scroller.md +86 -0
- package/src/components/ui/navigation-button-group.md +4 -3
- package/src/components/ui/navigation-menu.md +52 -0
- package/src/components/ui/number-input.md +8 -0
- package/src/components/ui/pagination.md +51 -0
- package/src/components/ui/panel.md +6 -0
- package/src/components/ui/popover.md +10 -7
- package/src/components/ui/progress.md +31 -0
- package/src/components/ui/radio-group.md +36 -0
- package/src/components/ui/resizable.md +2 -1
- package/src/components/ui/scroll-area.md +3 -1
- package/src/components/ui/search-field.md +6 -1
- package/src/components/ui/segmented-control.md +6 -1
- package/src/components/ui/separator.md +35 -0
- package/src/components/ui/sidebar.md +20 -3
- package/src/components/ui/skeleton.md +36 -0
- package/src/components/ui/slider.md +58 -0
- package/src/components/ui/spinner.md +41 -0
- package/src/components/ui/split-view.md +8 -4
- package/src/components/ui/switch.md +44 -0
- package/src/components/ui/table.md +7 -7
- package/src/components/ui/tabs.md +3 -1
- package/src/components/ui/textarea.md +41 -0
- package/src/components/ui/toggle-group.md +2 -2
- package/src/components/ui/toggle.md +9 -9
- package/src/components/ui/toolbar-controls.md +17 -9
- package/src/components/ui/toolbar.md +6 -6
- package/src/styles/index.css +171 -117
- package/src/tokens/contracts.ts +131 -0
- package/src/tokens/index.css +6 -0
- package/src/tokens/index.ts +23 -0
- package/src/tokens/macos-26/README.md +37 -0
- package/src/tokens/macos-26/aliases.css +53 -0
- package/src/tokens/macos-26/compatibility.css +7 -0
- package/src/tokens/macos-26/index.css +3 -0
- package/src/tokens/macos-26/source/provenance.generated.json +28 -0
- package/src/tokens/macos-26/source/sidebar.generated.css +29 -0
- package/src/tokens/macos-26/source.css +7 -0
- package/src/tokens/macos-26/web-adaptations.json +25 -0
- package/src/tokens/macos-26/web-adaptations.md +15 -0
- package/src/tokens/macos-27/accessibility.css +11 -0
- package/src/tokens/macos-27/aliases.css +304 -0
- package/src/tokens/macos-27/compatibility.css +212 -0
- package/src/tokens/macos-27/index.css +15 -0
- package/src/tokens/macos-27/recipes.css +23 -0
- package/src/tokens/macos-27/source/chrome.generated.css +338 -0
- package/src/tokens/macos-27/source/colors.generated.css +140 -0
- package/src/tokens/macos-27/source/context.generated.css +18 -0
- package/src/tokens/macos-27/source/controls.generated.css +764 -0
- package/src/tokens/macos-27/source/effects.generated.css +68 -0
- package/src/tokens/macos-27/source/kit.generated.css +50 -0
- package/src/tokens/macos-27/source/overlays-status.generated.css +931 -0
- package/src/tokens/macos-27/source/paint-styles.generated.css +81 -0
- package/src/tokens/macos-27/source/provenance.generated.json +62 -0
- package/src/tokens/macos-27/source/sizes.generated.css +385 -0
- package/src/tokens/macos-27/source/source.generated.json +554 -0
- package/src/tokens/macos-27/source/text-styles.generated.css +116 -0
- package/src/tokens/macos-27/source.css +17 -0
- package/src/tokens/macos-27/web-adaptations.css +98 -0
- package/src/tokens/macos-27/web-adaptations.json +163 -0
- package/src/tokens/macos-27/web-adaptations.md +117 -0
- package/src/tokens/moldable/brand.css +48 -0
- package/src/tokens/moldable/index.css +1 -0
- package/src/tokens/platform-contract.test.ts +290 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export const CONTROL_SIZES = [
|
|
2
|
+
'mini',
|
|
3
|
+
'small',
|
|
4
|
+
'medium',
|
|
5
|
+
'large',
|
|
6
|
+
'xl',
|
|
7
|
+
];
|
|
8
|
+
export const MATERIAL_THICKNESSES = [
|
|
9
|
+
'ultra-thick',
|
|
10
|
+
'thick',
|
|
11
|
+
'medium',
|
|
12
|
+
'thin',
|
|
13
|
+
'ultra-thin',
|
|
14
|
+
];
|
|
15
|
+
export const SIDEBAR_STYLES = {
|
|
16
|
+
platform: {
|
|
17
|
+
id: 'platform',
|
|
18
|
+
sourcePlatform: null,
|
|
19
|
+
sourceVersion: null,
|
|
20
|
+
},
|
|
21
|
+
floating: {
|
|
22
|
+
id: 'floating',
|
|
23
|
+
sourcePlatform: 'macos',
|
|
24
|
+
sourceVersion: '26',
|
|
25
|
+
},
|
|
26
|
+
'edge-to-edge': {
|
|
27
|
+
id: 'edge-to-edge',
|
|
28
|
+
sourcePlatform: 'macos',
|
|
29
|
+
sourceVersion: '27',
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
export const PLATFORM_PACKS = {
|
|
33
|
+
'macos-27': {
|
|
34
|
+
id: 'macos-27',
|
|
35
|
+
platform: 'macos',
|
|
36
|
+
version: '27',
|
|
37
|
+
capabilities: {
|
|
38
|
+
nativeMaterials: true,
|
|
39
|
+
nativeWindowChrome: true,
|
|
40
|
+
overlayScrollbars: true,
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
'web-default': {
|
|
44
|
+
id: 'web-default',
|
|
45
|
+
platform: 'web',
|
|
46
|
+
version: 'default',
|
|
47
|
+
capabilities: {
|
|
48
|
+
nativeMaterials: false,
|
|
49
|
+
nativeWindowChrome: false,
|
|
50
|
+
overlayScrollbars: false,
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
export function resolvePlatformPack(platform, version) {
|
|
55
|
+
const exact = Object.values(PLATFORM_PACKS).find((pack) => pack.platform === platform && pack.version === version);
|
|
56
|
+
return exact ?? PLATFORM_PACKS['web-default'];
|
|
57
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { CONTROL_SIZES, MATERIAL_THICKNESSES, PLATFORM_PACKS, SIDEBAR_STYLES, resolvePlatformPack, type ContrastPreference, type ControlSize, type LayoutDensity, type MaterialContext, type MaterialThickness, type MotionPreference, type PlatformPackId, type ResolvedUIAppearance, type TransparencyPreference, type UIAppearance, type UIPlatform, type UIPlatformPack, type UIPlatformVersion, type UIPreferences, type UISidebarStyle, type UITheme, } from './contracts.js';
|
|
2
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,cAAc,EACd,mBAAmB,EACnB,KAAK,kBAAkB,EACvB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,OAAO,GACb,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { CONTROL_SIZES, MATERIAL_THICKNESSES, PLATFORM_PACKS, SIDEBAR_STYLES, resolvePlatformPack, } from './contracts.js';
|
package/docs/README.md
CHANGED
|
@@ -8,6 +8,8 @@ feels at home on macOS without imitating private platform implementation.
|
|
|
8
8
|
|
|
9
9
|
- [Foundations](./foundations.md)
|
|
10
10
|
- [Design tokens](./design-tokens.md)
|
|
11
|
+
- [Platform architecture](./platform-architecture.md)
|
|
12
|
+
- [macOS design audit](./macos-design-audit.md)
|
|
11
13
|
- [Adaptive materials](./adaptive-materials.md)
|
|
12
14
|
- [App anatomy](./app-anatomy.md)
|
|
13
15
|
- [Standalone app windows](./standalone-app-windows.md)
|
|
@@ -6,14 +6,15 @@ not replace content surfaces.
|
|
|
6
6
|
|
|
7
7
|
## Roles
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Choose `ultra-thick`, `thick`, `medium`, `thin`, or `ultra-thin` according to
|
|
10
|
+
the surface hierarchy. Medium material is the normal choice for window chrome,
|
|
11
|
+
grouped controls, menus, and temporary control overlays.
|
|
12
12
|
|
|
13
|
-
Use
|
|
13
|
+
Use ultra-thin material only for compact controls floating over photos, maps,
|
|
14
14
|
video, or another richly colored canvas. Check the control against the
|
|
15
15
|
lightest, darkest, and busiest content it can cover. If contrast is not stable,
|
|
16
|
-
use `regular
|
|
16
|
+
use medium. The `regular` and `clear` names remain compatibility aliases for
|
|
17
|
+
`medium` and `ultra-thin`, respectively.
|
|
17
18
|
|
|
18
19
|
Documents, calendars, tables, forms, cards, sheets, inspectors, and primary
|
|
19
20
|
working canvases remain opaque. Do not stack translucent content cards to
|
|
@@ -24,7 +25,7 @@ create hierarchy.
|
|
|
24
25
|
`Material` applies one adaptive surface:
|
|
25
26
|
|
|
26
27
|
```tsx
|
|
27
|
-
<Material asChild variant="
|
|
28
|
+
<Material asChild variant="ultra-thin" shape="circle" interactive>
|
|
28
29
|
<IconButton label="Center map" variant="ghost">
|
|
29
30
|
<Locate />
|
|
30
31
|
</IconButton>
|
|
@@ -34,7 +35,7 @@ create hierarchy.
|
|
|
34
35
|
`MaterialGroup` applies one sampled layer to a related cluster:
|
|
35
36
|
|
|
36
37
|
```tsx
|
|
37
|
-
<MaterialGroup variant="
|
|
38
|
+
<MaterialGroup variant="medium" shape="capsule" spacing="compact">
|
|
38
39
|
<IconButton label="Previous" variant="ghost">
|
|
39
40
|
<ChevronLeft />
|
|
40
41
|
</IconButton>
|
|
@@ -75,5 +76,9 @@ sampled layers and avoid nesting them.
|
|
|
75
76
|
CSS material samples content inside the app renderer. It cannot sample the
|
|
76
77
|
desktop behind a native window. Native behind-window material, window
|
|
77
78
|
transparency, active-window appearance, and energy policy remain host-owned
|
|
78
|
-
capabilities. Apps should use the same
|
|
79
|
-
adapter renders them.
|
|
79
|
+
capabilities. Apps should use the same thickness roles regardless of which
|
|
80
|
+
adapter renders them. Apps opt into native regions per window through
|
|
81
|
+
`moldable.json`; renderer-owned background and sidebar surfaces additionally
|
|
82
|
+
opt in through `AppFrame`. Full-window background material uses a frosted,
|
|
83
|
+
tinted host surface rather than uncovered transparency. Content that needs a
|
|
84
|
+
stable reading surface can remain opaque above it.
|
package/docs/design-tokens.md
CHANGED
|
@@ -114,8 +114,9 @@ disabled, and invalid states. Disabled wins over pointer states. Focus remains
|
|
|
114
114
|
visible when combined with selected or invalid. Selection is durable state;
|
|
115
115
|
hover is not a substitute for it.
|
|
116
116
|
|
|
117
|
-
Focus rings use the
|
|
118
|
-
plain `focus:` ring utilities or
|
|
117
|
+
Focus rings use the shared `--ring` token and the width defined by each
|
|
118
|
+
component recipe. Never use plain `focus:` ring utilities or invent a
|
|
119
|
+
component-local focus color.
|
|
119
120
|
|
|
120
121
|
Do not use state-layer colors as arbitrary fills. Prefer the shared component
|
|
121
122
|
when one exists.
|
|
@@ -141,11 +142,14 @@ stay theme-aware and do not inherit Moldable's legacy brand orange. Apps may
|
|
|
141
142
|
override the complete series palette at a theme boundary, but chart
|
|
142
143
|
components and stories should never embed raw series colors.
|
|
143
144
|
|
|
144
|
-
Adaptive material has
|
|
145
|
-
|
|
145
|
+
Adaptive material has five standard thickness variants: `ultra-thick`,
|
|
146
|
+
`thick`, `medium`, `thin`, and `ultra-thin`. Each includes fill, fallback,
|
|
147
|
+
border, highlight, blur, and saturation tokens. `regular` remains a
|
|
148
|
+
compatibility alias for `medium`, and `clear` remains a compatibility alias
|
|
149
|
+
for `ultra-thin`.
|
|
146
150
|
|
|
147
|
-
-
|
|
148
|
-
-
|
|
151
|
+
- Medium material supports normal toolbar and control chrome.
|
|
152
|
+
- Ultra-thin material supports compact controls over media or a richly
|
|
149
153
|
colored canvas.
|
|
150
154
|
- `shadow-panel`, `shadow-overlay`, `shadow-dialog`, and `shadow-window`
|
|
151
155
|
provide elevation independently from translucency.
|
package/docs/foundations.md
CHANGED
|
@@ -22,9 +22,9 @@ Status color communicates status only; it is not decoration.
|
|
|
22
22
|
- Preserve usable pointer targets even when the visible control is small.
|
|
23
23
|
- Prefer separators, background shifts, and whitespace over nested cards.
|
|
24
24
|
- Working panes own scrolling. The window shell should not accidentally scroll.
|
|
25
|
-
- Set `data-density="compact"
|
|
26
|
-
|
|
27
|
-
inventing per-screen heights.
|
|
25
|
+
- Set `data-density="compact"` or `"comfortable"` at a composition boundary;
|
|
26
|
+
omit it for regular/default density. Components should consume density
|
|
27
|
+
tokens rather than inventing per-screen heights.
|
|
28
28
|
|
|
29
29
|
## Surfaces
|
|
30
30
|
|
|
@@ -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
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
4
|
-
|
|
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
|
|
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
|
|
71
|
-
`
|
|
72
|
-
|
|
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.
|
|
3
|
+
"version": "0.2.31",
|
|
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": {
|