@geoffcox/sterling-svelte 2.0.1 → 2.0.3

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/Button.svelte +18 -14
  3. package/dist/Button.svelte.d.ts +0 -1
  4. package/dist/Callout.svelte +162 -96
  5. package/dist/Callout.svelte.d.ts +1 -2
  6. package/dist/Checkbox.svelte +34 -15
  7. package/dist/Checkbox.svelte.d.ts +0 -1
  8. package/dist/Dialog.svelte +121 -71
  9. package/dist/Dialog.svelte.d.ts +1 -1
  10. package/dist/Dropdown.svelte +106 -56
  11. package/dist/Dropdown.svelte.d.ts +8 -3
  12. package/dist/Input.svelte +54 -29
  13. package/dist/Input.svelte.d.ts +1 -2
  14. package/dist/Label.svelte +99 -55
  15. package/dist/Label.svelte.d.ts +4 -4
  16. package/dist/Link.svelte +20 -14
  17. package/dist/Link.svelte.d.ts +0 -1
  18. package/dist/List.svelte +181 -126
  19. package/dist/List.svelte.d.ts +0 -1
  20. package/dist/ListItem.svelte +36 -21
  21. package/dist/ListItem.svelte.d.ts +0 -1
  22. package/dist/Menu.svelte +67 -45
  23. package/dist/Menu.svelte.d.ts +0 -1
  24. package/dist/MenuBar.svelte +96 -65
  25. package/dist/MenuBar.svelte.d.ts +0 -1
  26. package/dist/MenuButton.svelte +102 -62
  27. package/dist/MenuButton.svelte.d.ts +1 -1
  28. package/dist/MenuItem.svelte +332 -243
  29. package/dist/MenuItem.svelte.d.ts +3 -3
  30. package/dist/MenuSeparator.svelte +7 -7
  31. package/dist/MenuSeparator.svelte.d.ts +0 -1
  32. package/dist/Pagination.svelte +267 -0
  33. package/dist/Pagination.svelte.d.ts +4 -0
  34. package/dist/Pagination.types.d.ts +24 -0
  35. package/dist/Pagination.types.js +1 -0
  36. package/dist/Popover.svelte +114 -60
  37. package/dist/Popover.svelte.d.ts +1 -2
  38. package/dist/Portal.types.d.ts +1 -4
  39. package/dist/Progress.svelte +40 -15
  40. package/dist/Progress.svelte.d.ts +0 -1
  41. package/dist/Radio.svelte +37 -25
  42. package/dist/Radio.svelte.d.ts +0 -1
  43. package/dist/Select.svelte +191 -125
  44. package/dist/Select.svelte.d.ts +8 -2
  45. package/dist/Slider.svelte +120 -71
  46. package/dist/Slider.svelte.d.ts +0 -1
  47. package/dist/Switch.svelte +51 -20
  48. package/dist/Switch.svelte.d.ts +1 -1
  49. package/dist/Tab.svelte +39 -24
  50. package/dist/Tab.svelte.d.ts +0 -1
  51. package/dist/TabList.svelte +176 -125
  52. package/dist/TabList.svelte.d.ts +0 -1
  53. package/dist/TextArea.svelte +83 -41
  54. package/dist/TextArea.svelte.d.ts +2 -3
  55. package/dist/Tooltip.svelte +68 -36
  56. package/dist/Tree.svelte +52 -24
  57. package/dist/Tree.svelte.d.ts +0 -1
  58. package/dist/TreeChevron.svelte +24 -12
  59. package/dist/TreeChevron.svelte.d.ts +0 -1
  60. package/dist/TreeItem.svelte +292 -225
  61. package/dist/TreeItem.svelte.d.ts +1 -1
  62. package/dist/actions/extraClass.d.ts +1 -0
  63. package/dist/actions/extraClass.js +1 -0
  64. package/dist/idGenerator.d.ts +1 -0
  65. package/dist/idGenerator.js +1 -0
  66. package/dist/index.d.ts +3 -2
  67. package/dist/index.js +3 -2
  68. package/dist/mediaQueries/prefersColorSchemeDark.d.ts +0 -1
  69. package/dist/mediaQueries/prefersReducedMotion.d.ts +0 -1
  70. package/dist/mediaQueries/usingKeyboard.d.ts +0 -1
  71. package/package.json +21 -22
package/README.md CHANGED
@@ -11,7 +11,7 @@ npm install @geoffcox/sterling-svelte
11
11
  ## Documentation
