@greypan/web-ui 3.0.1 → 4.0.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 (184) hide show
  1. package/README.CN.md +292 -31
  2. package/README.md +294 -31
  3. package/dist/_virtual/{_@oxc-project_runtime@0.140.0 → _@oxc-project_runtime@0.146.0}/helpers/esm/decorate.js +1 -1
  4. package/dist/assets/glass.js +1 -1
  5. package/dist/assets/glass.js.map +1 -1
  6. package/dist/assets/menu-portal.js +1 -1
  7. package/dist/assets/menu-portal.js.map +1 -1
  8. package/dist/assets/overlay-motion.js +1 -1
  9. package/dist/assets/overlay-motion.js.map +1 -1
  10. package/dist/assets/toast-containers.js +1 -1
  11. package/dist/assets/toast-containers.js.map +1 -1
  12. package/dist/components/autocomplete/index.d.ts +4 -12
  13. package/dist/components/autocomplete/index.js +95 -102
  14. package/dist/components/autocomplete/index.js.map +1 -1
  15. package/dist/components/autocomplete/style.js +1 -1
  16. package/dist/components/autocomplete/style.js.map +1 -1
  17. package/dist/components/avatar/index.d.ts +0 -1
  18. package/dist/components/avatar/index.js +8 -13
  19. package/dist/components/avatar/index.js.map +1 -1
  20. package/dist/components/back-top/index.js +1 -1
  21. package/dist/components/back-top/style.js +1 -1
  22. package/dist/components/back-top/style.js.map +1 -1
  23. package/dist/components/badge/index.d.ts +1 -0
  24. package/dist/components/badge/index.js +12 -14
  25. package/dist/components/badge/index.js.map +1 -1
  26. package/dist/components/button/index.d.ts +2 -0
  27. package/dist/components/button/index.js +51 -38
  28. package/dist/components/button/index.js.map +1 -1
  29. package/dist/components/button/style.js +1 -1
  30. package/dist/components/button/style.js.map +1 -1
  31. package/dist/components/button-group/index.d.ts +1 -2
  32. package/dist/components/button-group/index.js +19 -23
  33. package/dist/components/button-group/index.js.map +1 -1
  34. package/dist/components/checkbox/index.d.ts +4 -7
  35. package/dist/components/checkbox/index.js +48 -37
  36. package/dist/components/checkbox/index.js.map +1 -1
  37. package/dist/components/checkbox/style.js +1 -1
  38. package/dist/components/checkbox/style.js.map +1 -1
  39. package/dist/components/checkbox-group/index.d.ts +4 -10
  40. package/dist/components/checkbox-group/index.js +74 -60
  41. package/dist/components/checkbox-group/index.js.map +1 -1
  42. package/dist/components/context-menu/index.js +7 -8
  43. package/dist/components/context-menu/index.js.map +1 -1
  44. package/dist/components/dialog/index.js +6 -6
  45. package/dist/components/dialog/index.js.map +1 -1
  46. package/dist/components/dialog/style.js +1 -1
  47. package/dist/components/dialog/style.js.map +1 -1
  48. package/dist/components/drawer/index.d.ts +15 -0
  49. package/dist/components/drawer/index.js +58 -34
  50. package/dist/components/drawer/index.js.map +1 -1
  51. package/dist/components/drawer/style.js +1 -1
  52. package/dist/components/drawer/style.js.map +1 -1
  53. package/dist/components/dropdown/index.js +1 -1
  54. package/dist/components/dropdown-divider/index.js +1 -1
  55. package/dist/components/dropdown-header/index.js +1 -1
  56. package/dist/components/dropdown-header/style.js +1 -1
  57. package/dist/components/dropdown-header/style.js.map +1 -1
  58. package/dist/components/dropdown-item/index.js +3 -2
  59. package/dist/components/dropdown-item/index.js.map +1 -1
  60. package/dist/components/empty/index.js +1 -1
  61. package/dist/components/empty/style.js +1 -1
  62. package/dist/components/empty/style.js.map +1 -1
  63. package/dist/components/icon/index.js +1 -1
  64. package/dist/components/index.js +9 -9
  65. package/dist/components/input/index.d.ts +2 -3
  66. package/dist/components/input/index.js +62 -52
  67. package/dist/components/input/index.js.map +1 -1
  68. package/dist/components/input/style.js +1 -1
  69. package/dist/components/input/style.js.map +1 -1
  70. package/dist/components/input-number/index.d.ts +2 -3
  71. package/dist/components/input-number/index.js +58 -38
  72. package/dist/components/input-number/index.js.map +1 -1
  73. package/dist/components/input-number/style.js +1 -1
  74. package/dist/components/input-number/style.js.map +1 -1
  75. package/dist/components/layout/index.d.ts +53 -3
  76. package/dist/components/layout/index.js +146 -39
  77. package/dist/components/layout/index.js.map +1 -1
  78. package/dist/components/layout/style.js +1 -1
  79. package/dist/components/layout/style.js.map +1 -1
  80. package/dist/components/option/index.js +1 -1
  81. package/dist/components/option/style.js +1 -1
  82. package/dist/components/option/style.js.map +1 -1
  83. package/dist/components/popover/index.js +7 -5
  84. package/dist/components/popover/index.js.map +1 -1
  85. package/dist/components/popover/style.js +1 -1
  86. package/dist/components/popover/style.js.map +1 -1
  87. package/dist/components/radio/index.d.ts +4 -7
  88. package/dist/components/radio/index.js +48 -37
  89. package/dist/components/radio/index.js.map +1 -1
  90. package/dist/components/radio/style.js +1 -1
  91. package/dist/components/radio/style.js.map +1 -1
  92. package/dist/components/radio-group/index.d.ts +4 -10
  93. package/dist/components/radio-group/index.js +70 -52
  94. package/dist/components/radio-group/index.js.map +1 -1
  95. package/dist/components/segmented/index.d.ts +6 -11
  96. package/dist/components/segmented/index.js +67 -55
  97. package/dist/components/segmented/index.js.map +1 -1
  98. package/dist/components/segmented/style.js +1 -1
  99. package/dist/components/segmented/style.js.map +1 -1
  100. package/dist/components/segmented-trigger/index.d.ts +1 -2
  101. package/dist/components/segmented-trigger/index.js +18 -19
  102. package/dist/components/segmented-trigger/index.js.map +1 -1
  103. package/dist/components/segmented-trigger/style.js +1 -1
  104. package/dist/components/segmented-trigger/style.js.map +1 -1
  105. package/dist/components/select/index.d.ts +13 -8
  106. package/dist/components/select/index.js +110 -75
  107. package/dist/components/select/index.js.map +1 -1
  108. package/dist/components/select/style.js +1 -1
  109. package/dist/components/select/style.js.map +1 -1
  110. package/dist/components/slider/index.d.ts +3 -5
  111. package/dist/components/slider/index.js +59 -42
  112. package/dist/components/slider/index.js.map +1 -1
  113. package/dist/components/slider/style.js +1 -1
  114. package/dist/components/slider/style.js.map +1 -1
  115. package/dist/components/spinner/index.d.ts +0 -2
  116. package/dist/components/spinner/index.js +14 -13
  117. package/dist/components/spinner/index.js.map +1 -1
  118. package/dist/components/spinner/style.js +1 -1
  119. package/dist/components/spinner/style.js.map +1 -1
  120. package/dist/components/svg-draw-lines/index.js +1 -1
  121. package/dist/components/switch/index.d.ts +5 -6
  122. package/dist/components/switch/index.js +51 -37
  123. package/dist/components/switch/index.js.map +1 -1
  124. package/dist/components/switch/style.js +1 -1
  125. package/dist/components/switch/style.js.map +1 -1
  126. package/dist/components/textarea/index.d.ts +5 -6
  127. package/dist/components/textarea/index.js +73 -63
  128. package/dist/components/textarea/index.js.map +1 -1
  129. package/dist/components/textarea/style.js +1 -1
  130. package/dist/components/textarea/style.js.map +1 -1
  131. package/dist/components/theme/index.js +1 -1
  132. package/dist/components/theme/style.js +1 -1
  133. package/dist/components/theme/style.js.map +1 -1
  134. package/dist/components/toast/style.js +1 -1
  135. package/dist/components/toast/style.js.map +1 -1
  136. package/dist/components/toast/toast.js +12 -12
  137. package/dist/components/toast/toast.js.map +1 -1
  138. package/dist/components/tooltip/index.js +1 -1
  139. package/dist/components/tooltip/style.js +1 -1
  140. package/dist/components/tooltip/style.js.map +1 -1
  141. package/dist/icons/generated/lucide-clapperboard.d.ts +6 -0
  142. package/dist/icons/generated/lucide-clapperboard.js +10 -0
  143. package/dist/icons/generated/lucide-clapperboard.js.map +1 -0
  144. package/dist/icons/generated/lucide-eye.d.ts +6 -0
  145. package/dist/icons/generated/lucide-eye.js +10 -0
  146. package/dist/icons/generated/lucide-eye.js.map +1 -0
  147. package/dist/icons/generated/lucide-headphones.d.ts +6 -0
  148. package/dist/icons/generated/lucide-headphones.js +10 -0
  149. package/dist/icons/generated/lucide-headphones.js.map +1 -0
  150. package/dist/icons/generated/lucide-link.d.ts +6 -0
  151. package/dist/icons/generated/lucide-link.js +10 -0
  152. package/dist/icons/generated/lucide-link.js.map +1 -0
  153. package/dist/icons/generated/lucide-pen-line.d.ts +6 -0
  154. package/dist/icons/generated/lucide-pen-line.js +10 -0
  155. package/dist/icons/generated/lucide-pen-line.js.map +1 -0
  156. package/dist/icons/generated/lucide-play.d.ts +6 -0
  157. package/dist/icons/generated/lucide-play.js +10 -0
  158. package/dist/icons/generated/lucide-play.js.map +1 -0
  159. package/dist/icons/generated/lucide-sliders-horizontal.d.ts +6 -0
  160. package/dist/icons/generated/lucide-sliders-horizontal.js +10 -0
  161. package/dist/icons/generated/lucide-sliders-horizontal.js.map +1 -0
  162. package/dist/icons/index.d.ts +7 -0
  163. package/dist/icons/index.js +8 -1
  164. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js +1 -3
  165. package/dist/node_modules/.pnpm/@floating-ui_core@1.8.0/node_modules/@floating-ui/core/dist/floating-ui.core.js.map +1 -1
  166. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js +2 -1
  167. package/dist/node_modules/.pnpm/@floating-ui_utils@0.2.12/node_modules/@floating-ui/utils/dist/floating-ui.utils.dom.js.map +1 -1
  168. package/dist/shared/events/user-change.js.map +1 -1
  169. package/dist/shared/form-association/index.js +41 -0
  170. package/dist/shared/form-association/index.js.map +1 -0
  171. package/dist/shared/group-management/index.js +109 -0
  172. package/dist/shared/group-management/index.js.map +1 -0
  173. package/dist/shared/menu-portal/menu-tree.js +20 -7
  174. package/dist/shared/menu-portal/menu-tree.js.map +1 -1
  175. package/dist/shared/option-portal/index.js +65 -0
  176. package/dist/shared/option-portal/index.js.map +1 -0
  177. package/dist/shared/overlay/overlay.js +1 -1
  178. package/dist/shared/overlay/overlay.js.map +1 -1
  179. package/dist/shared/overlay/portal.js +9 -6
  180. package/dist/shared/overlay/portal.js.map +1 -1
  181. package/dist/shared/overlay/presence.js.map +1 -1
  182. package/dist/shared/visible-area/index.js +69 -0
  183. package/dist/shared/visible-area/index.js.map +1 -0
  184. package/package.json +6 -4
