@marianmeres/stuic 2.3.2 → 2.4.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 (89) hide show
  1. package/README.md +0 -1
  2. package/dist/README.md +17 -11
  3. package/dist/actions/autogrow.svelte.js +4 -4
  4. package/dist/actions/autoscroll.d.ts +2 -2
  5. package/dist/actions/autoscroll.js +17 -8
  6. package/dist/actions/file-dropzone.svelte.d.ts +1 -1
  7. package/dist/actions/file-dropzone.svelte.js +1 -1
  8. package/dist/actions/focus-trap.js +33 -24
  9. package/dist/actions/highlight-dragover.svelte.js +6 -5
  10. package/dist/actions/on-submit-validity-check.svelte.js +2 -2
  11. package/dist/actions/resizable-width.svelte.d.ts +1 -1
  12. package/dist/actions/resizable-width.svelte.js +7 -5
  13. package/dist/actions/tooltip/index.css +2 -7
  14. package/dist/actions/tooltip/tooltip.svelte.js +5 -4
  15. package/dist/actions/trim.svelte.d.ts +1 -1
  16. package/dist/actions/trim.svelte.js +2 -2
  17. package/dist/actions/validate.svelte.d.ts +4 -4
  18. package/dist/actions/validate.svelte.js +9 -9
  19. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt-stack.svelte.d.ts +7 -6
  20. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt-stack.svelte.js +1 -2
  21. package/dist/components/AlertConfirmPrompt/index.d.ts +1 -1
  22. package/dist/components/AlertConfirmPrompt/index.js +1 -1
  23. package/dist/components/AnimatedElipsis/index.d.ts +1 -1
  24. package/dist/components/AnimatedElipsis/index.js +1 -1
  25. package/dist/components/Button/index.d.ts +1 -1
  26. package/dist/components/Button/index.js +1 -1
  27. package/dist/components/ButtonGroupRadio/ButtonGroupRadio.svelte +4 -1
  28. package/dist/components/ButtonGroupRadio/index.d.ts +1 -1
  29. package/dist/components/ButtonGroupRadio/index.js +1 -1
  30. package/dist/components/ColorScheme/index.d.ts +2 -2
  31. package/dist/components/ColorScheme/index.js +2 -2
  32. package/dist/components/CommandMenu/index.d.ts +1 -1
  33. package/dist/components/CommandMenu/index.js +1 -1
  34. package/dist/components/DismissibleMessage/index.d.ts +1 -1
  35. package/dist/components/DismissibleMessage/index.js +1 -1
  36. package/dist/components/HoverExpandableWidth/index.d.ts +1 -1
  37. package/dist/components/HoverExpandableWidth/index.js +1 -1
  38. package/dist/components/Input/FieldAssets.svelte +7 -3
  39. package/dist/components/Input/FieldLikeButton.svelte +1 -1
  40. package/dist/components/Input/FieldOptions.svelte +1 -1
  41. package/dist/components/Input/index.d.ts +7 -7
  42. package/dist/components/Input/index.js +7 -7
  43. package/dist/components/KbdShortcut/index.d.ts +1 -1
  44. package/dist/components/KbdShortcut/index.js +1 -1
  45. package/dist/components/ModalDialog/index.d.ts +1 -1
  46. package/dist/components/ModalDialog/index.js +1 -1
  47. package/dist/components/Notifications/index.d.ts +1 -1
  48. package/dist/components/Notifications/index.js +1 -1
  49. package/dist/components/Notifications/notifications-stack.svelte.d.ts +5 -5
  50. package/dist/components/Notifications/notifications-stack.svelte.js +8 -7
  51. package/dist/components/SlidingPanels/index.d.ts +1 -1
  52. package/dist/components/SlidingPanels/index.js +1 -1
  53. package/dist/components/Spinner/index.d.ts +1 -1
  54. package/dist/components/Spinner/index.js +1 -1
  55. package/dist/components/Switch/Switch.svelte +5 -2
  56. package/dist/components/Switch/index.d.ts +1 -1
  57. package/dist/components/Switch/index.js +1 -1
  58. package/dist/components/TypeaheadInput/index.d.ts +1 -1
  59. package/dist/components/TypeaheadInput/index.js +1 -1
  60. package/dist/utils/body-scroll-locker.js +4 -3
  61. package/dist/utils/breakpoint.svelte.js +0 -2
  62. package/dist/utils/colors.js +3 -3
  63. package/dist/utils/debounce.d.ts +1 -1
  64. package/dist/utils/debounce.js +1 -2
  65. package/dist/utils/escape-regex.js +1 -1
  66. package/dist/utils/event-emitter.d.ts +2 -3
  67. package/dist/utils/event-emitter.js +1 -2
  68. package/dist/utils/event-modifiers.d.ts +4 -4
  69. package/dist/utils/event-modifiers.js +4 -6
  70. package/dist/utils/get-file-type-label.js +1 -1
  71. package/dist/utils/is-image.js +2 -2
  72. package/dist/utils/is-nullish.d.ts +1 -1
  73. package/dist/utils/is-plain-object.d.ts +1 -1
  74. package/dist/utils/is-plain-object.js +4 -1
  75. package/dist/utils/maybe-json-parse.d.ts +1 -1
  76. package/dist/utils/maybe-json-parse.js +1 -1
  77. package/dist/utils/maybe-json-stringify.d.ts +1 -1
  78. package/dist/utils/move-array-item.d.ts +1 -1
  79. package/dist/utils/preload-img.js +2 -1
  80. package/dist/utils/sleep.d.ts +1 -1
  81. package/dist/utils/storage-abstraction.d.ts +13 -13
  82. package/dist/utils/storage-abstraction.js +2 -0
  83. package/dist/utils/svg-circle.js +2 -1
  84. package/dist/utils/switch.svelte.d.ts +1 -1
  85. package/dist/utils/switch.svelte.js +1 -1
  86. package/dist/utils/throttle.d.ts +1 -1
  87. package/dist/utils/throttle.js +7 -8
  88. package/dist/utils/to-integer.d.ts +1 -1
  89. package/package.json +6 -2
