@placeholderco/placeholder-ui 2.1.0 → 2.2.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/editors/CodeMirror.svelte +295 -297
- package/dist/editors/tiptap/LinkActionMenu.svelte +6 -1
- package/dist/editors/tiptap/extensions/Alert.js +17 -17
- package/dist/editors/tiptap/extensions/Div.js +19 -19
- package/dist/editors/tiptap/extensions/Span.js +14 -14
- package/dist/editors/tiptap/toolbar/AlertButton.svelte +254 -253
- package/dist/editors/tiptap/toolbar/AlignCenterButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignJustifyButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignLeftButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/AlignRightButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/BoldButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/BulletListButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/CodeButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/ColorButton.svelte +265 -265
- package/dist/editors/tiptap/toolbar/DocumentButton.svelte +51 -51
- package/dist/editors/tiptap/toolbar/HeadingButton.svelte +21 -21
- package/dist/editors/tiptap/toolbar/HtmlButton.svelte +48 -52
- package/dist/editors/tiptap/toolbar/ImageButton.svelte +35 -39
- package/dist/editors/tiptap/toolbar/ItalicButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/LinkButton.svelte +249 -249
- package/dist/editors/tiptap/toolbar/OrderedListButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/RedoButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/StrikethroughButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/SubscriptButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/SuperscriptButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/TableButton.svelte +231 -224
- package/dist/editors/tiptap/toolbar/ToolbarButton.svelte +59 -65
- package/dist/editors/tiptap/toolbar/UnderlineButton.svelte +11 -11
- package/dist/editors/tiptap/toolbar/UndoButton.svelte +11 -11
- package/dist/form/Autocomplete.svelte +24 -22
- package/dist/form/AutocompleteMulti.svelte +24 -22
- package/dist/form/Checkbox.svelte +4 -4
- package/dist/form/Chips.svelte +15 -7
- package/dist/form/ColorPicker.svelte +5 -20
- package/dist/form/ComboBox.svelte +4 -4
- package/dist/form/ComboBoxItemBuilder.svelte +14 -32
- package/dist/form/ComboBoxMulti.svelte +7 -3
- package/dist/form/CronBuilder.svelte +32 -110
- package/dist/form/DatePicker.svelte +9 -28
- package/dist/form/DateRangePicker.svelte +46 -36
- package/dist/form/DateTimePicker.svelte +11 -30
- package/dist/form/Number.svelte +1 -3
- package/dist/form/RadioGroup.svelte +1 -3
- package/dist/form/Select.svelte +25 -28
- package/dist/form/SelectMulti.svelte +36 -38
- package/dist/form/StringArrayBuilder.svelte +1 -3
- package/dist/form/TextArea.svelte +5 -6
- package/dist/form/Textbox.svelte +10 -4
- package/dist/form/TimePicker.svelte +10 -4
- package/dist/icon/Icon.svelte +5 -1
- package/dist/index.d.ts +147 -146
- package/dist/index.js +78 -77
- package/dist/layout/CustomNavbar.svelte +1 -1
- package/dist/layout/NavbarItemDisplay.svelte +1 -1
- package/dist/layout/NavbarItemView.svelte +3 -1
- package/dist/layout/Sidenav.svelte +1 -1
- package/dist/models/ComboBoxItem.d.ts +4 -4
- package/dist/models/NotifyModel.js +0 -1
- package/dist/theme.svelte.d.ts +1 -1
- package/dist/theme.svelte.js +46 -22
- package/dist/ui/Accordion.svelte +1 -3
- package/dist/ui/Badge.svelte +4 -5
- package/dist/ui/Button.svelte +7 -1
- package/dist/ui/ContextMenu.svelte +5 -11
- package/dist/ui/Dialog.svelte +16 -3
- package/dist/ui/Dialog.svelte.d.ts +7 -1
- package/dist/ui/Dropdown.svelte +21 -10
- package/dist/ui/MultiSortable.svelte +1 -3
- package/dist/ui/Pagination.svelte +2 -2
- package/dist/ui/Popover.svelte +16 -37
- package/dist/ui/ProgressBar.svelte +1 -4
- package/dist/ui/ThemeSwitcher.svelte +2 -1
- package/dist/ui/Tooltip.svelte +1 -37
- package/dist/util/DateFunctions.js +1 -1
- package/dist/util/Floating.d.ts +70 -0
- package/dist/util/Floating.js +321 -0
- package/dist/util/NavigateTo.js +2 -2
- package/dist/util/Transitions.d.ts +1 -1
- package/dist/util/Transitions.js +1 -1
- package/package.json +25 -25
|
@@ -194,7 +194,13 @@
|
|
|
194
194
|
isParsingExpression = true;
|
|
195
195
|
|
|
196
196
|
// Try to detect frequency type
|
|
197
|
-
if (
|
|
197
|
+
if (
|
|
198
|
+
min.startsWith('*/') &&
|
|
199
|
+
hour === '*' &&
|
|
200
|
+
dayOfMonth === '*' &&
|
|
201
|
+
month === '*' &&
|
|
202
|
+
dayOfWeek === '*'
|
|
203
|
+
) {
|
|
198
204
|
frequency = 'minute';
|
|
199
205
|
minuteInterval = parseInt(min.split('/')[1]) || 1;
|
|
200
206
|
} else if (hour.startsWith('*/') && dayOfMonth === '*' && month === '*' && dayOfWeek === '*') {
|
|
@@ -210,7 +216,10 @@
|
|
|
210
216
|
frequency = 'weekly';
|
|
211
217
|
weeklyMinute = parseInt(min) || 0;
|
|
212
218
|
weeklyHour = parseInt(hour) || 0;
|
|
213
|
-
weeklyDays = dayOfWeek
|
|
219
|
+
weeklyDays = dayOfWeek
|
|
220
|
+
.split(',')
|
|
221
|
+
.map((d) => parseInt(d))
|
|
222
|
+
.filter((d) => !isNaN(d));
|
|
214
223
|
} else if (month === '*' && dayOfWeek === '*' && !dayOfMonth.includes('*')) {
|
|
215
224
|
frequency = 'monthly';
|
|
216
225
|
monthlyMinute = parseInt(min) || 0;
|
|
@@ -236,7 +245,7 @@
|
|
|
236
245
|
|
|
237
246
|
function toggleWeekday(day: number) {
|
|
238
247
|
if (weeklyDays.includes(day)) {
|
|
239
|
-
weeklyDays = weeklyDays.filter(d => d !== day);
|
|
248
|
+
weeklyDays = weeklyDays.filter((d) => d !== day);
|
|
240
249
|
} else {
|
|
241
250
|
weeklyDays = [...weeklyDays, day];
|
|
242
251
|
}
|
|
@@ -298,14 +307,16 @@
|
|
|
298
307
|
return `Every ${dayText} at ${dailyHour.toString().padStart(2, '0')}:${dailyMinute.toString().padStart(2, '0')}`;
|
|
299
308
|
|
|
300
309
|
case 'weekly':
|
|
301
|
-
const dayNames = weeklyDays
|
|
310
|
+
const dayNames = weeklyDays
|
|
311
|
+
.map((d) => weekDays.find((wd) => wd.value === d)?.label)
|
|
312
|
+
.join(', ');
|
|
302
313
|
return `Every ${dayNames} at ${weeklyHour.toString().padStart(2, '0')}:${weeklyMinute.toString().padStart(2, '0')}`;
|
|
303
314
|
|
|
304
315
|
case 'monthly':
|
|
305
316
|
return `Day ${monthlyDay} of every month at ${monthlyHour.toString().padStart(2, '0')}:${monthlyMinute.toString().padStart(2, '0')}`;
|
|
306
317
|
|
|
307
318
|
case 'yearly':
|
|
308
|
-
const monthName = monthOptions.find(m => m.value === yearlyMonth.toString())?.label;
|
|
319
|
+
const monthName = monthOptions.find((m) => m.value === yearlyMonth.toString())?.label;
|
|
309
320
|
return `${monthName} ${yearlyDay} at ${yearlyHour.toString().padStart(2, '0')}:${yearlyMinute.toString().padStart(2, '0')}`;
|
|
310
321
|
|
|
311
322
|
case 'custom':
|
|
@@ -329,12 +340,7 @@
|
|
|
329
340
|
>
|
|
330
341
|
<div class="cron-builder {classes}" class:disabled>
|
|
331
342
|
<div class="cron-frequency">
|
|
332
|
-
<Select
|
|
333
|
-
label="Frequency"
|
|
334
|
-
bind:value={frequency}
|
|
335
|
-
options={frequencyOptions}
|
|
336
|
-
{disabled}
|
|
337
|
-
/>
|
|
343
|
+
<Select label="Frequency" bind:value={frequency} options={frequencyOptions} {disabled} />
|
|
338
344
|
</div>
|
|
339
345
|
|
|
340
346
|
<div class="cron-settings">
|
|
@@ -347,42 +353,12 @@
|
|
|
347
353
|
{disabled}
|
|
348
354
|
/>
|
|
349
355
|
{:else if frequency === 'hourly'}
|
|
350
|
-
<Number
|
|
351
|
-
|
|
352
|
-
bind:value={hourlyInterval}
|
|
353
|
-
min={1}
|
|
354
|
-
max={23}
|
|
355
|
-
{disabled}
|
|
356
|
-
/>
|
|
357
|
-
<Number
|
|
358
|
-
label="At minute"
|
|
359
|
-
bind:value={hourlyMinute}
|
|
360
|
-
min={0}
|
|
361
|
-
max={59}
|
|
362
|
-
{disabled}
|
|
363
|
-
/>
|
|
356
|
+
<Number label="Interval (hours)" bind:value={hourlyInterval} min={1} max={23} {disabled} />
|
|
357
|
+
<Number label="At minute" bind:value={hourlyMinute} min={0} max={59} {disabled} />
|
|
364
358
|
{:else if frequency === 'daily'}
|
|
365
|
-
<Number
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
min={1}
|
|
369
|
-
max={31}
|
|
370
|
-
{disabled}
|
|
371
|
-
/>
|
|
372
|
-
<Number
|
|
373
|
-
label="Hour"
|
|
374
|
-
bind:value={dailyHour}
|
|
375
|
-
min={0}
|
|
376
|
-
max={23}
|
|
377
|
-
{disabled}
|
|
378
|
-
/>
|
|
379
|
-
<Number
|
|
380
|
-
label="Minute"
|
|
381
|
-
bind:value={dailyMinute}
|
|
382
|
-
min={0}
|
|
383
|
-
max={59}
|
|
384
|
-
{disabled}
|
|
385
|
-
/>
|
|
359
|
+
<Number label="Interval (days)" bind:value={dailyInterval} min={1} max={31} {disabled} />
|
|
360
|
+
<Number label="Hour" bind:value={dailyHour} min={0} max={23} {disabled} />
|
|
361
|
+
<Number label="Minute" bind:value={dailyMinute} min={0} max={59} {disabled} />
|
|
386
362
|
{:else if frequency === 'weekly'}
|
|
387
363
|
<div class="weekday-selector">
|
|
388
364
|
<span class="weekday-label">Days of Week</span>
|
|
@@ -400,71 +376,17 @@
|
|
|
400
376
|
{/each}
|
|
401
377
|
</div>
|
|
402
378
|
</div>
|
|
403
|
-
<Number
|
|
404
|
-
|
|
405
|
-
bind:value={weeklyHour}
|
|
406
|
-
min={0}
|
|
407
|
-
max={23}
|
|
408
|
-
{disabled}
|
|
409
|
-
/>
|
|
410
|
-
<Number
|
|
411
|
-
label="Minute"
|
|
412
|
-
bind:value={weeklyMinute}
|
|
413
|
-
min={0}
|
|
414
|
-
max={59}
|
|
415
|
-
{disabled}
|
|
416
|
-
/>
|
|
379
|
+
<Number label="Hour" bind:value={weeklyHour} min={0} max={23} {disabled} />
|
|
380
|
+
<Number label="Minute" bind:value={weeklyMinute} min={0} max={59} {disabled} />
|
|
417
381
|
{:else if frequency === 'monthly'}
|
|
418
|
-
<Number
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
min={1}
|
|
422
|
-
max={31}
|
|
423
|
-
{disabled}
|
|
424
|
-
/>
|
|
425
|
-
<Number
|
|
426
|
-
label="Hour"
|
|
427
|
-
bind:value={monthlyHour}
|
|
428
|
-
min={0}
|
|
429
|
-
max={23}
|
|
430
|
-
{disabled}
|
|
431
|
-
/>
|
|
432
|
-
<Number
|
|
433
|
-
label="Minute"
|
|
434
|
-
bind:value={monthlyMinute}
|
|
435
|
-
min={0}
|
|
436
|
-
max={59}
|
|
437
|
-
{disabled}
|
|
438
|
-
/>
|
|
382
|
+
<Number label="Day of Month" bind:value={monthlyDay} min={1} max={31} {disabled} />
|
|
383
|
+
<Number label="Hour" bind:value={monthlyHour} min={0} max={23} {disabled} />
|
|
384
|
+
<Number label="Minute" bind:value={monthlyMinute} min={0} max={59} {disabled} />
|
|
439
385
|
{:else if frequency === 'yearly'}
|
|
440
|
-
<Number
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
max={12}
|
|
445
|
-
{disabled}
|
|
446
|
-
/>
|
|
447
|
-
<Number
|
|
448
|
-
label="Day"
|
|
449
|
-
bind:value={yearlyDay}
|
|
450
|
-
min={1}
|
|
451
|
-
max={31}
|
|
452
|
-
{disabled}
|
|
453
|
-
/>
|
|
454
|
-
<Number
|
|
455
|
-
label="Hour"
|
|
456
|
-
bind:value={yearlyHour}
|
|
457
|
-
min={0}
|
|
458
|
-
max={23}
|
|
459
|
-
{disabled}
|
|
460
|
-
/>
|
|
461
|
-
<Number
|
|
462
|
-
label="Minute"
|
|
463
|
-
bind:value={yearlyMinute}
|
|
464
|
-
min={0}
|
|
465
|
-
max={59}
|
|
466
|
-
{disabled}
|
|
467
|
-
/>
|
|
386
|
+
<Number label="Month" bind:value={yearlyMonth} min={1} max={12} {disabled} />
|
|
387
|
+
<Number label="Day" bind:value={yearlyDay} min={1} max={31} {disabled} />
|
|
388
|
+
<Number label="Hour" bind:value={yearlyHour} min={0} max={23} {disabled} />
|
|
389
|
+
<Number label="Minute" bind:value={yearlyMinute} min={0} max={59} {disabled} />
|
|
468
390
|
{:else if frequency === 'custom'}
|
|
469
391
|
<div class="custom-inputs">
|
|
470
392
|
<FormGroup label="Minute">
|
|
@@ -708,4 +630,4 @@
|
|
|
708
630
|
grid-template-columns: 1fr;
|
|
709
631
|
}
|
|
710
632
|
}
|
|
711
|
-
</style>
|
|
633
|
+
</style>
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
import { fade } from 'svelte/transition';
|
|
33
33
|
import dayjs from '../util/dayjs.js';
|
|
34
34
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
35
|
+
import { floating } from '../util/Floating.js';
|
|
35
36
|
import ActionIcon from '../ui/ActionIcon.svelte';
|
|
36
37
|
import { iconChevronLeft, iconChevronRight, iconX } from '../icon/index.js';
|
|
37
38
|
|
|
@@ -204,7 +205,6 @@
|
|
|
204
205
|
let readableDate: string = $state('');
|
|
205
206
|
let showCalendar = $state(false);
|
|
206
207
|
let showYearPicker = $state(false);
|
|
207
|
-
let dropdownPosition: 'above' | 'below' = $state('below');
|
|
208
208
|
|
|
209
209
|
// Year picker: show a range of years centered around the focused year
|
|
210
210
|
const yearRangeSize = 12;
|
|
@@ -241,22 +241,6 @@
|
|
|
241
241
|
showYearPicker = !showYearPicker;
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
function checkDropdownPosition() {
|
|
245
|
-
if (!textboxElement) return;
|
|
246
|
-
|
|
247
|
-
const rect = textboxElement.getBoundingClientRect();
|
|
248
|
-
const dropdownHeight = 300; // Approximate height of the calendar dropdown
|
|
249
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
250
|
-
const spaceAbove = rect.top;
|
|
251
|
-
|
|
252
|
-
// If not enough space below and more space above, position above
|
|
253
|
-
if (spaceBelow < dropdownHeight && spaceAbove > spaceBelow) {
|
|
254
|
-
dropdownPosition = 'above';
|
|
255
|
-
} else {
|
|
256
|
-
dropdownPosition = 'below';
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
244
|
function onClickOutside(event: MouseEvent) {
|
|
261
245
|
if (!showCalendar) return;
|
|
262
246
|
|
|
@@ -315,7 +299,6 @@
|
|
|
315
299
|
bind:textboxElement
|
|
316
300
|
value={readableDate}
|
|
317
301
|
onfocus={() => {
|
|
318
|
-
checkDropdownPosition();
|
|
319
302
|
showCalendar = true;
|
|
320
303
|
}}
|
|
321
304
|
onkeyup={onDateTextChange}
|
|
@@ -339,7 +322,13 @@
|
|
|
339
322
|
{/snippet}
|
|
340
323
|
<div class="date-picker">
|
|
341
324
|
{#if showCalendar}
|
|
342
|
-
|
|
325
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
326
|
+
<div
|
|
327
|
+
class="calendar"
|
|
328
|
+
transition:fade={{ duration: 200 }}
|
|
329
|
+
use:floating={{ anchor: () => textboxElement, placement: 'bottom-start', offset: 4 }}
|
|
330
|
+
use:clickOutside={onClickOutside}
|
|
331
|
+
>
|
|
343
332
|
<div class="month-buttons">
|
|
344
333
|
{#if showYearPicker}
|
|
345
334
|
<ActionIcon
|
|
@@ -426,10 +415,10 @@
|
|
|
426
415
|
line-height: 0;
|
|
427
416
|
}
|
|
428
417
|
|
|
418
|
+
/* Position and top-layer promotion come from use:floating */
|
|
429
419
|
.calendar {
|
|
430
420
|
width: 18rem;
|
|
431
421
|
text-align: center;
|
|
432
|
-
position: absolute;
|
|
433
422
|
z-index: 10;
|
|
434
423
|
user-select: none;
|
|
435
424
|
background-color: var(--paper-body-bg);
|
|
@@ -439,14 +428,6 @@
|
|
|
439
428
|
padding: 0.5rem;
|
|
440
429
|
}
|
|
441
430
|
|
|
442
|
-
.calendar.below {
|
|
443
|
-
top: 0
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
.calendar.above {
|
|
447
|
-
bottom: 2.25rem;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
431
|
.month-buttons {
|
|
451
432
|
display: flex;
|
|
452
433
|
justify-content: space-between;
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
import { fade } from 'svelte/transition';
|
|
27
27
|
import dayjs from '../util/dayjs.js';
|
|
28
28
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
29
|
+
import { floating } from '../util/Floating.js';
|
|
29
30
|
import ActionIcon from '../ui/ActionIcon.svelte';
|
|
30
31
|
import { iconChevronLeft, iconChevronRight, iconX } from '../icon/index.js';
|
|
31
32
|
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
let focusedMonth = $state((selectedStart ?? todayDate).startOf('month'));
|
|
66
67
|
let showCalendar = $state(false);
|
|
67
68
|
let showYearPicker = $state(false);
|
|
68
|
-
let
|
|
69
|
+
let inputWrapElement: HTMLElement | undefined = $state(undefined);
|
|
69
70
|
let containerElement: HTMLElement | undefined = $state(undefined);
|
|
70
71
|
|
|
71
72
|
const yearRangeSize = 12;
|
|
@@ -163,7 +164,15 @@
|
|
|
163
164
|
isInRange = date.isSame(effStart, 'date');
|
|
164
165
|
}
|
|
165
166
|
|
|
166
|
-
displayedDates.push({
|
|
167
|
+
displayedDates.push({
|
|
168
|
+
date,
|
|
169
|
+
text: date.date().toString(),
|
|
170
|
+
color,
|
|
171
|
+
isRangeStart,
|
|
172
|
+
isRangeEnd,
|
|
173
|
+
isInRange,
|
|
174
|
+
isDisabled
|
|
175
|
+
});
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
return displayedDates;
|
|
@@ -242,14 +251,6 @@
|
|
|
242
251
|
focusedMonth = focusedMonth.add(delta, 'month');
|
|
243
252
|
}
|
|
244
253
|
|
|
245
|
-
function checkDropdownPosition() {
|
|
246
|
-
if (!containerElement) return;
|
|
247
|
-
const rect = containerElement.getBoundingClientRect();
|
|
248
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
249
|
-
const spaceAbove = rect.top;
|
|
250
|
-
dropdownPosition = spaceBelow < 340 && spaceAbove > spaceBelow ? 'above' : 'below';
|
|
251
|
-
}
|
|
252
|
-
|
|
253
254
|
function onClickOutside(event: MouseEvent) {
|
|
254
255
|
if (!showCalendar) return;
|
|
255
256
|
const target = event.target as HTMLElement;
|
|
@@ -301,16 +302,15 @@
|
|
|
301
302
|
class:drp-open={showCalendar}
|
|
302
303
|
role="button"
|
|
303
304
|
tabindex={disabled ? -1 : 0}
|
|
305
|
+
bind:this={inputWrapElement}
|
|
304
306
|
onclick={() => {
|
|
305
307
|
if (!disabled) {
|
|
306
|
-
checkDropdownPosition();
|
|
307
308
|
showCalendar = true;
|
|
308
309
|
}
|
|
309
310
|
}}
|
|
310
311
|
onkeydown={(e) => {
|
|
311
312
|
if (!disabled && (e.key === 'Enter' || e.key === ' ')) {
|
|
312
313
|
e.preventDefault();
|
|
313
|
-
checkDropdownPosition();
|
|
314
314
|
showCalendar = true;
|
|
315
315
|
}
|
|
316
316
|
}}
|
|
@@ -321,36 +321,49 @@
|
|
|
321
321
|
|
|
322
322
|
{#if displayText && !disabled}
|
|
323
323
|
<div class="drp-clear">
|
|
324
|
-
<ActionIcon
|
|
325
|
-
variant="secondary-subtle"
|
|
326
|
-
svg={iconX}
|
|
327
|
-
size="0.75rem"
|
|
328
|
-
onclick={clearRange}
|
|
329
|
-
/>
|
|
324
|
+
<ActionIcon variant="secondary-subtle" svg={iconX} size="0.75rem" onclick={clearRange} />
|
|
330
325
|
</div>
|
|
331
326
|
{/if}
|
|
332
327
|
|
|
333
328
|
<div class="drp-calendar-anchor">
|
|
334
329
|
{#if showCalendar}
|
|
330
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
335
331
|
<div
|
|
336
|
-
class="calendar
|
|
332
|
+
class="calendar"
|
|
337
333
|
transition:fade={{ duration: 150 }}
|
|
334
|
+
use:floating={{ anchor: () => inputWrapElement, placement: 'bottom-start', offset: 4 }}
|
|
338
335
|
use:clickOutside={onClickOutside}
|
|
339
336
|
>
|
|
340
337
|
<!-- Month navigation -->
|
|
341
338
|
<div class="month-buttons">
|
|
342
339
|
{#if showYearPicker}
|
|
343
|
-
<ActionIcon
|
|
340
|
+
<ActionIcon
|
|
341
|
+
svg={iconChevronLeft}
|
|
342
|
+
size="1.5rem"
|
|
343
|
+
onclick={() => incrementYearRange(-1)}
|
|
344
|
+
/>
|
|
344
345
|
<button class="month-label clickable" onclick={toggleYearPicker}>
|
|
345
346
|
{yearRangeStart} – {yearRangeStart + yearRangeSize - 1}
|
|
346
347
|
</button>
|
|
347
|
-
<ActionIcon
|
|
348
|
+
<ActionIcon
|
|
349
|
+
svg={iconChevronRight}
|
|
350
|
+
size="1.5rem"
|
|
351
|
+
onclick={() => incrementYearRange(1)}
|
|
352
|
+
/>
|
|
348
353
|
{:else}
|
|
349
|
-
<ActionIcon
|
|
354
|
+
<ActionIcon
|
|
355
|
+
svg={iconChevronLeft}
|
|
356
|
+
size="1.5rem"
|
|
357
|
+
onclick={() => incrementFocusedMonth(-1)}
|
|
358
|
+
/>
|
|
350
359
|
<button class="month-label clickable" onclick={toggleYearPicker}>
|
|
351
360
|
{focusedMonth.format('MMMM YYYY')}
|
|
352
361
|
</button>
|
|
353
|
-
<ActionIcon
|
|
362
|
+
<ActionIcon
|
|
363
|
+
svg={iconChevronRight}
|
|
364
|
+
size="1.5rem"
|
|
365
|
+
onclick={() => incrementFocusedMonth(1)}
|
|
366
|
+
/>
|
|
354
367
|
{/if}
|
|
355
368
|
</div>
|
|
356
369
|
|
|
@@ -383,12 +396,16 @@
|
|
|
383
396
|
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
384
397
|
<div
|
|
385
398
|
class="days-grid"
|
|
386
|
-
onmouseleave={() => {
|
|
399
|
+
onmouseleave={() => {
|
|
400
|
+
if (selectingEnd) hoverDate = undefined;
|
|
401
|
+
}}
|
|
387
402
|
>
|
|
388
403
|
{#each calculateDays(effectiveStart, effectiveEnd, focusedMonth) as d, i (i)}
|
|
389
404
|
<div
|
|
390
405
|
class={buildCellClasses(d)}
|
|
391
|
-
onmouseenter={() => {
|
|
406
|
+
onmouseenter={() => {
|
|
407
|
+
if (selectingEnd && !d.isDisabled) hoverDate = d.date;
|
|
408
|
+
}}
|
|
392
409
|
>
|
|
393
410
|
<button
|
|
394
411
|
class={buildButtonClasses(d)}
|
|
@@ -477,10 +494,10 @@
|
|
|
477
494
|
|
|
478
495
|
/* ---- Calendar ---- */
|
|
479
496
|
|
|
497
|
+
/* Position and top-layer promotion come from use:floating */
|
|
480
498
|
.calendar {
|
|
481
499
|
width: 19rem;
|
|
482
500
|
text-align: center;
|
|
483
|
-
position: absolute;
|
|
484
501
|
z-index: 10;
|
|
485
502
|
background-color: var(--paper-body-bg);
|
|
486
503
|
border: 1px solid var(--border-color);
|
|
@@ -489,15 +506,6 @@
|
|
|
489
506
|
padding: 0.5rem;
|
|
490
507
|
}
|
|
491
508
|
|
|
492
|
-
.calendar.below {
|
|
493
|
-
top: 0.25rem;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
.calendar.above {
|
|
497
|
-
bottom: calc(100% + 0.25rem);
|
|
498
|
-
top: auto;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
509
|
.month-buttons {
|
|
502
510
|
display: flex;
|
|
503
511
|
justify-content: space-between;
|
|
@@ -655,7 +663,9 @@
|
|
|
655
663
|
background: transparent;
|
|
656
664
|
cursor: pointer;
|
|
657
665
|
font-size: 0.875rem;
|
|
658
|
-
transition:
|
|
666
|
+
transition:
|
|
667
|
+
background-color 0.15s ease,
|
|
668
|
+
color 0.15s ease;
|
|
659
669
|
flex-shrink: 0;
|
|
660
670
|
display: flex;
|
|
661
671
|
align-items: center;
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { fade } from 'svelte/transition';
|
|
25
25
|
import dayjs from '../util/dayjs.js';
|
|
26
26
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
27
|
+
import { floating } from '../util/Floating.js';
|
|
27
28
|
import ActionIcon from '../ui/ActionIcon.svelte';
|
|
28
29
|
import { iconChevronLeft, iconChevronRight, iconX } from '../icon/index.js';
|
|
29
30
|
import TimePicker from './TimePicker.svelte';
|
|
@@ -208,7 +209,6 @@
|
|
|
208
209
|
let readableDate: string = $state('');
|
|
209
210
|
let showCalendar = $state(false);
|
|
210
211
|
let showYearPicker = $state(false);
|
|
211
|
-
let dropdownPosition: 'above' | 'below' = $state('below');
|
|
212
212
|
|
|
213
213
|
// Year picker: show a range of years centered around the focused year
|
|
214
214
|
const yearRangeSize = 12;
|
|
@@ -245,22 +245,6 @@
|
|
|
245
245
|
showYearPicker = !showYearPicker;
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
function checkDropdownPosition() {
|
|
249
|
-
if (!textboxElement) return;
|
|
250
|
-
|
|
251
|
-
const rect = textboxElement.getBoundingClientRect();
|
|
252
|
-
const dropdownHeight = 400; // Approximate height of the calendar + time picker dropdown
|
|
253
|
-
const spaceBelow = window.innerHeight - rect.bottom;
|
|
254
|
-
const spaceAbove = rect.top;
|
|
255
|
-
|
|
256
|
-
// If not enough space below and more space above, position above
|
|
257
|
-
if (spaceBelow < dropdownHeight && spaceAbove > spaceBelow) {
|
|
258
|
-
dropdownPosition = 'above';
|
|
259
|
-
} else {
|
|
260
|
-
dropdownPosition = 'below';
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
248
|
function onClickOutside(event: MouseEvent) {
|
|
265
249
|
if (!showCalendar) return;
|
|
266
250
|
|
|
@@ -311,7 +295,6 @@
|
|
|
311
295
|
bind:textboxElement
|
|
312
296
|
value={readableDate}
|
|
313
297
|
onfocus={() => {
|
|
314
|
-
checkDropdownPosition();
|
|
315
298
|
showCalendar = true;
|
|
316
299
|
}}
|
|
317
300
|
onkeyup={onDateTextChange}
|
|
@@ -334,7 +317,13 @@
|
|
|
334
317
|
{/snippet}
|
|
335
318
|
<div class="date-picker">
|
|
336
319
|
{#if showCalendar}
|
|
337
|
-
|
|
320
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
321
|
+
<div
|
|
322
|
+
class="calendar"
|
|
323
|
+
transition:fade={{ duration: 200 }}
|
|
324
|
+
use:floating={{ anchor: () => textboxElement, placement: 'bottom-start', offset: 4 }}
|
|
325
|
+
use:clickOutside={onClickOutside}
|
|
326
|
+
>
|
|
338
327
|
<div class="month-buttons">
|
|
339
328
|
{#if showYearPicker}
|
|
340
329
|
<ActionIcon
|
|
@@ -405,8 +394,8 @@
|
|
|
405
394
|
|
|
406
395
|
<TimePicker
|
|
407
396
|
bind:value={selectedTime}
|
|
408
|
-
|
|
409
|
-
|
|
397
|
+
{minDate}
|
|
398
|
+
{maxDate}
|
|
410
399
|
selectedDate={selectedDate?.format('YYYY-MM-DD')}
|
|
411
400
|
onchange={(t) => {
|
|
412
401
|
selectedTime = t!;
|
|
@@ -439,10 +428,10 @@
|
|
|
439
428
|
line-height: 0;
|
|
440
429
|
}
|
|
441
430
|
|
|
431
|
+
/* Position and top-layer promotion come from use:floating */
|
|
442
432
|
.calendar {
|
|
443
433
|
width: 18rem;
|
|
444
434
|
text-align: center;
|
|
445
|
-
position: absolute;
|
|
446
435
|
z-index: 10;
|
|
447
436
|
user-select: none;
|
|
448
437
|
background-color: var(--paper-body-bg);
|
|
@@ -452,14 +441,6 @@
|
|
|
452
441
|
padding: 0.5rem;
|
|
453
442
|
}
|
|
454
443
|
|
|
455
|
-
.calendar.below {
|
|
456
|
-
top: 0
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
.calendar.above {
|
|
460
|
-
bottom: 2.25rem;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
444
|
.month-buttons {
|
|
464
445
|
display: flex;
|
|
465
446
|
justify-content: space-between;
|
package/dist/form/Number.svelte
CHANGED
|
@@ -108,9 +108,7 @@
|
|
|
108
108
|
children
|
|
109
109
|
}: NumberProps = $props();
|
|
110
110
|
|
|
111
|
-
let resolvedName = $derived(
|
|
112
|
-
(name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_')
|
|
113
|
-
);
|
|
111
|
+
let resolvedName = $derived((name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_'));
|
|
114
112
|
|
|
115
113
|
let id = $derived.by(() => {
|
|
116
114
|
if (inputId) return inputId;
|
|
@@ -52,9 +52,7 @@
|
|
|
52
52
|
}: RadioGroupProps = $props();
|
|
53
53
|
|
|
54
54
|
const autoName = `radio-${crypto.randomUUID()}`;
|
|
55
|
-
const resolvedName = $derived(
|
|
56
|
-
(name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_')
|
|
57
|
-
);
|
|
55
|
+
const resolvedName = $derived((name || label || autoName).replace(/[^a-zA-Z0-9_\-:.]/g, '_'));
|
|
58
56
|
|
|
59
57
|
function handleChange(option: ComboBoxItem) {
|
|
60
58
|
if (option.value === value) return;
|
package/dist/form/Select.svelte
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { clickOutside } from '../util/ClickOutside.js';
|
|
3
|
+
import { floating } from '../util/Floating.js';
|
|
3
4
|
import type {
|
|
4
5
|
ComboBoxGroup,
|
|
5
6
|
ComboBoxItem,
|
|
@@ -209,6 +210,7 @@
|
|
|
209
210
|
}
|
|
210
211
|
|
|
211
212
|
let comboBoxEl: ReturnType<typeof ComboBoxMulti> | undefined = $state(undefined);
|
|
213
|
+
let containerElement: HTMLElement | undefined = $state(undefined);
|
|
212
214
|
let textboxElement: HTMLElement | undefined = $state(undefined);
|
|
213
215
|
let buttonElement: HTMLElement | undefined = $state(undefined);
|
|
214
216
|
let comboBoxKeyDown: ((e: KeyboardEvent) => void) | undefined = $state(undefined);
|
|
@@ -253,7 +255,7 @@
|
|
|
253
255
|
});
|
|
254
256
|
</script>
|
|
255
257
|
|
|
256
|
-
<div class="select-container {containerClass}">
|
|
258
|
+
<div class="select-container {containerClass}" bind:this={containerElement}>
|
|
257
259
|
<FormGroup {label} {required} {tooltipContent} {tooltipText} {tooltipLocation}>
|
|
258
260
|
{#if computedAllowSearch && open}
|
|
259
261
|
<div class="select-input-wrapper">
|
|
@@ -375,26 +377,28 @@
|
|
|
375
377
|
</button>
|
|
376
378
|
{/if}
|
|
377
379
|
</FormGroup>
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
<
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
380
|
+
{#if open}
|
|
381
|
+
<!-- Rendered in the top layer so a scrolling Dialog body cannot clip it -->
|
|
382
|
+
<div
|
|
383
|
+
class="select-panel"
|
|
384
|
+
use:floating={{ anchor: () => containerElement, placement: 'bottom-start', matchWidth: true }}
|
|
385
|
+
>
|
|
386
|
+
<div class="select-panel-inner" use:clickOutside={closePopover}>
|
|
387
|
+
<ComboBoxMulti
|
|
388
|
+
bind:this={comboBoxEl}
|
|
389
|
+
{filterString}
|
|
390
|
+
values={rawValue ? [rawValue] : []}
|
|
391
|
+
{onSelection}
|
|
392
|
+
onkeydown={comboBoxKeyDown}
|
|
393
|
+
groupedOptions={core.filteredGroups}
|
|
394
|
+
{open}
|
|
395
|
+
loading={core.searching}
|
|
396
|
+
{hideNoResults}
|
|
397
|
+
{loadingText}
|
|
398
|
+
/>
|
|
399
|
+
</div>
|
|
396
400
|
</div>
|
|
397
|
-
|
|
401
|
+
{/if}
|
|
398
402
|
{#if showError && errorText}
|
|
399
403
|
<div class="text-error text-xs">{errorText}</div>
|
|
400
404
|
{/if}
|
|
@@ -473,14 +477,11 @@
|
|
|
473
477
|
right: 0.4rem;
|
|
474
478
|
}
|
|
475
479
|
|
|
480
|
+
/* Position, width and top-layer promotion come from use:floating */
|
|
476
481
|
.select-panel {
|
|
477
|
-
position: absolute;
|
|
478
|
-
width: 100%;
|
|
479
|
-
left: 0;
|
|
480
482
|
z-index: 70;
|
|
481
483
|
border-top-left-radius: 0;
|
|
482
484
|
border-top-right-radius: 0;
|
|
483
|
-
/* absolute w-full left-0 z-20 */
|
|
484
485
|
}
|
|
485
486
|
|
|
486
487
|
.select-panel-inner {
|
|
@@ -493,10 +494,6 @@
|
|
|
493
494
|
/* text-zinc-400 dark:text-neutral-500 */
|
|
494
495
|
}
|
|
495
496
|
|
|
496
|
-
.hidden {
|
|
497
|
-
display: none;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
497
|
.disabled {
|
|
501
498
|
opacity: 0.5;
|
|
502
499
|
cursor: not-allowed;
|