@moldable-ai/ui 0.2.31 → 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.
- package/dist/components/app-error-boundary.d.ts +1 -1
- package/dist/components/chat/chat-image-lightbox.d.ts +8 -0
- package/dist/components/chat/chat-image-lightbox.d.ts.map +1 -1
- package/dist/components/chat/chat-image-lightbox.js +24 -2
- package/dist/components/chat/chat-input.d.ts +3 -2
- package/dist/components/chat/chat-input.d.ts.map +1 -1
- package/dist/components/chat/chat-input.js +3 -3
- package/dist/components/chat/chat-message.d.ts.map +1 -1
- package/dist/components/chat/chat-message.js +3 -1
- package/dist/components/chat/chat-panel.d.ts +3 -1
- package/dist/components/chat/chat-panel.d.ts.map +1 -1
- package/dist/components/chat/chat-panel.js +53 -39
- package/dist/components/chat/conversation-history.d.ts +4 -2
- package/dist/components/chat/conversation-history.d.ts.map +1 -1
- package/dist/components/chat/conversation-history.js +20 -15
- package/dist/components/ui/alert.d.ts +1 -1
- package/dist/components/ui/button.d.ts +2 -2
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/context-menu.d.ts.map +1 -1
- package/dist/components/ui/context-menu.js +1 -0
- package/dist/components/ui/date-field.d.ts +1 -1
- package/dist/components/ui/dropdown-menu.d.ts +1 -0
- package/dist/components/ui/dropdown-menu.d.ts.map +1 -1
- package/dist/components/ui/dropdown-menu.js +3 -2
- package/dist/components/ui/menu-items.d.ts +2 -1
- package/dist/components/ui/menu-items.d.ts.map +1 -1
- package/dist/components/ui/menu-items.js +3 -2
- package/dist/components/ui/message-scroller-controller.d.ts +15 -17
- package/dist/components/ui/message-scroller-controller.d.ts.map +1 -1
- package/dist/components/ui/message-scroller-controller.js +106 -91
- package/dist/components/ui/message-scroller-primitive.d.ts +2 -0
- package/dist/components/ui/message-scroller-primitive.d.ts.map +1 -1
- package/dist/components/ui/message-scroller-primitive.js +2 -0
- package/dist/components/ui/message-scroller.d.ts.map +1 -1
- package/dist/components/ui/message-scroller.js +2 -2
- package/dist/components/ui/number-input.d.ts +1 -1
- package/dist/components/ui/popover.js +1 -1
- package/dist/components/ui/search-field.d.ts +1 -1
- package/dist/components/ui/sidebar.d.ts +6 -2
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/sidebar.js +26 -7
- package/dist/components/ui/toolbar-controls.d.ts +10 -2
- package/dist/components/ui/toolbar-controls.d.ts.map +1 -1
- package/dist/components/ui/toolbar-controls.js +25 -7
- package/package.json +1 -1
- package/src/components/ui/button.md +3 -2
- package/src/components/ui/dropdown-menu.md +16 -14
- package/src/components/ui/menu-items.md +2 -0
- package/src/components/ui/message-scroller.md +6 -3
- package/src/components/ui/sidebar.md +11 -5
- package/src/components/ui/toolbar-controls.md +11 -7
- package/src/styles/index.css +128 -1
- package/src/tokens/moldable/brand.css +124 -7
- package/src/tokens/platform-contract.test.ts +5 -1
|
@@ -6,16 +6,34 @@ import { cn } from '../../lib/utils.js';
|
|
|
6
6
|
import { Button } from './button.js';
|
|
7
7
|
import { DropdownMenu, DropdownMenuTrigger } from './dropdown-menu.js';
|
|
8
8
|
import { IconButton, } from './icon-button.js';
|
|
9
|
+
import { Material } from './material.js';
|
|
9
10
|
import { Separator } from './separator.js';
|
|
10
11
|
const ToolbarControlGroupContext = React.createContext(null);
|
|
11
|
-
function ToolbarButton({ appearance = 'chrome', className, size, variant, ...props }) {
|
|
12
|
+
function ToolbarButton({ appearance = 'chrome', className, material, size, variant, ...props }) {
|
|
12
13
|
const group = React.useContext(ToolbarControlGroupContext);
|
|
13
14
|
const groupedSize = group?.size === 'xl' ? 'lg' : 'sm';
|
|
14
15
|
const emphasis = variant === 'prominent' ? 'primary' : 'standard';
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const usesToolbarChrome = variant === undefined || variant === 'prominent' || variant === 'toolbar';
|
|
17
|
+
const resolvedMaterial = group || appearance === 'quiet'
|
|
18
|
+
? 'none'
|
|
19
|
+
: (material ??
|
|
20
|
+
(usesToolbarChrome
|
|
21
|
+
? variant === 'prominent'
|
|
22
|
+
? 'thick'
|
|
23
|
+
: 'regular'
|
|
24
|
+
: 'none'));
|
|
25
|
+
const resolvedVariant = resolvedMaterial !== 'none'
|
|
26
|
+
? 'ghost'
|
|
27
|
+
: usesToolbarChrome &&
|
|
28
|
+
(group || appearance === 'quiet' || material === 'none')
|
|
29
|
+
? 'ghost'
|
|
30
|
+
: variant === 'prominent'
|
|
31
|
+
? 'toolbar'
|
|
32
|
+
: (variant ?? 'toolbar');
|
|
33
|
+
const button = (_jsx(Button, { "data-slot": "toolbar-button", "data-emphasis": emphasis, size: size ?? (group ? groupedSize : 'xl'), variant: resolvedVariant, className: cn('rounded-pill gap-[var(--m-ui-toolbar-action-gap,var(--density-control-gap))] px-[var(--m-ui-toolbar-action-padding-inline,var(--density-control-padding-inline))] [&_svg:not([class*="size-"])]:size-[var(--m-ui-toolbar-action-icon-size,13px)]', emphasis === 'primary' && 'font-semibold', group && 'shadow-none', className), ...props }));
|
|
34
|
+
if (resolvedMaterial === 'none')
|
|
35
|
+
return button;
|
|
36
|
+
return (_jsx(Material, { asChild: true, variant: resolvedMaterial, shape: "capsule", elevation: "panel", interactive: true, children: button }));
|
|
19
37
|
}
|
|
20
38
|
function ToolbarIconButton({ appearance = 'chrome', className, size, variant, ...props }) {
|
|
21
39
|
const group = React.useContext(ToolbarControlGroupContext);
|
|
@@ -38,8 +56,8 @@ function ToolbarSidebarToggle({ expanded, hideLabel = 'Hide sidebar', onExpanded
|
|
|
38
56
|
const label = expanded ? hideLabel : showLabel;
|
|
39
57
|
return (_jsx(ToolbarIconButton, { "aria-pressed": expanded, "data-state": expanded ? 'on' : 'off', label: label, tooltip: tooltip, onClick: () => onExpandedChange(!expanded), ...props, children: _jsx(PanelLeftIcon, {}) }));
|
|
40
58
|
}
|
|
41
|
-
function ToolbarOverflowMenu({ items, label = 'More actions', onSelectItem, tooltip = true, ...props }) {
|
|
42
|
-
return (_jsx(DropdownMenu, { items: items, onSelectItem: onSelectItem, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ToolbarIconButton, { label: label, tooltip: tooltip, ...props, children: _jsx(EllipsisIcon, {}) }) }) }));
|
|
59
|
+
function ToolbarOverflowMenu({ items, label = 'More actions', nativeMenu = false, onSelectItem, tooltip = true, ...props }) {
|
|
60
|
+
return (_jsx(DropdownMenu, { items: items, nativeMenu: nativeMenu, onSelectItem: onSelectItem, children: _jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(ToolbarIconButton, { label: label, tooltip: tooltip, ...props, children: _jsx(EllipsisIcon, {}) }) }) }));
|
|
43
61
|
}
|
|
44
62
|
function ToolbarTitleField({ 'aria-label': ariaLabel, className, label = 'Document title', type = 'text', ...props }) {
|
|
45
63
|
return (_jsx("input", { "data-slot": "toolbar-title-field", "aria-label": ariaLabel ?? label, type: type, className: cn('text-foreground hover:bg-control-hover focus:bg-control-hover focus-visible:ring-ring h-control-md rounded-control min-w-0 max-w-[min(24rem,32vw)] bg-transparent px-2 text-[13px] font-bold outline-none transition-colors focus-visible:ring-1', className), ...props }));
|
package/package.json
CHANGED
|
@@ -56,8 +56,9 @@ For links that should look like buttons:
|
|
|
56
56
|
- `variant`: `default`, `prominent`, `bordered`, `borderless`, `tinted`,
|
|
57
57
|
`toolbar`, `destructive`, `destructive-tinted`, `outline`, `secondary`,
|
|
58
58
|
`ghost`, or `link`. Defaults to `default`; `default` and `prominent` share
|
|
59
|
-
the prominent recipe.
|
|
60
|
-
|
|
59
|
+
the prominent recipe. `borderless` uses the neutral foreground color without
|
|
60
|
+
a border or fill, then dims slightly on hover and press. Prefer the
|
|
61
|
+
toolbar-control wrappers instead of applying `toolbar` directly.
|
|
61
62
|
- `size`: `default`, `xs`, `sm`, `lg`, `xl`, `mini`, `small`, `medium`,
|
|
62
63
|
`large`, `icon`, `icon-xs`, `icon-sm`, `icon-lg`, or `icon-xl`. Defaults to
|
|
63
64
|
`default`.
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
`DropdownMenu` presents a compact list of commands from a visible trigger. Use
|
|
6
6
|
it for overflow actions, view commands, and small command groups. Its
|
|
7
|
-
declarative item API
|
|
7
|
+
declarative item API uses the portable menu by default and can opt into the
|
|
8
|
+
host-native menu when needed.
|
|
8
9
|
|
|
9
10
|
Use `Select` for a form value, `Combobox` for searchable selection,
|
|
10
11
|
`ContextMenu` for commands attached to the pointer target, and `Popover` when
|
|
@@ -91,9 +92,9 @@ shortcuts, and submenus are available when the command set needs structure.
|
|
|
91
92
|
|
|
92
93
|
## API summary
|
|
93
94
|
|
|
94
|
-
- `DropdownMenu` supports `items?: MenuItems[]`,
|
|
95
|
-
`onSelectItem?: (id: string) => void`, `open`, `defaultOpen`,
|
|
96
|
-
`
|
|
95
|
+
- `DropdownMenu` supports `items?: MenuItems[]`, `nativeMenu?: boolean`,
|
|
96
|
+
`onSelectItem?: (id: string) => void`, `open`, `defaultOpen`, `onOpenChange`,
|
|
97
|
+
`dir`, and `modal`.
|
|
97
98
|
- A `MenuItems` value supports `id`, `kind`, `label`, portable `icon`, reserved
|
|
98
99
|
`sfSymbol`, `enabled`, `checked`, `shortcut`, `destructive`, and `submenu`.
|
|
99
100
|
- Do not provide `DropdownMenuContent` together with `items`. In development
|
|
@@ -128,16 +129,17 @@ menu item; use `Popover` or `Dialog`.
|
|
|
128
129
|
|
|
129
130
|
## Platform behavior
|
|
130
131
|
|
|
131
|
-
With `items`, pointer and keyboard trigger activation
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
132
|
+
With `items`, pointer and keyboard trigger activation opens the portable Radix
|
|
133
|
+
menu by default, including when the host advertises `nativeMenu`.
|
|
134
|
+
|
|
135
|
+
Set `nativeMenu` explicitly on `DropdownMenu` to opt into the host-native menu.
|
|
136
|
+
The trigger rectangle is its anchor, `selectedId` is delivered to
|
|
137
|
+
`onSelectItem`, and dismissal is a no-op. No portable menu is rendered while
|
|
138
|
+
that native request is open. Without the host advertisement, including web and
|
|
139
|
+
iOS, the same items render through the existing Radix anatomy. A stale
|
|
140
|
+
advertisement that returns fallback opens the portable menu as well. Icons and
|
|
141
|
+
destructive styling are portable in v1; `sfSymbol` is reserved and is not
|
|
142
|
+
posted to or rendered by the native service.
|
|
141
143
|
|
|
142
144
|
Shortcuts are display metadata only. They do not register keyboard handlers;
|
|
143
145
|
keep command execution keyed by `onSelectItem`. See
|
|
@@ -45,6 +45,8 @@ import { Button, DropdownMenu, DropdownMenuTrigger } from '@moldable-ai/ui'
|
|
|
45
45
|
- `useDeclarativeMenuState` supports controlled or uncontrolled portable-open
|
|
46
46
|
state. While a native request is active, `nativeOpen` is true and
|
|
47
47
|
`portableOpen` is forced false.
|
|
48
|
+
- Native requests are gated by an explicit component policy. `DropdownMenu`
|
|
49
|
+
exposes that policy as its opt-in `nativeMenu` prop.
|
|
48
50
|
- A completed native request passes `selectedId` to `onSelectItem`.
|
|
49
51
|
Cancellation does nothing. A fallback result or request failure opens the
|
|
50
52
|
portable menu unless the caller supplies its own `onFallback`.
|
|
@@ -62,9 +62,12 @@ import {
|
|
|
62
62
|
|
|
63
63
|
## Hooks and behavior
|
|
64
64
|
|
|
65
|
-
- `useMessageScroller()` returns `scrollToStart`, `scrollToEnd`,
|
|
66
|
-
`scrollToMessage
|
|
67
|
-
|
|
65
|
+
- `useMessageScroller()` returns `scrollToStart`, `scrollToEnd`,
|
|
66
|
+
`scrollToMessage`, `beginHistoryLoad`, and `finishHistoryLoad`. Bracket an
|
|
67
|
+
asynchronous older-history request with the last two methods so prepends and
|
|
68
|
+
stale-page replacements preserve distance from the bottom before paint.
|
|
69
|
+
Targeted scrolls accept `align`, `behavior`, and `scrollMargin`; alignment
|
|
70
|
+
defaults to `start` and behavior to `auto`.
|
|
68
71
|
- `useMessageScrollerScrollable()` returns `{ start, end }`.
|
|
69
72
|
- `useMessageScrollerVisibility()` returns `currentAnchorId` and ordered
|
|
70
73
|
`visibleMessageIds`.
|
|
@@ -25,8 +25,11 @@ import {
|
|
|
25
25
|
} from '@moldable-ai/ui'
|
|
26
26
|
|
|
27
27
|
;<SidebarProvider className="h-full min-h-0">
|
|
28
|
-
<Sidebar collapsible="icon">
|
|
29
|
-
<SidebarContent
|
|
28
|
+
<Sidebar collapsible="icon" material="medium">
|
|
29
|
+
<SidebarContent
|
|
30
|
+
edgeFade
|
|
31
|
+
className="scrollbar-hide pb-[calc(var(--chat-safe-padding,0px)+1rem)]"
|
|
32
|
+
>
|
|
30
33
|
<SidebarGroup>
|
|
31
34
|
<SidebarGroupLabel>Mailboxes</SidebarGroupLabel>
|
|
32
35
|
<SidebarGroupContent>
|
|
@@ -65,14 +68,14 @@ icon tint, and text truncation.
|
|
|
65
68
|
|
|
66
69
|
- `SidebarProvider`: required context. Supports uncontrolled `defaultOpen`, controlled `open`/`onOpenChange`, and CSS variable overrides through `style`.
|
|
67
70
|
- `useSidebar()`: returns `state`, `open`, `setOpen`, `openMobile`, `setOpenMobile`, `isMobile`, and `toggleSidebar`.
|
|
68
|
-
- `Sidebar`: `side="left" | "right"`, `variant="sidebar" | "floating" | "inset"`, `sidebarStyle="platform" | "floating" | "edge-to-edge"`, and `collapsible="offcanvas" | "icon" | "none"`.
|
|
71
|
+
- `Sidebar`: `side="left" | "right"`, `variant="sidebar" | "floating" | "inset"`, `sidebarStyle="platform" | "floating" | "edge-to-edge"`, `material="ultra-thick" | "thick" | "medium" | "thin" | "ultra-thin"` (plus the compatibility aliases `regular` and `clear`), and `collapsible="offcanvas" | "icon" | "none"`.
|
|
69
72
|
- `SidebarInset`: main content surface paired with the sidebar.
|
|
70
73
|
- `SidebarTrigger`: compact toggle button.
|
|
71
74
|
- `SidebarRail`: pointer target along the sidebar edge.
|
|
72
75
|
|
|
73
76
|
### Structure
|
|
74
77
|
|
|
75
|
-
- `SidebarHeader`, `SidebarFooter`, `SidebarContent`, and `SidebarSeparator` divide the vertical shell.
|
|
78
|
+
- `SidebarHeader`, `SidebarFooter`, `SidebarContent`, and `SidebarSeparator` divide the vertical shell. `SidebarContent edgeFade` composes the shared top and bottom `EdgeFade` cues around its scroll viewport; it defaults off.
|
|
76
79
|
- `SidebarInput` is a compact search/filter input.
|
|
77
80
|
- `SidebarGroup`, `SidebarGroupLabel`, `SidebarGroupAction`, and `SidebarGroupContent` organize sections.
|
|
78
81
|
|
|
@@ -120,7 +123,10 @@ Choose the visual anatomy independently from the application's base platform:
|
|
|
120
123
|
|
|
121
124
|
- `edge-to-edge` is the default.
|
|
122
125
|
- `floating` uses the macOS inset, material-backed shell and forces the
|
|
123
|
-
component's resolved variant to `floating`.
|
|
126
|
+
component's resolved variant to `floating`. Its shell clips scrolling
|
|
127
|
+
content to the rounded material edge. Set `material` when the surface needs
|
|
128
|
+
an explicit adaptive-material thickness; thinner values are more
|
|
129
|
+
transparent without changing the standard blur.
|
|
124
130
|
- `edge-to-edge` uses the macOS joined window/sidebar anatomy and forces the
|
|
125
131
|
resolved variant to `sidebar`.
|
|
126
132
|
It has no independent fill, blur, shadow, or internal divider and reveals
|
|
@@ -39,15 +39,17 @@ keeping app toolbars visually consistent.
|
|
|
39
39
|
|
|
40
40
|
## Components
|
|
41
41
|
|
|
42
|
-
- `ToolbarButton` — text or mixed-content action.
|
|
43
|
-
|
|
42
|
+
- `ToolbarButton` — text or mixed-content action. Standalone chrome is a real
|
|
43
|
+
adaptive material surface: `material="regular"` by default and
|
|
44
|
+
`material="thick"` for `variant="prominent"`. Set `material="none"` or
|
|
45
|
+
`appearance="quiet"` to remove it.
|
|
44
46
|
- `ToolbarIconButton` — required accessible label and optional tooltip.
|
|
45
47
|
- `ToolbarBackButton` — single chevron Back affordance for root-to-detail
|
|
46
48
|
navigation.
|
|
47
49
|
- `ToolbarSidebarToggle` — controlled sidebar visibility button with accurate
|
|
48
50
|
pressed state and dynamic label.
|
|
49
51
|
- `ToolbarOverflowMenu` — an ellipsis button backed by Moldable's declarative
|
|
50
|
-
menu API
|
|
52
|
+
portable menu API. Set `nativeMenu` to opt into the native host menu.
|
|
51
53
|
- `ToolbarControlGroup` — a shared surface for closely related actions such as
|
|
52
54
|
Undo/Redo. It defaults to `size="xl"`, supports `size="medium"`, and makes
|
|
53
55
|
children compact quiet controls.
|
|
@@ -55,10 +57,12 @@ keeping app toolbars visually consistent.
|
|
|
55
57
|
- `ToolbarTitleField` — an accessible, inline-editable contextual title.
|
|
56
58
|
|
|
57
59
|
`ToolbarButton` and `ToolbarIconButton` accept `appearance="quiet"` when a
|
|
58
|
-
standalone action should not have raised chrome.
|
|
59
|
-
|
|
60
|
-
accepts `appearance="quiet"`
|
|
61
|
-
|
|
60
|
+
standalone action should not have raised chrome. `ToolbarButton` uses the
|
|
61
|
+
shared adaptive `Material` layer; `ToolbarIconButton` uses the compact toolbar
|
|
62
|
+
control treatment. `ToolbarControlGroup` also accepts `appearance="quiet"`
|
|
63
|
+
when related controls should not share a raised surface. Grouped buttons do
|
|
64
|
+
not add a nested material layer. Raised compact controls use these semantic
|
|
65
|
+
tokens:
|
|
62
66
|
|
|
63
67
|
- `--toolbar-control-background`
|
|
64
68
|
- `--toolbar-control-hover`
|
package/src/styles/index.css
CHANGED
|
@@ -1037,7 +1037,7 @@
|
|
|
1037
1037
|
}
|
|
1038
1038
|
|
|
1039
1039
|
.dark {
|
|
1040
|
-
--background: #
|
|
1040
|
+
--background: #181818;
|
|
1041
1041
|
--foreground: rgb(255 255 255 / 85%);
|
|
1042
1042
|
--card: #242424;
|
|
1043
1043
|
--card-foreground: rgb(255 255 255 / 85%);
|
|
@@ -1437,6 +1437,133 @@
|
|
|
1437
1437
|
saturate(var(--material-active-saturation));
|
|
1438
1438
|
}
|
|
1439
1439
|
}
|
|
1440
|
+
|
|
1441
|
+
/*
|
|
1442
|
+
* Popovers keep the quieter material treatment used before the general
|
|
1443
|
+
* surface-material expansion. They are compact menus, not floating windows.
|
|
1444
|
+
*/
|
|
1445
|
+
.moldable-popover {
|
|
1446
|
+
--shape-overlay: 0.75rem;
|
|
1447
|
+
--density-pane-padding: 0.75rem;
|
|
1448
|
+
--popover-material-fill: color-mix(
|
|
1449
|
+
in oklch,
|
|
1450
|
+
var(--background) 76%,
|
|
1451
|
+
transparent
|
|
1452
|
+
);
|
|
1453
|
+
--popover-material-fallback: color-mix(
|
|
1454
|
+
in oklch,
|
|
1455
|
+
var(--background) 94%,
|
|
1456
|
+
var(--foreground) 6%
|
|
1457
|
+
);
|
|
1458
|
+
--popover-material-border: color-mix(
|
|
1459
|
+
in oklch,
|
|
1460
|
+
var(--foreground) 10%,
|
|
1461
|
+
transparent
|
|
1462
|
+
);
|
|
1463
|
+
--popover-material-highlight: oklch(1 0 0 / 42%);
|
|
1464
|
+
--popover-material-blur: 20px;
|
|
1465
|
+
--popover-material-saturation: 1.18;
|
|
1466
|
+
--popover-material-shadow:
|
|
1467
|
+
0 8px 24px oklch(0.15 0.005 285 / 12%),
|
|
1468
|
+
0 2px 6px oklch(0.15 0.005 285 / 8%);
|
|
1469
|
+
|
|
1470
|
+
border: 1px solid var(--popover-material-border);
|
|
1471
|
+
background-color: var(--popover-material-fallback);
|
|
1472
|
+
box-shadow:
|
|
1473
|
+
inset 0 1px 0 var(--popover-material-highlight),
|
|
1474
|
+
var(--popover-material-shadow);
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
.moldable-popover[data-material='clear'] {
|
|
1478
|
+
--popover-material-fill: color-mix(
|
|
1479
|
+
in oklch,
|
|
1480
|
+
var(--background) 24%,
|
|
1481
|
+
transparent
|
|
1482
|
+
);
|
|
1483
|
+
--popover-material-fallback: color-mix(
|
|
1484
|
+
in oklch,
|
|
1485
|
+
var(--background) 88%,
|
|
1486
|
+
var(--foreground) 12%
|
|
1487
|
+
);
|
|
1488
|
+
--popover-material-border: color-mix(
|
|
1489
|
+
in oklch,
|
|
1490
|
+
var(--foreground) 14%,
|
|
1491
|
+
transparent
|
|
1492
|
+
);
|
|
1493
|
+
--popover-material-highlight: oklch(1 0 0 / 28%);
|
|
1494
|
+
--popover-material-blur: 12px;
|
|
1495
|
+
--popover-material-saturation: 1.24;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
.dark .moldable-popover {
|
|
1499
|
+
--popover-material-fill: color-mix(
|
|
1500
|
+
in oklch,
|
|
1501
|
+
var(--background) 68%,
|
|
1502
|
+
transparent
|
|
1503
|
+
);
|
|
1504
|
+
--popover-material-fallback: color-mix(
|
|
1505
|
+
in oklch,
|
|
1506
|
+
var(--background) 88%,
|
|
1507
|
+
var(--foreground) 12%
|
|
1508
|
+
);
|
|
1509
|
+
--popover-material-border: oklch(1 0 0 / 14%);
|
|
1510
|
+
--popover-material-highlight: oklch(1 0 0 / 12%);
|
|
1511
|
+
--popover-material-shadow:
|
|
1512
|
+
0 12px 32px oklch(0 0 0 / 34%), 0 2px 8px oklch(0 0 0 / 24%);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
.dark .moldable-popover[data-material='clear'] {
|
|
1516
|
+
--popover-material-fill: color-mix(
|
|
1517
|
+
in oklch,
|
|
1518
|
+
var(--background) 20%,
|
|
1519
|
+
transparent
|
|
1520
|
+
);
|
|
1521
|
+
--popover-material-fallback: color-mix(
|
|
1522
|
+
in oklch,
|
|
1523
|
+
var(--background) 78%,
|
|
1524
|
+
var(--foreground) 22%
|
|
1525
|
+
);
|
|
1526
|
+
--popover-material-border: oklch(1 0 0 / 18%);
|
|
1527
|
+
--popover-material-highlight: oklch(1 0 0 / 10%);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
:where([data-transparency='reduced']) .moldable-popover {
|
|
1531
|
+
--popover-material-fill: var(--popover-material-fallback);
|
|
1532
|
+
--popover-material-blur: 0px;
|
|
1533
|
+
--popover-material-saturation: 1;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
1537
|
+
.moldable-popover {
|
|
1538
|
+
--popover-material-fill: var(--popover-material-fallback);
|
|
1539
|
+
--popover-material-blur: 0px;
|
|
1540
|
+
--popover-material-saturation: 1;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
@media (forced-colors: active) {
|
|
1545
|
+
.moldable-popover {
|
|
1546
|
+
--popover-material-fill: Canvas;
|
|
1547
|
+
--popover-material-fallback: Canvas;
|
|
1548
|
+
--popover-material-border: ButtonBorder;
|
|
1549
|
+
--popover-material-highlight: transparent;
|
|
1550
|
+
--popover-material-shadow: none;
|
|
1551
|
+
--popover-material-blur: 0px;
|
|
1552
|
+
--popover-material-saturation: 1;
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
@supports (
|
|
1557
|
+
(-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
|
|
1558
|
+
) {
|
|
1559
|
+
.moldable-popover {
|
|
1560
|
+
background-color: var(--popover-material-fill);
|
|
1561
|
+
-webkit-backdrop-filter: blur(var(--popover-material-blur))
|
|
1562
|
+
saturate(var(--popover-material-saturation));
|
|
1563
|
+
backdrop-filter: blur(var(--popover-material-blur))
|
|
1564
|
+
saturate(var(--popover-material-saturation));
|
|
1565
|
+
}
|
|
1566
|
+
}
|
|
1440
1567
|
}
|
|
1441
1568
|
|
|
1442
1569
|
@layer utilities {
|
|
@@ -8,15 +8,132 @@
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/*
|
|
11
|
-
* Moldable's dark canvas stays close to the macOS window surface
|
|
12
|
-
*
|
|
13
|
-
*
|
|
11
|
+
* Moldable's dark canvas stays close to the macOS window surface with a
|
|
12
|
+
* neutral tone. Keep these product colors in the brand layer instead of
|
|
13
|
+
* changing the immutable platform source values.
|
|
14
14
|
*/
|
|
15
15
|
[data-ui-theme='moldable'][data-ui-appearance='dark'] {
|
|
16
|
-
--m-ui-surface-window: #
|
|
17
|
-
--m-ui-surface-content: #
|
|
18
|
-
--background: #
|
|
19
|
-
--surface-canvas: #
|
|
16
|
+
--m-ui-surface-window: #181818;
|
|
17
|
+
--m-ui-surface-content: #181818;
|
|
18
|
+
--background: #181818;
|
|
19
|
+
--surface-canvas: #181818;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
* Renderer-owned selects and dropdowns keep Moldable's compact web styling.
|
|
24
|
+
* Native menu geometry belongs only to the explicit host-native menu path.
|
|
25
|
+
* These values preserve the component treatment from 94f11aa without
|
|
26
|
+
* changing the platform source pack used by native integrations.
|
|
27
|
+
*/
|
|
28
|
+
[data-ui-theme='moldable'] [data-slot='select-trigger'] {
|
|
29
|
+
--shape-control: calc(0.65rem - 2px);
|
|
30
|
+
--density-control-height-sm: 2rem;
|
|
31
|
+
--density-control-height-md: 2.25rem;
|
|
32
|
+
--density-control-gap: 0.5rem;
|
|
33
|
+
--density-control-padding-inline: 0.75rem;
|
|
34
|
+
--type-body-size: 0.875rem;
|
|
35
|
+
--type-body-line-height: 1.25rem;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
[data-ui-theme='moldable']
|
|
39
|
+
:is(
|
|
40
|
+
[data-slot='select-content'],
|
|
41
|
+
[data-slot='dropdown-menu-content'],
|
|
42
|
+
[data-slot='dropdown-menu-sub-content']
|
|
43
|
+
) {
|
|
44
|
+
--shape-overlay: calc(0.65rem - 2px);
|
|
45
|
+
--m-ui-menu-padding-block: 0.25rem;
|
|
46
|
+
--m-ui-menu-item-radius: calc(0.65rem - 4px);
|
|
47
|
+
--type-body-size: 0.875rem;
|
|
48
|
+
--type-body-line-height: 1.25rem;
|
|
49
|
+
--type-caption-size: 0.75rem;
|
|
50
|
+
--type-caption-line-height: 1rem;
|
|
51
|
+
--material-shadow-overlay: var(--shadow-md);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
[data-ui-theme='moldable'] [data-slot='dropdown-menu-sub-content'] {
|
|
55
|
+
--material-shadow-overlay: var(--shadow-lg);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
[data-ui-theme='moldable'][data-ui-appearance='light']
|
|
59
|
+
:is(
|
|
60
|
+
[data-slot='select-content'],
|
|
61
|
+
[data-slot='dropdown-menu-content'],
|
|
62
|
+
[data-slot='dropdown-menu-sub-content']
|
|
63
|
+
) {
|
|
64
|
+
--popover: oklch(1 0 0);
|
|
65
|
+
--popover-foreground: oklch(0.141 0.005 285.823);
|
|
66
|
+
--accent: oklch(0.967 0.001 286.375);
|
|
67
|
+
--accent-foreground: oklch(0.21 0.006 285.885);
|
|
68
|
+
--muted-foreground: oklch(0.552 0.016 285.938);
|
|
69
|
+
--border: oklch(0.92 0.004 286.32);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
[data-ui-theme='moldable'][data-ui-appearance='dark']
|
|
73
|
+
:is(
|
|
74
|
+
[data-slot='select-content'],
|
|
75
|
+
[data-slot='dropdown-menu-content'],
|
|
76
|
+
[data-slot='dropdown-menu-sub-content']
|
|
77
|
+
) {
|
|
78
|
+
--popover: oklch(0.269 0.0018 286.28);
|
|
79
|
+
--popover-foreground: oklch(0.985 0 0);
|
|
80
|
+
--accent: oklch(0.3375 0.0035 286.21);
|
|
81
|
+
--accent-foreground: oklch(0.985 0 0);
|
|
82
|
+
--muted-foreground: oklch(0.705 0.015 286.067);
|
|
83
|
+
--border: oklch(1 0 0 / 10%);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/*
|
|
87
|
+
* Keep Moldable tooltips on the compact material recipe from 94f11aa. The
|
|
88
|
+
* selected platform kit now maps generic overlays to its larger popover
|
|
89
|
+
* geometry, so the product theme reasserts the tooltip's own smaller recipe.
|
|
90
|
+
*/
|
|
91
|
+
[data-ui-theme='moldable'] [data-slot='tooltip-content'] {
|
|
92
|
+
--shape-overlay: 0.75rem;
|
|
93
|
+
--type-caption-size: 0.75rem;
|
|
94
|
+
--type-caption-line-height: 1rem;
|
|
95
|
+
--surface-overlay: color-mix(in oklch, var(--popover) 92%, transparent);
|
|
96
|
+
--material-regular-fill: color-mix(
|
|
97
|
+
in oklch,
|
|
98
|
+
var(--background) 76%,
|
|
99
|
+
transparent
|
|
100
|
+
);
|
|
101
|
+
--material-regular-fallback: color-mix(
|
|
102
|
+
in oklch,
|
|
103
|
+
var(--background) 94%,
|
|
104
|
+
var(--foreground) 6%
|
|
105
|
+
);
|
|
106
|
+
--material-regular-blur: 20px;
|
|
107
|
+
--material-regular-saturation: 1.18;
|
|
108
|
+
--material-shadow-overlay:
|
|
109
|
+
0 8px 24px oklch(0.15 0.005 285 / 12%),
|
|
110
|
+
0 2px 6px oklch(0.15 0.005 285 / 8%);
|
|
111
|
+
box-shadow:
|
|
112
|
+
inset 0 1px 0 oklch(1 0 0 / 42%),
|
|
113
|
+
var(--material-shadow-overlay);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
[data-ui-theme='moldable'][data-ui-appearance='dark']
|
|
117
|
+
[data-slot='tooltip-content'] {
|
|
118
|
+
--material-regular-fill: color-mix(
|
|
119
|
+
in oklch,
|
|
120
|
+
var(--background) 68%,
|
|
121
|
+
transparent
|
|
122
|
+
);
|
|
123
|
+
--material-regular-fallback: color-mix(
|
|
124
|
+
in oklch,
|
|
125
|
+
var(--background) 88%,
|
|
126
|
+
var(--foreground) 12%
|
|
127
|
+
);
|
|
128
|
+
--material-shadow-overlay:
|
|
129
|
+
0 12px 32px oklch(0 0 0 / 34%), 0 2px 8px oklch(0 0 0 / 24%);
|
|
130
|
+
box-shadow:
|
|
131
|
+
inset 0 1px 0 oklch(1 0 0 / 12%),
|
|
132
|
+
var(--material-shadow-overlay);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
[data-ui-theme='moldable'] [data-slot='tooltip-shortcut'] {
|
|
136
|
+
font-size: 0.625rem;
|
|
20
137
|
}
|
|
21
138
|
|
|
22
139
|
/*
|
|
@@ -278,7 +278,11 @@ describe('platform token contract', () => {
|
|
|
278
278
|
expect(brand).not.toMatch(
|
|
279
279
|
/\[data-ui-sidebar-style='floating'\]\s+\[data-ui-appearance='dark'\]/,
|
|
280
280
|
)
|
|
281
|
-
expect(brand).toContain('--m-ui-surface-content: #
|
|
281
|
+
expect(brand).toContain('--m-ui-surface-content: #181818;')
|
|
282
|
+
expect(brand).toContain("[data-slot='select-trigger']")
|
|
283
|
+
expect(brand).toContain("[data-slot='select-content']")
|
|
284
|
+
expect(brand).toContain("[data-slot='dropdown-menu-content']")
|
|
285
|
+
expect(brand).toContain('--material-shadow-overlay: var(--shadow-md);')
|
|
282
286
|
expect(brand).toContain('--m-ui-sidebar-material-fill: #1b1d1e;')
|
|
283
287
|
expect(brand).toContain('--m-ui-sidebar-border-color: #394043;')
|
|
284
288
|
expect(brand).toContain(
|