package/README.md CHANGED
@@ -6,4 +6,3 @@ OPINIONATED, UNSTABLE AND IN PROGRESS...
6
6
 
7
7
  Ongoing effort to build reusable Svelte UI primitives as I need them, inspired by many
8
8
  other libs -- cherry-picked, combined, adjusted and tweaked to my personal preference and needs.
9
-
package/dist/README.md CHANGED
@@ -12,21 +12,22 @@ npm install @marianmeres/stuic
12
12
 
13
13
  ```svelte
14
14
  <script>
15
- import { Button, Modal } from '@marianmeres/stuic';
15
+ import { Button, Modal } from "@marianmeres/stuic";
16
16
 
17
- let modal;
17
+ let modal;
18
18
  </script>
19
19
 
20
20
  <Button onclick={() => modal.open()}>Open Modal</Button>
21
21
 
22
22
  <Modal bind:this={modal}>
23
- <p>Hello from Modal!</p>
23
+ <p>Hello from Modal!</p>
24
24
  </Modal>
25
25
  ```
26
26
 
27
27
  ## Components
28
28
 
29
29
  ### Layout & Overlays
30
+
30
31
  - **AppShell** - Application layout wrapper with header, sidebar, main content
31
32
  - **Backdrop** - Fullscreen overlay with transitions
32
33
  - **Modal** - Dialog overlay with focus trap and scroll lock
@@ -34,6 +35,7 @@ npm install @marianmeres/stuic
34
35
  - **Drawer** - Slide-in panel from screen edges
35
36
 
36
37
  ### Forms & Inputs
38
+
37
39
  - **FieldInput** - Text input with label, validation, description
38
40
  - **FieldTextarea** - Multiline text input with autogrow support
39
41
  - **FieldSelect** - Native select dropdown
@@ -46,12 +48,14 @@ npm install @marianmeres/stuic
46
48
  - **Fieldset** - Group of form fields with legend
47
49
 
48
50
  ### Buttons & Controls
51
+
49
52
  - **Button** - Styled button with variants (primary, secondary, ghost)
50
53
  - **ButtonGroupRadio** - Radio-style button group
51
54
  - **Switch** - Toggle switch component
52
55
  - **X** - Close/dismiss button icon
53
56
 
54
57
  ### Feedback & Notifications
58
+
55
59
  - **Notifications** - Toast notification system
56
60
  - **AlertConfirmPrompt** - Modal dialogs for alerts, confirms, and prompts
57
61
  - **DismissibleMessage** - Closable message banner
@@ -59,11 +63,13 @@ npm install @marianmeres/stuic
59
63
  - **Spinner** - Loading spinner animation
60
64
 
61
65
  ### Navigation & Interaction
66
+
62
67
  - **CommandMenu** - Keyboard-driven command palette
63
68
  - **TypeaheadInput** - Autocomplete text input
64
69
  - **KbdShortcut** - Keyboard shortcut display
65
70
 
66
71
  ### Utilities
72
+
67
73
  - **ColorScheme** - Dark/light mode management
68
74
  - **Thc** - Render text, HTML, or component dynamically
