noph-ui 0.51.2 → 0.53.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.
Files changed (187) hide show
  1. package/dist/animation.d.ts +14 -1
  2. package/dist/animation.js +55 -2
  3. package/dist/app-bar/AppBar.svelte +71 -7
  4. package/dist/app-bar/types.d.ts +6 -0
  5. package/dist/autocomplete/AutoComplete.svelte +6 -31
  6. package/dist/autocomplete/AutoComplete.svelte.d.ts +1 -1
  7. package/dist/badge/Badge.svelte +12 -4
  8. package/dist/badge/description.d.ts +4 -0
  9. package/dist/badge/description.js +4 -0
  10. package/dist/button/Button.svelte +53 -30
  11. package/dist/button/ButtonGroup.svelte +139 -19
  12. package/dist/button/ButtonGroup.svelte.d.ts +1 -1
  13. package/dist/button/IconButton.svelte +51 -33
  14. package/dist/button/SegmentedButton.svelte +52 -15
  15. package/dist/button/SplitButton.svelte +77 -3
  16. package/dist/button/SplitButton.svelte.d.ts +1 -1
  17. package/dist/button/buttonGroup.d.ts +0 -4
  18. package/dist/button/buttonGroup.js +0 -9
  19. package/dist/button/groupContext.d.ts +10 -0
  20. package/dist/button/groupContext.js +4 -0
  21. package/dist/button/types.d.ts +19 -0
  22. package/dist/card/Card.svelte +3 -19
  23. package/dist/card/types.d.ts +12 -2
  24. package/dist/carousel/Carousel.svelte +77 -14
  25. package/dist/carousel/CarouselItem.svelte +26 -14
  26. package/dist/carousel/carouselMorph.js +1 -1
  27. package/dist/carousel/carouselStrategy.js +25 -27
  28. package/dist/checkbox/Checkbox.svelte +6 -8
  29. package/dist/chip/ChipSet.svelte +28 -2
  30. package/dist/chip/FilterChip.svelte +33 -17
  31. package/dist/chip/InputChip.svelte +127 -26
  32. package/dist/chip/SuggestionChip.svelte +6 -22
  33. package/dist/chip/SuggestionChip.svelte.d.ts +1 -2
  34. package/dist/chip/types.d.ts +8 -1
  35. package/dist/date-picker/Calendar.svelte +34 -31
  36. package/dist/date-picker/Calendar.svelte.d.ts +2 -0
  37. package/dist/date-picker/CalendarHeader.svelte +84 -62
  38. package/dist/date-picker/CalendarHeader.svelte.d.ts +3 -0
  39. package/dist/date-picker/DatePickerDialog.svelte +135 -75
  40. package/dist/date-picker/DatePickerDialog.svelte.d.ts +4 -3
  41. package/dist/date-picker/DateRangePicker.svelte +227 -78
  42. package/dist/date-picker/DateRangePicker.svelte.d.ts +3 -3
  43. package/dist/date-picker/DockedDatePicker.svelte +76 -457
  44. package/dist/date-picker/DockedDatePicker.svelte.d.ts +3 -3
  45. package/dist/date-picker/DockedDateTimePicker.svelte +128 -518
  46. package/dist/date-picker/DockedDateTimePicker.svelte.d.ts +3 -3
  47. package/dist/date-picker/DockedPickerField.svelte +221 -0
  48. package/dist/date-picker/DockedPickerField.svelte.d.ts +9 -0
  49. package/dist/date-picker/MonthPanel.svelte +291 -0
  50. package/dist/date-picker/MonthPanel.svelte.d.ts +12 -0
  51. package/dist/date-picker/SelectionList.svelte +7 -6
  52. package/dist/date-picker/SelectionList.svelte.d.ts +1 -0
  53. package/dist/date-picker/TimeColumn.svelte +2 -6
  54. package/dist/date-picker/TimeColumn.svelte.d.ts +1 -0
  55. package/dist/date-picker/YearGrid.svelte +6 -13
  56. package/dist/date-picker/YearGrid.svelte.d.ts +1 -0
  57. package/dist/date-picker/dateUtils.d.ts +4 -0
  58. package/dist/date-picker/dateUtils.js +15 -88
  59. package/dist/date-picker/exitVisibility.svelte.js +13 -6
  60. package/dist/date-picker/formatters.d.ts +16 -0
  61. package/dist/date-picker/formatters.js +48 -15
  62. package/dist/date-picker/internalTypes.d.ts +59 -1
  63. package/dist/date-picker/shortcuts.d.ts +11 -0
  64. package/dist/date-picker/shortcuts.js +40 -0
  65. package/dist/date-picker/timeUtils.d.ts +8 -3
  66. package/dist/date-picker/timeUtils.js +33 -51
  67. package/dist/date-picker/types.d.ts +22 -0
  68. package/dist/dialog/Dialog.svelte +171 -33
  69. package/dist/dialog/Dialog.svelte.d.ts +2 -1
  70. package/dist/dialog/types.d.ts +6 -0
  71. package/dist/divider/Divider.svelte +36 -10
  72. package/dist/divider/types.d.ts +1 -0
  73. package/dist/fab/ExtendedFab.svelte +26 -60
  74. package/dist/fab/Fab.svelte +13 -48
  75. package/dist/fab/FabMenu.svelte +102 -44
  76. package/dist/fab/FabMenu.svelte.d.ts +2 -1
  77. package/dist/fab/FabMenuItem.svelte +8 -0
  78. package/dist/fab/FabMenuItem.svelte.d.ts +4 -0
  79. package/dist/fab/index.d.ts +1 -0
  80. package/dist/fab/index.js +1 -0
  81. package/dist/fab/types.d.ts +6 -4
  82. package/dist/icons/Icon.svelte +1 -4
  83. package/dist/icons/MenuIcon.svelte +13 -0
  84. package/dist/icons/MenuIcon.svelte.d.ts +7 -0
  85. package/dist/icons/MenuOpenIcon.svelte +15 -0
  86. package/dist/icons/MenuOpenIcon.svelte.d.ts +7 -0
  87. package/dist/icons/index.d.ts +2 -0
  88. package/dist/icons/index.js +2 -0
  89. package/dist/internal/exit.css +33 -0
  90. package/dist/internal/field.css +337 -0
  91. package/dist/internal/fieldTypes.d.ts +6 -0
  92. package/dist/internal/focus-ring.css +25 -6
  93. package/dist/internal/interest.css +3 -1
  94. package/dist/internal/pop-in.css +19 -0
  95. package/dist/internal/visually-hidden.css +11 -0
  96. package/dist/keyboard-nav.d.ts +12 -1
  97. package/dist/keyboard-nav.js +104 -14
  98. package/dist/list/Item.svelte +84 -24
  99. package/dist/list/List.svelte +35 -2
  100. package/dist/list/ListItem.svelte +16 -2
  101. package/dist/list/context.d.ts +6 -0
  102. package/dist/list/context.js +4 -0
  103. package/dist/list/types.d.ts +7 -0
  104. package/dist/media.d.ts +1 -0
  105. package/dist/media.js +1 -0
  106. package/dist/menu/Menu.svelte +53 -20
  107. package/dist/menu/Menu.svelte.d.ts +3 -1
  108. package/dist/menu/MenuItem.svelte +9 -3
  109. package/dist/menu/types.d.ts +7 -1
  110. package/dist/navigation-bar/NavigationBar.svelte +9 -3
  111. package/dist/navigation-bar/NavigationBarItem.svelte +31 -39
  112. package/dist/navigation-drawer/NavigationDrawer.svelte +96 -20
  113. package/dist/navigation-drawer/NavigationDrawer.svelte.d.ts +2 -1
  114. package/dist/navigation-drawer/NavigationDrawerItem.svelte +10 -12
  115. package/dist/navigation-drawer/NavigationDrawerSection.svelte +49 -0
  116. package/dist/navigation-drawer/NavigationDrawerSection.svelte.d.ts +4 -0
  117. package/dist/navigation-drawer/index.d.ts +1 -0
  118. package/dist/navigation-drawer/index.js +1 -0
  119. package/dist/navigation-drawer/types.d.ts +12 -0
  120. package/dist/navigation-rail/NavigationRail.svelte +367 -7
  121. package/dist/navigation-rail/NavigationRail.svelte.d.ts +1 -1
  122. package/dist/navigation-rail/NavigationRailItem.svelte +185 -59
  123. package/dist/navigation-rail/NavigationRailSection.svelte +57 -0
  124. package/dist/navigation-rail/NavigationRailSection.svelte.d.ts +4 -0
  125. package/dist/navigation-rail/context.d.ts +6 -0
  126. package/dist/navigation-rail/context.js +5 -0
  127. package/dist/navigation-rail/index.d.ts +1 -0
  128. package/dist/navigation-rail/index.js +1 -0
  129. package/dist/navigation-rail/morph.d.ts +14 -0
  130. package/dist/navigation-rail/morph.js +78 -0
  131. package/dist/navigation-rail/types.d.ts +21 -0
  132. package/dist/press.svelte.d.ts +0 -1
  133. package/dist/press.svelte.js +0 -11
  134. package/dist/progress/CircularProgress.svelte +28 -82
  135. package/dist/progress/CircularProgress.svelte.d.ts +1 -0
  136. package/dist/progress/LinearProgress.svelte +67 -171
  137. package/dist/progress/LinearProgress.svelte.d.ts +1 -0
  138. package/dist/progress/four-color.css +34 -0
  139. package/dist/progress/types.d.ts +1 -0
  140. package/dist/radio/Radio.svelte +13 -10
  141. package/dist/ripple/Ripple.svelte +8 -16
  142. package/dist/search/Search.svelte +238 -58
  143. package/dist/search/Search.svelte.d.ts +1 -0
  144. package/dist/search/types.d.ts +4 -0
  145. package/dist/select/Check.svelte +8 -31
  146. package/dist/select/Check.svelte.d.ts +1 -1
  147. package/dist/select/NativeSelect.svelte +113 -374
  148. package/dist/select/NativeSelect.svelte.d.ts +1 -0
  149. package/dist/select/Option.svelte +2 -11
  150. package/dist/select/Select.svelte +170 -858
  151. package/dist/select/Select.svelte.d.ts +1 -0
  152. package/dist/select/VirtualList.svelte +16 -2
  153. package/dist/select/VirtualList.svelte.d.ts +6 -2
  154. package/dist/sheet/Sheet.svelte +229 -22
  155. package/dist/sheet/Sheet.svelte.d.ts +3 -1
  156. package/dist/sheet/types.d.ts +10 -0
  157. package/dist/slider/Slider.svelte +14 -64
  158. package/dist/slider/Slider.svelte.d.ts +1 -0
  159. package/dist/snackbar/Snackbar.svelte +3 -0
  160. package/dist/snackbar/Snackbar.svelte.d.ts +2 -1
  161. package/dist/switch/Switch.svelte +53 -19
  162. package/dist/tabs/Tab.svelte +30 -18
  163. package/dist/tabs/Tabs.svelte +28 -4
  164. package/dist/tabs/types.d.ts +3 -0
  165. package/dist/text-field/TextField.svelte +124 -616
  166. package/dist/text-field/TextField.svelte.d.ts +1 -0
  167. package/dist/time-picker/ClockDial.svelte +8 -25
  168. package/dist/time-picker/ClockDial.svelte.d.ts +2 -0
  169. package/dist/time-picker/DockedTimePicker.svelte +102 -239
  170. package/dist/time-picker/DockedTimePicker.svelte.d.ts +3 -3
  171. package/dist/time-picker/PeriodSelector.svelte +8 -7
  172. package/dist/time-picker/PeriodSelector.svelte.d.ts +1 -0
  173. package/dist/time-picker/TimeInputs.svelte +13 -2
  174. package/dist/time-picker/TimePickerDialog.svelte +33 -26
  175. package/dist/time-picker/TimePickerDialog.svelte.d.ts +3 -3
  176. package/dist/time-picker/TimePickerPanel.svelte +26 -4
  177. package/dist/time-picker/TimeSelectors.svelte +4 -9
  178. package/dist/time-picker/TimeSelectors.svelte.d.ts +1 -0
  179. package/dist/time-picker/internalTypes.d.ts +2 -0
  180. package/dist/time-picker/timePickerState.svelte.js +3 -9
  181. package/dist/toolbar/Toolbar.svelte +21 -11
  182. package/dist/toolbar/types.d.ts +1 -0
  183. package/dist/tooltip/RichTooltip.svelte +2 -23
  184. package/dist/tooltip/RichTooltip.svelte.d.ts +2 -1
  185. package/dist/tooltip/Tooltip.svelte +5 -25
  186. package/dist/tooltip/Tooltip.svelte.d.ts +2 -1
  187. package/package.json +12 -12
