@noahbaumgartner/svelte-ui 0.0.4 → 0.0.6

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 (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +28 -13
  3. package/dist/components/accordion/Accordion.svelte +44 -0
  4. package/dist/components/accordion/Accordion.svelte.d.ts +13 -0
  5. package/dist/components/accordion/AccordionItem.svelte +145 -0
  6. package/dist/components/accordion/AccordionItem.svelte.d.ts +17 -0
  7. package/dist/components/accordion/context.d.ts +5 -0
  8. package/dist/components/accordion/context.js +2 -0
  9. package/dist/components/alert-dialog/AlertDialog.svelte +108 -76
  10. package/dist/components/alert-dialog/AlertDialog.svelte.d.ts +5 -2
  11. package/dist/components/avatar/Avatar.svelte +71 -49
  12. package/dist/components/avatar/Avatar.svelte.d.ts +5 -2
  13. package/dist/components/avatar-group/AvatarGroup.svelte +103 -0
  14. package/dist/components/avatar-group/AvatarGroup.svelte.d.ts +19 -0
  15. package/dist/components/badge/Badge.svelte +50 -28
  16. package/dist/components/badge/Badge.svelte.d.ts +6 -4
  17. package/dist/components/breadcrumb/Breadcrumb.svelte +21 -17
  18. package/dist/components/breadcrumb/Breadcrumb.svelte.d.ts +3 -1
  19. package/dist/components/breadcrumb/BreadcrumbEllipsis.svelte +17 -6
  20. package/dist/components/breadcrumb/BreadcrumbEllipsis.svelte.d.ts +5 -2
  21. package/dist/components/breadcrumb/BreadcrumbItem.svelte +75 -36
  22. package/dist/components/breadcrumb/BreadcrumbItem.svelte.d.ts +8 -5
  23. package/dist/components/breadcrumb/BreadcrumbSeparator.svelte +32 -9
  24. package/dist/components/breadcrumb/BreadcrumbSeparator.svelte.d.ts +10 -17
  25. package/dist/components/button/Button.svelte +206 -168
  26. package/dist/components/button/Button.svelte.d.ts +9 -5
  27. package/dist/components/button-group/ButtonGroup.svelte +52 -55
  28. package/dist/components/button-group/ButtonGroup.svelte.d.ts +3 -1
  29. package/dist/components/calendar/Calendar.svelte +232 -144
  30. package/dist/components/calendar/Calendar.svelte.d.ts +19 -2
  31. package/dist/components/calendar/dates.d.ts +4 -1
  32. package/dist/components/calendar/dates.js +8 -2
  33. package/dist/components/card/Card.svelte +48 -32
  34. package/dist/components/card/Card.svelte.d.ts +3 -1
  35. package/dist/components/card/CardAction.svelte +11 -7
  36. package/dist/components/card/CardAction.svelte.d.ts +3 -1
  37. package/dist/components/card/CardContent.svelte +8 -4
  38. package/dist/components/card/CardContent.svelte.d.ts +3 -1
  39. package/dist/components/card/CardDescription.svelte +11 -7
  40. package/dist/components/card/CardDescription.svelte.d.ts +3 -1
  41. package/dist/components/card/CardFooter.svelte +15 -11
  42. package/dist/components/card/CardFooter.svelte.d.ts +3 -1
  43. package/dist/components/card/CardHeader.svelte +15 -11
  44. package/dist/components/card/CardHeader.svelte.d.ts +3 -1
  45. package/dist/components/card/CardTitle.svelte +11 -7
  46. package/dist/components/card/CardTitle.svelte.d.ts +3 -1
  47. package/dist/components/checkbox/Checkbox.svelte +152 -61
  48. package/dist/components/checkbox/Checkbox.svelte.d.ts +5 -2
  49. package/dist/components/color-picker/ColorPicker.svelte +131 -78
  50. package/dist/components/color-picker/ColorPicker.svelte.d.ts +10 -1
  51. package/dist/components/context-menu/ContextMenu.svelte +78 -61
  52. package/dist/components/context-menu/ContextMenu.svelte.d.ts +5 -2
  53. package/dist/components/context-menu/ContextMenuInfo.svelte +91 -0
  54. package/dist/components/context-menu/ContextMenuInfo.svelte.d.ts +19 -0
  55. package/dist/components/context-menu/ContextMenuItem.svelte +102 -57
  56. package/dist/components/context-menu/ContextMenuItem.svelte.d.ts +10 -5
  57. package/dist/components/context-menu/ContextMenuLabel.svelte +28 -0
  58. package/dist/components/context-menu/ContextMenuLabel.svelte.d.ts +10 -0
  59. package/dist/components/context-menu/ContextMenuSeparator.svelte +29 -0
  60. package/dist/components/context-menu/ContextMenuSeparator.svelte.d.ts +8 -0
  61. package/dist/components/dialog/Dialog.svelte +149 -108
  62. package/dist/components/dialog/Dialog.svelte.d.ts +7 -2
  63. package/dist/components/drawer/Drawer.svelte +419 -0
  64. package/dist/components/drawer/Drawer.svelte.d.ts +28 -0
  65. package/dist/components/empty-state/EmptyState.svelte +106 -0
  66. package/dist/components/empty-state/EmptyState.svelte.d.ts +19 -0
  67. package/dist/components/entry/Entry.svelte +94 -0
  68. package/dist/components/entry/Entry.svelte.d.ts +16 -0
  69. package/dist/components/field/Field.svelte +66 -45
  70. package/dist/components/field/Field.svelte.d.ts +2 -1
  71. package/dist/components/field/FieldContent.svelte +11 -8
  72. package/dist/components/field/FieldContent.svelte.d.ts +2 -1
  73. package/dist/components/field/FieldDescription.svelte +18 -15
  74. package/dist/components/field/FieldDescription.svelte.d.ts +2 -1
  75. package/dist/components/field/FieldError.svelte +22 -13
  76. package/dist/components/field/FieldError.svelte.d.ts +2 -1
  77. package/dist/components/field/FieldGroup.svelte +15 -12
  78. package/dist/components/field/FieldGroup.svelte.d.ts +2 -1
  79. package/dist/components/field/FieldLegend.svelte +23 -14
  80. package/dist/components/field/FieldLegend.svelte.d.ts +2 -1
  81. package/dist/components/field/FieldSeparator.svelte +12 -9
  82. package/dist/components/field/FieldSeparator.svelte.d.ts +2 -1
  83. package/dist/components/field/FieldSet.svelte +18 -15
  84. package/dist/components/field/FieldSet.svelte.d.ts +2 -1
  85. package/dist/components/footer/Footer.svelte +105 -0
  86. package/dist/components/footer/Footer.svelte.d.ts +14 -0
  87. package/dist/components/footer/FooterColumn.svelte +37 -0
  88. package/dist/components/footer/FooterColumn.svelte.d.ts +11 -0
  89. package/dist/components/image/Image.svelte +61 -0
  90. package/dist/components/image/Image.svelte.d.ts +18 -0
  91. package/dist/components/input/Input.svelte +307 -208
  92. package/dist/components/input/Input.svelte.d.ts +12 -1
  93. package/dist/components/input-group/InputGroup.svelte +101 -61
  94. package/dist/components/input-group/InputGroup.svelte.d.ts +2 -1
  95. package/dist/components/input-group/InputGroupAddon.svelte +58 -49
  96. package/dist/components/kbd/Kbd.svelte +39 -30
  97. package/dist/components/kbd/Kbd.svelte.d.ts +2 -1
  98. package/dist/components/kbd/KbdGroup.svelte +15 -12
  99. package/dist/components/kbd/KbdGroup.svelte.d.ts +2 -1
  100. package/dist/components/label/Label.svelte +47 -28
  101. package/dist/components/label/Label.svelte.d.ts +2 -1
  102. package/dist/components/link/Link.svelte +71 -17
  103. package/dist/components/link/Link.svelte.d.ts +2 -1
  104. package/dist/components/mesh-gradient/MeshGradient.svelte +97 -0
  105. package/dist/components/mesh-gradient/MeshGradient.svelte.d.ts +11 -0
  106. package/dist/components/navbar/Navbar.svelte +137 -99
  107. package/dist/components/navbar/Navbar.svelte.d.ts +4 -2
  108. package/dist/components/navigation-menu/NavigationMenu.svelte +37 -20
  109. package/dist/components/navigation-menu/NavigationMenu.svelte.d.ts +4 -2
  110. package/dist/components/navigation-menu/NavigationMenuItem.svelte +131 -89
  111. package/dist/components/navigation-menu/NavigationMenuItem.svelte.d.ts +4 -2
  112. package/dist/components/navigation-menu/NavigationMenuLink.svelte +90 -51
  113. package/dist/components/navigation-menu/NavigationMenuLink.svelte.d.ts +7 -5
  114. package/dist/components/number-stepper/NumberStepper.svelte +101 -0
  115. package/dist/components/number-stepper/NumberStepper.svelte.d.ts +21 -0
  116. package/dist/components/popover/Popover.svelte +85 -65
  117. package/dist/components/popover/Popover.svelte.d.ts +5 -2
  118. package/dist/components/preview-card/PreviewCard.svelte +184 -0
  119. package/dist/components/preview-card/PreviewCard.svelte.d.ts +23 -0
  120. package/dist/components/progress/Progress.svelte +111 -0
  121. package/dist/components/progress/Progress.svelte.d.ts +13 -0
  122. package/dist/components/radio-group/RadioGroup.svelte +24 -19
  123. package/dist/components/radio-group/RadioGroup.svelte.d.ts +2 -1
  124. package/dist/components/radio-group/RadioGroupItem.svelte +101 -54
  125. package/dist/components/radio-group/RadioGroupItem.svelte.d.ts +2 -1
  126. package/dist/components/section/Section.svelte +114 -0
  127. package/dist/components/section/Section.svelte.d.ts +22 -0
  128. package/dist/components/select/Select.svelte +474 -0
  129. package/dist/components/select/Select.svelte.d.ts +48 -0
  130. package/dist/components/separator/Separator.svelte +21 -10
  131. package/dist/components/separator/Separator.svelte.d.ts +2 -1
  132. package/dist/components/sidebar/Sidebar.svelte +158 -87
  133. package/dist/components/sidebar/Sidebar.svelte.d.ts +6 -1
  134. package/dist/components/sidebar/SidebarContent.svelte +15 -12
  135. package/dist/components/sidebar/SidebarContent.svelte.d.ts +2 -1
  136. package/dist/components/sidebar/SidebarFooter.svelte +10 -7
  137. package/dist/components/sidebar/SidebarFooter.svelte.d.ts +2 -1
  138. package/dist/components/sidebar/SidebarGroup.svelte +35 -25
  139. package/dist/components/sidebar/SidebarGroup.svelte.d.ts +2 -1
  140. package/dist/components/sidebar/SidebarHeader.svelte +37 -8
  141. package/dist/components/sidebar/SidebarHeader.svelte.d.ts +6 -1
  142. package/dist/components/sidebar/SidebarInset.svelte +11 -8
  143. package/dist/components/sidebar/SidebarInset.svelte.d.ts +2 -1
  144. package/dist/components/sidebar/SidebarMenu.svelte +13 -10
  145. package/dist/components/sidebar/SidebarMenu.svelte.d.ts +2 -1
  146. package/dist/components/sidebar/SidebarMenuItem.svelte +195 -114
  147. package/dist/components/sidebar/SidebarMenuItem.svelte.d.ts +11 -5
  148. package/dist/components/sidebar/SidebarProvider.svelte +18 -9
  149. package/dist/components/sidebar/SidebarProvider.svelte.d.ts +2 -1
  150. package/dist/components/sidebar/SidebarSeparator.svelte +6 -1
  151. package/dist/components/sidebar/SidebarSeparator.svelte.d.ts +6 -17
  152. package/dist/components/sidebar/SidebarTrigger.svelte +17 -5
  153. package/dist/components/sidebar/SidebarTrigger.svelte.d.ts +4 -2
  154. package/dist/components/skeleton/Skeleton.svelte +26 -16
  155. package/dist/components/skeleton/Skeleton.svelte.d.ts +4 -2
  156. package/dist/components/spinner/Spinner.svelte +71 -46
  157. package/dist/components/spinner/Spinner.svelte.d.ts +2 -1
  158. package/dist/components/switch/Switch.svelte +126 -65
  159. package/dist/components/switch/Switch.svelte.d.ts +4 -2
  160. package/dist/components/table/Table.svelte +135 -76
  161. package/dist/components/table/Table.svelte.d.ts +12 -2
  162. package/dist/components/tabs/Tabs.svelte +337 -0
  163. package/dist/components/tabs/Tabs.svelte.d.ts +50 -0
  164. package/dist/components/textarea/Textarea.svelte +76 -42
  165. package/dist/components/textarea/Textarea.svelte.d.ts +4 -1
  166. package/dist/components/time-picker/TimePicker.svelte +214 -85
  167. package/dist/components/time-picker/TimePicker.svelte.d.ts +18 -1
  168. package/dist/components/toaster/Toaster.svelte +132 -70
  169. package/dist/components/toaster/Toaster.svelte.d.ts +18 -2
  170. package/dist/components/toaster/toast.svelte.d.ts +3 -3
  171. package/dist/components/toggle/Toggle.svelte +25 -4
  172. package/dist/components/toggle/Toggle.svelte.d.ts +1 -1
  173. package/dist/components/tooltip/Tooltip.svelte +87 -58
  174. package/dist/components/tooltip/Tooltip.svelte.d.ts +4 -2
  175. package/dist/icon.d.ts +12 -0
  176. package/dist/icon.js +1 -0
  177. package/dist/index.d.ts +21 -0
  178. package/dist/index.js +19 -0
  179. package/dist/internal/icons/ArrowDown.svelte +14 -0
  180. package/dist/internal/icons/ArrowDown.svelte.d.ts +4 -0
  181. package/dist/internal/icons/ArrowUp.svelte +14 -0
  182. package/dist/internal/icons/ArrowUp.svelte.d.ts +4 -0
  183. package/dist/internal/icons/Calendar.svelte +16 -0
  184. package/dist/internal/icons/Calendar.svelte.d.ts +4 -0
  185. package/dist/internal/icons/Check.svelte +8 -0
  186. package/dist/internal/icons/Check.svelte.d.ts +4 -0
  187. package/dist/internal/icons/ChevronDown.svelte +8 -0
  188. package/dist/internal/icons/ChevronDown.svelte.d.ts +4 -0
  189. package/dist/internal/icons/ChevronLeft.svelte +8 -0
  190. package/dist/internal/icons/ChevronLeft.svelte.d.ts +4 -0
  191. package/dist/internal/icons/ChevronRight.svelte +8 -0
  192. package/dist/internal/icons/ChevronRight.svelte.d.ts +4 -0
  193. package/dist/internal/icons/ChevronUp.svelte +8 -0
  194. package/dist/internal/icons/ChevronUp.svelte.d.ts +4 -0
  195. package/dist/internal/icons/ChevronsUpDown.svelte +14 -0
  196. package/dist/internal/icons/ChevronsUpDown.svelte.d.ts +4 -0
  197. package/dist/internal/icons/Clock.svelte +14 -0
  198. package/dist/internal/icons/Clock.svelte.d.ts +4 -0
  199. package/dist/internal/icons/Ellipsis.svelte +15 -0
  200. package/dist/internal/icons/Ellipsis.svelte.d.ts +4 -0
  201. package/dist/internal/icons/Icon.svelte +33 -0
  202. package/dist/internal/icons/Icon.svelte.d.ts +8 -0
  203. package/dist/internal/icons/Minus.svelte +8 -0
  204. package/dist/internal/icons/Minus.svelte.d.ts +4 -0
  205. package/dist/internal/icons/PanelLeft.svelte +14 -0
  206. package/dist/internal/icons/PanelLeft.svelte.d.ts +4 -0
  207. package/dist/internal/icons/Plus.svelte +14 -0
  208. package/dist/internal/icons/Plus.svelte.d.ts +4 -0
  209. package/dist/internal/icons/User.svelte +14 -0
  210. package/dist/internal/icons/User.svelte.d.ts +4 -0
  211. package/dist/internal/icons/X.svelte +14 -0
  212. package/dist/internal/icons/X.svelte.d.ts +4 -0
  213. package/dist/styles/tokens.css +39 -41
  214. package/package.json +5 -10
  215. package/dist/icons.d.ts +0 -2
  216. package/dist/icons.js +0 -4
@@ -3,13 +3,29 @@
3
3
  import Input from '../input/Input.svelte';
4
4
 
5
5
  type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> & {
6
+ /** The root element. Bindable. */
7
+ ref?: HTMLDivElement | null;
6
8
  /** Bindable, `#rrggbb` like `<input type="color">`. */
7
9
  value?: string;
8
10
  /** Called on every change while dragging or typing. */
9
11
  onselect?: (value: string) => void;
12
+ /** Accessible names of the controls, e.g. to translate them. */
13
+ labels?: {
14
+ area?: string;
15
+ areaValue?: (saturation: number, brightness: number) => string;
16
+ hue?: string;
17
+ hex?: string;
18
+ };
10
19
  };
11
20
 
12
- let { value = $bindable('#000000'), onselect, class: className, ...rest }: Props = $props();
21
+ let {
22
+ ref = $bindable(null),
23
+ value = $bindable('#000000'),
24
+ onselect,
25
+ labels,
26
+ class: className,
27
+ ...rest
28
+ }: Props = $props();
13
29
 
14
30
  type Hsv = { h: number; s: number; v: number };
15
31
 
@@ -105,14 +121,15 @@
105
121
  }
