@human-synthesis/norns-ui 0.0.5 → 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 (50) hide show
  1. package/README.md +32 -20
  2. package/package.json +7 -3
  3. package/src/auto-import.js +1 -4
  4. package/src/components/Accordion.n +24 -23
  5. package/src/components/Autocomplete.n +108 -33
  6. package/src/components/Collapsible.n +8 -11
  7. package/src/components/ContextMenu.n +55 -36
  8. package/src/components/DatePicker.n +19 -31
  9. package/src/components/DateRangePicker.n +17 -29
  10. package/src/components/Dialog.n +35 -22
  11. package/src/components/Dropdown.n +54 -23
  12. package/src/components/MultiSelect.n +138 -36
  13. package/src/components/Popover.n +30 -15
  14. package/src/components/ScrollArea.n +9 -20
  15. package/src/components/Sheet.n +36 -22
  16. package/src/components/Tabs.n +39 -13
  17. package/src/components/TimePicker.n +52 -65
  18. package/src/components/ToggleButton.n +18 -12
  19. package/src/components/ToggleButtonGroup.n +31 -11
  20. package/src/components/Tooltip.n +52 -19
  21. package/src/index.js +1 -4
  22. package/src/lib/behaviors/clickOutside.svelte.js +54 -0
  23. package/src/lib/behaviors/escape.svelte.js +36 -0
  24. package/src/lib/behaviors/floating.svelte.js +137 -0
  25. package/src/lib/behaviors/focusTrap.svelte.js +80 -0
  26. package/src/lib/behaviors/index.js +14 -0
  27. package/src/lib/behaviors/portal.svelte.js +32 -0
  28. package/src/lib/behaviors/rovingTabindex.svelte.js +76 -0
  29. package/src/lib/behaviors/scrollLock.svelte.js +56 -0
  30. package/src/styles/atoms.css +622 -919
  31. package/src/styles/tokens.css +33 -0
  32. package/src/types/Collapsible.d.ts +1 -0
  33. package/src/types/ContextMenu.d.ts +6 -1
  34. package/src/types/DatePicker.d.ts +7 -2
  35. package/src/types/DateRangePicker.d.ts +3 -3
  36. package/src/types/Dialog.d.ts +4 -0
  37. package/src/types/Dropdown.d.ts +2 -1
  38. package/src/types/MultiSelect.d.ts +3 -0
  39. package/src/types/ScrollArea.d.ts +1 -1
  40. package/src/types/Sheet.d.ts +3 -0
  41. package/src/types/Tabs.d.ts +2 -0
  42. package/src/types/ToggleButton.d.ts +2 -1
  43. package/src/types/ToggleButtonGroup.d.ts +2 -1
  44. package/src/types/Tooltip.d.ts +3 -0
  45. package/src/components/Drawer.n +0 -49
  46. package/src/components/PreviewCard.n +0 -30
  47. package/src/components/RichTooltip.n +0 -33
  48. package/src/types/Drawer.d.ts +0 -18
  49. package/src/types/PreviewCard.d.ts +0 -16
  50. package/src/types/RichTooltip.d.ts +0 -16
@@ -145,6 +145,31 @@
145
145
  --ui-h-sm: 1.75rem; /* 28px */
146
146
  --ui-h-md: 2.25rem; /* 36px */
147
147
  --ui-h-lg: 2.75rem; /* 44px */
148
+
149
+ /* Square icon-button sizes (close buttons, nav arrows, chevron triggers).
150
+ * Distinct from full button heights above. */
151
+ --ui-icon-btn-sm: 1.5rem; /* 24px */
152
+ --ui-icon-btn-md: 1.75rem; /* 28px */
153
+ --ui-icon-btn-lg: 2.25rem; /* 36px */
154
+
155
+ /* Motion timings — shared so animations feel coordinated. */
156
+ --ui-motion-fast: 150ms;
157
+ --ui-motion-med: 200ms;
158
+ --ui-motion-slow: 300ms;
159
+ --ui-motion-ease: cubic-bezier(0.2, 0, 0, 1);
160
+
161
+ /* Elevation — the only shadow vocabulary in the library.
162
+ * elev-1: subtle (cards, hover-lifts)
163
+ * elev-2: floating menus, popovers, tooltips
164
+ * elev-3: dialogs, sheets
165
+ */
166
+ --ui-elev-1: 0 1px 2px oklch(0% 0 0 / 0.06), 0 1px 3px oklch(0% 0 0 / 0.04);
167
+ --ui-elev-2: 0 4px 12px -2px oklch(0% 0 0 / 0.08), 0 2px 4px -1px oklch(0% 0 0 / 0.04);
168
+ --ui-elev-3: 0 16px 32px -8px oklch(0% 0 0 / 0.18), 0 4px 8px -4px oklch(0% 0 0 / 0.06);
169
+
170
+ /* Single canonical focus indicator. 2px halo on the surface color + 2px
171
+ * ring color outside it, so the ring stays visible on any background. */
172
+ --ui-focus-ring: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-ring);
148
173
  }