package/README.md CHANGED
@@ -31,6 +31,30 @@ import '@greypan/web-ui'
31
31
 
32
32
  ## Framework Setup
33
33
 
34
+ ### Cross-framework API conventions
35
+
36
+ `web-ui-*` elements expose three surfaces. The **DOM / JavaScript API is the source of truth**: Properties use
37
+ camelCase, Attributes use kebab-case, Events use kebab-case.
38
+
39
+ | Surface | Naming | Examples |
40
+ | --------- | ---------- | --------------------------------------------- |
41
+ | Property | camelCase | `open`, `sidebarCollapsed`, `noScrollLock` |
42
+ | Attribute | kebab-case | `open`, `sidebar-collapsed`, `no-scroll-lock` |
43
+ | Event | kebab-case | `open-change`, `sidebar-collapsed-change` |
44
+
45
+ - **Boolean attributes** follow native HTML presence semantics: absent → `false`, presence → `true`. A framework
46
+ binding that writes `disabled="false"` produces the string `"false"`, which is truthy — **bind dynamic booleans as
47
+ properties** (camelCase), not attributes, so `false` is written as a real property.
48
+ - **Vue**: dynamic binding must go to **Properties** with camelCase names (`:sidebarCollapsed="x"`, `:open="x"`).
49
+ A kebab-case binding like `:sidebar-collapsed="x"` is written as a string attribute and cannot express `false`;
50
+ use the camelCase property. The `.prop` modifier is only valid with the camelCase name
51
+ (`:sidebarCollapsed.prop="x"`). String/number values may stay on kebab-case attributes (`:max-height="120"`).
52
+ `v-model` is supported on value-bearing controls (`web-ui-input`, `web-ui-select`, `web-ui-autocomplete`, …) and
53
+ compiles to the element `value` property + `input` event.
54
+ - **React**: React 19 writes DOM properties for custom-element props, so use camelCase props (`open={open}`,
55
+ `noScrollLock`, `value={value}`). Never pass complex data (objects, arrays) through attribute strings — bind
56
+ them as properties. Kebab-case JSX props on a custom element are written as attributes.
57
+
34
58
  ### React
35
59
 
36
60
  Requires `@types/react >= 19` as optional peer dependency.
@@ -129,6 +153,21 @@ import '@greypan/web-ui/types/vue'
129
153
  </template>
