@moldable-ai/ui 0.2.29 → 0.2.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/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.d.ts.map +1 -1
- package/dist/components/ui/context-menu.js +7 -6
- 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 +9 -8
- 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/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 +4 -2
- 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 +10 -4
- package/dist/components/ui/sidebar.d.ts.map +1 -1
- package/dist/components/ui/sidebar.js +74 -17
- 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 +13 -3
- package/dist/components/ui/toolbar-controls.d.ts.map +1 -1
- package/dist/components/ui/toolbar-controls.js +35 -10
- 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 +21 -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/dropdown-menu.md +16 -14
- 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 +62 -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 +89 -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 +29 -6
- 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 +24 -12
- package/src/components/ui/toolbar.md +6 -6
- package/src/styles/index.css +298 -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 +165 -0
- package/src/tokens/moldable/index.css +1 -0
- package/src/tokens/platform-contract.test.ts +294 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Form
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
The form adapter connects React Hook Form state to labels, controls,
|
|
6
|
+
descriptions, and validation messages. `Form` is `FormProvider`; the native
|
|
7
|
+
`form` element remains part of the composition.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { useForm } from 'react-hook-form'
|
|
13
|
+
import {
|
|
14
|
+
Button,
|
|
15
|
+
Form,
|
|
16
|
+
FormControl,
|
|
17
|
+
FormDescription,
|
|
18
|
+
FormField,
|
|
19
|
+
FormItem,
|
|
20
|
+
FormLabel,
|
|
21
|
+
FormMessage,
|
|
22
|
+
Input,
|
|
23
|
+
} from '@moldable-ai/ui'
|
|
24
|
+
|
|
25
|
+
type Values = { project: string }
|
|
26
|
+
|
|
27
|
+
function ProjectForm() {
|
|
28
|
+
const form = useForm<Values>({ defaultValues: { project: '' } })
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<Form {...form}>
|
|
32
|
+
<form onSubmit={form.handleSubmit(saveProject)}>
|
|
33
|
+
<FormField
|
|
34
|
+
control={form.control}
|
|
35
|
+
name="project"
|
|
36
|
+
rules={{ required: 'Enter a project name.' }}
|
|
37
|
+
render={({ field }) => (
|
|
38
|
+
<FormItem>
|
|
39
|
+
<FormLabel>Project name</FormLabel>
|
|
40
|
+
<FormControl>
|
|
41
|
+
<Input {...field} />
|
|
42
|
+
</FormControl>
|
|
43
|
+
<FormDescription>Shown in the app titlebar.</FormDescription>
|
|
44
|
+
<FormMessage />
|
|
45
|
+
</FormItem>
|
|
46
|
+
)}
|
|
47
|
+
/>
|
|
48
|
+
<Button type="submit">Save</Button>
|
|
49
|
+
</form>
|
|
50
|
+
</Form>
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`FormField` forwards React Hook Form `Controller` props. Within its
|
|
56
|
+
`FormItem`, `FormLabel` targets the slotted `FormControl`; the control receives
|
|
57
|
+
`id`, `aria-invalid`, and description/message references. `FormMessage` shows
|
|
58
|
+
the current field error message, falls back to its children, and renders
|
|
59
|
+
nothing when both are absent. `useFormField` exposes the generated IDs and
|
|
60
|
+
field state to custom parts.
|
|
61
|
+
|
|
62
|
+
## Quality bar
|
|
63
|
+
|
|
64
|
+
- Put `FormControl`, `FormLabel`, `FormDescription`, and `FormMessage` inside
|
|
65
|
+
the same `FormField` and `FormItem`.
|
|
66
|
+
- Give `FormControl` one interactive child that can accept the injected
|
|
67
|
+
accessibility props.
|
|
68
|
+
- Keep validation messages specific and place them beside the affected field.
|
|
69
|
+
- Use a native `form` with `onSubmit`; `Form` alone does not submit anything.
|
|
70
|
+
- Prefer the simpler `Field` primitives when React Hook Form state is not
|
|
71
|
+
needed.
|
|
@@ -61,9 +61,10 @@ Prefer changing this value at deliberate window breakpoints. A smaller window sh
|
|
|
61
61
|
- Home and End move to the first and last available tile in the current row.
|
|
62
62
|
- Control/Command + Home and End move to the first and last available tile in
|
|
63
63
|
the entire grid.
|
|
64
|
-
- Space changes selection.
|
|
65
|
-
- Enter changes selection and invokes `onAction`.
|
|
66
|
-
- A single pointer click changes selection. A double
|
|
64
|
+
- Space changes selection when selection is enabled.
|
|
65
|
+
- Enter changes selection when enabled and invokes `onAction`.
|
|
66
|
+
- A single pointer click changes selection when selection is enabled. A double
|
|
67
|
+
click invokes `onAction`.
|
|
67
68
|
- Disabled tiles are skipped.
|
|
68
69
|
- Buttons and links inside a tile preserve their own pointer behavior.
|
|
69
70
|
- When the grid first mounts, the first selected, enabled tile receives the
|
|
@@ -22,7 +22,10 @@ import { IconButton } from '@moldable-ai/ui'
|
|
|
22
22
|
</IconButton>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
`size` is `xs`, `sm`, `default`, or `
|
|
25
|
+
`size` is `xs`, `sm`, `default`, `lg`, or `xl`. `shape` is `rounded` or
|
|
26
|
+
`circle`. `loading` disables the control, exposes `aria-busy`, and replaces the
|
|
27
|
+
icon with a progress indicator. `tooltip` may be `true` to reuse the label as
|
|
28
|
+
a native hint or a specific string.
|
|
26
29
|
|
|
27
30
|
## Quality bar
|
|
28
31
|
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Input Group
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`InputGroup` combines one text control with inline or stacked context and
|
|
6
|
+
actions inside a single bordered surface.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import {
|
|
12
|
+
InputGroup,
|
|
13
|
+
InputGroupAddon,
|
|
14
|
+
InputGroupButton,
|
|
15
|
+
InputGroupInput,
|
|
16
|
+
InputGroupText,
|
|
17
|
+
} from '@moldable-ai/ui'
|
|
18
|
+
|
|
19
|
+
;<InputGroup>
|
|
20
|
+
<InputGroupAddon>
|
|
21
|
+
<InputGroupText>https://</InputGroupText>
|
|
22
|
+
</InputGroupAddon>
|
|
23
|
+
<InputGroupInput aria-label="Workspace address" />
|
|
24
|
+
<InputGroupAddon align="inline-end">
|
|
25
|
+
<InputGroupButton aria-label="Copy address">Copy</InputGroupButton>
|
|
26
|
+
</InputGroupAddon>
|
|
27
|
+
</InputGroup>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `InputGroupInput` for a native input or `InputGroupTextarea` for multiline
|
|
31
|
+
text. `InputGroupAddon` defaults to `inline-start` and also supports
|
|
32
|
+
`inline-end`, `block-start`, and `block-end`. Clicking a non-button inline
|
|
33
|
+
addon focuses the contained input. `InputGroupButton` defaults to
|
|
34
|
+
`type="button"`, `variant="ghost"`, and `size="xs"`; its sizes are `xs`, `sm`,
|
|
35
|
+
`icon-xs`, and `icon-sm`.
|
|
36
|
+
|
|
37
|
+
## Quality bar
|
|
38
|
+
|
|
39
|
+
- Label the actual input or textarea; the group and its adornments do not
|
|
40
|
+
provide its accessible name.
|
|
41
|
+
- Mark decorative icons `aria-hidden` and give icon-only buttons an
|
|
42
|
+
`aria-label`.
|
|
43
|
+
- Put interactive controls in `InputGroupButton`, not in a clickable addon.
|
|
44
|
+
- Set `aria-invalid` on the input or textarea so the group shows its error
|
|
45
|
+
state.
|
|
46
|
+
- When disabling the control, add `data-disabled="true"` to `InputGroup` if
|
|
47
|
+
its addons should also appear disabled.
|
|
48
|
+
- Keep addons short. Use `block-start` or `block-end` for context that cannot
|
|
49
|
+
fit inline.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Input OTP
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`InputOTP` presents a one-time code as visual slots while retaining one
|
|
6
|
+
keyboard- and paste-friendly input through the `input-otp` primitive.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import {
|
|
12
|
+
InputOTP,
|
|
13
|
+
InputOTPGroup,
|
|
14
|
+
InputOTPSeparator,
|
|
15
|
+
InputOTPSlot,
|
|
16
|
+
} from '@moldable-ai/ui'
|
|
17
|
+
|
|
18
|
+
;<InputOTP
|
|
19
|
+
aria-label="Verification code"
|
|
20
|
+
maxLength={6}
|
|
21
|
+
value={code}
|
|
22
|
+
onChange={setCode}
|
|
23
|
+
>
|
|
24
|
+
<InputOTPGroup>
|
|
25
|
+
{[0, 1, 2].map((index) => (
|
|
26
|
+
<InputOTPSlot key={index} index={index} />
|
|
27
|
+
))}
|
|
28
|
+
</InputOTPGroup>
|
|
29
|
+
<InputOTPSeparator />
|
|
30
|
+
<InputOTPGroup>
|
|
31
|
+
{[3, 4, 5].map((index) => (
|
|
32
|
+
<InputOTPSlot key={index} index={index} />
|
|
33
|
+
))}
|
|
34
|
+
</InputOTPGroup>
|
|
35
|
+
</InputOTP>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`maxLength` defines the code length and the rendered slot indexes must match
|
|
39
|
+
it. Native input props and `input-otp` options such as `pattern`,
|
|
40
|
+
`pasteTransformer`, `onComplete`, and `pushPasswordManagerStrategy` pass
|
|
41
|
+
through. `containerClassName` styles the visible slot container; `className`
|
|
42
|
+
targets the underlying input. `InputOTPSeparator` renders a separator role
|
|
43
|
+
with the shared minus icon.
|
|
44
|
+
|
|
45
|
+
## Quality bar
|
|
46
|
+
|
|
47
|
+
- Give the root a visible label or an accessible name.
|
|
48
|
+
- Match every `InputOTPSlot` index to a valid position below `maxLength`.
|
|
49
|
+
- Use `pattern` when the code format is restricted; do not reject valid pasted
|
|
50
|
+
codes silently.
|
|
51
|
+
- Let users paste and use password managers or system code autofill; add an
|
|
52
|
+
appropriate `autoComplete` value for the workflow.
|
|
53
|
+
- Report expiration, resend status, and server errors outside the slots in
|
|
54
|
+
text, not by color alone.
|
|
55
|
+
- Do not submit solely because the last character was entered unless the
|
|
56
|
+
result is safe, reversible, and clearly communicated.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`Input` is the shared styled native input. It preserves native input types,
|
|
6
|
+
editing behavior, constraints, and form participation while applying semantic
|
|
7
|
+
control tokens.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Input, Label } from '@moldable-ai/ui'
|
|
13
|
+
|
|
14
|
+
;<div className="grid gap-2">
|
|
15
|
+
<Label htmlFor="workspace-name">Workspace name</Label>
|
|
16
|
+
<Input
|
|
17
|
+
id="workspace-name"
|
|
18
|
+
name="workspaceName"
|
|
19
|
+
autoComplete="organization"
|
|
20
|
+
required
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
All native input props pass through. `controlSize` accepts `mini`, `small`,
|
|
26
|
+
`medium`, `large`, or `xl`; when omitted, the input inherits the active theme
|
|
27
|
+
size. File inputs receive matching typography and file-button treatment.
|
|
28
|
+
|
|
29
|
+
## Quality bar
|
|
30
|
+
|
|
31
|
+
- Associate every input with a visible label or an accessible name.
|
|
32
|
+
- Choose the correct native `type`, `name`, `autoComplete`, `inputMode`, and
|
|
33
|
+
constraints for the data.
|
|
34
|
+
- Set `aria-invalid` when invalid and connect supporting or error text with
|
|
35
|
+
`aria-describedby`.
|
|
36
|
+
- Use `disabled` only for unavailable controls; use `readOnly` for values that
|
|
37
|
+
should remain selectable.
|
|
38
|
+
- Keep placeholder text as a short hint, never as the only label.
|
|
39
|
+
- Use `Textarea`, `SearchField`, `DateField`, or `InputGroup` when their
|
|
40
|
+
behavior matches the task more closely.
|
|
@@ -1,11 +1,51 @@
|
|
|
1
1
|
# Inspector
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Purpose
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
The inspector primitives compose a secondary property pane for the current
|
|
6
|
+
selection. The root is an `aside`; its header stays fixed while
|
|
7
|
+
`InspectorContent` scrolls and includes bottom chat clearance.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
Input,
|
|
14
|
+
Inspector,
|
|
15
|
+
InspectorContent,
|
|
16
|
+
InspectorHeader,
|
|
17
|
+
InspectorLabel,
|
|
18
|
+
InspectorRow,
|
|
19
|
+
InspectorSection,
|
|
20
|
+
InspectorValue,
|
|
21
|
+
} from '@moldable-ai/ui'
|
|
22
|
+
|
|
23
|
+
;<Inspector>
|
|
24
|
+
<InspectorHeader>Inspector</InspectorHeader>
|
|
25
|
+
<InspectorContent>
|
|
26
|
+
<InspectorSection title="Appearance">
|
|
27
|
+
<InspectorRow>
|
|
28
|
+
<InspectorLabel htmlFor="document-title">Title</InspectorLabel>
|
|
29
|
+
<InspectorValue>
|
|
30
|
+
<Input id="document-title" controlSize="small" />
|
|
31
|
+
</InspectorValue>
|
|
32
|
+
</InspectorRow>
|
|
33
|
+
</InspectorSection>
|
|
34
|
+
</InspectorContent>
|
|
35
|
+
</Inspector>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`InspectorSection` accepts optional `title` and `actions`; it omits its header
|
|
39
|
+
when neither is present. `InspectorRow` aligns a label and value in two
|
|
40
|
+
columns. `InspectorLabel` renders a compact native label, and
|
|
41
|
+
`InspectorValue` contains the control or read-only value.
|
|
42
|
+
|
|
43
|
+
## Quality bar
|
|
44
|
+
|
|
45
|
+
- Keep the inspector subordinate to the primary pane and collapse it when
|
|
46
|
+
width is constrained.
|
|
47
|
+
- Group related properties into short sections and use section actions only
|
|
48
|
+
for local operations.
|
|
49
|
+
- Connect each `InspectorLabel` to its control with `htmlFor` and `id`.
|
|
50
|
+
- Use compact control sizes and keep unpredictable values truncatable.
|
|
51
|
+
- Keep primary workflow actions out of the inspector.
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from '@moldable-ai/ui'
|
|
24
24
|
|
|
25
25
|
;<ItemGroup>
|
|
26
|
-
<Item size="sm">
|
|
26
|
+
<Item role="listitem" size="sm">
|
|
27
27
|
<ItemMedia variant="icon">
|
|
28
28
|
<FileText />
|
|
29
29
|
</ItemMedia>
|
|
@@ -53,8 +53,10 @@ Use `asChild` when the whole item is a link or another interactive primitive. Av
|
|
|
53
53
|
|
|
54
54
|
## API summary
|
|
55
55
|
|
|
56
|
-
- `ItemGroup`: `role="list"` container.
|
|
57
|
-
|
|
56
|
+
- `ItemGroup`: `role="list"` container. Give each direct `Item`
|
|
57
|
+
`role="listitem"`.
|
|
58
|
+
- `Item`: `variant="default"`, `"outline"`, or `"muted"`;
|
|
59
|
+
`size="default"` or `"sm"`; optional `asChild`.
|
|
58
60
|
- `ItemMedia`: `variant="default"`, `"icon"`, or `"image"`.
|
|
59
61
|
- `ItemContent`: flexible title/description column.
|
|
60
62
|
- `ItemTitle`, `ItemDescription`: primary and secondary text.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Kbd
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`Kbd` displays a keyboard key or shortcut hint. `KbdGroup` lays out several
|
|
6
|
+
keys as one shortcut. These components are visual labels only; they do not
|
|
7
|
+
register keyboard handlers.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { Kbd, KbdGroup } from '@moldable-ai/ui'
|
|
13
|
+
|
|
14
|
+
;<KbdGroup aria-label="Command K">
|
|
15
|
+
<Kbd>⌘</Kbd>
|
|
16
|
+
<Kbd>K</Kbd>
|
|
17
|
+
</KbdGroup>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Both components accept native `<kbd>` props and `className`. `Kbd` applies the
|
|
21
|
+
keycap treatment and sizes unclassified SVG children; `KbdGroup` supplies only
|
|
22
|
+
an inline flex layout.
|
|
23
|
+
|
|
24
|
+
## Guidance
|
|
25
|
+
|
|
26
|
+
- Show shortcuts only when the command really supports them.
|
|
27
|
+
- Keep key names brief and use the same notation throughout the app.
|
|
28
|
+
- Add an accessible label when modifier glyphs may not be announced clearly.
|
|
29
|
+
- Keep `Kbd` non-interactive; place click behavior on a real button or link.
|
|
30
|
+
- Do not use shortcut hints as the only way to discover an action.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Label
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`Label` gives a form control a visible, clickable name. It wraps the Radix
|
|
6
|
+
label primitive and accepts its props.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
```tsx
|
|
11
|
+
import { Input, Label } from '@moldable-ai/ui'
|
|
12
|
+
|
|
13
|
+
;<div className="space-y-2">
|
|
14
|
+
<Label htmlFor="project-name">Project name</Label>
|
|
15
|
+
<Input id="project-name" name="projectName" />
|
|
16
|
+
</div>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Guidance
|
|
20
|
+
|
|
21
|
+
- Pair `htmlFor` with a unique control `id`, or nest the control when that is
|
|
22
|
+
the clearer native relationship.
|
|
23
|
+
- Use a short noun phrase and keep instructions or validation outside the
|
|
24
|
+
label.
|
|
25
|
+
- Keep a visible label for text fields; a placeholder is not a replacement.
|
|
26
|
+
- Mark optional or required state consistently and expose it to assistive
|
|
27
|
+
technology on the control.
|
|
28
|
+
- The built-in styles respond to disabled peer or group state; set the actual
|
|
29
|
+
control's `disabled` attribute as well.
|
|
@@ -81,8 +81,8 @@ const [selected, setSelected] = useState<ReadonlySet<string>>(
|
|
|
81
81
|
|
|
82
82
|
- Arrow Up/Down moves through a vertical list; Arrow Left/Right moves through a horizontal list.
|
|
83
83
|
- Home and End move to the first and last available item.
|
|
84
|
-
- Space changes selection.
|
|
85
|
-
- Enter changes selection and invokes `onAction`.
|
|
84
|
+
- Space changes selection when selection is enabled.
|
|
85
|
+
- Enter changes selection when enabled and invokes `onAction`.
|
|
86
86
|
- A single pointer click changes selection. A double click invokes `onAction`.
|
|
87
87
|
- Disabled items are skipped during keyboard navigation and cannot be selected or activated.
|
|
88
88
|
- Interactive descendants such as buttons and links keep their own pointer behavior. They do not select or activate the containing item.
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
# Material
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`Material` provides an adaptive sampled layer for navigation and control
|
|
4
|
+
chrome. `MaterialGroup` gives a related control cluster one shared layer.
|
|
4
5
|
|
|
5
6
|
```tsx
|
|
6
|
-
<Material asChild variant="
|
|
7
|
+
<Material asChild variant="medium" elevation="none">
|
|
7
8
|
<Toolbar>{/* context and actions */}</Toolbar>
|
|
8
9
|
</Material>
|
|
9
10
|
|
|
10
|
-
<MaterialGroup variant="
|
|
11
|
+
<MaterialGroup variant="thin" shape="capsule" spacing="compact">
|
|
11
12
|
<IconButton label="Previous" variant="ghost">
|
|
12
13
|
<ChevronLeft />
|
|
13
14
|
</IconButton>
|
|
@@ -19,15 +20,25 @@ Adaptive material for navigation and control chrome.
|
|
|
19
20
|
|
|
20
21
|
## Variants
|
|
21
22
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
|
|
23
|
+
- Standard thicknesses are `ultra-thick`, `thick`, `medium`, `thin`, and
|
|
24
|
+
`ultra-thin`, ordered from most filled to most transparent. They all use the
|
|
25
|
+
standard material blur; thickness controls translucency.
|
|
26
|
+
- `regular` is a compatibility alias for `medium` and remains the default.
|
|
27
|
+
- `clear` is a compatibility alias for `ultra-thin`.
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
when the renderer supports it.
|
|
28
|
-
fallback opaque.
|
|
29
|
+
Every variant starts with an opaque fallback. Backdrop sampling is enabled only
|
|
30
|
+
when the renderer supports it.
|
|
29
31
|
|
|
30
|
-
##
|
|
32
|
+
## Shape, elevation, and grouping
|
|
33
|
+
|
|
34
|
+
- `shape` is `rounded`, `capsule`, or `circle`; it defaults to `rounded`.
|
|
35
|
+
- `elevation` is `none`, `panel`, or `overlay`; it defaults to `none` and
|
|
36
|
+
controls shadow independently of thickness.
|
|
37
|
+
- `interactive` adds hover and press feedback when the material surface itself
|
|
38
|
+
is the control.
|
|
39
|
+
- `asChild` applies `Material` to its single child through a Radix slot.
|
|
40
|
+
- `MaterialGroup` supports `spacing="compact" | "default" | "comfortable"`
|
|
41
|
+
and defaults to `default`.
|
|
31
42
|
|
|
32
43
|
`MaterialGroup` creates one sampled layer for a related cluster. Put ordinary
|
|
33
44
|
ghost or transparent controls inside it. Do not wrap each child in another
|
|
@@ -42,8 +53,10 @@ do not read as one group.
|
|
|
42
53
|
temporary control layers.
|
|
43
54
|
- Keep documents, calendars, tables, forms, cards, sheets, and primary content
|
|
44
55
|
canvases opaque.
|
|
45
|
-
- Prefer
|
|
46
|
-
|
|
56
|
+
- Prefer a named standard thickness when the hierarchy is known. Use the
|
|
57
|
+
compatibility aliases only where their existing semantics are intentional.
|
|
58
|
+
- Thin and ultra-thin surfaces need stable contrast across every part of the
|
|
59
|
+
content behind them.
|
|
47
60
|
- Use `interactive` only when the material surface itself is the control.
|
|
48
61
|
- Do not animate blur or saturation. Shared motion tokens provide restrained
|
|
49
62
|
press feedback and remove it when reduced motion is requested.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Menu Items
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`menu-items.tsx` is the internal adapter shared by `DropdownMenu` and
|
|
6
|
+
`ContextMenu` when their declarative `items` API is used. It coordinates the
|
|
7
|
+
host-native request and portable fallback, formats shortcut labels, renders
|
|
8
|
+
portable row contents, and removes conflicting authored content.
|
|
9
|
+
|
|
10
|
+
App code should use `DropdownMenu` or `ContextMenu`, not import these helpers
|
|
11
|
+
directly.
|
|
12
|
+
|
|
13
|
+
## Declarative usage
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { Button, DropdownMenu, DropdownMenuTrigger } from '@moldable-ai/ui'
|
|
17
|
+
|
|
18
|
+
;<DropdownMenu
|
|
19
|
+
items={[
|
|
20
|
+
{
|
|
21
|
+
id: 'rename',
|
|
22
|
+
label: 'Rename',
|
|
23
|
+
shortcut: { key: 'r', modifiers: ['cmd'] },
|
|
24
|
+
},
|
|
25
|
+
{ id: 'divider', kind: 'separator' },
|
|
26
|
+
{ id: 'delete', label: 'Move to trash', destructive: true },
|
|
27
|
+
]}
|
|
28
|
+
onSelectItem={(id) => runCommand(id)}
|
|
29
|
+
>
|
|
30
|
+
<DropdownMenuTrigger asChild>
|
|
31
|
+
<Button
|
|
32
|
+
type="button"
|
|
33
|
+
variant="outline"
|
|
34
|
+
size="sm"
|
|
35
|
+
className="cursor-pointer"
|
|
36
|
+
>
|
|
37
|
+
Actions
|
|
38
|
+
</Button>
|
|
39
|
+
</DropdownMenuTrigger>
|
|
40
|
+
</DropdownMenu>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Internal contract
|
|
44
|
+
|
|
45
|
+
- `useDeclarativeMenuState` supports controlled or uncontrolled portable-open
|
|
46
|
+
state. While a native request is active, `nativeOpen` is true and
|
|
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.
|
|
50
|
+
- A completed native request passes `selectedId` to `onSelectItem`.
|
|
51
|
+
Cancellation does nothing. A fallback result or request failure opens the
|
|
52
|
+
portable menu unless the caller supplies its own `onFallback`.
|
|
53
|
+
- `formatMenuShortcut` renders modifiers in array order as `⌘`, `⇧`, `⌥`, and
|
|
54
|
+
`⌃`, then uppercases a one-character key. It is display metadata only.
|
|
55
|
+
- `MenuItemContents` renders an optional Lucide icon, the label, and a `Kbd`
|
|
56
|
+
shortcut. Separators are handled by the owning menu.
|
|
57
|
+
- Content detection and removal recurse through fragments. When declarative
|
|
58
|
+
items and authored content are both provided, the owning menu reports the
|
|
59
|
+
conflict in development and declarative items win.
|
|
60
|
+
|
|
61
|
+
Keep item IDs stable and labels concise. Do not execute a command from shortcut
|
|
62
|
+
metadata, and do not mix declarative items with authored menu content.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Menubar
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`Menubar` presents a persistent row of related command menus, such as File,
|
|
6
|
+
Edit, and View. Use it for command families that benefit from repeated
|
|
7
|
+
keyboard access; use `DropdownMenu` for a single contextual action menu.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import {
|
|
13
|
+
Menubar,
|
|
14
|
+
MenubarContent,
|
|
15
|
+
MenubarItem,
|
|
16
|
+
MenubarMenu,
|
|
17
|
+
MenubarShortcut,
|
|
18
|
+
MenubarTrigger,
|
|
19
|
+
} from '@moldable-ai/ui'
|
|
20
|
+
|
|
21
|
+
;<Menubar>
|
|
22
|
+
<MenubarMenu>
|
|
23
|
+
<MenubarTrigger className="cursor-pointer">File</MenubarTrigger>
|
|
24
|
+
<MenubarContent>
|
|
25
|
+
<MenubarItem onSelect={createDocument}>
|
|
26
|
+
New document
|
|
27
|
+
<MenubarShortcut>⌘N</MenubarShortcut>
|
|
28
|
+
</MenubarItem>
|
|
29
|
+
</MenubarContent>
|
|
30
|
+
</MenubarMenu>
|
|
31
|
+
</Menubar>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API summary
|
|
35
|
+
|
|
36
|
+
- `Menubar`, `MenubarMenu`, and `MenubarTrigger` form the required shell.
|
|
37
|
+
- `MenubarContent` is portalled and defaults to `align="start"`,
|
|
38
|
+
`alignOffset={-4}`, and `sideOffset={8}`.
|
|
39
|
+
- `MenubarItem` supports `inset` and
|
|
40
|
+
`variant="default" | "destructive"`.
|
|
41
|
+
- Checkbox items, radio groups/items, groups, labels, separators, shortcuts,
|
|
42
|
+
and submenus are exported for structured command sets.
|
|
43
|
+
- `MenubarLabel` and `MenubarSubTrigger` support `inset`.
|
|
44
|
+
- Components otherwise accept the corresponding Radix menubar props.
|
|
45
|
+
|
|
46
|
+
## Guidance
|
|
47
|
+
|
|
48
|
+
- Keep top-level trigger labels short and conventional.
|
|
49
|
+
- Use checkbox and radio items for menu-owned state, and `onSelect` for
|
|
50
|
+
commands.
|
|
51
|
+
- Put destructive commands last or in a separated group; do not rely on color
|
|
52
|
+
alone to communicate risk.
|
|
53
|
+
- `MenubarShortcut` is display text only and does not register a handler.
|
|
54
|
+
- Radix supplies menu roles, focus movement, typeahead, Escape dismissal, and
|
|
55
|
+
submenu navigation. Preserve those semantics and give icon-only content an
|
|
56
|
+
accessible name.
|
|
57
|
+
- Keep submenus shallow and use `Popover` or `Dialog` for arbitrary form
|
|
58
|
+
controls.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Message Scroller Primitive
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`message-scroller-primitive.tsx` is the unstyled React wiring for the
|
|
6
|
+
in-repository transcript controller and scroll-ownership policy. The public
|
|
7
|
+
`MessageScroller*` components wrap this module with layout, button, and
|
|
8
|
+
animation styles; app code should use those wrappers.
|
|
9
|
+
|
|
10
|
+
## Anatomy
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
<MessageScroller.Provider autoScroll>
|
|
14
|
+
<MessageScroller.Root>
|
|
15
|
+
<MessageScroller.Viewport>
|
|
16
|
+
<MessageScroller.Content>
|
|
17
|
+
<MessageScroller.Item messageId="turn-1" scrollAnchor>
|
|
18
|
+
{/* message */}
|
|
19
|
+
</MessageScroller.Item>
|
|
20
|
+
</MessageScroller.Content>
|
|
21
|
+
</MessageScroller.Viewport>
|
|
22
|
+
<MessageScroller.Button direction="end" />
|
|
23
|
+
</MessageScroller.Root>
|
|
24
|
+
</MessageScroller.Provider>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This local-only example uses the `MessageScroller` object exported by the
|
|
28
|
+
primitive module. `Provider` must wrap every root, item, button, and hook.
|
|
29
|
+
|
|
30
|
+
## Primitive contract
|
|
31
|
+
|
|
32
|
+
- Provider defaults: `autoScroll={false}`, `defaultScrollPosition="end"`,
|
|
33
|
+
`scrollEdgeThreshold={8}`, `scrollPreviousItemPeek={64}`, and
|
|
34
|
+
`scrollMargin={0}`. Changing `defaultScrollPosition` resets the one-time
|
|
35
|
+
initial-position decision for the next content mutation.
|
|
36
|
+
- `Viewport` forwards scroll, wheel, touch, and scroll-key events after
|
|
37
|
+
notifying the controller. It defaults to a focusable messages region and
|
|
38
|
+
observes viewport size changes.
|
|
39
|
+
- `Content` defaults to an additions-only live log, observes direct child
|
|
40
|
+
mutations and size changes, and appends a hidden internal spacer.
|
|
41
|
+
- `Item` registers `messageId` elements and writes anchor data used for
|
|
42
|
+
initial placement, new-turn anchoring, targeted scrolling, and visibility.
|
|
43
|
+
- `Button` supports `direction="start" | "end"`, `behavior`, and a `render`
|
|
44
|
+
element or render function. Defaults are end, smooth, and `type="button"`.
|
|
45
|
+
Inactive buttons are inert with `tabIndex={-1}`; preventing the click event's
|
|
46
|
+
default also prevents the scroll command.
|
|
47
|
+
|
|
48
|
+
## Controller and policy behavior
|
|
49
|
+
|
|
50
|
+
The controller is the sole owner of programmatic transcript movement. The
|
|
51
|
+
policy distinguishes following the end, free reading, an anchored turn, and a
|
|
52
|
+
settling commanded jump. Wheel, touch, scroll-key, scrollbar, or other motion
|
|
53
|
+
away from a declared target gives control to the reader immediately.
|
|
54
|
+
|
|
55
|
+
It also:
|
|
56
|
+
|
|
57
|
+
- keeps a followed end pinned during growth;
|
|
58
|
+
- reanchors a streaming turn after resize;
|
|
59
|
+
- preserves the first visible row when older items are prepended;
|
|
60
|
+
- restores a stable visible leaf when content above collapses;
|
|
61
|
+
- grows the internal spacer so late items can reach the requested alignment;
|
|
62
|
+
- exposes edge state as `data-scrollable` and active programmatic movement as
|
|
63
|
+
`data-autoscrolling` on root and viewport;
|
|
64
|
+
- observes visibility only while `useMessageScrollerVisibility` has
|
|
65
|
+
subscribers.
|
|
66
|
+
|
|
67
|
+
For finer reading-position stability inside a complex item, mark stable
|
|
68
|
+
descendants with `data-message-scroll-anchor`. Do not manipulate the
|
|
69
|
+
controller, spacer, data attributes, or scroll position from a competing
|
|
70
|
+
effect; extend the wrapper API when new behavior is required.
|