69
75
  - **SlidingPanels** - Animated panel transitions
@@ -86,7 +92,7 @@ npm install @marianmeres/stuic
86
92
  ## Utilities
87
93
 
88
94
  ```ts
89
- import { debounce, throttle, twMerge, localStorageState } from '@marianmeres/stuic';
95
+ import { debounce, throttle, twMerge, localStorageState } from "@marianmeres/stuic";
90
96
  ```
91
97
 
92
98
  - **debounce/throttle** - Function rate limiting
@@ -103,10 +109,10 @@ Components use CSS custom properties for theming. Override in your CSS:
103
109
 
104
110
  ```css
105
111
  :root {
106
- --color-button-bg: theme('colors.blue.500');
107
- --color-button-text: white;
108
- --color-input-accent: theme('colors.blue.500');
109
- /* ... */
112
+ --color-button-bg: theme("colors.blue.500");
113
+ --color-button-text: white;
114
+ --color-input-accent: theme("colors.blue.500");
115
+ /* ... */
110
116
  }
111
117
  ```
112
118
 
@@ -117,10 +123,10 @@ See `src/lib/theme.css` for all available custom properties.
117
123
  All components export their Props types:
118
124
 
119
125
  ```ts
120
- import type { ButtonProps, ModalProps } from '@marianmeres/stuic';
126
+ import type { ButtonProps, ModalProps } from "@marianmeres/stuic";
121
127
 
122
128
  const buttonConfig: Partial<ButtonProps> = {
123
- variant: 'primary',
124
- size: 'lg',
129
+ variant: "primary",
130
+ size: "lg",
125
131
  };
126
132
  ```