106
122
  </script>
107
123
 
108
- <div {...rest} class={['color-picker', className]}>
124
+ <div {...rest} bind:this={ref} class={['color-picker', className]}>
109
125
  <div
110
126
  class="color-picker-area"
111
127
  role="slider"
112
128
  tabindex="0"
113
- aria-label="Saturation and brightness"
129
+ aria-label={labels?.area ?? 'Saturation and brightness'}
114
130
  aria-valuenow={Math.round(hsv.s * 100)}
115
- aria-valuetext="Saturation {Math.round(hsv.s * 100)}%, brightness {Math.round(hsv.v * 100)}%"
131
+ aria-valuetext={labels?.areaValue?.(Math.round(hsv.s * 100), Math.round(hsv.v * 100)) ??
132
+ `Saturation ${Math.round(hsv.s * 100)}%, brightness ${Math.round(hsv.v * 100)}%`}
116
133
  style:--hue={hsv.h}
117
134
  onpointerdown={(event) => drag(event, (x, y) => emit({ h: hsv.h, s: x, v: 1 - y }))}
118
135
  onkeydown={areaKeydown}
@@ -129,7 +146,7 @@
129
146
  class="color-picker-hue"
130
147
  role="slider"
131
148
  tabindex="0"
132
- aria-label="Hue"
149
+ aria-label={labels?.hue ?? 'Hue'}
133
150
  aria-valuemin={0}