130
154
  ```
131
155
 
156
+ Boolean properties must be bound with the **camelCase property name**, not the kebab-case attribute. Vue writes
157
+ attribute bindings as strings, and boolean attributes follow presence semantics — so `:sidebar-collapsed="false"`
158
+ produces the string `"false"`, which is truthy. Binding the camelCase name (`:sidebarCollapsed="false"`, or the
159
+ `.prop` modifier) makes Vue write the DOM property directly:
160
+
161
+ ```vue
162
+ <web-ui-layout
163
+ header-glow
164
+ :sidebarCollapsed="sidebarCollapsed"
165
+ :sidebarOpen="sidebarOpen"
166
+ @sidebar-collapsed-change="sidebarCollapsed = $event.detail.collapsed"
167
+ @sidebar-open-change="sidebarOpen = $event.detail.open"
168
+ />
169
+ ```
170
+
132
171
  Vue events are typed cast-free: `@input`/`@change` on value-bearing components resolve to the component emit, so
133
172
  `$event.target` is the component instance and `value`/`checked` are read directly. `$event.detail` keeps the
134
173
  `CustomEvent` payload type for kebab-case events like `open-change`. Named handlers annotate with
@@ -148,6 +187,10 @@ Components own their role and interaction state. Browser-native composed events
148
187
  remain the primary interaction API. Kebab-case custom events such as `open-change` describe user-originated component
149
188
  state changes; assigning a property programmatically does not emit them.
150
189
 
190
+ ### Form-associated controls
191
+
192
+ All form controls participate in native `FormData`, constraint validation, `form.reset()` and browser form-state restoration. The control captures its reset default once, after declarative attributes have been applied on its first connection. Later runtime property updates do not redefine that default. A disabled ancestor `fieldset` disables validation and interaction without mutating the control's public `disabled` property. For checkbox/radio groups, the group is the single submission, reset and restoration owner; managed child controls do not submit or restore an independent state.
193
+
151
194
  ## All Components
152
195
 
153
196
  | Category | Component |
@@ -216,6 +259,12 @@ Text input with clearable, prefix/suffix slots.
216
259
 
217
260
  **Slots:** `prefix`, `default`, `suffix`
218
261
 
262
+ **CSS Custom Properties:**
263
+
264
+ | Property | Default | Description |
265
+ | ------------------------- | -------------------------------- | ------------------ |
266
+ | `--wui-input-clear-color` | `var(--wui-color-text-tertiary)` | Clear button color |
267
+
219
268
  #### `<web-ui-textarea>`
220
269
 
221
270
  Multi-line text input with auto-resize.
@@ -245,6 +294,13 @@ Multi-line text input with auto-resize.
245
294
 
246
295
  **Slots:** `prefix`, `suffix`
247
296
 
297
+ **CSS Custom Properties:**
298
+
299
+ | Property | Default | Description |
300
+ | ---------------------------- | -------------------------------- | ------------------ |
301
+ | `--wui-textarea-width` | `200px` | Textarea width |
302
+ | `--wui-textarea-clear-color` | `var(--wui-color-text-tertiary)` | Clear button color |
303
+
248
304
  #### `<web-ui-input-number>`
249
305
 
250
306
  Numeric input with step buttons and keyboard control.
@@ -289,6 +345,13 @@ Select dropdown with option items, keyboard navigation, and portal support.
289
345
 
290
346
  Child `<web-ui-option>` elements register via `option-register` / `option-unregister` events. Supports ArrowDown/ArrowUp/Enter/Escape keyboard navigation.
291
347
 
348
+ **CSS Custom Properties:**
349
+
350
+ | Property | Default | Description |
351
+ | ------------------------- | ------- | ------------------ |
352
+ | `--wui-select-max-width` | `500px` | Dropdown max width |
353
+ | `--wui-overlay-min-width` | `200px` | Dropdown min width |
354
+
292
355
  #### `<web-ui-autocomplete>`
293
356
 
294
357
  Editable combobox with input filtering and single option selection.
@@ -315,6 +378,13 @@ Editable combobox with input filtering and single option selection.
315
378
 
316
379
  Typing filters the option list by label (`contains` or `prefix`, or `none` to disable filtering). Selecting an option fills the input with its label and exposes the option's value via `selected-value`; `change` fires on selection commit. Supports ArrowDown/ArrowUp/Enter/Escape keyboard navigation.
317
380
 
381
+ **CSS Custom Properties:**
382
+
383
+ | Property | Default | Description |
384
+ | ------------------------------ | ------- | ---------------------- |
385
+ | `--wui-autocomplete-max-width` | `500px` | Dropdown max width |
386
+ | `--wui-overlay-min-width` | `200px` | Dropdown minimum width |
387
+
318
388
  #### `<web-ui-slider>`
319
389
 
320
390
  Range slider with marks and vertical orientation.
@@ -337,6 +407,18 @@ Range slider with marks and vertical orientation.
337
407
 
338
408
  Supports ArrowLeft/Right/Up/Down, Home/End, PageUp/PageDown keyboard navigation. Uses pointer capture for drag interaction across mouse, touch, and pen.
339
409
 
410
+ **CSS Custom Properties:**
411
+
412
+ | Property | Default | Description |
413
+ | ------------------------------ | ----------------------------------- | ---------------------- |
414
+ | `--wui-slider-width` | `200px` | Slider width |
415
+ | `--wui-slider-vertical-height` | `200px` | Vertical slider height |
416
+ | `--wui-slider-height` | `var(--wui-slider-track-size, 6px)` | Track thickness |
417
+ | `--wui-slider-track-size` | `6px` | Track size |
418
+ | `--wui-slider-thumb-width` | `24px` | Thumb short axis |
419
+ | `--wui-slider-thumb-height` | `32px` | Thumb long axis |
420
+ | `--wui-slider-marks-inset` | `0` | Marks inset from edges |
421
+
340
422
  #### `<web-ui-checkbox>`
341
423
 
342
424
  Individual checkbox.
@@ -451,16 +533,16 @@ Radio group managing single selection.
451
533
 
452
534
  Styled button with variants and loading state.
453
535
 
454
- | Attribute | Type | Default | Description |
455
- | ------------ | ------------------------------------------------------------ | ---------- | ------------------------------------------------- |
456
- | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | Button variant |
457
- | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Inner-button type; invalid values become `button` |
458
- | `disabled` | `boolean` | `false` | Disabled state |
459
- | `loading` | `boolean` | `false` | Loading spinner |
460
- | `full` | `boolean` | `false` | Full width |
461
- | `icon` | `boolean` | `false` | Icon-only mode |
462
- | `size` | `string` | `''` | Size format `height` or `heightxwidth` |
463
- | `aria-label` | `string` | — | Accessible label (delegated to inner button) |
536
+ | Attribute | Type | Default | Description |
537
+ | ------------ | ------------------------------------------------------------ | ---------- | ----------------------------------------------------------------------- |
538
+ | `variant` | `'primary' \| 'secondary' \| 'ghost' \| 'danger' \| 'glass'` | `'glass'` | Button variant |
539
+ | `type` | `'button' \| 'submit' \| 'reset'` | `'button'` | Inner-button type; invalid values become `button` |
540
+ | `disabled` | `boolean` | `false` | Disabled state |
541
+ | `loading` | `boolean` | `false` | Loading spinner |
542
+ | `full` | `boolean` | `false` | Full width |
543
+ | `icon` | `boolean` | `false` | Icon-only mode |
544
+ | `size` | `string` | `''` | Button height in px (icon mode: also sets min-width for square default) |
545
+ | `aria-label` | `string` | — | Accessible label (delegated to inner button) |
464
546
 
465
547
  **Events:** standard `click`
466
548
 
@@ -471,6 +553,18 @@ form-associated control when external form submission behavior is required.
471
553
 
472
554
  Disabled and loading states prevent `click` events.
473
555
 
556
+ **CSS Custom Properties:**
557
+
558
+ | Property | Default | Description |
559
+ | ------------------------ | ------------- | --------------------------------------- |
560
+ | `--wui-button-width` | `max-content` | Button width |
561
+ | `--wui-button-px` | `12px` | Horizontal padding |
562
+ | `--wui-button-gap` | `8px` | Gap between prefix/default/suffix slots |
563
+ | `--wui-button-color` | variant-based | Button text color |
564
+ | `--wui-button-bg` | variant-based | Button background color |
565
+ | `--wui-button-bg-hover` | variant-based | Button hover background |
566
+ | `--wui-button-bg-active` | variant-based | Button active background |
567
+
474
568
  #### `<web-ui-button-group>`
475
569
 
476
570
  Button group that manages child button layout and direction.
@@ -481,7 +575,7 @@ Button group that manages child button layout and direction.
481
575
 
482
576
  **Slots:** `default` (project `<web-ui-button>` elements)
483
577
 
484
- Propagates `direction` attribute to child buttons.
578
+ Applies the direction to the grouped button layout without changing child button attributes.
485
579
 
486
580
  ---
487
581
 
@@ -506,26 +600,47 @@ Modal dialog using native `<dialog>` with `showModal()`.
506
600
 
507
601
  Uses native `<dialog>` with `@cancel` prevention. Escape calls `close()` unless `no-escape-close` is present. Click on backdrop closes dialog unless `no-backdrop-close` is present.
508
602
 
603
+ **CSS Custom Properties:**
604
+
605
+ | Property | Default | Description |
606
+ | ------------------------- | --------------------------- | ------------------- |
607
+ | `--wui-dialog-max-width` | `360px` | Dialog max width |
608
+ | `--wui-dialog-overlay-bg` | `var(--wui-color-backdrop)` | Backdrop background |
609
+
509
610
  #### `<web-ui-drawer>`
510
611
 
511
612
  Side drawer using native `<dialog>` with closing animation.
512
613
 
513
- | Attribute | Type | Default | Description |
514
- | ------------------- | ---------------------------------------- | --------- | ----------------------------------------- |
515
- | `open` | `boolean` | `false` | Drawer visibility |
516
- | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | Slide-in direction |
517
- | `heading` | `string` | `''` | Title text (fallback when no header slot) |
518
- | `closable` | `boolean` | `false` | Show close button |
519
- | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
520
- | `no-backdrop-close` | `boolean` | `false` | Do not close on backdrop click |
614
+ | Attribute | Type | Default | Description |
615
+ | ------------------- | ---------------------------------------- | --------- | --------------------------------------------------------------------------------- |
616
+ | `open` | `boolean` | `false` | Drawer visibility |
617
+ | `placement` | `'right' \| 'left' \| 'top' \| 'bottom'` | `'right'` | Slide-in direction |
618
+ | `heading` | `string` | `''` | Title text (fallback when no header slot) |
619
+ | `closable` | `boolean` | `false` | Show close button |
620
+ | `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
621
+ | `no-backdrop-close` | `boolean` | `false` | Do not close on backdrop click |
622
+ | `request-only` | `boolean` | `false` | User close actions only request `open=false`; the consumer must update `open` |
623
+ | `headless` | `boolean` | `false` | Keep only overlay behavior and render the default slot without built-in drawer UI |
624
+ | `dialog-label` | `string` | `''` | Accessible name for the internal native dialog; required in headless mode |
521
625
 
