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.
Files changed (136) hide show
  1. package/README.md +10 -1
  2. package/dist/animation.d.ts +2 -0
  3. package/dist/animation.js +33 -0
  4. package/dist/app-bar/AppBar.svelte +230 -0
  5. package/dist/app-bar/AppBar.svelte.d.ts +4 -0
  6. package/dist/app-bar/index.d.ts +1 -0
  7. package/dist/app-bar/index.js +1 -0
  8. package/dist/app-bar/types.d.ts +13 -0
  9. package/dist/app-bar/types.js +1 -0
  10. package/dist/autocomplete/AutoComplete.svelte +10 -11
  11. package/dist/autocomplete/AutoComplete.svelte.d.ts +1 -1
  12. package/dist/autocomplete/types.d.ts +1 -1
  13. package/dist/badge/Badge.svelte +6 -1
  14. package/dist/badge/types.d.ts +0 -1
  15. package/dist/button/Button.svelte +5 -15
  16. package/dist/button/IconButton.svelte +5 -15
  17. package/dist/button/SegmentedButton.svelte +15 -1
  18. package/dist/button/SplitButton.svelte +75 -0
  19. package/dist/button/SplitButton.svelte.d.ts +4 -0
  20. package/dist/button/index.d.ts +1 -0
  21. package/dist/button/index.js +1 -0
  22. package/dist/button/types.d.ts +17 -4
  23. package/dist/card/types.d.ts +1 -1
  24. package/dist/checkbox/Checkbox.svelte +47 -58
  25. package/dist/chip/AssistChip.svelte +5 -5
  26. package/dist/chip/ChipSet.svelte +3 -11
  27. package/dist/chip/FilterChip.svelte +33 -27
  28. package/dist/chip/InputChip.svelte +13 -2
  29. package/dist/chip/SuggestionChip.svelte +29 -0
  30. package/dist/chip/SuggestionChip.svelte.d.ts +4 -0
  31. package/dist/chip/index.d.ts +1 -0
  32. package/dist/chip/index.js +1 -0
  33. package/dist/chip/types.d.ts +16 -9
  34. package/dist/date-picker/Calendar.svelte +1 -1
  35. package/dist/date-picker/DatePickerDialog.svelte +23 -11
  36. package/dist/date-picker/DatePickerDialog.svelte.d.ts +4 -1
  37. package/dist/date-picker/DateRangePicker.svelte +40 -10
  38. package/dist/date-picker/DateRangePicker.svelte.d.ts +4 -1
  39. package/dist/date-picker/DockedDatePicker.svelte +13 -10
  40. package/dist/date-picker/DockedDatePicker.svelte.d.ts +4 -1
  41. package/dist/date-picker/DockedDateTimePicker.svelte +13 -7
  42. package/dist/date-picker/DockedDateTimePicker.svelte.d.ts +4 -1
  43. package/dist/date-picker/SelectionList.svelte +6 -32
  44. package/dist/date-picker/SelectionList.svelte.d.ts +2 -12
  45. package/dist/date-picker/TimeColumn.svelte +4 -29
  46. package/dist/date-picker/exitVisibility.svelte.d.ts +5 -0
  47. package/dist/date-picker/exitVisibility.svelte.js +23 -0
  48. package/dist/date-picker/optionList.d.ts +4 -0
  49. package/dist/date-picker/optionList.js +31 -0
  50. package/dist/date-picker/types.d.ts +11 -4
  51. package/dist/dialog/Dialog.svelte +55 -68
  52. package/dist/dialog/Dialog.svelte.d.ts +3 -3
  53. package/dist/dialog/types.d.ts +4 -3
  54. package/dist/fab/ExtendedFab.svelte +255 -0
  55. package/dist/fab/ExtendedFab.svelte.d.ts +5 -0
  56. package/dist/fab/Fab.svelte +211 -0
  57. package/dist/fab/Fab.svelte.d.ts +5 -0
  58. package/dist/fab/FabMenu.svelte +207 -0
  59. package/dist/fab/FabMenu.svelte.d.ts +7 -0
  60. package/dist/fab/index.d.ts +3 -0
  61. package/dist/fab/index.js +3 -0
  62. package/dist/fab/types.d.ts +34 -0
  63. package/dist/fab/types.js +1 -0
  64. package/dist/icons/ArrowBackIcon.svelte +13 -0
  65. package/dist/icons/ArrowBackIcon.svelte.d.ts +7 -0
  66. package/dist/icons/ChevronDownIcon.svelte +3 -0
  67. package/dist/icons/ChevronDownIcon.svelte.d.ts +26 -0
  68. package/dist/icons/SearchIcon.svelte +15 -0
  69. package/dist/icons/SearchIcon.svelte.d.ts +7 -0
  70. package/dist/icons/index.d.ts +3 -0
  71. package/dist/icons/index.js +3 -0
  72. package/dist/index.d.ts +6 -0
  73. package/dist/index.js +6 -0
  74. package/dist/internal/focus-ring.css +12 -0
  75. package/dist/loading-indicator/shapes.js +0 -7
  76. package/dist/menu/Menu.svelte +12 -7
  77. package/dist/menu/Menu.svelte.d.ts +2 -2
  78. package/dist/menu/types.d.ts +0 -2
  79. package/dist/navigation-bar/NavigationBar.svelte +59 -0
  80. package/dist/navigation-bar/NavigationBar.svelte.d.ts +4 -0
  81. package/dist/navigation-bar/NavigationBarItem.svelte +239 -0
  82. package/dist/navigation-bar/NavigationBarItem.svelte.d.ts +5 -0
  83. package/dist/navigation-bar/index.d.ts +2 -0
  84. package/dist/navigation-bar/index.js +2 -0
  85. package/dist/navigation-bar/types.d.ts +19 -0
  86. package/dist/navigation-bar/types.js +1 -0
  87. package/dist/navigation-drawer/NavigationDrawer.svelte +107 -76
  88. package/dist/navigation-drawer/NavigationDrawer.svelte.d.ts +4 -1
  89. package/dist/navigation-drawer/NavigationDrawerItem.svelte +10 -3
  90. package/dist/navigation-drawer/types.d.ts +3 -1
  91. package/dist/navigation-rail/NavigationRailItem.svelte +16 -0
  92. package/dist/navigation-rail/types.d.ts +3 -0
  93. package/dist/popover.svelte.d.ts +5 -0
  94. package/dist/popover.svelte.js +22 -0
  95. package/dist/press.svelte.d.ts +6 -0
  96. package/dist/press.svelte.js +32 -0
  97. package/dist/radio/Radio.svelte +26 -7
  98. package/dist/radio/types.d.ts +3 -0
  99. package/dist/search/Search.svelte +391 -0
  100. package/dist/search/Search.svelte.d.ts +5 -0
  101. package/dist/search/index.d.ts +1 -0
  102. package/dist/search/index.js +1 -0
  103. package/dist/search/types.d.ts +19 -0
  104. package/dist/search/types.js +1 -0
  105. package/dist/select/Select.svelte +48 -87
  106. package/dist/sheet/Sheet.svelte +235 -0
  107. package/dist/sheet/Sheet.svelte.d.ts +7 -0
  108. package/dist/sheet/index.d.ts +1 -0
  109. package/dist/sheet/index.js +1 -0
  110. package/dist/sheet/types.d.ts +11 -0
  111. package/dist/sheet/types.js +1 -0
  112. package/dist/slider/Slider.svelte +118 -30
  113. package/dist/slider/types.d.ts +3 -0
  114. package/dist/snackbar/Snackbar.svelte +32 -35
  115. package/dist/snackbar/Snackbar.svelte.d.ts +2 -2
  116. package/dist/snackbar/types.d.ts +3 -2
  117. package/dist/switch/Switch.svelte +51 -20
  118. package/dist/switch/types.d.ts +3 -0
  119. package/dist/tabs/Tab.svelte +4 -12
  120. package/dist/tabs/Tabs.svelte +5 -5
  121. package/dist/text-field/TextField.svelte +2 -4
  122. package/dist/toolbar/Toolbar.svelte +121 -0
  123. package/dist/toolbar/Toolbar.svelte.d.ts +4 -0
  124. package/dist/toolbar/index.d.ts +1 -0
  125. package/dist/toolbar/index.js +1 -0
  126. package/dist/toolbar/types.d.ts +8 -0
  127. package/dist/toolbar/types.js +1 -0
  128. package/dist/tooltip/RichTooltip.svelte +18 -12
  129. package/dist/tooltip/RichTooltip.svelte.d.ts +2 -2
  130. package/dist/tooltip/Tooltip.svelte +22 -11
  131. package/dist/tooltip/Tooltip.svelte.d.ts +4 -1
  132. package/dist/types.d.ts +6 -0
  133. package/dist/types.js +6 -0
  134. package/package.json +13 -13
  135. package/dist/date-picker/enterAnimation.d.ts +0 -1
  136. package/dist/date-picker/enterAnimation.js +0 -10
