@loidolt/theme-svelte 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/README.md +11 -0
  2. package/dist/announcer.svelte.d.ts +36 -0
  3. package/dist/announcer.svelte.js +73 -0
  4. package/dist/attachments.d.ts +83 -0
  5. package/dist/attachments.js +211 -0
  6. package/dist/components/ActiveFilterChips.svelte +80 -0
  7. package/dist/components/ActiveFilterChips.svelte.d.ts +41 -0
  8. package/dist/components/AlertDialog.svelte +4 -4
  9. package/dist/components/AppShell.svelte +9 -2
  10. package/dist/components/AppShell.svelte.d.ts +3 -1
  11. package/dist/components/AspectRatio.svelte +32 -0
  12. package/dist/components/AspectRatio.svelte.d.ts +13 -0
  13. package/dist/components/AudioPlayer.svelte +94 -0
  14. package/dist/components/AudioPlayer.svelte.d.ts +24 -0
  15. package/dist/components/Avatar.svelte +85 -0
  16. package/dist/components/Avatar.svelte.d.ts +31 -0
  17. package/dist/components/Badge.svelte +28 -2
  18. package/dist/components/Badge.svelte.d.ts +13 -1
  19. package/dist/components/Combobox.svelte +180 -0
  20. package/dist/components/Combobox.svelte.d.ts +77 -0
  21. package/dist/components/DataTable.svelte +228 -0
  22. package/dist/components/DataTable.svelte.d.ts +62 -0
  23. package/dist/components/DataTableColumnVisibility.svelte +46 -0
  24. package/dist/components/DataTableColumnVisibility.svelte.d.ts +31 -0
  25. package/dist/components/DataTableFacetedFilter.svelte +87 -0
  26. package/dist/components/DataTableFacetedFilter.svelte.d.ts +40 -0
  27. package/dist/components/DataTablePagination.svelte +68 -0
  28. package/dist/components/DataTablePagination.svelte.d.ts +42 -0
  29. package/dist/components/DataTableSearch.svelte +67 -0
  30. package/dist/components/DataTableSearch.svelte.d.ts +37 -0
  31. package/dist/components/Dialog.svelte +35 -14
  32. package/dist/components/Dialog.svelte.d.ts +7 -0
  33. package/dist/components/Drawer.svelte +3 -3
  34. package/dist/components/DropdownMenu.svelte +95 -28
  35. package/dist/components/DropdownMenu.svelte.d.ts +12 -3
  36. package/dist/components/Field.svelte +2 -3
  37. package/dist/components/Fieldset.svelte +2 -3
  38. package/dist/components/Filmstrip.svelte +10 -3
  39. package/dist/components/FilterPanel.svelte +62 -0
  40. package/dist/components/FilterPanel.svelte.d.ts +22 -0
  41. package/dist/components/Lightbox.svelte +239 -0
  42. package/dist/components/Lightbox.svelte.d.ts +40 -0
  43. package/dist/components/LiveRegion.svelte +48 -0
  44. package/dist/components/LiveRegion.svelte.d.ts +20 -0
  45. package/dist/components/MediaCarousel.svelte +177 -0
  46. package/dist/components/MediaCarousel.svelte.d.ts +32 -0
  47. package/dist/components/MediaEmbed.svelte +116 -0
  48. package/dist/components/MediaEmbed.svelte.d.ts +34 -0
  49. package/dist/components/MediaGrid.svelte +91 -0
  50. package/dist/components/MediaGrid.svelte.d.ts +24 -0
  51. package/dist/components/MultiSelect.svelte +232 -0
  52. package/dist/components/MultiSelect.svelte.d.ts +67 -0
  53. package/dist/components/NumberField.svelte +53 -25
  54. package/dist/components/NumberField.svelte.d.ts +47 -18
  55. package/dist/components/OTPInput.svelte +94 -0
  56. package/dist/components/OTPInput.svelte.d.ts +26 -0
  57. package/dist/components/PasswordInput.svelte +93 -0
  58. package/dist/components/PasswordInput.svelte.d.ts +24 -0
  59. package/dist/components/Progress.svelte +57 -14
  60. package/dist/components/Progress.svelte.d.ts +13 -0
  61. package/dist/components/RadioGroup.svelte +19 -5
  62. package/dist/components/RadioGroup.svelte.d.ts +3 -2
  63. package/dist/components/Select.svelte +15 -5
  64. package/dist/components/Select.svelte.d.ts +3 -2
  65. package/dist/components/SignaturePad.svelte +317 -0
  66. package/dist/components/SignaturePad.svelte.d.ts +48 -0
  67. package/dist/components/Skeleton.svelte +40 -9
  68. package/dist/components/Skeleton.svelte.d.ts +8 -0
  69. package/dist/components/SkipLink.svelte +48 -0
  70. package/dist/components/SkipLink.svelte.d.ts +14 -0
  71. package/dist/components/Slider.svelte +148 -0
  72. package/dist/components/Slider.svelte.d.ts +55 -0
  73. package/dist/components/Spinner.svelte +11 -2
  74. package/dist/components/Spinner.svelte.d.ts +3 -0
  75. package/dist/components/Tabs.svelte.d.ts +1 -1
  76. package/dist/components/Thumbnail.svelte +52 -6
  77. package/dist/components/Thumbnail.svelte.d.ts +14 -2
  78. package/dist/components/Toast.svelte +24 -0
  79. package/dist/components/Toast.svelte.d.ts +10 -0
  80. package/dist/components/ToastViewport.svelte +10 -1
  81. package/dist/components/ToastViewport.svelte.d.ts +2 -0
  82. package/dist/components/Toolbar.svelte +49 -0
  83. package/dist/components/Toolbar.svelte.d.ts +23 -0
  84. package/dist/components/Tooltip.svelte +9 -1
  85. package/dist/components/Tooltip.svelte.d.ts +2 -0
  86. package/dist/components/VideoPlayer.svelte +136 -0
  87. package/dist/components/VideoPlayer.svelte.d.ts +38 -0
  88. package/dist/data-table-utils.d.ts +62 -0
  89. package/dist/data-table-utils.js +91 -0
  90. package/dist/data-table.svelte.d.ts +132 -0
  91. package/dist/data-table.svelte.js +292 -0
  92. package/dist/hls.d.ts +35 -0
  93. package/dist/hls.js +37 -0
  94. package/dist/hls.svelte.d.ts +22 -0
  95. package/dist/hls.svelte.js +66 -0
  96. package/dist/index.d.ts +47 -4
  97. package/dist/index.js +35 -2
  98. package/dist/internal/EditableCell.svelte +58 -0
  99. package/dist/internal/EditableCell.svelte.d.ts +8 -0
  100. package/dist/internal/ListboxEntries.svelte +49 -0
  101. package/dist/internal/ListboxEntries.svelte.d.ts +35 -0
  102. package/dist/internal/media/MediaControls.svelte +163 -0
  103. package/dist/internal/media/MediaControls.svelte.d.ts +12 -0
  104. package/dist/internal/media/MediaStage.svelte +49 -0
  105. package/dist/internal/media/MediaStage.svelte.d.ts +11 -0
  106. package/dist/internal/media/MediaTile.svelte +36 -0
  107. package/dist/internal/media/MediaTile.svelte.d.ts +11 -0
  108. package/dist/internal/media/keys.d.ts +7 -0
  109. package/dist/internal/media/keys.js +51 -0
  110. package/dist/internal/media/labels.d.ts +19 -0
  111. package/dist/internal/media/labels.js +15 -0
  112. package/dist/internal/options.d.ts +9 -0
  113. package/dist/internal/options.js +20 -0
  114. package/dist/media-player.svelte.d.ts +61 -0
  115. package/dist/media-player.svelte.js +246 -0
  116. package/dist/media-utils.d.ts +112 -0
  117. package/dist/media-utils.js +205 -0
  118. package/dist/media-zoom.svelte.d.ts +33 -0
  119. package/dist/media-zoom.svelte.js +126 -0
  120. package/dist/signature.d.ts +55 -0
  121. package/dist/signature.js +52 -0
  122. package/dist/toaster.svelte.d.ts +31 -2
  123. package/dist/toaster.svelte.js +30 -2
  124. package/dist/types.d.ts +62 -3
  125. package/dist/utils.d.ts +9 -0
  126. package/dist/utils.js +11 -0
  127. package/package.json +10 -4