522
- **Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
626
+ **Events:** `open-change` (`CustomEvent<{ open: boolean }>`). With `request-only`, Escape, backdrop and the built-in close button only request `open=false`; the drawer remains open until the consumer writes `open=false`. If native dialog closure occurs while that request is rejected, the drawer restores its open top-layer state and emits the same request.
523
627
 
524
- **Slots:** `header`, `default`, `footer`
628
+ **Slots:** `header`, `default`, `footer` — with `headless`, only the `default` slot is rendered.
525
629
 
526
630
  **Methods:** `show()`, `close()`
527
631
 
528
- Closing keeps the native dialog in the top layer until the `--wui-duration-drawer` transition completes (280ms by default), then calls `dialog.close()`. Escape always follows this close path; `no-backdrop-close` controls backdrop clicks only.
632
+ `headless` keeps the native dialog, backdrop, placement animation, Escape/backdrop close behavior, and scroll locking. It does not render the built-in glass body, header, close button, or footer; style the default-slot content completely in the consumer.
633
+
634
+ Closing keeps the native dialog in the top layer until the `--wui-duration-drawer-exit` transition completes (240ms by default), then calls `dialog.close()`. Escape always follows this close path; `no-backdrop-close` controls backdrop clicks only.
635
+
636
+ **CSS Custom Properties:**
637
+
638
+ | Property | Default | Description |
639
+ | ------------------------- | ---------------------------------- | -------------------------- |
640
+ | `--wui-drawer-width` | `320px` | Drawer width |
641
+ | `--wui-drawer-height` | `300px` | Drawer height (top/bottom) |
642
+ | `--wui-drawer-bg` | `var(--wui-color-surface-overlay)` | Drawer body background |
643
+ | `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | Backdrop background |
529
644
 
530
645
  ---
531
646
 
@@ -575,6 +690,13 @@ Tooltip overlay using pointer/focus triggers.
575
690
 
576
691
  `open` is a controlled visibility property. Pointer/focus triggers update it, and direct updates synchronize the local or portal panel. Adjacent tooltips open immediately after the first tooltip is visible; pointer/focus triggers otherwise use delay timers.
577
692
 
693
+ **CSS Custom Properties:**
694
+
695
+ | Property | Default | Description |
696
+ | ------------------------- | ------- | ----------------- |
697
+ | `--wui-tooltip-max-width` | `240px` | Tooltip max width |
698
+ | `--wui-tooltip-font-size` | `13px` | Tooltip font size |
699
+
578
700
  #### `<web-ui-context-menu>`
579
701
 
580
702
  Right-click context menu.
@@ -687,6 +809,17 @@ Empty state placeholder.
687
809
 
688
810
  **Slots:** `default` (title, overrides `title` prop), `icon`, `description`, `action`
689
811
 
812
+ **CSS Custom Properties:**
813
+
814
+ | Property | Default | Description |
815
+ | ----------------------------------- | ----------- | ------------------------------ |
816
+ | `--wui-empty-min-height` | `240px` | Min height (medium) |
817
+ | `--wui-empty-padding` | `32px 24px` | Padding (medium) |
818
+ | `--wui-empty-icon-size` | `56px` | Icon container size (medium) |
819
+ | `--wui-empty-content-width` | `480px` | Max width of title/description |
820
+ | `--wui-empty-title-font-size` | `16px` | Title font size (medium) |
821
+ | `--wui-empty-description-font-size` | `14px` | Description font size (medium) |
822
+
690
823
  #### `<web-ui-icon>`
691
824
 
692
825
  Icon renderer using Iconify data objects.
@@ -705,6 +838,12 @@ import { lucideLoaderCircle } from '@greypan/web-ui/icons'
705
838
  html`<web-ui-icon .icon=${lucideLoaderCircle} spin />`
706
839
  ```
707
840
 
841
+ **CSS Custom Properties:**
842
+
843
+ | Property | Default | Description |
844
+ | ------------------ | --------- | ----------- |
845
+ | `--wui-icon-color` | `inherit` | Icon color |
846
+
708
847
  #### `<web-ui-spinner>`
709
848
 
710
849
  Loading spinner.
@@ -737,14 +876,37 @@ WebUiSpinner.hide() // hide
737
876
 
738
877
  #### `<web-ui-layout>`
739
878
 
740
- Page layout grid.
879
+ Responsive page layout with an optional full-width banner, a collapsible desktop sidebar, and a headless-drawer mobile sidebar. The page itself scrolls; the desktop sidebar and header stick to the viewport after the banner scrolls away.
880
+
881
+ | Attribute | Type | Default | Description |
882
+ | ------------------- | --------- | --------- | ----------------------------------------------------- |
883
+ | `sidebar-collapsed` | `boolean` | `false` | Controlled desktop sidebar collapsed state |
884
+ | `sidebar-open` | `boolean` | `false` | Controlled mobile sidebar drawer open state |
885
+ | `header-glow` | `boolean` | `false` | Decorative Header background glow behind slot content |
886
+ | `sidebar-width` | `string` | `'240px'` | Expanded desktop and mobile sidebar width |
887
+ | `collapsed-width` | `string` | `'72px'` | Collapsed desktop sidebar width |
888
+
889
+ **Events:** `sidebar-collapsed-change` (`CustomEvent<{ collapsed: boolean }>`) requests a desktop collapse-state update. `sidebar-open-change` (`CustomEvent<{ open: boolean }>`) requests a mobile drawer open-state update. Consumers must write the requested value back to the corresponding controlled property.
890
+
891
+ | Slot | Description |
892
+ | --------- | ----------------------------------------------------------------------------------------- |
893
+ | `banner` | Optional full-width banner above the layout body |
894
+ | `header` | Sticky content-area header |
895
+ | `sidebar` | Sidebar-card content. The consumer owns its internal fixed regions and scroll containers. |
896
+ | `default` | Main content |
897
+ | `tabbar` | Bottom tab bar |
898
+
899
+ `web-ui-layout` constrains the sidebar card and owns the desktop toggle area, but does not create a sidebar scrollport. To make only part of the sidebar scroll, make the `sidebar` slot root a `height: 100%; min-height: 0` flex column and apply `overflow-y: auto` to the intended child. This keeps consumer-defined headers and footers fixed without adding extra public slots.
741
900
 