134
151
  aria-valuemax={360}
135
152
  aria-valuenow={Math.round(hsv.h)}
@@ -145,89 +162,125 @@
145
162
 
146
163
  <div class="color-picker-footer">
147
164
  <span class="color-picker-swatch" style:background-color={value}></span>
148
- <Input value={hexText} aria-label="Hex color" spellcheck="false" oninput={hexInput} />
165
+ <Input
166
+ value={hexText}
167
+ aria-label={labels?.hex ?? 'Hex color'}
168
+ spellcheck="false"
169
+ oninput={hexInput}
170
+ />
149
171
  </div>
150
172
  </div>
151
173
 
152
174
  <style>
153
- .color-picker {
154
- display: flex;
155
- flex-direction: column;
156
- gap: 12px;
157
- width: 224px;
158
- user-select: none;
159
- }
175
+ @layer svelte-ui {
176
+ .color-picker {
177
+ display: flex;
178
+ flex-direction: column;
179
+ gap: 12px;
180
+ width: 224px;
181
+ user-select: none;
182
+ }
160
183
 
161
- .color-picker-area {
162
- position: relative;
163
- height: 150px;
164
- border-radius: 8px;
165
- background:
166
- linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent),
167
- hsl(var(--hue) 100% 50%);
168
- outline: none;
169
- cursor: crosshair;
170
- touch-action: none;
171
- }
184
+ .color-picker-area {
185
+ position: relative;
186
+ height: 150px;
187
+ border-radius: 8px;
188
+ background:
189
+ linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent),
190
+ hsl(var(--hue) 100% 50%);
191
+ outline: none;
192
+ cursor: crosshair;
193
+ touch-action: none;
194
+ }
172
195
 