@@ -0,0 +1,55 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { Orientation } from '../types.js';
4
+ declare function $$render<V extends number | number[] = number>(): {
5
+ props: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
6
+ /** A number for one thumb, an array for a range — one thumb per entry. */
7
+ value?: V;
8
+ min?: number;
9
+ max?: number;
10
+ /** The increment, or an explicit list of the only values allowed. */
11
+ step?: number | number[];
12
+ orientation?: Orientation;
13
+ disabled?: boolean;
14
+ /** Accessible name. With two or more thumbs each is named from it by `thumbLabel`. */
15
+ label: string;
16
+ thumbLabel?: (index: number, count: number) => string;
17
+ /** Spoken (`aria-valuetext`) and shown for each value — add units here: `(v) => \`${v} mm\``. */
18
+ formatValue?: (value: number) => string;
19
+ /** Show the formatted value beside the track. */
20
+ showValue?: boolean;
21
+ /** Mark every step along the track. Sensible only for a coarse `step`. */
22
+ ticks?: boolean;
23
+ /** Submits each value as a hidden input under this name. */
24
+ name?: string;
25
+ /** Every change, while dragging too. */
26
+ onValueChange?: (value: V) => void;
27
+ /** Only when the user lets go or finishes a key press — the moment to save. */
28
+ onValueCommit?: (value: V) => void;
29
+ /** Rendered after the track, e.g. min/max captions. */
30
+ children?: Snippet;
31
+ class?: string;
32
+ ref?: HTMLDivElement | null;
33
+ };
34
+ exports: {};
35
+ bindings: "value" | "ref";
36
+ slots: {};
37
+ events: {};
38
+ };
39
+ declare class __sveltets_Render<V extends number | number[] = number> {
40
+ props(): ReturnType<typeof $$render<V>>['props'];
41
+ events(): ReturnType<typeof $$render<V>>['events'];
42
+ slots(): ReturnType<typeof $$render<V>>['slots'];
43
+ bindings(): "value" | "ref";
44
+ exports(): {};
45
+ }
46
+ interface $$IsomorphicComponent {
47
+ new <V extends number | number[] = number>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<V>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<V>['props']>, ReturnType<__sveltets_Render<V>['events']>, ReturnType<__sveltets_Render<V>['slots']>> & {
48
+ $$bindings?: ReturnType<__sveltets_Render<V>['bindings']>;
49
+ } & ReturnType<__sveltets_Render<V>['exports']>;
50
+ <V extends number | number[] = number>(internal: unknown, props: ReturnType<__sveltets_Render<V>['props']> & {}): ReturnType<__sveltets_Render<V>['exports']>;
51
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
52
+ }
53
+ declare const Slider: $$IsomorphicComponent;
54
+ type Slider<V extends number | number[] = number> = InstanceType<typeof Slider<V>>;
55
+ export default Slider;
@@ -1,20 +1,29 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { ControlSize } from '../types.js';
3
4
  import { cx } from '../utils.js';
