@scattered-light/loomiere-base-ui 0.1.0 → 0.2.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.
Files changed (122) hide show
  1. package/README.md +10 -1
  2. package/dist/design-system/components/Accordion/README.md +97 -0
  3. package/dist/design-system/components/Accordion/preview.html +19 -0
  4. package/dist/design-system/components/AlertDialog/README.md +52 -0
  5. package/dist/design-system/components/AlertDialog/preview.html +19 -0
  6. package/dist/design-system/components/Autocomplete/README.md +68 -0
  7. package/dist/design-system/components/Autocomplete/preview.html +19 -0
  8. package/dist/design-system/components/Avatar/README.md +39 -0
  9. package/dist/design-system/components/Avatar/preview.html +19 -0
  10. package/dist/design-system/components/Button/README.md +27 -0
  11. package/dist/design-system/components/Button/preview.html +23 -0
  12. package/dist/design-system/components/Checkbox/README.md +39 -0
  13. package/dist/design-system/components/Checkbox/preview.html +19 -0
  14. package/dist/design-system/components/CheckboxGroup/README.md +56 -0
  15. package/dist/design-system/components/CheckboxGroup/preview.html +19 -0
  16. package/dist/design-system/components/Collapsible/README.md +48 -0
  17. package/dist/design-system/components/Collapsible/preview.html +19 -0
  18. package/dist/design-system/components/Combobox/README.md +105 -0
  19. package/dist/design-system/components/Combobox/preview.html +19 -0
  20. package/dist/design-system/components/ContextMenu/README.md +70 -0
  21. package/dist/design-system/components/ContextMenu/preview.html +19 -0
  22. package/dist/design-system/components/Dialog/README.md +62 -0
  23. package/dist/design-system/components/Dialog/preview.html +19 -0
  24. package/dist/design-system/components/Drawer/README.md +32 -0
  25. package/dist/design-system/components/Drawer/preview.html +19 -0
  26. package/dist/design-system/components/Field/README.md +41 -0
  27. package/dist/design-system/components/Field/preview.html +19 -0
  28. package/dist/design-system/components/Fieldset/README.md +45 -0
  29. package/dist/design-system/components/Fieldset/preview.html +19 -0
  30. package/dist/design-system/components/Form/README.md +57 -0
  31. package/dist/design-system/components/Form/preview.html +19 -0
  32. package/dist/design-system/components/Input/README.md +38 -0
  33. package/dist/design-system/components/Input/preview.html +19 -0
  34. package/dist/design-system/components/Menu/README.md +58 -0
  35. package/dist/design-system/components/Menu/preview.html +19 -0
  36. package/dist/design-system/components/Menubar/README.md +105 -0
  37. package/dist/design-system/components/Menubar/preview.html +19 -0
  38. package/dist/design-system/components/Meter/README.md +43 -0
  39. package/dist/design-system/components/Meter/preview.html +19 -0
  40. package/dist/design-system/components/NavigationMenu/README.md +148 -0
  41. package/dist/design-system/components/NavigationMenu/preview.html +19 -0
  42. package/dist/design-system/components/NumberField/README.md +58 -0
  43. package/dist/design-system/components/NumberField/preview.html +19 -0
  44. package/dist/design-system/components/OTPField/README.md +39 -0
  45. package/dist/design-system/components/OTPField/preview.html +19 -0
  46. package/dist/design-system/components/Popover/README.md +56 -0
  47. package/dist/design-system/components/Popover/preview.html +19 -0
  48. package/dist/design-system/components/PreviewCard/README.md +74 -0
  49. package/dist/design-system/components/PreviewCard/preview.html +19 -0
  50. package/dist/design-system/components/Progress/README.md +58 -0
  51. package/dist/design-system/components/Progress/preview.html +19 -0
  52. package/dist/design-system/components/Radio/README.md +74 -0
  53. package/dist/design-system/components/Radio/preview.html +19 -0
  54. package/dist/design-system/components/ScrollArea/README.md +62 -0
  55. package/dist/design-system/components/ScrollArea/preview.html +40 -0
  56. package/dist/design-system/components/Select/README.md +84 -0
  57. package/dist/design-system/components/Select/preview.html +19 -0
  58. package/dist/design-system/components/Separator/README.md +37 -0
  59. package/dist/design-system/components/Separator/preview.html +19 -0
  60. package/dist/design-system/components/Slider/README.md +44 -0
  61. package/dist/design-system/components/Slider/preview.html +19 -0
  62. package/dist/design-system/components/Switch/README.md +34 -0
  63. package/dist/design-system/components/Switch/preview.html +19 -0
  64. package/dist/design-system/components/Tabs/README.md +56 -0
  65. package/dist/design-system/components/Tabs/preview.html +19 -0
  66. package/dist/design-system/components/Toast/README.md +78 -0
  67. package/dist/design-system/components/Toast/preview.html +19 -0
  68. package/dist/design-system/components/Toggle/README.md +32 -0
  69. package/dist/design-system/components/Toggle/preview.html +19 -0
  70. package/dist/design-system/components/ToggleGroup/README.md +40 -0
  71. package/dist/design-system/components/ToggleGroup/preview.html +19 -0
  72. package/dist/design-system/components/Toolbar/README.md +65 -0
  73. package/dist/design-system/components/Toolbar/preview.html +19 -0
  74. package/dist/design-system/components/Tooltip/README.md +46 -0
  75. package/dist/design-system/components/Tooltip/preview.html +19 -0
  76. package/dist/design-system/components/bundle.js +5 -0
  77. package/dist/design-system/components/index.d.ts +107 -0
  78. package/dist/design-system/components/styles.css +5533 -0
  79. package/dist/styles/components/Accordion.css +1 -1
  80. package/dist/styles/components/AlertDialog.css +1 -1
  81. package/dist/styles/components/Autocomplete.css +1 -1
  82. package/dist/styles/components/Avatar.css +1 -1
  83. package/dist/styles/components/Button.css +1 -1
  84. package/dist/styles/components/Checkbox.css +1 -1
  85. package/dist/styles/components/CheckboxGroup.css +1 -1
  86. package/dist/styles/components/Collapsible.css +1 -1
  87. package/dist/styles/components/Combobox.css +1 -1
  88. package/dist/styles/components/ContextMenu.css +1 -1
  89. package/dist/styles/components/Dialog.css +1 -1
  90. package/dist/styles/components/Drawer.css +1 -1
  91. package/dist/styles/components/Field.css +1 -1
  92. package/dist/styles/components/Fieldset.css +1 -1
  93. package/dist/styles/components/Form.css +1 -1
  94. package/dist/styles/components/Input.css +1 -1
  95. package/dist/styles/components/Menu.css +1 -1
  96. package/dist/styles/components/Menubar.css +1 -1
  97. package/dist/styles/components/Meter.css +1 -1
  98. package/dist/styles/components/NavigationMenu.css +1 -1
  99. package/dist/styles/components/NumberField.css +1 -1
  100. package/dist/styles/components/OTPField.css +1 -1
  101. package/dist/styles/components/Popover.css +1 -1
  102. package/dist/styles/components/PreviewCard.css +1 -1
  103. package/dist/styles/components/Progress.css +1 -1
  104. package/dist/styles/components/Radio.css +1 -1
  105. package/dist/styles/components/ScrollArea.css +1 -1
  106. package/dist/styles/components/Select.css +1 -1
  107. package/dist/styles/components/Separator.css +1 -1
  108. package/dist/styles/components/Slider.css +1 -1
  109. package/dist/styles/components/Switch.css +1 -1
  110. package/dist/styles/components/Tabs.css +1 -1
  111. package/dist/styles/components/Toast.css +1 -1
  112. package/dist/styles/components/Toggle.css +1 -1
  113. package/dist/styles/components/ToggleGroup.css +1 -1
  114. package/dist/styles/components/Toolbar.css +1 -1
  115. package/dist/styles/components/Tooltip.css +1 -1
  116. package/dist/styles/index.css +1 -1
  117. package/dist/styles/reset/accessibility.css +1 -1
  118. package/dist/styles/reset/reset-accessibility.css +1 -1
  119. package/dist/styles/reset/reset-tailwind.css +441 -0
  120. package/dist/styles/reset/reset.css +1 -1
  121. package/dist/styles/tailwind.css +55 -0
  122. package/package.json +5 -3