@@ -1,47 +1,46 @@
1
1
  <script lang="ts">
2
2
  import Button from '../button/Button.svelte'
3
3
  import IconButton from '../button/IconButton.svelte'
4
+ import { popoverController, syncOpenEffect } from '../popover.svelte.js'
4
5
  import type { SnackbarProps } from './types.js'
5
6
 
6
7
  let {
7
8
  label,
8
9
  supportingText,
9
10
  actionLabel,
10
- onActionClick,
11
+ onactionclick,
11
12
  icon,
12
- onIconClick = () => {
13
- element?.hidePopover()
14
- },
13
+ iconAriaLabel = 'Close',
14
+ oniconclick = () => close(),
15
15
  open = $bindable(false),
16
- onbeforetoggle,
16
+ ontoggle,
17
17
  timeout = 4000,
18
18
  element = $bindable(),
19
19
  popover = 'manual',
20
20
  ...attributes
21
21
  }: SnackbarProps = $props()
22
22
 
23
- let timeoutId: ReturnType<typeof setTimeout> | undefined
24
- const uid = $props.id()
25
-
26
- export const showPopover = () => {
27
- element?.showPopover()
28
- }
23
+ let hovered = $state(false)
24
+ let focused = $state(false)
29
25
 
30
- export const hidePopover = () => {
31
- element?.hidePopover()
32
- }
26
+ const uid = $props.id()
27
+ const controller = popoverController(() => element)
33
28
 
