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
@@ -2,3 +2,4 @@ export { default as Button } from './Button.svelte';
2
2
  export { default as ButtonGroup } from './ButtonGroup.svelte';
3
3
  export { default as IconButton } from './IconButton.svelte';
4
4
  export { default as SegmentedButton } from './SegmentedButton.svelte';
5
+ export { default as SplitButton } from './SplitButton.svelte';
@@ -2,3 +2,4 @@ export { default as Button } from './Button.svelte';
2
2
  export { default as ButtonGroup } from './ButtonGroup.svelte';
3
3
  export { default as IconButton } from './IconButton.svelte';
4
4
  export { default as SegmentedButton } from './SegmentedButton.svelte';
5
+ export { default as SplitButton } from './SplitButton.svelte';
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
- import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements';
2
+ import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes, MouseEventHandler } from 'svelte/elements';
3
3
  export type ButtonElement = HTMLButtonElement | HTMLAnchorElement;
4
- interface BaseButtonProps extends HTMLAttributes<ButtonElement>, Omit<HTMLButtonAttributes, keyof HTMLAttributes<HTMLButtonElement> | 'type'>, Omit<HTMLAnchorAttributes, keyof HTMLAttributes<HTMLAnchorElement> | 'type'> {
4
+ export interface BaseButtonProps extends HTMLAttributes<ButtonElement>, Omit<HTMLButtonAttributes, keyof HTMLAttributes<HTMLButtonElement> | 'type'>, Omit<HTMLAnchorAttributes, keyof HTMLAttributes<HTMLAnchorElement> | 'type'> {
5
5
  element?: HTMLElement;
6
6
  disabled?: boolean | null;
7
7
  loading?: boolean;
@@ -27,7 +27,18 @@ export interface ButtonGroupProps extends HTMLAttributes<HTMLDivElement> {
27
27
  expandedRatio?: number;
28
28
  compressionLimit?: number;
29
29
  element?: HTMLElement;
30
- children?: Snippet;
30
+ }
31
+ export interface SplitButtonProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onclick'> {
32
+ label?: string;
33
+ icon?: Snippet;
34
+ menu?: Snippet<[string]>;
35
+ variant?: Exclude<ButtonProps['variant'], 'text'>;
36
+ size?: BaseButtonProps['size'];
37
+ disabled?: boolean | null;
38
+ open?: boolean;
39
+ menuLabel?: string;
40
+ onclick?: MouseEventHandler<ButtonElement>;
41
+ element?: HTMLElement;
31
42
  }
32
43
  export interface SegmentedButtonProps extends HTMLAttributes<HTMLDivElement> {
33
44
  name: string;
@@ -42,5 +53,7 @@ export interface SegmentedButtonProps extends HTMLAttributes<HTMLDivElement> {
42
53
  }[];
43
54
  group?: string | number | (string | number)[] | null;
44
55
  element?: HTMLElement;
56
+ issues?: {
57
+ message: string;
58
+ }[];
45
59
  }
46
- export {};
@@ -3,7 +3,7 @@ import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes } from
3
3
  export type CardElement = HTMLDivElement | HTMLButtonElement | HTMLAnchorElement;
