@dryui/ui 1.5.1 → 1.6.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/button-group/context.svelte.js +4 -7
- package/dist/calendar/calendar-root.svelte +15 -32
- package/dist/chip-group/context.svelte.d.ts +2 -4
- package/dist/chip-group/context.svelte.js +2 -9
- package/dist/context-menu/context-menu-content.svelte +24 -12
- package/dist/context-menu/context-menu-group.svelte +3 -2
- package/dist/context-menu/context-menu-item.svelte +8 -61
- package/dist/context-menu/context-menu-label.svelte +3 -11
- package/dist/context-menu/context-menu-root.svelte +10 -29
- package/dist/context-menu/context-menu-separator.svelte +2 -9
- package/dist/context-menu/context.svelte.d.ts +2 -12
- package/dist/date-picker/datepicker-content.svelte +11 -81
- package/dist/date-picker/datepicker-content.svelte.d.ts +1 -1
- package/dist/date-picker/datepicker-input-root.svelte +39 -47
- package/dist/date-range-picker/date-range-picker-content.svelte +11 -75
- package/dist/date-range-picker/date-range-picker-content.svelte.d.ts +1 -1
- package/dist/date-range-picker/date-range-picker-root.svelte +44 -49
- package/dist/drag-and-drop/group-context.svelte.d.ts +1 -1
- package/dist/drag-and-drop/group-context.svelte.js +4 -4
- package/dist/dropdown-menu/context.svelte.d.ts +2 -8
- package/dist/dropdown-menu/dropdown-menu-content.svelte +15 -3
- package/dist/dropdown-menu/dropdown-menu-group.svelte +3 -2
- package/dist/dropdown-menu/dropdown-menu-item.svelte +8 -61
- package/dist/dropdown-menu/dropdown-menu-label.svelte +3 -11
- package/dist/dropdown-menu/dropdown-menu-root.svelte +10 -21
- package/dist/dropdown-menu/dropdown-menu-separator.svelte +2 -9
- package/dist/flip-card/context.svelte.d.ts +5 -0
- package/dist/flip-card/context.svelte.js +2 -0
- package/dist/flip-card/flip-card-back.svelte +2 -2
- package/dist/flip-card/flip-card-root.svelte +42 -15
- package/dist/heading/heading.svelte +10 -1
- package/dist/heading/heading.svelte.d.ts +1 -0
- package/dist/heading/index.d.ts +1 -0
- package/dist/hover-card/hover-card-content.svelte +9 -21
- package/dist/hover-card/hover-card-root.svelte +2 -2
- package/dist/hover-card/hover-card-root.svelte.d.ts +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/internal/anchored-overlay-content.svelte.d.ts +20 -0
- package/dist/internal/anchored-overlay-content.svelte.js +28 -0
- package/dist/internal/date-family-controller.svelte.d.ts +45 -0
- package/dist/internal/date-family-controller.svelte.js +99 -0
- package/dist/internal/menu-group.svelte +15 -0
- package/dist/internal/menu-group.svelte.d.ts +9 -0
- package/dist/internal/menu-item.svelte +82 -0
- package/dist/internal/menu-item.svelte.d.ts +11 -0
- package/dist/internal/menu-label.svelte +24 -0
- package/dist/internal/menu-label.svelte.d.ts +9 -0
- package/dist/internal/menu-root-state.svelte.d.ts +24 -0
- package/dist/internal/menu-root-state.svelte.js +42 -0
- package/dist/internal/menu-separator.svelte +19 -0
- package/dist/internal/menu-separator.svelte.d.ts +7 -0
- package/dist/internal/motion.js +12 -1
- package/dist/internal/picker-popover-content.svelte +112 -0
- package/dist/internal/picker-popover-content.svelte.d.ts +16 -0
- package/dist/link-preview/link-preview-content.svelte +7 -10
- package/dist/list/list-item-icon.svelte +3 -3
- package/dist/list/list-item-icon.svelte.d.ts +1 -1
- package/dist/list/list-item-text.svelte +3 -3
- package/dist/list/list-item-text.svelte.d.ts +1 -1
- package/dist/list/list-item.svelte +58 -35
- package/dist/list/list-item.svelte.d.ts +8 -2
- package/dist/popover/popover-content.svelte +9 -11
- package/dist/range-calendar/range-calendar-root.svelte +13 -19
- package/dist/text/index.d.ts +1 -0
- package/dist/text/text.svelte +3 -1
- package/dist/text/text.svelte.d.ts +1 -0
- package/dist/theme-toggle/index.d.ts +18 -0
- package/dist/theme-toggle/index.js +3 -0
- package/dist/theme-toggle/theme-controller.svelte.d.ts +54 -0
- package/dist/theme-toggle/theme-controller.svelte.js +121 -0
- package/dist/theme-toggle/theme-flash.d.ts +16 -0
- package/dist/theme-toggle/theme-flash.js +38 -0
- package/dist/theme-toggle/theme-toggle.svelte +189 -0
- package/dist/theme-toggle/theme-toggle.svelte.d.ts +40 -0
- package/dist/tooltip/tooltip-content.svelte +8 -10
- package/dist/typography/heading.svelte +13 -89
- package/dist/typography/heading.svelte.d.ts +3 -8
- package/dist/typography/index.d.ts +8 -7
- package/dist/typography/text.svelte +12 -84
- package/dist/typography/text.svelte.d.ts +3 -10
- package/package.json +7 -2
- package/skills/dryui/SKILL.md +18 -5
- package/skills/dryui/rules/composition.md +1 -1
- package/skills/dryui/rules/theming.md +1 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { fromAction } from 'svelte/attachments';
|
|
3
2
|
import type { Snippet } from 'svelte';
|
|
4
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
5
|
-
import {
|
|
4
|
+
import type { Placement } from '@dryui/primitives';
|
|
5
|
+
import PickerPopoverContent from '../internal/picker-popover-content.svelte';
|
|
6
6
|
import { getDateRangePickerCtx } from './context.svelte.js';
|
|
7
7
|
|
|
8
8
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
@@ -21,79 +21,15 @@
|
|
|
21
21
|
}: Props = $props();
|
|
22
22
|
|
|
23
23
|
const ctx = getDateRangePickerCtx();
|
|
24
|
-
|
|
25
|
-
let el = $state<HTMLDivElement | null>(null);
|
|
26
|
-
|
|
27
|
-
function attachContent(node: HTMLDivElement) {
|
|
28
|
-
el = node;
|
|
29
|
-
|
|
30
|
-
return () => {
|
|
31
|
-
if (el === node) {
|
|
32
|
-
el = null;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const popover = createAnchoredPopover({
|
|
38
|
-
triggerEl: () => ctx.triggerEl,
|
|
39
|
-
contentEl: () => el ?? null,
|
|
40
|
-
open: () => ctx.open,
|
|
41
|
-
placement: () => placement,
|
|
42
|
-
offset: () => offset
|
|
43
|
-
});
|
|
44
24
|
</script>
|
|
45
25
|
|
|
46
|
-
<
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
data-drp-content
|
|
55
|
-
class={className}
|
|
56
|
-
ontoggle={(e) => {
|
|
57
|
-
const newState = (e as ToggleEvent).newState === 'open';
|
|
58
|
-
if (newState && !ctx.open) {
|
|
59
|
-
ctx.show();
|
|
60
|
-
} else if (!newState && ctx.open) {
|
|
61
|
-
ctx.close();
|
|
62
|
-
}
|
|
63
|
-
}}
|
|
26
|
+
<PickerPopoverContent
|
|
27
|
+
controller={ctx}
|
|
28
|
+
dataAttribute="data-drp-content"
|
|
29
|
+
{placement}
|
|
30
|
+
{offset}
|
|
31
|
+
contentStyle={style}
|
|
32
|
+
contentClass={className}
|
|
33
|
+
{children}
|
|
64
34
|
{...rest}
|
|
65
|
-
|
|
66
|
-
{@render children()}
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<style>
|
|
70
|
-
[data-drp-content] {
|
|
71
|
-
inset: unset;
|
|
72
|
-
margin: 0;
|
|
73
|
-
padding: var(--dry-space-3);
|
|
74
|
-
border: 1px solid var(--dry-color-stroke-weak);
|
|
75
|
-
border-radius: var(--dry-radius-lg);
|
|
76
|
-
background: var(--dry-color-bg-overlay);
|
|
77
|
-
box-shadow: var(--dry-shadow-lg);
|
|
78
|
-
color: var(--dry-color-text-strong);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
[data-drp-content]:popover-open {
|
|
82
|
-
opacity: 1;
|
|
83
|
-
transform: translateY(0) scale(1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
@starting-style {
|
|
87
|
-
[data-drp-content]:popover-open {
|
|
88
|
-
opacity: 0;
|
|
89
|
-
transform: translateY(calc(var(--dry-motion-distance-xs) * -1))
|
|
90
|
-
scale(var(--dry-motion-scale-enter));
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
[data-drp-content] {
|
|
95
|
-
transition:
|
|
96
|
-
opacity var(--dry-duration-fast) var(--dry-ease-emphasized),
|
|
97
|
-
transform var(--dry-duration-fast) var(--dry-ease-emphasized);
|
|
98
|
-
}
|
|
99
|
-
</style>
|
|
35
|
+
/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import {
|
|
3
|
+
import type { Placement } from '@dryui/primitives';
|
|
4
4
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
5
5
|
placement?: Placement;
|
|
6
6
|
offset?: number;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
createDateViewController,
|
|
5
|
+
createPickerPopoverController
|
|
6
|
+
} from '../internal/date-family-controller.svelte.js';
|
|
4
7
|
import { setDateRangePickerCtx } from './context.svelte.js';
|
|
5
|
-
import { getWeekStartDay, addMonths, isSameDay } from '@dryui/primitives';
|
|
6
8
|
|
|
7
9
|
interface Props {
|
|
8
10
|
open?: boolean;
|
|
@@ -26,18 +28,10 @@
|
|
|
26
28
|
children
|
|
27
29
|
}: Props = $props();
|
|
28
30
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// View state: which month/year is the calendar showing
|
|
35
|
-
let viewMonth = $state(startDate ? startDate.getMonth() : new Date().getMonth());
|
|
36
|
-
let viewYear = $state(startDate ? startDate.getFullYear() : new Date().getFullYear());
|
|
37
|
-
let triggerEl = $state<HTMLElement | null>(null);
|
|
38
|
-
|
|
39
|
-
// The day that has keyboard focus within the calendar grid
|
|
40
|
-
let focusedDate = $state<Date>(startDate ?? new Date());
|
|
31
|
+
const view = createDateViewController({
|
|
32
|
+
initialDate: startDate,
|
|
33
|
+
locale: () => locale
|
|
34
|
+
});
|
|
41
35
|
|
|
42
36
|
// Hover date for range preview
|
|
43
37
|
let hoverDate = $state<Date | null>(null);
|
|
@@ -45,6 +39,22 @@
|
|
|
45
39
|
// Selection mode: 'start' means next click sets start, 'end' means next click sets end
|
|
46
40
|
let selecting = $state<'start' | 'end'>('start');
|
|
47
41
|
|
|
42
|
+
const popover = createPickerPopoverController({
|
|
43
|
+
triggerIdPrefix: 'date-range-picker-trigger',
|
|
44
|
+
contentIdPrefix: 'date-range-picker-content',
|
|
45
|
+
open: () => open,
|
|
46
|
+
setOpen: (nextOpen) => {
|
|
47
|
+
open = nextOpen;
|
|
48
|
+
},
|
|
49
|
+
disabled: () => disabled,
|
|
50
|
+
onShow: () => {
|
|
51
|
+
selecting = 'start';
|
|
52
|
+
},
|
|
53
|
+
onClose: () => {
|
|
54
|
+
hoverDate = null;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
48
58
|
setDateRangePickerCtx({
|
|
49
59
|
get open() {
|
|
50
60
|
return open;
|
|
@@ -56,13 +66,13 @@
|
|
|
56
66
|
return endDate;
|
|
57
67
|
},
|
|
58
68
|
get focusedDate() {
|
|
59
|
-
return focusedDate;
|
|
69
|
+
return view.focusedDate;
|
|
60
70
|
},
|
|
61
71
|
get viewMonth() {
|
|
62
|
-
return viewMonth;
|
|
72
|
+
return view.viewMonth;
|
|
63
73
|
},
|
|
64
74
|
get viewYear() {
|
|
65
|
-
return viewYear;
|
|
75
|
+
return view.viewYear;
|
|
66
76
|
},
|
|
67
77
|
get locale() {
|
|
68
78
|
return locale;
|
|
@@ -77,7 +87,7 @@
|
|
|
77
87
|
return disabled;
|
|
78
88
|
},
|
|
79
89
|
get weekStartDay() {
|
|
80
|
-
return weekStartDay;
|
|
90
|
+
return view.weekStartDay;
|
|
81
91
|
},
|
|
82
92
|
get hoverDate() {
|
|
83
93
|
return hoverDate;
|
|
@@ -85,41 +95,33 @@
|
|
|
85
95
|
get selecting() {
|
|
86
96
|
return selecting;
|
|
87
97
|
},
|
|
88
|
-
triggerId
|
|
89
|
-
|
|
98
|
+
get triggerId() {
|
|
99
|
+
return popover.triggerId;
|
|
100
|
+
},
|
|
101
|
+
get contentId() {
|
|
102
|
+
return popover.contentId;
|
|
103
|
+
},
|
|
90
104
|
get triggerEl() {
|
|
91
|
-
return triggerEl;
|
|
105
|
+
return popover.triggerEl;
|
|
92
106
|
},
|
|
93
107
|
set triggerEl(element: HTMLElement | null) {
|
|
94
|
-
|
|
108
|
+
popover.setTriggerEl(element);
|
|
95
109
|
},
|
|
96
110
|
show() {
|
|
97
|
-
|
|
98
|
-
selecting = 'start';
|
|
99
|
-
open = true;
|
|
100
|
-
}
|
|
111
|
+
popover.show();
|
|
101
112
|
},
|
|
102
113
|
close() {
|
|
103
|
-
|
|
104
|
-
hoverDate = null;
|
|
114
|
+
popover.close();
|
|
105
115
|
},
|
|
106
116
|
toggle() {
|
|
107
|
-
|
|
108
|
-
if (!open) {
|
|
109
|
-
selecting = 'start';
|
|
110
|
-
}
|
|
111
|
-
open = !open;
|
|
112
|
-
if (!open) {
|
|
113
|
-
hoverDate = null;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
117
|
+
popover.toggle();
|
|
116
118
|
},
|
|
117
119
|
selectDate(date: Date) {
|
|
118
120
|
if (selecting === 'start') {
|
|
119
121
|
startDate = date;
|
|
120
122
|
endDate = null;
|
|
121
123
|
selecting = 'end';
|
|
122
|
-
|
|
124
|
+
view.focusDate(date);
|
|
123
125
|
} else {
|
|
124
126
|
// 'end' mode
|
|
125
127
|
if (startDate && date.getTime() < startDate.getTime()) {
|
|
@@ -130,27 +132,20 @@
|
|
|
130
132
|
endDate = date;
|
|
131
133
|
}
|
|
132
134
|
selecting = 'start';
|
|
133
|
-
|
|
134
|
-
open = false;
|
|
135
|
+
popover.close();
|
|
135
136
|
}
|
|
136
137
|
},
|
|
137
138
|
setHoverDate(date: Date | null) {
|
|
138
139
|
hoverDate = date;
|
|
139
140
|
},
|
|
140
141
|
nextMonth() {
|
|
141
|
-
|
|
142
|
-
viewMonth = next.getMonth();
|
|
143
|
-
viewYear = next.getFullYear();
|
|
142
|
+
view.nextMonth();
|
|
144
143
|
},
|
|
145
144
|
prevMonth() {
|
|
146
|
-
|
|
147
|
-
viewMonth = prev.getMonth();
|
|
148
|
-
viewYear = prev.getFullYear();
|
|
145
|
+
view.prevMonth();
|
|
149
146
|
},
|
|
150
147
|
setFocusedDate(date: Date) {
|
|
151
|
-
|
|
152
|
-
viewMonth = date.getMonth();
|
|
153
|
-
viewYear = date.getFullYear();
|
|
148
|
+
view.setFocusedDate(date);
|
|
154
149
|
}
|
|
155
150
|
});
|
|
156
151
|
</script>
|
|
@@ -9,5 +9,5 @@ export interface DragAndDropGroupContext {
|
|
|
9
9
|
setActiveTarget(listId: string | null, index: number | null): void;
|
|
10
10
|
move(fromListId: string, fromIndex: number, toListId: string, toIndex: number): void;
|
|
11
11
|
}
|
|
12
|
-
export declare function setGroupCtx(ctx: DragAndDropGroupContext):
|
|
12
|
+
export declare function setGroupCtx(ctx: DragAndDropGroupContext): DragAndDropGroupContext;
|
|
13
13
|
export declare function getGroupCtx(): DragAndDropGroupContext | null;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const
|
|
1
|
+
import { createContext } from '@dryui/primitives';
|
|
2
|
+
const [_setGroupCtx, _getGroupCtx] = createContext('drag-and-drop-group');
|
|
3
3
|
export function setGroupCtx(ctx) {
|
|
4
|
-
|
|
4
|
+
return _setGroupCtx(ctx);
|
|
5
5
|
}
|
|
6
6
|
export function getGroupCtx() {
|
|
7
|
-
return
|
|
7
|
+
return _getGroupCtx() ?? null;
|
|
8
8
|
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
readonly triggerId: string;
|
|
4
|
-
readonly contentId: string;
|
|
5
|
-
triggerEl: HTMLElement | null;
|
|
6
|
-
show: () => void;
|
|
7
|
-
close: () => void;
|
|
8
|
-
toggle: () => void;
|
|
1
|
+
import type { MenuRootState } from '../internal/menu-root-state.svelte.js';
|
|
2
|
+
export interface DropdownMenuContext extends MenuRootState {
|
|
9
3
|
}
|
|
10
4
|
export declare const setDropdownMenuCtx: (ctx: DropdownMenuContext) => DropdownMenuContext, getDropdownMenuCtx: () => DropdownMenuContext;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
+
import { fromAction } from 'svelte/attachments';
|
|
3
4
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
5
|
import { createAnchoredPopover, createMenuNavigation } from '@dryui/primitives';
|
|
5
6
|
import type { Placement } from '@dryui/primitives';
|
|
@@ -22,7 +23,17 @@
|
|
|
22
23
|
|
|
23
24
|
const ctx = getDropdownMenuCtx();
|
|
24
25
|
|
|
25
|
-
let el = $state<HTMLDivElement>();
|
|
26
|
+
let el = $state<HTMLDivElement | null>(null);
|
|
27
|
+
|
|
28
|
+
function attachContent(node: HTMLDivElement) {
|
|
29
|
+
el = node;
|
|
30
|
+
|
|
31
|
+
return () => {
|
|
32
|
+
if (el === node) {
|
|
33
|
+
el = null;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
26
37
|
|
|
27
38
|
const popover = createAnchoredPopover({
|
|
28
39
|
triggerEl: () => ctx.triggerEl,
|
|
@@ -39,7 +50,8 @@
|
|
|
39
50
|
</script>
|
|
40
51
|
|
|
41
52
|
<div
|
|
42
|
-
|
|
53
|
+
{@attach attachContent}
|
|
54
|
+
{@attach fromAction(popover.applyPosition, () => style)}
|
|
43
55
|
popover="auto"
|
|
44
56
|
role="menu"
|
|
45
57
|
tabindex="-1"
|
|
@@ -48,7 +60,6 @@
|
|
|
48
60
|
data-dropdown-menu-content
|
|
49
61
|
data-state={ctx.open ? 'open' : 'closed'}
|
|
50
62
|
class={className}
|
|
51
|
-
use:popover.applyPosition={style}
|
|
52
63
|
ontoggle={(e) => {
|
|
53
64
|
const newState = (e as ToggleEvent).newState === 'open';
|
|
54
65
|
if (newState && !ctx.open) {
|
|
@@ -70,6 +81,7 @@
|
|
|
70
81
|
inset: unset;
|
|
71
82
|
margin: 0;
|
|
72
83
|
|
|
84
|
+
--dry-menu-item-padding: var(--dry-space-3) var(--dry-space-4);
|
|
73
85
|
background: var(--dry-menu-bg, var(--dry-overlay-bg, var(--dry-color-bg-overlay)));
|
|
74
86
|
color: var(--dry-color-text-strong);
|
|
75
87
|
border: 1px solid
|
|
@@ -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 MenuGroup from '../internal/menu-group.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
6
7
|
children: Snippet;
|
|
@@ -9,6 +10,6 @@
|
|
|
9
10
|
let { class: className, children, ...rest }: Props = $props();
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
|
-
<
|
|
13
|
+
<MenuGroup {className} {...rest}>
|
|
13
14
|
{@render children()}
|
|
14
|
-
</
|
|
15
|
+
</MenuGroup>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { getDropdownMenuCtx } from './context.svelte.js';
|
|
5
|
+
import MenuItem from '../internal/menu-item.svelte';
|
|
5
6
|
|
|
6
7
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
7
8
|
disabled?: boolean;
|
|
@@ -11,70 +12,16 @@
|
|
|
11
12
|
let { class: className, disabled, children, onclick, onkeydown, ...rest }: Props = $props();
|
|
12
13
|
|
|
13
14
|
const ctx = getDropdownMenuCtx();
|
|
14
|
-
|
|
15
|
-
function handleClick(e: MouseEvent & { currentTarget: HTMLDivElement }) {
|
|
16
|
-
if (disabled) return;
|
|
17
|
-
if (onclick) (onclick as (e: MouseEvent & { currentTarget: HTMLDivElement }) => void)(e);
|
|
18
|
-
ctx.close();
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function handleKeydown(e: KeyboardEvent & { currentTarget: HTMLDivElement }) {
|
|
22
|
-
if (disabled) return;
|
|
23
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
24
|
-
e.preventDefault();
|
|
25
|
-
(e.currentTarget as HTMLElement).click();
|
|
26
|
-
}
|
|
27
|
-
if (onkeydown) (onkeydown as (e: KeyboardEvent & { currentTarget: HTMLDivElement }) => void)(e);
|
|
28
|
-
}
|
|
29
15
|
</script>
|
|
30
16
|
|
|
31
|
-
<
|
|
32
|
-
role="menuitem"
|
|
33
|
-
tabindex={disabled ? undefined : -1}
|
|
34
|
-
aria-disabled={disabled || undefined}
|
|
17
|
+
<MenuItem
|
|
35
18
|
data-dropdown-menu-item
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
19
|
+
{className}
|
|
20
|
+
close={ctx.close}
|
|
21
|
+
{disabled}
|
|
22
|
+
{onclick}
|
|
23
|
+
{onkeydown}
|
|
40
24
|
{...rest}
|
|
41
25
|
>
|
|
42
26
|
{@render children()}
|
|
43
|
-
</
|
|
44
|
-
|
|
45
|
-
<style>
|
|
46
|
-
[data-dropdown-menu-item] {
|
|
47
|
-
display: grid;
|
|
48
|
-
grid-auto-flow: column;
|
|
49
|
-
grid-auto-columns: max-content;
|
|
50
|
-
align-items: center;
|
|
51
|
-
gap: var(--dry-space-2);
|
|
52
|
-
padding: var(--dry-menu-item-padding, var(--dry-space-3) var(--dry-space-4));
|
|
53
|
-
border-radius: var(
|
|
54
|
-
--dry-menu-item-radius,
|
|
55
|
-
min(var(--dry-control-radius, var(--dry-radius-sm)), var(--dry-space-4))
|
|
56
|
-
);
|
|
57
|
-
font-size: var(--dry-type-small-size, var(--dry-text-sm-size));
|
|
58
|
-
cursor: pointer;
|
|
59
|
-
user-select: none;
|
|
60
|
-
outline: none;
|
|
61
|
-
color: var(--dry-color-text-strong);
|
|
62
|
-
min-height: var(--dry-space-11);
|
|
63
|
-
transition: background var(--dry-duration-fast) var(--dry-ease-default);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
[data-dropdown-menu-item]:hover:not([data-disabled]),
|
|
67
|
-
[data-dropdown-menu-item]:focus-visible {
|
|
68
|
-
background: var(--dry-color-fill);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
[data-dropdown-menu-item]:active:not([data-disabled]) {
|
|
72
|
-
background: var(--dry-color-fill-hover);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
[data-dropdown-menu-item][data-disabled] {
|
|
76
|
-
color: var(--dry-color-text-disabled);
|
|
77
|
-
cursor: not-allowed;
|
|
78
|
-
pointer-events: none;
|
|
79
|
-
}
|
|
80
|
-
</style>
|
|
27
|
+
</MenuItem>
|
|
@@ -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 MenuLabel from '../internal/menu-label.svelte';
|
|
4
5
|
|
|
5
6
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
6
7
|
children: Snippet;
|
|
@@ -9,15 +10,6 @@
|
|
|
9
10
|
let { class: className, children, ...rest }: Props = $props();
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
|
-
<
|
|
13
|
+
<MenuLabel data-dropdown-menu-label {className} {...rest}>
|
|
13
14
|
{@render children()}
|
|
14
|
-
</
|
|
15
|
-
|
|
16
|
-
<style>
|
|
17
|
-
[data-dropdown-menu-label] {
|
|
18
|
-
padding: var(--dry-space-1_5) var(--dry-space-2);
|
|
19
|
-
font-size: var(--dry-type-tiny-size, var(--dry-text-xs-size));
|
|
20
|
-
color: var(--dry-color-text-weak);
|
|
21
|
-
font-weight: 500;
|
|
22
|
-
}
|
|
23
|
-
</style>
|
|
15
|
+
</MenuLabel>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
import { generateFormId } from '@dryui/primitives';
|
|
4
3
|
import { setDropdownMenuCtx } from './context.svelte.js';
|
|
4
|
+
import { createMenuRootState } from '../internal/menu-root-state.svelte.js';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
7
7
|
open?: boolean;
|
|
@@ -10,26 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
let { open = $bindable(false), children }: Props = $props();
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
triggerEl: null,
|
|
23
|
-
show() {
|
|
24
|
-
open = true;
|
|
25
|
-
},
|
|
26
|
-
close() {
|
|
27
|
-
open = false;
|
|
28
|
-
},
|
|
29
|
-
toggle() {
|
|
30
|
-
open = !open;
|
|
31
|
-
}
|
|
32
|
-
});
|
|
13
|
+
setDropdownMenuCtx(
|
|
14
|
+
createMenuRootState({
|
|
15
|
+
idBase: 'dropdown',
|
|
16
|
+
getOpen: () => open,
|
|
17
|
+
setOpen: (value) => {
|
|
18
|
+
open = value;
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
);
|
|
33
22
|
</script>
|
|
34
23
|
|
|
35
24
|
{@render children()}
|
|
@@ -1,17 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import MenuSeparator from '../internal/menu-separator.svelte';
|
|
3
4
|
|
|
4
5
|
interface Props extends HTMLAttributes<HTMLDivElement> {}
|
|
5
6
|
|
|
6
7
|
let { class: className, ...rest }: Props = $props();
|
|
7
8
|
</script>
|
|
8
9
|
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
<style>
|
|
12
|
-
[data-dropdown-menu-separator] {
|
|
13
|
-
height: 1px;
|
|
14
|
-
background: var(--dry-color-stroke-weak);
|
|
15
|
-
margin: var(--dry-space-1) 0;
|
|
16
|
-
}
|
|
17
|
-
</style>
|
|
10
|
+
<MenuSeparator data-dropdown-menu-separator {className} {...rest}></MenuSeparator>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
-
import {
|
|
4
|
+
import { getFlipCardCtx } from './context.svelte.js';
|
|
5
5
|
|
|
6
6
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
7
7
|
children: Snippet;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
let { class: className, children, ...rest }: Props = $props();
|
|
11
|
-
const ctx =
|
|
11
|
+
const ctx = getFlipCardCtx();
|
|
12
12
|
</script>
|
|
13
13
|
|
|
14
14
|
<div
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
-
import
|
|
4
|
+
import Button from '../button/button.svelte';
|
|
5
|
+
import VisuallyHidden from '../visually-hidden/visually-hidden.svelte';
|
|
6
|
+
import { setFlipCardCtx } from './context.svelte.js';
|
|
5
7
|
|
|
6
8
|
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
7
9
|
trigger?: 'hover' | 'click';
|
|
@@ -14,6 +16,8 @@
|
|
|
14
16
|
trigger = 'hover',
|
|
15
17
|
direction = 'horizontal',
|
|
16
18
|
flipped = $bindable(false),
|
|
19
|
+
'aria-label': ariaLabel,
|
|
20
|
+
'aria-labelledby': ariaLabelledBy,
|
|
17
21
|
class: className,
|
|
18
22
|
children,
|
|
19
23
|
...rest
|
|
@@ -23,7 +27,9 @@
|
|
|
23
27
|
flipped = !flipped;
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
const toggleLabel = $derived(flipped ? 'Show front of card' : 'Show back of card');
|
|
31
|
+
|
|
32
|
+
setFlipCardCtx({
|
|
27
33
|
get flipped() {
|
|
28
34
|
return flipped;
|
|
29
35
|
},
|
|
@@ -33,29 +39,34 @@
|
|
|
33
39
|
});
|
|
34
40
|
</script>
|
|
35
41
|
|
|
36
|
-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
37
42
|
<div
|
|
38
43
|
data-flip-card
|
|
44
|
+
data-part="root"
|
|
39
45
|
data-flipped={flipped ? '' : undefined}
|
|
40
46
|
data-trigger={trigger}
|
|
41
47
|
data-direction={direction}
|
|
42
|
-
role={trigger === '
|
|
43
|
-
aria-roledescription=
|
|
44
|
-
|
|
48
|
+
role={trigger === 'hover' ? 'group' : undefined}
|
|
49
|
+
aria-roledescription={trigger === 'hover' ? 'flip card' : undefined}
|
|
50
|
+
aria-label={trigger === 'hover' ? ariaLabel : undefined}
|
|
51
|
+
aria-labelledby={trigger === 'hover' ? ariaLabelledBy : undefined}
|
|
45
52
|
onmouseenter={trigger === 'hover' ? () => (flipped = true) : undefined}
|
|
46
53
|
onmouseleave={trigger === 'hover' ? () => (flipped = false) : undefined}
|
|
47
|
-
onclick={trigger === 'click' ? toggle : undefined}
|
|
48
|
-
onkeydown={trigger === 'click'
|
|
49
|
-
? (e) => {
|
|
50
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
51
|
-
e.preventDefault();
|
|
52
|
-
toggle();
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
: undefined}
|
|
56
54
|
class={className}
|
|
57
55
|
{...rest}
|
|
58
56
|
>
|
|
57
|
+
{#if trigger === 'click'}
|
|
58
|
+
<span data-flip-card-toggle-shell>
|
|
59
|
+
<Button
|
|
60
|
+
variant="bare"
|
|
61
|
+
aria-pressed={flipped}
|
|
62
|
+
aria-label={ariaLabel ?? toggleLabel}
|
|
63
|
+
aria-labelledby={ariaLabelledBy}
|
|
64
|
+
onclick={toggle}
|
|
65
|
+
>
|
|
66
|
+
<VisuallyHidden>{toggleLabel}</VisuallyHidden>
|
|
67
|
+
</Button>
|
|
68
|
+
</span>
|
|
69
|
+
{/if}
|
|
59
70
|
{@render children()}
|
|
60
71
|
</div>
|
|
61
72
|
|
|
@@ -72,6 +83,22 @@
|
|
|
72
83
|
transform-style: preserve-3d;
|
|
73
84
|
}
|
|
74
85
|
|
|
86
|
+
[data-flip-card-toggle-shell] {
|
|
87
|
+
position: absolute;
|
|
88
|
+
inset: 0;
|
|
89
|
+
z-index: 3;
|
|
90
|
+
display: grid;
|
|
91
|
+
border-radius: inherit;
|
|
92
|
+
--dry-btn-bg: transparent;
|
|
93
|
+
--dry-btn-border: transparent;
|
|
94
|
+
--dry-btn-color: inherit;
|
|
95
|
+
--dry-btn-padding-x: 0;
|
|
96
|
+
--dry-btn-padding-y: 0;
|
|
97
|
+
--dry-btn-min-height: 0;
|
|
98
|
+
--dry-btn-radius: inherit;
|
|
99
|
+
box-shadow: none;
|
|
100
|
+
}
|
|
101
|
+
|
|
75
102
|
[data-flip-card][data-direction='horizontal'][data-flipped] {
|
|
76
103
|
--dry-flip-card-front-transform: rotateY(180deg);
|
|
77
104
|
--dry-flip-card-back-transform: rotateY(360deg);
|