12
12
 
13
13
  The project builds the documentation for the library as a SvelteKit application.
14
- See the published version of the [documentation](https://geoffcox.github.io/demos/sterling-svelte/).
14
+ See the published version of the [documentation](https://geoffcox.github.io/docs/sterling-svelte/).
15
15
 
16
16
  ## Repository
17
17
 
@@ -1,24 +1,28 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
- <script lang="ts">let { children, class: _class, ...rest } = $props();
4
- let buttonRef;
5
- export const click = () => {
3
+ <script lang="ts">
4
+ import type { HTMLButtonAttributes } from 'svelte/elements';
5
+
6
+ type Props = HTMLButtonAttributes;
7
+
8
+ let { children, class: _class, ...rest }: Props = $props();
9
+
10
+ let buttonRef: HTMLButtonElement;
11
+
12
+ export const click = () => {
6
13
  buttonRef?.click();
7
- };
8
- export const blur = () => {
14
+ };
15
+
16
+ export const blur = () => {
9
17
  buttonRef?.blur();
10
- };
11
- export const focus = (options) => {
18
+ };
19
+
20
+ export const focus = (options?: FocusOptions) => {
12
21
  buttonRef?.focus(options);
13
- };
22
+ };
14
23
  </script>
15
24
 
16
- <button
17
- bind:this={buttonRef}
18
- class={['sterling-button', _class].filter(Boolean).join(' ')}
19
- type="button"
20
- {...rest}
21
- >
25
+ <button bind:this={buttonRef} class={['sterling-button', _class]} type="button" {...rest}>
22
26
  {#if children}
23
27
  {@render children()}
24
28
  {/if}
@@ -1,4 +1,3 @@
1
- /// <reference types="svelte" />
2
1
  import type { HTMLButtonAttributes } from 'svelte/elements';
3
2
  declare const Button: import("svelte").Component<HTMLButtonAttributes, {
4
3
  click: () => void;
@@ -1,139 +1,205 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
- <script lang="ts">import { getContext, tick } from 'svelte';
4
- import { arrow, autoUpdate, computePosition, flip, offset } from '@floating-ui/dom';
5
- import { portal } from './actions/portal';
6
- import { fade } from 'svelte/transition';
7
- import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
8
- import { STERLING_PORTAL_HOST_ID, STERLING_PORTAL_CONTEXT_ID } from './Portal.constants';
9
- let { children, conditionalRender = $bindable(true), crossAxisOffset = $bindable(0), mainAxisOffset = $bindable(0), open = $bindable(false), placement = $bindable('top-start'), portalHost, reference, class: _class, ...rest } = $props();
10
- let popupRef = $state(undefined);
11
- let arrowRef = $state(undefined);
12
- let popupPosition = $state({ x: 0, y: 0 });
13
- let floatingUIPlacement = $derived(placement);
14
- let bodyHeight = $state(0);
15
- let resizeObserver = undefined;
16
- const { portalHost: contextPortalHost } = getContext(STERLING_PORTAL_CONTEXT_ID) || {
3
+ <script lang="ts">
4
+ import {
5
+ arrow,
6
+ autoUpdate,
7
+ computePosition,
8
+ flip,
9
+ offset,
10
+ type ComputePositionReturn,
11
+ type Placement
12
+ } from '@floating-ui/dom';
13
+ import { getContext, tick } from 'svelte';
14
+ import type { HTMLAttributes, KeyboardEventHandler } from 'svelte/elements';
15
+ import { fade, type FadeParams, type TransitionConfig } from 'svelte/transition';
16
+ import { portal } from './actions/portal';
17
+ import { prefersReducedMotion } from './mediaQueries/prefersReducedMotion';
18
+ import type { PopoverPlacement } from './Popover.types';
19
+ import { STERLING_PORTAL_CONTEXT_ID, STERLING_PORTAL_HOST_ID } from './Portal.constants';
20
+ import type { PortalContext } from './Portal.types';
21
+
22
+ type Props = HTMLAttributes<HTMLDivElement> & {
23
+ conditionalRender?: boolean | null;
24
+ crossAxisOffset?: number;
25
+ mainAxisOffset?: number;
26
+ open?: boolean | null;
27
+ placement?: PopoverPlacement;
28
+ portalHost?: HTMLElement;
29
+ reference?: HTMLElement | null;
30
+ };
31
+
32
+ let {
33
+ children,
34
+ conditionalRender = $bindable(true),
35
+ crossAxisOffset = $bindable(0),
36
+ mainAxisOffset = $bindable(0),
37
+ open = $bindable(false),
38
+ placement = $bindable('top-start'),
39
+ portalHost,
40
+ reference,
41
+ class: _class,
42
+ ...rest
43
+ }: Props = $props();
44
+
45
+ let popupRef: HTMLDivElement | undefined = $state(undefined);
46
+ let arrowRef: HTMLDivElement | undefined = $state(undefined);
47
+ let popupPosition: Partial<ComputePositionReturn> = $state({ x: 0, y: 0 });
48
+ let floatingUIPlacement = $derived(placement as Placement);
49
+ let bodyHeight = $state(0);
50
+ let resizeObserver: ResizeObserver | undefined = undefined;
51
+
52
+ const portalContext = getContext<PortalContext>(STERLING_PORTAL_CONTEXT_ID) || {
17
53
  portalHost: undefined
18
- };
19
- const ensurePortalHost = async () => {
54
+ };
55
+
56
+ const ensurePortalHost = async () => {
20
57
  await tick();
58
+
21
59
  // use the host set from context, usually set from a Dialog
22
- let host = $contextPortalHost;
60
+ let host = portalContext.portalHost;
61
+
23
62
  // use or create the sterling portal host
24
63
  if (!host && globalThis?.document) {
25
- host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`);
26
- // fallback to creating the sterling portal host
27
- if (!host) {
28
- host = globalThis.document.createElement('div');
29
- host.id = STERLING_PORTAL_HOST_ID;
30
- host.style.overflow = 'visible';
31
- globalThis.document.body.append(host);
32
- }
64
+ host = globalThis.document.querySelector(`#${STERLING_PORTAL_HOST_ID}`) as HTMLElement;
65
+
66
+ // fallback to creating the sterling portal host
67
+ if (!host) {
68
+ host = globalThis.document.createElement('div');
69
+ host.id = STERLING_PORTAL_HOST_ID;
70
+ host.style.overflow = 'visible';
71
+ globalThis.document.body.append(host);
72
+ }
33
73
  }
74
+
34
75
  portalHost = host;
35
- };
36
- let middleware = $derived([
76
+ };
77
+
78
+ let middleware = $derived([
37
79
  offset({ mainAxis: mainAxisOffset, crossAxis: crossAxisOffset }),
38
80
  flip(),
39
81
  arrowRef && arrow({ element: arrowRef, padding: 8 })
40
- ]);
41
- const computeCalloutPosition = async () => {
82
+ ]);
83
+
84
+ const computeCalloutPosition = async () => {
42
85
  if (reference && popupRef) {
43
- popupPosition = await computePosition(reference, popupRef, {
44
- placement: floatingUIPlacement,
45
- middleware
46
- });
47
- console.log('popupPosition', popupPosition);
48
- }
49
- else {
50
- popupPosition = { x: 0, y: 0 };
86
+ popupPosition = await computePosition(reference, popupRef, {
87
+ placement: floatingUIPlacement,
88
+ middleware
89
+ });
90
+ } else {
91
+ popupPosition = { x: 0, y: 0 };
51
92
  }
52
- };
53
- // whenever a positioned element is portaled it needs resubscription to auto-update
54
- let cleanupAutoUpdate = () => { };
55
- const autoUpdateCalloutPosition = () => {
93
+ };
94
+
95
+ // whenever a positioned element is portaled it needs resubscription to auto-update
96
+ let cleanupAutoUpdate = () => {};
97
+
98
+ const autoUpdateCalloutPosition = () => {
56
99
  cleanupAutoUpdate();
57
- cleanupAutoUpdate = () => { };
100
+ cleanupAutoUpdate = () => {};
58
101
  if (reference && popupRef) {
59
- cleanupAutoUpdate = autoUpdate(reference, popupRef, computeCalloutPosition);
102
+ cleanupAutoUpdate = autoUpdate(reference, popupRef, computeCalloutPosition);
60
103
  }
61
- };
62
- $effect(() => {
104
+ };
105
+
106
+ $effect(() => {
63
107
  autoUpdateCalloutPosition();
64
108
  return () => {
65
- cleanupAutoUpdate();
66
- cleanupAutoUpdate = () => { };
109
+ cleanupAutoUpdate();
110
+ cleanupAutoUpdate = () => {};
67
111
  };
68
- });
69
- $effect(() => {
112
+ });
113
+
114
+ $effect(() => {
70
115
  bodyHeight;
71
116
  reference;
72
117
  computeCalloutPosition();
73
- });
74
- // ----- Arrow ----- //
75
- const getArrowPlacementStyle = (position) => {
118
+ });
119
+
120
+ // ----- Arrow ----- //
121
+
122
+ const getArrowPlacementStyle = (position?: Partial<ComputePositionReturn>) => {
76
123
  if (position?.placement && arrowRef) {
77
- switch (position.placement) {
78
- case 'top':
79
- case 'top-start':
80
- case 'top-end':
81
- return (`bottom: -${arrowRef.offsetWidth}px;` + `transform:translate(0, -50%) rotate(135deg);`);
82
- case 'right':
83
- case 'right-start':
84
- case 'right-end':
85
- return (`left: -${arrowRef.offsetWidth}px;` + `transform:translate(50%, 0) rotate(225deg);`);
86
- case 'bottom':
87
- case 'bottom-start':
88
- case 'bottom-end':
89
- return `top: -${arrowRef.offsetWidth}px;` + `transform:translate(0, 50%) rotate(-45deg);`;
90
- case 'left':
91
- case 'left-start':
92
- case 'left-end':
93
- return (`right: -${arrowRef.offsetWidth}px;` + `transform:translate(-50%, 0) rotate(45deg);`);
94
- }
124
+ switch (position.placement) {
125
+ case 'top':
126
+ case 'top-start':
127
+ case 'top-end':
128
+ return (
129
+ `bottom: -${arrowRef.offsetWidth}px;` + `transform:translate(0, -50%) rotate(135deg);`
130
+ );
131
+ case 'right':
132
+ case 'right-start':
133
+ case 'right-end':
134
+ return (
135
+ `left: -${arrowRef.offsetWidth}px;` + `transform:translate(50%, 0) rotate(225deg);`
136
+ );
137
+ case 'bottom':
138
+ case 'bottom-start':
139
+ case 'bottom-end':
140
+ return `top: -${arrowRef.offsetWidth}px;` + `transform:translate(0, 50%) rotate(-45deg);`;
141
+ case 'left':
142
+ case 'left-start':
143
+ case 'left-end':
144
+ return (
145
+ `right: -${arrowRef.offsetWidth}px;` + `transform:translate(-50%, 0) rotate(45deg);`
146
+ );
147
+ }
95
148
  }
96
149
  return '';
97
- };
98
- const getArrowOffsetStyle = (position) => {
150
+ };
151
+
152
+ const getArrowOffsetStyle = (position?: Partial<ComputePositionReturn>) => {
99
153
  const arrow = position?.middlewareData?.arrow;
100
154
  if (arrow) {
101
- if (arrow.x !== null && arrow.x !== undefined) {
102
- return `left: ${arrow.x}px;`;
103
- }
104
- else if (arrow.y !== null && arrow.y !== undefined) {
105
- return `top: ${arrow.y}px;`;
106
- }
155
+ if (arrow.x !== null && arrow.x !== undefined) {
156
+ return `left: ${arrow.x}px;`;
157
+ } else if (arrow.y !== null && arrow.y !== undefined) {
158
+ return `top: ${arrow.y}px;`;
159
+ }
107
160
  }
108
161
  return '';
109
- };
110
- let arrowStyle = $derived(getArrowPlacementStyle(popupPosition) + getArrowOffsetStyle(popupPosition));
111
- // ----- Animation ----- //
112
- const fadeNoOp = (node, params) => {
162
+ };
163
+
164
+ let arrowStyle = $derived(
165
+ getArrowPlacementStyle(popupPosition) + getArrowOffsetStyle(popupPosition)
166
+ );
167
+
168
+ // ----- Animation ----- //
169
+
170
+ const fadeNoOp = (node: Element, params?: FadeParams): TransitionConfig => {
113
171
  return { delay: 0, duration: 0 };
114
- };
115
- let fadeMotion = $derived(!$prefersReducedMotion ? fade : fadeNoOp);
116
- // ----- EventHandlers ----- //
117
- const onKeydown = (event) => {
172
+ };
173
+
174
+ let fadeMotion = $derived(!$prefersReducedMotion ? fade : fadeNoOp);
175
+
176
+ // ----- EventHandlers ----- //
177
+
178
+ const onKeydown: KeyboardEventHandler<HTMLDivElement> = (event) => {
118
179
  if (event.key === 'Escape') {
119
- open = false;
180
+ open = false;
120
181
  }
121
182
  rest.onkeydown?.(event);
122
- };
123
- $effect(() => {
183
+ };
184
+
185
+ $effect(() => {
124
186
  ensurePortalHost();
187
+
125
188
  resizeObserver = new ResizeObserver((entries) => {
126
- bodyHeight = entries[0].target.clientHeight;
189
+ bodyHeight = entries[0].target.clientHeight;
127
190
  });
191
+
128
192
  // start observing a DOM node
129
193
  resizeObserver.observe(document.body);
194
+
130
195
  return () => {
131
- resizeObserver?.unobserve(document.body);
132
- resizeObserver?.disconnect();
133
- resizeObserver = undefined;
196
+ resizeObserver?.unobserve(document.body);
197
+ resizeObserver?.disconnect();
198
+ resizeObserver = undefined;
134
199
  };
135
- });
136
- ensurePortalHost();
200
+ });
201
+
202
+ ensurePortalHost();
137
203
  </script>
138
204
 
139
205
  {#if open || !conditionalRender}
@@ -145,7 +211,7 @@ ensurePortalHost();
145
211
  <!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
146
212
  <div
147
213
  bind:this={popupRef}
148
- class={['sterling-callout', _class].filter(Boolean).join(' ')}
214
+ class={['sterling-callout', _class]}
149
215
  class:open
150
216
  class:top={popupPosition.placement === 'top'}
151
217
  class:top-start={popupPosition.placement === 'top-start'}
@@ -1,6 +1,5 @@
1
- /// <reference types="svelte" />
2
- import type { PopoverPlacement } from './Popover.types';
3
1
  import type { HTMLAttributes } from 'svelte/elements';
2
+ import type { PopoverPlacement } from './Popover.types';
4
3
  type Props = HTMLAttributes<HTMLDivElement> & {
5
4
  conditionalRender?: boolean | null;
6
5
  crossAxisOffset?: number;
@@ -1,24 +1,43 @@
1
1
  <svelte:options runes={true} />
2
2
 
3
- <script lang="ts">import { idGenerator } from './idGenerator';
4
- import { usingKeyboard } from './mediaQueries/usingKeyboard';
5
- let { id, children, checked = $bindable(false), class: _class, disabled = $bindable(false), ...rest } = $props();
6
- let inputRef;
7
- $effect(() => {
3
+ <script lang="ts">
4
+ import type { HTMLInputAttributes } from 'svelte/elements';
5
+ import { usingKeyboard } from './mediaQueries/usingKeyboard';
6
+
7
+ const uuid = $props.id();
8
+
9
+ type Props = HTMLInputAttributes;
10
+
11
+ let {
12
+ id,
13
+ children,
14
+ checked = $bindable(false),
15
+ class: _class,
16
+ disabled = $bindable(false),
17
+ ...rest
18
+ }: Props = $props();
19
+
20
+ let inputRef: HTMLInputElement;
21
+
22
+ $effect(() => {
8
23
  if (children && id === undefined) {
9
- id = idGenerator.nextId('Checkbox');
24
+ id = `Checkbox-${uuid}`;
10
25
  }
11
- });
12
- // ----- Methods ----- //
13
- export const blur = () => {
26
+ });
27
+
28
+ // ----- Methods ----- //
29
+
30
+ export const blur = () => {
14
31
  inputRef?.blur();
15
- };
16
- export const click = () => {
32
+ };
33
+
34
+ export const click = () => {
17
35
  inputRef?.click();
18
- };
19
- export const focus = (options) => {
36
+ };
37
+
38
+ export const focus = (options?: FocusOptions) => {
20
39
  inputRef?.focus(options);
21
- };
40
+ };
22
41
  </script>
23
42
 
24
43
  <!--
@@ -26,7 +45,7 @@ export const focus = (options) => {
26
45
  A styled HTML input type=checkbox element.
27
46
  -->
28
47
  <div
29
- class={['sterling-checkbox', _class].filter(Boolean).join(' ')}
48
+ class={['sterling-checkbox', _class]}
30
49
  class:checked
31
50
  class:disabled
32
51
  class:using-keyboard={$usingKeyboard}
@@ -1,4 +1,3 @@
1
- /// <reference types="svelte" />
2
1
  import type { HTMLInputAttributes } from 'svelte/elements';
3
2
  /** A styled HTML input type=checkbox element. */
4
3
  declare const Checkbox: import("svelte").Component<HTMLInputAttributes, {