742
- | Slot | Description |
743
- | --------- | --------------- |
744
- | `header` | Sticky top bar |
745
- | `default` | Main content |
746
- | `sidebar` | Side navigation |
747
- | `tabbar` | Bottom tab bar |
901
+ At `640px` and below, the sidebar becomes a headless `web-ui-drawer`. The consumer content is rendered in the same rounded sidebar card; the mobile toggle appears in the header row.
902
+
903
+ `header-glow` adds a pointer-transparent decorative glow behind header-slot content and the mobile toggle. It is a Header background rather than a foreground layer, so slotted content remains above it. Override its color with `--wui-layout-header-glow-color` (default: `--wui-color-page`). The glow concentration and spread are controlled by the internal variable `--wui-layout-header-glow-height` (default: `150%`); increase for stronger coverage, decrease for a subtler effect. Layout layers are ordered as Header (`10`) < Auxiliary (`20`) < Banner (`30`) < Tabbar (`40`) < Sidebar (`50`).
904
+
905
+ **CSS Custom Properties:**
906
+
907
+ | Property | Default | Description |
908
+ | ----------------------------- | ------- | ------------------------------------------------ |
909
+ | `--wui-layout-sidebar-radius` | `28px` | Border radius of sidebar card (desktop & mobile) |
748
910
 
749
911
  #### `<web-ui-back-top>`
750
912
 
@@ -761,10 +923,21 @@ Scroll-to-top button.
761
923
 
762
924
  **Methods:** `toTop()`
763
925
 
764
- **Positioning:** With `scrollTarget` as `window`, the button is fixed to the viewport corner. With `scrollTarget` as an `HTMLElement`, place the element inside that container and the button floats at the container's bottom corner via `position: sticky`. Offsets follow the `--web-ui-back-top-top/right/bottom/left` CSS variables.
926
+ **Positioning:** With `scrollTarget` as `window`, the button is fixed to the viewport corner. With `scrollTarget` as an `HTMLElement`, place the element inside that container and the button floats at the container's bottom corner via `position: sticky`. Offsets follow the `--wui-back-top-top/right/bottom/left` CSS variables.
765
927
 
766
928
  Role: `button`, keyboard Enter scrolls to top.
767
929
 
930
+ **CSS Custom Properties:**
931
+
932
+ | Property | Default | Description |
933
+ | ------------------------- | -------------------------------- | ------------- |
934
+ | `--wui-back-top-position` | `fixed` | CSS position |
935
+ | `--wui-back-top-z-index` | `var(--wui-layer-auxiliary, 20)` | Z-index |
936
+ | `--wui-back-top-top` | `auto` | Top offset |
937
+ | `--wui-back-top-right` | `20px` | Right offset |
938
+ | `--wui-back-top-bottom` | `20px` | Bottom offset |
939
+ | `--wui-back-top-left` | `auto` | Left offset |
940
+
768
941
  #### `<web-ui-svg-draw-lines>`
769
942
 
770
943
  SVG line drawing animation using `stroke-dashoffset`. Animates geometry in-place — no cloning, no DOM manipulation.
@@ -793,7 +966,76 @@ Theme provider defining CSS custom property tokens.
793
966
 
794
967
  **Methods:** `getOverlayRoot()` — returns the portal overlay container
795
968
 
796
- Defines `--wui-color-*`, `--wui-shadow-*`, `--wui-layer-*`, and motion tokens. Motion tokens are stable and may be overridden per theme scope: `--wui-duration-press`, `--wui-duration-feedback`, `--wui-duration-trigger`, `--wui-duration-focus`, `--wui-duration-menu-enter`, `--wui-duration-menu-exit`, `--wui-duration-overlay-enter`, `--wui-duration-overlay-exit`, `--wui-duration-drawer-enter`, `--wui-duration-drawer-exit`, `--wui-ease-enter`, `--wui-ease-slide`, and `--wui-scale-enter`. `motion="system"` follows `prefers-reduced-motion`; use `motion="reduced"` to reduce animation in a scope or `motion="full"` in a nested theme to restore the normal token values. System appearance follows `prefers-color-scheme`.
969
+ Defines foundation, color, layer, shadow, and motion tokens for its subtree. `motion="system"` follows `prefers-reduced-motion`; use `motion="reduced"` to reduce animation in a scope or `motion="full"` in a nested theme to restore normal token values. System appearance follows `prefers-color-scheme`.
970
+
971
+ **Foundation tokens:**
972
+
973
+ | Property | Default | Description |
974
+ | ------------------------- | ------- | ------------------------------------------------ |
975
+ | `--wui-font-size` | `14px` | Base font size for controls |
976
+ | `--wui-input-width` | `200px` | Default width for compact form controls |
977
+ | `--wui-control-size` | `40px` | Default height and square min-width for controls |
978
+ | `--wui-overlay-min-width` | `200px` | Minimum anchored overlay width |
979
+ | `--wui-focus-ring-width` | `3px` | Focus indicator width |
980
+
981
+ **Layer tokens:**
982
+
983
+ | Property | Default | Description |
984
+ | ---------------------------- | ------- | ---------------------------- |
985
+ | `--wui-layer-base` | `0` | Base content |
986
+ | `--wui-layer-inline-overlay` | `1` | Overlay local to a component |
987
+ | `--wui-layer-header` | `10` | Page header |
988
+ | `--wui-layer-auxiliary` | `20` | Floating utility controls |
989
+ | `--wui-layer-banner` | `30` | Banners |
990
+ | `--wui-layer-tabbar` | `40` | Tab bars |
991
+ | `--wui-layer-sidebar` | `50` | Sidebars |
992
+ | `--wui-layer-menu` | `100` | Menus and floating panels |
993
+ | `--wui-layer-menu-nested` | `110` | Nested menus |
994
+ | `--wui-layer-toast` | `200` | Toasts |
995
+ | `--wui-layer-loading` | `300` | Blocking loading surfaces |
996
+
997
+ **Motion tokens:** duration defaults are `--wui-duration-press: 80ms`, `--wui-duration-feedback: 100ms`, `--wui-duration-trigger: 160ms`, `--wui-duration-focus: 200ms`, `--wui-duration-menu-enter: 140ms`, `--wui-duration-menu-exit: 100ms`, `--wui-duration-overlay-enter: 180ms`, `--wui-duration-overlay-exit: 140ms`, `--wui-duration-drawer-enter: 280ms`, `--wui-duration-drawer-exit: 240ms`, `--wui-duration-layout: 200ms`. Easing tokens are `--wui-ease-enter` and `--wui-ease-slide`; enter scale is `--wui-scale-enter: 0.97`.
998
+
999
+ **Color tokens:**
1000
+
1001
+ | Property | Light default | Dark default | Description |
1002
+ | ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------- |
1003
+ | `--wui-color-page` | `#fff` | `#18181a` | Page background |
1004
+ | `--wui-color-surface` | `#fff` | `#2c2c2e` | Plain surface |
1005
+ | `--wui-color-surface-raised` | `#f2f2f7` | `#2c2c2e` | Raised surface |
1006
+ | `--wui-color-surface-control` | `#dfdfdf` | `#3a3a3c` | Neutral control surface |
1007
+ | `--wui-color-surface-track` | `#e5e5ea` | `#444446` | Slider and switch track surface |
1008
+ | `--wui-color-surface-glass` | `rgb(250 250 250 / 0.34)` | `rgb(44 44 46 / 0.42)` | Liquid glass surface |
1009
+ | `--wui-color-surface-glass-hover` | `color-mix(... text 6%, surface-glass)` | `color-mix(... text 6%, surface-glass)` | Full glass hover background |
1010
+ | `--wui-color-surface-glass-active` | `color-mix(... text 15%, surface-glass)` | `color-mix(... text 15%, surface-glass)` | Full glass pressed background |
1011
+ | `--wui-color-surface-overlay` | `rgb(246 246 246 / 0.82)` | `rgb(44 44 46 / 0.82)` | Translucent overlay surface |
1012
+ | `--wui-color-text` | `#1b1b1b` | `#f5f5f7` | Primary text |
1013
+ | `--wui-color-text-secondary` | `#6a6a6a` | `#a1a1a6` | Secondary text |
1014
+ | `--wui-color-text-tertiary` | `color-mix(in srgb, var(--wui-color-text) 35%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 42%, transparent)` | Tertiary text and quiet icons |
1015
+ | `--wui-color-text-disabled` | `color-mix(in srgb, var(--wui-color-text) 32%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 38%, transparent)` | Disabled foreground text |
1016
+ | `--wui-color-state-layer-hover` | `color-mix(in srgb, var(--wui-color-text) 6%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 6%, transparent)` | Transparent hover overlay |
1017
+ | `--wui-color-state-layer-active` | `color-mix(in srgb, var(--wui-color-text) 15%, transparent)` | `color-mix(in srgb, var(--wui-color-text) 15%, transparent)` | Transparent pressed overlay |
1018
+ | `--wui-color-border` | `rgb(0 0 0 / 0.1)` | `rgb(255 255 255 / 0.14)` | Normal border and divider |
1019
+ | `--wui-color-glass-border` | `rgb(51 51 51 / 0.12)` | `rgb(255 255 255 / 0.16)` | Glass border tint |
1020
+ | `--wui-color-glass-highlight` | `rgb(255 255 255 / 0.9)` | `rgb(255 255 255 / 0.22)` | Glass edge highlight |
1021
+ | `--wui-color-accent` | `#08f` | `#0a84ff` | Accent and focused input border |
1022
+ | `--wui-color-on-accent` | `#fff` | `#fff` | Foreground on accent |
1023
+ | `--wui-color-success` | `#16a34a` | `#30d158` | Success |
1024
+ | `--wui-color-warning` | `#d97706` | `#ff9f0a` | Warning |
1025
+ | `--wui-color-danger` | `#dc2626` | `#ff453a` | Danger |
1026
+ | `--wui-color-info` | `#2563eb` | `#64d2ff` | Info |
1027
+ | `--wui-color-backdrop` | `rgb(0 0 0 / 0.12)` | `rgb(0 0 0 / 0.48)` | Modal backdrop |
1028
+ | `--wui-color-focus-ring` | `rgb(0 136 255 / 0.4)` | `rgb(10 132 255 / 0.62)` | Focus indicator color |
1029
+
1030
+ **Shadow tokens:**
1031
+
1032
+ | Property | Light default | Dark default | Description |
1033
+ | ---------------------- | -------------------------------- | ------------------------------- | --------------------------- |
1034
+ | `--wui-shadow-overlay` | `2px 16px 40px rgb(0 0 0 / 0.4)` | `0 18px 48px rgb(0 0 0 / 0.54)` | Modal and drawer shadow |
1035
+ | `--wui-shadow-panel` | `0 3px 9px rgb(0 0 0 / 0.27)` | `0 4px 16px rgb(0 0 0 / 0.35)` | Small floating panel shadow |
1036
+ | `--wui-shadow-glass` | four-layer diffuse shadow | `0 12px 32px rgb(0 0 0 / 0.38)` | Base liquid glass shadow |
1037
+
1038
+ **Internal tokens:** variables prefixed `--wui-internal-*` are private wiring between shadow DOM parts; they are not part of the public token API and must not be overridden by consumers.
797
1039
 