149
174
 
150
175
  /* === Dark theme ===
@@ -173,6 +198,14 @@
173
198
  /* Ring brightens slightly so it stays visible on dark surfaces */
174
199
  --color-ring: var(--color-primary-400);
175
200
 
201
+ /* Dark-mode elevation — true-black shadow on dark bg disappears, so we
202
+ * lean on darker shadow + the existing border to convey depth. */
203
+ --ui-elev-1: 0 1px 2px oklch(0% 0 0 / 0.4);
204
+ --ui-elev-2: 0 4px 12px -2px oklch(0% 0 0 / 0.5), 0 2px 4px -1px oklch(0% 0 0 / 0.3);
205
+ --ui-elev-3: 0 16px 32px -8px oklch(0% 0 0 / 0.6), 0 4px 8px -4px oklch(0% 0 0 / 0.4);
206
+
207
+ --ui-focus-ring: 0 0 0 2px var(--color-bg-elevated), 0 0 0 4px var(--color-ring);
208
+
176
209
  /* Feedback — flip to deep tinted bg + light fg */
177
210
  --color-success-bg: oklch(28% 0.05 152);
178
211
  --color-success-fg: var(--color-success-200);
@@ -5,6 +5,7 @@ export type CollapsibleProps = {
5
5
  title?: string;
6
6
  trigger?: Snippet;
7
7
  children?: Snippet;
8
+ onopenchange?: (open: boolean) => void;
8
9
  class?: string;
9
10
  };
10
11
 
@@ -5,7 +5,12 @@ export type ContextMenuItem = {
5
5
  icon?: string;
6
6
  separator?: boolean;
7
7
  disabled?: boolean;
8
- onSelect?: (event: Event) => void;
8
+ onSelect?: () => void;
9
+ /**
10
+ * NOTE: nested submenus are not supported in 0.0.6+ (the property is
11
+ * accepted but children are ignored). Re-introduce when the upstream
12
+ * design needs them.
13
+ */
9
14
  children?: ContextMenuItem[];
10
15
  };
11
16
 
