@x33025/sveltely 0.1.1 → 0.1.2
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/components/Library/Button/Button.demo.svelte +5 -3
- package/dist/components/Library/Button/Button.demo.svelte.d.ts +1 -0
- package/dist/components/Library/Calendar/Calendar.demo.svelte +2 -14
- package/dist/components/Library/Calendar/Calendar.svelte +54 -50
- package/dist/components/Library/Divider/Divider.svelte +10 -0
- package/dist/components/Library/Divider/Divider.svelte.d.ts +26 -0
- package/dist/components/Library/Divider/index.d.ts +1 -0
- package/dist/components/Library/Divider/index.js +1 -0
- package/dist/components/Library/Dropdown/Dropdown.demo.svelte +10 -3
- package/dist/components/Library/Dropdown/Dropdown.svelte +39 -5
- package/dist/components/Library/Dropdown/index.d.ts +1 -1
- package/dist/components/Library/Dropdown/types.d.ts +4 -1
- package/dist/components/Library/Floating/Floating.svelte +35 -1
- package/dist/components/Library/ForEach/ForEach.svelte +14 -0
- package/dist/components/Library/ForEach/ForEach.svelte.d.ts +28 -0
- package/dist/components/Library/ForEach/index.d.ts +1 -0
- package/dist/components/Library/ForEach/index.js +1 -0
- package/dist/components/Library/Grid/Grid.svelte +74 -0
- package/dist/components/Library/Grid/Grid.svelte.d.ts +13 -0
- package/dist/components/Library/Grid/index.d.ts +1 -0
- package/dist/components/Library/Grid/index.js +1 -0
- package/dist/components/Library/GridItem/GridItem.svelte +65 -0
- package/dist/components/Library/GridItem/GridItem.svelte.d.ts +14 -0
- package/dist/components/Library/GridItem/index.d.ts +1 -0
- package/dist/components/Library/GridItem/index.js +1 -0
- package/dist/components/Library/HStack/HStack.svelte +45 -0
- package/dist/components/Library/HStack/HStack.svelte.d.ts +9 -0
- package/dist/components/Library/HStack/index.d.ts +1 -0
- package/dist/components/Library/HStack/index.js +1 -0
- package/dist/components/Library/Image/Image.demo.svelte +18 -0
- package/dist/components/Library/Image/Image.demo.svelte.d.ts +23 -0
- package/dist/components/Library/Image/Image.svelte +57 -0
- package/dist/components/Library/Image/Image.svelte.d.ts +17 -0
- package/dist/components/Library/Image/ImagePlaceholder.svelte +202 -0
- package/dist/components/Library/Image/ImagePlaceholder.svelte.d.ts +7 -0
- package/dist/components/Library/Image/index.d.ts +1 -0
- package/dist/components/Library/Image/index.js +1 -0
- package/dist/components/Library/ImageMask/BrushPreview.svelte +119 -0
- package/dist/components/Library/ImageMask/BrushPreview.svelte.d.ts +11 -0
- package/dist/components/Library/ImageMask/ImageMask.demo.svelte +117 -0
- package/dist/components/Library/ImageMask/ImageMask.demo.svelte.d.ts +10 -0
- package/dist/components/Library/ImageMask/ImageMask.svelte +46 -0
- package/dist/components/Library/ImageMask/ImageMask.svelte.d.ts +20 -0
- package/dist/components/Library/ImageMask/MaskLayer.svelte +341 -0
- package/dist/components/Library/ImageMask/MaskLayer.svelte.d.ts +12 -0
- package/dist/components/Library/ImageMask/contour.d.ts +11 -0
- package/dist/components/Library/ImageMask/contour.js +152 -0
- package/dist/components/Library/ImageMask/index.d.ts +2 -0
- package/dist/components/Library/ImageMask/index.js +1 -0
- package/dist/components/Library/ImageMask/marchingAnts.d.ts +8 -0
- package/dist/components/Library/ImageMask/marchingAnts.js +29 -0
- package/dist/components/Library/ImageMask/maskSurface.d.ts +5 -0
- package/dist/components/Library/ImageMask/maskSurface.js +94 -0
- package/dist/components/Library/ImageMask/types.d.ts +23 -0
- package/dist/components/Library/ImageMask/types.js +1 -0
- package/dist/components/Library/Label/Label.demo.svelte +28 -0
- package/dist/components/Library/Label/Label.demo.svelte.d.ts +9 -0
- package/dist/components/Library/Label/Label.svelte +177 -0
- package/dist/components/Library/Label/Label.svelte.d.ts +18 -0
- package/dist/components/Library/Label/index.d.ts +1 -0
- package/dist/components/Library/Label/index.js +1 -0
- package/dist/components/Library/NumberField/NumberField.demo.svelte +21 -0
- package/dist/components/Library/NumberField/NumberField.demo.svelte.d.ts +8 -0
- package/dist/components/Library/NumberField/NumberField.svelte +194 -0
- package/dist/components/Library/NumberField/NumberField.svelte.d.ts +21 -0
- package/dist/components/Library/NumberField/index.d.ts +1 -0
- package/dist/components/Library/NumberField/index.js +1 -0
- package/dist/components/Library/ScrollView/ScrollView.svelte +25 -9
- package/dist/components/Library/ScrollView/ScrollView.svelte.d.ts +4 -4
- package/dist/components/Library/Spacer/Spacer.svelte +7 -0
- package/dist/components/Library/Spacer/Spacer.svelte.d.ts +26 -0
- package/dist/components/Library/Spacer/index.d.ts +1 -0
- package/dist/components/Library/Spacer/index.js +1 -0
- package/dist/components/Library/TextField/TextField.demo.svelte +14 -0
- package/dist/components/Library/TextField/TextField.demo.svelte.d.ts +8 -0
- package/dist/components/Library/TextField/TextField.svelte +149 -0
- package/dist/components/Library/TextField/TextField.svelte.d.ts +19 -0
- package/dist/components/Library/TextField/index.d.ts +1 -0
- package/dist/components/Library/TextField/index.js +1 -0
- package/dist/components/Library/VStack/VStack.svelte +45 -0
- package/dist/components/Library/VStack/VStack.svelte.d.ts +9 -0
- package/dist/components/Library/VStack/index.d.ts +1 -0
- package/dist/components/Library/VStack/index.js +1 -0
- package/dist/components/Local/ComponentGrid.svelte +15 -31
- package/dist/components/Local/HeroCard.svelte +26 -36
- package/dist/components/Local/HeroCard.svelte.d.ts +0 -2
- package/dist/index.d.ts +23 -0
- package/dist/index.js +17 -0
- package/dist/style/index.css +28 -17
- package/dist/style/label.d.ts +6 -0
- package/dist/style/label.js +4 -0
- package/dist/style/layout.d.ts +57 -0
- package/dist/style/layout.js +128 -0
- package/dist/style/media.d.ts +12 -0
- package/dist/style/media.js +8 -0
- package/dist/style/scroll.d.ts +7 -0
- package/dist/style/scroll.js +5 -0
- package/dist/style/text-editor.d.ts +34 -0
- package/dist/style/text-editor.js +29 -0
- package/dist/style.css +58 -35
- package/package.json +1 -1
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
2
|
export const demo = {
|
|
3
3
|
name: 'Button',
|
|
4
|
-
description: 'Token-aware button primitive with optional icon support.'
|
|
4
|
+
description: 'Token-aware button primitive with optional icon support.',
|
|
5
|
+
columnSpan: 2
|
|
5
6
|
};
|
|
6
7
|
</script>
|
|
7
8
|
|
|
8
9
|
<script lang="ts">
|
|
9
10
|
import { SaveIcon } from '@lucide/svelte';
|
|
10
11
|
import Button from './Button.svelte';
|
|
12
|
+
import HStack from '../HStack';
|
|
11
13
|
</script>
|
|
12
14
|
|
|
13
|
-
<
|
|
15
|
+
<HStack align="center" gap={0.75}>
|
|
14
16
|
<Button label="Default" />
|
|
15
17
|
<Button label="Solid" variant="solid" />
|
|
16
18
|
<Button icon={SaveIcon} label="With icon" />
|
|
17
|
-
</
|
|
19
|
+
</HStack>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const demo: {
|
|
2
2
|
name: string;
|
|
3
3
|
description: string;
|
|
4
|
+
columnSpan: number;
|
|
4
5
|
};
|
|
5
6
|
import Button from './Button.svelte';
|
|
6
7
|
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
name: 'Calendar',
|
|
4
4
|
description: 'Compact month calendar with token-driven spacing and radius.',
|
|
5
5
|
columnSpan: 2,
|
|
6
|
-
rowSpan:
|
|
6
|
+
rowSpan: 3
|
|
7
7
|
};
|
|
8
8
|
</script>
|
|
9
9
|
|
|
@@ -15,16 +15,4 @@
|
|
|
15
15
|
let weekStart = $state<'monday' | 'sunday'>('monday');
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
|
-
<
|
|
19
|
-
<div class="hstack gap-2">
|
|
20
|
-
<button type="button" onclick={() => (weekStart = 'monday')}>Monday start</button>
|
|
21
|
-
<button type="button" onclick={() => (weekStart = 'sunday')}>Sunday start</button>
|
|
22
|
-
</div>
|
|
23
|
-
<Calendar bind:value bind:month {weekStart} />
|
|
24
|
-
<p class="text-xs text-zinc-500">
|
|
25
|
-
Selected: {value ? value.toLocaleDateString() : 'none'} | Month: {month.toLocaleDateString(undefined, {
|
|
26
|
-
month: 'long',
|
|
27
|
-
year: 'numeric'
|
|
28
|
-
})} | Week starts: {weekStart}
|
|
29
|
-
</p>
|
|
30
|
-
</div>
|
|
18
|
+
<Calendar bind:value bind:month {weekStart} />
|
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
const startOfDay = (value: Date) =>
|
|
6
6
|
new Date(value.getFullYear(), value.getMonth(), value.getDate());
|
|
7
7
|
|
|
8
|
-
const startOfMonth = (value: Date) =>
|
|
9
|
-
new Date(value.getFullYear(), value.getMonth(), 1);
|
|
8
|
+
const startOfMonth = (value: Date) => new Date(value.getFullYear(), value.getMonth(), 1);
|
|
10
9
|
|
|
11
10
|
type CalendarCell = {
|
|
12
11
|
key: string;
|
|
@@ -23,7 +22,8 @@
|
|
|
23
22
|
month?: Date;
|
|
24
23
|
weekdayLabels?: string[];
|
|
25
24
|
weekStart?: 'monday' | 'sunday';
|
|
26
|
-
} & StyleProps &
|
|
25
|
+
} & StyleProps &
|
|
26
|
+
Record<string, unknown>;
|
|
27
27
|
|
|
28
28
|
const defaultWeekdayLabels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
|
|
29
29
|
const today = new Date();
|
|
@@ -42,14 +42,10 @@
|
|
|
42
42
|
const rootStyle = $derived.by(() => surfaceStyle(styleProps, 'calendar'));
|
|
43
43
|
|
|
44
44
|
const orderedWeekdayLabels = $derived(
|
|
45
|
-
weekStart === 'sunday'
|
|
46
|
-
? [weekdayLabels[6], ...weekdayLabels.slice(0, 6)]
|
|
47
|
-
: weekdayLabels
|
|
45
|
+
weekStart === 'sunday' ? [weekdayLabels[6], ...weekdayLabels.slice(0, 6)] : weekdayLabels
|
|
48
46
|
);
|
|
49
47
|
|
|
50
|
-
const weekendColumnIndexes = $derived(
|
|
51
|
-
weekStart === 'sunday' ? [0, 6] : [5, 6]
|
|
52
|
-
);
|
|
48
|
+
const weekendColumnIndexes = $derived(weekStart === 'sunday' ? [0, 6] : [5, 6]);
|
|
53
49
|
|
|
54
50
|
function shiftMonth(offset: number) {
|
|
55
51
|
month = new Date(month.getFullYear(), month.getMonth() + offset, 1);
|
|
@@ -59,6 +55,17 @@
|
|
|
59
55
|
value = startOfDay(nextValue);
|
|
60
56
|
}
|
|
61
57
|
|
|
58
|
+
function activateCell(cell: CalendarCell) {
|
|
59
|
+
if (!cell.value) return;
|
|
60
|
+
|
|
61
|
+
if (cell.isCurrentMonth) {
|
|
62
|
+
selectDate(cell.value);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
month = startOfMonth(cell.value);
|
|
67
|
+
}
|
|
68
|
+
|
|
62
69
|
const displayYear = $derived(month.getFullYear());
|
|
63
70
|
const displayMonth = $derived(month.getMonth());
|
|
64
71
|
const todayYear = today.getFullYear();
|
|
@@ -74,37 +81,28 @@
|
|
|
74
81
|
|
|
75
82
|
const cells = $derived.by(() => {
|
|
76
83
|
const firstDay = new Date(displayYear, displayMonth, 1);
|
|
77
|
-
const daysInMonth = new Date(displayYear, displayMonth + 1, 0).getDate();
|
|
78
84
|
const leadingEmptyDays =
|
|
79
85
|
weekStart === 'sunday' ? firstDay.getDay() : (firstDay.getDay() + 6) % 7;
|
|
80
86
|
|
|
81
|
-
return Array.from({ length:
|
|
87
|
+
return Array.from({ length: 42 }, (_, index): CalendarCell => {
|
|
82
88
|
const dayNumber = index - leadingEmptyDays + 1;
|
|
83
|
-
if (dayNumber < 1) {
|
|
84
|
-
return {
|
|
85
|
-
key: `empty-${index}`,
|
|
86
|
-
label: '',
|
|
87
|
-
isCurrentMonth: false,
|
|
88
|
-
isToday: false,
|
|
89
|
-
isWeekend: false,
|
|
90
|
-
isSelected: false
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
89
|
const cellDate = new Date(displayYear, displayMonth, dayNumber);
|
|
95
90
|
const dayOfWeek = cellDate.getDay();
|
|
91
|
+
const isCurrentMonth = cellDate.getMonth() === displayMonth;
|
|
96
92
|
|
|
97
93
|
return {
|
|
98
|
-
key: `day-${
|
|
99
|
-
label: String(
|
|
100
|
-
isCurrentMonth
|
|
94
|
+
key: `day-${cellDate.getFullYear()}-${cellDate.getMonth()}-${cellDate.getDate()}`,
|
|
95
|
+
label: String(cellDate.getDate()),
|
|
96
|
+
isCurrentMonth,
|
|
101
97
|
value: cellDate,
|
|
102
98
|
isToday:
|
|
99
|
+
isCurrentMonth &&
|
|
103
100
|
displayYear === todayYear &&
|
|
104
101
|
displayMonth === todayMonth &&
|
|
105
|
-
|
|
102
|
+
cellDate.getDate() === todayDate,
|
|
106
103
|
isWeekend: dayOfWeek === 0 || dayOfWeek === 6,
|
|
107
104
|
isSelected:
|
|
105
|
+
isCurrentMonth &&
|
|
108
106
|
value !== null &&
|
|
109
107
|
cellDate.getFullYear() === value.getFullYear() &&
|
|
110
108
|
cellDate.getMonth() === value.getMonth() &&
|
|
@@ -116,16 +114,26 @@
|
|
|
116
114
|
|
|
117
115
|
<div class="calendar vstack" style={rootStyle} {...props}>
|
|
118
116
|
<div class="calendar-grid">
|
|
119
|
-
<button
|
|
117
|
+
<button
|
|
118
|
+
class="calendar-nav-button"
|
|
119
|
+
type="button"
|
|
120
|
+
aria-label="Previous month"
|
|
121
|
+
onclick={() => shiftMonth(-1)}
|
|
122
|
+
>
|
|
120
123
|
<ChevronLeftIcon class="calendar-nav-icon" strokeWidth={2} />
|
|
121
124
|
</button>
|
|
122
125
|
<div class="calendar-title-cell">
|
|
123
126
|
<h2 class="calendar-title">{monthLabel}</h2>
|
|
124
127
|
</div>
|
|
125
|
-
<button
|
|
128
|
+
<button
|
|
129
|
+
class="calendar-nav-button"
|
|
130
|
+
type="button"
|
|
131
|
+
aria-label="Next month"
|
|
132
|
+
onclick={() => shiftMonth(1)}
|
|
133
|
+
>
|
|
126
134
|
<ChevronRightIcon class="calendar-nav-icon" strokeWidth={2} />
|
|
127
135
|
</button>
|
|
128
|
-
{#each orderedWeekdayLabels as weekday, index}
|
|
136
|
+
{#each orderedWeekdayLabels as weekday, index (weekday)}
|
|
129
137
|
<div
|
|
130
138
|
class="calendar-weekday"
|
|
131
139
|
class:calendar-weekday-weekend={weekendColumnIndexes.includes(index)}
|
|
@@ -135,23 +143,18 @@
|
|
|
135
143
|
{/each}
|
|
136
144
|
|
|
137
145
|
{#each cells as cell (cell.key)}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
{:else}
|
|
151
|
-
<div class="calendar-day calendar-day-empty">
|
|
152
|
-
{cell.label}
|
|
153
|
-
</div>
|
|
154
|
-
{/if}
|
|
146
|
+
<button
|
|
147
|
+
type="button"
|
|
148
|
+
class="calendar-day"
|
|
149
|
+
class:calendar-day-outside={!cell.isCurrentMonth}
|
|
150
|
+
class:calendar-day-today={cell.isToday}
|
|
151
|
+
class:calendar-day-selected={cell.isSelected}
|
|
152
|
+
class:calendar-day-weekend={cell.isWeekend}
|
|
153
|
+
aria-pressed={cell.isSelected}
|
|
154
|
+
onclick={() => activateCell(cell)}
|
|
155
|
+
>
|
|
156
|
+
{cell.label}
|
|
157
|
+
</button>
|
|
155
158
|
{/each}
|
|
156
159
|
</div>
|
|
157
160
|
</div>
|
|
@@ -165,7 +168,9 @@
|
|
|
165
168
|
--calendar-weekend-header-color: var(--color-zinc-400);
|
|
166
169
|
--calendar-weekend-selected-color: white;
|
|
167
170
|
--calendar-cell-width: calc(var(--calendar-cell-core-size) + (var(--sveltely-padding-x) * 2.2));
|
|
168
|
-
--calendar-cell-height: calc(
|
|
171
|
+
--calendar-cell-height: calc(
|
|
172
|
+
var(--calendar-cell-core-size) + (var(--sveltely-padding-y) * 2.2)
|
|
173
|
+
);
|
|
169
174
|
--calendar-title-size: calc(var(--calendar-font-size) * 1.03);
|
|
170
175
|
--calendar-weekday-size: calc(var(--calendar-font-size) * 0.75);
|
|
171
176
|
font-size: var(--calendar-font-size);
|
|
@@ -283,11 +288,10 @@
|
|
|
283
288
|
background: var(--sveltely-hover-color);
|
|
284
289
|
}
|
|
285
290
|
|
|
286
|
-
.calendar-day-
|
|
291
|
+
.calendar-day-outside {
|
|
287
292
|
border-color: transparent;
|
|
288
293
|
background: transparent;
|
|
289
|
-
color:
|
|
290
|
-
cursor: default;
|
|
294
|
+
color: var(--color-zinc-400);
|
|
291
295
|
}
|
|
292
296
|
|
|
293
297
|
.calendar-day-today {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default Divider;
|
|
2
|
+
type Divider = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const Divider: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
15
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
16
|
+
$$bindings?: Bindings;
|
|
17
|
+
} & Exports;
|
|
18
|
+
(internal: unknown, props: {
|
|
19
|
+
$$events?: Events;
|
|
20
|
+
$$slots?: Slots;
|
|
21
|
+
}): Exports & {
|
|
22
|
+
$set?: any;
|
|
23
|
+
$on?: any;
|
|
24
|
+
};
|
|
25
|
+
z_$$bindings?: Bindings;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Divider.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './Divider.svelte';
|
|
@@ -7,19 +7,22 @@
|
|
|
7
7
|
|
|
8
8
|
<script lang="ts">
|
|
9
9
|
import Dropdown from './Dropdown.svelte';
|
|
10
|
+
import type { DropdownEntry } from './types';
|
|
10
11
|
|
|
11
|
-
const allItems = [
|
|
12
|
+
const allItems: DropdownEntry<string>[] = [
|
|
12
13
|
{
|
|
13
14
|
type: 'group' as const,
|
|
14
15
|
label: 'Publishing',
|
|
15
16
|
items: [
|
|
16
17
|
{ label: 'Draft', value: 'draft' },
|
|
17
18
|
{ label: 'Scheduled', value: 'scheduled' },
|
|
19
|
+
{ type: 'divider' },
|
|
18
20
|
{
|
|
19
21
|
type: 'submenu' as const,
|
|
20
22
|
label: 'Advanced',
|
|
21
23
|
items: [
|
|
22
24
|
{ label: 'Review queue', value: 'review' },
|
|
25
|
+
{ type: 'divider' },
|
|
23
26
|
{
|
|
24
27
|
type: 'action' as const,
|
|
25
28
|
label: 'Open workflow',
|
|
@@ -48,11 +51,15 @@
|
|
|
48
51
|
}
|
|
49
52
|
];
|
|
50
53
|
|
|
51
|
-
const filterEntries = (entries:
|
|
54
|
+
const filterEntries = (entries: DropdownEntry<string>[], query: string): DropdownEntry<string>[] => {
|
|
52
55
|
const normalizedQuery = query.trim().toLowerCase();
|
|
53
56
|
if (!normalizedQuery) return allItems;
|
|
54
57
|
|
|
55
|
-
return entries.flatMap((entry) => {
|
|
58
|
+
return entries.flatMap<DropdownEntry<string>>((entry) => {
|
|
59
|
+
if (entry.type === 'divider') {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
|
|
56
63
|
if (entry.type === 'group') {
|
|
57
64
|
const nextItems = filterEntries(entry.items, normalizedQuery);
|
|
58
65
|
return nextItems.length > 0 ? [{ ...entry, items: nextItems }] : [];
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends string | number = string">
|
|
2
2
|
import { CheckIcon, ChevronDownIcon, ChevronRightIcon } from '@lucide/svelte';
|
|
3
|
+
import Divider from '../Divider';
|
|
3
4
|
import Floating from '../Floating/Floating.svelte';
|
|
4
5
|
import SearchInput from '../SearchInput';
|
|
5
6
|
import { surfaceStyle, type StyleProps } from '../../../style/surface';
|
|
6
7
|
import type { Anchor } from '../../../utils/positioning';
|
|
7
8
|
import type {
|
|
8
9
|
DropdownAction,
|
|
10
|
+
DropdownDivider,
|
|
9
11
|
DropdownEntry,
|
|
10
12
|
DropdownGroup,
|
|
11
13
|
DropdownItem,
|
|
@@ -31,6 +33,8 @@
|
|
|
31
33
|
'type' in entry && entry.type === 'group';
|
|
32
34
|
const isAction = (entry: DropdownItem<T> | DropdownAction): entry is DropdownAction =>
|
|
33
35
|
'type' in entry && entry.type === 'action';
|
|
36
|
+
const isDivider = (entry: DropdownEntry<T>): entry is DropdownDivider =>
|
|
37
|
+
'type' in entry && entry.type === 'divider';
|
|
34
38
|
const isSubmenu = (entry: DropdownEntry<T>): entry is DropdownSubmenu<T> =>
|
|
35
39
|
'type' in entry && entry.type === 'submenu';
|
|
36
40
|
|
|
@@ -62,6 +66,10 @@
|
|
|
62
66
|
inheritedDisabled = false
|
|
63
67
|
): DropdownItem<T>[] =>
|
|
64
68
|
entries.flatMap((entry) => {
|
|
69
|
+
if (isDivider(entry)) {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
const nextDisabled = inheritedDisabled || !!entry.disabled;
|
|
66
74
|
if (isGroup(entry) || isSubmenu(entry)) {
|
|
67
75
|
return flattenItems(entry.items, nextDisabled);
|
|
@@ -79,6 +87,9 @@
|
|
|
79
87
|
if (nested) return nested;
|
|
80
88
|
continue;
|
|
81
89
|
}
|
|
90
|
+
if (isDivider(entry)) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
82
93
|
return entry.label;
|
|
83
94
|
}
|
|
84
95
|
return null;
|
|
@@ -154,7 +165,7 @@
|
|
|
154
165
|
aria-haspopup="dialog"
|
|
155
166
|
onclick={floating.toggle}
|
|
156
167
|
>
|
|
157
|
-
<span>{triggerText}</span>
|
|
168
|
+
<span class="dropdown-trigger-label">{triggerText}</span>
|
|
158
169
|
<ChevronDownIcon class="size-4 text-zinc-500" />
|
|
159
170
|
</button>
|
|
160
171
|
{/snippet}
|
|
@@ -168,12 +179,13 @@
|
|
|
168
179
|
bind:value={query}
|
|
169
180
|
placeholder={searchPlaceholder}
|
|
170
181
|
radiusSource={true}
|
|
171
|
-
class="w-64"
|
|
172
182
|
/>
|
|
173
183
|
{/if}
|
|
174
184
|
{#snippet renderEntries(entries: DropdownEntry<T>[], inheritedDisabled = false)}
|
|
175
|
-
{#each entries as entry, index (`${index}-${entry.type ?? 'option'}-${entry.label}`)}
|
|
176
|
-
{#if
|
|
185
|
+
{#each entries as entry, index (`${index}-${entry.type ?? 'option'}-${isDivider(entry) ? 'divider' : entry.label}`)}
|
|
186
|
+
{#if isDivider(entry)}
|
|
187
|
+
<Divider />
|
|
188
|
+
{:else if isGroup(entry)}
|
|
177
189
|
<div class="dropdown-group vstack">
|
|
178
190
|
{#if entry.label}
|
|
179
191
|
<div class="dropdown-group-label">{entry.label}</div>
|
|
@@ -274,6 +286,7 @@
|
|
|
274
286
|
.dropdown-trigger {
|
|
275
287
|
display: inline-flex;
|
|
276
288
|
min-width: 8rem;
|
|
289
|
+
max-width: 100%;
|
|
277
290
|
align-items: center;
|
|
278
291
|
border: 1px solid var(--sveltely-border-color);
|
|
279
292
|
border-radius: var(--sveltely-border-radius);
|
|
@@ -286,6 +299,18 @@
|
|
|
286
299
|
transition: color 150ms, border-color 150ms, background-color 150ms;
|
|
287
300
|
}
|
|
288
301
|
|
|
302
|
+
.dropdown-trigger-label {
|
|
303
|
+
min-width: 0;
|
|
304
|
+
flex: 1 1 auto;
|
|
305
|
+
overflow: hidden;
|
|
306
|
+
text-overflow: ellipsis;
|
|
307
|
+
white-space: nowrap;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.dropdown-trigger :global(svg) {
|
|
311
|
+
flex: 0 0 auto;
|
|
312
|
+
}
|
|
313
|
+
|
|
289
314
|
.dropdown-trigger:hover {
|
|
290
315
|
background: var(--sveltely-hover-color);
|
|
291
316
|
}
|
|
@@ -300,6 +325,8 @@
|
|
|
300
325
|
}
|
|
301
326
|
|
|
302
327
|
.dropdown-content {
|
|
328
|
+
--dropdown-item-padding-x: calc(var(--sveltely-padding-x) * 0.67);
|
|
329
|
+
--dropdown-item-padding-y: calc(var(--sveltely-padding-y) * 0.33);
|
|
303
330
|
gap: var(--sveltely-inset);
|
|
304
331
|
}
|
|
305
332
|
|
|
@@ -307,11 +334,18 @@
|
|
|
307
334
|
gap: var(--sveltely-inset);
|
|
308
335
|
}
|
|
309
336
|
|
|
337
|
+
.dropdown-content :global(.divider) {
|
|
338
|
+
--divider-width: auto;
|
|
339
|
+
margin-inline: var(--dropdown-item-padding-x);
|
|
340
|
+
margin-block: calc(var(--sveltely-inset) * 0.5);
|
|
341
|
+
background: var(--sveltely-border-color);
|
|
342
|
+
}
|
|
343
|
+
|
|
310
344
|
.dropdown-item {
|
|
311
345
|
width: 100%;
|
|
312
346
|
gap: calc(var(--sveltely-inset) * 2);
|
|
313
347
|
border-radius: var(--dropdown-item-radius, var(--sveltely-border-radius-nested));
|
|
314
|
-
padding:
|
|
348
|
+
padding: var(--dropdown-item-padding-y) var(--dropdown-item-padding-x);
|
|
315
349
|
}
|
|
316
350
|
|
|
317
351
|
.dropdown-item :global(*) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { default } from './Dropdown.svelte';
|
|
2
|
-
export type { DropdownAction, DropdownEntry, DropdownGroup, DropdownItem, DropdownSubmenu } from './types';
|
|
2
|
+
export type { DropdownAction, DropdownDivider, DropdownEntry, DropdownGroup, DropdownItem, DropdownSubmenu } from './types';
|
|
@@ -11,6 +11,9 @@ export type DropdownAction = {
|
|
|
11
11
|
disabled?: boolean;
|
|
12
12
|
onSelect: () => void;
|
|
13
13
|
};
|
|
14
|
+
export type DropdownDivider = {
|
|
15
|
+
type: 'divider';
|
|
16
|
+
};
|
|
14
17
|
export type DropdownSubmenu<TValue extends string | number = string> = {
|
|
15
18
|
type: 'submenu';
|
|
16
19
|
label: string;
|
|
@@ -24,4 +27,4 @@ export type DropdownGroup<TValue extends string | number = string> = {
|
|
|
24
27
|
disabled?: boolean;
|
|
25
28
|
items: DropdownEntry<TValue>[];
|
|
26
29
|
};
|
|
27
|
-
export type DropdownEntry<TValue extends string | number = string> = DropdownItem<TValue> | DropdownAction | DropdownGroup<TValue> | DropdownSubmenu<TValue>;
|
|
30
|
+
export type DropdownEntry<TValue extends string | number = string> = DropdownItem<TValue> | DropdownAction | DropdownDivider | DropdownGroup<TValue> | DropdownSubmenu<TValue>;
|
|
@@ -177,6 +177,39 @@
|
|
|
177
177
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
+
const resolveCssLength = (element: HTMLElement, value: string) => {
|
|
181
|
+
const trimmedValue = value.trim();
|
|
182
|
+
if (!trimmedValue) return 0;
|
|
183
|
+
if (trimmedValue.endsWith('px')) return parsePx(trimmedValue);
|
|
184
|
+
|
|
185
|
+
const probe = document.createElement('div');
|
|
186
|
+
probe.style.position = 'absolute';
|
|
187
|
+
probe.style.visibility = 'hidden';
|
|
188
|
+
probe.style.pointerEvents = 'none';
|
|
189
|
+
probe.style.width = trimmedValue;
|
|
190
|
+
element.appendChild(probe);
|
|
191
|
+
const width = probe.getBoundingClientRect().width;
|
|
192
|
+
probe.remove();
|
|
193
|
+
return width;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
const getFloatingInset = () => {
|
|
197
|
+
if (!panelEl) return 0;
|
|
198
|
+
const styles = getComputedStyle(panelEl);
|
|
199
|
+
return resolveCssLength(panelEl, styles.getPropertyValue('--sveltely-floating-inset'));
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const offsetCoords = (
|
|
203
|
+
coords: { top: number; left: number },
|
|
204
|
+
currentAnchor: Anchor,
|
|
205
|
+
offset: number
|
|
206
|
+
) => {
|
|
207
|
+
if (currentAnchor === 'bottom') return { ...coords, top: coords.top + offset };
|
|
208
|
+
if (currentAnchor === 'top') return { ...coords, top: coords.top - offset };
|
|
209
|
+
if (currentAnchor === 'right') return { ...coords, left: coords.left + offset };
|
|
210
|
+
return { ...coords, left: coords.left - offset };
|
|
211
|
+
};
|
|
212
|
+
|
|
180
213
|
const updateRadiusFromSource = () => {
|
|
181
214
|
if (!matchPanelRadiusToSource || !panelEl || !contentEl) {
|
|
182
215
|
computedPanelRadius = null;
|
|
@@ -222,7 +255,7 @@
|
|
|
222
255
|
placement,
|
|
223
256
|
preferredAlign
|
|
224
257
|
);
|
|
225
|
-
panelCoords = { top: result.top, left: result.left };
|
|
258
|
+
panelCoords = offsetCoords({ top: result.top, left: result.left }, result.anchor, getFloatingInset());
|
|
226
259
|
panelTransform = result.transform;
|
|
227
260
|
resolvedAnchor = result.anchor;
|
|
228
261
|
};
|
|
@@ -317,6 +350,7 @@
|
|
|
317
350
|
|
|
318
351
|
const resolvedPanelStyle = $derived.by(() => {
|
|
319
352
|
const declarations = [
|
|
353
|
+
'--sveltely-floating-inset: var(--sveltely-inset);',
|
|
320
354
|
`top: ${panelCoords.top}px;`,
|
|
321
355
|
`left: ${panelCoords.left}px;`,
|
|
322
356
|
`transform: ${panelTransform};`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<script lang="ts" generics="T">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
type Props = {
|
|
5
|
+
items: T[];
|
|
6
|
+
children: Snippet<[item: T, index: number]>;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
let { items, children }: Props = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
{#each items as item, index}
|
|
13
|
+
{@render children(item, index)}
|
|
14
|
+
{/each}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
declare function $$render<T>(): {
|
|
3
|
+
props: {
|
|
4
|
+
items: T[];
|
|
5
|
+
children: Snippet<[item: T, index: number]>;
|
|
6
|
+
};
|
|
7
|
+
exports: {};
|
|
8
|
+
bindings: "";
|
|
9
|
+
slots: {};
|
|
10
|
+
events: {};
|
|
11
|
+
};
|
|
12
|
+
declare class __sveltets_Render<T> {
|
|
13
|
+
props(): ReturnType<typeof $$render<T>>['props'];
|
|
14
|
+
events(): ReturnType<typeof $$render<T>>['events'];
|
|
15
|
+
slots(): ReturnType<typeof $$render<T>>['slots'];
|
|
16
|
+
bindings(): "";
|
|
17
|
+
exports(): {};
|
|
18
|
+
}
|
|
19
|
+
interface $$IsomorphicComponent {
|
|
20
|
+
new <T>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<T>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<T>['props']>, ReturnType<__sveltets_Render<T>['events']>, ReturnType<__sveltets_Render<T>['slots']>> & {
|
|
21
|
+
$$bindings?: ReturnType<__sveltets_Render<T>['bindings']>;
|
|
22
|
+
} & ReturnType<__sveltets_Render<T>['exports']>;
|
|
23
|
+
<T>(internal: unknown, props: ReturnType<__sveltets_Render<T>['props']> & {}): ReturnType<__sveltets_Render<T>['exports']>;
|
|
24
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
25
|
+
}
|
|
26
|
+
declare const ForEach: $$IsomorphicComponent;
|
|
27
|
+
type ForEach<T> = InstanceType<typeof ForEach<T>>;
|
|
28
|
+
export default ForEach;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './ForEach.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './ForEach.svelte';
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import { extractLayoutProps, layoutStyle, type LayoutProps } from '../../../style/layout';
|
|
4
|
+
import { extractStyleProps, surfaceStyle, type StyleProps } from '../../../style/surface';
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
columns?: number | string;
|
|
9
|
+
rows?: number | string;
|
|
10
|
+
autoRows?: number | string;
|
|
11
|
+
dense?: boolean;
|
|
12
|
+
} & LayoutProps &
|
|
13
|
+
StyleProps;
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
children,
|
|
17
|
+
columns = 1,
|
|
18
|
+
rows,
|
|
19
|
+
autoRows,
|
|
20
|
+
dense = false,
|
|
21
|
+
...restProps
|
|
22
|
+
}: Props = $props();
|
|
23
|
+
|
|
24
|
+
const extractedLayoutProps = $derived.by(() => extractLayoutProps(restProps));
|
|
25
|
+
const layoutProps = $derived(extractedLayoutProps.layoutProps);
|
|
26
|
+
const afterLayoutProps = $derived(extractedLayoutProps.restProps);
|
|
27
|
+
const extractedStyleProps = $derived.by(() => extractStyleProps(afterLayoutProps));
|
|
28
|
+
const styleProps = $derived(extractedStyleProps.styleProps);
|
|
29
|
+
const templateColumns = $derived(
|
|
30
|
+
typeof columns === 'number' ? `repeat(${columns}, minmax(0, 1fr))` : columns
|
|
31
|
+
);
|
|
32
|
+
const templateRows = $derived(
|
|
33
|
+
rows === undefined ? undefined : typeof rows === 'number' ? `repeat(${rows}, minmax(0, 1fr))` : rows
|
|
34
|
+
);
|
|
35
|
+
const gridAutoRows = $derived(
|
|
36
|
+
autoRows === undefined ? undefined : typeof autoRows === 'number' ? `${autoRows}rem` : autoRows
|
|
37
|
+
);
|
|
38
|
+
const rootStyle = $derived.by(() =>
|
|
39
|
+
[
|
|
40
|
+
`grid-template-columns: ${templateColumns};`,
|
|
41
|
+
templateRows ? `grid-template-rows: ${templateRows};` : '',
|
|
42
|
+
gridAutoRows ? `grid-auto-rows: ${gridAutoRows};` : '',
|
|
43
|
+
layoutStyle(layoutProps),
|
|
44
|
+
surfaceStyle(styleProps, 'grid')
|
|
45
|
+
]
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
.join(' ')
|
|
48
|
+
);
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<div class="grid" class:grid-dense={dense} style={rootStyle}>
|
|
52
|
+
{#if children}
|
|
53
|
+
{@render children()}
|
|
54
|
+
{/if}
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<style>
|
|
58
|
+
.grid {
|
|
59
|
+
display: grid;
|
|
60
|
+
min-width: 0;
|
|
61
|
+
min-height: 0;
|
|
62
|
+
align-items: stretch;
|
|
63
|
+
gap: var(--grid-gap, 0px);
|
|
64
|
+
border-radius: var(--grid-border-radius, 0px);
|
|
65
|
+
padding:
|
|
66
|
+
var(--grid-padding-y, 0px)
|
|
67
|
+
var(--grid-padding-x, 0px);
|
|
68
|
+
font-size: var(--grid-font-size, inherit);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.grid-dense {
|
|
72
|
+
grid-auto-flow: dense;
|
|
73
|
+
}
|
|
74
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import { type LayoutProps } from '../../../style/layout';
|
|
3
|
+
import { type StyleProps } from '../../../style/surface';
|
|
4
|
+
type Props = {
|
|
5
|
+
children?: Snippet;
|
|
6
|
+
columns?: number | string;
|
|
7
|
+
rows?: number | string;
|
|
8
|
+
autoRows?: number | string;
|
|
9
|
+
dense?: boolean;
|
|
10
|
+
} & LayoutProps & StyleProps;
|
|
11
|
+
declare const Grid: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type Grid = ReturnType<typeof Grid>;
|
|
13
|
+
export default Grid;
|