173
- .color-picker-hue {
174
- position: relative;
175
- height: 12px;
176
- margin: 0 6px;
177
- border-radius: 999px;
178
- background: linear-gradient(
179
- to right,
180
- #f00 0%,
181
- #ff0 17%,
182
- #0f0 33%,
183
- #0ff 50%,
184
- #00f 67%,
185
- #f0f 83%,
186
- #f00 100%
187
- );
188
- outline: none;
189
- cursor: pointer;
190
- touch-action: none;
191
- }
196
+ .color-picker-hue {
197
+ position: relative;
198
+ height: 12px;
199
+ margin: 0 6px;
200
+ border-radius: 999px;
201
+ background: linear-gradient(
202
+ to right,
203
+ #f00 0%,
204
+ #ff0 17%,
205
+ #0f0 33%,
206
+ #0ff 50%,
207
+ #00f 67%,
208
+ #f0f 83%,
209
+ #f00 100%
210
+ );
211
+ outline: none;
212
+ cursor: pointer;
213
+ touch-action: none;
214
+ }
192
215
 
193
- /* Let the hue thumb reach both ends of the rounded track */
194
- .color-picker-hue::before {
195
- content: '';
196
- position: absolute;
197
- inset: 0 -6px;
198
- }
216
+ /* Let the hue thumb reach both ends of the rounded track */
217
+ .color-picker-hue::before {
218
+ content: '';
219
+ position: absolute;
220
+ inset: 0 -6px;
221
+ }
199
222
 
