@scattered-light/loomiere-base-ui 0.1.1 → 0.3.0
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/README.md +10 -1
- package/dist/design-system/components/Accordion/README.md +97 -0
- package/dist/design-system/components/Accordion/preview.html +19 -0
- package/dist/design-system/components/AlertDialog/README.md +52 -0
- package/dist/design-system/components/AlertDialog/preview.html +19 -0
- package/dist/design-system/components/Autocomplete/README.md +68 -0
- package/dist/design-system/components/Autocomplete/preview.html +19 -0
- package/dist/design-system/components/Avatar/README.md +39 -0
- package/dist/design-system/components/Avatar/preview.html +19 -0
- package/dist/design-system/components/Button/README.md +27 -0
- package/dist/design-system/components/Button/preview.html +23 -0
- package/dist/design-system/components/Checkbox/README.md +39 -0
- package/dist/design-system/components/Checkbox/preview.html +19 -0
- package/dist/design-system/components/CheckboxGroup/README.md +56 -0
- package/dist/design-system/components/CheckboxGroup/preview.html +19 -0
- package/dist/design-system/components/Collapsible/README.md +48 -0
- package/dist/design-system/components/Collapsible/preview.html +19 -0
- package/dist/design-system/components/Combobox/README.md +105 -0
- package/dist/design-system/components/Combobox/preview.html +19 -0
- package/dist/design-system/components/ContextMenu/README.md +70 -0
- package/dist/design-system/components/ContextMenu/preview.html +19 -0
- package/dist/design-system/components/Dialog/README.md +62 -0
- package/dist/design-system/components/Dialog/preview.html +19 -0
- package/dist/design-system/components/Drawer/README.md +32 -0
- package/dist/design-system/components/Drawer/preview.html +19 -0
- package/dist/design-system/components/Field/README.md +41 -0
- package/dist/design-system/components/Field/preview.html +19 -0
- package/dist/design-system/components/Fieldset/README.md +45 -0
- package/dist/design-system/components/Fieldset/preview.html +19 -0
- package/dist/design-system/components/Form/README.md +57 -0
- package/dist/design-system/components/Form/preview.html +19 -0
- package/dist/design-system/components/IconButton/README.md +31 -0
- package/dist/design-system/components/IconButton/preview.html +19 -0
- package/dist/design-system/components/Input/README.md +38 -0
- package/dist/design-system/components/Input/preview.html +19 -0
- package/dist/design-system/components/Menu/README.md +58 -0
- package/dist/design-system/components/Menu/preview.html +19 -0
- package/dist/design-system/components/Menubar/README.md +105 -0
- package/dist/design-system/components/Menubar/preview.html +19 -0
- package/dist/design-system/components/Meter/README.md +43 -0
- package/dist/design-system/components/Meter/preview.html +19 -0
- package/dist/design-system/components/NavigationMenu/README.md +148 -0
- package/dist/design-system/components/NavigationMenu/preview.html +19 -0
- package/dist/design-system/components/NumberField/README.md +58 -0
- package/dist/design-system/components/NumberField/preview.html +19 -0
- package/dist/design-system/components/OTPField/README.md +39 -0
- package/dist/design-system/components/OTPField/preview.html +19 -0
- package/dist/design-system/components/Popover/README.md +56 -0
- package/dist/design-system/components/Popover/preview.html +19 -0
- package/dist/design-system/components/PreviewCard/README.md +74 -0
- package/dist/design-system/components/PreviewCard/preview.html +19 -0
- package/dist/design-system/components/Progress/README.md +58 -0
- package/dist/design-system/components/Progress/preview.html +19 -0
- package/dist/design-system/components/Radio/README.md +74 -0
- package/dist/design-system/components/Radio/preview.html +19 -0
- package/dist/design-system/components/ScrollArea/README.md +62 -0
- package/dist/design-system/components/ScrollArea/preview.html +40 -0
- package/dist/design-system/components/Select/README.md +84 -0
- package/dist/design-system/components/Select/preview.html +19 -0
- package/dist/design-system/components/Separator/README.md +37 -0
- package/dist/design-system/components/Separator/preview.html +19 -0
- package/dist/design-system/components/Slider/README.md +44 -0
- package/dist/design-system/components/Slider/preview.html +19 -0
- package/dist/design-system/components/Switch/README.md +34 -0
- package/dist/design-system/components/Switch/preview.html +19 -0
- package/dist/design-system/components/Tabs/README.md +56 -0
- package/dist/design-system/components/Tabs/preview.html +19 -0
- package/dist/design-system/components/Toast/README.md +78 -0
- package/dist/design-system/components/Toast/preview.html +19 -0
- package/dist/design-system/components/Toggle/README.md +32 -0
- package/dist/design-system/components/Toggle/preview.html +19 -0
- package/dist/design-system/components/ToggleGroup/README.md +40 -0
- package/dist/design-system/components/ToggleGroup/preview.html +19 -0
- package/dist/design-system/components/Toolbar/README.md +65 -0
- package/dist/design-system/components/Toolbar/preview.html +19 -0
- package/dist/design-system/components/Tooltip/README.md +46 -0
- package/dist/design-system/components/Tooltip/preview.html +19 -0
- package/dist/design-system/components/bundle.js +5 -0
- package/dist/design-system/components/index.d.ts +118 -0
- package/dist/design-system/components/styles.css +5606 -0
- package/dist/index.d.ts +13 -2
- package/dist/index.js +36 -26
- package/dist/index.js.map +1 -1
- package/dist/styles/components/Accordion.css +1 -1
- package/dist/styles/components/AlertDialog.css +1 -1
- package/dist/styles/components/Autocomplete.css +1 -1
- package/dist/styles/components/Avatar.css +1 -1
- package/dist/styles/components/Button.css +25 -5
- package/dist/styles/components/Checkbox.css +1 -1
- package/dist/styles/components/CheckboxGroup.css +1 -1
- package/dist/styles/components/Collapsible.css +1 -1
- package/dist/styles/components/Combobox.css +1 -1
- package/dist/styles/components/ContextMenu.css +1 -1
- package/dist/styles/components/Dialog.css +1 -1
- package/dist/styles/components/Drawer.css +1 -1
- package/dist/styles/components/Field.css +1 -1
- package/dist/styles/components/Fieldset.css +1 -1
- package/dist/styles/components/Form.css +1 -1
- package/dist/styles/components/IconButton.css +49 -0
- package/dist/styles/components/Input.css +1 -1
- package/dist/styles/components/Menu.css +1 -1
- package/dist/styles/components/Menubar.css +1 -1
- package/dist/styles/components/Meter.css +1 -1
- package/dist/styles/components/NavigationMenu.css +1 -1
- package/dist/styles/components/NumberField.css +1 -1
- package/dist/styles/components/OTPField.css +1 -1
- package/dist/styles/components/Popover.css +5 -2
- package/dist/styles/components/PreviewCard.css +1 -1
- package/dist/styles/components/Progress.css +1 -1
- package/dist/styles/components/Radio.css +1 -1
- package/dist/styles/components/ScrollArea.css +1 -1
- package/dist/styles/components/Select.css +1 -1
- package/dist/styles/components/Separator.css +1 -1
- package/dist/styles/components/Slider.css +1 -1
- package/dist/styles/components/Switch.css +1 -1
- package/dist/styles/components/Tabs.css +1 -1
- package/dist/styles/components/Toast.css +1 -1
- package/dist/styles/components/Toggle.css +1 -1
- package/dist/styles/components/ToggleGroup.css +1 -1
- package/dist/styles/components/Toolbar.css +1 -1
- package/dist/styles/components/Tooltip.css +1 -1
- package/dist/styles/index.css +2 -1
- package/dist/styles/reset/accessibility.css +1 -1
- package/dist/styles/reset/reset-accessibility.css +1 -1
- package/dist/styles/reset/reset-tailwind.css +441 -0
- package/dist/styles/reset/reset.css +1 -1
- package/dist/styles/tailwind.css +56 -0
- package/package.json +5 -3
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Fieldset
|
|
2
|
+
|
|
3
|
+
The Base UI Fieldset styled by the theme. No component tokens: a titled group of fields, spaced by the stack gaps, with whole text styles.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Fieldset`, this package's wrapper: it puts the class names on for you (`import { Fieldset } from '@scattered-light/loomiere-base-ui'` in an app). The bare Base UI part is `Loomiere.Base.Fieldset`.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/fieldset
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `Fieldset` | |
|
|
14
|
+
| `FieldsetLegend` | |
|
|
15
|
+
| `FieldsetDescription` | |
|
|
16
|
+
|
|
17
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
18
|
+
|
|
19
|
+
## Example
|
|
20
|
+
|
|
21
|
+
From the Fieldset stories (`Default`):
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
render: () => (
|
|
26
|
+
<div style={{ width: '400px' }}>
|
|
27
|
+
<Fieldset.Root>
|
|
28
|
+
<Fieldset.Legend>Personal Information</Fieldset.Legend>
|
|
29
|
+
|
|
30
|
+
<Field.Root name="firstName">
|
|
31
|
+
<Field.Label>First name</Field.Label>
|
|
32
|
+
<Field.Control type="text" placeholder="John" />
|
|
33
|
+
</Field.Root>
|
|
34
|
+
|
|
35
|
+
<Field.Root name="lastName">
|
|
36
|
+
<Field.Label>Last name</Field.Label>
|
|
37
|
+
<Field.Control type="text" placeholder="Doe" />
|
|
38
|
+
</Field.Root>
|
|
39
|
+
</Fieldset.Root>
|
|
40
|
+
</div>
|
|
41
|
+
),
|
|
42
|
+
};
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The preview also shows `WithDescription`, `WithValidation`, `Disabled`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Forms" height=480 subtitle="Default / WithDescription / WithValidation / Disabled" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var L=Object.create;var s=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var x=(o,l)=>()=>(l||o((l={exports:{}}).exports,l),l.exports),f=(o,l)=>{for(var a in l)s(o,a,{get:l[a],enumerable:!0})},g=(o,l,a,r)=>{if(l&&typeof l=="object"||typeof l=="function")for(let n of b(l))!u.call(o,n)&&n!==a&&s(o,n,{get:()=>l[n],enumerable:!(r=R(l,n))||r.enumerable});return o};var D=(o,l,a)=>(a=o!=null?L(h(o)):{},g(l||!o||!o.__esModule?s(a,"default",{value:o,enumerable:!0}):a,o));var F=x((A,p)=>{p.exports=window.Loomiere});var c={};f(c,{Default:()=>v,Disabled:()=>N,MultipleFieldsets:()=>S,WithDescription:()=>C,WithValidation:()=>E,default:()=>m});var t=D(F(),1);var d=window.React;function e(o,l,a){let{children:r,...n}=l||{};return a!==void 0&&(n.key=a),r===void 0?d.createElement(o,n):Array.isArray(r)?d.createElement(o,n,...r):d.createElement(o,n,r)}var J=d.Fragment;var w={title:"Components/Lib/Fieldset",parameters:{layout:"centered"},tags:["autodocs","ds:lib"]},m=w,v={render:()=>e("div",{style:{width:"400px"},children:e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Personal Information"}),e(t.Field.Root,{name:"firstName",children:[e(t.Field.Label,{children:"First name"}),e(t.Field.Control,{type:"text",placeholder:"John"})]}),e(t.Field.Root,{name:"lastName",children:[e(t.Field.Label,{children:"Last name"}),e(t.Field.Control,{type:"text",placeholder:"Doe"})]})]})})},C={render:()=>e("div",{style:{width:"400px"},children:e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Contact Information"}),e(t.FieldsetDescription,{children:"We'll use this information to contact you about your order."}),e(t.Field.Root,{name:"email",children:[e(t.Field.Label,{children:"Email address"}),e(t.Field.Control,{type:"email",placeholder:"you@example.com"})]}),e(t.Field.Root,{name:"phone",children:[e(t.Field.Label,{children:"Phone number"}),e(t.Field.Control,{type:"tel",placeholder:"(555) 123-4567"})]})]})})},E={render:()=>e("div",{style:{width:"400px"},children:e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Account Details"}),e(t.Field.Root,{name:"firstName",children:[e(t.Field.Label,{children:"First name"}),e(t.Field.Control,{type:"text",placeholder:"John"})]}),e(t.Field.Root,{name:"lastName",children:[e(t.Field.Label,{children:"Last name"}),e(t.Field.Control,{type:"text",placeholder:"Doe"})]}),e(t.Field.Root,{name:"email",invalid:!0,children:[e(t.Field.Label,{children:["Email address ",e("span",{style:{color:"var(--sl-status-warning)"},children:"*"})]}),e(t.Field.Control,{type:"email",placeholder:"you@example.com","aria-invalid":"true",defaultValue:"invalid-email"}),e(t.Field.Error,{children:"Please enter a valid email address"})]})]})})},N={render:()=>e("div",{style:{width:"400px"},children:e(t.Fieldset.Root,{disabled:!0,children:[e(t.Fieldset.Legend,{children:"Personal Information"}),e(t.FieldsetDescription,{children:"This section is currently disabled."}),e(t.Field.Root,{name:"firstName",children:[e(t.Field.Label,{children:"First name"}),e(t.Field.Control,{type:"text",placeholder:"John"})]}),e(t.Field.Root,{name:"lastName",children:[e(t.Field.Label,{children:"Last name"}),e(t.Field.Control,{type:"text",placeholder:"Doe"})]})]})})},S={render:()=>e("div",{style:{width:"400px",display:"flex",flexDirection:"column",gap:"32px"},children:[e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Personal Information"}),e(t.Field.Root,{name:"firstName",children:[e(t.Field.Label,{children:"First name"}),e(t.Field.Control,{type:"text",placeholder:"John"})]}),e(t.Field.Root,{name:"lastName",children:[e(t.Field.Label,{children:"Last name"}),e(t.Field.Control,{type:"text",placeholder:"Doe"})]})]}),e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Contact Information"}),e(t.FieldsetDescription,{children:"How can we reach you?"}),e(t.Field.Root,{name:"email2",children:[e(t.Field.Label,{children:"Email address"}),e(t.Field.Control,{type:"email",placeholder:"you@example.com"})]}),e(t.Field.Root,{name:"phone2",children:[e(t.Field.Label,{children:"Phone number"}),e(t.Field.Control,{type:"tel",placeholder:"(555) 123-4567"})]})]})]})};var i=window.React,y=m||{},I=["Default","WithDescription","WithValidation","Disabled"];function P({id:o}){let l=c[o],a={...y.args||{},...l.args||{}};return(l.render||(n=>i.createElement(y.component,n)))(a,{args:a,id:o,name:o})}var W=I.map(o=>i.createElement("section",{key:o,className:"ds-story"},i.createElement("p",{className:"ds-story-name"},o.replace(/([a-z])([A-Z])/g,"$1 $2")),i.createElement("div",{className:"ds-story-body"},i.createElement(P,{id:o}))));window.ReactDOM.createRoot(document.getElementById("root")).render(i.createElement(i.Fragment,null,W));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Form
|
|
2
|
+
|
|
3
|
+
The Base UI Form styled by the theme. No component tokens: fields stack with the large block space, and the action buttons sit in a row after them.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Form`, this package's wrapper: it puts the class names on for you (`import { Form } from '@scattered-light/loomiere-base-ui'` in an app). The bare Base UI part is `Loomiere.Base.Form`.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/form
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `Form` | |
|
|
14
|
+
| `FormActions` | |
|
|
15
|
+
|
|
16
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
17
|
+
|
|
18
|
+
## Example
|
|
19
|
+
|
|
20
|
+
From the Form stories (`Default`):
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
export const Default: Story = {
|
|
24
|
+
render: () => {
|
|
25
|
+
const handleSubmit = (formValues: Record<string, unknown>) => {
|
|
26
|
+
console.log('Form submitted', formValues);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div style={{ width: '400px' }}>
|
|
31
|
+
<Form onFormSubmit={handleSubmit}>
|
|
32
|
+
<Field.Root name="name">
|
|
33
|
+
<Field.Label>Name</Field.Label>
|
|
34
|
+
<Field.Control type="text" placeholder="John Doe" required />
|
|
35
|
+
</Field.Root>
|
|
36
|
+
|
|
37
|
+
<Field.Root name="email">
|
|
38
|
+
<Field.Label>Email</Field.Label>
|
|
39
|
+
<Field.Control type="email" placeholder="you@example.com" required />
|
|
40
|
+
</Field.Root>
|
|
41
|
+
|
|
42
|
+
<FormActions>
|
|
43
|
+
<Button type="submit" data-variant="solid">
|
|
44
|
+
Submit
|
|
45
|
+
</Button>
|
|
46
|
+
<Button type="reset" data-variant="outline">
|
|
47
|
+
Reset
|
|
48
|
+
</Button>
|
|
49
|
+
</FormActions>
|
|
50
|
+
</Form>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The preview also shows `WithFieldsets`, `WithValidation`, `ActionsAlignedRight`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Forms" height=480 subtitle="Default / WithFieldsets / WithValidation / ActionsAlignedRight" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var L=Object.create;var d=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var x=Object.getOwnPropertyNames;var S=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var u=(o,a)=>()=>(a||o((a={exports:{}}).exports,a),a.exports),f=(o,a)=>{for(var r in a)d(o,r,{get:a[r],enumerable:!0})},C=(o,a,r,l)=>{if(a&&typeof a=="object"||typeof a=="function")for(let n of x(a))!v.call(o,n)&&n!==r&&d(o,n,{get:()=>a[n],enumerable:!(l=w(a,n))||l.enumerable});return o};var p=(o,a,r)=>(r=o!=null?L(S(o)):{},C(a||!o||!o.__esModule?d(r,"default",{value:o,enumerable:!0}):r,o));var b=u((W,F)=>{F.exports=window.React});var h=u((V,y)=>{y.exports=window.Loomiere});var c={};f(c,{ActionsAlignedRight:()=>B,Default:()=>A,WithFieldsets:()=>q,WithValidation:()=>D,default:()=>m});var R=p(b(),1),t=p(h(),1);var s=window.React;function e(o,a,r){let{children:l,...n}=a||{};return r!==void 0&&(n.key=r),l===void 0?s.createElement(o,n):Array.isArray(l)?s.createElement(o,n,...l):s.createElement(o,n,l)}var I=s.Fragment;var E={title:"Components/Lib/Form",parameters:{layout:"centered"},tags:["autodocs","ds:lib"]},m=E,A={render:()=>e("div",{style:{width:"400px"},children:e(t.Form,{onFormSubmit:a=>{console.log("Form submitted",a)},children:[e(t.Field.Root,{name:"name",children:[e(t.Field.Label,{children:"Name"}),e(t.Field.Control,{type:"text",placeholder:"John Doe",required:!0})]}),e(t.Field.Root,{name:"email",children:[e(t.Field.Label,{children:"Email"}),e(t.Field.Control,{type:"email",placeholder:"you@example.com",required:!0})]}),e(t.FormActions,{children:[e(t.Button,{type:"submit","data-variant":"solid",children:"Submit"}),e(t.Button,{type:"reset","data-variant":"outline",children:"Reset"})]})]})})},q={render:()=>e("div",{style:{width:"400px"},children:e(t.Form,{onFormSubmit:a=>{console.log("Form submitted",a)},children:[e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Personal Information"}),e(t.Field.Root,{name:"firstName",children:[e(t.Field.Label,{children:"First name"}),e(t.Field.Control,{type:"text",placeholder:"John",required:!0})]}),e(t.Field.Root,{name:"lastName",children:[e(t.Field.Label,{children:"Last name"}),e(t.Field.Control,{type:"text",placeholder:"Doe",required:!0})]})]}),e(t.Fieldset.Root,{children:[e(t.Fieldset.Legend,{children:"Contact Information"}),e(t.Field.Root,{name:"email",children:[e(t.Field.Label,{children:"Email address"}),e(t.Field.Control,{type:"email",placeholder:"you@example.com",required:!0})]}),e(t.Field.Root,{name:"phone",children:[e(t.Field.Label,{children:"Phone number"}),e(t.Field.Control,{type:"tel",placeholder:"(555) 123-4567"})]})]}),e(t.Field.Root,{name:"message",children:[e(t.Field.Label,{children:"Message"}),e(t.Field.Control,{render:e("textarea",{placeholder:"Enter your message..."}),required:!0})]}),e(t.FormActions,{children:[e(t.Button,{type:"submit","data-variant":"solid",children:"Submit"}),e(t.Button,{type:"reset","data-variant":"outline",children:"Cancel"})]})]})})},D={render:()=>{let[o]=R.useState({username:!0,email:!1});return e("div",{style:{width:"400px"},children:e(t.Form,{onFormSubmit:r=>{console.log("Form submitted",r)},children:[e(t.Field.Root,{name:"username",invalid:o.username,children:[e(t.Field.Label,{children:["Username ",e("span",{style:{color:"var(--sl-status-warning)"},children:"*"})]}),e(t.Field.Control,{type:"text",placeholder:"johndoe","aria-invalid":o.username,defaultValue:"john",required:!0}),o.username&&e(t.Field.Error,{children:"Username must be at least 5 characters"})]}),e(t.Field.Root,{name:"email",children:[e(t.Field.Label,{children:["Email address ",e("span",{style:{color:"var(--sl-status-warning)"},children:"*"})]}),e(t.Field.Control,{type:"email",placeholder:"you@example.com",required:!0}),e(t.Field.Description,{children:"We'll never share your email with anyone else"})]}),e(t.Field.Root,{name:"password",children:[e(t.Field.Label,{children:["Password ",e("span",{style:{color:"var(--sl-status-warning)"},children:"*"})]}),e(t.Field.Control,{type:"password",placeholder:"Enter password",required:!0}),e(t.Field.Description,{children:"Must be at least 8 characters"})]}),e(t.FormActions,{children:[e(t.Button,{type:"submit","data-variant":"solid",children:"Create Account"}),e(t.Button,{type:"button","data-variant":"ghost",children:"Cancel"})]})]})})}},B={render:()=>e("div",{style:{width:"400px"},children:e(t.Form,{onFormSubmit:a=>{console.log("Form submitted",a)},children:[e(t.Field.Root,{name:"name",children:[e(t.Field.Label,{children:"Name"}),e(t.Field.Control,{type:"text",placeholder:"John Doe",required:!0})]}),e(t.Field.Root,{name:"email",children:[e(t.Field.Label,{children:"Email"}),e(t.Field.Control,{type:"email",placeholder:"you@example.com",required:!0})]}),e(t.FormActions,{style:{justifyContent:"flex-end"},children:[e(t.Button,{type:"button","data-variant":"ghost",children:"Cancel"}),e(t.Button,{type:"submit","data-variant":"solid",children:"Save"})]})]})})};var i=window.React,g=m||{},j=["Default","WithFieldsets","WithValidation","ActionsAlignedRight"];function N({id:o}){let a=c[o],r={...g.args||{},...a.args||{}};return(a.render||(n=>i.createElement(g.component,n)))(r,{args:r,id:o,name:o})}var k=j.map(o=>i.createElement("section",{key:o,className:"ds-story"},i.createElement("p",{className:"ds-story-name"},o.replace(/([a-z])([A-Z])/g,"$1 $2")),i.createElement("div",{className:"ds-story-body"},i.createElement(N,{id:o}))));window.ReactDOM.createRoot(document.getElementById("root")).render(i.createElement(i.Fragment,null,k));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# IconButton
|
|
2
|
+
|
|
3
|
+
The Base UI Button styled by the theme. A small, quiet icon-only button: the icon-button concept (tokens/semantic/icon-button.json), the same look as the X that closes a dialog or toast, as a part of its own. For calendar arrows, row actions and clear buttons, where a Button would be too loud. No component tokens.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.IconButton`, this package's wrapper: it puts the class names on for you (`import { IconButton } from '@scattered-light/loomiere-base-ui'` in an app). The bare Base UI part is `Loomiere.Base.Button`.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/button
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `IconButton` | |
|
|
14
|
+
|
|
15
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
16
|
+
|
|
17
|
+
## Example
|
|
18
|
+
|
|
19
|
+
From the IconButton stories (`Default`):
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
export const Default: Story = {
|
|
23
|
+
render: () => (
|
|
24
|
+
<IconButton type="button" aria-label="Next month">
|
|
25
|
+
<Icon name="chevron_right" />
|
|
26
|
+
</IconButton>
|
|
27
|
+
),
|
|
28
|
+
};
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The preview also shows `CalendarHeader`, `RowActions`, `Disabled`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Actions" height=480 subtitle="Default / CalendarHeader / RowActions / Disabled" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var x=Object.create;var m=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,w=Object.prototype.hasOwnProperty;var I=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),v=(e,t)=>{for(var o in t)m(e,o,{get:t[o],enumerable:!0})},E=(e,t,o,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of g(t))!w.call(e,a)&&a!==o&&m(e,a,{get:()=>t[a],enumerable:!(s=f(t,a))||s.enumerable});return e};var B=(e,t,o)=>(o=e!=null?x(h(e)):{},E(t||!e||!e.__esModule?m(o,"default",{value:e,enumerable:!0}):o,e));var u=I((F,y)=>{y.exports=window.Loomiere});var p={};v(p,{CalendarHeader:()=>N,Default:()=>D,Disabled:()=>A,RowActions:()=>R,default:()=>d});var r=B(u(),1);var i=window.React;function n(e,t,o){let{children:s,...a}=t||{};return o!==void 0&&(a.key=o),s===void 0?i.createElement(e,a):Array.isArray(s)?i.createElement(e,a,...s):i.createElement(e,a,s)}var M=i.Fragment;var S={title:"Components/Lib/IconButton",component:r.IconButton,parameters:{layout:"centered"},tags:["autodocs","ds:lib"]},d=S,c=({name:e})=>n("span",{className:"material-symbols-outlined","aria-hidden":"true",children:e}),D={render:()=>n(r.IconButton,{type:"button","aria-label":"Next month",children:n(c,{name:"chevron_right"})})},N={render:()=>n("div",{style:{display:"flex",alignItems:"center",gap:"var(--sl-space-2)",width:"280px"},children:[n(r.IconButton,{type:"button","aria-label":"Previous month",children:n(c,{name:"chevron_left"})}),n("span",{className:"text-style-base-subtitle",style:{flexGrow:1,textAlign:"center"},children:"October 2026"}),n(r.IconButton,{type:"button","aria-label":"Next month",children:n(c,{name:"chevron_right"})})]})},R={render:()=>n("div",{style:{display:"flex",gap:"var(--sl-space-1)"},children:[n(r.IconButton,{type:"button","aria-label":"Edit",children:n(c,{name:"edit"})}),n(r.IconButton,{type:"button","aria-label":"Duplicate",children:n(c,{name:"content_copy"})}),n(r.IconButton,{type:"button","aria-label":"Delete",children:n(c,{name:"delete"})})]})},A={render:()=>n(r.IconButton,{type:"button","aria-label":"Next month",disabled:!0,children:n(c,{name:"chevron_right"})})};var l=window.React,b=d||{},_=["Default","CalendarHeader","RowActions","Disabled"];function j({id:e}){let t=p[e],o={...b.args||{},...t.args||{}};return(t.render||(a=>l.createElement(b.component,a)))(o,{args:o,id:e,name:e})}var O=_.map(e=>l.createElement("section",{key:e,className:"ds-story"},l.createElement("p",{className:"ds-story-name"},e.replace(/([a-z])([A-Z])/g,"$1 $2")),l.createElement("div",{className:"ds-story-body"},l.createElement(j,{id:e}))));window.ReactDOM.createRoot(document.getElementById("root")).render(l.createElement(l.Fragment,null,O));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
The Base UI Input styled by the theme. No component tokens: the look is the field concept (tokens/semantic/field.json), sizes are control.*, and text is a whole text style. Field.Control is the same control inside a Field, and Number field's, Autocomplete's and Combobox's inputs are the same control with buttons at the end, and an OTP field's slots are the same control cut into squares (OTPField.css sizes them), so they share these rules.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Input`, this package's wrapper: it puts the class names on for you (`import { Input } from '@scattered-light/loomiere-base-ui'` in an app). The bare Base UI part is `Loomiere.Base.Input`.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/input
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `Input` | `data-error`; `data-size`: `xs`, `sm`, `lg` |
|
|
14
|
+
| `FieldControl` | |
|
|
15
|
+
| `NumberFieldInput` | |
|
|
16
|
+
| `AutocompleteInput` | |
|
|
17
|
+
| `ComboboxInput` | |
|
|
18
|
+
| `OTPFieldInput` | `data-invalid` |
|
|
19
|
+
| `FieldRoot` | `data-invalid` |
|
|
20
|
+
| `NumberFieldRoot` | `data-invalid` |
|
|
21
|
+
|
|
22
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
23
|
+
|
|
24
|
+
## Example
|
|
25
|
+
|
|
26
|
+
From the Input stories (`Default`):
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
export const Default: Story = {
|
|
30
|
+
render: () => (
|
|
31
|
+
<div style={{ width: '400px' }}>
|
|
32
|
+
<Input type="text" placeholder="Enter your name" />
|
|
33
|
+
</div>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The preview also shows `WithValue`, `Disabled`, `Warning`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Forms" height=480 subtitle="Default / WithValue / Disabled / Warning" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var u=Object.create;var l=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var h=Object.getPrototypeOf,v=Object.prototype.hasOwnProperty;var w=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),g=(e,t)=>{for(var a in t)l(e,a,{get:t[a],enumerable:!0})},E=(e,t,a,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of f(t))!v.call(e,o)&&o!==a&&l(e,o,{get:()=>t[o],enumerable:!(s=S(t,o))||s.enumerable});return e};var b=(e,t,a)=>(a=e!=null?u(h(e)):{},E(t||!e||!e.__esModule?l(a,"default",{value:e,enumerable:!0}):a,e));var y=w((O,m)=>{m.exports=window.Loomiere});var p={};g(p,{Default:()=>z,Disabled:()=>V,SizeLarge:()=>W,SizeSmall:()=>L,SizeXSmall:()=>I,Warning:()=>j,WithValue:()=>R,default:()=>c});var n=b(y(),1);var i=window.React;function r(e,t,a){let{children:s,...o}=t||{};return a!==void 0&&(o.key=a),s===void 0?i.createElement(e,o):Array.isArray(s)?i.createElement(e,o,...s):i.createElement(e,o,s)}var k=i.Fragment;var D={title:"Components/Lib/Input",component:n.Input,parameters:{layout:"centered"},tags:["autodocs","ds:lib"]},c=D,z={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text",placeholder:"Enter your name"})})},R={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text",defaultValue:"John Doe"})})},V={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text",placeholder:"Disabled input",disabled:!0})})},j={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"email","data-warning":!0,"aria-invalid":"true",defaultValue:"invalid-email"})})},I={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text","data-size":"xs",placeholder:"Extra small input"})})},L={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text","data-size":"sm",placeholder:"Small input"})})},W={render:()=>r("div",{style:{width:"400px"},children:r(n.Input,{type:"text","data-size":"lg",placeholder:"Large input"})})};var d=window.React,x=c||{},A=["Default","WithValue","Disabled","Warning"];function F({id:e}){let t=p[e],a={...x.args||{},...t.args||{}};return(t.render||(o=>d.createElement(x.component,o)))(a,{args:a,id:e,name:e})}var M=A.map(e=>d.createElement("section",{key:e,className:"ds-story"},d.createElement("p",{className:"ds-story-name"},e.replace(/([a-z])([A-Z])/g,"$1 $2")),d.createElement("div",{className:"ds-story-body"},d.createElement(F,{id:e}))));window.ReactDOM.createRoot(document.getElementById("root")).render(d.createElement(d.Fragment,null,M));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
The Base UI Menu styled by the theme. No component tokens. The trigger is a Button. The popup is the popup concept, rows are item rows at the dense menu height, and group labels, separators and check slots are the shared list parts, so menus and listboxes read as one family.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Menu` (`import { Menu } from '@base-ui/react/menu'` in an app) and give each part the class below; the styles target those classes, not Base UI's own markup.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/menu
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `MenuPositioner` | |
|
|
14
|
+
| `MenuPopup` | |
|
|
15
|
+
| `MenuItem` | `data-highlighted`; `data-disabled` |
|
|
16
|
+
| `MenuCheckboxItem` | `data-highlighted`; `data-disabled` |
|
|
17
|
+
| `MenuRadioItem` | `data-highlighted`; `data-disabled` |
|
|
18
|
+
| `MenuSubmenuTrigger` | `data-highlighted`; `data-disabled` |
|
|
19
|
+
| `MenuCheckboxItemIndicator` | |
|
|
20
|
+
| `MenuRadioItemIndicator` | `data-unchecked` |
|
|
21
|
+
| `MenuCheckboxItemIndicatorIcon` | |
|
|
22
|
+
| `MenuRadioItemIndicatorIcon` | |
|
|
23
|
+
| `MenuGroup` | |
|
|
24
|
+
| `MenuGroupLabel` | |
|
|
25
|
+
| `MenuSeparator` | |
|
|
26
|
+
|
|
27
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
28
|
+
|
|
29
|
+
## Example
|
|
30
|
+
|
|
31
|
+
From the Menu stories (`Default`):
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
export const Default: Story = {
|
|
35
|
+
render: () => (
|
|
36
|
+
<Menu.Root>
|
|
37
|
+
<Menu.Trigger className="Button">
|
|
38
|
+
Open Menu
|
|
39
|
+
</Menu.Trigger>
|
|
40
|
+
<Menu.Portal>
|
|
41
|
+
<Menu.Positioner className="MenuPositioner">
|
|
42
|
+
<Menu.Popup className="MenuPopup">
|
|
43
|
+
<Menu.Item className="MenuItem">New File</Menu.Item>
|
|
44
|
+
<Menu.Item className="MenuItem">New Window</Menu.Item>
|
|
45
|
+
<Menu.Separator className="MenuSeparator" />
|
|
46
|
+
<Menu.Item className="MenuItem">Save</Menu.Item>
|
|
47
|
+
<Menu.Item className="MenuItem">Save As...</Menu.Item>
|
|
48
|
+
<Menu.Separator className="MenuSeparator" />
|
|
49
|
+
<Menu.Item className="MenuItem">Exit</Menu.Item>
|
|
50
|
+
</Menu.Popup>
|
|
51
|
+
</Menu.Positioner>
|
|
52
|
+
</Menu.Portal>
|
|
53
|
+
</Menu.Root>
|
|
54
|
+
),
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The preview also shows `WithCheckboxes`, `WithRadioGroup`, `WithSubmenu`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Navigation" height=480 subtitle="Default / WithCheckboxes / WithRadioGroup / WithSubmenu" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var S=Object.create;var i=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var x=Object.getPrototypeOf,y=Object.prototype.hasOwnProperty;var d=(a,o)=>()=>(o||a((o={exports:{}}).exports,o),o.exports),C=(a,o)=>{for(var n in o)i(a,n,{get:o[n],enumerable:!0})},w=(a,o,n,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of k(o))!y.call(a,s)&&s!==n&&i(a,s,{get:()=>o[s],enumerable:!(r=g(o,s))||r.enumerable});return a};var M=(a,o,n)=>(n=a!=null?S(x(a)):{},w(o||!a||!a.__esModule?i(n,"default",{value:a,enumerable:!0}):n,a));var h=d((D,p)=>{p.exports=window.React});var R=d((O,N)=>{N.exports=window.Loomiere.Base});var I={};C(I,{Default:()=>T,WithCheckboxes:()=>E,WithDisabledItems:()=>v,WithRadioGroup:()=>F,WithSubmenu:()=>_,default:()=>l});var c=M(h(),1),t=M(R(),1);var u=window.React;function e(a,o,n){let{children:r,...s}=o||{};return n!==void 0&&(s.key=n),r===void 0?u.createElement(a,s):Array.isArray(r)?u.createElement(a,s,...r):u.createElement(a,s,r)}var V=u.Fragment;var f={title:"Components/Menu",component:t.Menu.Root,parameters:{layout:"centered"},tags:["autodocs"]},l=f,T={render:()=>e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"Button",children:"Open Menu"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New File"}),e(t.Menu.Item,{className:"MenuItem",children:"New Window"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Save"}),e(t.Menu.Item,{className:"MenuItem",children:"Save As..."}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Exit"})]})})})]})},E={render:()=>{let[a,o]=c.useState(!1),[n,r]=c.useState(!0),[s,P]=c.useState(!1);return e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"Button","data-variant":"outline",children:"View Options"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:a,onCheckedChange:o,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Toolbar"]}),e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:n,onCheckedChange:r,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Sidebar"]}),e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:s,onCheckedChange:P,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Footer"]})]})})})]})}},F={render:()=>{let[a,o]=c.useState("light");return e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"Button","data-variant":"ghost",children:"Theme"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:e(t.Menu.RadioGroup,{value:a,onValueChange:o,children:[e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"light",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Light"]}),e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"dark",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Dark"]}),e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"system",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"System"]})]})})})})]})}},_={render:()=>e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"Button",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New File"}),e(t.Menu.Item,{className:"MenuItem",children:"New Window"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.SubmenuRoot,{children:[e(t.Menu.SubmenuTrigger,{className:"MenuSubmenuTrigger",children:"Open Recent"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"project-1.txt"}),e(t.Menu.Item,{className:"MenuItem",children:"project-2.txt"}),e(t.Menu.Item,{className:"MenuItem",children:"project-3.txt"})]})})})]}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Exit"})]})})})]})},v={render:()=>e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"Button",children:"Edit"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Cut"}),e(t.Menu.Item,{className:"MenuItem",children:"Copy"}),e(t.Menu.Item,{className:"MenuItem",disabled:!0,children:"Paste (Nothing to paste)"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Select All"})]})})})]})};var m=window.React,b=l||{},W=["Default","WithCheckboxes","WithRadioGroup","WithSubmenu"];function L({id:a}){let o=I[a],n={...b.args||{},...o.args||{}};return(o.render||(s=>m.createElement(b.component,s)))(n,{args:n,id:a,name:a})}var j=W.map(a=>m.createElement("section",{key:a,className:"ds-story"},m.createElement("p",{className:"ds-story-name"},a.replace(/([a-z])([A-Z])/g,"$1 $2")),m.createElement("div",{className:"ds-story-body"},m.createElement(L,{id:a}))));window.ReactDOM.createRoot(document.getElementById("root")).render(m.createElement(m.Fragment,null,j));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Menubar
|
|
2
|
+
|
|
3
|
+
The Base UI Menubar styled by the theme. No component tokens. A row of quiet triggers, each opening a menu. The popup is the popup concept, rows are item rows at the dense menu height, and group labels, separators and check slots are the shared list parts, so menus and listboxes read as one family.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Menubar` (`import { Menubar } from '@base-ui/react/menubar'` in an app) and give each part the class below; the styles target those classes, not Base UI's own markup.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/menubar
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `MenubarRoot` | |
|
|
14
|
+
| `MenubarTrigger` | `data-popup-open` |
|
|
15
|
+
| `MenubarPositioner` | |
|
|
16
|
+
| `MenubarPopup` | |
|
|
17
|
+
| `MenubarItem` | `data-highlighted`; `data-disabled` |
|
|
18
|
+
| `MenubarCheckboxItem` | `data-highlighted`; `data-disabled` |
|
|
19
|
+
| `MenubarRadioItem` | `data-highlighted`; `data-disabled` |
|
|
20
|
+
| `MenubarSubmenuTrigger` | `data-highlighted`; `data-disabled` |
|
|
21
|
+
| `MenubarCheckboxItemIndicator` | |
|
|
22
|
+
| `MenubarRadioItemIndicator` | `data-unchecked` |
|
|
23
|
+
| `MenubarCheckboxItemIndicatorIcon` | |
|
|
24
|
+
| `MenubarRadioItemIndicatorIcon` | |
|
|
25
|
+
| `MenubarGroup` | |
|
|
26
|
+
| `MenubarGroupLabel` | |
|
|
27
|
+
| `MenubarSeparator` | |
|
|
28
|
+
|
|
29
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
30
|
+
|
|
31
|
+
## Example
|
|
32
|
+
|
|
33
|
+
From the Menubar stories (`Default`):
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
export const Default: Story = {
|
|
37
|
+
render: () => (
|
|
38
|
+
<Menubar className="MenubarRoot">
|
|
39
|
+
<Menu.Root>
|
|
40
|
+
<Menu.Trigger className="MenubarTrigger">File</Menu.Trigger>
|
|
41
|
+
<Menu.Portal>
|
|
42
|
+
<Menu.Positioner className="MenuPositioner" sideOffset={6}>
|
|
43
|
+
<Menu.Popup className="MenuPopup">
|
|
44
|
+
<Menu.Item className="MenuItem">New File</Menu.Item>
|
|
45
|
+
<Menu.Item className="MenuItem">New Window</Menu.Item>
|
|
46
|
+
<Menu.Separator className="MenuSeparator" />
|
|
47
|
+
<Menu.Item className="MenuItem">Open...</Menu.Item>
|
|
48
|
+
<Menu.Item className="MenuItem">Save</Menu.Item>
|
|
49
|
+
<Menu.Separator className="MenuSeparator" />
|
|
50
|
+
<Menu.Item className="MenuItem">Exit</Menu.Item>
|
|
51
|
+
</Menu.Popup>
|
|
52
|
+
</Menu.Positioner>
|
|
53
|
+
</Menu.Portal>
|
|
54
|
+
</Menu.Root>
|
|
55
|
+
|
|
56
|
+
<Menu.Root>
|
|
57
|
+
<Menu.Trigger className="MenubarTrigger">Edit</Menu.Trigger>
|
|
58
|
+
<Menu.Portal>
|
|
59
|
+
<Menu.Positioner className="MenuPositioner" sideOffset={6}>
|
|
60
|
+
<Menu.Popup className="MenuPopup">
|
|
61
|
+
<Menu.Item className="MenuItem">Undo</Menu.Item>
|
|
62
|
+
<Menu.Item className="MenuItem">Redo</Menu.Item>
|
|
63
|
+
<Menu.Separator className="MenuSeparator" />
|
|
64
|
+
<Menu.Item className="MenuItem">Cut</Menu.Item>
|
|
65
|
+
<Menu.Item className="MenuItem">Copy</Menu.Item>
|
|
66
|
+
<Menu.Item className="MenuItem">Paste</Menu.Item>
|
|
67
|
+
</Menu.Popup>
|
|
68
|
+
</Menu.Positioner>
|
|
69
|
+
</Menu.Portal>
|
|
70
|
+
</Menu.Root>
|
|
71
|
+
|
|
72
|
+
<Menu.Root>
|
|
73
|
+
<Menu.Trigger className="MenubarTrigger">View</Menu.Trigger>
|
|
74
|
+
<Menu.Portal>
|
|
75
|
+
<Menu.Positioner className="MenuPositioner" sideOffset={6}>
|
|
76
|
+
<Menu.Popup className="MenuPopup">
|
|
77
|
+
<Menu.Item className="MenuItem">Zoom In</Menu.Item>
|
|
78
|
+
<Menu.Item className="MenuItem">Zoom Out</Menu.Item>
|
|
79
|
+
<Menu.Item className="MenuItem">Reset Zoom</Menu.Item>
|
|
80
|
+
<Menu.Separator className="MenuSeparator" />
|
|
81
|
+
<Menu.Item className="MenuItem">Full Screen</Menu.Item>
|
|
82
|
+
</Menu.Popup>
|
|
83
|
+
</Menu.Positioner>
|
|
84
|
+
</Menu.Portal>
|
|
85
|
+
</Menu.Root>
|
|
86
|
+
|
|
87
|
+
<Menu.Root>
|
|
88
|
+
<Menu.Trigger className="MenubarTrigger">Help</Menu.Trigger>
|
|
89
|
+
<Menu.Portal>
|
|
90
|
+
<Menu.Positioner className="MenuPositioner" sideOffset={6}>
|
|
91
|
+
<Menu.Popup className="MenuPopup">
|
|
92
|
+
<Menu.Item className="MenuItem">Documentation</Menu.Item>
|
|
93
|
+
<Menu.Item className="MenuItem">Keyboard Shortcuts</Menu.Item>
|
|
94
|
+
<Menu.Separator className="MenuSeparator" />
|
|
95
|
+
<Menu.Item className="MenuItem">About</Menu.Item>
|
|
96
|
+
</Menu.Popup>
|
|
97
|
+
</Menu.Positioner>
|
|
98
|
+
</Menu.Portal>
|
|
99
|
+
</Menu.Root>
|
|
100
|
+
</Menubar>
|
|
101
|
+
),
|
|
102
|
+
};
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The preview also shows `WithCheckboxes`, `WithRadioGroup`, `WithSubmenu`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Navigation" height=480 subtitle="Default / WithCheckboxes / WithRadioGroup / WithSubmenu" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var x=Object.create;var M=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var k=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,C=Object.prototype.hasOwnProperty;var l=(a,o)=>()=>(o||a((o={exports:{}}).exports,o),o.exports),w=(a,o)=>{for(var n in o)M(a,n,{get:o[n],enumerable:!0})},O=(a,o,n,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of k(o))!C.call(a,s)&&s!==n&&M(a,s,{get:()=>o[s],enumerable:!(r=T(o,s))||r.enumerable});return a};var I=(a,o,n)=>(n=a!=null?x(y(a)):{},O(o||!a||!a.__esModule?M(n,"default",{value:a,enumerable:!0}):n,a));var P=l((D,N)=>{N.exports=window.React});var b=l((A,g)=>{g.exports=window.Loomiere.Base});var h=l((z,R)=>{R.exports=window.Loomiere.Base});var d={};w(d,{Default:()=>F,WithCheckboxes:()=>L,WithDisabledItems:()=>W,WithRadioGroup:()=>_,WithSubmenu:()=>G,default:()=>p});var i=I(P(),1),u=I(b(),1),t=I(h(),1);var c=window.React;function e(a,o,n){let{children:r,...s}=o||{};return n!==void 0&&(s.key=n),r===void 0?c.createElement(a,s):Array.isArray(r)?c.createElement(a,s,...r):c.createElement(a,s,r)}var Z=c.Fragment;var E={title:"Components/Menubar",component:u.Menubar,parameters:{layout:"centered"},tags:["autodocs"]},p=E,F={render:()=>e(u.Menubar,{className:"MenubarRoot",children:[e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New File"}),e(t.Menu.Item,{className:"MenuItem",children:"New Window"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Open..."}),e(t.Menu.Item,{className:"MenuItem",children:"Save"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Exit"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"Edit"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Undo"}),e(t.Menu.Item,{className:"MenuItem",children:"Redo"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Cut"}),e(t.Menu.Item,{className:"MenuItem",children:"Copy"}),e(t.Menu.Item,{className:"MenuItem",children:"Paste"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"View"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Zoom In"}),e(t.Menu.Item,{className:"MenuItem",children:"Zoom Out"}),e(t.Menu.Item,{className:"MenuItem",children:"Reset Zoom"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Full Screen"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"Help"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Documentation"}),e(t.Menu.Item,{className:"MenuItem",children:"Keyboard Shortcuts"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"About"})]})})})]})]})},L={render:()=>{let[a,o]=i.useState(!0),[n,r]=i.useState(!0),[s,f]=i.useState(!1);return e(u.Menubar,{className:"MenubarRoot",children:[e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New"}),e(t.Menu.Item,{className:"MenuItem",children:"Open"}),e(t.Menu.Item,{className:"MenuItem",children:"Save"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"View"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:a,onCheckedChange:o,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Toolbar"]}),e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:n,onCheckedChange:r,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Sidebar"]}),e(t.Menu.CheckboxItem,{className:"MenuCheckboxItem",checked:s,onCheckedChange:f,children:[e(t.Menu.CheckboxItemIndicator,{className:"MenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined MenuCheckboxItemIndicatorIcon",children:"check"})}),"Show Status Bar"]})]})})})]})]})}},_={render:()=>{let[a,o]=i.useState("medium");return e(u.Menubar,{className:"MenubarRoot",children:[e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New"}),e(t.Menu.Item,{className:"MenuItem",children:"Open"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"Format"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:e(t.Menu.Group,{className:"MenuGroup",children:[e(t.Menu.GroupLabel,{className:"MenuGroupLabel",children:"Text Size"}),e(t.Menu.RadioGroup,{value:a,onValueChange:o,children:[e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"small",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Small"]}),e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"medium",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Medium"]}),e(t.Menu.RadioItem,{className:"MenuRadioItem",value:"large",children:[e(t.Menu.RadioItemIndicator,{className:"MenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"MenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined MenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Large"]})]})]})})})})]})]})}},G={render:()=>e(u.Menubar,{className:"MenubarRoot",children:[e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New File"}),e(t.Menu.Item,{className:"MenuItem",children:"New Window"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.SubmenuRoot,{children:[e(t.Menu.SubmenuTrigger,{className:"MenuSubmenuTrigger",children:"Open Recent"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"project-1.txt"}),e(t.Menu.Item,{className:"MenuItem",children:"project-2.txt"}),e(t.Menu.Item,{className:"MenuItem",children:"project-3.txt"})]})})})]}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Exit"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"Edit"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Undo"}),e(t.Menu.Item,{className:"MenuItem",children:"Redo"})]})})})]})]})},W={render:()=>e(u.Menubar,{className:"MenubarRoot",children:[e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"File"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"New"}),e(t.Menu.Item,{className:"MenuItem",children:"Open"}),e(t.Menu.Item,{className:"MenuItem",children:"Save"})]})})})]}),e(t.Menu.Root,{children:[e(t.Menu.Trigger,{className:"MenubarTrigger",children:"Edit"}),e(t.Menu.Portal,{children:e(t.Menu.Positioner,{className:"MenuPositioner",sideOffset:6,children:e(t.Menu.Popup,{className:"MenuPopup",children:[e(t.Menu.Item,{className:"MenuItem",children:"Cut"}),e(t.Menu.Item,{className:"MenuItem",children:"Copy"}),e(t.Menu.Item,{className:"MenuItem",disabled:!0,children:"Paste (Nothing to paste)"}),e(t.Menu.Separator,{className:"MenuSeparator"}),e(t.Menu.Item,{className:"MenuItem",children:"Select All"})]})})})]})]})};var m=window.React,S=p||{},v=["Default","WithCheckboxes","WithRadioGroup","WithSubmenu"];function j({id:a}){let o=d[a],n={...S.args||{},...o.args||{}};return(o.render||(s=>m.createElement(S.component,s)))(n,{args:n,id:a,name:a})}var V=v.map(a=>m.createElement("section",{key:a,className:"ds-story"},m.createElement("p",{className:"ds-story-name"},a.replace(/([a-z])([A-Z])/g,"$1 $2")),m.createElement("div",{className:"ds-story-body"},m.createElement(j,{id:a}))));window.ReactDOM.createRoot(document.getElementById("root")).render(m.createElement(m.Fragment,null,V));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Meter
|
|
2
|
+
|
|
3
|
+
The Base UI Meter styled by the theme. A gauge (tokens/semantic/gauge.json). The fill is the solid color of the scope around it: the accent by default, or set data-color on the root (success, warning, error, any palette) to show a zone. Base UI doesn't map low/high/optimum, so the app picks the color.
|
|
4
|
+
|
|
5
|
+
Use `Loomiere.Meter` (`import { Meter } from '@base-ui/react/meter'` in an app) and give each part the class below; the styles target those classes, not Base UI's own markup.
|
|
6
|
+
|
|
7
|
+
Base UI docs: https://base-ui.com/react/components/meter
|
|
8
|
+
|
|
9
|
+
## Classes
|
|
10
|
+
|
|
11
|
+
| Class | Data attributes it answers to |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `MeterRoot` | |
|
|
14
|
+
| `MeterLabel` | |
|
|
15
|
+
| `MeterTrack` | `data-size`: `sm`, `lg` |
|
|
16
|
+
| `MeterIndicator` | |
|
|
17
|
+
| `MeterValue` | |
|
|
18
|
+
|
|
19
|
+
Base UI sets the state attributes (`data-checked`, `data-open`, `data-disabled`...) itself. Set `data-size`, `data-emphasis`, `data-variant` and `data-color` yourself; `data-color` takes any palette name (`primary`, `secondary`, `error`...) and repaints the part in it.
|
|
20
|
+
|
|
21
|
+
## Example
|
|
22
|
+
|
|
23
|
+
From the Meter stories (`Default`):
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
export const Default: Story = {
|
|
27
|
+
render: () => (
|
|
28
|
+
<div style={{ width: '300px' }}>
|
|
29
|
+
<Meter.Root value={75} min={0} max={100} className="MeterRoot">
|
|
30
|
+
<div className="MeterLabel">
|
|
31
|
+
<span>Storage</span>
|
|
32
|
+
<Meter.Value className="MeterValue" />
|
|
33
|
+
</div>
|
|
34
|
+
<Meter.Track className="MeterTrack">
|
|
35
|
+
<Meter.Indicator className="MeterIndicator" />
|
|
36
|
+
</Meter.Track>
|
|
37
|
+
</Meter.Root>
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The preview also shows `WithOptimumRange`, `Sizes`, `DiskUsage`.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<!-- @dsCard group="Feedback" height=480 subtitle="Default / WithOptimumRange / Sizes / DiskUsage" -->
|
|
2
|
+
<!doctype html>
|
|
3
|
+
<html>
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<style>
|
|
7
|
+
body { margin: 0; padding: var(--sl-space-4, 16px); background: var(--sl-surface-canvas); color: var(--sl-text-primary); }
|
|
8
|
+
#root { display: grid; gap: var(--sl-space-5, 20px); }
|
|
9
|
+
.ds-story-name { margin: 0 0 var(--sl-space-2, 8px); font: var(--sl-font-minimize-label-font, 500 10px sans-serif); color: var(--sl-text-tertiary); text-transform: uppercase; letter-spacing: 0.06em; }
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script>
|
|
15
|
+
(()=>{var y=Object.create;var m=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,I=Object.prototype.hasOwnProperty;var M=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports),g=(t,r)=>{for(var s in r)m(t,s,{get:r[s],enumerable:!0})},b=(t,r,s,c)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of f(r))!I.call(t,o)&&o!==s&&m(t,o,{get:()=>r[o],enumerable:!(c=T(r,o))||c.enumerable});return t};var p=(t,r,s)=>(s=t!=null?y(V(t)):{},b(r||!t||!t.__esModule?m(s,"default",{value:t,enumerable:!0}):s,t));var N=M((O,u)=>{u.exports=window.React});var x=M((j,v)=>{v.exports=window.Loomiere.Base});var d={};g(d,{BatteryLevel:()=>E,Default:()=>w,DiskUsage:()=>L,NetworkSpeed:()=>B,Sizes:()=>D,WithOptimumRange:()=>S,WithoutLabel:()=>C,default:()=>i});var R=p(N(),1),a=p(x(),1);var n=window.React;function e(t,r,s){let{children:c,...o}=r||{};return s!==void 0&&(o.key=s),c===void 0?n.createElement(t,o):Array.isArray(c)?n.createElement(t,o,...c):n.createElement(t,o,c)}var A=n.Fragment;var h={title:"Components/Meter",parameters:{layout:"centered"},tags:["autodocs"]},i=h,w={render:()=>e("div",{style:{width:"300px"},children:e(a.Meter.Root,{value:75,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Storage"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]})})},S={render:()=>e("div",{style:{width:"300px",display:"flex",flexDirection:"column",gap:"24px"},children:[e("p",{style:{margin:0,fontSize:"14px",color:"var(--sl-text-tertiary)"},children:["Base UI Meter doesn't map ",e("code",{children:"low"}),"/",e("code",{children:"high"}),"/",e("code",{children:"optimum"}),", so pick the zone in the app and set ",e("code",{children:"data-color"})," on the root."]}),e(a.Meter.Root,{value:30,min:0,max:100,className:"MeterRoot","data-color":"success",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"CPU load (lower is calmer)"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:60,min:0,max:100,className:"MeterRoot","data-color":"warning",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"CPU load (moderate)"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:90,min:0,max:100,className:"MeterRoot","data-color":"error",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"CPU load (high)"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]})]})},D={render:()=>e("div",{style:{width:"300px",display:"flex",flexDirection:"column",gap:"24px"},children:[e(a.Meter.Root,{value:45,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Small"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack","data-size":"sm",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:65,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Medium (default)"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:85,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Large"}),e(a.Meter.Value,{className:"MeterValue"})]}),e(a.Meter.Track,{className:"MeterTrack","data-size":"lg",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]})]})},L={render:()=>e("div",{style:{width:"400px",display:"flex",flexDirection:"column",gap:"24px"},children:[e(a.Meter.Root,{value:45,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"System Drive (C:)"}),e(a.Meter.Value,{className:"MeterValue",children:(t,r)=>`${r}% used`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:78,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Data Drive (D:)"}),e(a.Meter.Value,{className:"MeterValue",children:(t,r)=>`${r}% used`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:95,min:0,max:100,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Backup Drive (E:)"}),e(a.Meter.Value,{className:"MeterValue",children:(t,r)=>`${r}% used`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]})]})},E={render:()=>{let[t,r]=R.useState(85);return e("div",{style:{width:"300px",display:"flex",flexDirection:"column",gap:"16px"},children:[e(a.Meter.Root,{value:t,min:0,max:100,className:"MeterRoot","data-color":t<=20?"error":t<=50?"warning":"success",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Battery Level"}),e(a.Meter.Value,{className:"MeterValue",children:(s,c)=>`${c}%`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e("div",{style:{display:"flex",gap:"8px"},children:[e("button",{type:"button",className:"Button","data-emphasis":"standard",onClick:()=>r(Math.max(0,t-10)),children:"Drain -10%"}),e("button",{type:"button",className:"Button","data-emphasis":"standard",onClick:()=>r(Math.min(100,t+10)),children:"Charge +10%"})]})]})}},B={render:()=>e("div",{style:{width:"350px",display:"flex",flexDirection:"column",gap:"24px"},children:[e(a.Meter.Root,{value:850,min:0,max:1e3,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Download Speed"}),e(a.Meter.Value,{className:"MeterValue",children:(t,r)=>`${r} Mbps`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]}),e(a.Meter.Root,{value:450,min:0,max:1e3,className:"MeterRoot",children:[e("div",{className:"MeterLabel",children:[e("span",{children:"Upload Speed"}),e(a.Meter.Value,{className:"MeterValue",children:(t,r)=>`${r} Mbps`})]}),e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})]})]})},C={render:()=>e("div",{style:{width:"300px"},children:e(a.Meter.Root,{value:60,min:0,max:100,className:"MeterRoot",children:e(a.Meter.Track,{className:"MeterTrack",children:e(a.Meter.Indicator,{className:"MeterIndicator"})})})})};var l=window.React,k=i||{},$=["Default","WithOptimumRange","Sizes","DiskUsage"];function z({id:t}){let r=d[t],s={...k.args||{},...r.args||{}};return(r.render||(o=>l.createElement(k.component,o)))(s,{args:s,id:t,name:t})}var U=$.map(t=>l.createElement("section",{key:t,className:"ds-story"},l.createElement("p",{className:"ds-story-name"},t.replace(/([a-z])([A-Z])/g,"$1 $2")),l.createElement("div",{className:"ds-story-body"},l.createElement(z,{id:t}))));window.ReactDOM.createRoot(document.getElementById("root")).render(l.createElement(l.Fragment,null,U));})();
|
|
16
|
+
|
|
17
|
+
</script>
|
|
18
|
+
</body>
|
|
19
|
+
</html>
|