@@ -1,9 +1,9 @@
1
1
  <script lang="ts">
2
- import { afterTwoFrames } from '../animation.js'
2
+ import '../internal/focus-ring.css'
3
+ import { afterTwoFrames, morphSize } from '../animation.js'
3
4
  import Button from '../button/Button.svelte'
4
5
  import IconButton from '../button/IconButton.svelte'
5
6
  import Dialog from '../dialog/Dialog.svelte'
6
- import { syncOpenEffect } from '../popover.svelte.js'
7
7
  import Divider from '../divider/Divider.svelte'
8
8
  import { exitVisibility } from './exitVisibility.svelte.js'
9
9
  import ArrowDropDownIcon from '../icons/ArrowDropDownIcon.svelte'
@@ -11,17 +11,20 @@
11
11
  import ChevronLeftIcon from '../icons/ChevronLeftIcon.svelte'
12
12
  import ChevronRightIcon from '../icons/ChevronRightIcon.svelte'
13
13
  import EditCalendarIcon from '../icons/EditCalendarIcon.svelte'
14
+ import Ripple from '../ripple/Ripple.svelte'
14
15
  import TextField from '../text-field/TextField.svelte'
15
- import { tick } from 'svelte'
16
+ import Tooltip from '../tooltip/Tooltip.svelte'
17
+ import { flushSync, tick } from 'svelte'
16
18
  import Calendar from './Calendar.svelte'