4
5
 
5
6
  interface Props extends HTMLAttributes<HTMLSpanElement> {
6
7
  /** Accessible name. Pass `undefined` when an adjacent label already announces the wait. */
7
8
  label?: string;
9
+ /** Omit to follow the surrounding font size, which suits a spinner inside a button. */
10
+ size?: ControlSize;
8
11
  class?: string;
9
12
  ref?: HTMLSpanElement | null;
10
13
  }
11
14
 
12
- let { label = 'Loading', class: className, ref = $bindable(null), ...rest }: Props = $props();
15
+ let {
16
+ label = 'Loading',
17
+ size,
18
+ class: className,
19
+ ref = $bindable(null),
20
+ ...rest
21
+ }: Props = $props();
13
22
  </script>
14
23
 
15
24
  <span
16
25
  bind:this={ref}
17
- class={cx('ldt-spinner', className)}
26
+ class={cx('ldt-spinner', size && `ldt-spinner--${size}`, className)}
18
27
  role={label ? 'status' : undefined}
19
28
  aria-label={label}
20
29
  aria-hidden={label ? undefined : 'true'}
@@ -1,7 +1,10 @@
1
1
  import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { ControlSize } from '../types.js';
2
3
  interface Props extends HTMLAttributes<HTMLSpanElement> {
3
4
  /** Accessible name. Pass `undefined` when an adjacent label already announces the wait. */
4
5
  label?: string;
6
+ /** Omit to follow the surrounding font size, which suits a spinner inside a button. */
7
+ size?: ControlSize;
5
8
  class?: string;
6
9
  ref?: HTMLSpanElement | null;
7
10
  }