@@ -25,10 +25,10 @@
25
25
  export function autogrow(el, fn) {
26
26
  let lastValue = el.value;
27
27
  $effect(() => {
28
- let { enabled = true, max = 250, immediate = true, value } = fn?.() || {};
28
+ const { enabled = true, max = 250, immediate = true, value } = fn?.() || {};
29
29
  if (!enabled)
30
30
  return;
31
- function set_height(_e) {
31
+ function set_height() {
32
32
  // console.log(123, el.value);
33
33
  if (enabled) {
34
34
  el.style.height = "auto"; // Reset height to auto to correctly calculate scrollHeight
@@ -38,14 +38,14 @@ export function autogrow(el, fn) {
38
38
  // eventlistener strategy (we're not passing value)
39
39
  if (value === undefined) {
40
40
  if (immediate)
41
- set_height(null);
41
+ set_height();
42
42
  el.addEventListener("input", set_height);
43
43
  el.addEventListener("blur", set_height);
44
44
  }
45
45
  // strategy with provided value
46
46
  else {
47
47
  if (value !== lastValue) {
48
- set_height(null);
48
+ set_height();
49
49
  lastValue = value;
50
50
  }
51
51
  }
@@ -12,8 +12,8 @@ interface StoreLike<T> extends StoreReadable<T> {
12
12
  * Options for the autoscroll action.
13
13
  */
14
14
  export type AutoscrollOptions = ScrollOptions & {
15
- dependencies?: StoreReadable<any>[];
16
- logger?: (...args: any[]) => void;
15
+ dependencies?: StoreReadable<unknown>[];
16
+ logger?: (...args: unknown[]) => void;
17
17
  newScrollableContentSignal?: StoreLike<boolean>;
18
18
  shouldScrollThresholdPx?: number;
19
19
  startScrollTimeout?: number;
@@ -43,16 +43,19 @@ export function autoscroll(node, options = {
43
43
  startScrollTimeout: DEFAULTS.startScrollTimeout,
44
44
  }) {
45
45
  // use "smooth" by default
46
- options.behavior ??= 'smooth';
46
+ options.behavior ??= "smooth";
47
47
  options.shouldScrollThresholdPx ??= DEFAULTS.shouldScrollThresholdPx;
48
48
  options.startScrollTimeout ??= DEFAULTS.startScrollTimeout;
49
49
  const { behavior, shouldScrollThresholdPx, dependencies, logger, newScrollableContentSignal, startScrollTimeout, } = options || {};
50
50
  let origScrollHeight = 0;
51
- const log = (...args) => typeof logger === 'function' && logger.apply(null, [...args]);
51
+ const log = (...args) => {
52
+ if (typeof logger === "function")
53
+ logger.apply(null, [...args]);
54
+ };
52
55
  const shouldScroll = () => {
53
56
  const { scrollTop, clientHeight } = node;
54
57
  const result = origScrollHeight - scrollTop - clientHeight < shouldScrollThresholdPx;
55
- log('shouldScroll?', result, { scrollTop, origScrollHeight, clientHeight });
58
+ log("shouldScroll?", result, { scrollTop, origScrollHeight, clientHeight });
56
59
  return result;
57
60
  };
58
61
  const scroll = () => {
@@ -62,17 +65,23 @@ export function autoscroll(node, options = {
62
65
  };
63
66
  // for when children change sizes
64
67
  const resizeObserver = new ResizeObserver(() => {
65
- log('observed resize...');
66
- shouldScroll() && scroll();
68
+ log("observed resize...");
69
+ if (shouldScroll())
70
+ scroll();
67
71
  });
68
72
  // for when children
69
73
  const mutationObserver = new MutationObserver(() => {
70
- log('observed mutation...');
71
- shouldScroll() ? scroll() : newScrollableContentSignal?.set(true);
74
+ log("observed mutation...");
75
+ if (shouldScroll()) {
76
+ scroll();
77
+ }
78
+ else {
79
+ newScrollableContentSignal?.set(true);
80
+ }
72
81
  origScrollHeight = node.scrollHeight;
73
82
  });
74
83
  const unsubs = dependencies?.map((dep) => dep.subscribe((v) => {
75
- log('dependency update...', v);
84
+ log("dependency update...", v);
76
85
  setTimeout(scroll, startScrollTimeout);
77
86
  })) ?? [];
78
87
  // observe size of all children
@@ -5,7 +5,7 @@ interface FileDropzoneOptions {
5
5
  enabled?: boolean;
6
6
  inputEl: HTMLInputElement;
7
7
  allowClick?: boolean;
8
- processFiles?: (files: FileList | null, wasDrop?: boolean) => any | Promise<any>;
8
+ processFiles?: (files: FileList | null, wasDrop?: boolean) => void | Promise<void>;
9
9
  }
10
10
  /**
11
11
  * A Svelte action that turns any element into a file drop zone.
@@ -40,7 +40,7 @@
40
40
  */
41
41
  export function fileDropzone(el, fn) {
42
42
  $effect(() => {
43
- let { enabled = true, allowClick = true, inputEl, processFiles, } = fn?.() || {};
43
+ const { enabled = true, allowClick = true, inputEl, processFiles, } = fn?.() || {};
44
44
  if (!enabled)
45
45
  return;
46
46
  if (!inputEl) {
@@ -32,34 +32,36 @@ const defaults = { enabled: true, autoFocusFirst: true };
32
32
  * ```
33
33
  */
34
34
  export function focusTrap(node, options = {}) {
35
- let { enabled, autoFocusFirst } = { ...defaults, ...(options || {}) };
35
+ let enabled;
36
+ const { enabled: _enabled, autoFocusFirst } = { ...defaults, ...(options || {}) };
37
+ enabled = _enabled ?? true;
36
38
  const focusableSelectors = [
37
- '[contentEditable=true]',
39
+ "[contentEditable=true]",
38
40
  //
39
- 'button:not([disabled])',
40
- 'input:not([disabled])',
41
- 'select:not([disabled])',
42
- 'textarea:not([disabled])',
41
+ "button:not([disabled])",
42
+ "input:not([disabled])",
43
+ "select:not([disabled])",
44
+ "textarea:not([disabled])",
43
45
  //
44
- 'a[href]',
45
- 'area[href]',
46
- 'details',
47
- 'iframe',
46
+ "a[href]",
47
+ "area[href]",
48
+ "details",
49
+ "iframe",
48
50
  // see more below on tabindexes
49
51
  '[tabindex]:not([tabindex^="-"])',
50
- ].join(',');
52
+ ].join(",");
51
53
  let first;
52
54
  let last;
53
55
  // When the first element is selected, shift+tab pressed, jump to the last selectable item.
54
56
  function onFirstElemKeydown(e) {
55
- if (e.shiftKey && e.code === 'Tab') {
57
+ if (e.shiftKey && e.code === "Tab") {
56
58
  e.preventDefault();
57
59
  last.focus();
58
60
  }
59
61
  }
60
62
  // When the last item selected, tab pressed, jump to the first selectable item.
61
63
  function onLastElemKeydown(e) {
62
- if (!e.shiftKey && e.code === 'Tab') {
64
+ if (!e.shiftKey && e.code === "Tab") {
63
65
  e.preventDefault();
64
66
  first.focus();
65
67
  }
@@ -68,15 +70,15 @@ export function focusTrap(node, options = {}) {
68
70
  if (enabled === false)
69
71
  return;
70
72
  let maxTabindex = 0;
71
- let focusable = [...node.querySelectorAll(focusableSelectors)]
73
+ const focusable = [...node.querySelectorAll(focusableSelectors)]
72
74
  // filter negative tabindexes (afaik there is no :not([disabled] OR [tabindex^="-"]))
73
75
  .filter((e) => {
74
76
  // reusing loop for a side job here... see sort below
75
- maxTabindex = Math.max(maxTabindex, parseInt(e.getAttribute('tabindex') || '0'));
77
+ maxTabindex = Math.max(maxTabindex, parseInt(e.getAttribute("tabindex") || "0"));
76
78
  //
77
- if (e.getAttribute('disabled') === '')
79
+ if (e.getAttribute("disabled") === "")
78
80
  return false;
79
- if ((e.getAttribute('tabindex') || '').startsWith('-'))
81
+ if ((e.getAttribute("tabindex") || "").startsWith("-"))
80
82
  return false;
81
83
  return true;
82
84
  })
@@ -84,8 +86,8 @@ export function focusTrap(node, options = {}) {
84
86
  // but must increase zero to max + 1 first, because browsers focus zeros as last...
85
87
  // https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
86
88
  .sort((e1, e2) => {
87
- const a = parseInt(e1.getAttribute('tabindex') || '0') || maxTabindex + 1;
88
- const b = parseInt(e2.getAttribute('tabindex') || '0') || maxTabindex + 1;
89
+ const a = parseInt(e1.getAttribute("tabindex") || "0") || maxTabindex + 1;
90
+ const b = parseInt(e2.getAttribute("tabindex") || "0") || maxTabindex + 1;
89
91
  return a - b;
90
92
  });
91
93
  if (focusable.length) {
@@ -95,14 +97,16 @@ export function focusTrap(node, options = {}) {
95
97
  if (!fromObserver && autoFocusFirst)
96
98
  first.focus();
97
99
  // Listen for keydown on first & last element
98
- first.addEventListener('keydown', onFirstElemKeydown);
99
- last.addEventListener('keydown', onLastElemKeydown);
100
+ first.addEventListener("keydown", onFirstElemKeydown);
101
+ last.addEventListener("keydown", onLastElemKeydown);
100
102
  }
101
103
  };
102
104
  queryElements(false);
103
105
  function cleanup() {
104
- first && first.removeEventListener('keydown', onFirstElemKeydown);
105
- last && last.removeEventListener('keydown', onLastElemKeydown);
106
+ if (first)
107
+ first.removeEventListener("keydown", onFirstElemKeydown);
108
+ if (last)
109
+ last.removeEventListener("keydown", onLastElemKeydown);
106
110
  }
107
111
  // When children of node are changed (added or removed)
108
112
  const observer = new MutationObserver((mutations, observer) => {
@@ -117,7 +121,12 @@ export function focusTrap(node, options = {}) {
117
121
  return {
118
122
  update(options = {}) {
119
123
  enabled = !!options?.enabled;
120
- enabled ? queryElements(false) : cleanup();
124
+ if (enabled) {
125
+ queryElements(false);
126
+ }
127
+ else {
128
+ cleanup();
129
+ }
121
130
  },
122
131
  destroy() {
123
132
  cleanup();
@@ -32,15 +32,16 @@ export function highlightDragover(el, fn) {
32
32
  // // Trigger change event for any listeners
33
33
  // el.dispatchEvent(new Event("change"));
34
34
  // }
35
- function prevent(e) {
36
- e.preventDefault();
37
- // e.stopPropagation();
38
- }
35
+ // function prevent(e: DragEvent) {
36
+ // e.preventDefault();
37
+ // // e.stopPropagation();
38
+ // }
39
39
  const HIGH = ["dragenter", "dragover"];
40
40
  const UNHIGH = ["dragleave", "drop"];
41
41
  // const ALL = [...HIGH, ...UNHIGH];
42
42
  $effect(() => {
43
- let { classes = ["dragover"], enabled = true } = fn?.() || {};
43
+ const { enabled = true } = fn?.() || {};
44
+ let { classes = ["dragover"] } = fn?.() || {};
44
45
  if (!enabled)
45
46
  return;
46
47
  if (!Array.isArray(classes))
@@ -47,9 +47,9 @@ export function onSubmitValidityCheck(node) {
47
47
  e.preventDefault();
48
48
  // this will disable all other onsubmit listeners...
49
49
  e.stopImmediatePropagation();
50
- let invalid = [];
50
+ const invalid = [];
51
51
  for (let i = 0; i < node.elements?.length; i++) {
52
- let el = node.elements[i];
52
+ const el = node.elements[i];
53
53
  if (typeof el.checkValidity === "function") {
54
54
  // hm... radios are tricky, as triggering change automatically checks the last
55
55
  // input (last radio input), which is not desired
@@ -16,7 +16,7 @@ export interface ResizableWidthOptions {
16
16
  units: "px" | "%";
17
17
  container: number;
18
18
  }) => void;
19
- debug?: (...args: any[]) => void;
19
+ debug?: (...args: unknown[]) => void;
20
20
  }
21
21
  /**
22
22
  * A Svelte action that makes an element's width resizable via drag handle.
@@ -73,7 +73,8 @@ export function resizableWidth(el, fn) {
73
73
  return handle;
74
74
  }
75
75
  $effect(() => {
76
- let { enabled = true, initial = 0, min = 0, max = 0, units = "px", key, storage = "session", handleClass = "", handleDragClass = "", onResize, debug, } = fn?.() || {};
76
+ const { enabled = true, initial: initialValue = 0, min = 0, max = 0, units = "px", key, storage = "session", handleClass = "", handleDragClass = "", onResize, debug, } = fn?.() || {};
77
+ let initial = initialValue;
77
78
  const _debug = (...args) => debug?.("[resizable-width]", ...args);
78
79
  _debug("$effect");
79
80
  if (!enabled)
@@ -108,7 +109,8 @@ export function resizableWidth(el, fn) {
108
109
  value = Math.max(min, value);
109
110
  if (max)
110
111
  value = Math.min(max, value);
111
- _initial !== value && _debug("clamped", value, units);
112
+ if (_initial !== value)
113
+ _debug("clamped", value, units);
112
114
  return value;
113
115
  };
114
116
  let width;
@@ -132,7 +134,7 @@ export function resizableWidth(el, fn) {
132
134
  e.preventDefault(); // prevent scrolling on touch devices
133
135
  isResizing = true;
134
136
  //
135
- const clientX = e.touches ? e.touches[0].clientX : e.clientX;
137
+ const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
136
138
  startX = clientX;
137
139
  startWidth = parseInt(getComputedStyle(el).width, 10);
138
140
  containerW = container.offsetWidth;
@@ -145,9 +147,9 @@ export function resizableWidth(el, fn) {
145
147
  return;
146
148
  e.preventDefault(); // prevent scrolling on touch devices
147
149
  //
148
- const clientX = e.touches ? e.touches[0].clientX : e.clientX;
150
+ const clientX = "touches" in e ? e.touches[0].clientX : e.clientX;
149
151
  const deltaX = clientX - startX;
150
- let width = startWidth + deltaX;
152
+ const width = startWidth + deltaX;
151
153
  set_width_px(width);
152
154
  }
153
155
  function resize_stop() {
@@ -41,13 +41,8 @@
41
41
  /* position-area is set via inline style based on position param */
42
42
  /* fallbacks ensure tooltip stays within viewport */
43
43
  position-try-fallbacks:
44
- --tt-top-span-right,
45
- --tt-top-span-left,
46
- flip-block,
47
- --tt-bottom-span-right,
48
- --tt-bottom-span-left,
49
- --tt-left,
50
- --tt-right;
44
+ --tt-top-span-right, --tt-top-span-left, flip-block, --tt-bottom-span-right,
45
+ --tt-bottom-span-left, --tt-left, --tt-right;
51
46
 
52
47
  &.tt-block {
53
48
  display: block;
@@ -103,7 +103,8 @@ export function tooltip(anchorEl, fn) {
103
103
  anchorEl.setAttribute("aria-describedby", id);
104
104
  anchorEl.setAttribute("aria-expanded", "false");
105
105
  const debug = (...args) => {
106
- do_debug && console.debug("[tooltip]", rnd, ...args);
106
+ if (do_debug)
107
+ console.debug("[tooltip]", rnd, ...args);
107
108
  };
108
109
  function ensure_tooltip() {
109
110
  debug("ensure_tooltip()", content, classTooltip);
@@ -132,7 +133,7 @@ export function tooltip(anchorEl, fn) {
132
133
  // update position-area in case it changed
133
134
  tooltipEl.style.setProperty("position-area", POSITION_MAP[position] || "top");
134
135
  if (classTooltip) {
135
- let old = tooltipEl.className;
136
+ const old = tooltipEl.className;
136
137
  tooltipEl.className = ""; // reset
137
138
  tooltipEl.classList.add(...twMerge(old, classTooltip).split(/\s/));
138
139
  }
@@ -201,12 +202,12 @@ export function tooltip(anchorEl, fn) {
201
202
  }
202
203
  // "reactive" params re/set
203
204
  $effect(() => {
204
- let { enabled: _enabled, content: _content, position: _position, debug: debugParam, class: _classTooltip, onShow, onHide, } = fn?.() || {};
205
+ const { enabled: _enabled, content: _content, position: _position, debug: debugParam, class: _classTooltip, onShow, onHide, } = fn?.() || {};
205
206
  // re/assign new params
206
207
  do_debug = !!debugParam;
207
208
  on_show = onShow;
208
209
  on_hide = onHide;
209
- content = _content ||= anchorEl.getAttribute("aria-label");
210
+ content = _content || anchorEl.getAttribute("aria-label");
210
211
  classTooltip = _classTooltip;
211
212
  enabled = _enabled ?? true;
212
213
  position = _position || "top";
@@ -22,5 +22,5 @@
22
22
  */
23
23
  export declare function trim(el: HTMLInputElement | HTMLTextAreaElement, fn?: () => {
24
24
  enabled?: boolean;
25
- setValue?: (v: string) => any;
25
+ setValue?: (v: string) => void;
26
26
  }): void;
@@ -24,8 +24,8 @@ export function trim(el, fn) {
24
24
  // the node has been mounted in the DOM
25
25
  $effect(() => {
26
26
  // setup goes here
27
- let { enabled, setValue } = fn?.() || { enabled: true };
28
- function trim(e) {
27
+ const { enabled, setValue } = fn?.() || { enabled: true };
28
+ function trim() {
29
29
  if (enabled && typeof el.value === "string") {
30
30
  el.value = el.value.trim();
31
31
  setValue?.(el.value);
@@ -71,14 +71,14 @@ export interface ValidationResult {
71
71
  valid: boolean;
72
72
  message: string;
73
73
  }
74
- type ReasonTranslate = (reason: keyof ValidityStateFlags, value: any, fallback: string) => string;
74
+ type ReasonTranslate = (reason: keyof ValidityStateFlags, value: unknown, fallback: string) => string;
75
75
  /**
76
76
  * Options for the validate action.
77
77
  */
78
78
  export interface ValidateOptions {
79
79
  enabled?: boolean;
80
- context?: Record<string, any>;
81
- customValidator?: (value: any, context: Record<string, any> | undefined, el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => string | undefined;
80
+ context?: Record<string, unknown>;
81
+ customValidator?: (value: unknown, context: Record<string, unknown> | undefined, el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => string | undefined;
82
82
  on?: "input" | "change";
83
83
  setValidationResult?: (res: ValidationResult) => void;
84
84
  t?: false | ReasonTranslate;
@@ -148,6 +148,6 @@ export interface ValidateOptions {
148
148
  */
149
149
  export declare function validate(el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, fn?: () => boolean | ValidateOptions): void;
150
150
  export declare namespace validate {
151
- var t: null;
151
+ var t: ReasonTranslate | null;
152
152
  }
153
153
  export {};
@@ -1,5 +1,3 @@
1
- import { tick } from "svelte";
2
- import { waitForNextRepaint, waitForTwoRepaints } from "../utils/paint.js";
3
1
  /**
4
2
  * Creates a ValidityStateLike object for testing/mocking validation states.
5
3
  *
@@ -133,8 +131,8 @@ const KNOWN_REASONS = [
133
131
  export function validate(el, fn) {
134
132
  $effect(() => {
135
133
  //
136
- let fnResult = fn?.() ?? {};
137
- let { enabled, context, customValidator, on = "change", setValidationResult, t, } = typeof fnResult === "boolean" ? { enabled: !!fnResult } : fnResult;
134
+ const fnResult = fn?.() ?? {};
135
+ const { enabled, context, customValidator, on = "change", setValidationResult, t, } = typeof fnResult === "boolean" ? { enabled: !!fnResult } : fnResult;
138
136
  //
139
137
  const _t = (reason, value, fallback) => {
140
138
  // explicit false
@@ -187,10 +185,13 @@ export function validate(el, fn) {
187
185
  el.addEventListener(on, _doValidate);
188
186
  //
189
187
  let _touchCount = 0;
190
- const onFocus = (e) => _touchCount++;
188
+ const onFocus = () => _touchCount++;
191
189
  el.addEventListener("focus", onFocus);
192
190
  // also validate on first blur
193
- const onBlur = (e) => _touchCount === 1 && _doValidate();
191
+ const onBlur = () => {
192
+ if (_touchCount === 1)
193
+ _doValidate();
194
+ };
194
195
  el.addEventListener("blur", onBlur);
195
196
  return () => {
196
197
  el.removeEventListener(on, _doValidate);
@@ -199,6 +200,5 @@ export function validate(el, fn) {
199
200
  };
200
201
  });
201
202
  }
202
- // ReasonTranslate
203
- const t = null;
204
- validate.t = t;
203
+ // Global translation function - can be set by consumers
204
+ validate.t = null;
@@ -1,3 +1,4 @@
1
+ import type { Component } from "svelte";
1
2
  import type { THC } from "../Thc/Thc.svelte";
2
3
  /**
3
4
  * Types of alert/confirm/prompt dialogs.
@@ -12,13 +13,13 @@ export declare enum AlertConfirmPromptType {
12
13
  */
13
14
  export type AlertConfirmPromptVariant = "info" | "success" | "warn" | "error";
14
15
  /** Callback type for OK button click. */
15
- export type FnOnOK = (value: any) => any;
16
+ export type FnOnOK = (value: any) => void;
16
17
  /** Callback type for Cancel button click. */
17
- export type FnOnCancel = (value: false) => any;
18
+ export type FnOnCancel = (value: false) => void;
18
19
  /** Callback type for Escape key press. */
19
20
  export type FnOnEscape = () => void;
20
21
  /** Callback type for custom button click. */
21
- export type FnOnCustom = (value: any) => any;
22
+ export type FnOnCustom = (value: any) => void;
22
23
  /**
23
24
  * Configuration object for an alert/confirm/prompt dialog.
24
25
  */
@@ -38,9 +39,9 @@ export interface AlertConfirmPromptObj extends Record<string, any> {
38
39
  variant: AlertConfirmPromptVariant;
39
40
  iconFn: (() => string) | boolean;
40
41
  forceAsHtml?: boolean;
41
- CmpButtonOk?: any;
42
- CmpButtonCancel?: any;
43
- CmpButtonCustom?: any;
42
+ CmpButtonOk?: Component;
43
+ CmpButtonCancel?: Component;
44
+ CmpButtonCustom?: Component;
44
45
  }
45
46
  /**
46
47
  * A reactive stack manager for alert, confirm, and prompt dialogs.
@@ -1,5 +1,4 @@
1
- import { createClog } from "@marianmeres/clog";
2
- const clog = createClog("alert-confirm-prompt-stack").debug;
1
+ // const clog = createClog("alert-confirm-prompt-stack").debug;
3
2
  /**
4
3
  * Types of alert/confirm/prompt dialogs.
5
4
  */
@@ -1,2 +1,2 @@
1
1
  export * from "./alert-confirm-prompt-stack.svelte.js";
2
- export { default as AlertConfirmPrompt, type Props as AlertConfirmPromptProps } from "./AlertConfirmPrompt.svelte";
2
+ export { default as AlertConfirmPrompt, type Props as AlertConfirmPromptProps, } from "./AlertConfirmPrompt.svelte";
@@ -1,2 +1,2 @@
1
1
  export * from "./alert-confirm-prompt-stack.svelte.js";
2
- export { default as AlertConfirmPrompt } from "./AlertConfirmPrompt.svelte";
2
+ export { default as AlertConfirmPrompt, } from "./AlertConfirmPrompt.svelte";
@@ -1 +1 @@
1
- export { default as AnimatedEllipsis, type Props as AnimatedEllipsisProps } from "./AnimatedEllipsis.svelte";
1
+ export { default as AnimatedEllipsis, type Props as AnimatedEllipsisProps, } from "./AnimatedEllipsis.svelte";
@@ -1 +1 @@
1
- export { default as AnimatedEllipsis } from "./AnimatedEllipsis.svelte";
1
+ export { default as AnimatedEllipsis, } from "./AnimatedEllipsis.svelte";
@@ -1 +1 @@
1
- export { default as Button, type Props as ButtonProps } from './Button.svelte';
1
+ export { default as Button, type Props as ButtonProps } from "./Button.svelte";
@@ -1 +1 @@
1
- export { default as Button } from './Button.svelte';
1
+ export { default as Button } from "./Button.svelte";
@@ -30,7 +30,10 @@
30
30
 
31
31
  <script lang="ts">
32
32
  import { ItemCollection } from "@marianmeres/item-collection";
33
- type ItemCollectionItem = { id: string; option: import("../Input/types.js").FieldRadiosOption };
33
+ type ItemCollectionItem = {
34
+ id: string;
35
+ option: import("../Input/types.js").FieldRadiosOption;
36
+ };
34
37
  import { twMerge } from "../../utils/tw-merge.js";
35
38
  import Button from "../Button/Button.svelte";
36
39
  //