34
- const startTimer = () => {
35
- clearTimeout(timeoutId)
36
- if (!open || timeout <= 0) return
37
- timeoutId = setTimeout(() => {
38
- element?.hidePopover()
39
- }, timeout)
40
- }
29
+ export const show = () => controller.show()
30
+ export const close = () => controller.close()
41
31
 
42
- const pauseTimer = () => clearTimeout(timeoutId)
32
+ syncOpenEffect(
33
+ () => element,
34
+ () => open,
35
+ show,
36
+ close,
37
+ )
43
38
 
44
- $effect(() => () => clearTimeout(timeoutId))
39
+ $effect(() => {
40
+ if (!open || hovered || focused || timeout <= 0) return
41
+ const timeoutId = setTimeout(close, timeout)
42
+ return () => clearTimeout(timeoutId)
43
+ })
45
44
  </script>
46
45
 
47
46
  <div
@@ -51,15 +50,13 @@
51
50
  bind:this={element}
52
51
  role="alert"
53
52
  aria-labelledby="np-snackbar-label-{uid}"
54
- onpointerenter={pauseTimer}
55
- onpointerleave={startTimer}
56
- onfocusin={pauseTimer}
57
- onfocusout={startTimer}
58
- onbeforetoggle={(event) => {
59
- let { newState } = event
60
- open = newState === 'open'
61
- startTimer()
62
- onbeforetoggle?.(event)
53
+ onpointerenter={() => (hovered = true)}
54
+ onpointerleave={() => (hovered = false)}
55
+ onfocusin={() => (focused = true)}
56
+ onfocusout={() => (focused = false)}
57
+ ontoggle={(event) => {
58
+ open = event.newState === 'open'
59
+ ontoggle?.(event)
63
60
  }}
64
61
  >
65
62
  <div class="np-snackbar-inner">
@@ -74,7 +71,7 @@
74
71
  variant="text"
75
72
  --np-text-button-label-text-color="var(--np-snackbar-action-color, var(--np-color-inverse-primary))"
76
73
  aria-label={actionLabel}
77
- onclick={onActionClick}
74
+ onclick={onactionclick}
78
75
  >
79
76
  {actionLabel}
80
77
  </Button>
@@ -83,8 +80,8 @@
83
80
  <div class="np-snackbar-icon-container">
84
81
  <IconButton
85
82
  --np-icon-button-icon-color="var(--np-snackbar-text-color, var(--np-color-inverse-on-surface))"
86
- aria-label="Close"
87
- onclick={onIconClick}
83
+ aria-label={iconAriaLabel}
84
+ onclick={oniconclick}
88
85
  >
89
86
  {@render icon()}</IconButton
90
87
  >
@@ -1,7 +1,7 @@
1
1
  import type { SnackbarProps } from './types.ts';
2
2
  declare const Snackbar: import("svelte").Component<SnackbarProps, {
3
- showPopover: () => void;
4
- hidePopover: () => void;
3
+ show: () => void;
4
+ close: () => void;
5
5
  }, "element" | "open">;
6
6
  type Snackbar = ReturnType<typeof Snackbar>;
7
7
  export default Snackbar;
@@ -5,9 +5,10 @@ export interface SnackbarProps extends HTMLAttributes<HTMLDivElement> {
5
5
  open?: boolean;
6
6
  supportingText?: string | undefined;
7
7
  actionLabel?: string | undefined;
8
- onActionClick?: (event: Event) => void;
8
+ onactionclick?: (event: Event) => void;
9
9
  icon?: Snippet | undefined;
10
- onIconClick?: (event: Event) => void;
10
+ oniconclick?: (event: Event) => void;
11
+ iconAriaLabel?: string;
11
12
  timeout?: number;
12
13
  element?: HTMLElement;
13
14
  popover?: 'auto' | 'manual';
@@ -10,11 +10,23 @@
10
10
  inputElement = $bindable(),
11
11
  icons,
12
12
  onkeyup,
13
+ issues,
14
+ 'aria-invalid': ariaInvalid,
13
15
  ...attributes
14
16
  }: SwitchProps = $props()
17
+
18
+ let hasError = $derived(!!issues?.length)
15
19
  </script>
16
20
 
17
- <div bind:this={element} class={['np-switch', disabled && 'np-disabled', attributes.class]}>
21
+ <div
22
+ bind:this={element}
23
+ class={[
24
+ 'np-switch',
25
+ disabled && 'np-disabled',
26
+ hasError && !disabled && 'np-error',
27
+ attributes.class,
28
+ ]}
29
+ >
18
30
  <div class="np-track"></div>
19
31
  <div class={['np-handle', icons === 'both' && 'both-icons']}>
20
32
  {#if icons}
@@ -57,6 +69,7 @@
57
69
  bind:this={inputElement}
58
70
  bind:checked={selected}
59
71
  {disabled}
72
+ aria-invalid={hasError ? 'true' : ariaInvalid}
60
73
  />
61
74
  </div>
62
75
 
@@ -78,7 +91,7 @@
78
91
  width: 3.25rem;
79
92
  height: 2rem;
80
93
  background-color: var(
81
- --np-comp-switch-unselected-track-color,
94
+ --np-switch-unselected-track-color,
82
95
  var(--np-color-surface-container-highest)
83
96
  );
84
97
  border-radius: var(--np-shape-corner-full);
@@ -86,7 +99,7 @@
86
99
  background-color 0.2s,
87
100
  outline-color 0.2s;
88
101
  outline-width: 0.125rem;
89
- outline-color: var(--np-comp-switch-unselected-track-outline-color, var(--np-color-outline));
102
+ outline-color: var(--np-switch-unselected-track-outline-color, var(--np-color-outline));
90
103
  outline-style: solid;
91
104
  outline-offset: -0.125rem;
92
105
  }
@@ -100,8 +113,8 @@
100
113
  transition:
101
114
  transform var(--np-motion-expressive-fast-spatial),
102
115
  background-color var(--np-motion-expressive-default-effects);
103
- background-color: var(--np-comp-switch-unselected-handle-color, var(--np-color-outline));
104
- border-radius: var(--np-comp-switch-handle-shape, var(--np-shape-corner-full));
116
+ background-color: var(--np-switch-unselected-handle-color, var(--np-color-outline));
117
+ border-radius: var(--np-switch-handle-shape, var(--np-shape-corner-full));
105
118
  }
106
119
 
107
120
  .np-handle.both-icons {
@@ -110,12 +123,12 @@
110
123
 
111
124
  .np-state-layer {
112
125
  position: relative;
113
- width: var(--np-comp-switch-state-layer-size, 2.5rem);
114
- height: var(--np-comp-switch-state-layer-size, 2.5rem);
126
+ width: var(--np-switch-state-layer-size, 2.5rem);
127
+ height: var(--np-switch-state-layer-size, 2.5rem);
115
128
  margin-block-start: -0.25rem;
116
129
  margin-inline-start: -0.25rem;
117
130
  transition: var(--np-motion-expressive-fast-spatial);
118
- border-radius: var(--np-comp-switch-state-layer-shape, var(--np-shape-corner-full));
131
+ border-radius: var(--np-switch-state-layer-shape, var(--np-shape-corner-full));
119
132
  }
120
133
 
121
134
  .np-switch:has(input:checked) .np-state-layer {
@@ -152,37 +165,55 @@
152
165
 
153
166
  .np-switch:has(input:checked) .np-handle {
154
167
  transform: translateX(1.25rem) scale(1.5);
155
- color: var(--np-comp-switch-selected-icon-color, var(--np-color-primary));
156
- background-color: var(--np-comp-switch-selected-handle-color, var(--np-color-on-primary));
168
+ color: var(--np-switch-selected-icon-color, var(--np-color-primary));
169
+ background-color: var(--np-switch-selected-handle-color, var(--np-color-on-primary));
157
170
  }
158
171
 
159
172
  .np-disabled .np-handle {
160
- opacity: var(--np-comp-switch-disabled-unselected-handle-opacity, 0.38);
173
+ opacity: var(--np-switch-disabled-unselected-handle-opacity, 0.38);
161
174
  }
162
175
 
163
176
  .np-switch.np-disabled:has(input:checked) .np-handle {
164
- opacity: var(--np-comp-switch-disabled-selected-handle-opacity, 1);
165
- background-color: var(--np-comp-switch-selected-handle-color, var(--np-color-surface));
177
+ opacity: var(--np-switch-disabled-selected-handle-opacity, 1);
178
+ background-color: var(--np-switch-selected-handle-color, var(--np-color-surface));
166
179
  }
167
180
 
168
181
  .np-switch:has(input:checked) .np-track {
169
- background-color: var(--np-comp-switch-selected-track-color, var(--np-color-primary));
182
+ background-color: var(--np-switch-selected-track-color, var(--np-color-primary));
170
183
  outline-color: transparent;
171
184
  }
172
185
 
186
+ .np-error .np-track {
187
+ outline-color: var(--np-color-error);
188
+ }
189
+
190
+ .np-error:has(input:checked) .np-track {
191
+ background-color: var(--np-color-error);
192
+ }
193
+
194
+ .np-error:has(input:checked) .np-handle {
195
+ background-color: var(--np-color-on-error);
196
+ }
197
+
198
+ .np-error:has(input:checked) .np-switch-icon {
199
+ fill: var(--np-color-error);
200
+ }
201
+
202
+ .np-error {
203
+ --np-ripple-hover-color: var(--np-color-error);
204
+ --np-ripple-pressed-color: var(--np-color-error);
205
+ }
206
+
173
207
  .np-disabled .np-track {
174
- opacity: var(--np-comp-switch-disabled-track-opacity, 0.12);
208
+ opacity: var(--np-switch-disabled-track-opacity, 0.12);
175
209
  background-color: var(
176
- --np-comp-switch-disabled-unselected-track-color,
210
+ --np-switch-disabled-unselected-track-color,
177
211
  var(--np-color-surface-container-highest)
178
212
  );
179
213
  }
180
214
 
181
215
  .np-switch.np-disabled:has(input:checked) .np-track {
182
- background-color: var(
183
- --np-comp-switch-disabled-selected-track-color,
184
- var(--np-color-on-surface)
185
- );
216
+ background-color: var(--np-switch-disabled-selected-track-color, var(--np-color-on-surface));
186
217
  }
187
218
 
188
219
  .np-disabled {
@@ -5,4 +5,7 @@ export interface SwitchProps extends Omit<HTMLInputAttributes, 'type' | 'role' |
5
5
  icons?: 'selected' | 'both';
6
6
  inputElement?: HTMLInputElement;
7
7
  element?: HTMLDivElement;
8
+ issues?: {
9
+ message: string;
10
+ }[];
8
11
  }
@@ -2,7 +2,6 @@
2
2
  import '../internal/focus-ring.css'
3
3
  import Badge from '../badge/Badge.svelte'
4
4
  import Ripple from '../ripple/Ripple.svelte'
5
- import { tick } from 'svelte'
6
5
  import { getTabsContext } from './context.js'
7
6
  import type { TabProps } from './types.js'
8
7
 
@@ -29,11 +28,6 @@
29
28
  tabsContext.indicatorValue = value
30
29
  }
31
30
  })