@@ -3,11 +3,16 @@ import type { Component } from 'svelte';
3
3
  export type DatePickerProps = {
4
4
  /** ISO date string (YYYY-MM-DD). Bindable. */
5
5
  value?: string;
6
+ /** Whether the popover is open. Bindable. */
7
+ open?: boolean;
6
8
  min?: string;
7
9
  max?: string;
10
+ placeholder?: string;
8
11
  disabled?: boolean;
9
- readonly?: boolean;
10
- required?: boolean;
12
+ /** Close the popover automatically once a date is picked (default true). */
13
+ closeOnSelect?: boolean;
14
+ /** aria-label override; defaults to "Pick a date". */
15
+ label?: string;
11
16
  name?: string;
12
17
  id?: string;
13
18
  error?: boolean;
@@ -4,12 +4,12 @@ export type DateRange = { start: string; end: string };
4
4
 
5
5
  export type DateRangePickerProps = {
6
6
  value?: DateRange;
7
+ /** Whether the popover is open. Bindable. */
8
+ open?: boolean;
7
9
  min?: string;
8
10
  max?: string;
11
+ placeholder?: string;
9
12
  disabled?: boolean;
10
- required?: boolean;
11
- /** Form name. The two inputs serialize as `${name}_start` and `${name}_end`. */
12
- name?: string;
13
13
  class?: string;
14
14
  };
15
15
 
@@ -5,6 +5,10 @@ export type DialogProps = {
5
5
  title?: string;
6
6
  description?: string;
7
7
  hideClose?: boolean;
8
+ /** Close on overlay click and Escape. Default true. */
9
+ dismissable?: boolean;
10
+ /** Used as `aria-label` on the dialog when no `title` is provided. */
11
+ ariaLabel?: string;
8
12
  trigger?: Snippet;
9
13
  actions?: Snippet;
10
14
  children?: Snippet;
@@ -2,9 +2,10 @@ import type { Component, Snippet } from 'svelte';
2
2
 
3
3
  export type DropdownItem = {
4
4
  label?: string;
5
+ icon?: string;
5
6
  separator?: boolean;
6
7
  disabled?: boolean;
7
- onSelect?: (event: Event) => void;
8
+ onSelect?: () => void;
8
9
  };
9
10
 
10
11
  export type DropdownProps = {
@@ -7,6 +7,9 @@ export type MultiSelectProps = {
7
7
  open?: boolean;
8
8
  placeholder?: string;
9
9
  disabled?: boolean;
10
+ name?: string;
11
+ id?: string;
12
+ error?: boolean;
10
13
  };
11
14
 
12
15
  declare const MultiSelect: Component<MultiSelectProps>;
@@ -1,7 +1,7 @@
1
1
  import type { Component, Snippet } from 'svelte';
2
2
 
3
3
  export type ScrollAreaProps = {
4
- type?: 'hover' | 'auto' | 'scroll' | 'always';
4
+ /** Allow horizontal scrolling instead of just vertical. */
5
5
  horizontal?: boolean;
6
6
  children?: Snippet;
7
7
  class?: string;
@@ -4,10 +4,13 @@ export type SheetSide = 'top' | 'right' | 'bottom' | 'left';
4
4
 
5
5
  export type SheetProps = {
6
6
  open?: boolean;
7
+ /** `'left'` was previously the default for the now-removed `<Drawer>`. */
7
8
  side?: SheetSide;
8
9
  title?: string;
9
10
  description?: string;
10
11
  hideClose?: boolean;
12
+ dismissable?: boolean;
13
+ ariaLabel?: string;
11
14
  trigger?: Snippet;
12
15
  actions?: Snippet;
13
16
  children?: Snippet;
@@ -10,6 +10,8 @@ export type TabsItem = {
10
10
  export type TabsProps = {
11
11
  value?: string;
12
12
  items?: TabsItem[];
13
+ /** ARIA label for the tablist. Default 'Tabs'. */
14
+ label?: string;
13
15
  class?: string;
14
16
  };
15
17
 
@@ -4,7 +4,8 @@ export type ToggleButtonProps = {
4
4
  pressed?: boolean;
5
5
  disabled?: boolean;
6
6
  icon?: string;
7
- variant?: 'default' | 'outline';
7
+ /** Any `.btn-*` variant. The toggle visual state is controlled by `data-pressed`. */
8
+ variant?: 'primary' | 'secondary' | 'ghost' | 'danger' | 'link';
8
9
  size?: 'sm' | 'md' | 'lg';
9
10
  onpressedchange?: (pressed: boolean) => void;
10
11
  children?: Snippet;
@@ -10,9 +10,10 @@ export type ToggleGroupItem = {
10
10
 
11
11
  export type ToggleButtonGroupProps = {
12
12
  items?: ToggleGroupItem[];
13
- value?: string | string[];
13
+ value?: string | string[] | undefined;
14
14
  multiple?: boolean;
15
15
  disabled?: boolean;
16
+ label?: string;
16
17
  class?: string;
17
18
  };
18
19
 
@@ -3,8 +3,11 @@ import type { Component, Snippet } from 'svelte';
3
3
  export type TooltipProps = {
4
4
  content?: string;
5
5
  side?: 'top' | 'right' | 'bottom' | 'left';
6
+ align?: 'start' | 'center' | 'end';
6
7
  sideOffset?: number;
7
8
  delay?: number;
9
+ /** Wider, surface-elevated styling for tooltips with markup/multiline content. */
10
+ rich?: boolean;
8
11
  trigger?: Snippet;
9
12
  children?: Snippet;
10
13
  triggerClass?: string;
@@ -1,49 +0,0 @@
1
- DialogRoot(bind:open)
2
- +if('trigger')
3
- DialogTrigger(class!="{triggerClass ?? undefined}")
4
- | {@render trigger()}
5
- DialogPortal
6
- DialogOverlay.dialog-overlay
7
- DialogContent(class!="{contentClasses}" data-side!="{side}")
8
- +if('title')
9
- DialogTitle.dialog-title
10
- | {title}
11
- +if('description')
12
- DialogDescription.dialog-description
13
- | {description}
14
- +if('children')
15
- .sheet-body
16
- | {@render children()}
17
- +if('!hideClose')
18
- DialogClose.dialog-close(aria-label="Close")
19
- | ✕
20
-
21
- <script>
22
- import { Dialog } from 'bits-ui'
23
- import { cn } from '@human-synthesis/norns-ui/cn'
24
-
25
- {
26
- Root: DialogRoot
27
- Trigger: DialogTrigger
28
- Portal: DialogPortal
29
- Overlay: DialogOverlay
30
- Content: DialogContent
31
- Title: DialogTitle
32
- Description: DialogDescription
33
- Close: DialogClose
34
- } := Dialog
35
-
36
- {
37
- open = $bindable(false)
38
- side = 'left'
39
- title
40
- description
41
- hideClose = false
42
- trigger
43
- children
44
- triggerClass
45
- class: extra = ''
46
- } .= $props()
47
-
48
- contentClasses := cn 'sheet-content', `sheet-${side}`, extra
49
- </script>
@@ -1,30 +0,0 @@
1
- LinkPreviewRoot(openDelay!="{openDelay}")
2
- LinkPreviewTrigger(href!="{href}" class!="{triggerClass ?? ''}")
3
- | {@render trigger?.()}
4
- LinkPreviewContent.popover-content(side!="{side}" align!="{align}" sideOffset!="{sideOffset}" class!="{contentClass}")
5
- | {@render children?.()}
6
-
7
- <script>
8
- import { LinkPreview } from 'bits-ui'
9
- import { cn } from '@human-synthesis/norns-ui/cn'
10
-
11
- {
12
- Root: LinkPreviewRoot
13
- Trigger: LinkPreviewTrigger
14
- Content: LinkPreviewContent
15
- } := LinkPreview
16
-
17
- {
18
- href
19
- side = 'top'
20
- align = 'center'
21
- sideOffset = 8
22
- openDelay = 700
23
- trigger
24
- children
25
- triggerClass
26
- class: extra = ''
27
- } := $props()
28
-
29
- contentClass := cn 'w-72 p-3', extra
30
- </script>
@@ -1,33 +0,0 @@
1
- TooltipProvider(delayDuration!="{openDelay}")
2
- TooltipRoot
3
- TooltipTrigger(class!="{triggerClass ?? ''}")
4
- | {@render trigger?.()}
5
- TooltipPortal
6
- TooltipContent.popover-content(side!="{side}" align!="{align}" sideOffset!="{sideOffset}" class!="{contentClass}")
7
- | {@render children?.()}
8
-
9
- <script>
10
- import { Tooltip } from 'bits-ui'
11
- import { cn } from '@human-synthesis/norns-ui/cn'
12
-
13
- {
14
- Provider: TooltipProvider
15
- Root: TooltipRoot
16
- Trigger: TooltipTrigger
17
- Portal: TooltipPortal
18
- Content: TooltipContent
19
- } := Tooltip
20
-
21
- {
22
- side = 'top'
23
- align = 'center'
24
- sideOffset = 6
25
- openDelay = 300
26
- trigger
27
- children
28
- triggerClass
29
- class: extra = ''
30
- } := $props()
31
-
32
- contentClass := cn 'max-w-xs p-3 text-sm', extra
33
- </script>
@@ -1,18 +0,0 @@
1
- import type { Component, Snippet } from 'svelte';
2
-
3
- export type DrawerSide = 'left' | 'right';
4
-
5
- export type DrawerProps = {
6
- open?: boolean;
7
- side?: DrawerSide;
8
- title?: string;
9
- description?: string;
10
- hideClose?: boolean;
11
- trigger?: Snippet;
12
- children?: Snippet;
13
- triggerClass?: string;
14
- class?: string;
15
- };
16
-
17
- declare const Drawer: Component<DrawerProps>;
18
- export default Drawer;
@@ -1,16 +0,0 @@
1
- import type { Component, Snippet } from 'svelte';
2
-
3
- export type PreviewCardProps = {
4
- href?: string;
5
- side?: 'top' | 'right' | 'bottom' | 'left';
6
- align?: 'start' | 'center' | 'end';
7
- sideOffset?: number;
8
- openDelay?: number;
9
- trigger?: Snippet;
10
- children?: Snippet;
11
- triggerClass?: string;
12
- class?: string;
13
- };
14
-
15
- declare const PreviewCard: Component<PreviewCardProps>;
16
- export default PreviewCard;
@@ -1,16 +0,0 @@
1
- import type { Component, Snippet } from 'svelte';
2
-
3
- export type RichTooltipProps = {
4
- side?: 'top' | 'right' | 'bottom' | 'left';
5
- align?: 'start' | 'center' | 'end';
6
- sideOffset?: number;
7
- openDelay?: number;
8
- closeDelay?: number;
9
- trigger?: Snippet;
10
- children?: Snippet;
11
- triggerClass?: string;
12
- class?: string;
13
- };
14
-
15
- declare const RichTooltip: Component<RichTooltipProps>;
16
- export default RichTooltip;