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
|
@@ -74,7 +74,6 @@
|
|
|
74
74
|
)
|
|
75
75
|
|
|
76
76
|
let field = $state<HTMLDivElement>()
|
|
77
|
-
let clientWidth = $state(0)
|
|
78
77
|
let menuOpen = $state(false)
|
|
79
78
|
let focusIndex = $state(-1)
|
|
80
79
|
let pendingFocus = false
|
|
@@ -230,6 +229,30 @@
|
|
|
230
229
|
}
|
|
231
230
|
}
|
|
232
231
|
|
|
232
|
+
const optionKeydown = (event: KeyboardEvent, option: SelectOption) => {
|
|
233
|
+
const key = event.key
|
|
234
|
+
if (key === 'ArrowDown') {
|
|
235
|
+
event.preventDefault()
|
|
236
|
+
moveFocus(1)
|
|
237
|
+
} else if (key === 'ArrowUp') {
|
|
238
|
+
event.preventDefault()
|
|
239
|
+
moveFocus(-1)
|
|
240
|
+
} else if (key === 'Home') {
|
|
241
|
+
event.preventDefault()
|
|
242
|
+
focusEdge(true)
|
|
243
|
+
} else if (key === 'End') {
|
|
244
|
+
event.preventDefault()
|
|
245
|
+
focusEdge(false)
|
|
246
|
+
} else if (key === 'Enter' || key === ' ') {
|
|
247
|
+
event.preventDefault()
|
|
248
|
+
handleOptionSelect(event, option)
|
|
249
|
+
} else if (key === 'Tab') {
|
|
250
|
+
menuElement?.hidePopover()
|
|
251
|
+
} else if (key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
252
|
+
performTypeahead(key)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
233
256
|
const performTypeahead = (char: string) => {
|
|
234
257
|
const now = performance.now()
|
|
235
258
|
if (now - lastTypeTime > 700) typeBuffer = ''
|
|
@@ -268,7 +291,7 @@
|
|
|
268
291
|
: !label?.length
|
|
269
292
|
? '--top-space:1rem;--bottom-space:1rem;'
|
|
270
293
|
: '') + style}
|
|
271
|
-
class={['text-field', attributes.class]}
|
|
294
|
+
class={['np-text-field', attributes.class]}
|
|
272
295
|
bind:this={element}
|
|
273
296
|
>
|
|
274
297
|
<!-- svelte-ignore a11y_autofocus -->
|
|
@@ -291,7 +314,6 @@
|
|
|
291
314
|
aria-activedescendant={activeDescendantId}
|
|
292
315
|
data-testid={attributes['data-testid']}
|
|
293
316
|
bind:this={field}
|
|
294
|
-
bind:clientWidth
|
|
295
317
|
autofocus={disabled ? false : autofocus}
|
|
296
318
|
onclick={(event) => {
|
|
297
319
|
const target = event.target as HTMLElement
|
|
@@ -453,93 +475,32 @@
|
|
|
453
475
|
</div>
|
|
454
476
|
|
|
455
477
|
{#snippet item(option: SelectOption, index: number)}
|
|
456
|
-
{
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
focusEdge(true)
|
|
478
|
-
} else if (key === 'End') {
|
|
479
|
-
event.preventDefault()
|
|
480
|
-
focusEdge(false)
|
|
481
|
-
} else if (key === 'Enter' || key === ' ') {
|
|
482
|
-
event.preventDefault()
|
|
483
|
-
handleOptionSelect(event, option)
|
|
484
|
-
} else if (key === 'Tab') {
|
|
485
|
-
menuElement?.hidePopover()
|
|
486
|
-
} else if (key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
487
|
-
performTypeahead(key)
|
|
488
|
-
}
|
|
489
|
-
}}
|
|
490
|
-
variant="button"
|
|
491
|
-
selected={Array.isArray(value) ? value.includes(option.value) : value === option.value}
|
|
492
|
-
aria-selected={Array.isArray(value) ? value.includes(option.value) : value === option.value}
|
|
493
|
-
>{option.label}
|
|
494
|
-
{#snippet start()}
|
|
495
|
-
<Check disabled={option.disabled} checked={value.includes(option.value)} />
|
|
496
|
-
{/snippet}
|
|
497
|
-
</Item>
|
|
498
|
-
{:else}
|
|
499
|
-
<Item
|
|
500
|
-
id="{uid}-opt-{index}"
|
|
501
|
-
onclick={(event) => {
|
|
502
|
-
handleOptionSelect(event, option)
|
|
503
|
-
field?.focus()
|
|
504
|
-
}}
|
|
505
|
-
tabindex={-1}
|
|
506
|
-
disabled={option.disabled}
|
|
507
|
-
aria-disabled={option.disabled}
|
|
508
|
-
role="option"
|
|
509
|
-
onkeydown={(event) => {
|
|
510
|
-
const key = event.key
|
|
511
|
-
if (key === 'ArrowDown') {
|
|
512
|
-
event.preventDefault()
|
|
513
|
-
moveFocus(1)
|
|
514
|
-
} else if (key === 'ArrowUp') {
|
|
515
|
-
event.preventDefault()
|
|
516
|
-
moveFocus(-1)
|
|
517
|
-
} else if (key === 'Home') {
|
|
518
|
-
event.preventDefault()
|
|
519
|
-
focusEdge(true)
|
|
520
|
-
} else if (key === 'End') {
|
|
521
|
-
event.preventDefault()
|
|
522
|
-
focusEdge(false)
|
|
523
|
-
} else if (key === 'Enter' || key === ' ') {
|
|
524
|
-
event.preventDefault()
|
|
525
|
-
handleOptionSelect(event, option)
|
|
526
|
-
} else if (key === 'Tab') {
|
|
527
|
-
menuElement?.hidePopover()
|
|
528
|
-
} else if (key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
|
|
529
|
-
performTypeahead(key)
|
|
530
|
-
}
|
|
531
|
-
}}
|
|
532
|
-
variant="button"
|
|
533
|
-
selected={Array.isArray(value) ? value.includes(option.value) : value === option.value}
|
|
534
|
-
aria-selected={Array.isArray(value) ? value.includes(option.value) : value === option.value}
|
|
535
|
-
>{option.label}
|
|
536
|
-
</Item>
|
|
537
|
-
{/if}
|
|
478
|
+
{@const isSelected = selectedSet.has(option.value)}
|
|
479
|
+
{#snippet check()}
|
|
480
|
+
<Check disabled={option.disabled} checked={isSelected} />
|
|
481
|
+
{/snippet}
|
|
482
|
+
<Item
|
|
483
|
+
id="{uid}-opt-{index}"
|
|
484
|
+
onclick={(event) => {
|
|
485
|
+
handleOptionSelect(event, option)
|
|
486
|
+
field?.focus()
|
|
487
|
+
}}
|
|
488
|
+
tabindex={-1}
|
|
489
|
+
disabled={option.disabled}
|
|
490
|
+
aria-disabled={option.disabled}
|
|
491
|
+
role="option"
|
|
492
|
+
onkeydown={(event) => optionKeydown(event, option)}
|
|
493
|
+
variant="button"
|
|
494
|
+
selected={isSelected}
|
|
495
|
+
aria-selected={isSelected}
|
|
496
|
+
start={multiple ? check : undefined}
|
|
497
|
+
>{option.label}
|
|
498
|
+
</Item>
|
|
538
499
|
{/snippet}
|
|
539
500
|
|
|
540
501
|
<Menu
|
|
541
502
|
id="listbox-{uid}"
|
|
542
|
-
style={`position-anchor:--${uid};${widthProp}
|
|
503
|
+
style={`position-anchor:--${uid};${widthProp}:anchor-size(width)`}
|
|
543
504
|
role="listbox"
|
|
544
505
|
aria-multiselectable={multiple}
|
|
545
506
|
--np-menu-justify-self="none"
|
|
@@ -689,7 +650,7 @@
|
|
|
689
650
|
height: 100%;
|
|
690
651
|
position: relative;
|
|
691
652
|
}
|
|
692
|
-
.text-field {
|
|
653
|
+
.np-text-field {
|
|
693
654
|
display: inline-flex;
|
|
694
655
|
resize: both;
|
|
695
656
|
text-align: start;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { syncOpenEffect } from '../popover.svelte.js'
|
|
3
|
+
import type { SheetProps } from './types.js'
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
open = $bindable(false),
|
|
7
|
+
modal = true,
|
|
8
|
+
placement = 'bottom',
|
|
9
|
+
handle = true,
|
|
10
|
+
headline,
|
|
11
|
+
action,
|
|
12
|
+
children,
|
|
13
|
+
element = $bindable(),
|
|
14
|
+
onclose,
|
|
15
|
+
ontoggle,
|
|
16
|
+
...attributes
|
|
17
|
+
}: SheetProps = $props()
|
|
18
|
+
|
|
19
|
+
const uid = $props.id()
|
|
20
|
+
const headlineId = `np-sheet-headline-${uid}`
|
|
21
|
+
|
|
22
|
+
export const show = () => {
|
|
23
|
+
if (!element || element.open) return
|
|
24
|
+
if (modal) element.showModal()
|
|
25
|
+
else element.show()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const close = () => {
|
|
29
|
+
element?.close()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
syncOpenEffect(
|
|
33
|
+
() => element,
|
|
34
|
+
() => open,
|
|
35
|
+
show,
|
|
36
|
+
close,
|
|
37
|
+
)
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
<dialog
|
|
41
|
+
{...attributes}
|
|
42
|
+
bind:this={element}
|
|
43
|
+
tabindex="-1"
|
|
44
|
+
closedby={modal ? 'any' : 'none'}
|
|
45
|
+
aria-labelledby={headline ? headlineId : attributes['aria-labelledby']}
|
|
46
|
+
class={['np-sheet', `np-sheet-${placement}`, modal && 'np-sheet-modal', attributes.class]}
|
|
47
|
+
onclose={(event) => {
|
|
48
|
+
open = false
|
|
49
|
+
onclose?.(event)
|
|
50
|
+
}}
|
|
51
|
+
ontoggle={(event) => {
|
|
52
|
+
open = event.newState === 'open'
|
|
53
|
+
if (event.newState === 'open') element?.focus()
|
|
54
|
+
ontoggle?.(event)
|
|
55
|
+
}}
|
|
56
|
+
onclick={(event) => {
|
|
57
|
+
if (modal && event.target === element) close()
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{#if handle && placement === 'bottom'}
|
|
61
|
+
<div class="np-sheet-handle" aria-hidden="true"></div>
|
|
62
|
+
{/if}
|
|
63
|
+
{#if headline || action}
|
|
64
|
+
<div class="np-sheet-header">
|
|
65
|
+
{#if headline}
|
|
66
|
+
<h2 id={headlineId} class="np-sheet-headline">{headline}</h2>
|
|
67
|
+
{/if}
|
|
68
|
+
{#if action}
|
|
69
|
+
<div class="np-sheet-action">{@render action()}</div>
|
|
70
|
+
{/if}
|
|
71
|
+
</div>
|
|
72
|
+
{/if}
|
|
73
|
+
<div class="np-sheet-content">
|
|
74
|
+
{@render children?.()}
|
|
75
|
+
</div>
|
|
76
|
+
</dialog>
|
|
77
|
+
|
|
78
|
+
<style>
|
|
79
|
+
.np-sheet {
|
|
80
|
+
position: fixed;
|
|
81
|
+
outline: none;
|
|
82
|
+
z-index: var(--np-sheet-z-index, 24);
|
|
83
|
+
box-sizing: border-box;
|
|
84
|
+
margin: 0;
|
|
85
|
+
padding: 0;
|
|
86
|
+
border: none;
|
|
87
|
+
max-width: none;
|
|
88
|
+
max-height: none;
|
|
89
|
+
display: flex;
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
background-color: var(--np-sheet-container-color, var(--np-color-surface-container-low));
|
|
93
|
+
color: var(--np-color-on-surface);
|
|
94
|
+
box-shadow: var(--np-sheet-elevation, var(--np-elevation-1));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.np-sheet:not([open]) {
|
|
98
|
+
display: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.np-sheet-bottom,
|
|
102
|
+
.np-sheet-top {
|
|
103
|
+
inset-inline: 0;
|
|
104
|
+
width: 100%;
|
|
105
|
+
max-height: var(--np-sheet-size, 50dvh);
|
|
106
|
+
}
|
|
107
|
+
.np-sheet-bottom {
|
|
108
|
+
inset-block-end: 0;
|
|
109
|
+
inset-block-start: auto;
|
|
110
|
+
border-start-start-radius: var(--np-sheet-shape, var(--np-shape-corner-extra-large));
|
|
111
|
+
border-start-end-radius: var(--np-sheet-shape, var(--np-shape-corner-extra-large));
|
|
112
|
+
}
|
|
113
|
+
.np-sheet-top {
|
|
114
|
+
inset-block-start: 0;
|
|
115
|
+
inset-block-end: auto;
|
|
116
|
+
border-end-start-radius: var(--np-sheet-shape, var(--np-shape-corner-extra-large));
|
|
117
|
+
border-end-end-radius: var(--np-sheet-shape, var(--np-shape-corner-extra-large));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.np-sheet-start,
|
|
121
|
+
.np-sheet-end {
|
|
122
|
+
inset-block: 0;
|
|
123
|
+
height: 100dvh;
|
|
124
|
+
width: var(--np-sheet-size, 20rem);
|
|
125
|
+
max-width: 100%;
|
|
126
|
+
}
|
|
127
|
+
.np-sheet-start {
|
|
128
|
+
inset-inline-start: 0;
|
|
129
|
+
inset-inline-end: auto;
|
|
130
|
+
border-start-end-radius: var(--np-sheet-shape, var(--np-shape-corner-large));
|
|
131
|
+
border-end-end-radius: var(--np-sheet-shape, var(--np-shape-corner-large));
|
|
132
|
+
}
|
|
133
|
+
.np-sheet-end {
|
|
134
|
+
inset-inline-end: 0;
|
|
135
|
+
inset-inline-start: auto;
|
|
136
|
+
border-start-start-radius: var(--np-sheet-shape, var(--np-shape-corner-large));
|
|
137
|
+
border-end-start-radius: var(--np-sheet-shape, var(--np-shape-corner-large));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.np-sheet-handle {
|
|
141
|
+
flex: none;
|
|
142
|
+
width: 2rem;
|
|
143
|
+
height: 0.25rem;
|
|
144
|
+
margin: 1rem auto 0;
|
|
145
|
+
border-radius: var(--np-shape-corner-full);
|
|
146
|
+
background-color: var(--np-sheet-handle-color, var(--np-color-outline-variant));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.np-sheet-header {
|
|
150
|
+
flex: none;
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: 0.5rem;
|
|
154
|
+
padding: 1rem 1.5rem 0;
|
|
155
|
+
}
|
|
156
|
+
.np-sheet-headline {
|
|
157
|
+
flex: 1;
|
|
158
|
+
margin: 0;
|
|
159
|
+
font-size: 1.5rem;
|
|
160
|
+
line-height: 2rem;
|
|
161
|
+
font-weight: 400;
|
|
162
|
+
}
|
|
163
|
+
.np-sheet-action {
|
|
164
|
+
flex: none;
|
|
165
|
+
display: flex;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.np-sheet-content {
|
|
169
|
+
flex: 1;
|
|
170
|
+
min-height: 0;
|
|
171
|
+
overflow-y: auto;
|
|
172
|
+
overscroll-behavior: contain;
|
|
173
|
+
padding: 1rem 1.5rem 1.5rem;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.np-sheet-modal::backdrop {
|
|
177
|
+
background-color: var(--np-color-scrim);
|
|
178
|
+
opacity: 0.32;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
182
|
+
.np-sheet {
|
|
183
|
+
transition:
|
|
184
|
+
translate var(--np-motion-expressive-default-spatial),
|
|
185
|
+
display var(--np-motion-expressive-default-spatial) allow-discrete,
|
|
186
|
+
overlay var(--np-motion-expressive-default-spatial) allow-discrete;
|
|
187
|
+
}
|
|
188
|
+
.np-sheet::backdrop {
|
|
189
|
+
transition:
|
|
190
|
+
opacity var(--np-motion-expressive-fast-effects),
|
|
191
|
+
display var(--np-motion-expressive-fast-effects) allow-discrete,
|
|
192
|
+
overlay var(--np-motion-expressive-fast-effects) allow-discrete;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.np-sheet-bottom {
|
|
196
|
+
translate: 0 100%;
|
|
197
|
+
}
|
|
198
|
+
.np-sheet-top {
|
|
199
|
+
translate: 0 -100%;
|
|
200
|
+
}
|
|
201
|
+
.np-sheet-start {
|
|
202
|
+
translate: -100% 0;
|
|
203
|
+
}
|
|
204
|
+
.np-sheet-end {
|
|
205
|
+
translate: 100% 0;
|
|
206
|
+
}
|
|
207
|
+
.np-sheet[open] {
|
|
208
|
+
translate: 0 0;
|
|
209
|
+
}
|
|
210
|
+
@starting-style {
|
|
211
|
+
.np-sheet-bottom[open] {
|
|
212
|
+
translate: 0 100%;
|
|
213
|
+
}
|
|
214
|
+
.np-sheet-top[open] {
|
|
215
|
+
translate: 0 -100%;
|
|
216
|
+
}
|
|
217
|
+
.np-sheet-start[open] {
|
|
218
|
+
translate: -100% 0;
|
|
219
|
+
}
|
|
220
|
+
.np-sheet-end[open] {
|
|
221
|
+
translate: 100% 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.np-sheet-modal::backdrop {
|
|
226
|
+
opacity: 0;
|
|
227
|
+
}
|
|
228
|
+
.np-sheet-modal[open]::backdrop {
|
|
229
|
+
opacity: 0.32;
|
|
230
|
+
@starting-style {
|
|
231
|
+
opacity: 0;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
</style>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Sheet } from './Sheet.svelte';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Sheet } from './Sheet.svelte';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLDialogAttributes } from 'svelte/elements';
|
|
3
|
+
export interface SheetProps extends Omit<HTMLDialogAttributes, 'open'> {
|
|
4
|
+
open?: boolean;
|
|
5
|
+
modal?: boolean;
|
|
6
|
+
placement?: 'bottom' | 'top' | 'start' | 'end';
|
|
7
|
+
handle?: boolean;
|
|
8
|
+
headline?: string;
|
|
9
|
+
action?: Snippet;
|
|
10
|
+
element?: HTMLDialogElement;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { popoverController, syncOpenEffect } from '../popover.svelte.js'
|
|
2
3
|
import type { SliderProps } from './types.js'
|
|
3
4
|
|
|
4
5
|
let {
|
|
@@ -21,9 +22,14 @@
|
|
|
21
22
|
element = $bindable(),
|
|
22
23
|
inputElement = $bindable(),
|
|
23
24
|
endInputElement = $bindable(),
|
|
25
|
+
issues,
|
|
26
|
+
'aria-invalid': ariaInvalid,
|
|
24
27
|
...attributes
|
|
25
28
|
}: SliderProps = $props()
|
|
26
29
|
|
|
30
|
+
let hasError = $derived(!!issues?.length)
|
|
31
|
+
const uid = $props.id()
|
|
32
|
+
|
|
27
33
|
const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v))
|
|
28
34
|
|
|
29
35
|
let span = $derived(max - min || 1)
|
|
@@ -109,6 +115,24 @@
|
|
|
109
115
|
|
|
110
116
|
const DRAG_THRESHOLD = 3
|
|
111
117
|
|
|
118
|
+
let startLabelElement = $state<HTMLDivElement>()
|
|
119
|
+
let endLabelElement = $state<HTMLDivElement>()
|
|
120
|
+
let startHandleElement = $state<HTMLDivElement>()
|
|
121
|
+
let endHandleElement = $state<HTMLDivElement>()
|
|
122
|
+
let hovered = $state<'start' | 'end' | null>(null)
|
|
123
|
+
let focused = $state<'start' | 'end' | null>(null)
|
|
124
|
+
|
|
125
|
+
let labelled = $derived(
|
|
126
|
+
disabled ? null : (dragging ?? hovered ?? (pointerFocused ? null : focused)),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const bindLabel = (getElement: () => HTMLDivElement | undefined, side: 'start' | 'end') => {
|
|
130
|
+
const controller = popoverController(getElement)
|
|
131
|
+
syncOpenEffect(getElement, () => labelled === side, controller.show, controller.close)
|
|
132
|
+
}
|
|
133
|
+
bindLabel(() => startLabelElement, 'start')
|
|
134
|
+
bindLabel(() => endLabelElement, 'end')
|
|
135
|
+
|
|
112
136
|
$effect(() => {
|
|
113
137
|
if (!icon || !activeLaneElement) return
|
|
114
138
|
const lane = activeLaneElement
|
|
@@ -155,7 +179,24 @@
|
|
|
155
179
|
}
|
|
156
180
|
}
|
|
157
181
|
|
|
182
|
+
const HOVER_TOLERANCE = 12
|
|
183
|
+
|
|
184
|
+
const distanceTo = (handle: HTMLDivElement | undefined, e: PointerEvent) => {
|
|
185
|
+
if (!handle) return Infinity
|
|
186
|
+
const r = handle.getBoundingClientRect()
|
|
187
|
+
const dx = Math.max(r.left - e.clientX, 0, e.clientX - r.right)
|
|
188
|
+
const dy = Math.max(r.top - e.clientY, 0, e.clientY - r.bottom)
|
|
189
|
+
return Math.hypot(dx, dy)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const updateHover = (e: PointerEvent) => {
|
|
193
|
+
const toStart = distanceTo(startHandleElement, e)
|
|
194
|
+
const toEnd = distanceTo(endHandleElement, e)
|
|
195
|
+
hovered = Math.min(toStart, toEnd) > HOVER_TOLERANCE ? null : toStart <= toEnd ? 'start' : 'end'
|
|
196
|
+
}
|
|
197
|
+
|
|
158
198
|
const onpointermove = (e: PointerEvent) => {
|
|
199
|
+
updateHover(e)
|
|
159
200
|
if (!dragging) return
|
|
160
201
|
if (!tracking) {
|
|
161
202
|
const d = pointerOrigin
|
|
@@ -195,6 +236,7 @@
|
|
|
195
236
|
tracking = false
|
|
196
237
|
pointerOrigin = null
|
|
197
238
|
element?.releasePointerCapture(e.pointerId)
|
|
239
|
+
updateHover(e)
|
|
198
240
|
input?.dispatchEvent(new Event('change', { bubbles: true }))
|
|
199
241
|
}
|
|
200
242
|
|
|
@@ -215,6 +257,7 @@
|
|
|
215
257
|
dragging && 'np-dragging',
|
|
216
258
|
tracking && 'np-tracking',
|
|
217
259
|
pointerFocused && 'np-pointer-focused',
|
|
260
|
+
hasError && !disabled && 'np-error',
|
|
218
261
|
attributes.class,
|
|
219
262
|
]}
|
|
220
263
|
role="presentation"
|
|
@@ -222,8 +265,13 @@
|
|
|
222
265
|
{onpointermove}
|
|
223
266
|
onpointerup={endDrag}
|
|
224
267
|
onpointercancel={endDrag}
|
|
268
|
+
onpointerleave={() => (hovered = null)}
|
|
225
269
|
onkeydown={() => (pointerFocused = false)}
|
|
226
|
-
|
|
270
|
+
onfocusin={(event) => (focused = event.target === endInputElement ? 'end' : 'start')}
|
|
271
|
+
onfocusout={() => {
|
|
272
|
+
focused = null
|
|
273
|
+
pointerFocused = false
|
|
274
|
+
}}
|
|
227
275
|
>
|
|
228
276
|
<div class="np-slider-track" bind:this={trackElement}>
|
|
229
277
|
{#if hasStartStop}
|
|
@@ -247,21 +295,37 @@
|
|
|
247
295
|
<span class={['np-slider-tick', isActive(t) && 'np-on-active']} style="--_t:{t}"></span>
|
|
248
296
|
{/each}
|
|
249
297
|
|
|
250
|
-
<div
|
|
298
|
+
<div
|
|
299
|
+
bind:this={startHandleElement}
|
|
300
|
+
class="np-slider-handle np-slider-handle-start"
|
|
301
|
+
style="anchor-name: --np-slider-{uid}-start"
|
|
302
|
+
></div>
|
|
303
|
+
{#if labeled}
|
|
304
|
+
<div
|
|
305
|
+
bind:this={startLabelElement}
|
|
306
|
+
popover="manual"
|
|
307
|
+
class="np-slider-label-anchor"
|
|
308
|
+
style="position-anchor: --np-slider-{uid}-start"
|
|
309
|
+
>
|
|
310
|
+
<div class="np-slider-label">{labelFor(range ? Math.min(lo, hi) : lo)}</div>
|
|
311
|
+
</div>
|
|
312
|
+
{/if}
|
|
313
|
+
{#if range}
|
|
314
|
+
<div
|
|
315
|
+
bind:this={endHandleElement}
|
|
316
|
+
class="np-slider-handle np-slider-handle-end"
|
|
317
|
+
style="anchor-name: --np-slider-{uid}-end"
|
|
318
|
+
></div>
|
|
251
319
|
{#if labeled}
|
|
252
|
-
<div
|
|
253
|
-
|
|
320
|
+
<div
|
|
321
|
+
bind:this={endLabelElement}
|
|
322
|
+
popover="manual"
|
|
323
|
+
class="np-slider-label-anchor"
|
|
324
|
+
style="position-anchor: --np-slider-{uid}-end"
|
|
325
|
+
>
|
|
326
|
+
<div class="np-slider-label">{labelFor(Math.max(lo, hi))}</div>
|
|
254
327
|
</div>
|
|
255
328
|
{/if}
|
|
256
|
-
</div>
|
|
257
|
-
{#if range}
|
|
258
|
-
<div class="np-slider-handle np-slider-handle-end">
|
|
259
|
-
{#if labeled}
|
|
260
|
-
<div class="np-slider-label-anchor">
|
|
261
|
-
<div class="np-slider-label">{labelFor(Math.max(lo, hi))}</div>
|
|
262
|
-
</div>
|
|
263
|
-
{/if}
|
|
264
|
-
</div>
|
|
265
329
|
{/if}
|
|
266
330
|
</div>
|
|
267
331
|
|
|
@@ -277,6 +341,7 @@
|
|
|
277
341
|
{disabled}
|
|
278
342
|
aria-orientation={orientation}
|
|
279
343
|
aria-valuetext={format ? labelFor(lo) : attributes['aria-valuetext']}
|
|
344
|
+
aria-invalid={hasError ? 'true' : ariaInvalid}
|
|
280
345
|
/>
|
|
281
346
|
{#if range}
|
|
282
347
|
<input
|
|
@@ -377,6 +442,14 @@
|
|
|
377
442
|
background: var(--np-slider-active-track-color, var(--np-color-primary));
|
|
378
443
|
}
|
|
379
444
|
|
|
445
|
+
.np-error {
|
|
446
|
+
--np-slider-active-track-color: var(--np-color-error);
|
|
447
|
+
--np-slider-handle-color: var(--np-color-error);
|
|
448
|
+
--np-slider-active-stop-color: var(--np-color-on-error);
|
|
449
|
+
--np-slider-label-container-color: var(--np-color-error);
|
|
450
|
+
--np-slider-label-text-color: var(--np-color-on-error);
|
|
451
|
+
}
|
|
452
|
+
|
|
380
453
|
.np-slider-inactive-start {
|
|
381
454
|
inset-inline-start: 0;
|
|
382
455
|
inset-inline-end: calc(100% - var(--_i1));
|
|
@@ -502,15 +575,42 @@
|
|
|
502
575
|
block-size var(--np-motion-expressive-fast-effects);
|
|
503
576
|
}
|
|
504
577
|
|
|
505
|
-
.np-slider-label-anchor {
|
|
506
|
-
position:
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
578
|
+
.np-slider-label-anchor[popover] {
|
|
579
|
+
position-area: block-start;
|
|
580
|
+
justify-self: anchor-center;
|
|
581
|
+
margin: 0 0 0.375rem 0;
|
|
582
|
+
border: none;
|
|
583
|
+
background: none;
|
|
584
|
+
padding: 0;
|
|
510
585
|
justify-content: center;
|
|
511
586
|
pointer-events: none;
|
|
512
587
|
}
|
|
513
588
|
|
|
589
|
+
.np-slider-label-anchor:popover-open {
|
|
590
|
+
display: flex;
|
|
591
|
+
opacity: 1;
|
|
592
|
+
scale: 1;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
596
|
+
.np-slider-label-anchor:popover-open {
|
|
597
|
+
animation:
|
|
598
|
+
fadeIn var(--np-motion-expressive-fast-effects),
|
|
599
|
+
scaleIn var(--np-motion-expressive-fast-spatial);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
@keyframes fadeIn {
|
|
604
|
+
from {
|
|
605
|
+
opacity: 0;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
@keyframes scaleIn {
|
|
609
|
+
from {
|
|
610
|
+
scale: 0.8;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
514
614
|
.np-slider-label {
|
|
515
615
|
flex: none;
|
|
516
616
|
writing-mode: horizontal-tb;
|
|
@@ -526,18 +626,6 @@
|
|
|
526
626
|
font-weight: 500;
|
|
527
627
|
text-align: center;
|
|
528
628
|
white-space: nowrap;
|
|
529
|
-
opacity: 0;
|
|
530
|
-
transition: opacity var(--np-motion-expressive-fast-effects);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
.np-slider.np-labeled:hover .np-slider-label,
|
|
534
|
-
.np-slider.np-labeled.np-dragging .np-slider-label,
|
|
535
|
-
.np-slider.np-labeled:has(.np-slider-input:focus-visible) .np-slider-label {
|
|
536
|
-
opacity: 1;
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
.np-slider.np-disabled .np-slider-label {
|
|
540
|
-
opacity: 0;
|
|
541
629
|
}
|
|
542
630
|
|
|
543
631
|
.np-slider-input {
|
package/dist/slider/types.d.ts
CHANGED