32
-
33
- const setIndicatorValue = async () => {
34
- await tick()
35
- tabsContext.indicatorValue = value
36
- }
37
31
  </script>
38
32
 
39
33
  {#snippet content()}
@@ -47,7 +41,7 @@
47
41
  {#if icon}
48
42
  {#if badge && tabsContext.variant === 'primary' && !inlineIcon}
49
43
  <div class="np-tab-icon-badge">
50
- <Badge label={badgeLabel} ariaLabel={badgeAriaLabel} />
44
+ <Badge label={badgeLabel} aria-label={badgeAriaLabel} />
51
45
  {@render icon?.()}
52
46
  </div>
53
47
  {:else}
@@ -58,7 +52,7 @@
58
52
  <div style="--np-badge-position:static;">
59
53
  <span class="np-tab-label-badge">{@render children?.()}</span><Badge
60
54
  label={badgeLabel}
61
- ariaLabel={badgeAriaLabel}
55
+ aria-label={badgeAriaLabel}
62
56
  />
63
57
  </div>
64
58
  {:else}
@@ -116,13 +110,11 @@
116
110
  ]}
117
111
  onclick={(event) => {
118
112
  tabsContext.value = value
119
- setIndicatorValue()
120
113
  onclick?.(event)
121
114
  }}
122
115
  onkeydown={(event) => {
123
116
  if (event.key === 'Enter' || event.key === ' ') {
124
117
  tabsContext.value = value
125
- setIndicatorValue()
126
118
  }
127
119
  onkeydown?.(event)
128
120
  }}
@@ -205,8 +197,8 @@
205
197
  @supports not (anchor-name: --np-tab-indicator) {
206
198
  .np-tab-content-active .np-indicator {
207
199
  background-color: var(--np-color-primary);
208
- border-start-start-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
209
- border-start-end-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
200
+ border-start-start-radius: var(--np-tabs-indicator-radius, var(--np-shape-corner-full));
201
+ border-start-end-radius: var(--np-tabs-indicator-radius, var(--np-shape-corner-full));
210
202
  }
211
203
  }
212
204
 
@@ -1,4 +1,5 @@
1
1
  <script lang="ts">
2
+ import { untrack } from 'svelte'
2
3
  import Divider from '../divider/Divider.svelte'
3
4
  import { arrowKeyNav, rovingTabindex } from '../keyboard-nav.js'
4
5
  import { setTabsContext } from './context.js'
@@ -12,11 +13,10 @@
12
13
  ...attributes
13
14
  }: TabsProps = $props()