@@ -2,7 +2,7 @@ import { Tabs as TabsPrimitive } from 'bits-ui';
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { NavItem, Orientation } from '../types.js';
4
4
  declare function $$render<T extends string = string>(): {
5
- props: Omit<TabsPrimitive.RootProps, "children" | "class" | "value" | "onValueChange" | "ref" | "child" | "orientation"> & {
5
+ props: Omit<TabsPrimitive.RootProps, "orientation" | "value" | "children" | "class" | "onValueChange" | "ref" | "child"> & {
6
6
  /** Defaults to the first tab, so a panel is always rendered. */
7
7
  value?: T;
8
8
  tabs: NavItem<T>[];
@@ -1,19 +1,32 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
+ import { aspectRatio } from '@loidolt/theme-tokens';
5
+ import type { AspectRatioName } from '../media-utils.js';
4
6
  import { cx } from '../utils.js';
5
7
 
6
8
  interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
7
9
  src?: string;
8
10
  /** Required whenever `src` is set — decorative images should say so with `alt=""`. */
9
11
  alt?: string;
10
- /** CSS aspect-ratio value: `'4/3'`, `'1/1'`, or a number. */
11
- ratio?: string | number;
12
+ /** Candidate sources for responsive images, with `sizes`. */
13
+ srcset?: string;
14
+ sizes?: string;
15
+ /** A named frame (`photo`, `video`, `square`…), a CSS aspect-ratio value, or a number. */
16
+ ratio?: AspectRatioName | string | number;
12
17
  fit?: 'contain' | 'cover';
13
18
  /** `sunken` recesses into the page; `paper` stays white in every theme for artwork. */
14
19
  surface?: 'sunken' | 'paper';
20
+ /** `lazy` (the default) waits until the image nears the viewport. */
21
+ loading?: 'lazy' | 'eager';
22
+ /** Shown if the image fails to load. Defaults to an empty frame. */
23
+ fallback?: Snippet;
24
+ /** Content over the image — a badge, a duration, a selection mark. */
25
+ overlay?: Snippet;
15
26
  /** Alternative to `src` — inline SVG, canvas, anything that fills the frame. */
16
27
  children?: Snippet;
28
+ onload?: (event: Event) => void;
29
+ onerror?: (event: Event) => void;
17
30
  class?: string;
18
31
  ref?: HTMLElement | null;
19
32
  }
@@ -21,14 +34,33 @@
21
34
  let {
22
35
  src,
23
36
  alt = '',
37
+ srcset,
38
+ sizes,
24
39
  ratio = '4/3',
25
40
  fit = 'contain',
26
41
  surface = 'sunken',
42
+ loading = 'lazy',
43
+ fallback,
44
+ overlay,
27
45
  children,
46
+ onload,
47
+ onerror,
28
48
  class: className,
29
49
  ref = $bindable(null),
30
50
  ...rest
31
51
  }: Props = $props();
52
+
53
+ const frame = $derived(
54
+ typeof ratio === 'string' && ratio in aspectRatio
55
+ ? aspectRatio[ratio as AspectRatioName]
56
+ : ratio
57
+ );
58
+
59
+ // Resets to `loading` whenever `src` changes; the image's own events move it on.
60
+ let status = $derived.by<'loading' | 'loaded' | 'error'>(() => {
61
+ void src;
62
+ return 'loading';
63
+ });
32
64
  </script>
33
65
 
34
66
  <figure
@@ -39,13 +71,27 @@
39
71
  fit === 'cover' && 'ldt-thumbnail--cover',
40
72
  className
41
73
  )}
42
- style={`--ldt-thumbnail-ratio: ${ratio};`}
74
+ style={`--ldt-thumbnail-ratio: ${frame};`}
75
+ data-status={src && !children ? status : undefined}
43
76
  {...rest}
44
77
  >