200
- .color-picker-thumb {
201
- position: absolute;
202
- top: 50%;
203
- width: 14px;
204
- height: 14px;
205
- box-sizing: border-box;
206
- border: 2px solid #fff;
207
- border-radius: 999px;
208
- box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
209
- transform: translate(-50%, -50%);
210
- pointer-events: none;
211
- }
223
+ .color-picker-thumb {
224
+ position: absolute;
225
+ top: 50%;
226
+ width: 14px;
227
+ height: 14px;
228
+ box-sizing: border-box;
229
+ border: 2px solid #fff;
230
+ border-radius: 999px;
231
+ box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
232
+ transform: translate(-50%, -50%);
233
+ pointer-events: none;
234
+ }
212
235
 
213
- .color-picker-area:focus-visible .color-picker-thumb,
214
- .color-picker-hue:focus-visible .color-picker-thumb {
215
- outline: 2px solid var(--color-accent);
216
- outline-offset: 2px;
217
- }
236
+ .color-picker-area:focus-visible .color-picker-thumb,
237
+ .color-picker-hue:focus-visible .color-picker-thumb {
238
+ outline: 2px solid var(--color-accent);
239
+ outline-offset: 2px;
240
+ }
218
241
 
219
- .color-picker-footer {
220
- display: flex;
221
- align-items: center;
222
- gap: 8px;
223
- }
242
+ @media (pointer: coarse) {
243
+ .color-picker-hue::before {
244
+ inset: -16px -6px;
245
+ }
246
+ }
247
+
248
+ @media (forced-colors: active) {
249
+ .color-picker-area,
250
+ .color-picker-hue {
251
+ border: 1px solid CanvasText;
252
+ }
253
+
254
+ .color-picker-thumb {
255
+ forced-color-adjust: none;
256
+ border-color: Canvas;
257
+ box-shadow: 0 0 0 2px CanvasText;
258
+ }
224
259
 
225
- .color-picker-swatch {
226
- flex-shrink: 0;
227
- width: 32px;
228
- height: 32px;
229
- box-sizing: border-box;
230
- border: 1px solid var(--color-border);
231
- border-radius: 10px;
260
+ .color-picker-area:focus-visible .color-picker-thumb,
261
+ .color-picker-hue:focus-visible .color-picker-thumb {
262
+ outline-color: Highlight;
263
+ }
264
+
265
+ .color-picker-swatch {
266
+ forced-color-adjust: none;
267
+ border-color: CanvasText;
268
+ }
269
+ }
270
+
271
+ .color-picker-footer {
272
+ display: flex;
273
+ align-items: center;
274
+ gap: 8px;
275
+ }
276
+
277
+ .color-picker-swatch {
278
+ flex-shrink: 0;
279
+ width: 32px;
280
+ height: 32px;
281
+ box-sizing: border-box;
282
+ border: 1px solid var(--color-border);
283
+ border-radius: 10px;
284
+ }
232
285
  }