14
15
 
15
- // svelte-ignore state_referenced_locally
16
16
  let tabsContext = $state<TabsContext>({
17
17
  value,
18
18
  indicatorValue: value,
19
- variant,
19
+ variant: untrack(() => variant),
20
20
  })
21
21
  $effect(() => {
22
22
  value = tabsContext.value
@@ -30,7 +30,7 @@
30
30
 
31
31
  const secondaryStyle = $derived(
32
32
  tabsContext.variant === 'secondary'
33
- ? '--np-indicator-radius: 0;--_indicator-gap: 0;--_indicator-height: 2px'
33
+ ? '--np-tabs-indicator-radius: 0;--_indicator-gap: 0;--_indicator-height: 2px'
34
34
  : '',
35
35
  )
36
36
 
@@ -77,8 +77,8 @@
77
77
  right: anchor(right);
78
78
  bottom: anchor(bottom);
79
79
  background-color: var(--np-color-primary);
80
- border-start-start-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
81
- border-start-end-radius: var(--np-indicator-radius, var(--np-shape-corner-full));
80
+ border-start-start-radius: var(--np-tabs-indicator-radius, var(--np-shape-corner-full));
81
+ border-start-end-radius: var(--np-tabs-indicator-radius, var(--np-shape-corner-full));
82
82
  position-anchor: --np-tab-indicator;
83
83
 
84
84
  @media (prefers-reduced-motion: no-preference) {
@@ -33,8 +33,6 @@
33
33
  const uid = $props.id()
34
34
  let errorText = $derived(issues?.map((issue) => issue.message).join(', '))
35
35
 
36
- // Merged rather than set before the spread, so a consumer's own aria wiring adds to the
37
- // supporting-text wiring instead of silently replacing it.
38
36
  const supportingTextId = `supporting-text-${uid}`
39
37
  const ids = (...values: (string | undefined | null | false)[]) =>
40
38
  values.filter(Boolean).join(' ') || undefined
@@ -54,7 +52,7 @@
54
52
  (children ? '--top-space:2rem;--bottom-space:1rem;' : '')) +
55
53
  `--_min-height:calc(${minLines} * 1lh);--_max-height:${`calc(${maxLines} * 1lh)`};` +
56
54
  style}
57
- class={['text-field', attributes.class]}
55
+ class={['np-text-field', attributes.class]}
58
56
  bind:this={element}
59
57
  bind:clientWidth
60
58
  bind:clientHeight
@@ -279,7 +277,7 @@
279
277
  height: 100%;
280
278
  position: relative;
281
279
  }