@@ -0,0 +1,48 @@
1
+ # Collapsible
2
+
3
+ The Base UI Collapsible styled by the theme. No component tokens. Hover, press, chevron and motion are the disclosure concept (tokens/semantic/disclosure.json). The trigger is base-subtitle text with a base-size chevron; the panel lines up under the trigger's text and sits on the overlay surface.
4
+
5
+ Use `Loomiere.Collapsible` (`import { Collapsible } from '@base-ui/react/collapsible'` 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/collapsible
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `Collapsible` | |
14
+ | `CollapsibleTrigger` | `data-panel-open` |
15
+ | `CollapsibleIcon` | |
16
+ | `CollapsiblePanel` | `data-starting-style`; `data-ending-style` |
17
+ | `CollapsibleContent` | |
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 Collapsible stories (`Default`):
24
+
25
+ ```tsx
26
+ export const Default: Story = {
27
+ render: () => (
28
+ <Collapsible.Root className="Collapsible">
29
+ <Collapsible.Trigger className="CollapsibleTrigger">
30
+ <span className="material-symbols-outlined CollapsibleIcon">
31
+ chevron_right
32
+ </span>
33
+ Show more information
34
+ </Collapsible.Trigger>
35
+ <Collapsible.Panel className="CollapsiblePanel">
36
+ <div className="CollapsibleContent">
37
+ <p>
38
+ This is additional content that can be collapsed and expanded.
39
+ It contains important information that users can choose to view.
40
+ </p>
41
+ </div>
42
+ </Collapsible.Panel>
43
+ </Collapsible.Root>
44
+ ),
45
+ };
46
+ ```
47
+
48
+ The preview also shows `DefaultOpen`, `FAQ`, `RecoveryKeys`.
@@ -0,0 +1,19 @@
1
+ <!-- @dsCard group="Disclosure" height=480 subtitle="Default / DefaultOpen / FAQ / RecoveryKeys" -->
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 g=Object.create;var p=Object.defineProperty;var y=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var v=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var h=(l,a)=>()=>(a||l((a={exports:{}}).exports,a),a.exports),f=(l,a)=>{for(var o in a)p(l,o,{get:a[o],enumerable:!0})},R=(l,a,o,n)=>{if(a&&typeof a=="object"||typeof a=="function")for(let t of u(a))!N.call(l,t)&&t!==o&&p(l,t,{get:()=>a[t],enumerable:!(n=y(a,t))||n.enumerable});return l};var T=(l,a,o)=>(o=l!=null?g(v(l)):{},R(a||!l||!l.__esModule?p(o,"default",{value:l,enumerable:!0}):o,l));var d=h((B,b)=>{b.exports=window.Loomiere.Base});var m={};f(m,{Default:()=>w,DefaultOpen:()=>x,FAQ:()=>I,RecoveryKeys:()=>S,default:()=>c});var s=T(d(),1);var r=window.React;function e(l,a,o){let{children:n,...t}=a||{};return o!==void 0&&(t.key=o),n===void 0?r.createElement(l,t):Array.isArray(n)?r.createElement(l,t,...n):r.createElement(l,t,n)}var O=r.Fragment;var P={title:"Components/Collapsible",component:s.Collapsible.Root,parameters:{layout:"centered"},tags:["autodocs"]},c=P,w={render:()=>e(s.Collapsible.Root,{className:"Collapsible",children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"Show more information"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:e("p",{children:"This is additional content that can be collapsed and expanded. It contains important information that users can choose to view."})})})]})},x={render:()=>e(s.Collapsible.Root,{className:"Collapsible",defaultOpen:!0,children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"Hide details"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:e("p",{children:"This collapsible starts in an open state by default. Click the trigger to collapse it."})})})]})},I={render:()=>e("div",{style:{display:"flex",flexDirection:"column",gap:"12px"},children:[e(s.Collapsible.Root,{className:"Collapsible",children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"What is Base UI?"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:e("p",{children:`Base UI is a library of headless ("unstyled") React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.`})})})]}),e(s.Collapsible.Root,{className:"Collapsible",children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"How do I install it?"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:[e("p",{children:"You can install Base UI using npm, yarn, or pnpm:"}),e("code",{children:"npm install @base-ui/react"})]})})]}),e(s.Collapsible.Root,{className:"Collapsible",children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"Is it accessible?"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:e("p",{children:"Yes! Base UI components follow WAI-ARIA authoring practices and are fully accessible out of the box with proper keyboard navigation and screen reader support."})})})]})]})},S={render:()=>e(s.Collapsible.Root,{className:"Collapsible",children:[e(s.Collapsible.Trigger,{className:"CollapsibleTrigger",children:[e("span",{className:"material-symbols-outlined CollapsibleIcon",children:"chevron_right"}),"Recovery keys"]}),e(s.Collapsible.Panel,{className:"CollapsiblePanel",children:e("div",{className:"CollapsibleContent",children:[e("div",{children:"alien-bean-pasta"}),e("div",{children:"wild-irish-burrito"}),e("div",{children:"horse-battery-staple"})]})})]})};var i=window.React,C=c||{},E=["Default","DefaultOpen","FAQ","RecoveryKeys"];function A({id:l}){let a=m[l],o={...C.args||{},...a.args||{}};return(a.render||(t=>i.createElement(C.component,t)))(o,{args:o,id:l,name:l})}var D=E.map(l=>i.createElement("section",{key:l,className:"ds-story"},i.createElement("p",{className:"ds-story-name"},l.replace(/([a-z])([A-Z])/g,"$1 $2")),i.createElement("div",{className:"ds-story-body"},i.createElement(A,{id:l}))));window.ReactDOM.createRoot(document.getElementById("root")).render(i.createElement(i.Fragment,null,D));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,105 @@
1
+ # Combobox
2
+
3
+ The Base UI Combobox styled by the theme. No component tokens. The input is Input (Input.css); the chips box is a field; the clear and open buttons are icon buttons; the list is a popup of item rows with the shared group label, separator and empty message. Rules that adjust Input are scoped under a Combobox parent so they win over Input.css, which loads later.
4
+
5
+ Use `Loomiere.Combobox` (`import { Combobox } from '@base-ui/react/combobox'` 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/combobox
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `ComboboxRoot` | |
14
+ | `ComboboxContainer` | |
15
+ | `ComboboxLabel` | |
16
+ | `ComboboxInputWrapper` | |
17
+ | `ComboboxInput` | |
18
+ | `ComboboxChips` | |
19
+ | `ComboboxChip` | `data-highlighted` |
20
+ | `ComboboxChipRemove` | |
21
+ | `ComboboxChipRemoveIcon` | |
22
+ | `ComboboxActionButtons` | |
23
+ | `ComboboxClear` | |
24
+ | `ComboboxTrigger` | |
25
+ | `ComboboxClearIcon` | |
26
+ | `ComboboxTriggerIcon` | |
27
+ | `ComboboxPositioner` | |
28
+ | `ComboboxPopup` | |
29
+ | `ComboboxList` | |
30
+ | `ComboboxItem` | `data-highlighted`; `data-selected`; `data-disabled` |
31
+ | `ComboboxItemIndicator` | |
32
+ | `ComboboxItemIndicatorIcon` | |
33
+ | `ComboboxItemText` | |
34
+ | `ComboboxGroupLabel` | |
35
+ | `ComboboxSeparator` | |
36
+ | `ComboboxEmpty` | |
37
+ | `ComboboxStatus` | |
38
+ | `ComboboxSelectTrigger` | |
39
+ | `ComboboxIcon` | |
40
+ | `ComboboxInputContainer` | |
41
+ | `ComboboxSpinner` | |
42
+ | `ComboboxItemTitle` | |
43
+ | `ComboboxItemSubtitle` | |
44
+ | `ComboboxItemUsername` | |
45
+ | `ComboboxItemEmail` | |
46
+
47
+ 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.
48
+
49
+ ## Example
50
+
51
+ From the Combobox stories (`Default`):
52
+
53
+ ```tsx
54
+ export const Default: Story = {
55
+ render: () => {
56
+ const id = React.useId();
57
+ return (
58
+ <div className="ComboboxRoot" style={{ width: '400px' }}>
59
+ <Combobox.Root items={fruits}>
60
+ <label htmlFor={id} className="ComboboxLabel">
61
+ Choose a fruit
62
+ <div className="ComboboxInputWrapper">
63
+ <Combobox.Input placeholder="e.g. Apple" id={id} className="ComboboxInput" />
64
+ <div className="ComboboxActionButtons">
65
+ <Combobox.Clear className="ComboboxClear" aria-label="Clear selection">
66
+ <span className="material-symbols-outlined ComboboxClearIcon">
67
+ close
68
+ </span>
69
+ </Combobox.Clear>
70
+ <Combobox.Trigger className="ComboboxTrigger" aria-label="Open popup">
71
+ <span className="material-symbols-outlined ComboboxTriggerIcon">
72
+ expand_more
73
+ </span>
74
+ </Combobox.Trigger>
75
+ </div>
76
+ </div>
77
+ </label>
78
+
79
+ <Combobox.Portal>
80
+ <Combobox.Positioner className="ComboboxPositioner" sideOffset={4}>
81
+ <Combobox.Popup className="ComboboxPopup">
82
+ <Combobox.Empty className="ComboboxEmpty">No fruits found.</Combobox.Empty>
83
+ <Combobox.List className="ComboboxList">
84
+ {(item: string) => (
85
+ <Combobox.Item key={item} value={item} className="ComboboxItem">
86
+ <Combobox.ItemIndicator className="ComboboxItemIndicator">
87
+ <span className="material-symbols-outlined ComboboxItemIndicatorIcon">
88
+ check
89
+ </span>
90
+ </Combobox.ItemIndicator>
91
+ <div className="ComboboxItemText">{item}</div>
92
+ </Combobox.Item>
93
+ )}
94
+ </Combobox.List>
95
+ </Combobox.Popup>
96
+ </Combobox.Positioner>
97
+ </Combobox.Portal>
98
+ </Combobox.Root>
99
+ </div>
100
+ );
101
+ },
102
+ };
103
+ ```
104
+
105
+ The preview also shows `MultipleSelect`, `Grouped`, `Creatable`.
@@ -0,0 +1,19 @@
1
+ <!-- @dsCard group="Forms" height=480 subtitle="Default / MultipleSelect / Grouped / Creatable" -->
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 q=Object.create;var V=Object.defineProperty;var ee=Object.getOwnPropertyDescriptor;var oe=Object.getOwnPropertyNames;var ae=Object.getPrototypeOf,te=Object.prototype.hasOwnProperty;var O=(a,t)=>()=>(t||a((t={exports:{}}).exports,t),t.exports),se=(a,t)=>{for(var l in t)V(a,l,{get:t[l],enumerable:!0})},ne=(a,t,l,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let m of oe(t))!te.call(a,m)&&m!==l&&V(a,m,{get:()=>t[m],enumerable:!(r=ee(t,m))||r.enumerable});return a};var U=(a,t,l)=>(l=a!=null?q(ae(a)):{},ne(t||!a||!a.__esModule?V(l,"default",{value:a,enumerable:!0}):l,a));var $=O((he,G)=>{G.exports=window.React});var K=O((Ne,H)=>{H.exports=window.Loomiere.Base});var _=O((fe,W)=>{W.exports=window.Loomiere.Base});var j={};se(j,{AsyncSearchMultiple:()=>Ce,AsyncSearchSingle:()=>pe,Creatable:()=>be,Default:()=>re,Grouped:()=>ie,InputInsidePopup:()=>ue,MultipleSelect:()=>me,default:()=>B});var n=U($(),1),o=U(K(),1),v=U(_(),1);var k=window.React;function e(a,t,l){let{children:r,...m}=t||{};return l!==void 0&&(m.key=l),r===void 0?k.createElement(a,m):Array.isArray(r)?k.createElement(a,m,...r):k.createElement(a,m,r)}var ve=k.Fragment;var Q=["Apple","Banana","Cherry","Date","Elderberry","Fig","Grape","Honeydew","Kiwi","Lemon","Mango","Orange"],le={title:"Components/Combobox",parameters:{layout:"centered"},tags:["autodocs"]},B=le,re={render:()=>{let a=n.useId();return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:Q,children:[e("label",{htmlFor:a,className:"ComboboxLabel",children:["Choose a fruit",e("div",{className:"ComboboxInputWrapper",children:[e(o.Combobox.Input,{placeholder:"e.g. Apple",id:a,className:"ComboboxInput"}),e("div",{className:"ComboboxActionButtons",children:[e(o.Combobox.Clear,{className:"ComboboxClear","aria-label":"Clear selection",children:e("span",{className:"material-symbols-outlined ComboboxClearIcon",children:"close"})}),e(o.Combobox.Trigger,{className:"ComboboxTrigger","aria-label":"Open popup",children:e("span",{className:"material-symbols-outlined ComboboxTriggerIcon",children:"expand_more"})})]})]})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",sideOffset:4,children:e(o.Combobox.Popup,{className:"ComboboxPopup",children:[e(o.Combobox.Empty,{className:"ComboboxEmpty",children:"No fruits found."}),e(o.Combobox.List,{className:"ComboboxList",children:t=>e(o.Combobox.Item,{value:t,className:"ComboboxItem",children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:t})]},t)})]})})})]})})}},me={render:()=>{let a=n.useRef(null),t=n.useId();return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:Q,multiple:!0,children:[e("div",{className:"ComboboxContainer",children:[e("label",{className:"ComboboxLabel",htmlFor:t,children:"Choose fruits"}),e(o.Combobox.Chips,{className:"ComboboxChips",ref:a,children:e(o.Combobox.Value,{children:l=>e(n.Fragment,{children:[l.map(r=>e(o.Combobox.Chip,{className:"ComboboxChip","aria-label":r,children:[r,e(o.Combobox.ChipRemove,{className:"ComboboxChipRemove","aria-label":`Remove ${r}`,children:e("span",{className:"material-symbols-outlined ComboboxChipRemoveIcon",children:"close"})})]},r)),e(o.Combobox.Input,{id:t,placeholder:l.length>0?"":"e.g. Apple",className:"ComboboxInput"})]})})})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",sideOffset:4,anchor:a,children:e(o.Combobox.Popup,{className:"ComboboxPopup",children:[e(o.Combobox.Empty,{className:"ComboboxEmpty",children:"No fruits found."}),e(o.Combobox.List,{className:"ComboboxList",children:l=>e(o.Combobox.Item,{value:l,className:"ComboboxItem",children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:l})]},l)})]})})})]})})}},z=[{category:"Citrus",items:["Lemon","Lime","Orange","Grapefruit"]},{category:"Berries",items:["Strawberry","Blueberry","Raspberry","Blackberry"]},{category:"Tropical",items:["Mango","Pineapple","Papaya","Coconut"]}],ie={render:()=>{let a=n.useId(),t=z.flatMap(l=>l.items);return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:t,children:[e("label",{htmlFor:a,className:"ComboboxLabel",children:["Choose a fruit",e("div",{className:"ComboboxInputWrapper",children:[e(o.Combobox.Input,{placeholder:"Search fruits...",id:a,className:"ComboboxInput"}),e("div",{className:"ComboboxActionButtons",children:[e(o.Combobox.Clear,{className:"ComboboxClear","aria-label":"Clear selection",children:e("span",{className:"material-symbols-outlined ComboboxClearIcon",children:"close"})}),e(o.Combobox.Trigger,{className:"ComboboxTrigger","aria-label":"Open popup",children:e("span",{className:"material-symbols-outlined ComboboxTriggerIcon",children:"expand_more"})})]})]})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",sideOffset:4,children:e(o.Combobox.Popup,{className:"ComboboxPopup",children:[e(o.Combobox.Empty,{className:"ComboboxEmpty",children:"No fruits found."}),z.map((l,r)=>e(n.Fragment,{children:[r>0&&e(o.Combobox.Separator,{className:"ComboboxSeparator"}),e(o.Combobox.Group,{className:"ComboboxGroup",children:[e(o.Combobox.GroupLabel,{className:"ComboboxGroupLabel",children:l.category}),l.items.map(m=>e(o.Combobox.Item,{value:m,className:"ComboboxItem",children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:m})]},m))]})]},l.category))]})})})]})})}},ce=[{id:"bug",value:"bug"},{id:"docs",value:"documentation"},{id:"enhancement",value:"enhancement"},{id:"help-wanted",value:"help wanted"},{id:"good-first-issue",value:"good first issue"}],be={render:()=>{let a=n.useId(),[t,l]=n.useState(ce),[r,m]=n.useState([]),[R,g]=n.useState(""),[f,d]=n.useState(!1),p=n.useRef(null),y=n.useRef(null),h=n.useRef(null),I=n.useRef(""),N=n.useRef(void 0);function D(s){if(s.key!=="Enter"||N.current)return;let c=R.trim();if(c==="")return;let C=c.toLocaleLowerCase(),u=t.find(x=>x.value.trim().toLocaleLowerCase()===C);if(u){m(x=>x.some(F=>F.id===u.id)?x:[...x,u]),g("");return}I.current=c,d(!0)}function L(){let s=y.current||h.current,c=s?s.value.trim():"";if(!c)return;let C=c.toLocaleLowerCase(),u=C.replace(/\s+/g,"-"),x=t.find(b=>b.value.trim().toLocaleLowerCase()===C);if(x){m(b=>b.some(Y=>Y.id===x.id)?b:[...b,x]),d(!1),g("");return}let F=new Set(t.map(b=>b.id)),A=u;if(F.has(A)){let b=2;for(;F.has(`${u}-${b}`);)b+=1;A=`${u}-${b}`}let M={id:A,value:c};r.find(b=>b.id===M.id)||(l(b=>[...b,M]),m(b=>[...b,M])),d(!1),g("")}function P(s){s.preventDefault(),L()}let i=R.trim(),E=i.toLocaleLowerCase(),w=t.some(s=>s.value.trim().toLocaleLowerCase()===E),T=i!==""&&!w?[...t,{creatable:i,id:`create:${E}`,value:`Create "${i}"`}]:t;return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(n.Fragment,{children:[e(o.Combobox.Root,{items:T,multiple:!0,onValueChange:s=>{let c=s.find(u=>u.creatable&&!r.some(x=>x.id===u.id));if(c&&c.creatable){I.current=c.creatable,d(!0);return}let C=s.filter(u=>!u.creatable);m(C),g("")},value:r,inputValue:R,onInputValueChange:g,onItemHighlighted:s=>{N.current=s},children:[e("div",{className:"ComboboxContainer",children:[e("label",{className:"ComboboxLabel",htmlFor:a,children:"Labels"}),e(o.Combobox.Chips,{className:"ComboboxChips",ref:p,children:e(o.Combobox.Value,{children:s=>e(n.Fragment,{children:[s.map(c=>e(o.Combobox.Chip,{className:"ComboboxChip","aria-label":c.value,children:[c.value,e(o.Combobox.ChipRemove,{className:"ComboboxChipRemove","aria-label":"Remove",children:e("span",{className:"material-symbols-outlined ComboboxChipRemoveIcon",children:"close"})})]},c.id)),e(o.Combobox.Input,{ref:h,id:a,placeholder:s.length>0?"":"e.g. bug",className:"ComboboxInput",onKeyDown:D})]})})})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",sideOffset:4,anchor:p,children:e(o.Combobox.Popup,{className:"ComboboxPopup",children:[e(o.Combobox.Empty,{className:"ComboboxEmpty",children:"No labels found."}),e(o.Combobox.List,{className:"ComboboxList",children:s=>s.creatable?e(o.Combobox.Item,{className:"ComboboxItem",value:s,children:[e("span",{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"add"})}),e("div",{className:"ComboboxItemText",children:['Create "',s.creatable,'"']})]},s.id):e(o.Combobox.Item,{className:"ComboboxItem",value:s,children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:s.value})]},s.id)})]})})})]}),e(v.Dialog.Root,{open:f,onOpenChange:d,children:e(v.Dialog.Portal,{children:[e(v.Dialog.Backdrop,{className:"DialogBackdrop"}),e(v.Dialog.Popup,{className:"DialogPopup",initialFocus:y,children:[e(v.Dialog.Title,{className:"DialogTitle",children:"Create new label"}),e(v.Dialog.Description,{className:"DialogDescription",children:"Add a new label to select."}),e("form",{onSubmit:P,children:[e("input",{ref:y,className:"Input",placeholder:"Label name",defaultValue:I.current}),e("div",{className:"DialogActions",children:[e(v.Dialog.Close,{className:"Button","data-variant":"ghost",children:"Cancel"}),e("button",{type:"submit",className:"Button",children:"Create"})]})]})]})]})})]})})}},J=[{code:"",value:null,continent:"",label:"Select country"},{code:"af",value:"afghanistan",label:"Afghanistan",continent:"Asia"},{code:"au",value:"australia",label:"Australia",continent:"Oceania"},{code:"ca",value:"canada",label:"Canada",continent:"North America"},{code:"cn",value:"china",label:"China",continent:"Asia"},{code:"fr",value:"france",label:"France",continent:"Europe"},{code:"de",value:"germany",label:"Germany",continent:"Europe"},{code:"in",value:"india",label:"India",continent:"Asia"},{code:"jp",value:"japan",label:"Japan",continent:"Asia"},{code:"mx",value:"mexico",label:"Mexico",continent:"North America"},{code:"gb",value:"united-kingdom",label:"United Kingdom",continent:"Europe"},{code:"us",value:"united-states",label:"United States",continent:"North America"}],ue={render:()=>e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:J,defaultValue:J[0],children:[e(o.Combobox.Trigger,{className:"ComboboxSelectTrigger",children:[e(o.Combobox.Value,{}),e(o.Combobox.Icon,{className:"ComboboxIcon",children:e("span",{className:"material-symbols-outlined",children:"unfold_more"})})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",align:"start",sideOffset:4,children:e(o.Combobox.Popup,{className:"ComboboxPopup","aria-label":"Select country",children:[e("div",{className:"ComboboxInputContainer",children:e(o.Combobox.Input,{placeholder:"e.g. United Kingdom",className:"ComboboxInput"})}),e(o.Combobox.Empty,{className:"ComboboxEmpty",children:"No countries found."}),e(o.Combobox.List,{className:"ComboboxList",children:a=>e(o.Combobox.Item,{value:a,className:"ComboboxItem",children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:a.label??a.value})]},a.code)})]})})})]})})},de=[{id:"leslie-alexander",name:"Leslie Alexander",username:"leslie",email:"leslie.alexander@example.com",title:"Product Manager"},{id:"kathryn-murphy",name:"Kathryn Murphy",username:"kathryn",email:"kathryn.murphy@example.com",title:"Marketing Lead"},{id:"courtney-henry",name:"Courtney Henry",username:"courtney",email:"courtney.henry@example.com",title:"Design Systems"},{id:"michael-foster",name:"Michael Foster",username:"michael",email:"michael.foster@example.com",title:"Engineering Manager"},{id:"lindsay-walton",name:"Lindsay Walton",username:"lindsay",email:"lindsay.walton@example.com",title:"Product Designer"},{id:"tom-cook",name:"Tom Cook",username:"tom",email:"tom.cook@example.com",title:"Frontend Engineer"},{id:"whitney-francis",name:"Whitney Francis",username:"whitney",email:"whitney.francis@example.com",title:"Customer Success"},{id:"jacob-jones",name:"Jacob Jones",username:"jacob",email:"jacob.jones@example.com",title:"Security Engineer"}];async function Z(a,t){return await new Promise(r=>{setTimeout(r,Math.random()*500+100)}),Math.random()<.01||a==="will_error"?{users:[],error:"Failed to fetch people. Please try again."}:{users:de.filter(r=>t(r.name,a)||t(r.username,a)||t(r.email,a)||t(r.title,a)),error:null}}var pe={render:()=>{let a=n.useId(),[t,l]=n.useState([]),[r,m]=n.useState(null),[R,g]=n.useState(""),[f,d]=n.useState(null),[p,y]=n.useTransition(),{contains:h}=o.Combobox.useFilter(),I=n.useRef(null),N=R.trim(),D=n.useMemo(()=>!r||t.some(i=>i.id===r.id)?t:[...t,r],[t,r]);function L(){return p?e(n.Fragment,{children:[e("span",{className:"ComboboxSpinner","aria-hidden":!0}),"Searching..."]}):f||(N===""?r?null:"Start typing to search people...":t.length===0?`No matches for "${N}".`:null)}function P(){return N===""||p||t.length>0||f?null:"Try a different search term."}return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:D,itemToStringLabel:i=>i.name,filter:null,onOpenChangeComplete:i=>{!i&&r&&l([r])},onValueChange:i=>{m(i),g(""),d(null)},onInputValueChange:(i,{reason:E})=>{g(i);let w=new AbortController;if(I.current?.abort(),I.current=w,i===""){l([]),d(null);return}E!=="item-press"&&y(()=>{(async()=>{d(null);let T=await Z(i,h);w.signal.aborted||y(()=>{l(T.users),d(T.error)})})()})},children:[e("div",{className:"ComboboxLabel",children:[e("label",{htmlFor:a,children:"Assign reviewer"}),e("div",{className:"ComboboxInputWrapper",children:[e(o.Combobox.Input,{id:a,placeholder:"e.g. Michael",className:"ComboboxInput"}),e("div",{className:"ComboboxActionButtons",children:[e(o.Combobox.Clear,{className:"ComboboxClear","aria-label":"Clear selection",children:e("span",{className:"material-symbols-outlined ComboboxClearIcon",children:"close"})}),e(o.Combobox.Trigger,{className:"ComboboxTrigger","aria-label":"Open popup",children:e("span",{className:"material-symbols-outlined ComboboxTriggerIcon",children:"expand_more"})})]})]})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",sideOffset:4,children:e(o.Combobox.Popup,{className:"ComboboxPopup","aria-busy":p||void 0,children:[e(o.Combobox.Status,{className:"ComboboxStatus visually-hidden",children:L()}),e(o.Combobox.Empty,{className:"ComboboxEmpty",children:P()}),e(o.Combobox.List,{className:"ComboboxList",children:i=>e(o.Combobox.Item,{className:"ComboboxItem",value:i,children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:[e("div",{className:"ComboboxItemTitle",children:i.name}),e("div",{className:"ComboboxItemSubtitle",children:[e("span",{className:"ComboboxItemUsername",children:["@",i.username]}),e("span",{children:i.title})]}),e("div",{className:"ComboboxItemEmail",children:i.email})]})]},i.id)})]})})})]})})}},Ce={render:()=>{let a=n.useId(),t=n.useRef(null),[l,r]=n.useState([]),[m,R]=n.useState([]),[g,f]=n.useState(""),[d,p]=n.useState(null),[y,h]=n.useState(!1),[I,N]=n.useTransition(),{contains:D}=o.Combobox.useFilter(),L=n.useRef(null),P=n.useRef([]),i=g.trim(),E=n.useMemo(()=>{if(m.length===0)return l;let s=[...l];return m.forEach(c=>{l.some(C=>C.id===c.id)||s.push(c)}),s},[l,m]);function w(){return I?e(n.Fragment,{children:[e("span",{className:"ComboboxSpinner","aria-hidden":!0}),"Searching..."]}):d||(i===""&&!y?m.length>0?null:"Start typing to search people...":l.length===0&&!y?`No matches for "${i}".`:null)}function T(){return i===""||I||l.length>0||d?null:"Try a different search term."}return e("div",{className:"ComboboxRoot",style:{width:"400px"},children:e(o.Combobox.Root,{items:E,itemToStringLabel:s=>s.name,multiple:!0,filter:null,onOpenChangeComplete:s=>{s||(r(P.current),h(!1))},onValueChange:s=>{P.current=s,R(s),f(""),p(null),s.length===0?(r([]),h(!1)):h(!0)},onInputValueChange:(s,{reason:c})=>{f(s);let C=new AbortController;if(L.current?.abort(),L.current=C,s===""){r(P.current),p(null),h(!1);return}c!=="item-press"&&N(()=>{(async()=>{p(null);let u=await Z(s,D);C.signal.aborted||N(()=>{r(u.users),p(u.error)})})()})},children:[e("div",{className:"ComboboxContainer",children:[e("label",{className:"ComboboxLabel",htmlFor:a,children:"Assign reviewers"}),e(o.Combobox.Chips,{className:"ComboboxChips",ref:t,children:e(o.Combobox.Value,{children:s=>e(n.Fragment,{children:[s.map(c=>e(o.Combobox.Chip,{className:"ComboboxChip","aria-label":c.name,children:[c.name,e(o.Combobox.ChipRemove,{className:"ComboboxChipRemove","aria-label":"Remove",children:e("span",{className:"material-symbols-outlined ComboboxChipRemoveIcon",children:"close"})})]},c.id)),e(o.Combobox.Input,{id:a,placeholder:s.length>0?"":"e.g. Michael",className:"ComboboxInput"})]})})})]}),e(o.Combobox.Portal,{children:e(o.Combobox.Positioner,{className:"ComboboxPositioner",anchor:t,sideOffset:4,children:e(o.Combobox.Popup,{className:"ComboboxPopup","aria-busy":I||void 0,children:[e(o.Combobox.Status,{className:"ComboboxStatus visually-hidden",children:w()}),e(o.Combobox.Empty,{className:"ComboboxEmpty",children:T()}),e(o.Combobox.List,{className:"ComboboxList",children:s=>e(o.Combobox.Item,{className:"ComboboxItem",value:s,children:[e(o.Combobox.ItemIndicator,{className:"ComboboxItemIndicator",children:e("span",{className:"material-symbols-outlined ComboboxItemIndicatorIcon",children:"check"})}),e("div",{className:"ComboboxItemText",children:[e("div",{className:"ComboboxItemTitle",children:s.name}),e("div",{className:"ComboboxItemSubtitle",children:[e("span",{className:"ComboboxItemUsername",children:["@",s.username]}),e("span",{children:s.title})]}),e("div",{className:"ComboboxItemEmail",children:s.email})]})]},s.id)})]})})})]})})}};var S=window.React,X=B||{},xe=["Default","MultipleSelect","Grouped","Creatable"];function ge({id:a}){let t=j[a],l={...X.args||{},...t.args||{}};return(t.render||(m=>S.createElement(X.component,m)))(l,{args:l,id:a,name:a})}var Ie=xe.map(a=>S.createElement("section",{key:a,className:"ds-story"},S.createElement("p",{className:"ds-story-name"},a.replace(/([a-z])([A-Z])/g,"$1 $2")),S.createElement("div",{className:"ds-story-body"},S.createElement(ge,{id:a}))));window.ReactDOM.createRoot(document.getElementById("root")).render(S.createElement(S.Fragment,null,Ie));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,70 @@
1
+ # ContextMenu
2
+
3
+ The Base UI ContextMenu styled by the theme. No component tokens. Opens on right-click; the trigger area only sets the cursor. 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.ContextMenu` (`import { ContextMenu } from '@base-ui/react/context-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/context-menu
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `ContextMenuTrigger` | |
14
+ | `ContextMenuPositioner` | |
15
+ | `ContextMenuPopup` | |
16
+ | `ContextMenuItem` | `data-highlighted`; `data-disabled` |
17
+ | `ContextMenuCheckboxItem` | `data-highlighted`; `data-disabled` |
18
+ | `ContextMenuRadioItem` | `data-highlighted`; `data-disabled`; `data-unchecked` |
19
+ | `ContextMenuSubmenuTrigger` | `data-highlighted`; `data-disabled` |
20
+ | `ContextMenuCheckboxItemIndicator` | |
21
+ | `ContextMenuRadioItemIndicator` | |
22
+ | `ContextMenuCheckboxItemIndicatorIcon` | |
23
+ | `ContextMenuRadioItemIndicatorIcon` | |
24
+ | `ContextMenuGroup` | |
25
+ | `ContextMenuGroupLabel` | |
26
+ | `ContextMenuSeparator` | |
27
+ | `ContextMenuArrow` | |
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 ContextMenu stories (`Default`):
34
+
35
+ ```tsx
36
+ export const Default: Story = {
37
+ render: () => (
38
+ <ContextMenu.Root>
39
+ <ContextMenu.Trigger className="ContextMenuTrigger">
40
+ <div style={{
41
+ width: '300px',
42
+ height: '200px',
43
+ display: 'flex',
44
+ alignItems: 'center',
45
+ justifyContent: 'center',
46
+ border: '2px dashed var(--sl-border-strong)',
47
+ borderRadius: '8px',
48
+ background: 'var(--sl-surface-overlay)',
49
+ cursor: 'context-menu'
50
+ }}>
51
+ Right-click here
52
+ </div>
53
+ </ContextMenu.Trigger>
54
+ <ContextMenu.Portal>
55
+ <ContextMenu.Positioner className="ContextMenuPositioner">
56
+ <ContextMenu.Popup className="ContextMenuPopup">
57
+ <ContextMenu.Item className="ContextMenuItem">Copy</ContextMenu.Item>
58
+ <ContextMenu.Item className="ContextMenuItem">Cut</ContextMenu.Item>
59
+ <ContextMenu.Item className="ContextMenuItem">Paste</ContextMenu.Item>
60
+ <ContextMenu.Separator className="ContextMenuSeparator" />
61
+ <ContextMenu.Item className="ContextMenuItem">Delete</ContextMenu.Item>
62
+ </ContextMenu.Popup>
63
+ </ContextMenu.Positioner>
64
+ </ContextMenu.Portal>
65
+ </ContextMenu.Root>
66
+ ),
67
+ };
68
+ ```
69
+
70
+ 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 R=Object.create;var m=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var y=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var x=(o,n)=>()=>(n||o((n={exports:{}}).exports,n),n.exports),S=(o,n)=>{for(var a in n)m(o,a,{get:n[a],enumerable:!0})},f=(o,n,a,r)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of y(n))!P.call(o,s)&&s!==a&&m(o,s,{get:()=>n[s],enumerable:!(r=N(n,s))||r.enumerable});return o};var C=(o,n,a)=>(a=o!=null?R(k(o)):{},f(n||!o||!o.__esModule?m(a,"default",{value:o,enumerable:!0}):a,o));var p=x((W,I)=>{I.exports=window.React});var h=x((V,M)=>{M.exports=window.Loomiere.Base});var l={};S(l,{Default:()=>w,WithCheckboxes:()=>T,WithDisabledItems:()=>_,WithRadioGroup:()=>E,WithSubmenu:()=>L,default:()=>d});var u=C(p(),1),t=C(h(),1);var i=window.React;function e(o,n,a){let{children:r,...s}=n||{};return a!==void 0&&(s.key=a),r===void 0?i.createElement(o,s):Array.isArray(r)?i.createElement(o,s,...r):i.createElement(o,s,r)}var A=i.Fragment;var v={title:"Components/ContextMenu",component:t.ContextMenu.Root,parameters:{layout:"centered"},tags:["autodocs"]},d=v,w={render:()=>e(t.ContextMenu.Root,{children:[e(t.ContextMenu.Trigger,{className:"ContextMenuTrigger",children:e("div",{style:{width:"300px",height:"200px",display:"flex",alignItems:"center",justifyContent:"center",border:"2px dashed var(--sl-border-strong)",borderRadius:"8px",background:"var(--sl-surface-overlay)",cursor:"context-menu"},children:"Right-click here"})}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:[e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Copy"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Cut"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Paste"}),e(t.ContextMenu.Separator,{className:"ContextMenuSeparator"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Delete"})]})})})]})},T={render:()=>{let[o,n]=u.useState(!1),[a,r]=u.useState(!0),[s,g]=u.useState(!1);return e(t.ContextMenu.Root,{children:[e(t.ContextMenu.Trigger,{className:"ContextMenuTrigger",children:e("div",{style:{width:"300px",height:"200px",display:"flex",alignItems:"center",justifyContent:"center",border:"2px dashed var(--sl-border-strong)",borderRadius:"8px",background:"var(--sl-surface-overlay)",cursor:"context-menu"},children:"Right-click for view options"})}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:[e(t.ContextMenu.CheckboxItem,{className:"ContextMenuCheckboxItem",checked:o,onCheckedChange:n,children:[e(t.ContextMenu.CheckboxItemIndicator,{className:"ContextMenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuCheckboxItemIndicatorIcon",children:"check"})}),"Show toolbar"]}),e(t.ContextMenu.CheckboxItem,{className:"ContextMenuCheckboxItem",checked:a,onCheckedChange:r,children:[e(t.ContextMenu.CheckboxItemIndicator,{className:"ContextMenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuCheckboxItemIndicatorIcon",children:"check"})}),"Show sidebar"]}),e(t.ContextMenu.CheckboxItem,{className:"ContextMenuCheckboxItem",checked:s,onCheckedChange:g,children:[e(t.ContextMenu.CheckboxItemIndicator,{className:"ContextMenuCheckboxItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuCheckboxItemIndicatorIcon",children:"check"})}),"Show footer"]})]})})})]})}},E={render:()=>{let[o,n]=u.useState("light");return e(t.ContextMenu.Root,{children:[e(t.ContextMenu.Trigger,{className:"ContextMenuTrigger",children:e("div",{style:{width:"300px",height:"200px",display:"flex",alignItems:"center",justifyContent:"center",border:"2px dashed var(--sl-border-strong)",borderRadius:"8px",background:"var(--sl-surface-overlay)",cursor:"context-menu"},children:"Right-click to change theme"})}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:e(t.ContextMenu.Group,{className:"ContextMenuGroup",children:[e(t.ContextMenu.GroupLabel,{className:"ContextMenuGroupLabel",children:"Theme"}),e(t.ContextMenu.RadioGroup,{value:o,onValueChange:n,children:[e(t.ContextMenu.RadioItem,{value:"light",className:"ContextMenuRadioItem",children:[e(t.ContextMenu.RadioItemIndicator,{className:"ContextMenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"ContextMenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Light"]}),e(t.ContextMenu.RadioItem,{value:"dark",className:"ContextMenuRadioItem",children:[e(t.ContextMenu.RadioItemIndicator,{className:"ContextMenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"ContextMenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"Dark"]}),e(t.ContextMenu.RadioItem,{value:"system",className:"ContextMenuRadioItem",children:[e(t.ContextMenu.RadioItemIndicator,{className:"ContextMenuRadioItemIndicator",children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",style:{fontVariationSettings:'"FILL" 1'},children:"radio_button_checked"})}),e("span",{className:"ContextMenuRadioItemIndicator","data-unchecked":!0,children:e("span",{className:"material-symbols-outlined ContextMenuRadioItemIndicatorIcon",children:"radio_button_unchecked"})}),"System"]})]})]})})})})]})}},L={render:()=>e(t.ContextMenu.Root,{children:[e(t.ContextMenu.Trigger,{className:"ContextMenuTrigger",children:e("div",{style:{width:"300px",height:"200px",display:"flex",alignItems:"center",justifyContent:"center",border:"2px dashed var(--sl-border-strong)",borderRadius:"8px",background:"var(--sl-surface-overlay)",cursor:"context-menu"},children:"Right-click for nested menu"})}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:[e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"New File"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"New Folder"}),e(t.ContextMenu.Separator,{className:"ContextMenuSeparator"}),e(t.ContextMenu.SubmenuRoot,{children:[e(t.ContextMenu.SubmenuTrigger,{className:"ContextMenuSubmenuTrigger",children:"Share"}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:[e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Email"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Copy Link"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Social Media"})]})})})]})]})})})]})},_={render:()=>e(t.ContextMenu.Root,{children:[e(t.ContextMenu.Trigger,{className:"ContextMenuTrigger",children:e("div",{style:{width:"300px",height:"200px",display:"flex",alignItems:"center",justifyContent:"center",border:"2px dashed var(--sl-border-strong)",borderRadius:"8px",background:"var(--sl-surface-overlay)",cursor:"context-menu"},children:"Right-click here"})}),e(t.ContextMenu.Portal,{children:e(t.ContextMenu.Positioner,{className:"ContextMenuPositioner",children:e(t.ContextMenu.Popup,{className:"ContextMenuPopup",children:[e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Copy"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",disabled:!0,children:"Cut (disabled)"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",disabled:!0,children:"Paste (disabled)"}),e(t.ContextMenu.Separator,{className:"ContextMenuSeparator"}),e(t.ContextMenu.Item,{className:"ContextMenuItem",children:"Delete"})]})})})]})};var c=window.React,b=d||{},F=["Default","WithCheckboxes","WithRadioGroup","WithSubmenu"];function G({id:o}){let n=l[o],a={...b.args||{},...n.args||{}};return(n.render||(s=>c.createElement(b.component,s)))(a,{args:a,id:o,name:o})}var j=F.map(o=>c.createElement("section",{key:o,className:"ds-story"},c.createElement("p",{className:"ds-story-name"},o.replace(/([a-z])([A-Z])/g,"$1 $2")),c.createElement("div",{className:"ds-story-body"},c.createElement(G,{id:o}))));window.ReactDOM.createRoot(document.getElementById("root")).render(c.createElement(c.Fragment,null,j));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,62 @@
1
+ # Dialog
2
+
3
+ The Base UI Dialog styled by the theme. Both are centered modals built from the modal concept (tokens/semantic/modal.json): the modal-surface and modal-backdrop patterns, the maximize-xl heading and base description. Alert dialog shares every rule here; AlertDialog.css adds nothing of its own. Action buttons are plain .Button elements, so they follow the emphasis levels.
4
+
5
+ Use `Loomiere.Dialog` (`import { Dialog } from '@base-ui/react/dialog'` 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/dialog
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `DialogBackdrop` | `data-starting-style`; `data-ending-style` |
14
+ | `AlertDialogBackdrop` | `data-starting-style`; `data-ending-style` |
15
+ | `DialogPopup` | `data-starting-style`; `data-ending-style` |
16
+ | `AlertDialogPopup` | `data-starting-style`; `data-ending-style` |
17
+ | `DialogClose` | |
18
+ | `DialogTitle` | |
19
+ | `AlertDialogTitle` | |
20
+ | `DialogDescription` | |
21
+ | `AlertDialogDescription` | |
22
+ | `DialogContent` | |
23
+ | `Form` | |
24
+ | `DialogActions` | |
25
+ | `AlertDialogActions` | |
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 Dialog stories (`Default`):
32
+
33
+ ```tsx
34
+ export const Default: Story = {
35
+ render: () => (
36
+ <Dialog.Root>
37
+ <Dialog.Trigger className="Button">
38
+ Open Dialog
39
+ </Dialog.Trigger>
40
+ <Dialog.Portal>
41
+ <Dialog.Backdrop className="DialogBackdrop" />
42
+ <Dialog.Popup className="DialogPopup">
43
+ <Dialog.Title className="DialogTitle">Dialog Title</Dialog.Title>
44
+ <Dialog.Description className="DialogDescription">
45
+ This is a description of the dialog. It provides context about what the dialog is for.
46
+ </Dialog.Description>
47
+ <div className="DialogActions">
48
+ <Dialog.Close className="Button" data-variant="ghost">
49
+ Cancel
50
+ </Dialog.Close>
51
+ <Dialog.Close className="Button">
52
+ Confirm
53
+ </Dialog.Close>
54
+ </div>
55
+ </Dialog.Popup>
56
+ </Dialog.Portal>
57
+ </Dialog.Root>
58
+ ),
59
+ };
60
+ ```
61
+
62
+ The preview also shows `WithForm`, `Nested`, `LongContent`.
@@ -0,0 +1,19 @@
1
+ <!-- @dsCard group="Overlays" height=480 subtitle="Default / WithForm / Nested / LongContent" -->
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 C=Object.create;var c=Object.defineProperty;var P=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,B=Object.prototype.hasOwnProperty;var d=(a,t)=>()=>(t||a((t={exports:{}}).exports,t),t.exports),R=(a,t)=>{for(var i in t)c(a,i,{get:t[i],enumerable:!0})},b=(a,t,i,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let l of h(t))!B.call(a,l)&&l!==i&&c(a,l,{get:()=>t[l],enumerable:!(s=P(t,l))||s.enumerable});return a};var u=(a,t,i)=>(i=a!=null?C(y(a)):{},b(t||!a||!a.__esModule?c(i,"default",{value:a,enumerable:!0}):i,a));var N=d((I,D)=>{D.exports=window.React});var f=d((L,v)=>{v.exports=window.Loomiere.Base});var g={};R(g,{Default:()=>F,LongContent:()=>E,Nested:()=>q,WithForm:()=>S,default:()=>p});var m=u(N(),1),e=u(f(),1);var n=window.React;function o(a,t,i){let{children:s,...l}=t||{};return i!==void 0&&(l.key=i),s===void 0?n.createElement(a,l):Array.isArray(s)?n.createElement(a,l,...s):n.createElement(a,l,s)}var j=n.Fragment;var x={title:"Components/Dialog",component:e.Dialog.Root,parameters:{layout:"centered"},tags:["autodocs"]},p=x,F={render:()=>o(e.Dialog.Root,{children:[o(e.Dialog.Trigger,{className:"Button",children:"Open Dialog"}),o(e.Dialog.Portal,{children:[o(e.Dialog.Backdrop,{className:"DialogBackdrop"}),o(e.Dialog.Popup,{className:"DialogPopup",children:[o(e.Dialog.Title,{className:"DialogTitle",children:"Dialog Title"}),o(e.Dialog.Description,{className:"DialogDescription",children:"This is a description of the dialog. It provides context about what the dialog is for."}),o("div",{className:"DialogActions",children:[o(e.Dialog.Close,{className:"Button","data-variant":"ghost",children:"Cancel"}),o(e.Dialog.Close,{className:"Button",children:"Confirm"})]})]})]})]})},S={render:()=>{let a=m.useId(),t=m.useId(),i=s=>{s.preventDefault(),console.log("Form submitted")};return o(e.Dialog.Root,{children:[o(e.Dialog.Trigger,{className:"Button",children:"Open Form Dialog"}),o(e.Dialog.Portal,{children:[o(e.Dialog.Backdrop,{className:"DialogBackdrop"}),o(e.Dialog.Popup,{className:"DialogPopup",children:[o(e.Dialog.Title,{className:"DialogTitle",children:"Contact Information"}),o(e.Dialog.Description,{className:"DialogDescription",children:"Please provide your contact details."}),o("form",{className:"Form",onSubmit:i,children:[o("div",{className:"FieldRoot",children:[o("label",{htmlFor:a,className:"FieldLabel",children:"Name"}),o("input",{id:a,type:"text",className:"FieldControl",placeholder:"John Doe"})]}),o("div",{className:"FieldRoot",children:[o("label",{htmlFor:t,className:"FieldLabel",children:"Email"}),o("input",{id:t,type:"email",className:"FieldControl",placeholder:"you@example.com"})]})]}),o("div",{className:"DialogActions",children:[o(e.Dialog.Close,{className:"Button","data-variant":"ghost",children:"Cancel"}),o(e.Dialog.Close,{className:"Button",children:"Submit"})]})]})]})]})}},q={render:()=>o(e.Dialog.Root,{children:[o(e.Dialog.Trigger,{className:"Button",children:"Open First Dialog"}),o(e.Dialog.Portal,{children:[o(e.Dialog.Backdrop,{className:"DialogBackdrop"}),o(e.Dialog.Popup,{className:"DialogPopup",children:[o(e.Dialog.Title,{className:"DialogTitle",children:"First Dialog"}),o(e.Dialog.Description,{className:"DialogDescription",children:"This is the first dialog. You can open another dialog from here."}),o("div",{className:"DialogActions",children:[o(e.Dialog.Root,{children:[o(e.Dialog.Trigger,{className:"Button","data-variant":"outline",children:"Open Second Dialog"}),o(e.Dialog.Portal,{children:[o(e.Dialog.Backdrop,{className:"DialogBackdrop"}),o(e.Dialog.Popup,{className:"DialogPopup",children:[o(e.Dialog.Title,{className:"DialogTitle",children:"Second Dialog"}),o(e.Dialog.Description,{className:"DialogDescription",children:"This is a nested dialog opened from the first one."}),o("div",{className:"DialogActions",children:o(e.Dialog.Close,{className:"Button",children:"Close"})})]})]})]}),o(e.Dialog.Close,{className:"Button","data-variant":"ghost",children:"Close"})]})]})]})]})},E={render:()=>o(e.Dialog.Root,{children:[o(e.Dialog.Trigger,{className:"Button",children:"Open Long Dialog"}),o(e.Dialog.Portal,{children:[o(e.Dialog.Backdrop,{className:"DialogBackdrop"}),o(e.Dialog.Popup,{className:"DialogPopup",children:[o(e.Dialog.Title,{className:"DialogTitle",children:"Terms and Conditions"}),o(e.Dialog.Description,{className:"DialogDescription",children:"Please read and accept our terms and conditions."}),o("div",{className:"DialogContent",children:[o("p",{children:"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."}),o("p",{children:"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."}),o("p",{children:"Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."}),o("p",{children:"Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt."})]}),o("div",{className:"DialogActions",children:[o(e.Dialog.Close,{className:"Button","data-variant":"ghost",children:"Decline"}),o(e.Dialog.Close,{className:"Button",children:"Accept"})]})]})]})]})};var r=window.React,T=p||{},k=["Default","WithForm","Nested","LongContent"];function w({id:a}){let t=g[a],i={...T.args||{},...t.args||{}};return(t.render||(l=>r.createElement(T.component,l)))(i,{args:i,id:a,name:a})}var A=k.map(a=>r.createElement("section",{key:a,className:"ds-story"},r.createElement("p",{className:"ds-story-name"},a.replace(/([a-z])([A-Z])/g,"$1 $2")),r.createElement("div",{className:"ds-story-body"},r.createElement(w,{id:a}))));window.ReactDOM.createRoot(document.getElementById("root")).render(r.createElement(r.Fragment,null,A));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,32 @@
1
+ # Drawer
2
+
3
+ The Base UI Drawer styled by the theme. The surface, scrim, heading and motion are the modal concept's (--sl-modal-*), so a drawer reads as a dialog's sibling; only its size and grab bar are its own (--sl-drawer-*). Base UI supplies the swipe through --drawer-swipe-movement-x/y and data-swipe-direction on the popup.
4
+
5
+ Use `Loomiere.Drawer` (`import { Drawer } from '@base-ui/react/drawer'` 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/drawer
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `DrawerBackdrop` | `data-starting-style`; `data-ending-style` |
14
+ | `DrawerViewport` | |
15
+ | `DrawerPopup` | `data-swipe-direction`: `down`, `up`, `right`, `left`; `data-starting-style`; `data-ending-style`; `data-swiping` |
16
+ | `DrawerContent` | |
17
+ | `DrawerTitle` | |
18
+ | `DrawerDescription` | |
19
+
20
+ 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.
21
+
22
+ ## Example
23
+
24
+ From the Drawer stories (`Default`):
25
+
26
+ ```tsx
27
+ export const Default: Story = {
28
+ render: () => <Panel side="down" />,
29
+ };
30
+ ```
31
+
32
+ The preview also shows `Sides`.
@@ -0,0 +1,19 @@
1
+ <!-- @dsCard group="Overlays" height=240 subtitle="Default / Sides" -->
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 p=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var g=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,h=Object.prototype.hasOwnProperty;var N=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),R=(e,t)=>{for(var o in t)p(e,o,{get:t[o],enumerable:!0})},S=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of g(t))!h.call(e,a)&&a!==o&&p(e,a,{get:()=>t[a],enumerable:!(n=f(t,a))||n.enumerable});return e};var x=(e,t,o)=>(o=e!=null?y(E(e)):{},S(t||!e||!e.__esModule?p(o,"default",{value:e,enumerable:!0}):o,e));var w=N((j,d)=>{d.exports=window.Loomiere.Base});var m={};R(m,{Default:()=>B,Sides:()=>b,default:()=>i});var s=x(w(),1);var l=window.React;function r(e,t,o){let{children:n,...a}=t||{};return o!==void 0&&(a.key=o),n===void 0?l.createElement(e,a):Array.isArray(n)?l.createElement(e,a,...n):l.createElement(e,a,n)}var V=l.Fragment;var T={title:"Components/Drawer",component:s.Drawer.Root,parameters:{layout:"centered"},tags:["autodocs"]},i=T,D=({side:e})=>r(s.Drawer.Root,{swipeDirection:e,children:[r(s.Drawer.Trigger,{className:"Button","data-emphasis":"standard",children:[e==="down"?"Bottom":e==="up"?"Top":e==="left"?"Left":"Right"," drawer"]}),r(s.Drawer.Portal,{children:[r(s.Drawer.Backdrop,{className:"DrawerBackdrop"}),r(s.Drawer.Viewport,{className:"DrawerViewport",children:r(s.Drawer.Popup,{className:"DrawerPopup",children:[r(s.Drawer.Title,{className:"DrawerTitle",children:"Trail notes"}),r(s.Drawer.Description,{className:"DrawerDescription",children:"Swipe it away, press Escape, or use the button."}),r(s.Drawer.Content,{className:"DrawerContent",children:r("p",{children:"Three sites logged at dusk. Wind from the southwest, sand moving east."})}),r(s.Drawer.Close,{className:"Button","data-emphasis":"bold",children:"Done"})]})})]})]}),B={render:()=>r(D,{side:"down"})},b={render:()=>r("div",{style:{display:"flex",gap:"var(--sl-space-2)"},children:["down","right","left","up"].map(e=>r(D,{side:e},e))})};var c=window.React,u=i||{},k=["Default","Sides"];function C({id:e}){let t=m[e],o={...u.args||{},...t.args||{}};return(t.render||(a=>c.createElement(u.component,a)))(o,{args:o,id:e,name:e})}var P=k.map(e=>c.createElement("section",{key:e,className:"ds-story"},c.createElement("p",{className:"ds-story-name"},e.replace(/([a-z])([A-Z])/g,"$1 $2")),c.createElement("div",{className:"ds-story-body"},c.createElement(C,{id:e}))));window.ReactDOM.createRoot(document.getElementById("root")).render(c.createElement(c.Fragment,null,P));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>
@@ -0,0 +1,41 @@
1
+ # Field
2
+
3
+ The Base UI Field styled by the theme. Label, control, description and error. No component tokens: spacing is the field concept (tokens/semantic/field.json) and text is whole text styles. Field.Control is styled with Input (Input.css). Number field's label, description and error are the same parts, so they share these rules.
4
+
5
+ Use `Loomiere.Field`, this package's wrapper: it puts the class names on for you (`import { Field } from '@scattered-light/loomiere-base-ui'` in an app). The bare Base UI part is `Loomiere.Base.Field`.
6
+
7
+ Base UI docs: https://base-ui.com/react/components/field
8
+
9
+ ## Classes
10
+
11
+ | Class | Data attributes it answers to |
12
+ |---|---|
13
+ | `FieldRoot` | `data-disabled` |
14
+ | `FieldLabel` | |
15
+ | `NumberFieldLabel` | |
16
+ | `FieldDescription` | |
17
+ | `NumberFieldDescription` | |
18
+ | `FieldError` | |
19
+ | `NumberFieldError` | |
20
+ | `FieldControl` | |
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 Field stories (`Default`):
27
+
28
+ ```tsx
29
+ export const Default: Story = {
30
+ render: () => (
31
+ <div style={{ width: '400px' }}>
32
+ <Field.Root name="email">
33
+ <Field.Label>Email address</Field.Label>
34
+ <Field.Control type="email" placeholder="you@example.com" />
35
+ </Field.Root>
36
+ </div>
37
+ ),
38
+ };
39
+ ```
40
+
41
+ The preview also shows `WithDescription`, `WithError`, `Required`.
@@ -0,0 +1,19 @@
1
+ <!-- @dsCard group="Forms" height=480 subtitle="Default / WithDescription / WithError / Required" -->
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 d=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var b=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var f=(t,r)=>()=>(r||t((r={exports:{}}).exports,r),r.exports),E=(t,r)=>{for(var a in r)d(t,a,{get:r[a],enumerable:!0})},w=(t,r,a,l)=>{if(r&&typeof r=="object"||typeof r=="function")for(let n of b(r))!R.call(t,n)&&n!==a&&d(t,n,{get:()=>r[n],enumerable:!(l=h(r,n))||l.enumerable});return t};var v=(t,r,a)=>(a=t!=null?x(F(t)):{},w(r||!t||!t.__esModule?d(a,"default",{value:t,enumerable:!0}):a,t));var y=f((O,p)=>{p.exports=window.Loomiere});var m={};E(m,{Default:()=>L,Disabled:()=>j,Required:()=>C,Textarea:()=>M,WithDescription:()=>g,WithError:()=>S,default:()=>c});var o=v(y(),1);var i=window.React;function e(t,r,a){let{children:l,...n}=r||{};return a!==void 0&&(n.key=a),l===void 0?i.createElement(t,n):Array.isArray(l)?i.createElement(t,n,...l):i.createElement(t,n,l)}var U=i.Fragment;var D={title:"Components/Lib/Field",parameters:{layout:"centered"},tags:["autodocs","ds:lib"]},c=D,L={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"email",children:[e(o.Field.Label,{children:"Email address"}),e(o.Field.Control,{type:"email",placeholder:"you@example.com"})]})})},g={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"username",children:[e(o.Field.Label,{children:"Username"}),e(o.Field.Control,{type:"text",placeholder:"johndoe"}),e(o.Field.Description,{children:"Choose a unique username for your account"})]})})},S={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"username",invalid:!0,children:[e(o.Field.Label,{children:"Username"}),e(o.Field.Control,{type:"text",placeholder:"johndoe","aria-invalid":"true",defaultValue:"john"}),e(o.Field.Error,{children:"Username must be at least 5 characters"})]})})},C={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"fullName",children:[e(o.Field.Label,{children:["Full name ",e("span",{style:{color:"var(--sl-status-warning)"},children:"*"})]}),e(o.Field.Control,{type:"text",placeholder:"John Doe",required:!0})]})})},j={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"email",disabled:!0,children:[e(o.Field.Label,{children:"Email address"}),e(o.Field.Control,{type:"email",placeholder:"you@example.com",disabled:!0}),e(o.Field.Description,{children:"This field is currently disabled"})]})})},M={render:()=>e("div",{style:{width:"400px"},children:e(o.Field.Root,{name:"message",children:[e(o.Field.Label,{children:"Message"}),e(o.Field.Control,{render:e("textarea",{rows:4,placeholder:"Enter your message..."})}),e(o.Field.Description,{children:"Maximum 500 characters"})]})})};var s=window.React,u=c||{},q=["Default","WithDescription","WithError","Required"];function N({id:t}){let r=m[t],a={...u.args||{},...r.args||{}};return(r.render||(n=>s.createElement(u.component,n)))(a,{args:a,id:t,name:t})}var W=q.map(t=>s.createElement("section",{key:t,className:"ds-story"},s.createElement("p",{className:"ds-story-name"},t.replace(/([a-z])([A-Z])/g,"$1 $2")),s.createElement("div",{className:"ds-story-body"},s.createElement(N,{id:t}))));window.ReactDOM.createRoot(document.getElementById("root")).render(s.createElement(s.Fragment,null,W));})();
16
+
17
+ </script>
18
+ </body>
19
+ </html>