17
19
  import YearGrid from './YearGrid.svelte'
20
+ import { DEFAULT_SHORTCUT_LABELS, pickerShortcut, withShortcut } from './shortcuts.js'
18
21
  import {
19
22
  addMonths,
20
23
  clampMonthInYear,
21
- compareDays,
24
+ isMonthWithin,
22
25
  DEFAULT_YEAR_RANGE,
23
26
  formatDate,
24
- formatDateMedium,
27
+ formatDateHeadline,
25
28
  formatMonthYear,
26
29
  getDatePattern,
27
30
  getFirstDayOfWeek,
@@ -32,7 +35,7 @@
32
35
  toISODate,
33
36
  today as getToday,
34
37
  } from './dateUtils.js'
35
- import type { DatePickerDialogProps, ISODate } from './types.js'
38
+ import type { DatePickerDialogProps, DatePickerMode, ISODate } from './types.js'
36
39
 
37
40
  let {
38
41
  value = $bindable(),
@@ -53,12 +56,14 @@
53
56
  issues,
54
57
  name,
55
58
  form,
56
- modeToggle = false,
59
+ mode = $bindable<DatePickerMode>('calendar'),
60
+ modeToggle = true,
57
61
  cancelLabel = 'Cancel',
58
62
  confirmLabel = 'OK',
59
63
  nextMonthLabel = 'Next month',
60
64
  previousMonthLabel = 'Previous month',
61
65
  selectYearLabel = 'Select year',
66
+ shortcutLabels,
62
67
  calendarModeLabel = 'Switch to calendar mode',
63
68
  inputModeLabel = 'Switch to text input mode',
64
69
  selectedDateLabel = 'selected',
@@ -70,7 +75,6 @@
70
75
 
71
76
  const uid = $props.id()
72
77
 
73
- let mode = $state<'calendar' | 'input'>('calendar')
74
78
  let yearPickerVisible = $state(false)
75
79
  let pending = $state<ISODate | undefined>(undefined)
76
80
  let focusedDay = $state<Date | undefined>(undefined)
@@ -92,67 +96,61 @@
92
96
  parseISODate(displayMonth) ?? startOfMonth(pendingDate ?? parseISODate(value) ?? todayValue),
93
97
  )