282
- .text-field {
280
+ .np-text-field {
283
281
  display: inline-flex;
284
282
  text-align: start;
285
283
  }
@@ -0,0 +1,121 @@
1
+ <script lang="ts">
2
+ import { arrowKeyNav, rovingTabindex } from '../keyboard-nav.js'
3
+ import type { ToolbarProps } from './types.js'
4
+
5
+ let {
6
+ variant = 'docked',
7
+ placement = 'bottom',
8
+ orientation = 'horizontal',
9
+ color = 'standard',
10
+ children,
11
+ element = $bindable(),
12
+ onkeydown: userKeydown,
13
+ ...attributes
14
+ }: ToolbarProps = $props()
15
+
16
+ const ITEMS = 'button, a[href], input:not([type="hidden"])'
17
+ const attach = rovingTabindex(ITEMS)
18
+ const arrowHandler = $derived(arrowKeyNav(ITEMS, orientation))
19
+
20
+ const handleKeydown = (event: KeyboardEvent & { currentTarget: EventTarget & HTMLElement }) => {
21
+ userKeydown?.(event)
22
+ if (!event.defaultPrevented) arrowHandler(event)
23
+ }
24
+ </script>
25
+
26
+ <div
27
+ {...attributes}
28
+ {@attach attach}
29
+ bind:this={element}
30
+ role="toolbar"
31
+ aria-orientation={orientation}
32
+ class={[
33
+ 'np-toolbar',
34
+ `np-toolbar-${variant}`,
35
+ variant === 'floating' && `np-toolbar-${placement}`,
36
+ variant === 'floating' && color === 'vibrant' && 'np-toolbar-vibrant',
37
+ orientation === 'vertical' && 'np-toolbar-vertical',
38
+ attributes.class,
39
+ ]}
40
+ onkeydown={handleKeydown}
41
+ >
42
+ {@render children?.()}
43
+ </div>
44
+
45
+ <style>
46
+ .np-toolbar {
47
+ display: flex;
48
+ align-items: center;
49
+ box-sizing: border-box;
50
+ gap: var(--np-toolbar-gap, 0.25rem);
51
+ color: var(--np-toolbar-color, var(--np-color-on-surface));
52
+ --np-icon-button-icon-color: var(--np-toolbar-color, var(--np-color-on-surface-variant));
53
+ }
54
+
55
+ .np-toolbar-vertical {
56
+ flex-direction: column;
57
+ --np-tooltip-position-area: inline-end;
58
+ --np-tooltip-justify-self: auto;
59
+ --np-tooltip-align-self: anchor-center;
60
+ --np-tooltip-margin: 0 4px;
61
+ --np-tooltip-position-try-fallbacks: flip-inline;
62
+ --np-rich-tooltip-position-area: inline-end;
63
+ --np-rich-tooltip-justify-self: auto;
64
+ --np-rich-tooltip-align-self: anchor-center;
65
+ --np-rich-tooltip-margin: 0 4px;
66
+ --np-rich-tooltip-position-try-fallbacks: flip-inline;
67
+ }
68
+
69
+ .np-toolbar-docked {
70
+ width: 100%;
71
+ min-height: 4rem;
72
+ justify-content: center;
73
+ padding-inline: 0.5rem;
74
+ background-color: var(--np-toolbar-container-color, var(--np-color-surface-container));
75
+ padding-block-end: max(0px, env(safe-area-inset-bottom));
76
+ }
77
+ .np-toolbar-docked.np-toolbar-vertical {
78
+ width: auto;
79
+ height: 100%;
80
+ min-height: 0;
81
+ min-width: 4rem;
82
+ padding-block: 0.5rem;
83
+ padding-inline: 0;
84
+ }
85
+
86
+ .np-toolbar-floating {
87
+ position: sticky;
88
+ z-index: 8;
89
+ width: fit-content;
90
+ margin-inline: auto;
91
+ padding: 0.5rem;
92
+ border-radius: var(--np-toolbar-shape, var(--np-shape-corner-full));
93
+ background-color: var(--np-toolbar-container-color, var(--np-color-surface-container));
94
+ box-shadow: var(--np-toolbar-elevation, var(--np-elevation-3));
95
+ }
96
+
97
+ .np-toolbar-bottom {
98
+ inset-block-end: var(--np-toolbar-inset, 1rem);
99
+ }
100
+ .np-toolbar-top {
101
+ inset-block-start: var(--np-toolbar-inset, 1rem);
102
+ }
103
+ .np-toolbar-start,
104
+ .np-toolbar-end {
105
+ margin-inline: 0;
106
+ margin-block: auto;
107
+ }
108
+ .np-toolbar-start {
109
+ inset-inline-start: var(--np-toolbar-inset, 1rem);
110
+ }
111
+ .np-toolbar-end {
112
+ inset-inline-end: var(--np-toolbar-inset, 1rem);
113
+ margin-inline-start: auto;
114
+ }
115
+
116
+ .np-toolbar-vibrant {
117
+ background-color: var(--np-toolbar-container-color, var(--np-color-primary-container));
118
+ --np-toolbar-color: var(--np-color-on-primary-container);
119
+ color: var(--np-toolbar-color);
120
+ }
121
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ToolbarProps } from './types.ts';
2
+ declare const Toolbar: import("svelte").Component<ToolbarProps, {}, "element">;
3
+ type Toolbar = ReturnType<typeof Toolbar>;
4
+ export default Toolbar;
@@ -0,0 +1 @@
1
+ export { default as Toolbar } from './Toolbar.svelte';
@@ -0,0 +1 @@
1
+ export { default as Toolbar } from './Toolbar.svelte';
@@ -0,0 +1,8 @@
1
+ import type { HTMLAttributes } from 'svelte/elements';
2
+ export interface ToolbarProps extends HTMLAttributes<HTMLElement> {
3
+ variant?: 'docked' | 'floating';
4
+ placement?: 'bottom' | 'top' | 'start' | 'end';
5
+ orientation?: 'horizontal' | 'vertical';
6
+ color?: 'standard' | 'vibrant';
7
+ element?: HTMLElement;
8
+ }
@@ -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 { RichTooltipProps } from './types.js'
3
4
 