233
286
  </style>
@@ -1,10 +1,19 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
2
  type Props = Omit<HTMLAttributes<HTMLDivElement>, 'onselect'> & {
3
+ /** The root element. Bindable. */
4
+ ref?: HTMLDivElement | null;
3
5
  /** Bindable, `#rrggbb` like `<input type="color">`. */
4
6
  value?: string;
5
7
  /** Called on every change while dragging or typing. */
6
8
  onselect?: (value: string) => void;
9
+ /** Accessible names of the controls, e.g. to translate them. */
10
+ labels?: {
11
+ area?: string;
12
+ areaValue?: (saturation: number, brightness: number) => string;
13
+ hue?: string;
14
+ hex?: string;
15
+ };
7
16
  };
8
- declare const ColorPicker: import("svelte").Component<Props, {}, "value">;
17
+ declare const ColorPicker: import("svelte").Component<Props, {}, "ref" | "value">;
9
18
  type ColorPicker = ReturnType<typeof ColorPicker>;
10
19
  export default ColorPicker;
@@ -1,9 +1,12 @@
1
1
  <script lang="ts">
2
2
  import { tick, type Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
3
4
  import { scale } from 'svelte/transition';
4
5
  import { setMenuContext, type ContextMenuTriggerProps } from './context.js';
5
6
 
6
- type Props = {
7
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
8
+ /** The wrapper element around the trigger and menu. Bindable. */
9
+ ref?: HTMLDivElement | null;
7
10
  /** Whether the menu is open. Bindable. */
8
11
  open?: boolean;
9
12
  /** Horizontal alignment of the menu relative to the trigger. */
@@ -13,11 +16,21 @@
13
16
  children: Snippet;
14
17
  };
15
18
 
16
- let { open = $bindable(false), align = 'start', trigger, children }: Props = $props();
19
+ let {
20
+ ref = $bindable(null),
21
+ open = $bindable(false),
22
+ align = 'start',
23
+ trigger,
24
+ children,
25
+ class: className,
26
+ ...rest
27
+ }: Props = $props();
17
28
 
18
29
  const id = $props.id();
30
+
31
+ const reducedMotion = () =>
32
+ typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
19
33
  let side: 'top' | 'bottom' = $state('bottom');
20
- let wrapperEl: HTMLDivElement;
21
34
  let contentEl: HTMLDivElement | undefined = $state();
22
35
 
23
36
  function items() {
@@ -36,7 +49,7 @@
36
49
 
37
50
  function close({ restoreFocus = false } = {}) {
38
51
  open = false;
39
- if (restoreFocus) wrapperEl.querySelector<HTMLElement>('[aria-haspopup="menu"]')?.focus();
52
+ if (restoreFocus) ref?.querySelector<HTMLElement>('[aria-haspopup="menu"]')?.focus();
40
53
  }
41
54
 
42
55
  setMenuContext({ close: () => close({ restoreFocus: true }) });
@@ -78,7 +91,8 @@
78
91
 
79
92
  tick().then(() => {
80
93
  if (!contentEl) return;
81
- const triggerRect = wrapperEl.getBoundingClientRect();
94
+ if (!ref) return;
95
+ const triggerRect = ref.getBoundingClientRect();
82
96
  const contentHeight = contentEl.offsetHeight;
83
97
  const spaceBelow = window.innerHeight - triggerRect.bottom;
84
98
  side =
@@ -86,7 +100,7 @@
86
100
  });
87
101
 
88
102
  function handlePointerDown(event: PointerEvent) {
89
- if (!wrapperEl.contains(event.target as Node)) close();
103
+ if (!ref?.contains(event.target as Node)) close();
90
104
  }
91
105
 
92
106
  function handleKeydown(event: KeyboardEvent) {
@@ -109,7 +123,7 @@
109
123
  });
110
124
  </script>
111
125
 
112
- <div class="context-menu" bind:this={wrapperEl}>
126
+ <div {...rest} class={['context-menu', className]} bind:this={ref}>
113
127
  {@render trigger(triggerProps)}
114
128
 
115
129
  {#if open}
@@ -124,7 +138,7 @@
124
138
  ]}
