noph-ui 0.44.0 → 0.45.1
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/README.md +10 -1
- package/dist/animation.d.ts +2 -0
- package/dist/animation.js +33 -0
- package/dist/app-bar/AppBar.svelte +230 -0
- package/dist/app-bar/AppBar.svelte.d.ts +4 -0
- package/dist/app-bar/index.d.ts +1 -0
- package/dist/app-bar/index.js +1 -0
- package/dist/app-bar/types.d.ts +13 -0
- package/dist/app-bar/types.js +1 -0
- package/dist/autocomplete/AutoComplete.svelte +10 -11
- package/dist/autocomplete/AutoComplete.svelte.d.ts +1 -1
- package/dist/autocomplete/types.d.ts +1 -1
- package/dist/badge/Badge.svelte +6 -1
- package/dist/badge/types.d.ts +0 -1
- package/dist/button/Button.svelte +5 -15
- package/dist/button/IconButton.svelte +5 -15
- package/dist/button/SegmentedButton.svelte +15 -1
- package/dist/button/SplitButton.svelte +75 -0
- package/dist/button/SplitButton.svelte.d.ts +4 -0
- package/dist/button/index.d.ts +1 -0
- package/dist/button/index.js +1 -0
- package/dist/button/types.d.ts +17 -4
- package/dist/card/types.d.ts +1 -1
- package/dist/checkbox/Checkbox.svelte +47 -58
- package/dist/chip/AssistChip.svelte +5 -5
- package/dist/chip/ChipSet.svelte +3 -11
- package/dist/chip/FilterChip.svelte +33 -27
- package/dist/chip/InputChip.svelte +13 -2
- package/dist/chip/SuggestionChip.svelte +29 -0
- package/dist/chip/SuggestionChip.svelte.d.ts +4 -0
- package/dist/chip/index.d.ts +1 -0
- package/dist/chip/index.js +1 -0
- package/dist/chip/types.d.ts +16 -9
- package/dist/date-picker/Calendar.svelte +1 -1
- package/dist/date-picker/DatePickerDialog.svelte +23 -11
- package/dist/date-picker/DatePickerDialog.svelte.d.ts +4 -1
- package/dist/date-picker/DateRangePicker.svelte +40 -10
- package/dist/date-picker/DateRangePicker.svelte.d.ts +4 -1
- package/dist/date-picker/DockedDatePicker.svelte +13 -10
- package/dist/date-picker/DockedDatePicker.svelte.d.ts +4 -1
- package/dist/date-picker/DockedDateTimePicker.svelte +13 -7
- package/dist/date-picker/DockedDateTimePicker.svelte.d.ts +4 -1
- package/dist/date-picker/SelectionList.svelte +6 -32
- package/dist/date-picker/SelectionList.svelte.d.ts +2 -12
- package/dist/date-picker/TimeColumn.svelte +4 -29
- package/dist/date-picker/exitVisibility.svelte.d.ts +5 -0
- package/dist/date-picker/exitVisibility.svelte.js +23 -0
- package/dist/date-picker/optionList.d.ts +4 -0
- package/dist/date-picker/optionList.js +31 -0
- package/dist/date-picker/types.d.ts +11 -4
- package/dist/dialog/Dialog.svelte +55 -68
- package/dist/dialog/Dialog.svelte.d.ts +3 -3
- package/dist/dialog/types.d.ts +4 -3
- package/dist/fab/ExtendedFab.svelte +255 -0
- package/dist/fab/ExtendedFab.svelte.d.ts +5 -0
- package/dist/fab/Fab.svelte +211 -0
- package/dist/fab/Fab.svelte.d.ts +5 -0
- package/dist/fab/FabMenu.svelte +207 -0
- package/dist/fab/FabMenu.svelte.d.ts +7 -0
- package/dist/fab/index.d.ts +3 -0
- package/dist/fab/index.js +3 -0
- package/dist/fab/types.d.ts +34 -0
- package/dist/fab/types.js +1 -0
- package/dist/icons/ArrowBackIcon.svelte +13 -0
- package/dist/icons/ArrowBackIcon.svelte.d.ts +7 -0
- package/dist/icons/ChevronDownIcon.svelte +3 -0
- package/dist/icons/ChevronDownIcon.svelte.d.ts +26 -0
- package/dist/icons/SearchIcon.svelte +15 -0
- package/dist/icons/SearchIcon.svelte.d.ts +7 -0
- package/dist/icons/index.d.ts +3 -0
- package/dist/icons/index.js +3 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/internal/focus-ring.css +12 -0
- package/dist/loading-indicator/shapes.js +0 -7
- package/dist/menu/Menu.svelte +12 -7
- package/dist/menu/Menu.svelte.d.ts +2 -2
- package/dist/menu/types.d.ts +0 -2
- package/dist/navigation-bar/NavigationBar.svelte +59 -0
- package/dist/navigation-bar/NavigationBar.svelte.d.ts +4 -0
- package/dist/navigation-bar/NavigationBarItem.svelte +239 -0
- package/dist/navigation-bar/NavigationBarItem.svelte.d.ts +5 -0
- package/dist/navigation-bar/index.d.ts +2 -0
- package/dist/navigation-bar/index.js +2 -0
- package/dist/navigation-bar/types.d.ts +19 -0
- package/dist/navigation-bar/types.js +1 -0
- package/dist/navigation-drawer/NavigationDrawer.svelte +107 -76
- package/dist/navigation-drawer/NavigationDrawer.svelte.d.ts +4 -1
- package/dist/navigation-drawer/NavigationDrawerItem.svelte +10 -3
- package/dist/navigation-drawer/types.d.ts +3 -1
- package/dist/navigation-rail/NavigationRailItem.svelte +16 -0
- package/dist/navigation-rail/types.d.ts +3 -0
- package/dist/popover.svelte.d.ts +5 -0
- package/dist/popover.svelte.js +22 -0
- package/dist/press.svelte.d.ts +6 -0
- package/dist/press.svelte.js +32 -0
- package/dist/radio/Radio.svelte +26 -7
- package/dist/radio/types.d.ts +3 -0
- package/dist/search/Search.svelte +391 -0
- package/dist/search/Search.svelte.d.ts +5 -0
- package/dist/search/index.d.ts +1 -0
- package/dist/search/index.js +1 -0
- package/dist/search/types.d.ts +19 -0
- package/dist/search/types.js +1 -0
- package/dist/select/Select.svelte +48 -87
- package/dist/sheet/Sheet.svelte +235 -0
- package/dist/sheet/Sheet.svelte.d.ts +7 -0
- package/dist/sheet/index.d.ts +1 -0
- package/dist/sheet/index.js +1 -0
- package/dist/sheet/types.d.ts +11 -0
- package/dist/sheet/types.js +1 -0
- package/dist/slider/Slider.svelte +118 -30
- package/dist/slider/types.d.ts +3 -0
- package/dist/snackbar/Snackbar.svelte +32 -35
- package/dist/snackbar/Snackbar.svelte.d.ts +2 -2
- package/dist/snackbar/types.d.ts +3 -2
- package/dist/switch/Switch.svelte +51 -20
- package/dist/switch/types.d.ts +3 -0
- package/dist/tabs/Tab.svelte +4 -12
- package/dist/tabs/Tabs.svelte +5 -5
- package/dist/text-field/TextField.svelte +2 -4
- package/dist/toolbar/Toolbar.svelte +121 -0
- package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
- package/dist/toolbar/index.d.ts +1 -0
- package/dist/toolbar/index.js +1 -0
- package/dist/toolbar/types.d.ts +8 -0
- package/dist/toolbar/types.js +1 -0
- package/dist/tooltip/RichTooltip.svelte +18 -12
- package/dist/tooltip/RichTooltip.svelte.d.ts +2 -2
- package/dist/tooltip/Tooltip.svelte +22 -11
- package/dist/tooltip/Tooltip.svelte.d.ts +4 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.js +6 -0
- package/package.json +13 -13
- package/dist/date-picker/enterAnimation.d.ts +0 -1
- package/dist/date-picker/enterAnimation.js +0 -10
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { afterTwoFrames } from '../animation.js'
|
|
2
3
|
import Button from '../button/Button.svelte'
|
|
3
4
|
import IconButton from '../button/IconButton.svelte'
|
|
4
5
|
import Dialog from '../dialog/Dialog.svelte'
|
|
6
|
+
import { syncOpenEffect } from '../popover.svelte.js'
|
|
5
7
|
import Divider from '../divider/Divider.svelte'
|
|
8
|
+
import { exitVisibility } from './exitVisibility.svelte.js'
|
|
6
9
|
import ArrowDropDownIcon from '../icons/ArrowDropDownIcon.svelte'
|
|
7
10
|
import CalendarToday from '../icons/CalendarToday.svelte'
|
|
8
11
|
import ChevronLeftIcon from '../icons/ChevronLeftIcon.svelte'
|
|
@@ -29,7 +32,6 @@
|
|
|
29
32
|
toISODate,
|
|
30
33
|
today as getToday,
|
|
31
34
|
} from './dateUtils.js'
|
|
32
|
-
import { afterTwoFrames } from './enterAnimation.js'
|
|
33
35
|
import type { DatePickerDialogProps, ISODate } from './types.js'
|
|
34
36
|
|
|
35
37
|
let {
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
headline,
|
|
49
51
|
label = 'Date',
|
|
50
52
|
supportingText,
|
|
53
|
+
issues,
|
|
51
54
|
name,
|
|
52
55
|
form,
|
|
53
56
|
modeToggle = false,
|
|
@@ -77,6 +80,8 @@
|
|
|
77
80
|
let confirming = false
|
|
78
81
|
let monthBeforeOpen: ISODate | undefined
|
|
79
82
|
|
|
83
|
+
const exit = exitVisibility()
|
|
84
|
+
|
|
80
85
|
let todayValue = $derived(getToday())
|
|
81
86
|
let week = $derived(firstDayOfWeek ?? getFirstDayOfWeek(locale))
|
|
82
87
|
let minDate = $derived(parseISODate(min))
|
|
@@ -125,12 +130,20 @@
|
|
|
125
130
|
cancelYearEnter = afterTwoFrames(() => (yearEnter = false))
|
|
126
131
|
}
|
|
127
132
|
|
|
128
|
-
const
|
|
133
|
+
export const show = () => {
|
|
134
|
+
if (element && !element.open) element.showModal()
|
|
135
|
+
}
|
|
129
136
|
|
|
130
|
-
|
|
131
|
-
if (open
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
export const close = () => {
|
|
138
|
+
if (element?.open) element.close()
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
syncOpenEffect(
|
|
142
|
+
() => element,
|
|
143
|
+
() => open,
|
|
144
|
+
show,
|
|
145
|
+
close,
|
|
146
|
+
)
|
|
134
147
|
|
|
135
148
|
const setMonth = (date: Date) => {
|
|
136
149
|
displayMonth = toISODate(startOfMonth(date))
|
|
@@ -197,6 +210,7 @@
|
|
|
197
210
|
const nowOpen = event.newState === 'open'
|
|
198
211
|
open = nowOpen
|
|
199
212
|
if (nowOpen) {
|
|
213
|
+
exit.show()
|
|
200
214
|
monthBeforeOpen = displayMonth
|
|
201
215
|
confirming = false
|
|
202
216
|
pending = value ?? undefined
|
|
@@ -206,14 +220,14 @@
|
|
|
206
220
|
syncText()
|
|
207
221
|
focusCalendarWhenReady()
|
|
208
222
|
} else {
|
|
209
|
-
displayMonth = monthBeforeOpen
|
|
210
223
|
if (!confirming) oncancel?.()
|
|
211
224
|
confirming = false
|
|
225
|
+
exit.scheduleExit(element, () => (displayMonth = monthBeforeOpen))
|
|
212
226
|
}
|
|
213
227
|
}}
|
|
214
228
|
>
|
|
215
229
|
<input class="np-date-picker-dialog-value" type="hidden" value={value ?? ''} {name} {form} />
|
|
216
|
-
{#if
|
|
230
|
+
{#if exit.visible}
|
|
217
231
|
<div class="np-date-picker-dialog-content">
|
|
218
232
|
<div class="np-date-picker-dialog-header">
|
|
219
233
|
<div class="np-date-picker-dialog-header-text">
|
|
@@ -225,9 +239,6 @@
|
|
|
225
239
|
type="button"
|
|
226
240
|
aria-label={mode === 'calendar' ? inputModeLabel : calendarModeLabel}
|
|
227
241
|
onclick={() => {
|
|
228
|
-
// The calendar moves `pending` on without touching the field, so the text has to
|
|
229
|
-
// catch up before it is shown again. Otherwise the field contradicts the headline
|
|
230
|
-
// and OK confirms a date the user never saw there.
|
|
231
242
|
if (mode === 'calendar') syncText()
|
|
232
243
|
setMode(mode === 'calendar' ? 'input' : 'calendar')
|
|
233
244
|
showYearPicker(false)
|
|
@@ -247,6 +258,7 @@
|
|
|
247
258
|
<div class={['np-date-picker-dialog-input', modeEnter && modeEnter]}>
|
|
248
259
|
<TextField
|
|
249
260
|
{label}
|
|
261
|
+
{issues}
|
|
250
262
|
supportingText={supportingText ?? pattern}
|
|
251
263
|
value={text}
|
|
252
264
|
aria-invalid={inputInvalid ? 'true' : undefined}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { DatePickerDialogProps } from './types.ts';
|
|
2
|
-
declare const DatePickerDialog: import("svelte").Component<DatePickerDialogProps, {
|
|
2
|
+
declare const DatePickerDialog: import("svelte").Component<DatePickerDialogProps, {
|
|
3
|
+
show: () => void;
|
|
4
|
+
close: () => void;
|
|
5
|
+
}, "element" | "value" | "open" | "displayMonth">;
|
|
3
6
|
type DatePickerDialog = ReturnType<typeof DatePickerDialog>;
|
|
4
7
|
export default DatePickerDialog;
|
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
import Dialog from '../dialog/Dialog.svelte'
|
|
5
5
|
import Divider from '../divider/Divider.svelte'
|
|
6
6
|
import CloseIcon from '../icons/CloseIcon.svelte'
|
|
7
|
+
import { syncOpenEffect } from '../popover.svelte.js'
|
|
7
8
|
import { tick } from 'svelte'
|
|
8
9
|
import Calendar from './Calendar.svelte'
|
|
10
|
+
import { exitVisibility } from './exitVisibility.svelte.js'
|
|
9
11
|
import {
|
|
10
12
|
clampDate,
|
|
11
13
|
compareDays,
|
|
@@ -34,6 +36,10 @@
|
|
|
34
36
|
isDateEnabled,
|
|
35
37
|
adjacentMonthDays = false,
|
|
36
38
|
title = 'Select range',
|
|
39
|
+
headline,
|
|
40
|
+
name,
|
|
41
|
+
endName,
|
|
42
|
+
form,
|
|
37
43
|
startLabel = 'Start date',
|
|
38
44
|
endLabel = 'End date',
|
|
39
45
|
cancelLabel = 'Cancel',
|
|
@@ -52,6 +58,8 @@
|
|
|
52
58
|
let focusedDay = $state<Date | undefined>(undefined)
|
|
53
59
|
let confirming = false
|
|
54
60
|
|
|
61
|
+
const exit = exitVisibility()
|
|
62
|
+
|
|
55
63
|
let todayValue = $derived(getToday())
|
|
56
64
|
let week = $derived(firstDayOfWeek ?? getFirstDayOfWeek(locale))
|
|
57
65
|
let minDate = $derived(parseISODate(min))
|
|
@@ -108,12 +116,20 @@
|
|
|
108
116
|
if (target && scroller) scroller.scrollTop = target.offsetTop
|
|
109
117
|
}
|
|
110
118
|
|
|
111
|
-
const
|
|
119
|
+
export const show = () => {
|
|
120
|
+
if (element && !element.open) element.showModal()
|
|
121
|
+
}
|
|
112
122
|
|
|
113
|
-
|
|
114
|
-
if (open
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
export const close = () => {
|
|
124
|
+
if (element?.open) element.close()
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
syncOpenEffect(
|
|
128
|
+
() => element,
|
|
129
|
+
() => open,
|
|
130
|
+
show,
|
|
131
|
+
close,
|
|
132
|
+
)
|
|
117
133
|
|
|
118
134
|
let prepending = false
|
|
119
135
|
|
|
@@ -176,6 +192,7 @@
|
|
|
176
192
|
const nowOpen = event.newState === 'open'
|
|
177
193
|
open = nowOpen
|
|
178
194
|
if (nowOpen) {
|
|
195
|
+
exit.show()
|
|
179
196
|
confirming = false
|
|
180
197
|
pending = { ...value }
|
|
181
198
|
focusedDay = undefined
|
|
@@ -184,10 +201,19 @@
|
|
|
184
201
|
} else {
|
|
185
202
|
if (!confirming) oncancel?.()
|
|
186
203
|
confirming = false
|
|
204
|
+
exit.scheduleExit(element)
|
|
187
205
|
}
|
|
188
206
|
}}
|
|
189
207
|
>
|
|
190
|
-
{
|
|
208
|
+
<input class="np-date-range-picker-value" type="hidden" value={value.start ?? ''} {name} {form} />
|
|
209
|
+
<input
|
|
210
|
+
class="np-date-range-picker-value"
|
|
211
|
+
type="hidden"
|
|
212
|
+
value={value.end ?? ''}
|
|
213
|
+
name={endName}
|
|
214
|
+
{form}
|
|
215
|
+
/>
|
|
216
|
+
{#if exit.visible}
|
|
191
217
|
<div class="np-date-range-picker-content">
|
|
192
218
|
<div class="np-date-range-picker-header">
|
|
193
219
|
<div class="np-date-range-picker-top-bar">
|
|
@@ -201,9 +227,13 @@
|
|
|
201
227
|
<div class="np-date-range-picker-header-text">
|
|
202
228
|
<span class="np-date-range-picker-title">{title}</span>
|
|
203
229
|
<h2 class="np-date-range-picker-headline">
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
230
|
+
{#if headline}
|
|
231
|
+
<span>{headline}</span>
|
|
232
|
+
{:else}
|
|
233
|
+
<span class={[!startDate && 'placeholder']}>{headlineStart}</span>
|
|
234
|
+
<span aria-hidden="true">–</span>
|
|
235
|
+
<span class={[!endDate && 'placeholder']}>{headlineEnd}</span>
|
|
236
|
+
{/if}
|
|
207
237
|
</h2>
|
|
208
238
|
</div>
|
|
209
239
|
</div>
|
|
@@ -248,7 +278,7 @@
|
|
|
248
278
|
{/if}
|
|
249
279
|
|
|
250
280
|
{#snippet actions()}
|
|
251
|
-
{#if
|
|
281
|
+
{#if exit.visible}
|
|
252
282
|
<Button type="button" variant="text" onclick={cancel}>{cancelLabel}</Button>
|
|
253
283
|
<Button type="button" variant="text" disabled={!canConfirm} onclick={confirm}>
|
|
254
284
|
{confirmLabel}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { DateRangePickerProps } from './types.ts';
|
|
2
|
-
declare const DateRangePicker: import("svelte").Component<DateRangePickerProps, {
|
|
2
|
+
declare const DateRangePicker: import("svelte").Component<DateRangePickerProps, {
|
|
3
|
+
show: () => void;
|
|
4
|
+
close: () => void;
|
|
5
|
+
}, "element" | "value" | "open">;
|
|
3
6
|
type DateRangePicker = ReturnType<typeof DateRangePicker>;
|
|
4
7
|
export default DateRangePicker;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import CalendarToday from '../icons/CalendarToday.svelte'
|
|
6
6
|
import Menu from '../menu/Menu.svelte'
|
|
7
7
|
import { onFormReset } from '../form-reset.js'
|
|
8
|
+
import { syncOpenEffect } from '../popover.svelte.js'
|
|
8
9
|
import TextField from '../text-field/TextField.svelte'
|
|
9
10
|
import { onMount, tick } from 'svelte'
|
|
10
11
|
import Calendar from './Calendar.svelte'
|
|
@@ -34,7 +35,6 @@
|
|
|
34
35
|
let {
|
|
35
36
|
value = $bindable(),
|
|
36
37
|
defaultValue,
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- absorbed on purpose
|
|
38
38
|
type,
|
|
39
39
|
'aria-invalid': ariaInvalid,
|
|
40
40
|
style,
|
|
@@ -214,10 +214,18 @@
|
|
|
214
214
|
focusCalendar()
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
export const show = () => openPicker()
|
|
218
|
+
|
|
219
|
+
export const close = () => {
|
|
220
|
+
if (isShowing()) menuElement?.hidePopover()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
syncOpenEffect(
|
|
224
|
+
() => menuElement,
|
|
225
|
+
() => open,
|
|
226
|
+
show,
|
|
227
|
+
close,
|
|
228
|
+
)
|
|
221
229
|
|
|
222
230
|
const focusCalendar = () => {
|
|
223
231
|
menuElement?.querySelector<HTMLElement>('.np-calendar-day[tabindex="0"]')?.focus()
|
|
@@ -255,7 +263,6 @@
|
|
|
255
263
|
const parsed = usableDate(next)
|
|
256
264
|
commit(parsed ? toISODate(parsed) : undefined)
|
|
257
265
|
if (parsed) setMonth(parsed)
|
|
258
|
-
// Recorded after the commit, so that it is remembered against the value it just produced.
|
|
259
266
|
typed = { source: current, text: next }
|
|
260
267
|
invalidText = undefined
|
|
261
268
|
}
|
|
@@ -267,8 +274,6 @@
|
|
|
267
274
|
}
|
|
268
275
|
const parsed = usableDate(text)
|
|
269
276
|
invalidText = parsed ? undefined : text
|
|
270
|
-
// Leaving the field tidies a loose entry: dropping what was typed falls back to the
|
|
271
|
-
// canonical formatting of the value it produced.
|
|
272
277
|
if (parsed) typed = undefined
|
|
273
278
|
}
|
|
274
279
|
|
|
@@ -285,8 +290,6 @@
|
|
|
285
290
|
}
|
|
286
291
|
|
|
287
292
|
const chooseYear = (year: number) => {
|
|
288
|
-
// A year is offered as soon as any of its days is in range, so keeping the month the list was
|
|
289
|
-
// opened from can land on a month where nothing at all is selectable.
|
|
290
293
|
setMonth(new Date(year, clampMonthInYear(year, monthDate.getMonth(), minDate, maxDate), 1))
|
|
291
294
|
leaveList()
|
|
292
295
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { DockedDatePickerProps } from './types.ts';
|
|
2
|
-
declare const DockedDatePicker: import("svelte").Component<DockedDatePickerProps, {
|
|
2
|
+
declare const DockedDatePicker: import("svelte").Component<DockedDatePickerProps, {
|
|
3
|
+
show: () => void;
|
|
4
|
+
close: () => void;
|
|
5
|
+
}, "element" | "value" | "open" | "displayMonth">;
|
|
3
6
|
type DockedDatePicker = ReturnType<typeof DockedDatePicker>;
|
|
4
7
|
export default DockedDatePicker;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import CalendarToday from '../icons/CalendarToday.svelte'
|
|
6
6
|
import Menu from '../menu/Menu.svelte'
|
|
7
7
|
import { onFormReset } from '../form-reset.js'
|
|
8
|
+
import { syncOpenEffect } from '../popover.svelte.js'
|
|
8
9
|
import TextField from '../text-field/TextField.svelte'
|
|
9
10
|
import { onMount, tick } from 'svelte'
|
|
10
11
|
import Calendar from './Calendar.svelte'
|
|
@@ -48,7 +49,6 @@
|
|
|
48
49
|
let {
|
|
49
50
|
value = $bindable(),
|
|
50
51
|
defaultValue,
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- absorbed on purpose
|
|
52
52
|
type,
|
|
53
53
|
'aria-invalid': ariaInvalid,
|
|
54
54
|
style,
|
|
@@ -118,8 +118,6 @@
|
|
|
118
118
|
let week = $derived(firstDayOfWeek ?? getFirstDayOfWeek(locale))
|
|
119
119
|
let minDate = $derived(parseISODateTime(min))
|
|
120
120
|
let maxDate = $derived(parseISODateTime(max, MINUTES_IN_DAY - 1))
|
|
121
|
-
// `as('datetime-local')` types its value as `string | number` and carries the last submission in
|
|
122
|
-
// `defaultValue`, so both are funnelled into one ISO string the rest of the component reads.
|
|
123
121
|
let current = $derived<string | undefined>(
|
|
124
122
|
typeof value === 'string' ? value : typeof defaultValue === 'string' ? defaultValue : undefined,
|
|
125
123
|
)
|
|
@@ -297,10 +295,18 @@
|
|
|
297
295
|
focusCalendar()
|
|
298
296
|
}
|
|
299
297
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
298
|
+
export const show = () => openPicker()
|
|
299
|
+
|
|
300
|
+
export const close = () => {
|
|
301
|
+
if (isShowing()) menuElement?.hidePopover()
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
syncOpenEffect(
|
|
305
|
+
() => menuElement,
|
|
306
|
+
() => open,
|
|
307
|
+
show,
|
|
308
|
+
close,
|
|
309
|
+
)
|
|
304
310
|
|
|
305
311
|
const focusCalendar = () => {
|
|
306
312
|
menuElement?.querySelector<HTMLElement>('.np-calendar-day[tabindex="0"]')?.focus()
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { DockedDateTimePickerProps } from './types.ts';
|
|
2
|
-
declare const DockedDateTimePicker: import("svelte").Component<DockedDateTimePickerProps, {
|
|
2
|
+
declare const DockedDateTimePicker: import("svelte").Component<DockedDateTimePickerProps, {
|
|
3
|
+
show: () => void;
|
|
4
|
+
close: () => void;
|
|
5
|
+
}, "element" | "value" | "open" | "displayMonth">;
|
|
3
6
|
type DockedDateTimePicker = ReturnType<typeof DockedDateTimePicker>;
|
|
4
7
|
export default DockedDateTimePicker;
|
|
@@ -2,41 +2,15 @@
|
|
|
2
2
|
import CheckIcon from '../icons/CheckIcon.svelte'
|
|
3
3
|
import { arrowKeyNav } from '../keyboard-nav.js'
|
|
4
4
|
import Ripple from '../ripple/Ripple.svelte'
|
|
5
|
-
import
|
|
6
|
-
import type {
|
|
5
|
+
import { revealSelected, tabStop } from './optionList.js'
|
|
6
|
+
import type { TimeColumnProps } from './types.js'
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
value: number
|
|
10
|
-
label: string
|
|
11
|
-
disabled?: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
interface SelectionListProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> {
|
|
15
|
-
options: SelectionOption[]
|
|
16
|
-
value?: number
|
|
17
|
-
onselect?: (value: number) => void
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let { options, value, onselect, ...attributes }: SelectionListProps = $props()
|
|
8
|
+
let { options, value, onselect, ...attributes }: TimeColumnProps = $props()
|
|
21
9
|
|
|
22
10
|
const handleKeydown = arrowKeyNav('[role="option"]')
|
|
11
|
+
const reveal = revealSelected(true)
|
|
23
12
|
|
|
24
|
-
let tabStopValue = $derived
|
|
25
|
-
if (options.some((option) => option.value === value)) return value
|
|
26
|
-
const offered = options.filter((option) => !option.disabled)
|
|
27
|
-
const pool = offered.length ? offered : options
|
|
28
|
-
if (!pool.length) return undefined
|
|
29
|
-
if (value === undefined) return pool[0].value
|
|
30
|
-
return pool.reduce((nearest, option) =>
|
|
31
|
-
Math.abs(option.value - value) < Math.abs(nearest.value - value) ? option : nearest,
|
|
32
|
-
).value
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
const centerInList: Attachment<HTMLElement> = (element) => {
|
|
36
|
-
const list = element.closest<HTMLElement>('.np-date-picker-selection-list')
|
|
37
|
-
if (!list) return
|
|
38
|
-
list.scrollTop = element.offsetTop - list.clientHeight / 2 + element.offsetHeight / 2
|
|
39
|
-
}
|
|
13
|
+
let tabStopValue = $derived(tabStop(options, value))
|
|
40
14
|
</script>
|
|
41
15
|
|
|
42
16
|
<div
|
|
@@ -49,7 +23,7 @@
|
|
|
49
23
|
{#each options as option (option.value)}
|
|
50
24
|
{@const selected = option.value === value}
|
|
51
25
|
<button
|
|
52
|
-
{@attach selected &&
|
|
26
|
+
{@attach selected && reveal}
|
|
53
27
|
type="button"
|
|
54
28
|
role="option"
|
|
55
29
|
aria-selected={selected}
|
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
value: number;
|
|
4
|
-
label: string;
|
|
5
|
-
disabled?: boolean;
|
|
6
|
-
}
|
|
7
|
-
interface SelectionListProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> {
|
|
8
|
-
options: SelectionOption[];
|
|
9
|
-
value?: number;
|
|
10
|
-
onselect?: (value: number) => void;
|
|
11
|
-
}
|
|
12
|
-
declare const SelectionList: import("svelte").Component<SelectionListProps, {}, "">;
|
|
1
|
+
import type { TimeColumnProps } from './types.ts';
|
|
2
|
+
declare const SelectionList: import("svelte").Component<TimeColumnProps, {}, "">;
|
|
13
3
|
type SelectionList = ReturnType<typeof SelectionList>;
|
|
14
4
|
export default SelectionList;
|
|
@@ -1,40 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { arrowKeyNav } from '../keyboard-nav.js'
|
|
3
3
|
import Ripple from '../ripple/Ripple.svelte'
|
|
4
|
-
import
|
|
4
|
+
import { revealSelected, tabStop } from './optionList.js'
|
|
5
5
|
import type { TimeColumnProps } from './types.js'
|
|
6
6
|
|
|
7
7
|
let { options, value, onselect, ...attributes }: TimeColumnProps = $props()
|
|
8
8
|
|
|
9
9
|
const handleKeydown = arrowKeyNav('[role="option"]')
|
|
10
|
+
const reveal = revealSelected()
|
|
10
11
|
|
|
11
|
-
let tabStopValue = $derived
|
|
12
|
-
if (options.some((option) => option.value === value)) return value
|
|
13
|
-
const offered = options.filter((option) => !option.disabled)
|
|
14
|
-
const pool = offered.length ? offered : options
|
|
15
|
-
if (!pool.length) return undefined
|
|
16
|
-
if (value === undefined) return pool[0].value
|
|
17
|
-
return pool.reduce((nearest, option) =>
|
|
18
|
-
Math.abs(option.value - value) < Math.abs(nearest.value - value) ? option : nearest,
|
|
19
|
-
).value
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
let centred = false
|
|
23
|
-
|
|
24
|
-
const revealSelected: Attachment<HTMLElement> = (element) => {
|
|
25
|
-
const column = element.parentElement
|
|
26
|
-
if (!column) return
|
|
27
|
-
const top = element.offsetTop
|
|
28
|
-
const bottom = top + element.offsetHeight
|
|
29
|
-
if (!centred) {
|
|
30
|
-
centred = true
|
|
31
|
-
column.scrollTop = top - column.clientHeight / 2 + element.offsetHeight / 2
|
|
32
|
-
} else if (top < column.scrollTop) {
|
|
33
|
-
column.scrollTop = top
|
|
34
|
-
} else if (bottom > column.scrollTop + column.clientHeight) {
|
|
35
|
-
column.scrollTop = bottom - column.clientHeight
|
|
36
|
-
}
|
|
37
|
-
}
|
|
12
|
+
let tabStopValue = $derived(tabStop(options, value))
|
|
38
13
|
</script>
|
|
39
14
|
|
|
40
15
|
<div
|
|
@@ -47,7 +22,7 @@
|
|
|
47
22
|
{#each options as option (option.value)}
|
|
48
23
|
{@const selected = option.value === value}
|
|
49
24
|
<button
|
|
50
|
-
{@attach selected &&
|
|
25
|
+
{@attach selected && reveal}
|
|
51
26
|
type="button"
|
|
52
27
|
role="option"
|
|
53
28
|
aria-selected={selected}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { afterExit } from '../animation.js';
|
|
2
|
+
export const exitVisibility = () => {
|
|
3
|
+
let visible = $state(false);
|
|
4
|
+
let cancelExit;
|
|
5
|
+
$effect(() => () => cancelExit?.());
|
|
6
|
+
return {
|
|
7
|
+
get visible() {
|
|
8
|
+
return visible;
|
|
9
|
+
},
|
|
10
|
+
show: () => {
|
|
11
|
+
cancelExit?.();
|
|
12
|
+
cancelExit = undefined;
|
|
13
|
+
visible = true;
|
|
14
|
+
},
|
|
15
|
+
scheduleExit: (element, onDone) => {
|
|
16
|
+
cancelExit = afterExit(element, () => {
|
|
17
|
+
visible = false;
|
|
18
|
+
onDone?.();
|
|
19
|
+
cancelExit = undefined;
|
|
20
|
+
});
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
import type { TimeOption } from './types.ts';
|
|
3
|
+
export declare const tabStop: (options: TimeOption[], value: number | undefined) => number | undefined;
|
|
4
|
+
export declare const revealSelected: (centre?: boolean) => Attachment<HTMLElement>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const tabStop = (options, value) => {
|
|
2
|
+
if (options.some((option) => option.value === value))
|
|
3
|
+
return value;
|
|
4
|
+
const offered = options.filter((option) => !option.disabled);
|
|
5
|
+
const pool = offered.length ? offered : options;
|
|
6
|
+
if (!pool.length)
|
|
7
|
+
return undefined;
|
|
8
|
+
if (value === undefined)
|
|
9
|
+
return pool[0].value;
|
|
10
|
+
return pool.reduce((nearest, option) => Math.abs(option.value - value) < Math.abs(nearest.value - value) ? option : nearest).value;
|
|
11
|
+
};
|
|
12
|
+
export const revealSelected = (centre = false) => {
|
|
13
|
+
let centred = false;
|
|
14
|
+
return (element) => {
|
|
15
|
+
const list = element.parentElement;
|
|
16
|
+
if (!list)
|
|
17
|
+
return;
|
|
18
|
+
const top = element.offsetTop;
|
|
19
|
+
const bottom = top + element.offsetHeight;
|
|
20
|
+
if (centre || !centred) {
|
|
21
|
+
centred = true;
|
|
22
|
+
list.scrollTop = top - list.clientHeight / 2 + element.offsetHeight / 2;
|
|
23
|
+
}
|
|
24
|
+
else if (top < list.scrollTop) {
|
|
25
|
+
list.scrollTop = top;
|
|
26
|
+
}
|
|
27
|
+
else if (bottom > list.scrollTop + list.clientHeight) {
|
|
28
|
+
list.scrollTop = bottom - list.clientHeight;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -101,11 +101,11 @@ export interface TimeColumnProps extends Omit<HTMLAttributes<HTMLDivElement>, 'o
|
|
|
101
101
|
value?: number;
|
|
102
102
|
onselect?: (value: number) => void;
|
|
103
103
|
}
|
|
104
|
-
export interface DatePickerDialogProps extends Omit<HTMLAttributes<
|
|
104
|
+
export interface DatePickerDialogProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'onchange'>, DatePickerLocaleProps, DatePickerRangeProps, DatePickerCommonLabelProps, MonthStepperLabelProps {
|
|
105
105
|
value?: ISODate | null;
|
|
106
106
|
displayMonth?: ISODate;
|
|
107
107
|
open?: boolean;
|
|
108
|
-
element?:
|
|
108
|
+
element?: HTMLDialogElement;
|
|
109
109
|
name?: string;
|
|
110
110
|
form?: string;
|
|
111
111
|
title?: string;
|
|
@@ -113,6 +113,9 @@ export interface DatePickerDialogProps extends Omit<HTMLAttributes<HTMLDivElemen
|
|
|
113
113
|
modeToggle?: boolean;
|
|
114
114
|
label?: string;
|
|
115
115
|
supportingText?: string;
|
|
116
|
+
issues?: {
|
|
117
|
+
message: string;
|
|
118
|
+
}[];
|
|
116
119
|
selectYearLabel?: string;
|
|
117
120
|
calendarModeLabel?: string;
|
|
118
121
|
inputModeLabel?: string;
|
|
@@ -120,11 +123,15 @@ export interface DatePickerDialogProps extends Omit<HTMLAttributes<HTMLDivElemen
|
|
|
120
123
|
onconfirm?: (value: ISODate | undefined) => void;
|
|
121
124
|
oncancel?: () => void;
|
|
122
125
|
}
|
|
123
|
-
export interface DateRangePickerProps extends Omit<HTMLAttributes<
|
|
126
|
+
export interface DateRangePickerProps extends Omit<HTMLAttributes<HTMLDialogElement>, 'onchange'>, DatePickerLocaleProps, DatePickerRangeProps, DatePickerCommonLabelProps {
|
|
124
127
|
value?: DateRange;
|
|
125
128
|
open?: boolean;
|
|
126
|
-
element?:
|
|
129
|
+
element?: HTMLDialogElement;
|
|
127
130
|
title?: string;
|
|
131
|
+
headline?: string;
|
|
132
|
+
name?: string;
|
|
133
|
+
endName?: string;
|
|
134
|
+
form?: string;
|
|
128
135
|
startLabel?: string;
|
|
129
136
|
endLabel?: string;
|
|
130
137
|
onchange?: (value: DateRange) => void;
|