@dryui/ui 0.1.2 → 0.1.4
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-trigger.svelte +5 -6
- package/dist/alert-dialog/alert-dialog-action.svelte +42 -6
- package/dist/alert-dialog/alert-dialog-cancel.svelte +44 -5
- package/dist/alert-dialog/alert-dialog-footer.svelte +3 -2
- package/dist/aurora/aurora.svelte.d.ts +6 -0
- package/dist/beam/beam.svelte +17 -10
- package/dist/button/button.svelte +51 -1
- package/dist/button-group/button-group.svelte +7 -62
- package/dist/button-group/context.svelte.d.ts +5 -0
- package/dist/button-group/context.svelte.js +11 -0
- package/dist/chromatic-aberration/chromatic-aberration.svelte +60 -18
- package/dist/collapsible/collapsible-trigger.svelte +4 -7
- package/dist/color-picker/color-picker-eyedropper.svelte +4 -11
- package/dist/combobox/combobox-group.svelte +1 -1
- package/dist/data-grid/data-grid-pagination.svelte +20 -2
- package/dist/data-grid/data-grid-root.svelte +1 -0
- package/dist/date-field/date-field-root.svelte +66 -20
- package/dist/date-field/date-field-segment.svelte +11 -9
- package/dist/date-field/date-field-separator.svelte +9 -1
- package/dist/date-picker/datepicker-calendar.svelte +168 -13
- package/dist/date-picker/datepicker-trigger.svelte +3 -8
- package/dist/date-range-picker/date-range-picker-calendar.svelte +177 -13
- package/dist/date-range-picker/date-range-picker-root.svelte +0 -6
- package/dist/date-range-picker/date-range-picker-trigger.svelte +18 -12
- package/dist/dialog/dialog-content.svelte +1 -0
- package/dist/field/field-root.svelte +0 -1
- package/dist/file-select/file-select-clear.svelte +2 -8
- package/dist/file-upload/file-upload-item-delete.svelte +4 -7
- package/dist/file-upload/file-upload-root.svelte +0 -4
- package/dist/flip-card/flip-card-back.svelte +2 -2
- package/dist/flip-card/flip-card-front.svelte +2 -2
- package/dist/flip-card/flip-card-root.svelte +2 -0
- package/dist/float-button/float-button-root.svelte +2 -1
- package/dist/image-comparison/image-comparison.svelte +16 -24
- package/dist/input-group/input-group-action.svelte +5 -0
- package/dist/input-group/input-group-input.svelte +7 -2
- package/dist/input-group/input-group-prefix.svelte +5 -0
- package/dist/input-group/input-group-root.svelte +10 -2
- package/dist/input-group/input-group-select.svelte +5 -0
- package/dist/input-group/input-group-separator.svelte +10 -0
- package/dist/input-group/input-group-suffix.svelte +5 -0
- package/dist/list/list-item-icon.svelte +8 -0
- package/dist/list/list-item-text.svelte +19 -0
- package/dist/list/list-item.svelte +42 -0
- package/dist/list/list-root.svelte +0 -71
- package/dist/list/list-subheader.svelte +11 -0
- package/dist/map/map-marker.svelte +10 -0
- package/dist/map/map-popup.svelte +7 -0
- package/dist/map/map-root.svelte +0 -30
- package/dist/multi-select-combobox/multi-select-combobox-group.svelte +1 -1
- package/dist/option-swatch-group/option-swatch-group-item.svelte +46 -0
- package/dist/option-swatch-group/option-swatch-group-label.svelte +10 -0
- package/dist/option-swatch-group/option-swatch-group-meta.svelte +10 -0
- package/dist/option-swatch-group/option-swatch-group-root.svelte +0 -79
- package/dist/option-swatch-group/option-swatch-group-swatch.svelte +25 -6
- package/dist/pin-input/pin-input-cell.svelte +4 -1
- package/dist/radio-group/radio-group-item.svelte +90 -0
- package/dist/radio-group/radio-group.svelte +0 -89
- package/dist/range-calendar/range-calendar-grid.svelte +217 -179
- package/dist/range-calendar/range-calendar-root.svelte +24 -10
- package/dist/rich-text-editor/rich-text-editor-content.svelte +91 -3
- package/dist/rich-text-editor/rich-text-editor-root.svelte +168 -3
- package/dist/rich-text-editor/rich-text-editor-toolbar.svelte +318 -275
- package/dist/select/select-trigger.svelte +5 -8
- package/dist/shader-canvas/shader-canvas.svelte +0 -3
- package/dist/sidebar/sidebar-trigger.svelte +3 -2
- package/dist/system-map/system-map.svelte +120 -674
- package/dist/tabs/tabs-trigger.svelte +7 -4
- package/dist/tags-input/tags-input-input.svelte +3 -0
- package/dist/tags-input/tags-input-root.svelte +4 -13
- package/dist/tags-input/tags-input-tag.svelte +3 -0
- package/dist/themes/dark.css +6 -0
- package/dist/themes/default.css +3 -0
- package/dist/toast/toast-action.svelte +1 -0
- package/dist/toast/toast-close.svelte +4 -0
- package/dist/toast/toast-provider.svelte +5 -26
- package/dist/toast/toast-root.svelte +5 -10
- package/dist/virtual-list/virtual-list.svelte +187 -3
- package/package.json +3 -3
|
@@ -8,6 +8,13 @@
|
|
|
8
8
|
isDateInRange,
|
|
9
9
|
formatDate
|
|
10
10
|
} from '@dryui/primitives';
|
|
11
|
+
import {
|
|
12
|
+
generateWeekdayLabels,
|
|
13
|
+
splitIntoWeeks,
|
|
14
|
+
getDayISOString,
|
|
15
|
+
handleCalendarKeydown,
|
|
16
|
+
focusCalendarDay
|
|
17
|
+
} from '../internal/calendar-grid-utils.js';
|
|
11
18
|
|
|
12
19
|
interface Props extends HTMLAttributes<HTMLDivElement> {}
|
|
13
20
|
|
|
@@ -15,7 +22,7 @@
|
|
|
15
22
|
|
|
16
23
|
const ctx = getRangeCalendarCtx();
|
|
17
24
|
|
|
18
|
-
let gridEl = $state<HTMLDivElement>();
|
|
25
|
+
let gridEl = $state<HTMLDivElement | undefined>();
|
|
19
26
|
|
|
20
27
|
const weekdayLabels = $derived(generateWeekdayLabels(ctx.locale, ctx.weekStartDay));
|
|
21
28
|
|
|
@@ -30,28 +37,6 @@
|
|
|
30
37
|
|
|
31
38
|
const weeks = $derived(splitIntoWeeks(calendarDays));
|
|
32
39
|
|
|
33
|
-
function generateWeekdayLabels(locale: string, weekStartDay: number): string[] {
|
|
34
|
-
const formatter = new Intl.DateTimeFormat(locale, { weekday: 'short' });
|
|
35
|
-
const labels: string[] = [];
|
|
36
|
-
for (let i = 0; i < 7; i++) {
|
|
37
|
-
const d = new Date(2024, 0, 7 + ((i + weekStartDay) % 7));
|
|
38
|
-
labels.push(formatter.format(d));
|
|
39
|
-
}
|
|
40
|
-
return labels;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function splitIntoWeeks(days: Date[]): Date[][] {
|
|
44
|
-
const result: Date[][] = [];
|
|
45
|
-
for (let i = 0; i < days.length; i += 7) {
|
|
46
|
-
result.push(days.slice(i, i + 7));
|
|
47
|
-
}
|
|
48
|
-
return result;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function getDayISOString(day: Date): string {
|
|
52
|
-
return `${day.getFullYear()}-${String(day.getMonth() + 1).padStart(2, '0')}-${String(day.getDate()).padStart(2, '0')}`;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
40
|
function isInRange(day: Date): boolean {
|
|
56
41
|
const start = ctx.startDate;
|
|
57
42
|
const end = ctx.endDate ?? ctx.hoveredDate;
|
|
@@ -83,72 +68,71 @@
|
|
|
83
68
|
}
|
|
84
69
|
|
|
85
70
|
function handleDayKeydown(e: KeyboardEvent, day: Date) {
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
newDate.setDate(newDate.getDate() - 7);
|
|
101
|
-
} else if (key === 'ArrowDown') {
|
|
102
|
-
e.preventDefault();
|
|
103
|
-
newDate = new Date(day);
|
|
104
|
-
newDate.setDate(newDate.getDate() + 7);
|
|
105
|
-
} else if (key === 'Enter' || key === ' ') {
|
|
106
|
-
e.preventDefault();
|
|
107
|
-
if (isDateInRange(day, ctx.min, ctx.max)) ctx.selectDate(day);
|
|
108
|
-
return;
|
|
109
|
-
} else return;
|
|
110
|
-
|
|
111
|
-
if (newDate) {
|
|
112
|
-
ctx.setFocusedDate(newDate);
|
|
113
|
-
requestAnimationFrame(() => {
|
|
114
|
-
const isoStr = getDayISOString(newDate!);
|
|
115
|
-
const btn = gridEl?.querySelector(`[data-calendar-day="${isoStr}"]`) as HTMLButtonElement;
|
|
116
|
-
btn?.focus();
|
|
117
|
-
});
|
|
71
|
+
const result = handleCalendarKeydown(e, day, {
|
|
72
|
+
onSelect: (date) => {
|
|
73
|
+
if (isDateInRange(date, ctx.min, ctx.max)) {
|
|
74
|
+
ctx.selectDate(date);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
onEscape: () => {},
|
|
78
|
+
setFocusedDate: (date) => ctx.setFocusedDate(date),
|
|
79
|
+
weekStartDay: ctx.weekStartDay,
|
|
80
|
+
min: ctx.min,
|
|
81
|
+
max: ctx.max
|
|
82
|
+
});
|
|
83
|
+
if (result?.type === 'navigate') {
|
|
84
|
+
requestAnimationFrame(() => focusCalendarDay(gridEl, result.newDate));
|
|
118
85
|
}
|
|
119
86
|
}
|
|
120
87
|
|
|
121
88
|
function isDayDisabled(day: Date): boolean {
|
|
122
89
|
return !isDateInRange(day, ctx.min, ctx.max);
|
|
123
90
|
}
|
|
91
|
+
|
|
92
|
+
function captureGrid(node: HTMLDivElement) {
|
|
93
|
+
gridEl = node;
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
destroy() {
|
|
97
|
+
if (gridEl === node) {
|
|
98
|
+
gridEl = undefined;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
124
103
|
</script>
|
|
125
104
|
|
|
126
|
-
<div
|
|
127
|
-
<div role="group" aria-label={monthYearLabel}>
|
|
105
|
+
<div {@attach captureGrid} data-range-calendar-grid class={className} {...rest}>
|
|
106
|
+
<div data-calendar-panel role="group" aria-label={monthYearLabel}>
|
|
128
107
|
<div data-calendar-header>
|
|
129
|
-
<button
|
|
108
|
+
<button
|
|
109
|
+
type="button"
|
|
110
|
+
data-calendar-nav
|
|
111
|
+
aria-label="Previous month"
|
|
112
|
+
onclick={() => ctx.prevMonth()}
|
|
113
|
+
>
|
|
130
114
|
‹
|
|
131
115
|
</button>
|
|
132
|
-
<span aria-live="polite" aria-atomic="true">
|
|
116
|
+
<span data-calendar-heading aria-live="polite" aria-atomic="true">
|
|
133
117
|
{monthYearLabel}
|
|
134
118
|
</span>
|
|
135
|
-
<button type="button" aria-label="Next month" onclick={() => ctx.nextMonth()}>
|
|
119
|
+
<button type="button" data-calendar-nav aria-label="Next month" onclick={() => ctx.nextMonth()}>
|
|
136
120
|
›
|
|
137
121
|
</button>
|
|
138
122
|
</div>
|
|
139
123
|
|
|
140
124
|
<div role="grid" aria-label={monthYearLabel}>
|
|
141
|
-
<div role="row">
|
|
142
|
-
{#each weekdayLabels as label}
|
|
143
|
-
<div role="columnheader" aria-label={label}>
|
|
125
|
+
<div data-calendar-row role="row">
|
|
126
|
+
{#each weekdayLabels as label (label)}
|
|
127
|
+
<div data-calendar-columnheader role="columnheader" aria-label={label}>
|
|
144
128
|
<span aria-hidden="true">{label}</span>
|
|
145
129
|
</div>
|
|
146
130
|
{/each}
|
|
147
131
|
</div>
|
|
148
132
|
|
|
149
|
-
{#each weeks as week}
|
|
150
|
-
<div role="row">
|
|
151
|
-
{#each week as day}
|
|
133
|
+
{#each weeks as week (week[0]?.getTime() ?? 0)}
|
|
134
|
+
<div data-calendar-row role="row">
|
|
135
|
+
{#each week as day (day.getTime())}
|
|
152
136
|
{@const isCurrent = day.getMonth() === ctx.viewMonth}
|
|
153
137
|
{@const inRange = isInRange(day)}
|
|
154
138
|
{@const rangeStart = isRangeStart(day)}
|
|
@@ -157,16 +141,23 @@
|
|
|
157
141
|
{@const disabled = isDayDisabled(day)}
|
|
158
142
|
{@const focused = isSameDay(day, ctx.focusedDate)}
|
|
159
143
|
{@const isoStr = getDayISOString(day)}
|
|
160
|
-
<div
|
|
144
|
+
<div
|
|
145
|
+
data-calendar-cell
|
|
146
|
+
data-in-range={inRange ? '' : undefined}
|
|
147
|
+
data-range-start={rangeStart ? '' : undefined}
|
|
148
|
+
data-range-end={rangeEnd ? '' : undefined}
|
|
149
|
+
>
|
|
161
150
|
<button
|
|
162
151
|
role="gridcell"
|
|
163
152
|
type="button"
|
|
153
|
+
data-calendar-day-button
|
|
164
154
|
tabindex={focused ? 0 : -1}
|
|
165
155
|
aria-label={formatDate(day, ctx.locale, {
|
|
166
156
|
year: 'numeric',
|
|
167
157
|
month: 'long',
|
|
168
158
|
day: 'numeric'
|
|
169
159
|
})}
|
|
160
|
+
aria-current={today ? 'date' : undefined}
|
|
170
161
|
aria-selected={inRange || undefined}
|
|
171
162
|
aria-disabled={disabled}
|
|
172
163
|
data-calendar-day={isoStr}
|
|
@@ -195,137 +186,184 @@
|
|
|
195
186
|
[data-range-calendar-grid] {
|
|
196
187
|
display: grid;
|
|
197
188
|
gap: var(--dry-space-2);
|
|
189
|
+
user-select: none;
|
|
190
|
+
color: var(--dry-color-text-strong);
|
|
191
|
+
font-family: var(--dry-font-sans);
|
|
192
|
+
}
|
|
198
193
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
[data-range-calendar-grid] [data-calendar-panel] {
|
|
195
|
+
display: grid;
|
|
196
|
+
gap: var(--dry-space-3);
|
|
197
|
+
padding: var(--dry-space-3);
|
|
198
|
+
background: var(--dry-range-calendar-panel-bg, var(--dry-color-bg-overlay));
|
|
199
|
+
border: 1px solid var(--dry-range-calendar-panel-border, var(--dry-color-stroke-weak));
|
|
200
|
+
border-radius: calc(var(--dry-range-calendar-radius, var(--dry-radius-lg)) - var(--dry-space-1));
|
|
201
|
+
}
|
|
203
202
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
203
|
+
[data-range-calendar-grid] [data-calendar-header] {
|
|
204
|
+
display: grid;
|
|
205
|
+
grid-template-columns: auto 1fr auto;
|
|
206
|
+
align-items: center;
|
|
207
|
+
gap: var(--dry-space-2);
|
|
208
|
+
padding-block-end: var(--dry-space-1);
|
|
209
|
+
border-block-end: 1px solid
|
|
210
|
+
color-mix(
|
|
211
|
+
in srgb,
|
|
212
|
+
var(--dry-range-calendar-panel-border, var(--dry-color-stroke-weak)) 70%,
|
|
213
|
+
transparent
|
|
214
|
+
);
|
|
215
|
+
}
|
|
210
216
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
217
|
+
[data-range-calendar-grid] [data-calendar-nav] {
|
|
218
|
+
display: inline-grid;
|
|
219
|
+
place-items: center;
|
|
220
|
+
height: var(--dry-space-8);
|
|
221
|
+
aspect-ratio: 1;
|
|
222
|
+
border: 1px solid var(--dry-range-calendar-nav-border, var(--dry-color-stroke-weak));
|
|
223
|
+
border-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
224
|
+
background: var(--dry-range-calendar-nav-bg, var(--dry-color-bg-raised));
|
|
225
|
+
color: var(--dry-range-calendar-nav-color, var(--dry-color-text-weak));
|
|
226
|
+
cursor: pointer;
|
|
227
|
+
transition:
|
|
228
|
+
background var(--dry-duration-fast) var(--dry-ease-default),
|
|
229
|
+
border-color var(--dry-duration-fast) var(--dry-ease-default),
|
|
230
|
+
color var(--dry-duration-fast) var(--dry-ease-default);
|
|
231
|
+
}
|
|
225
232
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
233
|
+
[data-range-calendar-grid] [data-calendar-nav]:hover:not([disabled]) {
|
|
234
|
+
background: var(--dry-range-calendar-day-hover-bg, var(--dry-color-fill-hover));
|
|
235
|
+
border-color: var(--dry-color-stroke-strong);
|
|
236
|
+
color: var(--dry-color-text-strong);
|
|
237
|
+
}
|
|
230
238
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
[data-range-calendar-grid] [data-calendar-nav]:focus-visible {
|
|
240
|
+
outline: 2px solid var(--dry-color-focus-ring);
|
|
241
|
+
outline-offset: 1px;
|
|
242
|
+
}
|
|
235
243
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
244
|
+
[data-range-calendar-grid] [data-calendar-heading] {
|
|
245
|
+
font-size: var(--dry-type-small-size, var(--dry-type-small-size));
|
|
246
|
+
font-weight: 700;
|
|
247
|
+
letter-spacing: -0.02em;
|
|
248
|
+
color: var(--dry-range-calendar-heading-color, var(--dry-color-text-strong));
|
|
249
|
+
}
|
|
241
250
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
251
|
+
[data-range-calendar-grid] [role='grid'] {
|
|
252
|
+
display: grid;
|
|
253
|
+
gap: var(--dry-space-1);
|
|
254
|
+
}
|
|
246
255
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
[data-range-calendar-grid] [data-calendar-row] {
|
|
257
|
+
display: grid;
|
|
258
|
+
grid-template-columns: repeat(7, minmax(0, 1fr));
|
|
259
|
+
gap: var(--dry-space-1);
|
|
260
|
+
}
|
|
252
261
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
+
[data-range-calendar-grid] [data-calendar-columnheader] {
|
|
263
|
+
display: grid;
|
|
264
|
+
place-items: center;
|
|
265
|
+
min-height: var(--dry-space-7);
|
|
266
|
+
font-size: calc(var(--dry-type-tiny-size, var(--dry-type-tiny-size)) * 0.92);
|
|
267
|
+
color: var(--dry-range-calendar-outside-color, var(--dry-color-text-weak));
|
|
268
|
+
text-transform: uppercase;
|
|
269
|
+
letter-spacing: 0.08em;
|
|
270
|
+
}
|
|
262
271
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
272
|
+
[data-range-calendar-grid] [data-calendar-cell] {
|
|
273
|
+
display: grid;
|
|
274
|
+
grid-template-columns: var(--dry-range-calendar-day-size, 2.5rem);
|
|
275
|
+
place-items: center;
|
|
276
|
+
padding-block: var(--dry-space-0_5);
|
|
277
|
+
border-radius: 0;
|
|
278
|
+
}
|
|
267
279
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
border-radius: var(--dry-range-calendar-day-radius);
|
|
275
|
-
background: transparent;
|
|
276
|
-
color: var(--dry-color-text-strong);
|
|
277
|
-
font: inherit;
|
|
278
|
-
font-size: var(--dry-type-small-size, var(--dry-type-small-size));
|
|
279
|
-
font-variant-numeric: tabular-nums;
|
|
280
|
-
cursor: pointer;
|
|
281
|
-
transition:
|
|
282
|
-
background var(--dry-duration-fast) var(--dry-ease-default),
|
|
283
|
-
color var(--dry-duration-fast) var(--dry-ease-default);
|
|
284
|
-
}
|
|
280
|
+
[data-range-calendar-grid] [data-calendar-cell][data-in-range] {
|
|
281
|
+
background: var(
|
|
282
|
+
--dry-range-calendar-range-bg,
|
|
283
|
+
color-mix(in srgb, var(--dry-color-fill-brand) 14%, transparent)
|
|
284
|
+
);
|
|
285
|
+
}
|
|
285
286
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
287
|
+
[data-range-calendar-grid] [data-calendar-cell][data-range-start][data-in-range] {
|
|
288
|
+
border-start-start-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
289
|
+
border-end-start-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
290
|
+
}
|
|
289
291
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
[data-range-calendar-grid] [data-calendar-cell][data-range-end][data-in-range] {
|
|
293
|
+
border-start-end-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
294
|
+
border-end-end-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
295
|
+
}
|
|
294
296
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
297
|
+
[data-range-calendar-grid] [data-calendar-cell][data-range-start][data-range-end] {
|
|
298
|
+
border-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
299
|
+
}
|
|
299
300
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
301
|
+
[data-range-calendar-grid] [data-calendar-day-button] {
|
|
302
|
+
display: inline-grid;
|
|
303
|
+
place-items: center;
|
|
304
|
+
min-height: var(--dry-range-calendar-day-size, 2.5rem);
|
|
305
|
+
padding: 0;
|
|
306
|
+
aspect-ratio: 1;
|
|
307
|
+
border: 1px solid transparent;
|
|
308
|
+
border-radius: var(--dry-range-calendar-day-radius, var(--dry-radius-md));
|
|
309
|
+
background: transparent;
|
|
310
|
+
color: var(--dry-color-text-strong);
|
|
311
|
+
font: inherit;
|
|
312
|
+
font-size: var(--dry-type-small-size, var(--dry-type-small-size));
|
|
313
|
+
font-variant-numeric: tabular-nums;
|
|
314
|
+
font-weight: 500;
|
|
315
|
+
cursor: pointer;
|
|
316
|
+
transition:
|
|
317
|
+
background var(--dry-duration-fast) var(--dry-ease-default),
|
|
318
|
+
border-color var(--dry-duration-fast) var(--dry-ease-default),
|
|
319
|
+
color var(--dry-duration-fast) var(--dry-ease-default);
|
|
320
|
+
}
|
|
305
321
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
322
|
+
[data-range-calendar-grid]
|
|
323
|
+
[data-calendar-day-button]:hover:not([data-disabled]):not([data-range-start]):not(
|
|
324
|
+
[data-range-end]
|
|
325
|
+
) {
|
|
326
|
+
background: var(--dry-range-calendar-day-hover-bg, var(--dry-color-fill-hover));
|
|
327
|
+
}
|
|
309
328
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
329
|
+
[data-range-calendar-grid] [data-calendar-day-button]:focus-visible {
|
|
330
|
+
outline: 2px solid var(--dry-color-focus-ring);
|
|
331
|
+
outline-offset: 1px;
|
|
332
|
+
}
|
|
314
333
|
|
|
315
|
-
|
|
316
|
-
[
|
|
317
|
-
|
|
318
|
-
|
|
334
|
+
[data-range-calendar-grid]
|
|
335
|
+
[data-calendar-day-button][data-today]:not([data-range-start]):not([data-range-end]) {
|
|
336
|
+
border-color: color-mix(
|
|
337
|
+
in srgb,
|
|
338
|
+
var(--dry-range-calendar-today-color, var(--dry-color-text-brand)) 24%,
|
|
339
|
+
transparent
|
|
340
|
+
);
|
|
341
|
+
color: var(--dry-range-calendar-today-color, var(--dry-color-text-brand));
|
|
342
|
+
font-weight: 600;
|
|
343
|
+
}
|
|
319
344
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
345
|
+
[data-range-calendar-grid] [data-calendar-day-button][data-range-start],
|
|
346
|
+
[data-range-calendar-grid] [data-calendar-day-button][data-range-end] {
|
|
347
|
+
background: var(--dry-range-calendar-selected-bg, var(--dry-color-fill-brand));
|
|
348
|
+
color: var(--dry-range-calendar-selected-color, var(--dry-color-on-brand));
|
|
349
|
+
font-weight: 700;
|
|
350
|
+
}
|
|
324
351
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
352
|
+
[data-range-calendar-grid]
|
|
353
|
+
[data-calendar-day-button][data-range-start]:hover:not([data-disabled]),
|
|
354
|
+
[data-range-calendar-grid]
|
|
355
|
+
[data-calendar-day-button][data-range-end]:hover:not([data-disabled]) {
|
|
356
|
+
background: var(--dry-range-calendar-selected-hover-bg, var(--dry-color-fill-brand-hover));
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
[data-range-calendar-grid] [data-calendar-day-button][data-outside-month] {
|
|
360
|
+
color: var(--dry-range-calendar-outside-color, var(--dry-color-text-weak));
|
|
361
|
+
opacity: 0.55;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
[data-range-calendar-grid] [data-calendar-day-button][data-disabled] {
|
|
365
|
+
cursor: not-allowed;
|
|
366
|
+
opacity: 0.35;
|
|
367
|
+
pointer-events: none;
|
|
330
368
|
}
|
|
331
369
|
</style>
|
|
@@ -112,23 +112,39 @@
|
|
|
112
112
|
|
|
113
113
|
<style>
|
|
114
114
|
[data-range-calendar-root] {
|
|
115
|
-
--dry-range-calendar-bg: var(--dry-color-bg-
|
|
115
|
+
--dry-range-calendar-bg: var(--dry-color-bg-base);
|
|
116
116
|
--dry-range-calendar-border: var(--dry-color-stroke-weak);
|
|
117
|
-
--dry-range-calendar-
|
|
118
|
-
--dry-range-calendar-
|
|
117
|
+
--dry-range-calendar-panel-bg: var(--dry-color-bg-overlay);
|
|
118
|
+
--dry-range-calendar-panel-border: color-mix(
|
|
119
|
+
in srgb,
|
|
120
|
+
var(--dry-color-stroke-strong) 18%,
|
|
121
|
+
transparent
|
|
122
|
+
);
|
|
123
|
+
--dry-range-calendar-heading-color: var(--dry-color-text-strong);
|
|
124
|
+
--dry-range-calendar-nav-bg: var(--dry-color-bg-raised);
|
|
125
|
+
--dry-range-calendar-nav-border: var(--dry-color-stroke-weak);
|
|
126
|
+
--dry-range-calendar-nav-color: var(--dry-color-text-weak);
|
|
127
|
+
--dry-range-calendar-radius: var(--dry-radius-xl);
|
|
128
|
+
--dry-range-calendar-shadow: var(--dry-shadow-raised, var(--dry-shadow-sm));
|
|
119
129
|
--dry-range-calendar-padding: var(--dry-space-3);
|
|
120
|
-
--dry-range-calendar-day-size: 2.
|
|
130
|
+
--dry-range-calendar-day-size: 2.5rem;
|
|
121
131
|
--dry-range-calendar-day-radius: var(--dry-radius-md);
|
|
122
|
-
--dry-range-calendar-day-hover-bg: var(--dry-color-
|
|
132
|
+
--dry-range-calendar-day-hover-bg: var(--dry-color-fill-hover);
|
|
123
133
|
--dry-range-calendar-selected-bg: var(--dry-color-fill-brand);
|
|
124
134
|
--dry-range-calendar-selected-color: var(--dry-color-on-brand);
|
|
125
135
|
--dry-range-calendar-selected-hover-bg: var(--dry-color-fill-brand-hover);
|
|
126
|
-
--dry-range-calendar-range-bg: color-mix(
|
|
127
|
-
|
|
136
|
+
--dry-range-calendar-range-bg: color-mix(
|
|
137
|
+
in srgb,
|
|
138
|
+
var(--dry-color-fill-brand) 14%,
|
|
139
|
+
transparent
|
|
140
|
+
);
|
|
141
|
+
--dry-range-calendar-today-color: var(--dry-color-text-brand);
|
|
128
142
|
--dry-range-calendar-outside-color: var(--dry-color-text-weak);
|
|
129
143
|
|
|
130
|
-
display: grid;
|
|
144
|
+
display: inline-grid;
|
|
131
145
|
box-sizing: border-box;
|
|
146
|
+
justify-items: start;
|
|
147
|
+
gap: var(--dry-space-3);
|
|
132
148
|
padding: var(--dry-range-calendar-padding);
|
|
133
149
|
background: var(--dry-range-calendar-bg);
|
|
134
150
|
border: 1px solid var(--dry-range-calendar-border);
|
|
@@ -137,6 +153,4 @@
|
|
|
137
153
|
color: var(--dry-color-text-strong);
|
|
138
154
|
font-family: var(--dry-font-sans);
|
|
139
155
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
156
|
</style>
|
|
@@ -1,13 +1,101 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
-
import {
|
|
3
|
+
import { getRichTextEditorCtx } from '@dryui/primitives/rich-text-editor';
|
|
4
4
|
|
|
5
5
|
interface Props extends HTMLAttributes<HTMLDivElement> {}
|
|
6
6
|
|
|
7
7
|
let { ...rest }: Props = $props();
|
|
8
|
+
|
|
9
|
+
const ctx = getRichTextEditorCtx();
|
|
10
|
+
|
|
11
|
+
let contentEl = $state<HTMLDivElement>();
|
|
12
|
+
|
|
13
|
+
// Register the content element with the context
|
|
14
|
+
$effect(() => {
|
|
15
|
+
if (contentEl) {
|
|
16
|
+
ctx.contentEl = contentEl;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Sync value into contenteditable (also clears hint elements on mount)
|
|
21
|
+
$effect(() => {
|
|
22
|
+
if (!contentEl) return;
|
|
23
|
+
const html = ctx.html || '';
|
|
24
|
+
if (contentEl.innerHTML !== html && document.activeElement !== contentEl) {
|
|
25
|
+
contentEl.innerHTML = html;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Listen for selectionchange on document to track formatting state
|
|
30
|
+
$effect(() => {
|
|
31
|
+
if (!contentEl) return;
|
|
32
|
+
|
|
33
|
+
function onSelectionChange() {
|
|
34
|
+
const sel = window.getSelection();
|
|
35
|
+
if (!sel || sel.rangeCount === 0) return;
|
|
36
|
+
if (contentEl!.contains(sel.anchorNode)) {
|
|
37
|
+
ctx.updateState();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
document.addEventListener('selectionchange', onSelectionChange);
|
|
42
|
+
return () => {
|
|
43
|
+
document.removeEventListener('selectionchange', onSelectionChange);
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
function handleInput() {
|
|
48
|
+
ctx.updateState();
|
|
49
|
+
ctx.syncValue();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function handleKeydown(event: KeyboardEvent) {
|
|
53
|
+
if (ctx.readonly) return;
|
|
54
|
+
|
|
55
|
+
const mod = event.metaKey || event.ctrlKey;
|
|
56
|
+
if (!mod) return;
|
|
57
|
+
|
|
58
|
+
switch (event.key.toLowerCase()) {
|
|
59
|
+
case 'b':
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
ctx.toggleBold();
|
|
62
|
+
break;
|
|
63
|
+
case 'i':
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
ctx.toggleItalic();
|
|
66
|
+
break;
|
|
67
|
+
case 'u':
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
ctx.toggleUnderline();
|
|
70
|
+
break;
|
|
71
|
+
case 'k':
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
contentEl?.dispatchEvent(new CustomEvent('rte-link-request', { bubbles: true }));
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
8
77
|
</script>
|
|
9
78
|
|
|
10
|
-
|
|
79
|
+
<!--
|
|
80
|
+
The elements below (h1–h3, p, ul, ol, li, a) are created dynamically by the
|
|
81
|
+
browser's execCommand API inside the contenteditable div. They are declared
|
|
82
|
+
here so Svelte can verify the scoped CSS selectors that style them. The
|
|
83
|
+
$effect that syncs ctx.html into innerHTML replaces these on mount.
|
|
84
|
+
-->
|
|
85
|
+
<div
|
|
86
|
+
bind:this={contentEl}
|
|
87
|
+
contenteditable={!ctx.readonly}
|
|
88
|
+
role="textbox"
|
|
89
|
+
aria-multiline="true"
|
|
90
|
+
aria-placeholder={ctx.placeholder || undefined}
|
|
91
|
+
data-placeholder={ctx.placeholder || undefined}
|
|
92
|
+
data-part="content"
|
|
93
|
+
data-rte-content
|
|
94
|
+
data-readonly={ctx.readonly || undefined}
|
|
95
|
+
oninput={handleInput}
|
|
96
|
+
onkeydown={handleKeydown}
|
|
97
|
+
{...rest}
|
|
98
|
+
><h1>.</h1><h2>.</h2><h3>.</h3><p></p><ul><li></li></ul><ol><li></li></ol><a aria-hidden="true" href="https://example.com">.</a></div>
|
|
11
99
|
|
|
12
100
|
<style>
|
|
13
101
|
[data-part='content'] {
|
|
@@ -32,7 +120,7 @@
|
|
|
32
120
|
pointer-events: none;
|
|
33
121
|
}
|
|
34
122
|
|
|
35
|
-
/* Typography
|
|
123
|
+
/* Typography for contenteditable elements created by execCommand */
|
|
36
124
|
[data-part='content'] h1 {
|
|
37
125
|
font-size: var(--dry-type-heading-2-size, var(--dry-text-2xl-size));
|
|
38
126
|
font-weight: 700;
|