125
139
  bind:this={contentEl}
126
140
  onkeydown={handleMenuKeydown}
127
- transition:scale={{ duration: 140, start: 0.95 }}
141
+ transition:scale={{ duration: reducedMotion() ? 0 : 140, start: 0.95 }}
128
142
  >
129
143
  {@render children()}
130
144
  </div>
@@ -132,70 +146,73 @@
132
146
  </div>
133
147
 
134
148
  <style>
135
- .context-menu {
136
- position: relative;
137
- display: inline-flex;
138
- height: fit-content;
139
- }
149
+ @layer svelte-ui {
150
+ .context-menu {
151
+ position: relative;
152
+ display: inline-flex;
153
+ height: fit-content;
154
+ }
140
155
 
141
- .context-menu-content {
142
- position: absolute;
143
- z-index: 60;
144
- display: flex;
145
- flex-direction: column;
146
- gap: 2px;
147
- min-width: 160px;
148
- padding: 4px;
149
- background-color: var(--color-bg);
150
- border: 1px solid var(--color-border);
151
- border-radius: 10px;
152
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
153
- outline: none;
154
- user-select: none;
155
- }
156
+ .context-menu-content {
157
+ position: absolute;
158
+ z-index: 60;
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: 2px;
162
+ width: max-content;
163
+ min-width: 160px;
164
+ padding: 4px;
165
+ background-color: var(--color-bg);
166
+ border: 1px solid var(--color-border);
167
+ border-radius: 10px;
168
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
169
+ outline: none;
170
+ user-select: none;
171
+ }
156
172
 
157
- .context-menu-content--bottom {
158
- top: calc(100% + 8px);
159
- }
173
+ .context-menu-content--bottom {
174
+ top: calc(100% + 8px);
175
+ }
160
176
 
161
- .context-menu-content--top {
162
- bottom: calc(100% + 8px);
163
- }
177
+ .context-menu-content--top {
178
+ bottom: calc(100% + 8px);
179
+ }
164
180
 
165
- .context-menu-content--start {
166
- left: 0;
167
- }
181
+ .context-menu-content--start {
182
+ left: 0;
183
+ }
168
184
 
169
- .context-menu-content--center {
170
- left: 50%;
171
- transform: translateX(-50%);
172
- }
185
+ .context-menu-content--center {
186
+ left: 50%;
187
+ transform: translateX(-50%);
188
+ }
173
189
 
174
- .context-menu-content--end {
175
- right: 0;
176
- }
190
+ .context-menu-content--end {
191
+ right: 0;
192
+ }
177
193
 
178
- .context-menu-content--bottom.context-menu-content--start {
179
- transform-origin: top left;
180
- }
194
+ .context-menu-content--bottom.context-menu-content--start {
195
+ transform-origin: top left;
196
+ }
181
197
 
182
- .context-menu-content--bottom.context-menu-content--center {
183
- transform-origin: top center;
184
- }
198
+ .context-menu-content--bottom.context-menu-content--center {
199
+ transform-origin: top center;
200
+ }
185
201
 
186
- .context-menu-content--bottom.context-menu-content--end {
187
- transform-origin: top right;
188
- }
202
+ .context-menu-content--bottom.context-menu-content--end {
203
+ transform-origin: top right;
204
+ }
189
205
 
190
- .context-menu-content--top.context-menu-content--start {
191
- transform-origin: bottom left;
192
- }
206
+ .context-menu-content--top.context-menu-content--start {
207
+ transform-origin: bottom left;
208
+ }
193
209
 
194
- .context-menu-content--top.context-menu-content--center {
195
- transform-origin: bottom center;
196
- }
210
+ .context-menu-content--top.context-menu-content--center {
211
+ transform-origin: bottom center;
212
+ }
197
213
 
198
- .context-menu-content--top.context-menu-content--end {
199
- transform-origin: bottom right;
214
+ .context-menu-content--top.context-menu-content--end {
215
+ transform-origin: bottom right;
216
+ }
200
217
  }
201
218
  </style>
@@ -1,6 +1,9 @@
1
1
  import { type Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
2
3
  import { type ContextMenuTriggerProps } from './context.js';
3
- type Props = {
4
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
5
+ /** The wrapper element around the trigger and menu. Bindable. */
6
+ ref?: HTMLDivElement | null;
4
7
  /** Whether the menu is open. Bindable. */
5
8
  open?: boolean;
6
9
  /** Horizontal alignment of the menu relative to the trigger. */
@@ -9,6 +12,6 @@ type Props = {
9
12
  trigger: Snippet<[ContextMenuTriggerProps]>;
10
13
  children: Snippet;
11
14
  };
12
- declare const ContextMenu: import("svelte").Component<Props, {}, "open">;
15
+ declare const ContextMenu: import("svelte").Component<Props, {}, "ref" | "open">;
13
16
  type ContextMenu = ReturnType<typeof ContextMenu>;
14
17
  export default ContextMenu;
@@ -0,0 +1,91 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import type { IconComponent } from '../../icon.js';
5
+
6
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role'> & {
7
+ /** The info row element. Bindable. */
8
+ ref?: HTMLDivElement | null;
9
+ /** Any icon component, e.g. from `@lucide/svelte`. */
10
+ icon?: IconComponent;
11
+ /** Second, smaller line below the main text, e.g. an email address. */
12
+ description?: string;
13
+ /** Replaces the icon with custom content, e.g. an `Avatar`. */
14
+ leading?: Snippet;
15
+ /** Shown at the end of the row, e.g. a value. */
16
+ trailing?: Snippet;
17
+ children: Snippet;
18
+ };
19
+
20
+ let {
21
+ ref = $bindable(null),
22
+ icon: Icon,
23
+ description,
24
+ leading,
25
+ trailing,
26
+ class: className,
27
+ children,
28
+ ...rest
29
+ }: Props = $props();
30
+ </script>
31
+
32
+ <div
33
+ {...rest}
34
+ bind:this={ref}
35
+ role="presentation"
36
+ class={['context-menu-info', { 'context-menu-info--leading': leading }, className]}
37
+ >
38
+ {#if leading}
39
+ {@render leading()}
40
+ {:else if Icon}
41
+ <Icon class="context-menu-info-icon" aria-hidden="true" />
42
+ {/if}
43
+ <span class="context-menu-info-text">
44
+ <span class={['context-menu-info-label', { 'context-menu-info-label--title': description }]}>
45
+ {@render children()}
46
+ </span>
47
+ {#if description}<span class="context-menu-info-description">{description}</span>{/if}
48
+ </span>
49
+ {@render trailing?.()}
50
+ </div>
51
+
52
+ <style>
53
+ @layer svelte-ui {
54
+ .context-menu-info {
55
+ display: flex;
56
+ align-items: center;
57
+ gap: 10px;
58
+ padding: 8px 10px;
59
+ font-size: 13px;
60
+ color: var(--color-text-muted);
61
+ cursor: default;
62
+ }
63
+
64
+ .context-menu-info--leading {
65
+ gap: 14px;
66
+ padding: 10px;
67
+ }
68
+
69
+ .context-menu-info :global(.context-menu-info-icon) {
70
+ width: 16px;
71
+ height: 16px;
72
+ flex-shrink: 0;
73
+ }
74
+
75
+ .context-menu-info-text {
76
+ display: flex;
77
+ flex-direction: column;
78
+ flex-grow: 1;
79
+ min-width: 0;
80
+ }
81
+
82
+ .context-menu-info-label--title {
83
+ font-weight: 500;
84
+ color: var(--color-text);
85
+ }
86
+
87
+ .context-menu-info-description {
88
+ font-size: 12px;
89
+ }
90
+ }
91
+ </style>
@@ -0,0 +1,19 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { IconComponent } from '../../icon.js';
4
+ type Props = Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'role'> & {
5
+ /** The info row element. Bindable. */
6
+ ref?: HTMLDivElement | null;
7
+ /** Any icon component, e.g. from `@lucide/svelte`. */
8
+ icon?: IconComponent;
9
+ /** Second, smaller line below the main text, e.g. an email address. */
10
+ description?: string;
11
+ /** Replaces the icon with custom content, e.g. an `Avatar`. */
12
+ leading?: Snippet;
13
+ /** Shown at the end of the row, e.g. a value. */
14
+ trailing?: Snippet;
15
+ children: Snippet;
16
+ };
17
+ declare const ContextMenuInfo: import("svelte").Component<Props, {}, "ref">;
18
+ type ContextMenuInfo = ReturnType<typeof ContextMenuInfo>;
19
+ export default ContextMenuInfo;