sheer-ui 0.4.2 → 0.4.3
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/package.json +1 -1
- package/src/lib/components/avatar/avatar.svelte.ts +34 -37
- package/src/lib/components/avatar/components/avatar-fallback.svelte +9 -6
- package/src/lib/components/avatar/components/avatar-image.svelte +18 -9
- package/src/lib/components/avatar/components/avatar.svelte +20 -16
- package/src/lib/components/checkbox/checkbox.svelte.ts +45 -55
- package/src/lib/components/checkbox/components/checkbox-group-label.svelte +9 -6
- package/src/lib/components/checkbox/components/checkbox-group.svelte +25 -16
- package/src/lib/components/checkbox/components/checkbox.svelte +39 -25
- package/src/lib/components/dialog/components/dialog-close.svelte +13 -8
- package/src/lib/components/dialog/components/dialog-content-headless.svelte +14 -11
- package/src/lib/components/dialog/components/dialog-description.svelte +9 -6
- package/src/lib/components/dialog/components/dialog-overlay.svelte +10 -7
- package/src/lib/components/dialog/components/dialog-title.svelte +12 -7
- package/src/lib/components/dialog/components/dialog-trigger.svelte +12 -7
- package/src/lib/components/dialog/components/dialog.svelte +10 -4
- package/src/lib/components/dialog/components/modal-surface.svelte +11 -8
- package/src/lib/components/dialog/dialog.svelte.ts +73 -61
- package/src/lib/components/drawer/drawer.svelte +8 -3
- package/src/lib/components/link-preview/components/link-preview-content.svelte +15 -8
- package/src/lib/components/link-preview/components/link-preview-trigger.svelte +9 -6
- package/src/lib/components/link-preview/components/link-preview.svelte +19 -11
- package/src/lib/components/link-preview/link-preview.svelte.ts +42 -43
- package/src/lib/components/menu/menu.svelte.ts +20 -1
- package/src/lib/components/meter/components/meter.svelte +18 -9
- package/src/lib/components/meter/meter.svelte.ts +15 -18
- package/src/lib/components/popover/components/popover-close.svelte +9 -6
- package/src/lib/components/popover/components/popover-content.svelte +12 -7
- package/src/lib/components/popover/components/popover-trigger.svelte +21 -10
- package/src/lib/components/popover/components/popover.svelte +9 -8
- package/src/lib/components/popover/popover.svelte.ts +68 -74
- package/src/lib/components/progress/components/progress.svelte +18 -9
- package/src/lib/components/progress/progress.svelte.ts +14 -17
- package/src/lib/components/separator/components/separator.svelte +15 -8
- package/src/lib/components/separator/separator.svelte.ts +12 -15
- package/src/lib/components/sidebar/sidebar-mobile-surface.svelte +8 -4
- package/src/lib/components/toggle/components/toggle.svelte +19 -14
- package/src/lib/components/toggle/toggle.svelte.ts +15 -20
- package/src/lib/components/tooltip/components/tooltip-content.svelte +15 -8
- package/src/lib/components/tooltip/components/tooltip-provider.svelte +18 -7
- package/src/lib/components/tooltip/components/tooltip-trigger.svelte +21 -10
- package/src/lib/components/tooltip/components/tooltip.svelte +34 -21
- package/src/lib/components/tooltip/tooltip.svelte.ts +96 -99
- package/src/lib/internal/escape-layer/use-escape-layer.svelte.ts +13 -29
- package/src/lib/internal/group-value.svelte.ts +11 -10
- package/src/lib/internal/native-popover.svelte.ts +6 -6
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogCloseState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogCloseProps } from '../types.js';
|
|
@@ -10,13 +9,19 @@
|
|
|
10
9
|
let { children, child, id = createId(uid), ref = $bindable(null), disabled = false, ...restProps }: DialogCloseProps = $props();
|
|
11
10
|
|
|
12
11
|
const closeState = DialogCloseState.create({
|
|
13
|
-
variant:
|
|
14
|
-
id
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
variant: 'close',
|
|
13
|
+
get id() {
|
|
14
|
+
return id;
|
|
15
|
+
},
|
|
16
|
+
get ref() {
|
|
17
|
+
return ref;
|
|
18
|
+
},
|
|
19
|
+
set ref(v) {
|
|
20
|
+
ref = v;
|
|
21
|
+
},
|
|
22
|
+
get disabled() {
|
|
23
|
+
return Boolean(disabled);
|
|
24
|
+
},
|
|
20
25
|
});
|
|
21
26
|
|
|
22
27
|
const mergedProps = $derived(mergeProps({ 'data-slot': 'dialog-close' }, restProps, closeState.props));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogContentState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogContentProps } from '../types.js';
|
|
@@ -35,17 +34,21 @@
|
|
|
35
34
|
}: DialogContentProps = $props();
|
|
36
35
|
|
|
37
36
|
const contentState = DialogContentState.create({
|
|
38
|
-
id
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
get id() {
|
|
38
|
+
return id;
|
|
39
|
+
},
|
|
40
|
+
get ref() {
|
|
41
|
+
return ref;
|
|
42
|
+
},
|
|
43
|
+
set ref(v) {
|
|
44
|
+
ref = v;
|
|
45
|
+
},
|
|
43
46
|
});
|
|
44
47
|
|
|
45
48
|
// Closed state, on this element only (DialogContentState.props is shared with the native
|
|
46
49
|
// modal surface). The scroll lock's body styles land a tick after opening, after vaul's
|
|
47
50
|
// open effect has snapshotted them, as they did when the mount gate flipped a flush later.
|
|
48
|
-
const mergedProps = $derived(mergeProps(restProps, contentState.props, { style: contentState.root.
|
|
51
|
+
const mergedProps = $derived(mergeProps(restProps, contentState.props, { style: contentState.root.opts.open ? {} : { visibility: 'hidden' } }));
|
|
49
52
|
|
|
50
53
|
const escapeAttachment = escapeKeydownAttachment({
|
|
51
54
|
escapeKeydownBehavior: () => restProps.escapeKeydownBehavior ?? 'close',
|
|
@@ -54,7 +57,7 @@
|
|
|
54
57
|
if (e.defaultPrevented) return;
|
|
55
58
|
contentState.root.handleClose();
|
|
56
59
|
},
|
|
57
|
-
enabled: () => contentState.root.
|
|
60
|
+
enabled: () => contentState.root.opts.open,
|
|
58
61
|
});
|
|
59
62
|
|
|
60
63
|
// Dialog content historically dropped the dismissible focus-capture props (its default-slot
|
|
@@ -68,12 +71,12 @@
|
|
|
68
71
|
contentState.root.handleClose();
|
|
69
72
|
},
|
|
70
73
|
onFocusOutside: () => restProps.onFocusOutside,
|
|
71
|
-
enabled: () => contentState.root.
|
|
74
|
+
enabled: () => contentState.root.opts.open,
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
// Flags the open surface for the CSS text-selection guard in ui.css.
|
|
75
78
|
const textSelectionGuard = $derived(
|
|
76
|
-
contentState.root.
|
|
79
|
+
contentState.root.opts.open && (restProps.preventOverflowTextSelection ?? true) ? { 'data-text-selection-guard': '' } : {},
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
// Spans `present` (open through the settled exit), the window element lifecycle used to
|
|
@@ -84,7 +87,7 @@
|
|
|
84
87
|
});
|
|
85
88
|
|
|
86
89
|
const focusScope = createFocusScopeProps({
|
|
87
|
-
enabled: () => contentState.root.
|
|
90
|
+
enabled: () => contentState.root.opts.open,
|
|
88
91
|
trap: () => trapFocus,
|
|
89
92
|
loop: () => true,
|
|
90
93
|
onCloseAutoFocus: () => onCloseAutoFocus,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogDescriptionState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogDescriptionProps } from '../types.js';
|
|
@@ -10,11 +9,15 @@
|
|
|
10
9
|
let { id = createId(uid), children, child, ref = $bindable(null), ...restProps }: DialogDescriptionProps = $props();
|
|
11
10
|
|
|
12
11
|
const descriptionState = DialogDescriptionState.create({
|
|
13
|
-
id
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
get id() {
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
get ref() {
|
|
16
|
+
return ref;
|
|
17
|
+
},
|
|
18
|
+
set ref(v) {
|
|
19
|
+
ref = v;
|
|
20
|
+
},
|
|
18
21
|
});
|
|
19
22
|
|
|
20
23
|
const mergedProps = $derived(mergeProps(restProps, descriptionState.props));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogOverlayState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogOverlayProps } from '../types.js';
|
|
@@ -10,16 +9,20 @@
|
|
|
10
9
|
let { id = createId(uid), child, children, ref = $bindable(null), ...restProps }: DialogOverlayProps = $props();
|
|
11
10
|
|
|
12
11
|
const overlayState = DialogOverlayState.create({
|
|
13
|
-
id
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
get id() {
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
get ref() {
|
|
16
|
+
return ref;
|
|
17
|
+
},
|
|
18
|
+
set ref(v) {
|
|
19
|
+
ref = v;
|
|
20
|
+
},
|
|
18
21
|
});
|
|
19
22
|
|
|
20
23
|
// Always mounted; closed is visibility:hidden here, and the adapter's exit (the drawer's fadeOut
|
|
21
24
|
// keyframe, the sheet's overlay-surface transition) holds it visible while it plays.
|
|
22
|
-
const mergedProps = $derived(mergeProps(restProps, overlayState.props, { style: overlayState.root.
|
|
25
|
+
const mergedProps = $derived(mergeProps(restProps, overlayState.props, { style: overlayState.root.opts.open ? {} : { visibility: 'hidden' } }));
|
|
23
26
|
</script>
|
|
24
27
|
|
|
25
28
|
{#if child}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogTitleState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogTitleProps } from '../types.js';
|
|
@@ -10,12 +9,18 @@
|
|
|
10
9
|
let { id = createId(uid), ref = $bindable(null), child, children, level = 2, ...restProps }: DialogTitleProps = $props();
|
|
11
10
|
|
|
12
11
|
const titleState = DialogTitleState.create({
|
|
13
|
-
id
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
get id() {
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
get level() {
|
|
16
|
+
return level;
|
|
17
|
+
},
|
|
18
|
+
get ref() {
|
|
19
|
+
return ref;
|
|
20
|
+
},
|
|
21
|
+
set ref(v) {
|
|
22
|
+
ref = v;
|
|
23
|
+
},
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
const mergedProps = $derived(mergeProps(restProps, titleState.props));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
4
3
|
import { DialogTriggerState } from '../dialog.svelte.js';
|
|
5
4
|
import type { DialogTriggerProps } from '../types.js';
|
|
@@ -10,12 +9,18 @@
|
|
|
10
9
|
let { id = createId(uid), ref = $bindable(null), children, child, disabled = false, ...restProps }: DialogTriggerProps = $props();
|
|
11
10
|
|
|
12
11
|
const triggerState = DialogTriggerState.create({
|
|
13
|
-
id
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
get id() {
|
|
13
|
+
return id;
|
|
14
|
+
},
|
|
15
|
+
get ref() {
|
|
16
|
+
return ref;
|
|
17
|
+
},
|
|
18
|
+
set ref(v) {
|
|
19
|
+
ref = v;
|
|
20
|
+
},
|
|
21
|
+
get disabled() {
|
|
22
|
+
return Boolean(disabled);
|
|
23
|
+
},
|
|
19
24
|
});
|
|
20
25
|
|
|
21
26
|
const mergedProps = $derived(mergeProps(restProps, triggerState.props));
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
3
2
|
import { DialogRootState, DialogState } from '../dialog.svelte.js';
|
|
4
3
|
import type { DialogRootProps } from '../types.js';
|
|
5
4
|
|
|
@@ -12,9 +11,16 @@
|
|
|
12
11
|
// svelte-ignore state_referenced_locally
|
|
13
12
|
const dialog = state ?? new DialogState(() => open);
|
|
14
13
|
DialogRootState.create({
|
|
15
|
-
variant:
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
variant: 'dialog',
|
|
15
|
+
get open() {
|
|
16
|
+
return dialog.open;
|
|
17
|
+
},
|
|
18
|
+
set open(v) {
|
|
19
|
+
dialog.open = v;
|
|
20
|
+
},
|
|
21
|
+
get onOpenChangeComplete() {
|
|
22
|
+
return onOpenChangeComplete;
|
|
23
|
+
},
|
|
18
24
|
});
|
|
19
25
|
</script>
|
|
20
26
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
3
|
-
import { boxWith } from '../../../internal/tools/index.js';
|
|
4
3
|
import { mergeProps } from '../../../internal/merge-props.js';
|
|
5
4
|
import { DialogContentState } from '../dialog.svelte.js';
|
|
6
5
|
import type { DialogContentProps, DialogPortalProps } from '../types.js';
|
|
@@ -84,11 +83,15 @@
|
|
|
84
83
|
} = $props();
|
|
85
84
|
|
|
86
85
|
const contentState = DialogContentState.create({
|
|
87
|
-
id
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
get id() {
|
|
87
|
+
return id;
|
|
88
|
+
},
|
|
89
|
+
get ref() {
|
|
90
|
+
return ref;
|
|
91
|
+
},
|
|
92
|
+
set ref(v) {
|
|
93
|
+
ref = v;
|
|
94
|
+
},
|
|
92
95
|
});
|
|
93
96
|
|
|
94
97
|
// Bridge the shared root `open` to the native top-layer API and mirror native dismissal back
|
|
@@ -99,7 +102,7 @@
|
|
|
99
102
|
// `contentNode` (set by DialogContentState) and fires it once the <dialog>'s animations
|
|
100
103
|
// settle (useOpenChangeComplete) — a listener here would double-fire it.
|
|
101
104
|
const controllerAttachment = nativeDialogControllerAttachment({
|
|
102
|
-
open: () => contentState.root.
|
|
105
|
+
open: () => contentState.root.opts.open,
|
|
103
106
|
onClose: () => contentState.root.handleClose(),
|
|
104
107
|
// the controller takes this as a plain, non-reactive value — fixed per adapter at mount
|
|
105
108
|
// svelte-ignore state_referenced_locally
|
|
@@ -113,7 +116,7 @@
|
|
|
113
116
|
|
|
114
117
|
// The <dialog> persists across open/close, so the lock gates on the cell's open, not element lifecycle.
|
|
115
118
|
const scrollLock = scrollLockAttachment({
|
|
116
|
-
enabled: () => contentState.root.
|
|
119
|
+
enabled: () => contentState.root.opts.open && preventScroll,
|
|
117
120
|
restoreScrollDelay: () => restoreScrollDelay,
|
|
118
121
|
});
|
|
119
122
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { attachRef
|
|
1
|
+
import { attachRef } from '../../internal/tools/index.js';
|
|
2
2
|
import { createContext, onDestroy, untrack } from 'svelte';
|
|
3
3
|
import { createBitsAttrs, boolToStr, getDataOpenClosed, boolToEmptyStrOrUndef } from '../../internal/attrs.js';
|
|
4
|
-
import type { BitsKeyboardEvent, BitsMouseEvent, OnChangeFn, RefAttachment,
|
|
4
|
+
import type { BitsKeyboardEvent, BitsMouseEvent, OnChangeFn, RefAttachment, RefOpts } from '../../internal/types.js';
|
|
5
5
|
import { kbd } from '../../internal/kbd.js';
|
|
6
6
|
import { useOpenChangeComplete } from '../../internal/animations-settled.svelte.js';
|
|
7
7
|
|
|
@@ -19,12 +19,10 @@ const [getDialogRoot, setDialogRoot, hasDialogRoot] = createContext<DialogRootSt
|
|
|
19
19
|
import { OpenCell as DialogState } from '../../internal/open-cell.svelte.js';
|
|
20
20
|
export { DialogState };
|
|
21
21
|
|
|
22
|
-
interface DialogRootStateOpts
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}> {
|
|
27
|
-
cell: DialogState;
|
|
22
|
+
interface DialogRootStateOpts {
|
|
23
|
+
readonly variant: DialogVariant;
|
|
24
|
+
readonly onOpenChangeComplete: OnChangeFn<boolean>;
|
|
25
|
+
open: boolean;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export class DialogRootState {
|
|
@@ -34,7 +32,6 @@ export class DialogRootState {
|
|
|
34
32
|
}
|
|
35
33
|
|
|
36
34
|
readonly opts: DialogRootStateOpts;
|
|
37
|
-
readonly cell: DialogState;
|
|
38
35
|
triggerNode = $state<HTMLElement | null>(null);
|
|
39
36
|
contentNode = $state<HTMLElement | null>(null);
|
|
40
37
|
descriptionNode = $state<HTMLElement | null>(null);
|
|
@@ -42,33 +39,32 @@ export class DialogRootState {
|
|
|
42
39
|
triggerId = $state<string | undefined>(undefined);
|
|
43
40
|
titleState = $state<DialogTitleState | null>(null);
|
|
44
41
|
descriptionState = $state<DialogDescriptionState | null>(null);
|
|
45
|
-
readonly titleId = $derived.by(() => this.titleState?.opts.id
|
|
46
|
-
readonly descriptionId = $derived.by(() => this.descriptionState?.opts.id
|
|
42
|
+
readonly titleId = $derived.by(() => this.titleState?.opts.id);
|
|
43
|
+
readonly descriptionId = $derived.by(() => this.descriptionState?.opts.id);
|
|
47
44
|
cancelNode = $state<HTMLElement | null>(null);
|
|
48
45
|
nestedOpenCount = $state(0);
|
|
49
46
|
readonly depth: number;
|
|
50
47
|
readonly parent: DialogRootState | null;
|
|
51
48
|
readonly #completion: { readonly pending: boolean };
|
|
52
49
|
/** Rendered: open, or closing with the exit still settling — the window the headless content's scroll lock covers. */
|
|
53
|
-
readonly present = $derived.by(() => this.
|
|
50
|
+
readonly present = $derived.by(() => this.opts.open || this.#completion.pending);
|
|
54
51
|
|
|
55
52
|
constructor(opts: DialogRootStateOpts, parent: DialogRootState | null) {
|
|
56
53
|
this.opts = opts;
|
|
57
|
-
this.cell = opts.cell;
|
|
58
54
|
this.parent = parent;
|
|
59
55
|
this.depth = parent ? parent.depth + 1 : 0;
|
|
60
56
|
this.handleOpen = this.handleOpen.bind(this);
|
|
61
57
|
this.handleClose = this.handleClose.bind(this);
|
|
62
58
|
|
|
63
59
|
this.#completion = useOpenChangeComplete(
|
|
64
|
-
() => this.
|
|
60
|
+
() => this.opts.open,
|
|
65
61
|
() => this.contentNode,
|
|
66
|
-
(isOpen) => this.opts.onOpenChangeComplete
|
|
62
|
+
(isOpen) => this.opts.onOpenChangeComplete(isOpen),
|
|
67
63
|
);
|
|
68
64
|
|
|
69
65
|
let started = false;
|
|
70
66
|
$effect(() => {
|
|
71
|
-
const isOpen = this.
|
|
67
|
+
const isOpen = this.opts.open;
|
|
72
68
|
if (!started) {
|
|
73
69
|
started = true;
|
|
74
70
|
return;
|
|
@@ -84,22 +80,22 @@ export class DialogRootState {
|
|
|
84
80
|
});
|
|
85
81
|
|
|
86
82
|
onDestroy(() => {
|
|
87
|
-
if (this.
|
|
83
|
+
if (this.opts.open) {
|
|
88
84
|
this.parent?.decrementNested();
|
|
89
85
|
}
|
|
90
86
|
});
|
|
91
87
|
}
|
|
92
88
|
|
|
93
89
|
handleOpen() {
|
|
94
|
-
this.
|
|
90
|
+
this.opts.open = true;
|
|
95
91
|
}
|
|
96
92
|
|
|
97
93
|
handleClose() {
|
|
98
|
-
this.
|
|
94
|
+
this.opts.open = false;
|
|
99
95
|
}
|
|
100
96
|
|
|
101
97
|
getBitsAttr: typeof dialogAttrs.getAttr = (part) => {
|
|
102
|
-
return dialogAttrs.getAttr(part, this.opts.variant
|
|
98
|
+
return dialogAttrs.getAttr(part, this.opts.variant);
|
|
103
99
|
};
|
|
104
100
|
|
|
105
101
|
incrementNested() {
|
|
@@ -116,12 +112,14 @@ export class DialogRootState {
|
|
|
116
112
|
readonly sharedProps = $derived.by(
|
|
117
113
|
() =>
|
|
118
114
|
({
|
|
119
|
-
'data-state': getDataOpenClosed(this.
|
|
115
|
+
'data-state': getDataOpenClosed(this.opts.open),
|
|
120
116
|
}) as const,
|
|
121
117
|
);
|
|
122
118
|
}
|
|
123
119
|
|
|
124
|
-
interface DialogTriggerStateOpts extends
|
|
120
|
+
interface DialogTriggerStateOpts extends RefOpts {
|
|
121
|
+
readonly disabled: boolean;
|
|
122
|
+
}
|
|
125
123
|
|
|
126
124
|
export class DialogTriggerState {
|
|
127
125
|
static create(opts: DialogTriggerStateOpts) {
|
|
@@ -135,22 +133,25 @@ export class DialogTriggerState {
|
|
|
135
133
|
constructor(opts: DialogTriggerStateOpts, root: DialogRootState) {
|
|
136
134
|
this.opts = opts;
|
|
137
135
|
this.root = root;
|
|
138
|
-
this.attachment = attachRef(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
this.attachment = attachRef<HTMLElement>(
|
|
137
|
+
(v) => (opts.ref = v),
|
|
138
|
+
(v) => {
|
|
139
|
+
this.root.triggerNode = v;
|
|
140
|
+
this.root.triggerId = v?.id;
|
|
141
|
+
},
|
|
142
|
+
);
|
|
142
143
|
this.onclick = this.onclick.bind(this);
|
|
143
144
|
this.onkeydown = this.onkeydown.bind(this);
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
onclick(e: BitsMouseEvent) {
|
|
147
|
-
if (this.opts.disabled
|
|
148
|
+
if (this.opts.disabled) return;
|
|
148
149
|
if (e.button > 0) return;
|
|
149
150
|
this.root.handleOpen();
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
onkeydown(e: BitsKeyboardEvent) {
|
|
153
|
-
if (this.opts.disabled
|
|
154
|
+
if (this.opts.disabled) return;
|
|
154
155
|
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
|
155
156
|
e.preventDefault();
|
|
156
157
|
this.root.handleOpen();
|
|
@@ -160,21 +161,24 @@ export class DialogTriggerState {
|
|
|
160
161
|
readonly props = $derived.by(
|
|
161
162
|
() =>
|
|
162
163
|
({
|
|
163
|
-
id: this.opts.id
|
|
164
|
+
id: this.opts.id,
|
|
164
165
|
'aria-haspopup': 'dialog',
|
|
165
|
-
'aria-expanded': boolToStr(this.root.
|
|
166
|
+
'aria-expanded': boolToStr(this.root.opts.open),
|
|
166
167
|
'aria-controls': this.root.contentId,
|
|
167
168
|
[this.root.getBitsAttr('trigger')]: '',
|
|
168
169
|
onkeydown: this.onkeydown,
|
|
169
170
|
onclick: this.onclick,
|
|
170
|
-
disabled: this.opts.disabled
|
|
171
|
+
disabled: this.opts.disabled ? true : undefined,
|
|
171
172
|
...this.root.sharedProps,
|
|
172
173
|
...this.attachment,
|
|
173
174
|
}) as const,
|
|
174
175
|
);
|
|
175
176
|
}
|
|
176
177
|
|
|
177
|
-
interface DialogCloseStateOpts extends
|
|
178
|
+
interface DialogCloseStateOpts extends RefOpts {
|
|
179
|
+
readonly variant: 'action' | 'cancel' | 'close';
|
|
180
|
+
readonly disabled: boolean;
|
|
181
|
+
}
|
|
178
182
|
|
|
179
183
|
export class DialogCloseState {
|
|
180
184
|
static create(opts: DialogCloseStateOpts) {
|
|
@@ -188,19 +192,19 @@ export class DialogCloseState {
|
|
|
188
192
|
constructor(opts: DialogCloseStateOpts, root: DialogRootState) {
|
|
189
193
|
this.opts = opts;
|
|
190
194
|
this.root = root;
|
|
191
|
-
this.attachment = attachRef(
|
|
195
|
+
this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
|
|
192
196
|
this.onclick = this.onclick.bind(this);
|
|
193
197
|
this.onkeydown = this.onkeydown.bind(this);
|
|
194
198
|
}
|
|
195
199
|
|
|
196
200
|
onclick(e: BitsMouseEvent) {
|
|
197
|
-
if (this.opts.disabled
|
|
201
|
+
if (this.opts.disabled) return;
|
|
198
202
|
if (e.button > 0) return;
|
|
199
203
|
this.root.handleClose();
|
|
200
204
|
}
|
|
201
205
|
|
|
202
206
|
onkeydown(e: BitsKeyboardEvent) {
|
|
203
|
-
if (this.opts.disabled
|
|
207
|
+
if (this.opts.disabled) return;
|
|
204
208
|
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
|
|
205
209
|
e.preventDefault();
|
|
206
210
|
this.root.handleClose();
|
|
@@ -210,11 +214,11 @@ export class DialogCloseState {
|
|
|
210
214
|
readonly props = $derived.by(
|
|
211
215
|
() =>
|
|
212
216
|
({
|
|
213
|
-
id: this.opts.id
|
|
214
|
-
[this.root.getBitsAttr(this.opts.variant
|
|
217
|
+
id: this.opts.id,
|
|
218
|
+
[this.root.getBitsAttr(this.opts.variant)]: '',
|
|
215
219
|
onclick: this.onclick,
|
|
216
220
|
onkeydown: this.onkeydown,
|
|
217
|
-
disabled: this.opts.disabled
|
|
221
|
+
disabled: this.opts.disabled ? true : undefined,
|
|
218
222
|
tabindex: 0,
|
|
219
223
|
...this.root.sharedProps,
|
|
220
224
|
...this.attachment,
|
|
@@ -222,7 +226,9 @@ export class DialogCloseState {
|
|
|
222
226
|
);
|
|
223
227
|
}
|
|
224
228
|
|
|
225
|
-
interface DialogTitleStateOpts extends
|
|
229
|
+
interface DialogTitleStateOpts extends RefOpts {
|
|
230
|
+
readonly level: 1 | 2 | 3 | 4 | 5 | 6;
|
|
231
|
+
}
|
|
226
232
|
|
|
227
233
|
export class DialogTitleState {
|
|
228
234
|
static create(opts: DialogTitleStateOpts) {
|
|
@@ -237,15 +243,15 @@ export class DialogTitleState {
|
|
|
237
243
|
this.opts = opts;
|
|
238
244
|
this.root = root;
|
|
239
245
|
this.root.titleState = this;
|
|
240
|
-
this.attachment = attachRef(
|
|
246
|
+
this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
|
|
241
247
|
}
|
|
242
248
|
|
|
243
249
|
readonly props = $derived.by(
|
|
244
250
|
() =>
|
|
245
251
|
({
|
|
246
|
-
id: this.opts.id
|
|
252
|
+
id: this.opts.id,
|
|
247
253
|
role: 'heading',
|
|
248
|
-
'aria-level': this.opts.level
|
|
254
|
+
'aria-level': this.opts.level,
|
|
249
255
|
[this.root.getBitsAttr('title')]: '',
|
|
250
256
|
...this.root.sharedProps,
|
|
251
257
|
...this.attachment,
|
|
@@ -253,7 +259,7 @@ export class DialogTitleState {
|
|
|
253
259
|
);
|
|
254
260
|
}
|
|
255
261
|
|
|
256
|
-
interface DialogDescriptionStateOpts extends
|
|
262
|
+
interface DialogDescriptionStateOpts extends RefOpts {}
|
|
257
263
|
|
|
258
264
|
export class DialogDescriptionState {
|
|
259
265
|
static create(opts: DialogDescriptionStateOpts) {
|
|
@@ -268,15 +274,18 @@ export class DialogDescriptionState {
|
|
|
268
274
|
this.opts = opts;
|
|
269
275
|
this.root = root;
|
|
270
276
|
this.root.descriptionState = this;
|
|
271
|
-
this.attachment = attachRef(
|
|
272
|
-
|
|
273
|
-
|
|
277
|
+
this.attachment = attachRef<HTMLElement>(
|
|
278
|
+
(v) => (opts.ref = v),
|
|
279
|
+
(v) => {
|
|
280
|
+
this.root.descriptionNode = v;
|
|
281
|
+
},
|
|
282
|
+
);
|
|
274
283
|
}
|
|
275
284
|
|
|
276
285
|
readonly props = $derived.by(
|
|
277
286
|
() =>
|
|
278
287
|
({
|
|
279
|
-
id: this.opts.id
|
|
288
|
+
id: this.opts.id,
|
|
280
289
|
[this.root.getBitsAttr('description')]: '',
|
|
281
290
|
...this.root.sharedProps,
|
|
282
291
|
...this.attachment,
|
|
@@ -284,7 +293,7 @@ export class DialogDescriptionState {
|
|
|
284
293
|
);
|
|
285
294
|
}
|
|
286
295
|
|
|
287
|
-
interface DialogContentStateOpts extends
|
|
296
|
+
interface DialogContentStateOpts extends RefOpts {}
|
|
288
297
|
|
|
289
298
|
export class DialogContentState {
|
|
290
299
|
static create(opts: DialogContentStateOpts) {
|
|
@@ -298,26 +307,29 @@ export class DialogContentState {
|
|
|
298
307
|
constructor(opts: DialogContentStateOpts, root: DialogRootState) {
|
|
299
308
|
this.opts = opts;
|
|
300
309
|
this.root = root;
|
|
301
|
-
this.attachment = attachRef(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
310
|
+
this.attachment = attachRef<HTMLElement>(
|
|
311
|
+
(v) => (opts.ref = v),
|
|
312
|
+
(v) => {
|
|
313
|
+
this.root.contentNode = v;
|
|
314
|
+
this.root.contentId = v?.id;
|
|
315
|
+
},
|
|
316
|
+
);
|
|
305
317
|
}
|
|
306
318
|
|
|
307
|
-
readonly snippetProps = $derived.by(() => ({ open: this.root.
|
|
319
|
+
readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open }));
|
|
308
320
|
|
|
309
321
|
readonly props = $derived.by(
|
|
310
322
|
() =>
|
|
311
323
|
({
|
|
312
|
-
id: this.opts.id
|
|
313
|
-
role: this.root.opts.variant
|
|
324
|
+
id: this.opts.id,
|
|
325
|
+
role: this.root.opts.variant === 'alert-dialog' ? 'alertdialog' : 'dialog',
|
|
314
326
|
'aria-modal': 'true',
|
|
315
327
|
'aria-describedby': this.root.descriptionId,
|
|
316
328
|
'aria-labelledby': this.root.titleId,
|
|
317
329
|
[this.root.getBitsAttr('content')]: '',
|
|
318
330
|
style: {
|
|
319
331
|
pointerEvents: 'auto',
|
|
320
|
-
outline: this.root.opts.variant
|
|
332
|
+
outline: this.root.opts.variant === 'alert-dialog' ? 'none' : undefined,
|
|
321
333
|
'--bits-dialog-depth': this.root.depth,
|
|
322
334
|
'--bits-dialog-nested-count': this.root.nestedOpenCount,
|
|
323
335
|
// CSS containment isolates style/layout calculations from the rest of the page,
|
|
@@ -325,7 +337,7 @@ export class DialogContentState {
|
|
|
325
337
|
// Paint is omitted so tooltips/selects can render outside dialog bounds.
|
|
326
338
|
contain: 'layout style',
|
|
327
339
|
},
|
|
328
|
-
tabindex: this.root.opts.variant
|
|
340
|
+
tabindex: this.root.opts.variant === 'alert-dialog' ? -1 : undefined,
|
|
329
341
|
'data-nested-open': boolToEmptyStrOrUndef(this.root.nestedOpenCount > 0),
|
|
330
342
|
'data-nested': boolToEmptyStrOrUndef(this.root.parent !== null),
|
|
331
343
|
...this.root.sharedProps,
|
|
@@ -334,7 +346,7 @@ export class DialogContentState {
|
|
|
334
346
|
);
|
|
335
347
|
}
|
|
336
348
|
|
|
337
|
-
interface DialogOverlayStateOpts extends
|
|
349
|
+
interface DialogOverlayStateOpts extends RefOpts {}
|
|
338
350
|
|
|
339
351
|
export class DialogOverlayState {
|
|
340
352
|
static create(opts: DialogOverlayStateOpts) {
|
|
@@ -347,15 +359,15 @@ export class DialogOverlayState {
|
|
|
347
359
|
constructor(opts: DialogOverlayStateOpts, root: DialogRootState) {
|
|
348
360
|
this.opts = opts;
|
|
349
361
|
this.root = root;
|
|
350
|
-
this.attachment = attachRef(
|
|
362
|
+
this.attachment = attachRef<HTMLElement>((v) => (opts.ref = v));
|
|
351
363
|
}
|
|
352
364
|
|
|
353
|
-
readonly snippetProps = $derived.by(() => ({ open: this.root.
|
|
365
|
+
readonly snippetProps = $derived.by(() => ({ open: this.root.opts.open }));
|
|
354
366
|
|
|
355
367
|
readonly props = $derived.by(
|
|
356
368
|
() =>
|
|
357
369
|
({
|
|
358
|
-
id: this.opts.id
|
|
370
|
+
id: this.opts.id,
|
|
359
371
|
[this.root.getBitsAttr('overlay')]: '',
|
|
360
372
|
style: {
|
|
361
373
|
pointerEvents: 'auto',
|
|
@@ -118,9 +118,14 @@
|
|
|
118
118
|
});
|
|
119
119
|
|
|
120
120
|
DialogRootState.create({
|
|
121
|
-
variant:
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
variant: 'dialog',
|
|
122
|
+
get open() {
|
|
123
|
+
return dialogCell.open;
|
|
124
|
+
},
|
|
125
|
+
set open(v) {
|
|
126
|
+
dialogCell.open = v;
|
|
127
|
+
},
|
|
128
|
+
onOpenChangeComplete: handleOpenChangeComplete,
|
|
124
129
|
});
|
|
125
130
|
</script>
|
|
126
131
|
|