4
5
  let {
@@ -13,23 +14,27 @@
13
14
  }: RichTooltipProps = $props()
14
15
 
15
16
  const findControl = () =>
16
- id ? (document.querySelector<HTMLElement>(`[popovertarget="${id}"]`) ?? undefined) : undefined
17
+ id
18
+ ? (document.querySelector<HTMLElement>(`[commandfor="${id}"], [popovertarget="${id}"]`) ??
19
+ undefined)
20
+ : undefined
17
21
 
18
- export const showPopover = () => {
22
+ const controller = popoverController(() => element)
23
+
24
+ export const show = () => {
19
25
  if (!element || element.matches(':popover-open')) return
20
26
  const source = findControl()
21
27
  element.showPopover(source ? { source } : undefined)
22
28
  }
23
29
 
24
- export const hidePopover = () => {
25
- element?.hidePopover()
26
- }
30
+ export const close = () => controller.close()
27
31
 
28
- $effect(() => {
29
- if (!element) return
30
- if (open === true) showPopover()
31
- else if (open === false) hidePopover()
32
- })
32
+ syncOpenEffect(
33
+ () => element,
34
+ () => open,
35
+ show,
36
+ close,
37
+ )
33
38
  </script>
34
39
 
35
40
  <div
@@ -68,7 +73,7 @@
68
73
  max-width: 20rem;
69
74
  word-wrap: break-word;
70
75
  overflow-wrap: break-word;
71
- margin: 4px 0;
76
+ margin: var(--np-rich-tooltip-margin, 4px 0);
72
77
  padding: 0.25rem 1rem;
73
78
  border: none;
74
79
  border-radius: var(--np-shape-corner-medium);
@@ -78,8 +83,9 @@
78
83
  font-size: 0.875rem;
79
84
  line-height: 1.25rem;
80
85
  justify-self: var(--np-rich-tooltip-justify-self, anchor-center);
86
+ align-self: var(--np-rich-tooltip-align-self, auto);
81
87
  position-area: var(--np-rich-tooltip-position-area, bottom);
82
- position-try-fallbacks: flip-block;
88
+ position-try-fallbacks: var(--np-rich-tooltip-position-try-fallbacks, flip-block);
83
89
  }
84
90
  .np-rich-tooltip-with-subhead[popover] {
85
91
  padding-block: 0.75rem 1rem;
@@ -1,7 +1,7 @@
1
1
  import type { RichTooltipProps } from './types.ts';
2
2
  declare const RichTooltip: import("svelte").Component<RichTooltipProps, {
3
- showPopover: () => void;
4
- hidePopover: () => void;
3
+ show: () => void;
4
+ close: () => void;
5
5
  }, "element" | "open">;
6
6
  type RichTooltip = ReturnType<typeof RichTooltip>;
7
7
  export default RichTooltip;