798
1040
  ---
799
1041
 
@@ -847,6 +1089,13 @@ toast.updateMessage(id, { message: 'Upload 60% complete', heading: 'Uploading' }
847
1089
 
848
1090
  Hover pauses auto-close timer (uses `pointerenter`/`pointerleave`). Batch-mounts toasts created in the same microtask.
849
1091
 
1092
+ **CSS Custom Properties:**
1093
+
1094
+ | Property | Default | Description |
1095
+ | ------------------------------- | ------- | -------------------------------------------------- |
1096
+ | `--wui-toast-viewport-gap` | `16px` | Visible distance between toasts and viewport edges |
1097
+ | `--wui-toast-container-padding` | `40px` | Container padding reserved for diffuse shadows |
1098
+
850
1099
  ---
851
1100
 
852
1101
  ### Sub-items
@@ -866,6 +1115,12 @@ Selection option for `<web-ui-select>`.
866
1115
 
867
1116
  Not form-associated (child of select, not independent submit).
868
1117
 
1118
+ **CSS Custom Properties:**
1119
+
1120
+ | Property | Default | Description |
1121
+ | ---------------------------- | ------- | --------------------------------------------- |
1122
+ | `--wui-option-check-display` | `block` | Display mode of the selection check indicator |
1123
+
869
1124
  #### `<web-ui-segmented-trigger>`
870
1125
 
871
1126
  Segment trigger for `<web-ui-segmented>`.
@@ -879,3 +1134,11 @@ Segment trigger for `<web-ui-segmented>`.
879
1134
  **Events:** `change`
880
1135
 
881
1136
  Not form-associated (child of segmented, not independent submit).
1137
+
1138
+ **CSS Custom Properties:**
1139
+
1140
+ | Property | Default | Description |
1141
+ | ----------------------------------- | -------------------------------- | ------------------------- |
1142
+ | `--wui-segmented-trigger-px` | `12px` | Horizontal padding |
1143
+ | `--wui-segmented-trigger-bg-hover` | `--wui-color-state-layer-hover` | Trigger hover background |
1144
+ | `--wui-segmented-trigger-bg-active` | `--wui-color-state-layer-active` | Trigger active background |
@@ -1,4 +1,4 @@
1
- //#region \0@oxc-project+runtime@0.140.0/helpers/esm/decorate.js
1
+ //#region \0@oxc-project+runtime@0.146.0/helpers/esm/decorate.js
2
2
  function e(e, t, n, r) {
3
3
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
4
4
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/glass.css?inline
2
- var e = ".wui-glass{border:.5px double var(--wui-color-glass-border,#33333314);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);box-shadow:inset -1px -1px .5px -.5px var(--wui-color-glass-highlight,#ffffffe6), inset 1px 1px .5px -.5px var(--wui-color-glass-highlight,#ffffffe6), inset -3px -3px .5px -3px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 60%, transparent), inset 3px 3px .5px -3px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 60%, transparent), inset 0 0 1px #000c, var(--wui-glass-shadow,var(--wui-shadow-glass,0 2px 16px #0000000f));position:relative}";
2
+ var e = ".wui-glass{background-color:var(--wui-color-surface-glass,#fafafa57);background-image:linear-gradient(to bottom, color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 20%, transparent), color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 4%, transparent) 48%, transparent);-webkit-backdrop-filter:blur(4px)saturate(160%)brightness(1.06);backdrop-filter:blur(4px)saturate(160%)brightness(1.06);box-shadow:inset 0 0 0 .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 38%, transparent), inset 0 1px .5px color-mix(in srgb, var(--wui-color-glass-highlight,#ffffffe6) 52%, transparent), inset 0 -.5px 1px #00000008, var(--wui-internal-glass-focus-ring,0 0 0 0 transparent), var(--wui-internal-glass-shadow,var(--wui-shadow-glass,0 0 1px #0000000d, 0 0 8px #00000008, 0 2px 16px #00000006, 0 8px 32px #00000004));background-clip:padding-box;position:relative}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n position: relative;\n\n border: 0.5px double var(--wui-color-glass-border, rgb(51 51 51 / 0.08));\n\n /* Safari 16.4 只支持带 -webkit- 前缀的 backdrop-filter(无前缀 18 才支持),\n lightningcss 对 ?inline 导入不做自动前缀,需手动写前缀版本 */\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(2px);\n backdrop-filter: blur(2px);\n box-shadow:\n inset -1px -1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset 1px 1px 0.5px -0.5px var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)),\n inset -3px -3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 3px 3px 0.5px -3px\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 60%, transparent),\n inset 0 0 1px rgb(0 0 0 / 0.8),\n var(--wui-glass-shadow, var(--wui-shadow-glass, 0 2px 16px rgb(0 0 0 / 0.06)));\n}\n"],"mappings":""}
1
+ {"version":3,"file":"glass.js","names":[],"sources":["../../src/assets/glass.css?inline"],"sourcesContent":["/*\n * 玻璃公共样式\n */\n\n.wui-glass {\n position: relative;\n\n background-color: var(--wui-color-surface-glass, rgb(250 250 250 / 0.34));\n background-image: linear-gradient(\n to bottom,\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 20%, transparent),\n color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 4%, transparent) 48%,\n transparent\n );\n background-clip: padding-box;\n\n /* Safari 16.4 只支持带 -webkit- 前缀的 backdrop-filter(无前缀 18 才支持),\n lightningcss 对 ?inline 导入不做自动前缀,需手动写前缀版本 */\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(4px) saturate(160%) brightness(1.06);\n backdrop-filter: blur(4px) saturate(160%) brightness(1.06);\n box-shadow:\n inset 0 0 0 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 38%, transparent),\n inset 0 1px 0.5px color-mix(in srgb, var(--wui-color-glass-highlight, rgb(255 255 255 / 0.9)) 52%, transparent),\n inset 0 -0.5px 1px rgb(0 0 0 / 0.03),\n var(--wui-internal-glass-focus-ring, 0 0 0 0 transparent),\n var(\n --wui-internal-glass-shadow,\n var(\n --wui-shadow-glass,\n 0 0 1px rgb(0 0 0 / 0.05),\n 0 0 8px rgb(0 0 0 / 0.03),\n 0 2px 16px rgb(0 0 0 / 0.025),\n 0 8px 32px rgb(0 0 0 / 0.015)\n )\n );\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/menu-portal.css?inline
2
- var e = ".wui-menu-portal-overlay{--wui-glass-shadow:var(--wui-shadow-pop,0 3px 9px #00000045);--wui-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-duration-overlay-exit:var(--wui-duration-menu-exit,.1s);--wui-overlay-min-width:200px;-webkit-user-select:none;user-select:none;z-index:var(--wui-layer-menu,100);box-sizing:border-box;min-width:var(--wui-overlay-min-width,120px);max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-overlay,#f6f6f6e0);border-radius:20px;position:fixed;overflow:hidden}.wui-menu-portal-overlay .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay .wui-menu-content{padding:4px}.wui-menu-portal-overlay.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.context-submenu{z-index:var(--wui-layer-menu-submenu,110)}";
2
+ var e = ".wui-menu-portal-overlay{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-internal-duration-overlay-enter:var(--wui-duration-menu-enter,.14s);--wui-internal-duration-overlay-exit:var(--wui-duration-menu-exit,.1s);-webkit-user-select:none;user-select:none;z-index:var(--wui-layer-menu,100);box-sizing:border-box;min-width:var(--wui-overlay-min-width,200px);max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-overlay,#f6f6f6d1);border-radius:20px;position:fixed;overflow:hidden}.wui-menu-portal-overlay .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay .wui-menu-content{padding:4px}.wui-menu-portal-overlay.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.context-submenu{z-index:var(--wui-layer-menu-nested,110)}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":[".wui-menu-portal-overlay {\n --wui-glass-shadow: var(--wui-shadow-pop, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-duration-overlay-exit: var(--wui-duration-menu-exit, 100ms);\n --wui-overlay-min-width: 200px;\n user-select: none;\n\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n\n overflow: hidden;\n\n box-sizing: border-box;\n min-width: var(--wui-overlay-min-width, 120px);\n max-width: 90vw;\n max-height: 80vh;\n border-radius: 20px;\n\n color: var(--wui-color-text, #1b1b1b);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.88));\n\n & .wui-menu-scroll {\n overflow-y: auto;\n max-height: 80vh;\n }\n\n & .wui-menu-content {\n padding: 4px;\n }\n\n &.dropdown-overlay {\n & .wui-menu-scroll {\n max-height: 320px;\n }\n\n &[data-level]:not([data-level='0']) {\n z-index: var(--wui-layer-menu-submenu, 110);\n }\n }\n\n &.context-submenu {\n z-index: var(--wui-layer-menu-submenu, 110);\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":[".wui-menu-portal-overlay {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-internal-duration-overlay-enter: var(--wui-duration-menu-enter, 140ms);\n --wui-internal-duration-overlay-exit: var(--wui-duration-menu-exit, 100ms);\n user-select: none;\n\n position: fixed;\n z-index: var(--wui-layer-menu, 100);\n\n overflow: hidden;\n\n box-sizing: border-box;\n min-width: var(--wui-overlay-min-width, 200px);\n max-width: 90vw;\n max-height: 80vh;\n border-radius: 20px;\n\n color: var(--wui-color-text, #1b1b1b);\n\n background-color: var(--wui-color-surface-overlay, rgb(246 246 246 / 0.82));\n\n & .wui-menu-scroll {\n overflow-y: auto;\n max-height: 80vh;\n }\n\n & .wui-menu-content {\n padding: 4px;\n }\n\n &.dropdown-overlay {\n & .wui-menu-scroll {\n max-height: 320px;\n }\n\n &[data-level]:not([data-level='0']) {\n z-index: var(--wui-layer-menu-nested, 110);\n }\n }\n\n &.context-submenu {\n z-index: var(--wui-layer-menu-nested, 110);\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/overlay-motion.css?inline
2
- var e = ".wui-floating-panel{transform-origin:var(--wui-overlay-transform-origin,center);opacity:1;transition:opacity var(--wui-duration-overlay-enter,.18s) var(--wui-ease-out,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-duration-overlay-enter,.18s) var(--wui-ease-out,cubic-bezier(.23, 1, .32, 1));transform:scale(1)}.wui-floating-panel[data-wui-presence=entering],.wui-floating-panel[data-wui-presence=closing]{transform:scale(var(--wui-scale-enter,.97));opacity:0}.wui-floating-panel[data-wui-presence=closing]{pointer-events:none;transition-duration:var(--wui-duration-overlay-exit,.14s)}@media (prefers-reduced-motion:reduce){.wui-floating-panel,.wui-floating-panel[data-wui-presence=entering],.wui-floating-panel[data-wui-presence=closing]{transition-duration:.12s;transform:none}}";
2
+ var e = ".wui-floating-panel{transform-origin:var(--wui-internal-overlay-transform-origin,center);opacity:1;transition:opacity var(--wui-internal-duration-overlay-enter,var(--wui-duration-overlay-enter,.18s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-internal-duration-overlay-enter,var(--wui-duration-overlay-enter,.18s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1));transform:scale(1)}.wui-floating-panel[data-wui-presence=entering],.wui-floating-panel[data-wui-presence=closing]{transform:scale(var(--wui-scale-enter,.97));opacity:0}.wui-floating-panel[data-wui-presence=closing]{pointer-events:none;transition-duration:var(--wui-internal-duration-overlay-exit,var(--wui-duration-overlay-exit,.14s))}@media (prefers-reduced-motion:reduce){.wui-floating-panel,.wui-floating-panel[data-wui-presence=entering],.wui-floating-panel[data-wui-presence=closing]{transition-duration:.12s;transform:none}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"overlay-motion.js","names":[],"sources":["../../src/assets/overlay-motion.css?inline"],"sourcesContent":[".wui-floating-panel {\n transform-origin: var(--wui-overlay-transform-origin, center);\n transform: scale(1);\n opacity: 1;\n transition:\n opacity var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-out, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-duration-overlay-enter, 180ms) var(--wui-ease-out, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.wui-floating-panel[data-wui-presence='entering'],\n.wui-floating-panel[data-wui-presence='closing'] {\n transform: scale(var(--wui-scale-enter, 0.97));\n opacity: 0;\n}\n\n.wui-floating-panel[data-wui-presence='closing'] {\n pointer-events: none;\n transition-duration: var(--wui-duration-overlay-exit, 140ms);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-floating-panel,\n .wui-floating-panel[data-wui-presence='entering'],\n .wui-floating-panel[data-wui-presence='closing'] {\n transform: none;\n transition-duration: 120ms;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"overlay-motion.js","names":[],"sources":["../../src/assets/overlay-motion.css?inline"],"sourcesContent":[".wui-floating-panel {\n transform-origin: var(--wui-internal-overlay-transform-origin, center);\n transform: scale(1);\n opacity: 1;\n transition:\n opacity var(--wui-internal-duration-overlay-enter, var(--wui-duration-overlay-enter, 180ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-internal-duration-overlay-enter, var(--wui-duration-overlay-enter, 180ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1));\n}\n\n.wui-floating-panel[data-wui-presence='entering'],\n.wui-floating-panel[data-wui-presence='closing'] {\n transform: scale(var(--wui-scale-enter, 0.97));\n opacity: 0;\n}\n\n.wui-floating-panel[data-wui-presence='closing'] {\n pointer-events: none;\n transition-duration: var(--wui-internal-duration-overlay-exit, var(--wui-duration-overlay-exit, 140ms));\n}\n\n@media (prefers-reduced-motion: reduce) {\n .wui-floating-panel,\n .wui-floating-panel[data-wui-presence='entering'],\n .wui-floating-panel[data-wui-presence='closing'] {\n transform: none;\n transition-duration: 120ms;\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/assets/toast-containers.css?inline
2
- var e = ".wui-toast-container{pointer-events:none;z-index:var(--wui-layer-toast,200);overscroll-behavior:contain;flex-direction:column;gap:8px;max-height:100vh;padding:24px;display:flex;position:fixed;overflow-y:auto}.wui-toast-container>*{pointer-events:auto}.wui-toast-top-left{align-items:flex-start;top:0;left:0}.wui-toast-top-center{align-items:center;top:0;left:50%;transform:translate(-50%)}.wui-toast-top-right{align-items:flex-end;top:0;right:0}.wui-toast-bottom-left{flex-direction:column-reverse;align-items:flex-start;bottom:0;left:0}.wui-toast-bottom-center{flex-direction:column-reverse;align-items:center;bottom:0;left:50%;transform:translate(-50%)}.wui-toast-bottom-right{flex-direction:column-reverse;align-items:flex-end;bottom:0;right:0}";
2
+ var e = ".wui-toast-container{--wui-toast-viewport-gap:16px;--wui-toast-container-padding:40px;pointer-events:none;z-index:var(--wui-layer-toast,200);overscroll-behavior:contain;max-height:calc(100vh + 2 * (var(--wui-toast-container-padding) - var(--wui-toast-viewport-gap)));padding:var(--wui-toast-container-padding);flex-direction:column;gap:8px;display:flex;position:fixed;overflow-y:auto}.wui-toast-container>*{pointer-events:auto}.wui-toast-top-left{top:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));left:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));align-items:flex-start}.wui-toast-top-center{top:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));align-items:center;left:50%;transform:translate(-50%)}.wui-toast-top-right{top:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));right:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));align-items:flex-end}.wui-toast-bottom-left{bottom:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));left:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));flex-direction:column-reverse;align-items:flex-start}.wui-toast-bottom-center{bottom:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));flex-direction:column-reverse;align-items:center;left:50%;transform:translate(-50%)}.wui-toast-bottom-right{right:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));bottom:calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));flex-direction:column-reverse;align-items:flex-end}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"toast-containers.js","names":[],"sources":["../../src/assets/toast-containers.css?inline"],"sourcesContent":["/* Toast 容器定位 — 由 toast 命令式 API 动态注入到 body */\n\n.wui-toast-container {\n pointer-events: none;\n\n position: fixed;\n z-index: var(--wui-layer-toast, 200);\n\n overflow-y: auto;\n overscroll-behavior: contain;\n display: flex;\n flex-direction: column;\n gap: 8px;\n\n max-height: 100vh;\n\n /* padding 需要 >= 阴影模糊半径,否则 overflow 会裁剪子元素 box-shadow */\n padding: 24px;\n}\n\n.wui-toast-container > * {\n pointer-events: auto;\n}\n\n/* ===== 顶部位置 ===== */\n\n.wui-toast-top-left {\n top: 0;\n left: 0;\n align-items: flex-start;\n}\n\n.wui-toast-top-center {\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n}\n\n.wui-toast-top-right {\n top: 0;\n right: 0;\n align-items: flex-end;\n}\n\n/* ===== 底部位置 ===== */\n\n.wui-toast-bottom-left {\n bottom: 0;\n left: 0;\n flex-direction: column-reverse;\n align-items: flex-start;\n}\n\n.wui-toast-bottom-center {\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n\n flex-direction: column-reverse;\n align-items: center;\n}\n\n.wui-toast-bottom-right {\n right: 0;\n bottom: 0;\n flex-direction: column-reverse;\n align-items: flex-end;\n}\n"],"mappings":""}
1
+ {"version":3,"file":"toast-containers.js","names":[],"sources":["../../src/assets/toast-containers.css?inline"],"sourcesContent":["/* Toast 容器定位 — 由 toast 命令式 API 动态注入到 body */\n\n.wui-toast-container {\n --wui-toast-viewport-gap: 16px;\n --wui-toast-container-padding: 40px;\n pointer-events: none;\n\n position: fixed;\n z-index: var(--wui-layer-toast, 200);\n\n overflow-y: auto;\n overscroll-behavior: contain;\n display: flex;\n flex-direction: column;\n gap: 8px;\n\n /* 负向定位只露出可见 gap;剩余 padding 继续作为阴影裁剪缓冲区 */\n max-height: calc(100vh + 2 * (var(--wui-toast-container-padding) - var(--wui-toast-viewport-gap)));\n\n /* padding 需要 >= 阴影偏移 + 模糊半径,否则 overflow 会裁剪子元素 box-shadow */\n padding: var(--wui-toast-container-padding);\n}\n\n.wui-toast-container > * {\n pointer-events: auto;\n}\n\n/* ===== 顶部位置 ===== */\n\n.wui-toast-top-left {\n top: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n left: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n align-items: flex-start;\n}\n\n.wui-toast-top-center {\n top: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n}\n\n.wui-toast-top-right {\n top: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n right: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n align-items: flex-end;\n}\n\n/* ===== 底部位置 ===== */\n\n.wui-toast-bottom-left {\n bottom: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n left: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n flex-direction: column-reverse;\n align-items: flex-start;\n}\n\n.wui-toast-bottom-center {\n bottom: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n left: 50%;\n transform: translateX(-50%);\n\n flex-direction: column-reverse;\n align-items: center;\n}\n\n.wui-toast-bottom-right {\n right: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n bottom: calc(var(--wui-toast-viewport-gap) - var(--wui-toast-container-padding));\n flex-direction: column-reverse;\n align-items: flex-end;\n}\n"],"mappings":""}