@moldable-ai/ui 0.2.20 → 0.2.22
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/catalog-coverage.d.ts +15 -0
- package/dist/catalog/catalog-coverage.d.ts.map +1 -0
- package/dist/catalog/catalog-coverage.js +44 -0
- package/dist/catalog/catalog-manifest.d.ts.map +1 -1
- package/dist/catalog/catalog-manifest.js +35 -23
- package/dist/catalog/catalog-types.d.ts +17 -0
- package/dist/catalog/catalog-types.d.ts.map +1 -1
- package/dist/catalog/catalog-types.js +7 -0
- package/dist/catalog/component-catalog.d.ts.map +1 -1
- package/dist/catalog/component-catalog.js +16 -6
- package/dist/catalog/core-catalog-exclusions.d.ts +8 -0
- package/dist/catalog/core-catalog-exclusions.d.ts.map +1 -0
- package/dist/catalog/core-catalog-exclusions.js +155 -0
- package/dist/catalog/core-catalog.d.ts +0 -4
- package/dist/catalog/core-catalog.d.ts.map +1 -1
- package/dist/catalog/core-catalog.js +12 -98
- package/dist/catalog/core-collection-stories.d.ts +3 -0
- package/dist/catalog/core-collection-stories.d.ts.map +1 -0
- package/dist/catalog/core-collection-stories.js +42 -0
- package/dist/catalog/core-control-stories.d.ts +3 -0
- package/dist/catalog/core-control-stories.d.ts.map +1 -0
- package/dist/catalog/core-control-stories.js +97 -0
- package/dist/catalog/core-feedback-stories.d.ts +3 -0
- package/dist/catalog/core-feedback-stories.d.ts.map +1 -0
- package/dist/catalog/core-feedback-stories.js +50 -0
- package/dist/catalog/core-foundation-stories.d.ts +3 -0
- package/dist/catalog/core-foundation-stories.d.ts.map +1 -0
- package/dist/catalog/core-foundation-stories.js +53 -0
- package/dist/catalog/core-navigation-stories.d.ts +3 -0
- package/dist/catalog/core-navigation-stories.d.ts.map +1 -0
- package/dist/catalog/core-navigation-stories.js +25 -0
- package/dist/catalog/core-overlay-stories.d.ts +3 -0
- package/dist/catalog/core-overlay-stories.d.ts.map +1 -0
- package/dist/catalog/core-overlay-stories.js +20 -0
- package/dist/catalog/index.d.ts +3 -1
- package/dist/catalog/index.d.ts.map +1 -1
- package/dist/catalog/index.js +3 -1
- package/dist/components/app-error-boundary.d.ts.map +1 -1
- package/dist/components/app-error-boundary.js +3 -2
- package/dist/components/chat/chat-panel.d.ts +0 -1
- package/dist/components/chat/chat-panel.d.ts.map +1 -1
- package/dist/components/chat/chat-panel.js +7 -11
- package/dist/components/ui/alert-dialog.d.ts +10 -4
- package/dist/components/ui/alert-dialog.d.ts.map +1 -1
- package/dist/components/ui/alert-dialog.js +14 -6
- package/dist/components/ui/alert.d.ts +19 -3
- package/dist/components/ui/alert.d.ts.map +1 -1
- package/dist/components/ui/alert.js +25 -8
- package/dist/components/ui/app-frame.d.ts +9 -3
- package/dist/components/ui/app-frame.d.ts.map +1 -1
- package/dist/components/ui/app-frame.js +45 -6
- package/dist/components/ui/button.d.ts +6 -4
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.js +40 -8
- package/dist/components/ui/collapsible.d.ts +9 -1
- package/dist/components/ui/collapsible.d.ts.map +1 -1
- package/dist/components/ui/collapsible.js +13 -2
- package/dist/components/ui/collection-navigation.d.ts +8 -0
- package/dist/components/ui/collection-navigation.d.ts.map +1 -0
- package/dist/components/ui/collection-navigation.js +19 -0
- package/dist/components/ui/command.d.ts +5 -1
- package/dist/components/ui/command.d.ts.map +1 -1
- package/dist/components/ui/command.js +13 -1
- package/dist/components/ui/confirm-dialog.d.ts +19 -0
- package/dist/components/ui/confirm-dialog.d.ts.map +1 -0
- package/dist/components/ui/confirm-dialog.js +45 -0
- package/dist/components/ui/date-picker.d.ts +24 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -0
- package/dist/components/ui/date-picker.js +92 -0
- package/dist/components/ui/dialog-primary-action.d.ts +4 -0
- package/dist/components/ui/dialog-primary-action.d.ts.map +1 -0
- package/dist/components/ui/dialog-primary-action.js +37 -0
- package/dist/components/ui/dialog.d.ts +8 -2
- package/dist/components/ui/dialog.d.ts.map +1 -1
- package/dist/components/ui/dialog.js +15 -5
- package/dist/components/ui/empty.d.ts +7 -2
- package/dist/components/ui/empty.d.ts.map +1 -1
- package/dist/components/ui/empty.js +20 -7
- package/dist/components/ui/error-boundary-view.d.ts +12 -0
- package/dist/components/ui/error-boundary-view.d.ts.map +1 -0
- package/dist/components/ui/error-boundary-view.js +8 -0
- package/dist/components/ui/grid.d.ts.map +1 -1
- package/dist/components/ui/grid.js +70 -46
- package/dist/components/ui/icon-button.d.ts.map +1 -1
- package/dist/components/ui/icon-button.js +1 -2
- package/dist/components/ui/index.d.ts +5 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +5 -0
- package/dist/components/ui/input-group.d.ts +1 -1
- package/dist/components/ui/list.d.ts +5 -1
- package/dist/components/ui/list.d.ts.map +1 -1
- package/dist/components/ui/list.js +27 -16
- package/dist/components/ui/material.d.ts +34 -0
- package/dist/components/ui/material.d.ts.map +1 -0
- package/dist/components/ui/material.js +34 -0
- package/dist/components/ui/message-scroller-controller.d.ts +162 -0
- package/dist/components/ui/message-scroller-controller.d.ts.map +1 -0
- package/dist/components/ui/message-scroller-controller.js +888 -0
- package/dist/components/ui/message-scroller-policy.d.ts +74 -0
- package/dist/components/ui/message-scroller-policy.d.ts.map +1 -0
- package/dist/components/ui/message-scroller-policy.js +129 -0
- package/dist/components/ui/message-scroller-primitive.d.ts +55 -0
- package/dist/components/ui/message-scroller-primitive.d.ts.map +1 -0
- package/dist/components/ui/message-scroller-primitive.js +226 -0
- package/dist/components/ui/message-scroller.d.ts +2 -2
- package/dist/components/ui/message-scroller.d.ts.map +1 -1
- package/dist/components/ui/message-scroller.js +3 -15
- package/dist/components/ui/navigation-button-group.d.ts +16 -0
- package/dist/components/ui/navigation-button-group.d.ts.map +1 -0
- package/dist/components/ui/navigation-button-group.js +9 -0
- package/dist/components/ui/popover.d.ts +9 -2
- package/dist/components/ui/popover.d.ts.map +1 -1
- package/dist/components/ui/popover.js +13 -3
- package/dist/components/ui/scroll-area.d.ts +8 -2
- package/dist/components/ui/scroll-area.d.ts.map +1 -1
- package/dist/components/ui/scroll-area.js +6 -3
- package/dist/components/ui/search-field.d.ts.map +1 -1
- package/dist/components/ui/segmented-control.d.ts.map +1 -1
- package/dist/components/ui/segmented-control.js +6 -5
- package/dist/components/ui/sheet.d.ts +4 -2
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet.js +12 -9
- package/dist/components/ui/sonner.d.ts +1 -1
- package/dist/components/ui/sonner.d.ts.map +1 -1
- package/dist/components/ui/spinner.d.ts.map +1 -1
- package/dist/components/ui/spinner.js +1 -1
- package/dist/components/ui/table.d.ts.map +1 -1
- package/dist/components/ui/table.js +7 -2
- package/dist/components/ui/toggle.d.ts +12 -4
- package/dist/components/ui/toggle.d.ts.map +1 -1
- package/dist/components/ui/toggle.js +13 -2
- package/dist/components/ui/toolbar.d.ts +9 -2
- package/dist/components/ui/toolbar.d.ts.map +1 -1
- package/dist/components/ui/toolbar.js +23 -4
- package/dist/components/ui/tooltip.d.ts +8 -3
- package/dist/components/ui/tooltip.d.ts.map +1 -1
- package/dist/components/ui/tooltip.js +11 -6
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/lib/frame-lifecycle.d.ts +23 -0
- package/dist/lib/frame-lifecycle.d.ts.map +1 -1
- package/dist/lib/frame-lifecycle.js +30 -3
- package/dist/lib/host-date-time-picker.d.ts +36 -0
- package/dist/lib/host-date-time-picker.d.ts.map +1 -0
- package/dist/lib/host-date-time-picker.js +162 -0
- package/dist/lib/host-file-dialog.d.ts +66 -0
- package/dist/lib/host-file-dialog.d.ts.map +1 -0
- package/dist/lib/host-file-dialog.js +221 -0
- package/dist/lib/host-native-menu.d.ts +75 -0
- package/dist/lib/host-native-menu.d.ts.map +1 -0
- package/dist/lib/host-native-menu.js +187 -0
- package/dist/lib/host-services.d.ts +13 -0
- package/dist/lib/host-services.d.ts.map +1 -0
- package/dist/lib/host-services.js +161 -0
- package/dist/lib/host-share.d.ts +39 -0
- package/dist/lib/host-share.d.ts.map +1 -0
- package/dist/lib/host-share.js +161 -0
- package/dist/lib/theme.d.ts.map +1 -1
- package/dist/lib/theme.js +2 -1
- package/docs/README.md +4 -1
- package/docs/adaptive-materials.md +79 -0
- package/docs/app-anatomy.md +3 -1
- package/docs/component-catalog.md +26 -3
- package/docs/design-tokens.md +17 -4
- package/docs/foundations.md +5 -3
- package/docs/standalone-app-windows.md +8 -0
- package/docs/visual-regression.md +78 -0
- package/package.json +12 -4
- package/src/components/ui/alert-dialog.md +58 -0
- package/src/components/ui/alert.md +28 -6
- package/src/components/ui/app-frame.md +5 -0
- package/src/components/ui/button.md +10 -3
- package/src/components/ui/collapsible.md +52 -0
- package/src/components/ui/combobox.md +0 -1
- package/src/components/ui/command.md +54 -0
- package/src/components/ui/date-field.md +1 -1
- package/src/components/ui/date-picker.md +55 -0
- package/src/components/ui/dialog.md +59 -0
- package/src/components/ui/empty.md +8 -3
- package/src/components/ui/error-boundary-view.md +98 -0
- package/src/components/ui/grid.md +8 -4
- package/src/components/ui/icon-button.md +2 -2
- package/src/components/ui/list.md +35 -2
- package/src/components/ui/material.md +51 -0
- package/src/components/ui/navigation-button-group.md +46 -0
- package/src/components/ui/popover.md +31 -0
- package/src/components/ui/scroll-area.md +11 -7
- package/src/components/ui/search-field.md +1 -1
- package/src/components/ui/segmented-control.md +2 -5
- package/src/components/ui/sheet.md +30 -0
- package/src/components/ui/table.md +4 -2
- package/src/components/ui/toggle-button.md +48 -0
- package/src/components/ui/toolbar.md +5 -0
- package/src/components/ui/tooltip.md +31 -0
- package/src/styles/index.css +213 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# DatePicker
|
|
2
|
+
|
|
3
|
+
`DatePicker` is a portable, date-only calendar popover. Its value is an ISO
|
|
4
|
+
calendar date (`YYYY-MM-DD`), so app storage does not introduce timezone
|
|
5
|
+
conversion.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<DatePicker
|
|
9
|
+
aria-label="Due date"
|
|
10
|
+
value={dueDate}
|
|
11
|
+
onValueChange={setDueDate}
|
|
12
|
+
min="2026-01-01"
|
|
13
|
+
clearable
|
|
14
|
+
/>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## DatePicker or DateField
|
|
18
|
+
|
|
19
|
+
- Use `DatePicker` when a predictable renderer-owned calendar is important.
|
|
20
|
+
- Use `DateField` when compact keyboard entry and the browser's date control
|
|
21
|
+
are preferable.
|
|
22
|
+
- Use the standalone `Calendar` for ranges, multiple dates, or an always
|
|
23
|
+
visible month.
|
|
24
|
+
|
|
25
|
+
## API
|
|
26
|
+
|
|
27
|
+
- `value`, `defaultValue`: ISO `YYYY-MM-DD` or an empty string.
|
|
28
|
+
- `onValueChange`: receives the next ISO date or an empty string.
|
|
29
|
+
- `min`, `max`: inclusive ISO date limits.
|
|
30
|
+
- `placeholder`: trigger copy when empty.
|
|
31
|
+
- `locale`: the `react-day-picker` locale used by the calendar and display.
|
|
32
|
+
- `formatValue`: custom trigger rendering for the ISO value.
|
|
33
|
+
- `clearable`, `clearLabel`: optional clear action inside the popover.
|
|
34
|
+
- `density`: `compact`, `default`, or `comfortable`.
|
|
35
|
+
- `open`, `defaultOpen`, `onOpenChange`: controlled or uncontrolled popover.
|
|
36
|
+
- Remaining button props apply to the trigger.
|
|
37
|
+
|
|
38
|
+
## Keyboard and accessibility
|
|
39
|
+
|
|
40
|
+
Label the trigger through visible form text, `aria-labelledby`, or
|
|
41
|
+
`aria-label`. The trigger opens with Enter or Space. The calendar owns arrow,
|
|
42
|
+
Home, End, Page Up, and Page Down behavior. Selection closes the popover and
|
|
43
|
+
focus returns to the trigger.
|
|
44
|
+
|
|
45
|
+
## Platform behavior
|
|
46
|
+
|
|
47
|
+
This component is portable and uses no host API. A future native date or time
|
|
48
|
+
control must be introduced through a shared host capability with this
|
|
49
|
+
renderer-owned control as its fallback.
|
|
50
|
+
|
|
51
|
+
## Don't
|
|
52
|
+
|
|
53
|
+
- Do not put timestamps or UTC instants in this date-only value.
|
|
54
|
+
- Do not use this component for time, date-time, or date-range selection.
|
|
55
|
+
- Do not manually convert the selected value through `Date.toISOString()`.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
Use `Dialog` for focused work that temporarily blocks the current surface. Use
|
|
4
|
+
`AlertDialog` or `ConfirmDialog` for consequential confirmation, `Popover` for
|
|
5
|
+
small anchored controls, and `Sheet` for a secondary region that should retain
|
|
6
|
+
spatial context.
|
|
7
|
+
|
|
8
|
+
## Anatomy
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
<Dialog>
|
|
12
|
+
<DialogTrigger asChild>
|
|
13
|
+
<Button>Edit details</Button>
|
|
14
|
+
</DialogTrigger>
|
|
15
|
+
<DialogContent size="lg">
|
|
16
|
+
<DialogHeader>
|
|
17
|
+
<DialogTitle>Edit details</DialogTitle>
|
|
18
|
+
<DialogDescription>Update the selected record.</DialogDescription>
|
|
19
|
+
</DialogHeader>
|
|
20
|
+
<DialogBody>{/* the only scrolling region */}</DialogBody>
|
|
21
|
+
<DialogFooter>
|
|
22
|
+
<span className="text-muted-foreground mr-auto inline-flex items-center gap-1 text-xs">
|
|
23
|
+
Save <Kbd>⌘</Kbd>
|
|
24
|
+
<Kbd>Enter</Kbd>
|
|
25
|
+
</span>
|
|
26
|
+
<DialogAction primary loading={isSaving} onClick={saveChanges}>
|
|
27
|
+
Save changes
|
|
28
|
+
</DialogAction>
|
|
29
|
+
</DialogFooter>
|
|
30
|
+
</DialogContent>
|
|
31
|
+
</Dialog>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`DialogContent` supports `sm`, `default`, `lg`, and `full`. It limits itself to
|
|
35
|
+
the host-provided window and chat-safe insets. `DialogBody` owns vertical
|
|
36
|
+
scrolling; do not put overflow on both the content and body.
|
|
37
|
+
|
|
38
|
+
Keep dialogs opaque and visually stable. Translucent material belongs on small
|
|
39
|
+
temporary control overlays where seeing the underlying context is useful.
|
|
40
|
+
|
|
41
|
+
Use `DialogAction` for footer commands that need the standard async and keyboard
|
|
42
|
+
contracts. Its `loading` prop forwards to `Button`, preventing duplicate
|
|
43
|
+
activation while retaining the label width and accessible name. Keep the dialog
|
|
44
|
+
controlled, show inline field errors, and close only after success. Disable the
|
|
45
|
+
whole form only when edits during submission would be unsafe. Use
|
|
46
|
+
`ConfirmDialog` when confirmation is the entire workflow.
|
|
47
|
+
|
|
48
|
+
Set `primary` on at most one `DialogAction` to opt into the default-action
|
|
49
|
+
shortcut. Command+Enter activates it on macOS; Control+Enter does so on other
|
|
50
|
+
platforms. The shortcut works from anywhere in the dialog unless a focused
|
|
51
|
+
control consumes the key event with `preventDefault()`, or the primary action is
|
|
52
|
+
loading or disabled. Plain Enter keeps the focused control's native behavior.
|
|
53
|
+
Use `Kbd` to show the shortcut when it improves discovery; render the
|
|
54
|
+
platform-appropriate modifier in app code.
|
|
55
|
+
|
|
56
|
+
Every dialog needs a `DialogTitle`. Add `DialogDescription` when the outcome or
|
|
57
|
+
scope is not obvious. Escape, outside dismissal, initial focus, and focus return
|
|
58
|
+
come from the Radix primitive; do not replace them with manual document event
|
|
59
|
+
handlers.
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
EmptyTitle,
|
|
21
21
|
} from '@moldable-ai/ui'
|
|
22
22
|
|
|
23
|
-
;<Empty
|
|
23
|
+
;<Empty variant="pane" safeBottom>
|
|
24
24
|
<EmptyHeader>
|
|
25
25
|
<EmptyMedia variant="icon">
|
|
26
26
|
<Database />
|
|
@@ -52,6 +52,9 @@ For a successful zero state, omit the action when there is nothing useful to do:
|
|
|
52
52
|
## API summary
|
|
53
53
|
|
|
54
54
|
- `Empty`: centered flex container for the complete state.
|
|
55
|
+
- `Empty variant`: `compact`, `pane`, or `full`; defaults to `pane`.
|
|
56
|
+
- `Empty safeBottom`: adds host-provided chat clearance. Do not enable it when
|
|
57
|
+
an owning `AppFrameContent` or parent scroll region already applies clearance.
|
|
55
58
|
- `EmptyHeader`: groups media, title, and description.
|
|
56
59
|
- `EmptyMedia`: `variant="default"` or `variant="icon"`.
|
|
57
60
|
- `EmptyTitle`: primary label.
|
|
@@ -65,7 +68,7 @@ For a successful zero state, omit the action when there is nothing useful to do:
|
|
|
65
68
|
- Show one primary setup action when the state is blocked.
|
|
66
69
|
- Distinguish first-run, filtered-zero, permission, and successful-zero states.
|
|
67
70
|
- Keep the app’s normal shell or pane structure visible.
|
|
68
|
-
-
|
|
71
|
+
- Use `safeBottom` when the empty state itself owns a pane that reaches the bottom.
|
|
69
72
|
|
|
70
73
|
## Don't
|
|
71
74
|
|
|
@@ -79,4 +82,6 @@ For a successful zero state, omit the action when there is nothing useful to do:
|
|
|
79
82
|
|
|
80
83
|
An empty state should feel like part of a local instrument, not a landing page. Keep it visually small even when centered. If the desktop chat can resolve the state, provide specific app context or an explicit “Ask Moldable about this” affordance that prefills desktop chat; do not add another chat box.
|
|
81
84
|
|
|
82
|
-
For scrollable panes,
|
|
85
|
+
For scrollable panes, prefer `safeBottom` on the owning `ScrollArea`. Apply it
|
|
86
|
+
to `Empty` only when the empty state is the owner, so nested states do not add
|
|
87
|
+
the same safe area twice.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# ErrorBoundaryView
|
|
2
|
+
|
|
3
|
+
`ErrorBoundaryView` presents a compact recovery state without owning error
|
|
4
|
+
catching, reporting, or host policy.
|
|
5
|
+
|
|
6
|
+
## When to use
|
|
7
|
+
|
|
8
|
+
Use it as the renderer for a React error boundary, route-level failure, or
|
|
9
|
+
host-provided pane error. Supply `actions` when the host owns reporting,
|
|
10
|
+
navigation, or chat recovery.
|
|
11
|
+
|
|
12
|
+
## When not to use
|
|
13
|
+
|
|
14
|
+
Do not use it for inline field validation, routine empty states, or transient
|
|
15
|
+
request failures that can stay beside the initiating control. It does not catch
|
|
16
|
+
errors itself; use `AppErrorBoundary` when the package should own catching and
|
|
17
|
+
Moldable reporting.
|
|
18
|
+
|
|
19
|
+
## Anatomy
|
|
20
|
+
|
|
21
|
+
The view contains one compact surface with a title, optional message, optional
|
|
22
|
+
error-details disclosure, and one action row. It does not add illustrations or
|
|
23
|
+
nested cards.
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
import { ErrorBoundaryView } from '@moldable-ai/ui'
|
|
29
|
+
|
|
30
|
+
function PaneError() {
|
|
31
|
+
return (
|
|
32
|
+
<ErrorBoundaryView
|
|
33
|
+
title="Could not load this pane"
|
|
34
|
+
message="Retry the request or report the captured error."
|
|
35
|
+
details={error.stack}
|
|
36
|
+
onRetry={retry}
|
|
37
|
+
actions={
|
|
38
|
+
<Button type="button" variant="secondary" onClick={reportError}>
|
|
39
|
+
Report error
|
|
40
|
+
</Button>
|
|
41
|
+
}
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Variants and sizes
|
|
48
|
+
|
|
49
|
+
The renderer has one responsive layout. It uses the available height in a pane
|
|
50
|
+
and can fill a window when its parent gives it full height. The content remains
|
|
51
|
+
bounded to a readable width.
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
- `title`: heading content. Defaults to `"Something went wrong"`.
|
|
56
|
+
- `message`: optional supporting copy.
|
|
57
|
+
- `details`: optional string shown in a collapsed disclosure with a bounded,
|
|
58
|
+
scrollable monospace region.
|
|
59
|
+
- `onRetry`: when supplied, renders a `Retry` button and calls the handler once
|
|
60
|
+
per activation.
|
|
61
|
+
- `actions`: optional host-provided action content rendered after Retry.
|
|
62
|
+
- `className`: optional classes merged onto the outer renderer.
|
|
63
|
+
|
|
64
|
+
## States and interaction
|
|
65
|
+
|
|
66
|
+
Omit `details` when there is no safe diagnostic text to show. Omit both
|
|
67
|
+
`onRetry` and `actions` for a read-only failure. Keep retry state in the caller
|
|
68
|
+
and pass `loading` to a custom action when retrying is asynchronous.
|
|
69
|
+
|
|
70
|
+
## Keyboard and accessibility
|
|
71
|
+
|
|
72
|
+
The details use native `details` and `summary` semantics. The title is the
|
|
73
|
+
surface heading, the Retry control keeps native button behavior, and diagnostic
|
|
74
|
+
text remains selectable.
|
|
75
|
+
|
|
76
|
+
## Platform behavior
|
|
77
|
+
|
|
78
|
+
The component has no host calls or platform branches. `AppErrorBoundary`
|
|
79
|
+
supplies Moldable-specific reload and chat-prefill actions.
|
|
80
|
+
|
|
81
|
+
## Do
|
|
82
|
+
|
|
83
|
+
- Keep the title calm and literal.
|
|
84
|
+
- Give the message a concrete recovery path.
|
|
85
|
+
- Redact secrets before passing diagnostic details.
|
|
86
|
+
- Use semantic theme tokens in custom actions.
|
|
87
|
+
|
|
88
|
+
## Don't
|
|
89
|
+
|
|
90
|
+
- Do not add decorative error art or nested cards.
|
|
91
|
+
- Do not put binary data or unbounded logs in `details`.
|
|
92
|
+
- Do not make this presentational component report or reload implicitly.
|
|
93
|
+
|
|
94
|
+
## Testing
|
|
95
|
+
|
|
96
|
+
Contract tests should verify copy, disclosure behavior, Retry activation, and
|
|
97
|
+
host action rendering. Error-catching and reporting tests belong to the owning
|
|
98
|
+
boundary.
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
GridItemTitle,
|
|
19
19
|
} from '@moldable-ai/ui'
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
;<Grid
|
|
22
22
|
aria-label="Artifacts"
|
|
23
23
|
columns={3}
|
|
24
24
|
selectionMode="single"
|
|
@@ -56,14 +56,18 @@ Prefer changing this value at deliberate window breakpoints. A smaller window sh
|
|
|
56
56
|
|
|
57
57
|
## Interaction contract
|
|
58
58
|
|
|
59
|
-
- Arrow Left/Right moves
|
|
60
|
-
- Arrow Up/Down moves
|
|
61
|
-
- Home and End move to the first and last available tile.
|
|
59
|
+
- Arrow Left/Right moves within the current row and stops at its edge.
|
|
60
|
+
- Arrow Up/Down moves within the current column and stops at its edge.
|
|
61
|
+
- Home and End move to the first and last available tile in the current row.
|
|
62
|
+
- Control/Command + Home and End move to the first and last available tile in
|
|
63
|
+
the entire grid.
|
|
62
64
|
- Space changes selection.
|
|
63
65
|
- Enter changes selection and invokes `onAction`.
|
|
64
66
|
- A single pointer click changes selection. A double click invokes `onAction`.
|
|
65
67
|
- Disabled tiles are skipped.
|
|
66
68
|
- Buttons and links inside a tile preserve their own pointer behavior.
|
|
69
|
+
- When the grid first mounts, the first selected, enabled tile receives the
|
|
70
|
+
roving tab stop. If nothing is selected, the first enabled tile receives it.
|
|
67
71
|
|
|
68
72
|
## API summary
|
|
69
73
|
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
ListItemTitle,
|
|
18
18
|
} from '@moldable-ai/ui'
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
;<List
|
|
21
21
|
aria-label="Documents"
|
|
22
22
|
selectionMode="single"
|
|
23
23
|
defaultSelectedValues={['brief']}
|
|
@@ -38,6 +38,28 @@ import {
|
|
|
38
38
|
</List>
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Sections
|
|
42
|
+
|
|
43
|
+
Group related options with `ListSection` and give every section an accessible
|
|
44
|
+
name. `ListSectionHeader` automatically labels its containing section:
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
<List aria-label="Documents" selectionMode="single">
|
|
48
|
+
<ListSection>
|
|
49
|
+
<ListSectionHeader>Recent</ListSectionHeader>
|
|
50
|
+
<ListItem value="brief">Project brief</ListItem>
|
|
51
|
+
<ListItem value="notes">Research notes</ListItem>
|
|
52
|
+
</ListSection>
|
|
53
|
+
<ListSection aria-label="Archived documents">
|
|
54
|
+
<ListItem value="archive">Archive</ListItem>
|
|
55
|
+
</ListSection>
|
|
56
|
+
</List>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use either `ListSectionHeader`, `aria-label`, or an explicit
|
|
60
|
+
`aria-labelledby` value for each section. Keyboard movement follows the
|
|
61
|
+
rendered DOM order across section boundaries.
|
|
62
|
+
|
|
41
63
|
For controlled selection, pass an iterable to `selectedValues` and replace it when `onSelectionChange` fires:
|
|
42
64
|
|
|
43
65
|
```tsx
|
|
@@ -63,8 +85,9 @@ const [selected, setSelected] = useState<ReadonlySet<string>>(
|
|
|
63
85
|
- Enter changes selection and invokes `onAction`.
|
|
64
86
|
- A single pointer click changes selection. A double click invokes `onAction`.
|
|
65
87
|
- Disabled items are skipped during keyboard navigation and cannot be selected or activated.
|
|
66
|
-
- Interactive descendants such as buttons and links keep their own
|
|
88
|
+
- Interactive descendants such as buttons and links keep their own pointer behavior. They do not select or activate the containing item.
|
|
67
89
|
- Focus uses a roving `tabIndex`, so the collection contributes one stop to the tab order.
|
|
90
|
+
- When the list first mounts, the first selected, enabled item receives the roving tab stop. If nothing is selected, the first enabled item receives it.
|
|
68
91
|
|
|
69
92
|
## API summary
|
|
70
93
|
|
|
@@ -86,9 +109,16 @@ const [selected, setSelected] = useState<ReadonlySet<string>>(
|
|
|
86
109
|
|
|
87
110
|
`ListItemContent`, `ListItemTitle`, `ListItemDescription`, and `ListItemActions` provide compact row layout without changing semantics.
|
|
88
111
|
|
|
112
|
+
### `ListSection`
|
|
113
|
+
|
|
114
|
+
- Groups related items with `role="group"`.
|
|
115
|
+
- Use `ListSectionHeader` for an automatically connected visible label.
|
|
116
|
+
- Alternatively, provide `aria-label` or `aria-labelledby`.
|
|
117
|
+
|
|
89
118
|
## Do
|
|
90
119
|
|
|
91
120
|
- Give every collection a visible label or `aria-label`.
|
|
121
|
+
- Give every section an accessible label.
|
|
92
122
|
- Keep values stable when filtering or reordering.
|
|
93
123
|
- Put the primary row identity in `ListItemTitle` and secondary metadata in `ListItemDescription`.
|
|
94
124
|
- Use selection to represent durable collection state and action to open or execute.
|
|
@@ -98,6 +128,9 @@ const [selected, setSelected] = useState<ReadonlySet<string>>(
|
|
|
98
128
|
|
|
99
129
|
- Do not put a `List` inside another list item.
|
|
100
130
|
- Do not use array indexes as values when rows can reorder.
|
|
131
|
+
- Do not put buttons, links, or other interactive controls inside selectable
|
|
132
|
+
listbox items. Put independent actions outside the listbox or use a pattern
|
|
133
|
+
whose child-interaction model supports them.
|
|
101
134
|
- Do not rely on double click as the only way to perform an important action.
|
|
102
135
|
- Do not add a second manual arrow-key handler to the same collection.
|
|
103
136
|
- Do not visually mark focus and selection as if they were the same state.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Material
|
|
2
|
+
|
|
3
|
+
Adaptive material for navigation and control chrome.
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
<Material asChild variant="regular" elevation="none">
|
|
7
|
+
<Toolbar>{/* context and actions */}</Toolbar>
|
|
8
|
+
</Material>
|
|
9
|
+
|
|
10
|
+
<MaterialGroup variant="regular" shape="capsule" spacing="compact">
|
|
11
|
+
<IconButton label="Previous" variant="ghost">
|
|
12
|
+
<ChevronLeft />
|
|
13
|
+
</IconButton>
|
|
14
|
+
<IconButton label="Next" variant="ghost">
|
|
15
|
+
<ChevronRight />
|
|
16
|
+
</IconButton>
|
|
17
|
+
</MaterialGroup>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Variants
|
|
21
|
+
|
|
22
|
+
- `regular` provides a frosted, legible control or navigation layer.
|
|
23
|
+
- `clear` is less frosted and is only for compact controls floating over
|
|
24
|
+
photos, maps, video, or another richly colored canvas.
|
|
25
|
+
|
|
26
|
+
Both variants start with an opaque fallback. Backdrop sampling is enabled only
|
|
27
|
+
when the renderer supports it. Reduced transparency and forced colors keep the
|
|
28
|
+
fallback opaque.
|
|
29
|
+
|
|
30
|
+
## Grouping
|
|
31
|
+
|
|
32
|
+
`MaterialGroup` creates one sampled layer for a related cluster. Put ordinary
|
|
33
|
+
ghost or transparent controls inside it. Do not wrap each child in another
|
|
34
|
+
`Material`; nested sampling creates muddy, inconsistent results.
|
|
35
|
+
|
|
36
|
+
Use separate `Material` instances only when controls are spatially detached and
|
|
37
|
+
do not read as one group.
|
|
38
|
+
|
|
39
|
+
## Rules
|
|
40
|
+
|
|
41
|
+
- Use material for toolbars, compact floating controls, menus, and other
|
|
42
|
+
temporary control layers.
|
|
43
|
+
- Keep documents, calendars, tables, forms, cards, sheets, and primary content
|
|
44
|
+
canvases opaque.
|
|
45
|
+
- Prefer `regular`. A `clear` surface needs stable contrast across every part
|
|
46
|
+
of the media behind it.
|
|
47
|
+
- Use `interactive` only when the material surface itself is the control.
|
|
48
|
+
- Do not animate blur or saturation. Shared motion tokens provide restrained
|
|
49
|
+
press feedback and remove it when reduced motion is requested.
|
|
50
|
+
- CSS material samples content inside the renderer. Native behind-window
|
|
51
|
+
material remains owned by the host.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# NavigationButtonGroup
|
|
2
|
+
|
|
3
|
+
`NavigationButtonGroup` presents paired back and forward actions with one
|
|
4
|
+
consistent compact treatment.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
<NavigationButtonGroup
|
|
8
|
+
canGoBack={historyIndex > 0}
|
|
9
|
+
canGoForward={historyIndex < history.length - 1}
|
|
10
|
+
onBack={goBack}
|
|
11
|
+
onForward={goForward}
|
|
12
|
+
/>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
- `canGoBack` and `canGoForward` disable unavailable directions.
|
|
18
|
+
- `onBack` and `onForward` perform caller-owned navigation.
|
|
19
|
+
- `backLabel` and `forwardLabel` customize accessible names.
|
|
20
|
+
- `size` accepts the `IconButton` size scale.
|
|
21
|
+
- `variant` is `ghost` or `outline`.
|
|
22
|
+
- Native `ButtonGroup` props apply to the group.
|
|
23
|
+
|
|
24
|
+
## Keyboard and accessibility
|
|
25
|
+
|
|
26
|
+
The root has `role="group"` and the default accessible name “Navigation”.
|
|
27
|
+
Each icon button has a stable accessible name and participates in normal Tab
|
|
28
|
+
order. The component does not install global keyboard shortcuts.
|
|
29
|
+
|
|
30
|
+
## Platform behavior
|
|
31
|
+
|
|
32
|
+
This component is portable. It does not own browser history, Moldable
|
|
33
|
+
navigation state, or native window history. Connect it to the navigation owner
|
|
34
|
+
for the current surface.
|
|
35
|
+
|
|
36
|
+
## Do
|
|
37
|
+
|
|
38
|
+
- Put it in a leading toolbar group.
|
|
39
|
+
- Disable unavailable directions.
|
|
40
|
+
- Keep back and forward behavior scoped to the visible pane or app.
|
|
41
|
+
|
|
42
|
+
## Don't
|
|
43
|
+
|
|
44
|
+
- Do not render a fake forward action when no forward history exists.
|
|
45
|
+
- Do not use it for undo and redo.
|
|
46
|
+
- Do not add a second tooltip around its buttons.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Popover
|
|
2
|
+
|
|
3
|
+
Use `Popover` for a small, interactive surface anchored to a control. Use
|
|
4
|
+
`Tooltip` for terse non-interactive help, `HoverCard` for a preview, and
|
|
5
|
+
`Dialog` for a blocking task.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Popover>
|
|
9
|
+
<PopoverTrigger asChild>
|
|
10
|
+
<Button variant="outline">View options</Button>
|
|
11
|
+
</PopoverTrigger>
|
|
12
|
+
<PopoverContent size="sm" material="regular">
|
|
13
|
+
<PopoverHeader>
|
|
14
|
+
<PopoverTitle>View options</PopoverTitle>
|
|
15
|
+
<PopoverDescription>Choose what appears in the list.</PopoverDescription>
|
|
16
|
+
</PopoverHeader>
|
|
17
|
+
{/* interactive controls */}
|
|
18
|
+
</PopoverContent>
|
|
19
|
+
</Popover>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Sizes are `content`, `sm`, `default`, and `lg`. Content is capped to the
|
|
23
|
+
collision-aware available width and height and scrolls when necessary.
|
|
24
|
+
`material="regular"` is the standard temporary overlay. Use `clear` only above
|
|
25
|
+
media or a richly colored canvas where the stronger sampled effect has a clear
|
|
26
|
+
layering purpose.
|
|
27
|
+
|
|
28
|
+
`PopoverClose`, `PopoverPortal`, and `PopoverArrow` are available when the
|
|
29
|
+
composition needs them. Provide an accessible name on an icon-only close
|
|
30
|
+
action. Keep required instructions and critical actions discoverable without
|
|
31
|
+
hover.
|
|
@@ -11,10 +11,8 @@ For simple content, a native `overflow-y-auto` region is often sufficient. The i
|
|
|
11
11
|
```tsx
|
|
12
12
|
import { ScrollArea } from '@moldable-ai/ui'
|
|
13
13
|
|
|
14
|
-
;<ScrollArea className="h-full min-h-0">
|
|
15
|
-
<div className="px-3
|
|
16
|
-
{/* Long list */}
|
|
17
|
-
</div>
|
|
14
|
+
;<ScrollArea className="h-full min-h-0" safeBottom>
|
|
15
|
+
<div className="px-3 pt-3">{/* Long list */}</div>
|
|
18
16
|
</ScrollArea>
|
|
19
17
|
```
|
|
20
18
|
|
|
@@ -28,12 +26,17 @@ For a grouped list:
|
|
|
28
26
|
</ScrollArea>
|
|
29
27
|
```
|
|
30
28
|
|
|
31
|
-
The current `ScrollArea` composition installs a vertical scrollbar
|
|
29
|
+
The current `ScrollArea` composition installs a vertical scrollbar by default.
|
|
30
|
+
Set `scrollbars` to `horizontal`, `both`, or `none` for another explicit
|
|
31
|
+
configuration.
|
|
32
32
|
|
|
33
33
|
## API summary
|
|
34
34
|
|
|
35
35
|
- `ScrollArea`: Radix Scroll Area root with a full-size viewport, vertical `ScrollBar`, and corner.
|
|
36
36
|
- Accepts Radix root props, forwarded `ref`, and `className`.
|
|
37
|
+
- `scrollbars`: `vertical`, `horizontal`, `both`, or `none`.
|
|
38
|
+
- `viewportClassName`: styles the actual scrolling viewport.
|
|
39
|
+
- `safeBottom`: adds the shared chat-safe padding to the viewport exactly once.
|
|
37
40
|
- `ScrollBar`: exported scrollbar primitive with `orientation="vertical" | "horizontal"`; defaults to vertical.
|
|
38
41
|
- The root’s direct children are rendered inside the viewport.
|
|
39
42
|
- The viewport supplies focus-visible outline and ring treatment.
|
|
@@ -43,7 +46,7 @@ The current `ScrollArea` composition installs a vertical scrollbar automatically
|
|
|
43
46
|
- Give the scroll area a definite height through its own class and full-height ancestors.
|
|
44
47
|
- Put padding on an inner content wrapper when it should scroll with the content.
|
|
45
48
|
- Add `min-h-0` to flex or grid ancestors.
|
|
46
|
-
-
|
|
49
|
+
- Enable `safeBottom` on every owning scroll region that reaches the webview bottom.
|
|
47
50
|
- Keep sticky headers inside the same scrolling context as their content.
|
|
48
51
|
- Test keyboard, wheel, trackpad, and scrollbar-thumb interaction.
|
|
49
52
|
|
|
@@ -54,7 +57,8 @@ The current `ScrollArea` composition installs a vertical scrollbar automatically
|
|
|
54
57
|
- Do not put fixed controls inside the moving content when they must remain reachable.
|
|
55
58
|
- Do not hide focus outlines.
|
|
56
59
|
- Do not assume padding on a sibling pane protects this viewport from desktop chat.
|
|
57
|
-
- Do not
|
|
60
|
+
- Do not add `ScrollBar` as a child of `ScrollArea`; children belong to its
|
|
61
|
+
viewport. Use the `scrollbars` prop.
|
|
58
62
|
|
|
59
63
|
## Moldable considerations
|
|
60
64
|
|
|
@@ -9,12 +9,9 @@ Use it for choices such as list/grid, week/month, or preview/edit. Use `Tabs` wh
|
|
|
9
9
|
## Usage
|
|
10
10
|
|
|
11
11
|
```tsx
|
|
12
|
-
import {
|
|
13
|
-
SegmentedControl,
|
|
14
|
-
SegmentedControlItem,
|
|
15
|
-
} from '@moldable-ai/ui'
|
|
12
|
+
import { SegmentedControl, SegmentedControlItem } from '@moldable-ai/ui'
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
;<SegmentedControl
|
|
18
15
|
aria-label="Calendar view"
|
|
19
16
|
value={view}
|
|
20
17
|
onValueChange={setView}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Sheet
|
|
2
|
+
|
|
3
|
+
`Sheet` presents a secondary region from an edge while preserving the current
|
|
4
|
+
workspace. It is appropriate for narrow-window navigation, filters, or an
|
|
5
|
+
inspector that cannot remain beside the canvas.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Sheet>
|
|
9
|
+
<SheetTrigger asChild>
|
|
10
|
+
<Button variant="outline">Filters</Button>
|
|
11
|
+
</SheetTrigger>
|
|
12
|
+
<SheetContent side="right" size="default">
|
|
13
|
+
<SheetHeader>
|
|
14
|
+
<SheetTitle>Filters</SheetTitle>
|
|
15
|
+
<SheetDescription>Limit the visible results.</SheetDescription>
|
|
16
|
+
</SheetHeader>
|
|
17
|
+
<SheetBody>{/* scrolling controls */}</SheetBody>
|
|
18
|
+
<SheetFooter>{/* persistent actions */}</SheetFooter>
|
|
19
|
+
</SheetContent>
|
|
20
|
+
</Sheet>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Side sheets support `sm`, `default`, and `lg`. All sides respect host window
|
|
24
|
+
insets; their bottom edge also clears the embedded chat safe area. `SheetBody`
|
|
25
|
+
is the only flexing scroll owner, leaving its header, close action, and footer
|
|
26
|
+
reachable.
|
|
27
|
+
|
|
28
|
+
Use `Dialog` when the task is centered and blocking, `Drawer` for touch-first
|
|
29
|
+
presentation, and `Inspector` when contextual properties should remain visible
|
|
30
|
+
beside the canvas. Do not use a sheet as permanent desktop navigation.
|
|
@@ -29,7 +29,9 @@ Use `compact` for inspector-like datasets, `default` for general work, and
|
|
|
29
29
|
`comfortable` where scanning matters more than density.
|
|
30
30
|
|
|
31
31
|
When a row is selectable, selection is controlled by the caller and can be
|
|
32
|
-
toggled with pointer, Enter, or Space.
|
|
33
|
-
and
|
|
32
|
+
toggled with pointer, Enter, or Space. Independent buttons, links, form
|
|
33
|
+
controls, and editable descendants keep their own pointer and keyboard
|
|
34
|
+
behavior without toggling the containing row. Call `event.preventDefault()` in
|
|
35
|
+
a row event handler only when an app needs to cancel the built-in row response.
|
|
34
36
|
For rich grid navigation, column sorting, or cell editing, use a dedicated data
|
|
35
37
|
grid rather than layering those interactions onto a basic table.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# ToggleButton
|
|
2
|
+
|
|
3
|
+
`ToggleButton` is a single pressed/unpressed action. It is a semantic facade
|
|
4
|
+
over `Toggle`, so both share one Radix interaction model and one style source.
|
|
5
|
+
|
|
6
|
+
```tsx
|
|
7
|
+
<ToggleButton pressed={showGrid} onPressedChange={setShowGrid}>
|
|
8
|
+
Show grid
|
|
9
|
+
</ToggleButton>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
For an icon-only toggle, opt in explicitly and provide its accessible name:
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
<ToggleButton
|
|
16
|
+
iconOnly
|
|
17
|
+
aria-label="Pin inspector"
|
|
18
|
+
pressed={pinned}
|
|
19
|
+
onPressedChange={setPinned}
|
|
20
|
+
>
|
|
21
|
+
<PinIcon />
|
|
22
|
+
</ToggleButton>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Variants and sizes
|
|
26
|
+
|
|
27
|
+
- `variant`: `default`, `outline`, or `filled`.
|
|
28
|
+
- `size`: `xs`, `sm`, `default`, or `lg`.
|
|
29
|
+
- `iconOnly` makes the control square and requires `aria-label`.
|
|
30
|
+
|
|
31
|
+
## Choosing the right control
|
|
32
|
+
|
|
33
|
+
- Use `Button` for a momentary action.
|
|
34
|
+
- Use `ToggleButton` for one independent visible mode or tool.
|
|
35
|
+
- Use `SegmentedControl` for exactly one choice from a small set.
|
|
36
|
+
- Use `Switch` for a persistent setting that takes effect immediately.
|
|
37
|
+
|
|
38
|
+
## Keyboard and accessibility
|
|
39
|
+
|
|
40
|
+
Radix supplies button and `aria-pressed` semantics. Space and Enter toggle the
|
|
41
|
+
state. A visible text label or `aria-label` must identify the action; state
|
|
42
|
+
must not be communicated through color alone.
|
|
43
|
+
|
|
44
|
+
## Don't
|
|
45
|
+
|
|
46
|
+
- Do not use a toggle for a one-time command.
|
|
47
|
+
- Do not group unrelated toggles into a segmented control.
|
|
48
|
+
- Do not put a checkbox inside a toggle button.
|