45
- {#if children}{@render children()}{:else if src}<img
78
+ {#if children}{@render children()}{:else if src && status === 'error'}{#if fallback}{@render fallback()}{:else}<span
79
+ class="ldt-sr-only">{alt}</span
80
+ >{/if}{:else if src}<img
46
81
  class="ldt-thumbnail__image"
47
82
  {src}
48
83
  {alt}
49
- loading="lazy"
50
- />{/if}
84
+ {srcset}
85
+ {sizes}
86
+ {loading}
87
+ decoding="async"
88
+ onload={(event) => {
89
+ status = 'loaded';
90
+ onload?.(event);
91
+ }}
92
+ onerror={(event) => {
93
+ status = 'error';
94
+ onerror?.(event);
95
+ }}
96
+ />{/if}{#if overlay}<div class="ldt-thumbnail__overlay">{@render overlay()}</div>{/if}
51
97
  </figure>
@@ -1,16 +1,28 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { AspectRatioName } from '../media-utils.js';
3
4
  interface Props extends Omit<HTMLAttributes<HTMLElement>, 'children'> {
4
5
  src?: string;
5
6
  /** Required whenever `src` is set — decorative images should say so with `alt=""`. */
6
7
  alt?: string;
7
- /** CSS aspect-ratio value: `'4/3'`, `'1/1'`, or a number. */
8
- ratio?: string | number;
8
+ /** Candidate sources for responsive images, with `sizes`. */
9
+ srcset?: string;
10
+ sizes?: string;
11
+ /** A named frame (`photo`, `video`, `square`…), a CSS aspect-ratio value, or a number. */
12
+ ratio?: AspectRatioName | string | number;
9
13
  fit?: 'contain' | 'cover';
10
14
  /** `sunken` recesses into the page; `paper` stays white in every theme for artwork. */
11
15
  surface?: 'sunken' | 'paper';
16
+ /** `lazy` (the default) waits until the image nears the viewport. */
17
+ loading?: 'lazy' | 'eager';
18
+ /** Shown if the image fails to load. Defaults to an empty frame. */
19
+ fallback?: Snippet;
20
+ /** Content over the image — a badge, a duration, a selection mark. */
21
+ overlay?: Snippet;
12
22
  /** Alternative to `src` — inline SVG, canvas, anything that fills the frame. */
13
23
  children?: Snippet;
24
+ onload?: (event: Event) => void;
25
+ onerror?: (event: Event) => void;
14
26
  class?: string;
15
27
  ref?: HTMLElement | null;
16
28
  }
@@ -1,7 +1,9 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
+ import Button from './Button.svelte';
4
5
  import IconButton from './IconButton.svelte';
6
+ import type { ToastAction } from '../toaster.svelte.js';
5
7
  import type { StatusVariant } from '../types.js';
6
8
  import { cx } from '../utils.js';
7
9
 
@@ -11,6 +13,15 @@
11
13
  variant?: StatusVariant;
12
14
  dismissLabel?: string;
13
15
  onDismiss?: () => void;
16
+ /** One follow-up button, e.g. Undo. Runs `onAction`, then dismisses unless told not to. */
17
+ action?: ToastAction;
18
+ /** Custom action area, in place of `action`. */
19
+ actions?: Snippet;
20
+ /**
21
+ * Read by `createToaster`, not the component. Declared so `{...toast}` from a toaster's queue
22
+ * does not leak it onto the element as an attribute.
23
+ */
24
+ duration?: number;
14
25
  class?: string;
15
26
  children?: Snippet;
16
27
  ref?: HTMLDivElement | null;
@@ -22,6 +33,10 @@
22
33
  variant,
23
34
  dismissLabel = 'Dismiss notification',
24
35
  onDismiss,
36
+ action,
37
+ actions,
38
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- read by the toaster, never rendered
39
+ duration: _duration,
25
40
  class: className,
26
41
  children,
27
42
  ref = $bindable(null),
@@ -44,6 +59,15 @@
44
59
  {description}
45
60
  </p>{/if}{#if children}<div class="ldt-toast__description">
46
61
  {@render children()}
62
+ </div>{/if}{#if actions || action}<div class="ldt-toast__actions">
63
+ {#if actions}{@render actions()}{:else if action}<Button
64
+ size="sm"
65
+ variant="quiet"
66
+ onclick={() => {
67
+ action.onAction();
68
+ if (action.dismiss !== false) onDismiss?.();
69
+ }}>{action.label}</Button
70
+ >{/if}
47
71
  </div>{/if}{#if onDismiss}<IconButton
48
72
  class="ldt-toast__dismiss"
49
73
  size="sm"
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { ToastAction } from '../toaster.svelte.js';
3
4
  import type { StatusVariant } from '../types.js';
4
5
  interface Props extends HTMLAttributes<HTMLDivElement> {
5
6
  title: string;
@@ -7,6 +8,15 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
7
8
  variant?: StatusVariant;
8
9
  dismissLabel?: string;
9
10
  onDismiss?: () => void;
11
+ /** One follow-up button, e.g. Undo. Runs `onAction`, then dismisses unless told not to. */
12
+ action?: ToastAction;
13
+ /** Custom action area, in place of `action`. */
14
+ actions?: Snippet;
15
+ /**
16
+ * Read by `createToaster`, not the component. Declared so `{...toast}` from a toaster's queue
17
+ * does not leak it onto the element as an attribute.
18
+ */
19
+ duration?: number;
10
20
  class?: string;
11
21
  children?: Snippet;
12
22
  ref?: HTMLDivElement | null;
@@ -7,6 +7,9 @@
7
7
  label?: string;
8
8
  /** `polite` for routine updates; `assertive` interrupts and should be rare. */
9
9
  politeness?: 'polite' | 'assertive';
10
+ /** Which corner or edge the stack sits against. Top positions stack newest-last as well. */
11
+ position?:
12
+ 'bottom-end' | 'bottom-start' | 'bottom-center' | 'top-end' | 'top-start' | 'top-center';
10
13
  class?: string;
11
14
  children: Snippet;
12
15
  ref?: HTMLDivElement | null;
@@ -15,6 +18,7 @@
15
18
  let {
16
19
  label = 'Notifications',
17
20
  politeness = 'polite',
21
+ position = 'bottom-end',
18
22
  class: className,
19
23
  children,
20
24
  ref = $bindable(null),
@@ -28,11 +32,16 @@
28
32
  -->
29
33
  <div
30
34
  bind:this={ref}
31
- class={cx('ldt-toast-viewport', className)}
35
+ class={cx(
36
+ 'ldt-toast-viewport',
37
+ position !== 'bottom-end' && `ldt-toast-viewport--${position}`,
38
+ className
39
+ )}
32
40
  aria-label={label}
33
41
  aria-live={politeness}
34
42
  aria-relevant="additions text"
35
43
  {...rest}
44
+ role="log"
36
45
  >
37
46
  {@render children()}
38
47
  </div>
@@ -4,6 +4,8 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
4
4
  label?: string;
5
5
  /** `polite` for routine updates; `assertive` interrupts and should be rare. */
6
6
  politeness?: 'polite' | 'assertive';
7
+ /** Which corner or edge the stack sits against. Top positions stack newest-last as well. */
8
+ position?: 'bottom-end' | 'bottom-start' | 'bottom-center' | 'top-end' | 'top-start' | 'top-center';
7
9
  class?: string;
8
10
  children: Snippet;
9
11
  ref?: HTMLDivElement | null;
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import { rovingFocus } from '../attachments.js';
5
+ import type { Orientation } from '../types.js';
6
+ import { cx } from '../utils.js';
7
+
8
+ interface Props extends HTMLAttributes<HTMLDivElement> {
9
+ /** Accessible name, e.g. "Sheet list tools". */
10
+ label: string;
11
+ /** Leading controls — search, filters, a result count. */
12
+ children?: Snippet;
13
+ /** Controls pushed to the far end — view toggles, a sort menu. */
14
+ end?: Snippet;
15
+ orientation?: Orientation;
16
+ /**
17
+ * Make it an ARIA `toolbar`: one tab stop, arrow keys between the controls marked
18
+ * `data-roving-item`. Leave it off (a labelled `group`, Tab between controls) when the bar
19
+ * holds a text field or a control that owns its own arrow keys, like a `ToggleGroup`.
20
+ */
21
+ roving?: boolean;
22
+ class?: string;
23
+ ref?: HTMLDivElement | null;
24
+ }
25
+
26
+ let {
27
+ label,
28
+ children,
29
+ end,
30
+ orientation = 'horizontal',
31
+ roving = false,
32
+ class: className,
33
+ ref = $bindable(null),
34
+ ...rest
35
+ }: Props = $props();
36
+ </script>
37
+
38
+ <div
39
+ bind:this={ref}
40
+ class={cx('ldt-toolbar', orientation === 'vertical' && 'ldt-toolbar--vertical', className)}
41
+ role={roving ? 'toolbar' : 'group'}
42
+ aria-label={label}
43
+ aria-orientation={roving ? orientation : undefined}
44
+ {@attach roving ? rovingFocus({ orientation }) : undefined}
45
+ {...rest}
46
+ >
47
+ {#if children}{@render children()}{/if}
48
+ {#if end}<div class="ldt-toolbar__end">{@render end()}</div>{/if}
49
+ </div>
@@ -0,0 +1,23 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { Orientation } from '../types.js';
4
+ interface Props extends HTMLAttributes<HTMLDivElement> {
5
+ /** Accessible name, e.g. "Sheet list tools". */
6
+ label: string;
7
+ /** Leading controls — search, filters, a result count. */
8
+ children?: Snippet;
9
+ /** Controls pushed to the far end — view toggles, a sort menu. */
10
+ end?: Snippet;
11
+ orientation?: Orientation;
12
+ /**
13
+ * Make it an ARIA `toolbar`: one tab stop, arrow keys between the controls marked
14
+ * `data-roving-item`. Leave it off (a labelled `group`, Tab between controls) when the bar
15
+ * holds a text field or a control that owns its own arrow keys, like a `ToggleGroup`.
16
+ */
17
+ roving?: boolean;
18
+ class?: string;
19
+ ref?: HTMLDivElement | null;
20
+ }
21
+ declare const Toolbar: import("svelte").Component<Props, {}, "ref">;
22
+ type Toolbar = ReturnType<typeof Toolbar>;
23
+ export default Toolbar;
@@ -21,6 +21,8 @@
21
21
  side?: Placement;
22
22
  align?: Alignment;
23
23
  sideOffset?: number;
24
+ /** Point the tooltip at its trigger — worth it when the trigger is small or crowded. */
25
+ arrow?: boolean;
24
26
  /** Ignored when an ancestor `TooltipProvider` is present. */
25
27
  delayDuration?: number;
26
28
  /** `class` lands on the portaled Content element. */
@@ -39,6 +41,7 @@
39
41
  side = 'top',
40
42
  align = 'center',
41
43
  sideOffset = 6,
44
+ arrow = false,
42
45
  delayDuration = 350,
43
46
  class: className,
44
47
  onOpenChange,
@@ -65,7 +68,12 @@
65
68
  {align}
66
69
  {sideOffset}
67
70
  class={cx('ldt-tooltip', className)}
68
- {...rest}>{content}</TooltipPrimitive.Content
71
+ {...rest}
72
+ >{content}{#if arrow}<TooltipPrimitive.Arrow
73
+ class="ldt-tooltip__arrow"
74
+ width={10}
75
+ height={5}
76
+ />{/if}</TooltipPrimitive.Content
69
77
  ></TooltipPrimitive.Portal
70
78
  >
71
79
  </TooltipPrimitive.Root>
@@ -16,6 +16,8 @@ type Props = Omit<TooltipContentProps, 'children' | 'class' | 'child'> & {
16
16
  side?: Placement;
17
17
  align?: Alignment;
18
18
  sideOffset?: number;
19
+ /** Point the tooltip at its trigger — worth it when the trigger is small or crowded. */
20
+ arrow?: boolean;
19
21
  /** Ignored when an ancestor `TooltipProvider` is present. */
20
22
  delayDuration?: number;
21
23
  /** `class` lands on the portaled Content element. */
@@ -0,0 +1,136 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import type { HTMLAttributes } from 'svelte/elements';
4
+ import type { HlsLoader } from '../hls.js';
5
+ import { createHlsSource } from '../hls.svelte.js';
6
+ import { defaultMediaLabels, type MediaPlayerLabels } from '../internal/media/labels.js';
7
+ import { mediaKeydown } from '../internal/media/keys.js';
8
+ import MediaControls from '../internal/media/MediaControls.svelte';
9
+ import { createMediaPlayer } from '../media-player.svelte.js';
10
+ import {
11
+ isHlsSource,
12
+ resolveAspectRatio,
13
+ toMediaSources,
14
+ type AspectRatioName,
15
+ type MediaSourceEntry,
16
+ type MediaTextTrack,
17
+ } from '../media-utils.js';
18
+ import { cx } from '../utils.js';
19
+
20
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
21
+ /** A URL, or several sources for the browser to choose from. `.m3u8` plays as HLS. */
22
+ src: string | MediaSourceEntry[];
23
+ /** Names the player for assistive tech. */
24
+ label: string;
25
+ poster?: string;
26
+ /** Captions and subtitles. Provide captions for any video with speech (WCAG 1.2.2). */
27
+ tracks?: MediaTextTrack[];
28
+ ratio?: AspectRatioName | number | string;
29
+ fit?: 'contain' | 'cover';
30
+ /** Browsers only autoplay muted media; `autoplay` implies `muted`. */
31
+ autoplay?: boolean;
32
+ muted?: boolean;
33
+ loop?: boolean;
34
+ preload?: 'none' | 'metadata' | 'auto';
35
+ /** `custom` draws this library's controls; `native` uses the browser's; `none` hides both. */
36
+ controls?: 'custom' | 'native' | 'none';
37
+ /** hls.js loader for this player, in place of the one given to `setHlsLoader()`. */
38
+ hlsLoader?: HlsLoader;
39
+ hlsConfig?: Record<string, unknown>;
40
+ /** Content layered over the video, e.g. a title card. */
41
+ overlay?: Snippet;
42
+ labels?: Partial<MediaPlayerLabels>;
43
+ onEnded?: () => void;
44
+ onTimeUpdate?: (seconds: number) => void;
45
+ class?: string;
46
+ ref?: HTMLDivElement | null;
47
+ /** The `<video>` element. */
48
+ mediaRef?: HTMLVideoElement | null;
49
+ }
50
+
51
+ let {
52
+ src,
53
+ label,
54
+ poster,
55
+ tracks = [],
56
+ ratio = 'video',
57
+ fit = 'contain',
58
+ autoplay = false,
59
+ muted = false,
60
+ loop = false,
61
+ preload = 'metadata',
62
+ controls = 'custom',
63
+ hlsLoader,
64
+ hlsConfig,
65
+ overlay,
66
+ labels,
67
+ onEnded,
68
+ onTimeUpdate,
69
+ class: className,
70
+ ref = $bindable(null),
71
+ mediaRef = $bindable(null),
72
+ ...rest
73
+ }: Props = $props();
74
+
75
+ const text = $derived({ ...defaultMediaLabels, ...labels });
76
+ const sources = $derived(toMediaSources(src));
77
+ const stream = $derived(sources.find((source) => isHlsSource(source)));
78
+ const player = createMediaPlayer({
79
+ onEnded: () => onEnded?.(),
80
+ onTimeUpdate: (seconds) => onTimeUpdate?.(seconds),
81
+ });
82
+ const hls = createHlsSource({
83
+ get loader() {
84
+ return hlsLoader;
85
+ },
86
+ get config() {
87
+ return hlsConfig;
88
+ },
89
+ });
90
+ const failed = $derived(
91
+ Boolean(player.error) || hls.status === 'unsupported' || hls.status === 'error'
92
+ );
93
+ </script>
94
+
95
+ <div
96
+ bind:this={ref}
97
+ class={cx('ldt-media-player', 'ldt-media-player--video', className)}
98
+ style:--ldt-aspect-ratio={resolveAspectRatio(ratio)}
99
+ data-playing={player.playing ? '' : undefined}
100
+ role="group"
101
+ aria-label={label}
102
+ onkeydown={controls === 'custom' ? mediaKeydown(player, () => ref) : undefined}
103
+ {...rest}
104
+ >
105
+ <video
106
+ bind:this={mediaRef}
107
+ class="ldt-media-player__media"
108
+ style:object-fit={fit}
109
+ {poster}
110
+ {preload}
111
+ {autoplay}
112
+ muted={muted || autoplay}
113
+ {loop}
114
+ playsinline
115
+ controls={controls === 'native'}
116
+ crossorigin={tracks.length ? 'anonymous' : undefined}
117
+ {@attach player.attach}
118
+ {@attach stream ? hls.source(stream.src) : undefined}
119
+ onclick={controls === 'custom' ? () => player.toggle() : undefined}
120
+ >
121
+ {#if !stream}{#each sources as source (source.src)}<source
122
+ src={source.src}
123
+ type={source.type}
124
+ />{/each}{/if}
125
+ {#each tracks as track (track.src)}<track
126
+ src={track.src}
127
+ kind={track.kind ?? 'captions'}
128
+ srclang={track.srclang}
129
+ label={track.label}
130
+ default={track.default}
131
+ />{/each}
132
+ </video>
133
+ {#if overlay}<div class="ldt-media-player__overlay">{@render overlay()}</div>{/if}
134
+ {#if failed}<p class="ldt-media-player__error" role="alert">{text.error}</p>{/if}
135
+ {#if controls === 'custom'}<MediaControls {player} labels={text} video container={ref} />{/if}
136
+ </div>
@@ -0,0 +1,38 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLAttributes } from 'svelte/elements';
3
+ import type { HlsLoader } from '../hls.js';
4
+ import { type MediaPlayerLabels } from '../internal/media/labels.js';
5
+ import { type AspectRatioName, type MediaSourceEntry, type MediaTextTrack } from '../media-utils.js';
6
+ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
7
+ /** A URL, or several sources for the browser to choose from. `.m3u8` plays as HLS. */
8
+ src: string | MediaSourceEntry[];
9
+ /** Names the player for assistive tech. */
10
+ label: string;
11
+ poster?: string;
12
+ /** Captions and subtitles. Provide captions for any video with speech (WCAG 1.2.2). */
13
+ tracks?: MediaTextTrack[];
14
+ ratio?: AspectRatioName | number | string;
15
+ fit?: 'contain' | 'cover';
16
+ /** Browsers only autoplay muted media; `autoplay` implies `muted`. */
17
+ autoplay?: boolean;
18
+ muted?: boolean;
19
+ loop?: boolean;
20
+ preload?: 'none' | 'metadata' | 'auto';
21
+ /** `custom` draws this library's controls; `native` uses the browser's; `none` hides both. */
22
+ controls?: 'custom' | 'native' | 'none';
23
+ /** hls.js loader for this player, in place of the one given to `setHlsLoader()`. */
24
+ hlsLoader?: HlsLoader;
25
+ hlsConfig?: Record<string, unknown>;
26
+ /** Content layered over the video, e.g. a title card. */
27
+ overlay?: Snippet;
28
+ labels?: Partial<MediaPlayerLabels>;
29
+ onEnded?: () => void;
30
+ onTimeUpdate?: (seconds: number) => void;
31
+ class?: string;
32
+ ref?: HTMLDivElement | null;
33
+ /** The `<video>` element. */
34
+ mediaRef?: HTMLVideoElement | null;
35
+ }
36
+ declare const VideoPlayer: import("svelte").Component<Props, {}, "ref" | "mediaRef">;
37
+ type VideoPlayer = ReturnType<typeof VideoPlayer>;
38
+ export default VideoPlayer;