@greypan/web-ui 6.1.0 → 6.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.CN.md +209 -80
- package/README.md +189 -60
- package/dist/assets/menu-portal.js +1 -1
- package/dist/assets/menu-portal.js.map +1 -1
- package/dist/assets/overlay-motion.js +1 -1
- package/dist/assets/overlay-motion.js.map +1 -1
- package/dist/components/autocomplete/index.js +54 -53
- package/dist/components/autocomplete/index.js.map +1 -1
- package/dist/components/autocomplete/style.js +1 -1
- package/dist/components/autocomplete/style.js.map +1 -1
- package/dist/components/button/index.js +36 -32
- package/dist/components/button/index.js.map +1 -1
- package/dist/components/button/style.js +1 -1
- package/dist/components/button/style.js.map +1 -1
- package/dist/components/collapse/index.d.ts +29 -1
- package/dist/components/collapse/index.js +92 -30
- package/dist/components/collapse/index.js.map +1 -1
- package/dist/components/collapse/style.js +1 -1
- package/dist/components/collapse/style.js.map +1 -1
- package/dist/components/context-menu/index.d.ts +1 -0
- package/dist/components/context-menu/index.js +80 -76
- package/dist/components/context-menu/index.js.map +1 -1
- package/dist/components/dialog/index.js +6 -2
- package/dist/components/dialog/index.js.map +1 -1
- package/dist/components/dialog/style.js +1 -1
- package/dist/components/dialog/style.js.map +1 -1
- package/dist/components/drawer/index.js +24 -14
- package/dist/components/drawer/index.js.map +1 -1
- package/dist/components/drawer/style.js +1 -1
- package/dist/components/drawer/style.js.map +1 -1
- package/dist/components/dropdown/index.d.ts +1 -0
- package/dist/components/dropdown/index.js +65 -60
- package/dist/components/dropdown/index.js.map +1 -1
- package/dist/components/image-preview/index.d.ts +58 -0
- package/dist/components/image-preview/index.js +481 -0
- package/dist/components/image-preview/index.js.map +1 -0
- package/dist/components/image-preview/style.js +6 -0
- package/dist/components/image-preview/style.js.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +20 -19
- package/dist/components/input/style.js +1 -1
- package/dist/components/input/style.js.map +1 -1
- package/dist/components/input-number/style.js +1 -1
- package/dist/components/input-number/style.js.map +1 -1
- package/dist/components/layout/index.d.ts +1 -1
- package/dist/components/layout/index.js +5 -3
- package/dist/components/layout/index.js.map +1 -1
- package/dist/components/layout/style.js +1 -1
- package/dist/components/layout/style.js.map +1 -1
- package/dist/components/popover/index.d.ts +1 -0
- package/dist/components/popover/index.js +53 -39
- package/dist/components/popover/index.js.map +1 -1
- package/dist/components/popover/style.js.map +1 -1
- package/dist/components/radio/index.js +18 -16
- package/dist/components/radio/index.js.map +1 -1
- package/dist/components/radio/style.js +1 -1
- package/dist/components/radio/style.js.map +1 -1
- package/dist/components/segmented/index.js +24 -22
- package/dist/components/segmented/index.js.map +1 -1
- package/dist/components/segmented/style.js +1 -1
- package/dist/components/segmented/style.js.map +1 -1
- package/dist/components/segmented-trigger/index.js +17 -15
- package/dist/components/segmented-trigger/index.js.map +1 -1
- package/dist/components/segmented-trigger/style.js +1 -1
- package/dist/components/segmented-trigger/style.js.map +1 -1
- package/dist/components/select/index.js +43 -38
- package/dist/components/select/index.js.map +1 -1
- package/dist/components/select/style.js +1 -1
- package/dist/components/select/style.js.map +1 -1
- package/dist/components/slider/index.js +32 -30
- package/dist/components/slider/index.js.map +1 -1
- package/dist/components/slider/style.js +1 -1
- package/dist/components/slider/style.js.map +1 -1
- package/dist/components/svg-draw-lines/index.js +1 -1
- package/dist/components/svg-draw-lines/index.js.map +1 -1
- package/dist/components/switch/index.js +25 -23
- package/dist/components/switch/index.js.map +1 -1
- package/dist/components/switch/style.js +1 -1
- package/dist/components/switch/style.js.map +1 -1
- package/dist/components/textarea/style.js +1 -1
- package/dist/components/textarea/style.js.map +1 -1
- package/dist/components/theme/index.js +1 -1
- package/dist/components/theme/index.js.map +1 -1
- package/dist/components/theme/style.js +1 -1
- package/dist/components/theme/style.js.map +1 -1
- package/dist/components/toast/manager.js +2 -2
- package/dist/components/toast/manager.js.map +1 -1
- package/dist/components/toast/style.js +1 -1
- package/dist/components/toast/style.js.map +1 -1
- package/dist/components/tooltip/index.d.ts +1 -0
- package/dist/components/tooltip/index.js +37 -33
- package/dist/components/tooltip/index.js.map +1 -1
- package/dist/components/tooltip/style.js.map +1 -1
- package/dist/icons/generated/radix-icons-reset.d.ts +6 -0
- package/dist/icons/generated/radix-icons-reset.js +10 -0
- package/dist/icons/generated/radix-icons-reset.js.map +1 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +2 -1
- package/dist/shared/focus/pointer-focus.js +37 -0
- package/dist/shared/focus/pointer-focus.js.map +1 -0
- package/dist/shared/gesture/drag-gesture.js +53 -30
- package/dist/shared/gesture/drag-gesture.js.map +1 -1
- package/dist/shared/gesture/pinch-gesture.js +84 -0
- package/dist/shared/gesture/pinch-gesture.js.map +1 -0
- package/dist/shared/group-management/index.js.map +1 -1
- package/dist/shared/menu-portal/menu-portal.js.map +1 -1
- package/dist/shared/option-portal/combobox-shell.js +8 -6
- package/dist/shared/option-portal/combobox-shell.js.map +1 -1
- package/dist/shared/overlay/anchored-panel.js +33 -30
- package/dist/shared/overlay/anchored-panel.js.map +1 -1
- package/dist/shared/overlay/composition.js +57 -0
- package/dist/shared/overlay/composition.js.map +1 -0
- package/dist/shared/overlay/lifecycle.js +41 -0
- package/dist/shared/overlay/lifecycle.js.map +1 -0
- package/dist/shared/overlay/native-dialog-presence.js +15 -15
- package/dist/shared/overlay/native-dialog-presence.js.map +1 -1
- package/dist/shared/{theme → overlay}/overlay-root.js +1 -1
- package/dist/shared/overlay/overlay-root.js.map +1 -0
- package/dist/shared/overlay/overlay.js +43 -41
- package/dist/shared/overlay/overlay.js.map +1 -1
- package/dist/shared/overlay/portal.js +2 -2
- package/dist/shared/overlay/portal.js.map +1 -1
- package/dist/shared/overlay/positioning-generation.js +20 -0
- package/dist/shared/overlay/positioning-generation.js.map +1 -0
- package/dist/shared/{theme/theme-scope.js → overlay/theme-overlay-scope.js} +2 -2
- package/dist/shared/overlay/theme-overlay-scope.js.map +1 -0
- package/package.json +5 -5
- package/dist/shared/theme/overlay-root.js.map +0 -1
- package/dist/shared/theme/theme-scope.js.map +0 -1
package/README.md
CHANGED
|
@@ -289,6 +289,7 @@ All form controls participate in native `FormData`, constraint validation, `form
|
|
|
289
289
|
| | [`<web-ui-button-group>`](#web-ui-button-group) |
|
|
290
290
|
| **Overlay / Modal** | [`<web-ui-dialog>`](#web-ui-dialog) |
|
|
291
291
|
| | [`<web-ui-drawer>`](#web-ui-drawer) |
|
|
292
|
+
| | [`imagePreview()`](#imagepreview) |
|
|
292
293
|
| **In-flow Disclosure** | [`<web-ui-collapse>`](#web-ui-collapse) |
|
|
293
294
|
| **Floating** | [`<web-ui-popover>`](#web-ui-popover) |
|
|
294
295
|
| | [`<web-ui-tooltip>`](#web-ui-tooltip) |
|
|
@@ -405,16 +406,16 @@ ArrowUp/ArrowDown keyboard increments and decrements the value. Empty or `-` inp
|
|
|
405
406
|
|
|
406
407
|
Select dropdown with option items, keyboard navigation, and portal support.
|
|
407
408
|
|
|
408
|
-
| Attribute | Type | Default | Description
|
|
409
|
-
| ------------------ | ---------------------------------- | ------- |
|
|
410
|
-
| `value` | `string` | `''` | Selected value
|
|
411
|
-
| `placeholder` | `string` | `''` | Placeholder text
|
|
412
|
-
| `name` | `string` | `''` | Form field name
|
|
413
|
-
| `disabled` | `boolean` | `false` | Disabled state
|
|
414
|
-
| `required` | `boolean` | `false` | Required validation
|
|
415
|
-
| `portal` | `boolean` | `false` | Render dropdown in theme overlay
|
|
416
|
-
| `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open
|
|
417
|
-
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container
|
|
409
|
+
| Attribute | Type | Default | Description |
|
|
410
|
+
| ------------------ | ---------------------------------- | ------- | ------------------------------------------- |
|
|
411
|
+
| `value` | `string` | `''` | Selected value |
|
|
412
|
+
| `placeholder` | `string` | `''` | Placeholder text |
|
|
413
|
+
| `name` | `string` | `''` | Form field name |
|
|
414
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
415
|
+
| `required` | `boolean` | `false` | Required validation |
|
|
416
|
+
| `portal` | `boolean` | `false` | Render dropdown in theme-owned overlay root |
|
|
417
|
+
| `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
|
|
418
|
+
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
|
|
418
419
|
|
|
419
420
|
**Events:** `input`, `change`, `open-change` (`CustomEvent<{ open: boolean }>`)
|
|
420
421
|
|
|
@@ -452,7 +453,7 @@ Editable combobox with input filtering and single option selection.
|
|
|
452
453
|
| `readonly` | `boolean` | `false` | Read-only state (no typing, no dropdown) |
|
|
453
454
|
| `required` | `boolean` | `false` | Required validation |
|
|
454
455
|
| `allow-custom-value` | `boolean` | `false` | Allow Enter to submit a custom value that is not among candidates |
|
|
455
|
-
| `portal` | `boolean` | `false` | Render dropdown in theme overlay
|
|
456
|
+
| `portal` | `boolean` | `false` | Render dropdown in theme-owned overlay root |
|
|
456
457
|
| `no-scroll-lock` | `boolean` | `false` | Do not lock body scroll when open |
|
|
457
458
|
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
|
|
458
459
|
| `aria-label` | `string` | — | Accessible name |
|
|
@@ -498,7 +499,7 @@ Range slider with marks and vertical orientation.
|
|
|
498
499
|
|
|
499
500
|
**Methods:** `focus()`, `blur()`
|
|
500
501
|
|
|
501
|
-
Supports ArrowLeft/Right/Up/Down, Home/End, PageUp/PageDown keyboard navigation. Uses pointer capture for drag interaction across mouse, touch, and pen.
|
|
502
|
+
Supports ArrowLeft/Right/Up/Down, Home/End, PageUp/PageDown keyboard navigation. Uses pointer capture for drag interaction across mouse, touch, and pen. Both the component host and the track declare `touch-action: none`, and an active drag suppresses `touchmove` defaulting, so iOS Safari never takes over horizontal or vertical drags mid-gesture.
|
|
502
503
|
|
|
503
504
|
**CSS Custom Properties:**
|
|
504
505
|
|
|
@@ -508,8 +509,9 @@ Supports ArrowLeft/Right/Up/Down, Home/End, PageUp/PageDown keyboard navigation.
|
|
|
508
509
|
| `--wui-slider-vertical-height` | `200px` | Vertical slider height |
|
|
509
510
|
| `--wui-slider-height` | `var(--wui-slider-track-size, 6px)` | Track thickness |
|
|
510
511
|
| `--wui-slider-track-size` | `6px` | Track size |
|
|
511
|
-
| `--wui-slider-thumb-width` | `
|
|
512
|
-
| `--wui-slider-thumb-height` | `
|
|
512
|
+
| `--wui-slider-thumb-width` | `24px` | Thumb width |
|
|
513
|
+
| `--wui-slider-thumb-height` | `18px` | Thumb height |
|
|
514
|
+
| `--wui-slider-thumb-radius` | `8px` | Thumb border radius |
|
|
513
515
|
| `--wui-slider-marks-inset` | `0` | Marks inset from edges |
|
|
514
516
|
|
|
515
517
|
#### `<web-ui-checkbox>`
|
|
@@ -584,6 +586,8 @@ Form-associated: integrates with native `<form>` via `ElementInternals`.
|
|
|
584
586
|
|
|
585
587
|
Manages child trigger `checked` state based on `value`. `disabled` supplies inherited effective disabled state without changing a trigger's own `disabled` property. Setting `value` directly does not dispatch `input`/`change`.
|
|
586
588
|
|
|
589
|
+
Press the selected segment and drag horizontally to slide the indicator; on release it snaps to the nearest option (a fast flick switches by velocity). Touch surfaces declare `touch-action: none` and suppress `touchmove` defaulting during an active drag, so iOS Safari does not interrupt the gesture.
|
|
590
|
+
|
|
587
591
|
#### `<web-ui-checkbox-group>`
|
|
588
592
|
|
|
589
593
|
Checkbox group managing multiple selection.
|
|
@@ -699,11 +703,17 @@ Uses native `<dialog>` with `@cancel` prevention. Escape calls `close()` unless
|
|
|
699
703
|
|
|
700
704
|
**CSS Custom Properties:**
|
|
701
705
|
|
|
702
|
-
| Property
|
|
703
|
-
|
|
|
704
|
-
| `--wui-dialog-
|
|
705
|
-
| `--wui-dialog-
|
|
706
|
-
| `--wui-dialog-bg`
|
|
706
|
+
| Property | Default | Description |
|
|
707
|
+
| ----------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
708
|
+
| `--wui-dialog-width` | `360px` | Dialog width |
|
|
709
|
+
| `--wui-dialog-max-height` | `90vh` | Dialog max height |
|
|
710
|
+
| `--wui-dialog-overlay-bg` | `var(--wui-color-backdrop)` | Backdrop background |
|
|
711
|
+
| `--wui-dialog-bg` | `var(--wui-color-surface-overlay)` | Glass card background, falls back to `rgb(246 246 246 / 0.88)` |
|
|
712
|
+
| `--wui-dialog-padding` | `20px 24px 24px` | Dialog surface padding |
|
|
713
|
+
| `--wui-dialog-title-gap` | `16px` | Spacing below the title |
|
|
714
|
+
| `--wui-dialog-desc-gap` | `24px` | Spacing below the body content |
|
|
715
|
+
| `--wui-dialog-footer-gap` | `10px` / `12px` (horizontal) | Spacing between footer buttons |
|
|
716
|
+
| `--wui-dialog-footer-justify` | `flex-end` (default) / `center` (horizontal) | Footer `justify-content`; override to `flex-end` for right-aligned horizontal buttons |
|
|
707
717
|
|
|
708
718
|
#### `<web-ui-drawer>`
|
|
709
719
|
|
|
@@ -732,7 +742,9 @@ Side drawer using native `<dialog>` with closing animation. In non-headless mode
|
|
|
732
742
|
|
|
733
743
|
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.
|
|
734
744
|
|
|
735
|
-
|
|
745
|
+
When `closable` is set, the built-in close button is positioned at the header's top-right corner (defaults `16px` down and `20px` in from the edge) instead of stretching across the drawer body.
|
|
746
|
+
|
|
747
|
+
**Drag to close:** With `draggable`, a gray capsule drag bar (4×56px by default, visually centered 10px from the inner edge inside a 20px-thick hit zone) appears on the drawer's inner edge (left edge for `right`, right edge for `left`, bottom edge for `top`, top edge for `bottom`) while open:
|
|
736
748
|
|
|
737
749
|
- Dragging follows the pointer in real time; the backdrop fades proportionally.
|
|
738
750
|
- Releasing past ~1/3 of the drawer size, or with a fast closing flick, springs the drawer shut; otherwise it springs back open. The close direction is placement-aware.
|
|
@@ -750,9 +762,89 @@ Closing keeps the native dialog in the top layer until the `--wui-duration-drawe
|
|
|
750
762
|
| `--wui-drawer-radius` | `var(--wui-radius-overlay, 28px)` | Floating card corner radius (non-headless) |
|
|
751
763
|
| `--wui-drawer-inset` | `8px` | Floating card viewport inset (non-headless); `0` gives edge-to-edge geometry |
|
|
752
764
|
| `--wui-drawer-overlay-bg` | `rgb(0 0 0 / 0.12)` | Backdrop background |
|
|
753
|
-
| `--wui-drawer-drag-zone-size` | `
|
|
765
|
+
| `--wui-drawer-drag-zone-size` | `20px` | Drag-to-close hit zone thickness on the inner edge (draggable) |
|
|
754
766
|
| `--wui-drawer-drag-bar-thickness` | `4px` | Drag bar capsule thickness (short axis) |
|
|
755
767
|
| `--wui-drawer-drag-bar-length` | `56px` | Drag bar capsule length (along the drawer edge) |
|
|
768
|
+
| `--wui-drawer-header-padding` | `16px 20px` | Header section padding |
|
|
769
|
+
| `--wui-drawer-close-top` | `16px` | Built-in close button offset from the top of the header |
|
|
770
|
+
| `--wui-drawer-close-right` | `20px` | Built-in close button offset from the right edge of the drawer |
|
|
771
|
+
| `--wui-drawer-content-padding` | `20px` | Content area padding; also drives drag bar visual center (half value) |
|
|
772
|
+
| `--wui-drawer-footer-padding` | `16px 20px` | Footer section padding |
|
|
773
|
+
|
|
774
|
+
#### `imagePreview()`
|
|
775
|
+
|
|
776
|
+
Imperative image preview with no declarative tag contract: open it through `imagePreview()` and drive it through the returned handle. It uses the native `<dialog>` `showModal()` and mounts into the nearest `web-ui-theme` theme-owned overlay root, falling back to the global fallback overlay root when no theme-owned root exists.
|
|
777
|
+
|
|
778
|
+
It does not reuse the `<web-ui-dialog>` component: the preview needs a dialog that fills the viewport itself (the full-viewport backdrop scrim is rendered by a dedicated overlay layer inside the dialog, so the dialog element never fades its own opacity and the glass controls' backdrop blur stays continuous) plus its own pointer interaction, which is a different source than the dialog's glass panel and slot contract. The two share the `native-dialog-presence` and `scroll-lock` plugins, and `noScrollLock` / `noBackdropClose` mirror the same-named properties in naming and semantics.
|
|
779
|
+
|
|
780
|
+
```ts
|
|
781
|
+
import { imagePreview } from '@greypan/web-ui'
|
|
782
|
+
|
|
783
|
+
const preview = imagePreview({
|
|
784
|
+
images: [{ src: '/a.jpg', alt: 'Image A' }, { src: '/b.jpg' }],
|
|
785
|
+
index: 0,
|
|
786
|
+
nav: true,
|
|
787
|
+
toolbar: true,
|
|
788
|
+
closable: true,
|
|
789
|
+
indicator: true
|
|
790
|
+
})
|
|
791
|
+
|
|
792
|
+
preview.next()
|
|
793
|
+
preview.zoomIn()
|
|
794
|
+
|
|
795
|
+
await preview.closed
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
**Options:**
|
|
799
|
+
|
|
800
|
+
| Option | Type | Default | Description |
|
|
801
|
+
| ----------------- | -------------------- | ------- | --------------------------------------------------------------------------- |
|
|
802
|
+
| `images` | `ImagePreviewItem[]` | — | Image list; must contain at least one item, else it throws |
|
|
803
|
+
| `index` | `number` | `0` | Initial index, clamped into range |
|
|
804
|
+
| `loop` | `boolean` | `true` | Wrap around at both ends |
|
|
805
|
+
| `target` | `Element` | — | Trigger element used to resolve the nearest theme-owned overlay root |
|
|
806
|
+
| `container` | `HTMLElement` | — | Explicit mount container, highest priority |
|
|
807
|
+
| `nav` | `boolean` | `false` | Show prev/next buttons; rendered only when more than one image |
|
|
808
|
+
| `toolbar` | `boolean` | `false` | Show the zoom toolbar (out / factor / in / reset) |
|
|
809
|
+
| `closable` | `boolean` | `false` | Show the close button |
|
|
810
|
+
| `indicator` | `boolean` | `false` | Show the "current / total" indicator, announced via `aria-live` |
|
|
811
|
+
| `swipe` | `boolean` | `false` | At 1x, swipe horizontally to change images; owns that axis while it applies |
|
|
812
|
+
| `noScrollLock` | `boolean` | `false` | Do not lock page scroll while open |
|
|
813
|
+
| `noBackdropClose` | `boolean` | `false` | Clicking the blank area outside the image does not close |
|
|
814
|
+
|
|
815
|
+
`ImagePreviewItem` is `{ src: string; alt?: string }`; a missing `alt` defaults to an empty string.
|
|
816
|
+
|
|
817
|
+
Every presentation option defaults to off: with no options passed only the image itself is rendered, so navigation, toolbar, close button and indicator all have to be enabled explicitly.
|
|
818
|
+
|
|
819
|
+
**Returned handle:**
|
|
820
|
+
|
|
821
|
+
| Member | Type | Description |
|
|
822
|
+
| ---------------------------------------- | ----------------------------- | ----------------------------------------------- |
|
|
823
|
+
| `index` | `number` | Current index; keeps its last value after close |
|
|
824
|
+
| `scale` | `number` | Current zoom factor within `[1, 4]` |
|
|
825
|
+
| `images` | `readonly ImagePreviewItem[]` | Normalized image list |
|
|
826
|
+
| `closed` | `Promise<void>` | Resolves after the exit transition and unmount |
|
|
827
|
+
| `next()` / `prev()` | `() => void` | Relative navigation |
|
|
828
|
+
| `goTo(index)` | `(index: number) => void` | Jump; clamps at the bounds when `loop` is off |
|
|
829
|
+
| `zoomIn()` / `zoomOut()` / `resetZoom()` | `() => void` | Zoom controls |
|
|
830
|
+
| `close()` | `() => void` | Close and play the exit animation |
|
|
831
|
+
|
|
832
|
+
**Interaction:** Arrow keys always navigate, independently of `nav`; `+` / `-` and the mouse wheel zoom, and `0` resets. Zooming is anchored: the wheel keeps the point under the cursor fixed and a pinch keeps the midpoint between the two fingers fixed, while the toolbar buttons, keyboard shortcuts and double-click expand around the viewport center. Holding the mouse button down or resting a single finger drags the image to pan in any direction, at any zoom level: zoomed in it reveals the cropped edges, and at 1x it moves the image around within the viewport. Either way the drag is bounded by half the size difference between the image and the stage, so the image can never be dragged outside the viewport, and it is clamped (not snapped back) when you keep dragging past the edge. Double-clicking the image toggles between 1x and 2x.
|
|
833
|
+
|
|
834
|
+
Pinch-to-zoom is always on and has no option: the stage already owns pointer interaction, so there is nothing for a gesture to conflict with. The first finger still drives pan/swipe as usual and the second finger starts the pinch, which aborts any in-flight pan or swipe. A pinch does not close the preview, and the compatibility `click` that mixed input may synthesize afterwards is swallowed rather than treated as a backdrop click.
|
|
835
|
+
|
|
836
|
+
Clicking anywhere outside the image, or pressing Escape, closes the preview. The native dialog always exposes the accessible name `图片预览`. With `swipe` on and more than one image, the images live on a single carousel track: the current image and its neighbors sit side by side in slides of equal size, the stage clips the overflow, and the whole track translates with the finger. Releasing past the distance threshold (15% of the stage width, rounded) slides the next image in, as does a fast flick whose sampled velocity is at least 320px/s even below that distance; a flick covering at least 16px whose velocity (windowed sample or whole-gesture average) reaches 160px/s also commits; otherwise it bounces back. With `loop` on the wrap-around neighbor is always present beside the current image, and at the non-looping bounds the strip bounces back instead of crossing the boundary. While it applies, the swipe gesture takes over the drag entirely: at 1x only horizontal movement changes images, and vertical movement is ignored (no pan, no vertical follow). Once zoomed in, dragging always pans on both axes and never changes images. Because panning also works at 1x, `resetZoom()` is offered whenever the image is zoomed _or_ displaced — the reset button in the toolbar is enabled for a panned 1x image too.
|
|
837
|
+
|
|
838
|
+
A close request does not destroy the native dialog immediately: it stays in the top layer until the exit transition completes, then `dialog.close()` runs, the host is removed from the DOM, and `closed` resolves. Page scroll is locked while open unless `noScrollLock` is `true`.
|
|
839
|
+
|
|
840
|
+
**CSS Custom Properties:**
|
|
841
|
+
|
|
842
|
+
| Property | Default | Description |
|
|
843
|
+
| -------------------------------- | -------------------------------- | ------------------------------------------------- |
|
|
844
|
+
| `--wui-image-preview-overlay-bg` | `rgb(0 0 0 / 0.72)` | Full-viewport backdrop background color |
|
|
845
|
+
| `--wui-image-preview-edge-gap` | `20px` | Distance from controls to viewport edge |
|
|
846
|
+
| `--wui-duration-swipe-settle` | `220ms` | Carousel settle (slide-in / bounce-back) duration |
|
|
847
|
+
| `--wui-ease-swipe` | `cubic-bezier(0.32, 0.72, 0, 1)` | Carousel settle (slide-in / bounce-back) easing |
|
|
756
848
|
|
|
757
849
|
---
|
|
758
850
|
|
|
@@ -762,12 +854,13 @@ Closing keeps the native dialog in the top layer until the `--wui-duration-drawe
|
|
|
762
854
|
|
|
763
855
|
In-flow expand/collapse container with animated height (or width) transition. Single element with two slots; no portal, no scroll lock, no focus management.
|
|
764
856
|
|
|
765
|
-
| Attribute | Type | Default | Description
|
|
766
|
-
| -------------- | --------- | ------- |
|
|
767
|
-
| `open` | `boolean` | `false` | Expanded state; self-managed on interaction, `open-change` emits only for user-originated toggles
|
|
768
|
-
| `disabled` | `boolean` | `false` | Ignores trigger clicks and sets `aria-disabled` on the trigger element; expanded content is kept
|
|
769
|
-
| `horizontal` | `boolean` | `false` | Animate width instead of height
|
|
770
|
-
| `keep-mounted` | `boolean` | `false` | Closed state keeps the content in the 0fr track with `inert` (scroll position and layout measurable) instead of `hidden`
|
|
857
|
+
| Attribute | Type | Default | Description |
|
|
858
|
+
| -------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
859
|
+
| `open` | `boolean` | `false` | Expanded state; self-managed on interaction, `open-change` emits only for user-originated toggles |
|
|
860
|
+
| `disabled` | `boolean` | `false` | Ignores trigger clicks and sets `aria-disabled` on the trigger element; expanded content is kept |
|
|
861
|
+
| `horizontal` | `boolean` | `false` | Animate width instead of height |
|
|
862
|
+
| `keep-mounted` | `boolean` | `false` | Closed state keeps the content in the 0fr track with `inert` (scroll position and layout measurable) instead of `hidden` |
|
|
863
|
+
| `peek` | `string` | — | Closed state reveals this much of the content (CSS length, e.g. `120px`); along the animation axis; ends in an auto-sized edge fade |
|
|
771
864
|
|
|
772
865
|
**Events:** `open-change` (`CustomEvent<{ open: boolean }>`). Emitted only for user-originated toggles (trigger click). Programmatic writes (`open`, `show()`, `close()`, `toggle()`) never emit. Nested collapses: an inner `open-change` bubbles through the outer root (composed event); distinguish by `event.target`.
|
|
773
866
|
|
|
@@ -788,6 +881,38 @@ The initial `open` attribute settles instantly without playing the animation. Ne
|
|
|
788
881
|
|
|
789
882
|
**Closed-state semantics:** the consumer's light DOM is never moved or unmounted. Default closed state applies `hidden` to the internal content container; with `keep-mounted` the inner container is marked `inert` while staying measurable inside the collapsed track.
|
|
790
883
|
|
|
884
|
+
**`peek` (partial reveal):** setting `peek` makes the closed state reveal the first `peek` of the content along the animation axis (`horizontal` switches it to width) instead of collapsing to zero — the track stays at the content height and the inner container is clamped. It implies `keep-mounted` semantics: the content stays mounted but is `inert`, so the clipped portion is not focusable or clickable. Content shorter than `peek` collapses to its own size rather than leaving blank space. Because a fixed length and an auto height cannot be interpolated by CSS, the two `peek` ↔ expanded directions are driven by explicit pixel lengths (measured once per toggle); every other animation path stays a zero-measurement grid `fr` transition.
|
|
885
|
+
|
|
886
|
+
```html
|
|
887
|
+
<web-ui-collapse peek="120px">
|
|
888
|
+
<button type="button">Toggle me</button>
|
|
889
|
+
<div slot="content">Long content — only the first 120px show while closed</div>
|
|
890
|
+
</web-ui-collapse>
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
**Edge fade:** the revealed area ends in an alpha-gradient fade (right edge when `horizontal`) so the clipped portion melts into the background instead of ending in a hard line. The length is derived from `peek` — there is no second attribute to set. Tune it with CSS custom properties instead:
|
|
894
|
+
|
|
895
|
+
| Custom property | Default | Description |
|
|
896
|
+
| -------------------------------- | ------------- | --------------------------------------------------------------------- |
|
|
897
|
+
| `--wui-collapse-peek-edge-ratio` | `0.4` | Fade length as a fraction of `peek` |
|
|
898
|
+
| `--wui-collapse-peek-edge-max` | `112px` | Upper bound, so a large `peek` cannot produce an oversized fade band |
|
|
899
|
+
| `--wui-collapse-peek-edge` | — | Explicit fade length; wins over the derived value |
|
|
900
|
+
| `--wui-collapse-peek-edge-color` | `transparent` | Fade-stop color (must carry alpha — `mask-image` reads alpha channel) |
|
|
901
|
+
|
|
902
|
+
Set the ratio to `0` to turn the fade off. The derivation is pure CSS `calc(peek * ratio)`, so a `rem`-based `peek` scales the fade with the root font size and nothing has to be measured in JS. Known limitation: a percentage `peek` does not derive to a length, so the fade silently falls back to "none" — set `--wui-collapse-peek-edge` explicitly in that case.
|
|
903
|
+
|
|
904
|
+
The fade is a four-stop ease-out gradient rather than a linear one: the body stays fully opaque to the start of the fade band, drops to 60% alpha within the first 30% of the band, then 26%, then reaches the edge color. A linear gradient hugs 1.0 alpha across the first 40% of the band, so the eye perceives a much shorter fade than declared — front-loading the drop makes the band visibly soft from its very start, nearly doubling the perceived length at the same size.
|
|
905
|
+
|
|
906
|
+
The fade band is positioned in percentages, relative to the container's **current rendered height** — which is what `max-height` animates. So the band tracks the cut edge frame by frame during the collapse animation without the `mask-image` string ever needing to interpolate. Its length is driven by a registered `<length>` custom property so it can fade in and out with the toggle instead of popping in once the close animation settles.
|
|
907
|
+
|
|
908
|
+
```html
|
|
909
|
+
<!-- 调强渐隐:比例 0.5 → 120px peek 配 60px 渐隐 -->
|
|
910
|
+
<web-ui-collapse peek="120px" style="--wui-collapse-peek-edge-ratio: 0.5">
|
|
911
|
+
<button type="button">Toggle me</button>
|
|
912
|
+
<div slot="content">Long content with a stronger fade at the bottom of the 120px peek</div>
|
|
913
|
+
</web-ui-collapse>
|
|
914
|
+
```
|
|
915
|
+
|
|
791
916
|
**Known limitations:** the `horizontal` animation reflows content while width changes.
|
|
792
917
|
|
|
793
918
|
---
|
|
@@ -798,15 +923,15 @@ The initial `open` attribute settles instantly without playing the animation. Ne
|
|
|
798
923
|
|
|
799
924
|
Popover overlay anchored to trigger element.
|
|
800
925
|
|
|
801
|
-
| Attribute | Type | Default | Description
|
|
802
|
-
| ------------------ | ---------------------------------- | ---------- |
|
|
803
|
-
| `open` | `boolean` | `false` | Popover visibility
|
|
804
|
-
| `disabled` | `boolean` | `false` | Disabled state
|
|
805
|
-
| `placement` | `Placement` | `'bottom'` | Floating UI placement
|
|
806
|
-
| `trigger` | `'click' \| 'hover' \| 'manual'` | `'click'` | Open trigger
|
|
807
|
-
| `offset` | `number` | `8` | Offset from anchor
|
|
808
|
-
| `portal` | `boolean` | `false` | Render in theme overlay
|
|
809
|
-
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container
|
|
926
|
+
| Attribute | Type | Default | Description |
|
|
927
|
+
| ------------------ | ---------------------------------- | ---------- | ---------------------------------- |
|
|
928
|
+
| `open` | `boolean` | `false` | Popover visibility |
|
|
929
|
+
| `disabled` | `boolean` | `false` | Disabled state |
|
|
930
|
+
| `placement` | `Placement` | `'bottom'` | Floating UI placement |
|
|
931
|
+
| `trigger` | `'click' \| 'hover' \| 'manual'` | `'click'` | Open trigger |
|
|
932
|
+
| `offset` | `number` | `8` | Offset from anchor |
|
|
933
|
+
| `portal` | `boolean` | `false` | Render in theme-owned overlay root |
|
|
934
|
+
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
|
|
810
935
|
|
|
811
936
|
**Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
|
|
812
937
|
|
|
@@ -831,7 +956,7 @@ Tooltip overlay using pointer/focus triggers.
|
|
|
831
956
|
| `show-delay` | `number` | `200` | Show delay in ms |
|
|
832
957
|
| `hide-delay` | `number` | `100` | Hide delay in ms |
|
|
833
958
|
| `offset` | `number` | `6` | Offset from trigger |
|
|
834
|
-
| `portal` | `boolean` | `false` | Render in theme overlay
|
|
959
|
+
| `portal` | `boolean` | `false` | Render in theme-owned overlay root |
|
|
835
960
|
| `overlayContainer` | `HTMLElement \| () => HTMLElement` | — | Explicit portal container |
|
|
836
961
|
|
|
837
962
|
**Events:** `open-change` (`CustomEvent<{ open: boolean }>`)
|
|
@@ -1030,7 +1155,7 @@ WebUiSpinner.hide() // hide
|
|
|
1030
1155
|
|
|
1031
1156
|
#### `<web-ui-layout>`
|
|
1032
1157
|
|
|
1033
|
-
Responsive page layout with an optional full-width banner, a collapsible desktop sidebar, and a
|
|
1158
|
+
Responsive page layout with an optional full-width banner, a collapsible desktop sidebar, and a default-drawer mobile sidebar. The page itself scrolls; the desktop sidebar and header stick to the viewport after the banner scrolls away.
|
|
1034
1159
|
|
|
1035
1160
|
| Attribute | Type | Default | Description |
|
|
1036
1161
|
| ------------------- | --------- | --------- | -------------------------------------------------------------------------------------------------- |
|
|
@@ -1052,15 +1177,15 @@ Responsive page layout with an optional full-width banner, a collapsible desktop
|
|
|
1052
1177
|
- Keyboard (WAI-ARIA splitter pattern): focus the handle and use ←/→ to step by 16px (Shift for 64px), Home/End to jump to min/max, Enter to commit via the same `sidebar-width-change` request, and Escape to revert an uncommitted adjustment.
|
|
1053
1178
|
- The mobile drawer always supports drag-to-close via its built-in `draggable` drawer.
|
|
1054
1179
|
|
|
1055
|
-
| Slot | Description
|
|
1056
|
-
| --------- |
|
|
1057
|
-
| `banner` | Optional full-width banner above the layout body
|
|
1058
|
-
| `header` | Sticky content-area header
|
|
1059
|
-
| `sidebar` | Sidebar-card content.
|
|
1060
|
-
| `default` | Main content
|
|
1061
|
-
| `tabbar` | Bottom tab bar
|
|
1180
|
+
| Slot | Description |
|
|
1181
|
+
| --------- | ---------------------------------------------------------------------------------------------------- |
|
|
1182
|
+
| `banner` | Optional full-width banner above the layout body |
|
|
1183
|
+
| `header` | Sticky content-area header |
|
|
1184
|
+
| `sidebar` | Sidebar-card content. On desktop, the consumer owns its internal fixed regions and scroll container. |
|
|
1185
|
+
| `default` | Main content |
|
|
1186
|
+
| `tabbar` | Bottom tab bar |
|
|
1062
1187
|
|
|
1063
|
-
`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:
|
|
1188
|
+
`web-ui-layout` constrains the sidebar card and owns the desktop toggle area, but does not create a desktop sidebar scrollport. To make only part of the desktop 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:
|
|
1064
1189
|
|
|
1065
1190
|
```html
|
|
1066
1191
|
<div slot="sidebar" class="sidebar-root">
|
|
@@ -1088,7 +1213,7 @@ Responsive page layout with an optional full-width banner, a collapsible desktop
|
|
|
1088
1213
|
}
|
|
1089
1214
|
```
|
|
1090
1215
|
|
|
1091
|
-
At `640px` and below, the sidebar becomes a
|
|
1216
|
+
At `640px` and below, the sidebar becomes a `web-ui-drawer` with its built-in glass body, scrollable content, and drag zone. The layout maps `sidebar-width` to `--wui-drawer-width` and `--wui-layout-sidebar-radius` to `--wui-drawer-radius`. The mobile toggle appears in the header row as a glass button. Its left inset defaults to `8px`; align it with your own header padding via `--wui-layout-mobile-toggle-inset`.
|
|
1092
1217
|
|
|
1093
1218
|
`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`).
|
|
1094
1219
|
|
|
@@ -1155,10 +1280,14 @@ Theme provider defining CSS custom property tokens.
|
|
|
1155
1280
|
| `appearance` | `'light' \| 'dark' \| 'system'` | `'light'` | Color scheme |
|
|
1156
1281
|
| `motion` | `'full' \| 'reduced' \| 'system'` | `'system'` | Motion preference for this nested theme scope |
|
|
1157
1282
|
|
|
1158
|
-
**Methods:** `getOverlayRoot()` — returns
|
|
1283
|
+
**Methods:** `getOverlayRoot()` — returns this theme-owned overlay root
|
|
1284
|
+
|
|
1285
|
+
**Portal mounting contract:** Every active `<web-ui-theme>` is also the default scoped theme-owned overlay root. Portal-based components without an explicit `overlayContainer` resolve to the nearest active theme's `getOverlayRoot()`; target-less portal calls prefer the root theme's theme-owned overlay root. When no active theme provides a root, they fall back to the global fallback overlay root.
|
|
1159
1286
|
|
|
1160
1287
|
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`.
|
|
1161
1288
|
|
|
1289
|
+
The host uses `display: contents` and does not paint any background: the library never draws on the host page, so the embedding application keeps full control of the surface behind the themed subtree. Custom properties still inherit to slotted content reliably.
|
|
1290
|
+
|
|
1162
1291
|
**Foundation tokens:**
|
|
1163
1292
|
|
|
1164
1293
|
| Property | Default | Description |
|
|
@@ -1193,7 +1322,7 @@ Defines foundation, color, layer, shadow, and motion tokens for its subtree. `mo
|
|
|
1193
1322
|
| `--wui-layer-toast` | `200` | Toasts |
|
|
1194
1323
|
| `--wui-layer-loading` | `300` | Blocking loading surfaces |
|
|
1195
1324
|
|
|
1196
|
-
**Motion tokens:** duration defaults are `--wui-duration-press: 80ms`, `--wui-duration-feedback: 100ms`, `--wui-duration-trigger: 160ms`, `--wui-duration-focus: 200ms`, `--wui-duration-
|
|
1325
|
+
**Motion tokens:** duration defaults are `--wui-duration-press: 80ms`, `--wui-duration-feedback: 100ms`, `--wui-duration-trigger: 160ms`, `--wui-duration-focus: 200ms`, `--wui-duration-float-enter: 160ms`, `--wui-duration-float-exit: 120ms`, `--wui-duration-dialog-enter: 320ms`, `--wui-duration-dialog-exit: 260ms`, `--wui-duration-drawer-enter: 280ms`, `--wui-duration-drawer-exit: 240ms`, `--wui-duration-drawer-nested: 450ms`, `--wui-duration-toast-enter: 280ms`, `--wui-duration-toast-exit: 200ms`, `--wui-duration-collapse-enter: 200ms`, `--wui-duration-collapse-exit: 160ms`, `--wui-duration-layout: 200ms`. Easing tokens are `--wui-ease-enter`, `--wui-ease-dialog` (`cubic-bezier(0.2, 0, 0, 1)`), and `--wui-ease-slide`; enter scale is `--wui-scale-enter: 0.97`. Hover/active background feedback switches instantly with no transition; checked/pressed/focus transitions are unaffected.
|
|
1197
1326
|
|
|
1198
1327
|
**Color tokens:**
|
|
1199
1328
|
|
|
@@ -1278,17 +1407,17 @@ toast.updateMessage(id, { message: 'Upload 60% complete', heading: 'Uploading' }
|
|
|
1278
1407
|
|
|
1279
1408
|
**ToastOptions:**
|
|
1280
1409
|
|
|
1281
|
-
| Option | Type | Default | Description
|
|
1282
|
-
| ----------- | ------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
1283
|
-
| `message` | `string` | — | Notification text
|
|
1284
|
-
| `type` | `'success' \| 'info' \| 'warning' \| 'error'` | `'info'` | Toast type
|
|
1285
|
-
| `duration` | `number` | `3000` (`5000` for error) | Auto-close duration (0 = no auto-close)
|
|
1286
|
-
| `closable` | `boolean` | `true` | Show close button
|
|
1287
|
-
| `id` | `string` | auto | Deduplication identifier
|
|
1288
|
-
| `heading` | `string` | `''` | Bold heading text
|
|
1289
|
-
| `position` | `'top-left' \| 'top-center' \| 'top-right' \| 'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'top-right'` | Screen position
|
|
1290
|
-
| `target` | `Element` | — | Used to find nearest theme
|
|
1291
|
-
| `container` | `HTMLElement` | — | Explicit mount container (highest priority)
|
|
1410
|
+
| Option | Type | Default | Description |
|
|
1411
|
+
| ----------- | ------------------------------------------------------------------------------------------------- | ------------------------- | --------------------------------------------- |
|
|
1412
|
+
| `message` | `string` | — | Notification text |
|
|
1413
|
+
| `type` | `'success' \| 'info' \| 'warning' \| 'error'` | `'info'` | Toast type |
|
|
1414
|
+
| `duration` | `number` | `3000` (`5000` for error) | Auto-close duration (0 = no auto-close) |
|
|
1415
|
+
| `closable` | `boolean` | `true` | Show close button |
|
|
1416
|
+
| `id` | `string` | auto | Deduplication identifier |
|
|
1417
|
+
| `heading` | `string` | `''` | Bold heading text |
|
|
1418
|
+
| `position` | `'top-left' \| 'top-center' \| 'top-right' \| 'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'top-right'` | Screen position |
|
|
1419
|
+
| `target` | `Element` | — | Used to find nearest theme-owned overlay root |
|
|
1420
|
+
| `container` | `HTMLElement` | — | Explicit mount container (highest priority) |
|
|
1292
1421
|
|
|
1293
1422
|
**`toast.updateMessage(id, options)`** updates the visible toast's `message` and, when supplied, `heading`. It does not restart the auto-close timer. `options` is `ToastMessageUpdateOptions`: `{ message: string; heading?: string }`.
|
|
1294
1423
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//#region src/assets/menu-portal.css?inline
|
|
2
|
-
var e = ".wui-menu-portal-overlay.wui-
|
|
2
|
+
var e = ".wui-menu-portal-overlay.wui-floating-panel{--wui-internal-glass-shadow:var(--wui-shadow-panel,0 3px 9px #00000045);--wui-internal-duration-float-enter:var(--wui-duration-float-enter,.16s);--wui-internal-duration-float-exit:var(--wui-duration-float-exit,.12s);--wui-glass-corner-radius:var(--wui-radius-menu,18px);-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);border-radius:var(--wui-radius-menu,18px);max-width:90vw;max-height:80vh;color:var(--wui-color-text,#1b1b1b);background-color:var(--wui-color-surface-menu,#f6f6f6d1);position:fixed;overflow:hidden}.wui-menu-portal-overlay.wui-floating-panel .wui-menu-scroll{max-height:80vh;overflow-y:auto}.wui-menu-portal-overlay.wui-floating-panel .wui-menu-content{padding:4px}.wui-menu-portal-overlay.wui-floating-panel.dropdown-overlay .wui-menu-scroll{max-height:320px}.wui-menu-portal-overlay.wui-floating-panel.dropdown-overlay[data-level]:not([data-level=\"0\"]),.wui-menu-portal-overlay.wui-floating-panel.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":["/*
|
|
1
|
+
{"version":3,"file":"menu-portal.js","names":[],"sources":["../../src/assets/menu-portal.css?inline"],"sourcesContent":["/* 菜单面板:wui-glass 玻璃(背景/描边/阴影)由面板自身承担,随面板 opacity 与\n backdrop-filter 插值一起过渡(单层玻璃,见 overlay-motion.css)。\n 选择器用 .wui-menu-portal-overlay.wui-floating-panel(0,2,0)压制 .wui-glass\n (0,1,0):面板无自有 shadow root,直接挂在宿主 shadow(overlay root 的 \\3c style>\n 或 dialog 的 adopted stylesheets)里,若只用单类选择器,dialog 场景下宿主 adopted\n stylesheets 的 .wui-glass 会在层叠中晚于面板内联 \\3c style> 而胜出(position:relative\n 顶掉 fixed、背景/阴影变量回弱默认)。 */\n.wui-menu-portal-overlay.wui-floating-panel {\n --wui-internal-glass-shadow: var(--wui-shadow-panel, 0 3px 9px rgb(0 0 0 / 0.27));\n --wui-internal-duration-float-enter: var(--wui-duration-float-enter, 160ms);\n --wui-internal-duration-float-exit: var(--wui-duration-float-exit, 120ms);\n --wui-glass-corner-radius: var(--wui-radius-menu, 18px);\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: var(--wui-radius-menu, 18px);\n\n color: var(--wui-color-text, #1b1b1b);\n\n /* 玻璃背景:面板自身 overflow:hidden 不裁自身的 box-shadow(box-shadow 不受\n 元素自身 overflow 影响)。 */\n background-color: var(--wui-color-surface-menu, 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-internal-overlay-transform-origin,center);opacity:1;transition:opacity var(--wui-internal-duration-
|
|
2
|
+
var e = ".wui-floating-panel{transform-origin:var(--wui-internal-overlay-transform-origin,center);opacity:1;-webkit-backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(4px) saturate(160%) brightness(var(--wui-glass-brightness,1.06));transition:opacity var(--wui-internal-duration-float-enter,var(--wui-duration-float-enter,.16s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), -webkit-backdrop-filter var(--wui-internal-duration-float-enter,var(--wui-duration-float-enter,.16s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), backdrop-filter var(--wui-internal-duration-float-enter,var(--wui-duration-float-enter,.16s)) var(--wui-ease-enter,cubic-bezier(.23, 1, .32, 1)), transform var(--wui-internal-duration-float-enter,var(--wui-duration-float-enter,.16s)) 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;-webkit-backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06));backdrop-filter:blur(0) saturate(160%) brightness(var(--wui-glass-brightness,1.06))}.wui-floating-panel[data-wui-presence=closing]{pointer-events:none;transition-duration:var(--wui-internal-duration-float-exit,var(--wui-duration-float-exit,.12s))}@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-internal-overlay-transform-origin, center);\n transform: scale(1);\n opacity: 1;\n transition:\n opacity var(--wui-internal-duration-
|
|
1
|
+
{"version":3,"file":"overlay-motion.js","names":[],"sources":["../../src/assets/overlay-motion.css?inline"],"sourcesContent":["/*\n * 浮层面板共享动效(单层玻璃)。\n *\n * backdrop-filter 的 blur(0px) ↔ blur(4px) 在 Chrome/Safari 均平滑插值(Manager\n * 双引擎实测,Safari 逐帧采样 blur 值连续),当年「生硬跳变」的根因是 none↔blur\n * 不可插值,而不是 backdrop-filter 不可动画。因此面板自身直接承担玻璃:背景、\n * 阴影与 backdrop-filter 都在面板元素上(wui-glass 类也回面板),打开/关闭时\n * opacity 与 backdrop-filter 同步过渡,无需双层结构——双层带来的全部层间问题\n * (变白、关闭残影、双重模糊、阴影作用域承接)一并消失。\n */\n\n.wui-floating-panel {\n transform-origin: var(--wui-internal-overlay-transform-origin, center);\n transform: scale(1);\n\n opacity: 1;\n\n /* 玻璃由面板自身承担(wui-glass 提供背景/描边/阴影)。打开目标态 blur(4px),\n entering/closing 切到 blur(0px) 作为插值起点——blur(0px) 与 blur(4px) 平滑过渡\n (none↔blur 不可插值才是当年生硬跳变的根因)。 */\n /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(4px) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n\n transition:\n opacity var(--wui-internal-duration-float-enter, var(--wui-duration-float-enter, 160ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n -webkit-backdrop-filter var(--wui-internal-duration-float-enter, var(--wui-duration-float-enter, 160ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n backdrop-filter var(--wui-internal-duration-float-enter, var(--wui-duration-float-enter, 160ms))\n var(--wui-ease-enter, cubic-bezier(0.23, 1, 0.32, 1)),\n transform var(--wui-internal-duration-float-enter, var(--wui-duration-float-enter, 160ms))\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 /* stylelint-disable-next-line property-no-vendor-prefix */\n -webkit-backdrop-filter: blur(0) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n backdrop-filter: blur(0) saturate(160%) brightness(var(--wui-glass-brightness, 1.06));\n}\n\n.wui-floating-panel[data-wui-presence='closing'] {\n pointer-events: none;\n transition-duration: var(--wui-internal-duration-float-exit, var(--wui-duration-float-exit, 120ms));\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":""}
|