@dryui/ui 1.1.5 → 1.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/dist/accordion/accordion-button-trigger.svelte +6 -0
- package/dist/alert/alert.svelte +2 -1
- package/dist/alert-dialog/alert-dialog-content.svelte +9 -69
- package/dist/alpha-slider/alpha-slider-input.svelte +4 -0
- package/dist/avatar/avatar.svelte +3 -4
- package/dist/backdrop/backdrop.svelte +12 -9
- package/dist/badge/badge.svelte +84 -72
- package/dist/button/button.svelte +3 -6
- package/dist/button-group/button-group.svelte +2 -2
- package/dist/calendar/calendar-button-grid.svelte +1 -1
- package/dist/card/card-root.svelte +9 -4
- package/dist/chip-group/chip-group-root.svelte +2 -2
- package/dist/code-block/code-block-button.svelte +6 -2
- package/dist/context-menu/context-menu-content.svelte +12 -79
- package/dist/diagram/diagram.svelte +3 -4
- package/dist/dialog/dialog-content.svelte +5 -103
- package/dist/drag-and-drop/drag-and-drop-item.svelte +1 -1
- package/dist/drawer/drawer-dialog-content.svelte +5 -155
- package/dist/dropdown-menu/dropdown-menu-content.svelte +14 -71
- package/dist/heading/heading.svelte +7 -6
- package/dist/hover-card/hover-card-content.svelte +3 -12
- package/dist/icon/icon.svelte +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/input/input.svelte +3 -3
- package/dist/internal/calendar-grid-button.svelte +29 -26
- package/dist/internal/calendar-grid-button.svelte.d.ts +1 -0
- package/dist/internal/close-button-base.svelte +15 -2
- package/dist/internal/close-button-base.svelte.d.ts +1 -0
- package/dist/internal/modal-content.svelte +331 -0
- package/dist/internal/modal-content.svelte.d.ts +26 -0
- package/dist/link-preview/link-preview-content.svelte +3 -11
- package/dist/logo-mark/logo-mark.svelte +2 -3
- package/dist/mask-reveal/mask-reveal.svelte +17 -14
- package/dist/mega-menu/mega-menu-panel.svelte +14 -2
- package/dist/mega-menu/mega-menu-panel.svelte.d.ts +1 -0
- package/dist/menubar/menubar-content.svelte +21 -81
- package/dist/noise/noise.svelte +1 -0
- package/dist/option-picker/option-picker-preview.svelte +11 -10
- package/dist/popover/popover-content.svelte +10 -36
- package/dist/progress/progress.svelte +2 -2
- package/dist/prompt-input/index.d.ts +13 -1
- package/dist/prompt-input/prompt-input-button-textarea.svelte +13 -1
- package/dist/prompt-input/prompt-input-button-textarea.svelte.d.ts +3 -0
- package/dist/shimmer/shimmer.svelte +28 -3
- package/dist/slider/slider-input.svelte +3 -4
- package/dist/spacer/spacer.svelte +2 -2
- package/dist/spinner/spinner.svelte +2 -2
- package/dist/tabs/tabs-content.svelte +1 -1
- package/dist/tabs/tabs-list.svelte +1 -0
- package/dist/tag/tag-button.svelte +2 -3
- package/dist/text/text.svelte +4 -15
- package/dist/themes/dark.css +40 -24
- package/dist/themes/default.css +16 -12
- package/dist/themes/token-scope.d.ts +1 -0
- package/dist/themes/token-scope.js +1 -0
- package/dist/timeline/timeline-icon.svelte +11 -1
- package/dist/timeline/timeline-item.svelte +18 -5
- package/dist/timeline/timeline-root.svelte +3 -10
- package/dist/toast/toast-close-button.svelte +19 -7
- package/dist/toast/toast-provider.svelte +22 -1
- package/dist/toggle/toggle-button.svelte +7 -3
- package/dist/toggle-group/toggle-group-root.svelte +2 -2
- package/dist/tooltip/tooltip-content.svelte +8 -32
- package/dist/tour/tour-root.css +26 -26
- package/dist/tree/tree-item-label.svelte +8 -14
- package/dist/tree/tree-item-label.svelte.d.ts +2 -2
- package/dist/typography/heading.svelte +7 -6
- package/dist/typography/text.svelte +4 -3
- package/package.json +6 -2
- package/skills/dryui/SKILL.md +3 -3
- package/skills/dryui/rules/native-web-transitions.md +2 -2
- package/dist/themes/use-theme-override.svelte.d.ts +0 -1
- package/dist/themes/use-theme-override.svelte.js +0 -1
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { createDismiss, createMenuNavigation } from '@dryui/primitives';
|
|
4
5
|
import { getContextMenuCtx } from './context.svelte.js';
|
|
5
6
|
|
|
6
|
-
const MENU_ITEM_SELECTOR = '[role="menuitem"]:not([data-disabled])';
|
|
7
|
-
|
|
8
7
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
9
8
|
children: Snippet;
|
|
10
9
|
}
|
|
@@ -15,15 +14,10 @@
|
|
|
15
14
|
|
|
16
15
|
let el = $state<HTMLDivElement>();
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function focusItem(items: HTMLElement[], index: number): void {
|
|
23
|
-
if (items.length === 0) return;
|
|
24
|
-
const clamped = ((index % items.length) + items.length) % items.length;
|
|
25
|
-
items[clamped]?.focus();
|
|
26
|
-
}
|
|
17
|
+
const menu = createMenuNavigation({
|
|
18
|
+
container: () => el ?? null,
|
|
19
|
+
orientation: 'vertical'
|
|
20
|
+
});
|
|
27
21
|
|
|
28
22
|
$effect(() => {
|
|
29
23
|
if (ctx.open && el) {
|
|
@@ -32,80 +26,19 @@
|
|
|
32
26
|
el.style.top = `${ctx.position.y}px`;
|
|
33
27
|
if (!el.matches(':popover-open')) {
|
|
34
28
|
el.showPopover();
|
|
35
|
-
|
|
36
|
-
const first = items[0];
|
|
37
|
-
if (first) {
|
|
38
|
-
first.focus();
|
|
39
|
-
} else {
|
|
40
|
-
el.focus();
|
|
41
|
-
}
|
|
29
|
+
menu.focusFirst();
|
|
42
30
|
}
|
|
43
31
|
} else if (!ctx.open && el?.matches(':popover-open')) {
|
|
44
32
|
el.hidePopover();
|
|
45
33
|
}
|
|
46
34
|
});
|
|
47
35
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (el?.contains(e.target as Node)) return;
|
|
54
|
-
ctx.close();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function handleKeydown(e: KeyboardEvent) {
|
|
58
|
-
if (e.key === 'Escape') {
|
|
59
|
-
e.preventDefault();
|
|
60
|
-
ctx.close();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
document.addEventListener('pointerdown', handlePointerDown);
|
|
65
|
-
document.addEventListener('keydown', handleKeydown, true);
|
|
66
|
-
return () => {
|
|
67
|
-
document.removeEventListener('pointerdown', handlePointerDown);
|
|
68
|
-
document.removeEventListener('keydown', handleKeydown, true);
|
|
69
|
-
};
|
|
36
|
+
createDismiss({
|
|
37
|
+
enabled: () => ctx.open,
|
|
38
|
+
onDismiss: () => ctx.close(),
|
|
39
|
+
contentEl: () => el ?? null,
|
|
40
|
+
preventDefaultOnEscape: true
|
|
70
41
|
});
|
|
71
|
-
|
|
72
|
-
function handleKeydown(e: KeyboardEvent) {
|
|
73
|
-
if (!el) return;
|
|
74
|
-
const items = getMenuItems(el);
|
|
75
|
-
const currentIndex = items.indexOf(document.activeElement as HTMLElement);
|
|
76
|
-
|
|
77
|
-
switch (e.key) {
|
|
78
|
-
case 'ArrowDown': {
|
|
79
|
-
e.preventDefault();
|
|
80
|
-
focusItem(items, currentIndex + 1);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
case 'ArrowUp': {
|
|
84
|
-
e.preventDefault();
|
|
85
|
-
focusItem(items, currentIndex - 1);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
case 'Home': {
|
|
89
|
-
e.preventDefault();
|
|
90
|
-
focusItem(items, 0);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
case 'End': {
|
|
94
|
-
e.preventDefault();
|
|
95
|
-
focusItem(items, items.length - 1);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
default: {
|
|
99
|
-
if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
100
|
-
const char = e.key.toLowerCase();
|
|
101
|
-
const match = items.find((item) =>
|
|
102
|
-
item.textContent?.trim().toLowerCase().startsWith(char)
|
|
103
|
-
);
|
|
104
|
-
if (match) match.focus();
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
42
|
</script>
|
|
110
43
|
|
|
111
44
|
<div
|
|
@@ -119,7 +52,7 @@
|
|
|
119
52
|
data-state={ctx.open ? 'open' : 'closed'}
|
|
120
53
|
class={className}
|
|
121
54
|
{style}
|
|
122
|
-
onkeydown={handleKeydown}
|
|
55
|
+
onkeydown={(e) => menu.handleKeydown(e)}
|
|
123
56
|
{...rest}
|
|
124
57
|
>
|
|
125
58
|
{@render children()}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { SVGAttributes } from 'svelte/elements';
|
|
3
|
+
import { variantAttrs } from '@dryui/primitives';
|
|
3
4
|
import type { DiagramConfig } from './types.js';
|
|
4
5
|
import { computeLayout } from './layout.js';
|
|
5
6
|
|
|
@@ -300,8 +301,7 @@
|
|
|
300
301
|
{@const WpIcon = wp.iconComponent}
|
|
301
302
|
<g
|
|
302
303
|
data-part="waypoint"
|
|
303
|
-
|
|
304
|
-
data-color={wp.color}
|
|
304
|
+
{...variantAttrs({ variant: wp.variant, color: wp.color })}
|
|
305
305
|
transform="translate({wp.x},{wp.y})"
|
|
306
306
|
>
|
|
307
307
|
<rect
|
|
@@ -349,8 +349,7 @@
|
|
|
349
349
|
{@const NodeIcon = node.iconComponent}
|
|
350
350
|
<g
|
|
351
351
|
data-part="node"
|
|
352
|
-
|
|
353
|
-
data-color={node.color}
|
|
352
|
+
{...variantAttrs({ variant: node.variant, color: node.color })}
|
|
354
353
|
data-state={node.state}
|
|
355
354
|
transform="translate({node.x},{node.y})"
|
|
356
355
|
>
|
|
@@ -2,115 +2,17 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { getDialogCtx } from './context.svelte.js';
|
|
5
|
+
import ModalContent from '../internal/modal-content.svelte';
|
|
5
6
|
|
|
6
7
|
interface Props extends HTMLAttributes<HTMLDialogElement> {
|
|
7
8
|
children: Snippet;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
let {
|
|
11
|
+
let { children, ...rest }: Props = $props();
|
|
11
12
|
|
|
12
13
|
const ctx = getDialogCtx();
|
|
13
|
-
|
|
14
|
-
let dialogEl = $state<HTMLDialogElement>();
|
|
15
|
-
|
|
16
|
-
$effect(() => {
|
|
17
|
-
if (ctx.open && dialogEl && !dialogEl.open) {
|
|
18
|
-
dialogEl.showModal();
|
|
19
|
-
}
|
|
20
|
-
if (!ctx.open && dialogEl?.open) {
|
|
21
|
-
dialogEl.close();
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
14
|
</script>
|
|
25
15
|
|
|
26
|
-
<dialog
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
aria-labelledby={ctx.headerId}
|
|
30
|
-
data-state={ctx.open ? 'open' : 'closed'}
|
|
31
|
-
onclose={() => ctx.close()}
|
|
32
|
-
onclick={(e) => {
|
|
33
|
-
if (e.target === dialogEl) {
|
|
34
|
-
ctx.close();
|
|
35
|
-
}
|
|
36
|
-
}}
|
|
37
|
-
class={className}
|
|
38
|
-
{...rest}
|
|
39
|
-
>
|
|
40
|
-
<div data-dialog-panel>
|
|
41
|
-
{@render children()}
|
|
42
|
-
</div>
|
|
43
|
-
</dialog>
|
|
44
|
-
|
|
45
|
-
<style>
|
|
46
|
-
[data-dialog-content] {
|
|
47
|
-
position: fixed;
|
|
48
|
-
inset: 0;
|
|
49
|
-
/* dryui-allow width */
|
|
50
|
-
width: 100vw;
|
|
51
|
-
/* dryui-allow width */
|
|
52
|
-
max-width: none;
|
|
53
|
-
height: 100vh;
|
|
54
|
-
height: 100dvh;
|
|
55
|
-
max-height: none;
|
|
56
|
-
border: none;
|
|
57
|
-
background: transparent;
|
|
58
|
-
color: var(--dry-color-text-strong);
|
|
59
|
-
padding: 0;
|
|
60
|
-
display: grid;
|
|
61
|
-
grid-template-columns: min(90vw, var(--dry-dialog-max-width, 32rem));
|
|
62
|
-
place-content: center;
|
|
63
|
-
place-items: center;
|
|
64
|
-
overflow: visible;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
[data-dialog-content]:not([open]) {
|
|
68
|
-
display: none;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
[data-dialog-content]::backdrop {
|
|
72
|
-
background: var(--dry-overlay-bg, var(--dry-color-overlay-backdrop));
|
|
73
|
-
backdrop-filter: blur(var(--dry-overlay-blur, 12px));
|
|
74
|
-
-webkit-backdrop-filter: blur(var(--dry-overlay-blur, 12px));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
[data-dialog-panel] {
|
|
78
|
-
--dry-dialog-border: var(--dry-overlay-border, var(--dry-color-stroke-weak));
|
|
79
|
-
--dry-dialog-padding: var(--dry-space-8);
|
|
80
|
-
--dry-radius-nested: max(
|
|
81
|
-
0px,
|
|
82
|
-
calc(
|
|
83
|
-
var(--dry-dialog-radius, var(--dry-overlay-radius, var(--dry-radius-2xl))) -
|
|
84
|
-
var(--dry-dialog-padding)
|
|
85
|
-
)
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
container-type: inline-size;
|
|
89
|
-
justify-self: stretch;
|
|
90
|
-
border: 1px solid var(--dry-dialog-border);
|
|
91
|
-
border-radius: var(--dry-dialog-radius, var(--dry-overlay-radius, var(--dry-radius-2xl)));
|
|
92
|
-
background: var(--dry-dialog-bg, var(--dry-overlay-bg, var(--dry-color-bg-overlay)));
|
|
93
|
-
color: var(--dry-color-text-strong);
|
|
94
|
-
box-shadow: var(--dry-dialog-shadow, var(--dry-overlay-shadow, var(--dry-shadow-overlay)));
|
|
95
|
-
padding: 0;
|
|
96
|
-
max-block-size: var(--dry-dialog-max-block-size, 85vh);
|
|
97
|
-
display: grid;
|
|
98
|
-
overflow: var(--dry-dialog-overflow, auto);
|
|
99
|
-
|
|
100
|
-
transition:
|
|
101
|
-
opacity var(--dry-duration-normal) var(--dry-ease-spring-snappy),
|
|
102
|
-
transform var(--dry-duration-normal) var(--dry-ease-spring-snappy);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
[data-dialog-content][data-state='open'] [data-dialog-panel] {
|
|
106
|
-
opacity: 1;
|
|
107
|
-
transform: scale(1) translateY(0);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
@starting-style {
|
|
111
|
-
[data-dialog-content][open] [data-dialog-panel] {
|
|
112
|
-
opacity: 0;
|
|
113
|
-
transform: scale(var(--dry-motion-scale-enter)) translateY(var(--dry-motion-distance-sm));
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
</style>
|
|
16
|
+
<ModalContent {ctx} variant="dialog" side="center" {...rest}>
|
|
17
|
+
{@render children()}
|
|
18
|
+
</ModalContent>
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
const ctx = getDragAndDropCtx();
|
|
14
14
|
|
|
15
|
-
let itemIsDragging = $derived(ctx.draggedIndex === index);
|
|
15
|
+
let itemIsDragging = $derived(ctx.draggedIndex === index && ctx.isDragging);
|
|
16
16
|
let isOver = $derived(
|
|
17
17
|
(ctx.overIndex === index && ctx.isDragging && ctx.draggedIndex !== index) ||
|
|
18
18
|
ctx.foreignOverIndex === index
|
|
@@ -2,167 +2,17 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { getDrawerCtx } from './context.svelte.js';
|
|
5
|
+
import ModalContent from '../internal/modal-content.svelte';
|
|
5
6
|
|
|
6
7
|
interface Props extends HTMLAttributes<HTMLDialogElement> {
|
|
7
8
|
children: Snippet;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
let {
|
|
11
|
+
let { children, ...rest }: Props = $props();
|
|
11
12
|
|
|
12
13
|
const ctx = getDrawerCtx();
|
|
13
|
-
|
|
14
|
-
let dialogEl = $state<HTMLDialogElement>();
|
|
15
|
-
|
|
16
|
-
$effect(() => {
|
|
17
|
-
if (!dialogEl) return;
|
|
18
|
-
|
|
19
|
-
// Native <dialog> applies a max-width that leaves a strip beside edge drawers.
|
|
20
|
-
dialogEl.style.setProperty('max-width', 'none');
|
|
21
|
-
|
|
22
|
-
if (ctx.open && !dialogEl.open) {
|
|
23
|
-
dialogEl.showModal();
|
|
24
|
-
}
|
|
25
|
-
if (!ctx.open && dialogEl.open) {
|
|
26
|
-
dialogEl.close();
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
14
|
</script>
|
|
30
15
|
|
|
31
|
-
<
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
data-side={ctx.side}
|
|
35
|
-
aria-labelledby={ctx.headerId}
|
|
36
|
-
data-state={ctx.open ? 'open' : 'closed'}
|
|
37
|
-
onclose={() => ctx.close()}
|
|
38
|
-
onclick={(e) => {
|
|
39
|
-
if (e.target === dialogEl) {
|
|
40
|
-
ctx.close();
|
|
41
|
-
}
|
|
42
|
-
}}
|
|
43
|
-
class={className}
|
|
44
|
-
{...rest}
|
|
45
|
-
>
|
|
46
|
-
<div data-drawer-panel>
|
|
47
|
-
{@render children()}
|
|
48
|
-
</div>
|
|
49
|
-
</dialog>
|
|
50
|
-
|
|
51
|
-
<style>
|
|
52
|
-
[data-drawer-content] {
|
|
53
|
-
margin: 0;
|
|
54
|
-
position: fixed;
|
|
55
|
-
inset: 0;
|
|
56
|
-
height: 100vh;
|
|
57
|
-
height: 100dvh;
|
|
58
|
-
max-height: none;
|
|
59
|
-
border: none;
|
|
60
|
-
background: transparent;
|
|
61
|
-
color: var(--dry-color-text-strong);
|
|
62
|
-
padding: 0;
|
|
63
|
-
box-sizing: border-box;
|
|
64
|
-
display: grid;
|
|
65
|
-
grid-template-columns: minmax(0, 1fr);
|
|
66
|
-
grid-template-rows: minmax(0, 1fr);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
[data-drawer-content]:not([open]) {
|
|
70
|
-
display: none;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
[data-drawer-content]::backdrop {
|
|
74
|
-
background: var(--dry-overlay-bg, var(--dry-color-overlay-backdrop-strong));
|
|
75
|
-
backdrop-filter: blur(var(--dry-overlay-blur, 8px));
|
|
76
|
-
-webkit-backdrop-filter: blur(var(--dry-overlay-blur, 8px));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/* Side positioning via grid alignment */
|
|
80
|
-
[data-drawer-content][data-side='right'] {
|
|
81
|
-
grid-template-columns:
|
|
82
|
-
minmax(0, calc(100dvw - var(--dry-drawer-size, 25rem)))
|
|
83
|
-
var(--dry-drawer-size, 25rem);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
[data-drawer-content][data-side='left'] {
|
|
87
|
-
grid-template-columns:
|
|
88
|
-
var(--dry-drawer-size, 25rem)
|
|
89
|
-
minmax(0, calc(100dvw - var(--dry-drawer-size, 25rem)));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
[data-drawer-content][data-side='top'] {
|
|
93
|
-
grid-template-rows:
|
|
94
|
-
var(--dry-drawer-size, 25rem)
|
|
95
|
-
minmax(0, calc(100dvh - var(--dry-drawer-size, 25rem)));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
[data-drawer-content][data-side='bottom'] {
|
|
99
|
-
grid-template-rows:
|
|
100
|
-
minmax(0, calc(100dvh - var(--dry-drawer-size, 25rem)))
|
|
101
|
-
var(--dry-drawer-size, 25rem);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/* Panel */
|
|
105
|
-
[data-drawer-panel] {
|
|
106
|
-
--dry-drawer-bg: var(--dry-color-bg-overlay);
|
|
107
|
-
--dry-drawer-border: var(--dry-color-stroke-weak);
|
|
108
|
-
--dry-drawer-size: 25rem;
|
|
109
|
-
--_drawer-rest-transform: translateX(0);
|
|
110
|
-
--_drawer-enter-transform: translateX(100%);
|
|
111
|
-
|
|
112
|
-
background: var(--dry-drawer-bg);
|
|
113
|
-
color: var(--dry-color-text-strong);
|
|
114
|
-
box-shadow: var(--dry-drawer-shadow, var(--dry-shadow-overlay));
|
|
115
|
-
padding: 0;
|
|
116
|
-
display: grid;
|
|
117
|
-
grid-template-rows: max-content minmax(0, 1fr) max-content;
|
|
118
|
-
overflow: hidden;
|
|
119
|
-
opacity: 1;
|
|
120
|
-
transform: var(--_drawer-rest-transform);
|
|
121
|
-
will-change: transform, opacity;
|
|
122
|
-
|
|
123
|
-
transition:
|
|
124
|
-
transform var(--dry-duration-slow) var(--dry-ease-spring-snappy),
|
|
125
|
-
opacity var(--dry-duration-normal) var(--dry-ease-out);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
[data-drawer-content][data-side='right'] [data-drawer-panel] {
|
|
129
|
-
grid-column: 2;
|
|
130
|
-
height: 100%;
|
|
131
|
-
border-left: 1px solid var(--dry-drawer-border);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
[data-drawer-content][data-side='left'] [data-drawer-panel] {
|
|
135
|
-
--_drawer-enter-transform: translateX(-100%);
|
|
136
|
-
grid-column: 1;
|
|
137
|
-
height: 100%;
|
|
138
|
-
border-right: 1px solid var(--dry-drawer-border);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
[data-drawer-content][data-side='top'] [data-drawer-panel] {
|
|
142
|
-
--_drawer-rest-transform: translateY(0);
|
|
143
|
-
--_drawer-enter-transform: translateY(-100%);
|
|
144
|
-
grid-row: 1;
|
|
145
|
-
height: var(--dry-drawer-size);
|
|
146
|
-
border-bottom: 1px solid var(--dry-drawer-border);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
[data-drawer-content][data-side='bottom'] [data-drawer-panel] {
|
|
150
|
-
--_drawer-rest-transform: translateY(0);
|
|
151
|
-
--_drawer-enter-transform: translateY(100%);
|
|
152
|
-
grid-row: 2;
|
|
153
|
-
height: var(--dry-drawer-size);
|
|
154
|
-
border-top: 1px solid var(--dry-drawer-border);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
@starting-style {
|
|
158
|
-
[data-drawer-content][open] [data-drawer-panel] {
|
|
159
|
-
opacity: 0;
|
|
160
|
-
transform: var(--_drawer-enter-transform);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
[data-drawer-content][data-state='open'] [data-drawer-panel] {
|
|
165
|
-
opacity: 1;
|
|
166
|
-
transform: var(--_drawer-rest-transform);
|
|
167
|
-
}
|
|
168
|
-
</style>
|
|
16
|
+
<ModalContent {ctx} variant="drawer" side={ctx.side} {...rest}>
|
|
17
|
+
{@render children()}
|
|
18
|
+
</ModalContent>
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
-
import {
|
|
4
|
+
import { createAnchoredPopover, createMenuNavigation } from '@dryui/primitives';
|
|
5
5
|
import type { Placement } from '@dryui/primitives';
|
|
6
6
|
import { getDropdownMenuCtx } from './context.svelte.js';
|
|
7
7
|
|
|
8
|
-
const MENU_ITEM_SELECTOR = '[role="menuitem"]:not([data-disabled])';
|
|
9
|
-
|
|
10
8
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
11
9
|
placement?: Placement;
|
|
12
10
|
offset?: number;
|
|
@@ -26,79 +24,18 @@
|
|
|
26
24
|
|
|
27
25
|
let el = $state<HTMLDivElement>();
|
|
28
26
|
|
|
29
|
-
const popover =
|
|
27
|
+
const popover = createAnchoredPopover({
|
|
30
28
|
triggerEl: () => ctx.triggerEl,
|
|
31
29
|
contentEl: () => el ?? null,
|
|
30
|
+
open: () => ctx.open,
|
|
32
31
|
placement: () => placement,
|
|
33
32
|
offset: () => offset
|
|
34
33
|
});
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function focusItem(items: HTMLElement[], index: number): void {
|
|
41
|
-
if (items.length === 0) return;
|
|
42
|
-
const clamped = ((index % items.length) + items.length) % items.length;
|
|
43
|
-
items[clamped]?.focus();
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function focusFirstItem(): void {
|
|
47
|
-
if (!el) return;
|
|
48
|
-
const items = getMenuItems(el);
|
|
49
|
-
const first = items[0];
|
|
50
|
-
if (first) {
|
|
51
|
-
first.focus();
|
|
52
|
-
} else {
|
|
53
|
-
el.focus();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
$effect(() => {
|
|
58
|
-
if (ctx.open && el && !el.matches(':popover-open')) {
|
|
59
|
-
popover.showPopover(el);
|
|
60
|
-
} else if (!ctx.open && el?.matches(':popover-open')) {
|
|
61
|
-
popover.hidePopover(el);
|
|
62
|
-
}
|
|
35
|
+
const menu = createMenuNavigation({
|
|
36
|
+
container: () => el ?? null,
|
|
37
|
+
orientation: 'vertical'
|
|
63
38
|
});
|
|
64
|
-
|
|
65
|
-
function handleKeydown(e: KeyboardEvent) {
|
|
66
|
-
if (!el) return;
|
|
67
|
-
const items = getMenuItems(el);
|
|
68
|
-
const currentIndex = items.indexOf(document.activeElement as HTMLElement);
|
|
69
|
-
|
|
70
|
-
switch (e.key) {
|
|
71
|
-
case 'ArrowDown': {
|
|
72
|
-
e.preventDefault();
|
|
73
|
-
focusItem(items, currentIndex + 1);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
case 'ArrowUp': {
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
focusItem(items, currentIndex - 1);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
case 'Home': {
|
|
82
|
-
e.preventDefault();
|
|
83
|
-
focusItem(items, 0);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
case 'End': {
|
|
87
|
-
e.preventDefault();
|
|
88
|
-
focusItem(items, items.length - 1);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
default: {
|
|
92
|
-
if (e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
93
|
-
const char = e.key.toLowerCase();
|
|
94
|
-
const match = items.find((item) =>
|
|
95
|
-
item.textContent?.trim().toLowerCase().startsWith(char)
|
|
96
|
-
);
|
|
97
|
-
if (match) match.focus();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
39
|
</script>
|
|
103
40
|
|
|
104
41
|
<div
|
|
@@ -116,12 +53,12 @@
|
|
|
116
53
|
const newState = (e as ToggleEvent).newState === 'open';
|
|
117
54
|
if (newState && !ctx.open) {
|
|
118
55
|
ctx.show();
|
|
119
|
-
queueMicrotask(
|
|
56
|
+
queueMicrotask(() => menu.focusFirst());
|
|
120
57
|
} else if (!newState && ctx.open) {
|
|
121
58
|
ctx.close();
|
|
122
59
|
}
|
|
123
60
|
}}
|
|
124
|
-
onkeydown={handleKeydown}
|
|
61
|
+
onkeydown={(e) => menu.handleKeydown(e)}
|
|
125
62
|
{...rest}
|
|
126
63
|
>
|
|
127
64
|
{@render children()}
|
|
@@ -171,4 +108,10 @@
|
|
|
171
108
|
translateY(calc(var(--dry-motion-distance-xs) * -1));
|
|
172
109
|
}
|
|
173
110
|
}
|
|
111
|
+
|
|
112
|
+
@media (prefers-reduced-motion: reduce) {
|
|
113
|
+
[data-dropdown-menu-content] {
|
|
114
|
+
transition: none;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
174
117
|
</style>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { variantAttrs } from '@dryui/primitives';
|
|
4
5
|
|
|
5
6
|
interface Props extends HTMLAttributes<HTMLHeadingElement> {
|
|
6
7
|
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
@@ -12,27 +13,27 @@
|
|
|
12
13
|
</script>
|
|
13
14
|
|
|
14
15
|
{#if level === 1}
|
|
15
|
-
<h1 class={className}
|
|
16
|
+
<h1 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
16
17
|
{@render children()}
|
|
17
18
|
</h1>
|
|
18
19
|
{:else if level === 2}
|
|
19
|
-
<h2 class={className}
|
|
20
|
+
<h2 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
20
21
|
{@render children()}
|
|
21
22
|
</h2>
|
|
22
23
|
{:else if level === 3}
|
|
23
|
-
<h3 class={className}
|
|
24
|
+
<h3 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
24
25
|
{@render children()}
|
|
25
26
|
</h3>
|
|
26
27
|
{:else if level === 4}
|
|
27
|
-
<h4 class={className}
|
|
28
|
+
<h4 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
28
29
|
{@render children()}
|
|
29
30
|
</h4>
|
|
30
31
|
{:else if level === 5}
|
|
31
|
-
<h5 class={className}
|
|
32
|
+
<h5 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
32
33
|
{@render children()}
|
|
33
34
|
</h5>
|
|
34
35
|
{:else}
|
|
35
|
-
<h6 class={className}
|
|
36
|
+
<h6 class={className} {...variantAttrs({ level, variant })} {...rest}>
|
|
36
37
|
{@render children()}
|
|
37
38
|
</h6>
|
|
38
39
|
{/if}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
-
import {
|
|
4
|
+
import { createAnchoredPopover } from '@dryui/primitives';
|
|
5
5
|
import type { Placement } from '@dryui/primitives';
|
|
6
6
|
import { getHoverCardCtx } from './context.svelte.js';
|
|
7
7
|
|
|
@@ -24,22 +24,14 @@
|
|
|
24
24
|
|
|
25
25
|
let contentEl = $state<HTMLDivElement>();
|
|
26
26
|
|
|
27
|
-
const popover =
|
|
27
|
+
const popover = createAnchoredPopover({
|
|
28
28
|
triggerEl: () => ctx.triggerEl,
|
|
29
29
|
contentEl: () => contentEl ?? null,
|
|
30
|
+
open: () => ctx.open,
|
|
30
31
|
placement: () => placement,
|
|
31
32
|
offset: () => offset
|
|
32
33
|
});
|
|
33
34
|
|
|
34
|
-
$effect(() => {
|
|
35
|
-
if (!contentEl) return;
|
|
36
|
-
if (ctx.open) {
|
|
37
|
-
popover.showPopover(contentEl);
|
|
38
|
-
} else {
|
|
39
|
-
popover.hidePopover(contentEl);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
|
|
43
35
|
function handleKeydown(e: KeyboardEvent) {
|
|
44
36
|
if (e.key === 'Escape') {
|
|
45
37
|
e.preventDefault();
|
|
@@ -51,7 +43,6 @@
|
|
|
51
43
|
<div
|
|
52
44
|
bind:this={contentEl}
|
|
53
45
|
id={ctx.contentId}
|
|
54
|
-
role="dialog"
|
|
55
46
|
popover="manual"
|
|
56
47
|
data-hover-card-content
|
|
57
48
|
data-state={ctx.open ? 'open' : 'closed'}
|
package/dist/icon/icon.svelte
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { variantAttrs } from '@dryui/primitives';
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
@@ -24,8 +25,7 @@
|
|
|
24
25
|
role={label ? 'img' : 'presentation'}
|
|
25
26
|
aria-label={label}
|
|
26
27
|
aria-hidden={label ? undefined : true}
|
|
27
|
-
|
|
28
|
-
data-color={color}
|
|
28
|
+
{...variantAttrs({ size, color })}
|
|
29
29
|
class={className}
|
|
30
30
|
use:sizeSvg
|
|
31
31
|
>
|
package/dist/index.d.ts
CHANGED
|
@@ -292,7 +292,7 @@ export { StarRating } from './star-rating/index.js';
|
|
|
292
292
|
export type { StarRatingRootProps } from './star-rating/index.js';
|
|
293
293
|
export { Tag } from './tag/index.js';
|
|
294
294
|
export type { TagProps, TagColor } from './tag/index.js';
|
|
295
|
-
export {
|
|
296
|
-
export type {
|
|
295
|
+
export { TokenScope } from './themes/token-scope.js';
|
|
296
|
+
export type { TokenScopeProps } from './themes/token-scope.js';
|
|
297
297
|
export { Diagram } from './diagram/index.js';
|
|
298
298
|
export type { DiagramConfig, DiagramNode, DiagramEdge, DiagramCluster, DiagramAnnotation, DiagramSwimlane, DiagramRegion, DiagramColor, DiagramDirection } from './diagram/index.js';
|