94
98
  let headlineText = $derived(
95
- headline ?? (pendingDate ? formatDateMedium(pendingDate, locale) : title),
99
+ headline ?? (pendingDate ? formatDateHeadline(pendingDate, locale) : title),
96
100
  )
97
101
 
98
- let canPreviousMonth = $derived(
99
- !minDate ||
100
- compareDays(new Date(monthDate.getFullYear(), monthDate.getMonth(), 0), minDate) >= 0,
101
- )
102
- let canNextMonth = $derived(
103
- !maxDate ||
104
- compareDays(new Date(monthDate.getFullYear(), monthDate.getMonth() + 1, 1), maxDate) <= 0,
105
- )
102
+ let steps = $derived.by(() => {
103
+ const year = monthDate.getFullYear()
104
+ const month = monthDate.getMonth()
105
+ return {
106
+ previousMonth: isMonthWithin(year, month - 1, minDate, maxDate) ? -1 : 0,
107
+ nextMonth: isMonthWithin(year, month + 1, minDate, maxDate) ? 1 : 0,
108
+ previousYear:
109
+ year > yearRange[0] && isMonthWithin(year - 1, month, minDate, maxDate) ? -12 : 0,
110
+ nextYear: year < yearRange[1] && isMonthWithin(year + 1, month, minDate, maxDate) ? 12 : 0,
111
+ }
112
+ })
113
+ let canPreviousMonth = $derived(steps.previousMonth !== 0)
114
+ let canNextMonth = $derived(steps.nextMonth !== 0)
115
+
116
+ let keys = $derived({ ...DEFAULT_SHORTCUT_LABELS, ...shortcutLabels })
106
117
 