4
4
  export interface CardProps extends HTMLAttributes<CardElement>, Omit<HTMLButtonAttributes, keyof HTMLAttributes<HTMLButtonElement> | 'type'>, Omit<HTMLAnchorAttributes, keyof HTMLAttributes<HTMLAnchorElement> | 'type'> {
5
5
  variant?: 'elevated' | 'filled' | 'outlined';
6
- disabled?: boolean;
6
+ disabled?: boolean | null;
7
7
  image?: string | null;
8
8
  element?: HTMLElement;
9
9
  headline?: string | null;
@@ -21,9 +21,8 @@
21
21
  let groupValue = $derived(
22
22
  typeof value === 'string' || typeof value === 'number' ? value : undefined,
23
23
  )
24
- let grouped = $derived(Array.isArray(group) && groupValue !== undefined)
25
- let groupChecked = $derived(
26
- Array.isArray(group) && groupValue !== undefined ? group.includes(groupValue) : false,
24
+ let isChecked = $derived(
25
+ Array.isArray(group) && groupValue !== undefined ? group.includes(groupValue) : checked,
27
26
  )
28
27
 
29
28
  const onchange = (event: Event & { currentTarget: EventTarget & HTMLInputElement }) => {
@@ -42,7 +41,11 @@
42
41
 
43
42
  <div
44
43
  {style}
45
- class={['np-container', hasError && !attributes.disabled && 'np-error', attributes.class]}
44
+ class={[
45
+ 'np-checkbox-container',
46
+ hasError && !attributes.disabled && 'np-error',
47
+ attributes.class,
48
+ ]}
46
49
  bind:this={element}
47
50
  >
48
51
  <div class="np-outline"></div>
@@ -55,37 +58,23 @@
55
58
  {#if !attributes.disabled}
56
59
  <Ripple forElement={inputEl} />
57
60
  {/if}
58
- {#if grouped}
59
- <input
60
- {...attributes}
61
- {value}
62
- class="np-input"
63
- type="checkbox"
64
- bind:indeterminate
65
- bind:this={inputEl}
66
- checked={groupChecked}
67
- {onchange}
68
- aria-invalid={hasError ? 'true' : ariaInvalid}
69
- aria-checked={indeterminate ? 'mixed' : undefined}
70
- />
71
- {:else}
72
- <input
73
- {...attributes}
74
- {value}
75
- class="np-input"
76
- type="checkbox"
77
- bind:indeterminate
78
- bind:checked
79
- bind:this={inputEl}
80
- aria-invalid={hasError ? 'true' : ariaInvalid}
81
- aria-checked={indeterminate ? 'mixed' : undefined}
82
- />
83
- {/if}
61
+ <input
62
+ {...attributes}
63
+ {value}
64
+ class="np-input"
65
+ type="checkbox"
66
+ bind:indeterminate
67
+ bind:this={inputEl}
68
+ checked={isChecked}
69
+ {onchange}
70
+ aria-invalid={hasError ? 'true' : ariaInvalid}
71
+ aria-checked={indeterminate ? 'mixed' : undefined}
72
+ />
84
73
  </div>
85
74
  </div>
86
75
 
87
76
  <style>
88
- .np-container {
77
+ .np-checkbox-container {
89
78
  border-radius: var(--np-checkbox-container-shape, 2px);
90
79
  display: inline-flex;
91
80
  place-content: center;
@@ -102,7 +91,7 @@
102
91
  :global(label) {
103
92
  -webkit-tap-highlight-color: transparent;
104
93
  }
105
- .np-container:has(input:disabled) {
94
+ .np-checkbox-container:has(input:disabled) {
106
95
  cursor: default;
107
96
  }
108
97
  .np-input {
@@ -148,18 +137,18 @@
148
137
  border-width: 2px;
149
138
  box-sizing: border-box;
150
139
  }
151
- .np-container:focus-within .np-outline,
152
- .np-container:hover .np-outline {
140
+ .np-checkbox-container:focus-within .np-outline,
141
+ .np-checkbox-container:hover .np-outline {
153
142
  border-color: var(--np-color-on-surface);
154
143
  border-width: 2px;
155
144
  }
156
- .np-container:has(input:disabled) .np-outline {
145
+ .np-checkbox-container:has(input:disabled) .np-outline {
157
146
  border-color: var(--np-color-on-surface);
158
147
  border-width: 2px;
159
148
  opacity: 0.38;
160
149
  }
161
- .np-container:has(input:disabled:checked) .np-outline,
162
- .np-container:has(input:disabled:indeterminate) .np-outline {
150
+ .np-checkbox-container:has(input:disabled:checked) .np-outline,
151
+ .np-checkbox-container:has(input:disabled:indeterminate) .np-outline {
163
152
  visibility: hidden;
164
153
  }
165
154
  .np-background {
@@ -173,17 +162,17 @@
173
162
  transition-timing-function: cubic-bezier(0.3, 0, 0.8, 0.15), linear;
174
163
  transform: scale(0.6);
175
164
  }
176
- .np-container:has(input:indeterminate) .np-background,
177
- .np-container:has(input:checked) .np-background,
178
- .np-container:has(input:indeterminate) .np-icon,
179
- .np-container:has(input:checked) .np-icon {
165
+ .np-checkbox-container:has(input:indeterminate) .np-background,
166
+ .np-checkbox-container:has(input:checked) .np-background,
167
+ .np-checkbox-container:has(input:indeterminate) .np-icon,
168
+ .np-checkbox-container:has(input:checked) .np-icon {
180
169
  opacity: 1;
181
170
  transition-duration: 350ms, 50ms;
182
171
  transition-timing-function: cubic-bezier(0.05, 0.7, 0.1, 1), linear;
183
172
  transform: scale(1);
184
173
  }
185
- .np-container:has(input:disabled:checked) .np-background,
186
- .np-container:has(input:disabled:indeterminate) .np-background {
174
+ .np-checkbox-container:has(input:disabled:checked) .np-background,
175
+ .np-checkbox-container:has(input:disabled:indeterminate) .np-background {
187
176
  background: var(--np-color-on-surface);
188
177
  opacity: 0.38;
189
178
  }
@@ -208,23 +197,23 @@
208
197
  height: 18px;
209
198
  width: 18px;
210
199
  }
211
- .np-container:has(input:disabled) .np-icon {
200
+ .np-checkbox-container:has(input:disabled) .np-icon {
212
201
  fill: var(--np-color-surface);
213
202
  }
214
- .np-container:has(input:checked) .mark.short,
215
- .np-container:has(input:not(:checked):not(:indeterminate)) .mark.short {
203
+ .np-checkbox-container:has(input:checked) .mark.short,
204
+ .np-checkbox-container:has(input:not(:checked):not(:indeterminate)) .mark.short {
216
205
  height: 5.6568542495px;
217
206
  }
218
- .np-container:has(input:indeterminate) .mark,
219
- .np-container:has(input:checked) .mark {
207
+ .np-checkbox-container:has(input:indeterminate) .mark,
208
+ .np-checkbox-container:has(input:checked) .mark {
220
209
  transition-property: none;
221
210
  }
222
- .np-container:has(input:checked) .mark,
223
- .np-container:has(input:not(:checked):not(:indeterminate)) .mark {
211
+ .np-checkbox-container:has(input:checked) .mark,
212
+ .np-checkbox-container:has(input:not(:checked):not(:indeterminate)) .mark {
224
213
  transform: scaleY(-1) translate(7px, -14px) rotate(45deg);
225
214
  }
226
- .np-container:has(input:indeterminate) .mark,
227
- .np-container:has(input:checked) .mark {
215
+ .np-checkbox-container:has(input:indeterminate) .mark,
216
+ .np-checkbox-container:has(input:checked) .mark {
228
217
  animation-duration: 350ms;
229
218
  animation-timing-function: cubic-bezier(0.05, 0.7, 0.1, 1);
230
219
  transition-duration: 350ms;
@@ -241,11 +230,11 @@
241
230
  transition-duration: 150ms;
242
231
  transition-timing-function: cubic-bezier(0.3, 0, 0.8, 0.15);
243
232
  }
244
- .np-container:has(input:checked) .mark.long {
233
+ .np-checkbox-container:has(input:checked) .mark.long {
245
234
  animation-name: prev-unselected-to-checked;
246
235
  }
247
- .np-container:has(input:checked) .mark.long,
248
- .np-container:has(input:not(:checked):not(:indeterminate)) .mark.long {
236
+ .np-checkbox-container:has(input:checked) .mark.long,
237
+ .np-checkbox-container:has(input:not(:checked):not(:indeterminate)) .mark.long {
249
238
  width: 11.313708499px;
250
239
  }
251
240
  .mark.long {
@@ -253,7 +242,7 @@
253
242
  transition-property: transform, width;
254
243
  width: 10px;
255
244
  }
256
- .np-container:has(input:indeterminate) .mark {
245
+ .np-checkbox-container:has(input:indeterminate) .mark {
257
246
  transform: scaleY(-1) translate(4px, -10px) rotate(0deg);
258
247
  }
259
248
  @keyframes prev-unselected-to-checked {
@@ -266,7 +255,7 @@
266
255
  background-color: CanvasText;
267
256
  }
268
257
 
269
- .np-container:has(input:disabled:checked) .np-background {
258
+ .np-checkbox-container:has(input:disabled:checked) .np-background {
270
259
  background-color: GrayText;
271
260
  opacity: 1;
272
261
  }
@@ -275,7 +264,7 @@
275
264
  border-color: CanvasText;
276
265
  }
277
266
 
278
- .np-container:has(input:disabled) .np-outline {
267
+ .np-checkbox-container:has(input:disabled) .np-outline {
279
268
  border-color: GrayText;
280
269
  opacity: 1;
281
270
  }
@@ -3,7 +3,7 @@
3
3
  import Button from '../button/Button.svelte'
4
4
 
5
5
  let {
6
- elevated = false,
6
+ variant = 'outlined',
7
7
  disabled = false,
8
8
  label = '',
9
9
  icon,
@@ -13,8 +13,6 @@
13
13
  </script>
14
14
 
15
15
  <Button
16
- size="xs"
17
- shape="square"
18
16
  --np-elevated-button-label-text-color="var(--np-assist-chip-label-text-color, var(--np-color-on-surface))"
19
17
  --np-outlined-button-label-text-color="var(--np-assist-chip-label-text-color, var(--np-color-on-surface))"
20
18
  --np-outlined-button-outline-color="var(--np-assist-chip-outline-color, var(--np-color-outline-variant))"
@@ -27,9 +25,11 @@
27
25
  : 'var(--np-color-primary)'}
28
26
  style="letter-spacing: 0.006rem"
29
27
  bind:element
30
- variant={elevated ? 'elevated' : 'outlined'}
31
- {disabled}
32
28
  {...attributes}
29
+ size="xs"
30
+ shape="square"
31
+ {variant}
32
+ {disabled}
33
33
  start={icon}
34
34
  >
35
35
  {label}
@@ -2,7 +2,7 @@
2
2
  import { arrowKeyNav, rovingTabindex } from '../keyboard-nav.js'
3
3
  import type { ChipSetProps } from './types.js'
4
4
 
5
- let { children, chipsCount, element = $bindable(), ...attributes }: ChipSetProps = $props()
5
+ let { children, element = $bindable(), ...attributes }: ChipSetProps = $props()
6
6
 
7
7
  const CHIP_SELECTOR = "input:not([type='hidden']), button, a[href]"
8
8
  const attach = rovingTabindex(CHIP_SELECTOR, {
@@ -12,15 +12,7 @@
12
12
  const onkeydown = arrowKeyNav(CHIP_SELECTOR, 'horizontal')
13
13
  </script>
14
14
 
15
- <div
16
- {...attributes}
17
- bind:this={element}
18
- class={[
19
- 'np-chip-set-wrapper',
20
- (chipsCount ?? 0) > 0 && 'np-chip-set-has-chips',
21
- attributes.class,
22
- ]}
23
- >
15
+ <div {...attributes} bind:this={element} class={['np-chip-set-wrapper', attributes.class]}>
24
16
  {#if children}
25
17
  <div {@attach attach} class={['np-chip-set']} role="toolbar" tabindex="-1" {onkeydown}>
26
18
  {@render children()}
@@ -34,7 +26,7 @@
34
26
  padding: 0.5rem;
35
27
  margin: -0.5rem;
36
28
  }
37
- .np-chip-set-has-chips {
29
+ .np-chip-set-wrapper:has(.np-chip-set > :global(*)) {
38
30
  margin-inline-end: 0;
39
31
  }
40
32
  .np-chip-set {
@@ -9,25 +9,28 @@
9
9
  let {
10
10
  selected = $bindable(),
11
11
  removable = false,
12
- elevated = false,
12
+ variant = 'outlined',
13
13
  disabled = false,
14
14
  label = '',
15
15
  icon,
16
16
  element = $bindable(),
17
- ariaLabelRemove = 'Remove',
17
+ removeAriaLabel = 'Remove',
18
18
  onremove,
19
19
  name,
20
20
  value,
21
21
  group = $bindable(),
22
22
  defaultSelected,
23
+ issues,
24
+ 'aria-invalid': ariaInvalid,
23
25
  ...attributes
24
26
  }: FilterChipProps = $props()
25
27
 
28
+ let hasError = $derived(!!issues?.length)
29
+
26
30
  let chipLabel: HTMLLabelElement | undefined = $state()
27
31
 
28
- let grouped = $derived(Array.isArray(group) && value !== undefined)
29
- let groupChecked = $derived(
30
- Array.isArray(group) && value !== undefined ? group.includes(value) : false,
32
+ let isChecked = $derived(
33
+ Array.isArray(group) && value !== undefined ? group.includes(value) : selected,
31
34
  )
32
35
 
33
36
  const onchange = (event: Event & { currentTarget: EventTarget & HTMLInputElement }) => {
@@ -48,10 +51,11 @@
48
51
  bind:this={element}
49
52
  class={[
50
53
  'np-filter-chip',
51
- elevated ? 'np-filter-chip-elevated' : 'np-filter-chip-default',
54
+ variant === 'elevated' ? 'np-filter-chip-elevated' : 'np-filter-chip-default',
52
55
  icon ? 'np-filter-chip-icon' : '',
53
56
  removable ? 'np-filter-chip-removable' : '',
54
57
  disabled ? 'np-filter-chip-disabled' : '',
58
+ hasError && !disabled && 'np-chip-error',
55
59
  attributes.class,
56
60
  ]}
57
61
  >
@@ -65,26 +69,16 @@
65
69
  <CheckIcon width={18} height={18} />
66
70
  </div>
67
71
  <div class="np-chip-label">{label}</div>
68
- {#if grouped}
69
- <input
70
- type="checkbox"
71
- checked={groupChecked}
72
- {onchange}
73
- {value}
74
- {name}
75
- {disabled}
76
- defaultChecked={defaultSelected}
77
- />
78
- {:else}
79
- <input
80
- type="checkbox"
81
- bind:checked={selected}
82
- {value}
83
- {name}
84
- {disabled}
85
- defaultChecked={defaultSelected}
86
- />
87
- {/if}
72
+ <input
73
+ type="checkbox"
74
+ checked={isChecked}
75
+ {onchange}
76
+ {value}
77
+ {name}
78
+ {disabled}
79
+ defaultChecked={defaultSelected}
80
+ aria-invalid={hasError ? 'true' : ariaInvalid}
81
+ />
88
82
  </label>
89
83
  {#if !disabled}
90
84
  <Ripple forElement={chipLabel} />
@@ -95,7 +89,7 @@
95
89
  type="button"
96
90
  size="xs"
97
91
  --np-icon-button-icon-size="1.125rem"
98
- aria-label={ariaLabelRemove}
92
+ aria-label={removeAriaLabel}
99
93
  onclick={onremove}
100
94
  >
101
95
  <CloseIcon />
@@ -191,6 +185,18 @@
191
185
  outline-width: 1px;
192
186
  outline-offset: -1px;
193
187
  }
188
+ .np-chip-error {
189
+ --np-filter-chip-outline-color: var(--np-color-error);
190
+ --np-ripple-hover-color: var(--np-color-error);
191
+ --np-ripple-pressed-color: var(--np-color-error);
192
+ color: var(--np-color-error);
193
+ }
194
+ .np-chip-error:has(input:checked)::before {
195
+ background-color: var(--np-color-error-container);
196
+ }
197
+ .np-chip-error:has(input:checked) {
198
+ color: var(--np-color-on-error-container);
199
+ }
194
200
  .np-filter-chip:has(input:checked)::before {
195
201
  outline-color: transparent;
196
202
  background-color: var(--np-color-secondary-container);
@@ -12,13 +12,16 @@
12
12
  icon,
13
13
  element = $bindable(),
14
14
  actionElement = $bindable(),
15
- ariaLabelRemove = 'Remove',
15
+ removeAriaLabel = 'Remove',
16
16
  onclick,
17
17
  onremove,
18
18
  name,
19
19
  value,
20
+ issues,
20
21
  ...attributes
21
22
  }: InputChipProps = $props()
23
+
24
+ let hasError = $derived(!!issues?.length)
22
25
  </script>
23
26
 
24
27
  <div
@@ -30,6 +33,7 @@
30
33
  icon ? 'np-input-chip-icon' : '',
31
34
  disabled ? 'np-input-chip-disabled' : '',
32
35
  selected ? 'np-input-chip-selected' : '',
36
+ hasError && !disabled && 'np-chip-error',
33
37
  attributes.class,
34
38
  ]}
35
39
  >
@@ -57,7 +61,7 @@
57
61
  type="button"
58
62
  size="xs"
59
63
  --np-icon-button-icon-size="1.125rem"
60
- aria-label={ariaLabelRemove}
64
+ aria-label={removeAriaLabel}
61
65
  onclick={onremove}
62
66
  >
63
67
  <CloseIcon />
@@ -77,6 +81,13 @@
77
81
  padding-inline-end: 1px;
78
82
  min-width: 0;
79
83
  }
84
+ .np-chip-error {
85
+ --np-input-chip-outline-color: var(--np-color-error);
86
+ --np-icon-button-icon-color: var(--np-color-error);
87
+ --np-ripple-hover-color: var(--np-color-error);
88
+ --np-ripple-pressed-color: var(--np-color-error);
89
+ color: var(--np-color-error);
90
+ }
80
91
  .np-input-chip-label {
81
92
  appearance: none;
82
93
  background: none;
@@ -0,0 +1,29 @@
1
+ <script lang="ts">
2
+ import Button from '../button/Button.svelte'
3
+ import type { SuggestionChipProps } from './types.js'
4
+
5
+ let {
6
+ variant = 'outlined',
7
+ disabled = false,
8
+ label = '',
9
+ element = $bindable(),
10
+ ...attributes
11
+ }: SuggestionChipProps = $props()
12
+ </script>
13
+
14
+ <Button
15
+ --np-elevated-button-label-text-color="var(--np-suggestion-chip-label-text-color, var(--np-color-on-surface))"
16
+ --np-outlined-button-label-text-color="var(--np-suggestion-chip-label-text-color, var(--np-color-on-surface))"
17
+ --np-outlined-button-outline-color="var(--np-suggestion-chip-outline-color, var(--np-color-outline-variant))"
18
+ --np-button-padding="1rem"
19
+ --np-button-shape="0.5rem"
20
+ style="letter-spacing: 0.006rem"
21
+ bind:element
22
+ {...attributes}
23
+ size="xs"
24
+ shape="square"
25
+ {variant}
26
+ {disabled}
27
+ >
28
+ {label}
29
+ </Button>
@@ -0,0 +1,4 @@
1
+ import type { SuggestionChipProps } from './types.ts';
2
+ declare const SuggestionChip: import("svelte").Component<SuggestionChipProps, {}, "element">;
3
+ type SuggestionChip = ReturnType<typeof SuggestionChip>;
4
+ export default SuggestionChip;
@@ -1,4 +1,5 @@
1
1
  export { default as FilterChip } from './FilterChip.svelte';
2
2
  export { default as AssistChip } from './AssistChip.svelte';
3
3
  export { default as InputChip } from './InputChip.svelte';
4
+ export { default as SuggestionChip } from './SuggestionChip.svelte';
4
5
  export { default as ChipSet } from './ChipSet.svelte';
@@ -1,4 +1,5 @@
1
1
  export { default as FilterChip } from './FilterChip.svelte';
2
2
  export { default as AssistChip } from './AssistChip.svelte';
3
3
  export { default as InputChip } from './InputChip.svelte';
4
+ export { default as SuggestionChip } from './SuggestionChip.svelte';
4
5
  export { default as ChipSet } from './ChipSet.svelte';
@@ -1,44 +1,51 @@
1
- import type { ButtonElement, ButtonProps } from '../button/types.js';
1
+ import type { ButtonElement } from '../button/types.js';
2
2
  import type { Snippet } from 'svelte';
3
- import type { HTMLAttributes, MouseEventHandler } from 'svelte/elements';
3
+ import type { HTMLAnchorAttributes, HTMLAttributes, HTMLButtonAttributes, MouseEventHandler } from 'svelte/elements';
4
4
  export interface ChipSetProps extends HTMLAttributes<HTMLDivElement> {
5
- chipsCount?: number;
6
5
  element?: HTMLDivElement;
7
6
  }
8
- export interface AssistChipProps extends Omit<ButtonProps, 'variant' | 'start' | 'end' | 'element'> {
9
- elevated?: boolean;
10
- disabled?: boolean;
7
+ export interface AssistChipProps extends HTMLAttributes<ButtonElement>, Omit<HTMLButtonAttributes, keyof HTMLAttributes<HTMLButtonElement> | 'type'>, Omit<HTMLAnchorAttributes, keyof HTMLAttributes<HTMLAnchorElement> | 'type'> {
8
+ variant?: 'outlined' | 'elevated';
9
+ disabled?: boolean | null;
11
10
  label?: string;
12
11
  icon?: Snippet;
13
12
  element?: HTMLElement;
13
+ type?: 'submit' | 'reset' | 'button' | (string & {}) | null;
14
14
  }
15
+ export type SuggestionChipProps = Omit<AssistChipProps, 'icon'>;
15
16
  export interface FilterChipProps extends HTMLAttributes<HTMLDivElement> {
16
17
  selected?: boolean;
17
18
  removable?: boolean;
18
19
  disabled?: boolean;
19
- elevated?: boolean;
20
+ variant?: 'outlined' | 'elevated';
20
21
  label?: string;
21
22
  icon?: Snippet;
22
- ariaLabelRemove?: string;
23
+ removeAriaLabel?: string;
23
24
  element?: HTMLDivElement;
24
25
  name?: string;
25
26
  value?: string;
26
27
  group?: (string | number)[] | null;
27
28
  defaultSelected?: boolean | null;
28
29
  onremove?: MouseEventHandler<ButtonElement>;
30
+ issues?: {
31
+ message: string;
32
+ }[];
29
33
  }
30
34
  export interface InputChipProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onclick'> {
31
35
  selected?: boolean;
32
36
  disabled?: boolean;
33
37
  label?: string;
34
38
  icon?: Snippet;
35
- ariaLabelRemove?: string;
39
+ removeAriaLabel?: string;
36
40
  element?: HTMLDivElement;
37
41
  actionElement?: HTMLButtonElement;
38
42
  name?: string;
39
43
  value?: string | number;
40
44
  onclick?: MouseEventHandler<HTMLButtonElement>;
41
45
  onremove?: MouseEventHandler<ButtonElement>;
46
+ issues?: {
47
+ message: string;
48
+ }[];
42
49
  }
43
50
  export interface ChipSetContext {
44
51
  chips: {
@@ -20,7 +20,7 @@
20
20
  toISODate,
21
21
  today as getToday,
22
22
  } from './dateUtils.js'
23
- import { afterTwoFrames } from './enterAnimation.js'
23
+ import { afterTwoFrames } from '../animation.js'
24
24
  import type { CalendarProps } from './types.js'
25
25
 
26
26
  let {