107
118
  let canConfirm = $derived(
108
119
  !pendingDate ||
109
120
  (isWithin(pendingDate, minDate, maxDate) && (isDateEnabled?.(pendingDate) ?? true)),
110
121
  )
111
122
 
112
- let modeEnter = $state<'' | 'to-input' | 'to-calendar'>('')
113
- let yearEnter = $state(false)
123
+ // The view switched to slides in. Only a switch does, so opening in input mode stays still.
124
+ let modeEnter = $state<DatePickerMode>()
114
125
  let cancelModeEnter: (() => void) | undefined
115
- let cancelYearEnter: (() => void) | undefined
116
126
 
117
- const setMode = (next: 'calendar' | 'input') => {
127
+ let content = $state<HTMLElement>()
128
+
129
+ const setMode = (next: DatePickerMode) => {
118
130
  if (mode === next) return
119
- mode = next
120
131
  cancelModeEnter?.()
121
- modeEnter = next === 'input' ? 'to-input' : 'to-calendar'
122
- cancelModeEnter = afterTwoFrames(() => (modeEnter = ''))
132
+ morphSize(
133
+ content,
134
+ () =>
135
+ flushSync(() => {
136
+ mode = next
137
+ modeEnter = next
138
+ yearPickerVisible = false
139
+ }),
140
+ '--np-motion-expressive-default-spatial',
141
+ )
142
+ cancelModeEnter = afterTwoFrames(() => (modeEnter = undefined))
123
143
  }
124
144
 
125
- const showYearPicker = (next: boolean) => {
126
- yearPickerVisible = next
127
- if (!next) return
128
- cancelYearEnter?.()
129
- yearEnter = true
130
- cancelYearEnter = afterTwoFrames(() => (yearEnter = false))
131
- }
145
+ let dialog = $state<Dialog>()
132
146
 
133
- export const show = () => {
134
- if (element && !element.open) element.showModal()
135
- }
136
-
137
- export const close = () => {
138
- if (element?.open) element.close()
139
- }
140
-
141
- syncOpenEffect(
142
- () => element,
143
- () => open,
144
- show,
145
- close,
146
- )
147
+ export const show = () => dialog?.show()
148
+ export const close = () => dialog?.close()
147
149
 
148
150
  const setMonth = (date: Date) => {
149
151
  displayMonth = toISODate(startOfMonth(date))
150
152
  }
151
153
 
152
- const cancel = () => {
153
- open = false
154
- }
155
-
156
154
  const confirm = () => {
157
155
  confirming = true
158
156
  value = pending
@@ -161,9 +159,13 @@
161
159
  open = false
162
160
  }
163
161
 
164
- const focusCalendarWhenReady = async () => {
162
+ const focusWhenReady = async () => {
165
163
  await tick()
166
- element?.querySelector<HTMLElement>('.np-calendar-day[tabindex="0"]')?.focus()
164
+ element
165
+ ?.querySelector<HTMLElement>(
166
+ mode === 'input' ? '.np-date-picker-dialog-input input' : '.np-calendar-day[tabindex="0"]',
167
+ )
168
+ ?.focus()
167
169
  }
168
170
 
169
171
  const syncText = () => {
@@ -194,31 +196,66 @@
194
196
  inputInvalid = !parsed
195
197
  if (parsed) text = formatDate(parsed, locale)
196
198
  }
199
+
200
+ let navigation = $state<HTMLElement>()
201
+
202
+ const showYears = (visible: boolean) => {
203
+ flushSync(() => (yearPickerVisible = visible))
204
+ element
205
+ ?.querySelector<HTMLElement>(
206
+ yearPickerVisible ? '.np-date-picker-year[tabindex="0"]' : '.np-calendar-day[tabindex="0"]',
207
+ )
208
+ ?.focus()
209
+ }
210
+
211
+ const handleKeydown = (event: KeyboardEvent) => {
212
+ if (event.key === 'Escape' && yearPickerVisible && !event.defaultPrevented) {
213
+ event.preventDefault()
214
+ showYears(false)
215
+ return
216
+ }
217
+ const target = event.target as Node
218
+ const onHeader = target === event.currentTarget || !!navigation?.contains(target)
219
+ const shortcut = mode === 'calendar' ? pickerShortcut(event) : undefined
220
+ if (shortcut === 'yearList') {
221
+ event.preventDefault()
222
+ showYears(!yearPickerVisible)
223
+ } else if (shortcut && shortcut !== 'monthList' && !yearPickerVisible && onHeader) {
224
+ event.preventDefault()
225
+ if (steps[shortcut]) setMonth(addMonths(monthDate, steps[shortcut]))
226
+ }
227
+ }
197
228
  </script>
198
229
 
199
230
  <Dialog
231
+ role="dialog"
200
232
  {...attributes}
233
+ bind:this={dialog}
201
234
  bind:element
235
+ bind:open
202
236
  aria-label={title}
203
237
  class={['np-date-picker-dialog', attributes.class]}
204
238
  --np-dialog-container-width="fit-content"
205
239
  --np-dialog-container-min-width="0"
206
240
  --np-dialog-padding="0"
241
+ --np-dialog-elevation="none"
242
+ tabindex={-1}
207
243
  --np-dialog-container-color="var(--np-date-picker-dialog-container-color, var(--np-color-surface-container-high))"
208
244
  --np-dialog-container-shape="var(--np-date-picker-dialog-container-shape, var(--np-shape-corner-extra-large))"
245
+ onkeydown={(event) => {
246
+ attributes.onkeydown?.(event)
247
+ handleKeydown(event)
248
+ }}
209
249
  ontoggle={(event) => {
210
- const nowOpen = event.newState === 'open'
211
- open = nowOpen
212
- if (nowOpen) {
250
+ if (event.newState === 'open') {
213
251
  exit.show()
214
252
  monthBeforeOpen = displayMonth
215
253
  confirming = false
216
254
  pending = value ?? undefined
217
- setMode('calendar')
218
- showYearPicker(false)
255
+ yearPickerVisible = false
219
256
  focusedDay = undefined
220
257
  syncText()
221
- focusCalendarWhenReady()
258
+ focusWhenReady()
222
259
  } else {
223
260
  if (!confirming) oncancel?.()
224
261
  confirming = false
@@ -228,7 +265,7 @@
228
265
  >
229
266
  <input class="np-date-picker-dialog-value" type="hidden" value={value ?? ''} {name} {form} />
230
267
  {#if exit.visible}
231
- <div class="np-date-picker-dialog-content">
268
+ <div class="np-date-picker-dialog-content" bind:this={content}>
232
269
  <div class="np-date-picker-dialog-header">
233
270
  <div class="np-date-picker-dialog-header-text">
234
271
  <span class="np-date-picker-dialog-title">{title}</span>
@@ -241,7 +278,6 @@
241
278
  onclick={() => {
242
279
  if (mode === 'calendar') syncText()
243
280
  setMode(mode === 'calendar' ? 'input' : 'calendar')
244
- showYearPicker(false)
245
281
  }}
246
282
  >
247
283
  {#if mode === 'calendar'}
@@ -255,7 +291,7 @@
255
291
  <Divider />
256
292
 
257
293
  {#if mode === 'input'}
258
- <div class={['np-date-picker-dialog-input', modeEnter && modeEnter]}>
294
+ <div class={['np-date-picker-dialog-input', modeEnter === 'input' && 'to-input']}>
259
295
  <TextField
260
296
  {label}
261
297
  {issues}
@@ -264,28 +300,35 @@
264
300
  aria-invalid={inputInvalid ? 'true' : undefined}
265
301
  oninput={handleInput}
266
302
  onblur={handleBlur}
303
+ onkeydown={(event) => {
304
+ if (event.key === 'Enter') handleBlur()
305
+ }}
267
306
  />
268
307
  </div>
269
308
  {:else}
270
- <div class="np-date-picker-dialog-navigation">
309
+ <div class="np-date-picker-dialog-navigation" bind:this={navigation}>
271
310
  <button
272
311
  type="button"
273
- class="np-date-picker-dialog-year-button"
312
+ class="np-date-picker-dialog-year-button np-focus-ring"
274
313
  aria-label="{selectYearLabel}, {formatMonthYear(monthDate, locale)}"
314
+ aria-describedby="{uid}-year-tip"
275
315
  aria-expanded={yearPickerVisible}
276
316
  aria-controls={yearPickerVisible ? `${uid}-years` : undefined}
277
- onclick={() => showYearPicker(!yearPickerVisible)}
317
+ onclick={() => (yearPickerVisible = !yearPickerVisible)}
278
318
  >
279
319
  <span aria-live="polite">{formatMonthYear(monthDate, locale)}</span>
280
320
  <span class={['np-date-picker-dialog-caret', yearPickerVisible && 'expanded']}>
281
321
  <ArrowDropDownIcon />
282
322
  </span>
323
+ <Ripple />
283
324
  </button>
325
+ <Tooltip id="{uid}-year-tip">{withShortcut(selectYearLabel, keys.yearList)}</Tooltip>
284
326
  {#if !yearPickerVisible}
285
327
  <div class="np-date-picker-dialog-arrows">
286
328
  <IconButton
287
329
  type="button"
288
330
  aria-label={previousMonthLabel}
331
+ title={withShortcut(previousMonthLabel, keys.previousMonth)}
289
332
  disabled={!canPreviousMonth}
290
333
  onclick={() => setMonth(addMonths(monthDate, -1))}
291
334
  >
@@ -294,6 +337,7 @@
294
337
  <IconButton
295
338
  type="button"
296
339
  aria-label={nextMonthLabel}
340
+ title={withShortcut(nextMonthLabel, keys.nextMonth)}
297
341
  disabled={!canNextMonth}
298
342
  onclick={() => setMonth(addMonths(monthDate, 1))}
299
343
  >
@@ -305,7 +349,6 @@
305
349
 
306
350
  {#if yearPickerVisible}
307
351
  <YearGrid
308
- class={yearEnter ? 'entering' : undefined}
309
352
  id="{uid}-years"
310
353
  aria-label={selectYearLabel}
311
354
  {yearRange}
@@ -316,12 +359,14 @@
316
359
  setMonth(
317
360
  new Date(year, clampMonthInYear(year, monthDate.getMonth(), minDate, maxDate), 1),
318
361
  )
319
- showYearPicker(false)
362
+ showYears(false)
320
363
  }}
321
364
  />
322
365
  <Divider />
323
366
  {:else}
324
- <div class={['np-date-picker-dialog-calendar', modeEnter && modeEnter]}>
367
+ <div
368
+ class={['np-date-picker-dialog-calendar', modeEnter === 'calendar' && 'to-calendar']}
369
+ >
325
370
  <Calendar
326
371
  month={monthDate}
327
372
  selected={pendingDate}
@@ -339,6 +384,7 @@
339
384
  pending = toISODate(date)
340
385
  focusedDay = date
341
386
  }}
387
+ onconfirm={confirm}
342
388
  onfocusday={(date) => {
343
389
  focusedDay = date
344
390
  if (
@@ -356,7 +402,7 @@
356
402
  {/if}
357
403
 
358
404
  {#snippet actions()}
359
- <Button type="button" variant="text" onclick={cancel}>{cancelLabel}</Button>
405
+ <Button type="button" variant="text" onclick={close}>{cancelLabel}</Button>
360
406
  <Button type="button" variant="text" disabled={!canConfirm} onclick={confirm}>
361
407
  {confirmLabel}
362
408
  </Button>
@@ -374,6 +420,10 @@
374
420
  padding: 0.5rem 0.75rem 0.75rem;
375
421
  }
376
422
 
423
+ :global(.np-date-picker-dialog:has(.np-date-picker-dialog-calendar) .np-dialog-actions) {
424
+ padding-top: 0.25rem;
425
+ }
426
+
377
427
  .np-date-picker-dialog-header {
378
428
  box-sizing: border-box;
379
429
  height: 7.5rem;
@@ -429,6 +479,7 @@
429
479
  border: 0;
430
480
  color: inherit;
431
481
  cursor: pointer;
482
+ position: relative;
432
483
  display: flex;
433
484
  align-items: center;
434
485
  gap: 0.25rem;
@@ -439,9 +490,11 @@
439
490
  line-height: 1.25rem;
440
491
  }
441
492
 
442
- .np-date-picker-dialog-year-button:focus-visible {
443
- outline: 3px solid var(--np-color-secondary);
444
- outline-offset: 2px;
493
+ .np-date-picker-dialog-year-button::before {
494
+ content: '';
495
+ position: absolute;
496
+ inset-block: -0.375rem;
497
+ inset-inline: 0;
445
498
  }
446
499
 
447
500
  .np-date-picker-dialog-caret {
@@ -460,7 +513,7 @@
460
513
  }
461
514
 
462
515
  .np-date-picker-dialog-calendar {
463
- padding-inline: 0.75rem;
516
+ padding: 0 0.75rem 0.25rem;
464
517
  }
465
518
 
466
519
  .np-date-picker-dialog-input {
@@ -471,14 +524,14 @@
471
524
  overflow: hidden;
472
525
  }
473
526
 
474
- .np-date-picker-dialog-input.to-input {
475
- transform: translateY(100%);
527
+ .np-date-picker-dialog-calendar.to-calendar {
528
+ transform: translateY(-3rem);
476
529
  opacity: 0;
477
530
  transition: none;
478
531
  }
479
532
 
480
- .np-date-picker-dialog-calendar.to-calendar {
481
- transform: translateY(-3rem);
533
+ .np-date-picker-dialog-input.to-input {
534
+ transform: translateY(100%);
482
535
  opacity: 0;
483
536
  transition: none;
484
537
  }
@@ -490,5 +543,12 @@
490
543
  transform var(--np-motion-expressive-default-spatial),
491
544
  opacity var(--np-motion-expressive-default-effects);
492
545
  }
546
+
547
+ .np-date-picker-dialog-content :global(.np-date-picker-year-grid) {
548
+ @starting-style {
549
+ height: 0;
550
+ opacity: 0.6;
551
+ }
552
+ }
493
553
  }
494
554
  </style>
@@ -1,7 +1,8 @@
1
+ import '../internal/focus-ring.css';
1
2
  import type { DatePickerDialogProps } from './types.js';
2
3
  declare const DatePickerDialog: import("svelte").Component<DatePickerDialogProps, {
3
- show: () => void;
4
- close: () => void;
5
- }, "element" | "value" | "open" | "displayMonth">;
4
+ show: () => any;
5
+ close: () => any;
6
+ }, "open" | "element" | "value" | "displayMonth" | "mode">;
6
7
  type DatePickerDialog = ReturnType<typeof DatePickerDialog>;
7
8
  export default DatePickerDialog;