@marianmeres/stuic 1.125.0 → 2.0.0-next.2

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 (252) hide show
  1. package/README.md +2 -8
  2. package/dist/_shared.css +2 -0
  3. package/dist/actions/autogrow.svelte.d.ts +6 -0
  4. package/dist/actions/autogrow.svelte.js +19 -0
  5. package/dist/actions/highlight-dragover.svelte.d.ts +7 -0
  6. package/dist/actions/highlight-dragover.svelte.js +38 -0
  7. package/dist/actions/index.d.ts +7 -0
  8. package/dist/actions/index.js +7 -0
  9. package/dist/actions/on-submit-validity-check.svelte.d.ts +15 -0
  10. package/dist/actions/on-submit-validity-check.svelte.js +58 -0
  11. package/dist/actions/tooltip/index.css +34 -0
  12. package/dist/actions/tooltip/tooltip.svelte.d.ts +13 -0
  13. package/dist/actions/tooltip/tooltip.svelte.js +203 -0
  14. package/dist/actions/trim.svelte.d.ts +4 -0
  15. package/dist/actions/trim.svelte.js +17 -0
  16. package/dist/actions/{validate.d.ts → validate.svelte.d.ts} +8 -8
  17. package/dist/actions/validate.svelte.js +90 -0
  18. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte +59 -385
  19. package/dist/components/AlertConfirmPrompt/AlertConfirmPrompt.svelte.d.ts +9 -101
  20. package/dist/components/AlertConfirmPrompt/Current.svelte +202 -0
  21. package/dist/components/AlertConfirmPrompt/Current.svelte.d.ts +22 -0
  22. package/dist/components/AlertConfirmPrompt/acp-icons.d.ts +7 -2
  23. package/dist/components/AlertConfirmPrompt/acp-icons.js +8 -8
  24. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt-stack.svelte.d.ts +63 -0
  25. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt-stack.svelte.js +144 -0
  26. package/dist/components/AlertConfirmPrompt/index.d.ts +2 -0
  27. package/dist/components/AlertConfirmPrompt/index.js +2 -0
  28. package/dist/components/AnimatedElipsis/AnimatedEllipsis.svelte +47 -0
  29. package/dist/components/AnimatedElipsis/AnimatedEllipsis.svelte.d.ts +7 -0
  30. package/dist/components/AnimatedElipsis/index.d.ts +1 -0
  31. package/dist/components/AnimatedElipsis/index.js +1 -0
  32. package/dist/components/AppShell/AppShell.svelte +188 -127
  33. package/dist/components/AppShell/AppShell.svelte.d.ts +62 -43
  34. package/dist/components/AppShell/index.d.ts +1 -0
  35. package/dist/components/AppShell/index.js +1 -0
  36. package/dist/components/Backdrop/Backdrop.svelte +149 -49
  37. package/dist/components/Backdrop/Backdrop.svelte.d.ts +22 -37
  38. package/dist/components/Backdrop/index.d.ts +1 -0
  39. package/dist/components/Backdrop/index.js +1 -0
  40. package/dist/components/Button/Button.svelte +122 -146
  41. package/dist/components/Button/Button.svelte.d.ts +22 -80
  42. package/dist/components/Button/index.css +16 -0
  43. package/dist/components/Button/index.d.ts +1 -0
  44. package/dist/components/Button/index.js +1 -0
  45. package/dist/components/ColResize/ColResize.svelte +0 -0
  46. package/dist/components/ColResize/ColResize.svelte.d.ts +26 -0
  47. package/dist/components/ColorScheme/{LocalColorScheme.svelte → ColorSchemeLocal.svelte} +2 -2
  48. package/dist/components/ColorScheme/ColorSchemeLocal.svelte.d.ts +26 -0
  49. package/dist/components/ColorScheme/{SystemAwareColorScheme.svelte → ColorSchemeSystemAware.svelte} +4 -4
  50. package/dist/components/ColorScheme/ColorSchemeSystemAware.svelte.d.ts +26 -0
  51. package/dist/components/ColorScheme/color-scheme.d.ts +26 -8
  52. package/dist/components/ColorScheme/color-scheme.js +40 -16
  53. package/dist/components/ColorScheme/index.d.ts +3 -0
  54. package/dist/components/ColorScheme/index.js +3 -0
  55. package/dist/components/DismissibleMessage/DismissibleMessage.svelte +76 -83
  56. package/dist/components/DismissibleMessage/DismissibleMessage.svelte.d.ts +16 -37
  57. package/dist/components/DismissibleMessage/index.css +13 -0
  58. package/dist/components/DismissibleMessage/index.d.ts +1 -0
  59. package/dist/components/DismissibleMessage/index.js +1 -0
  60. package/dist/components/Drawer/Drawer.svelte +155 -84
  61. package/dist/components/Drawer/Drawer.svelte.d.ts +24 -35
  62. package/dist/components/Drawer/index.d.ts +1 -0
  63. package/dist/components/Drawer/index.js +1 -0
  64. package/dist/components/HoverExpandableWidth/HoverExpandableWidth.svelte +150 -111
  65. package/dist/components/HoverExpandableWidth/HoverExpandableWidth.svelte.d.ts +16 -29
  66. package/dist/components/HoverExpandableWidth/index.d.ts +1 -0
  67. package/dist/components/HoverExpandableWidth/index.js +1 -0
  68. package/dist/components/Input/FieldCheckbox.svelte +174 -132
  69. package/dist/components/Input/FieldCheckbox.svelte.d.ts +28 -64
  70. package/dist/components/Input/FieldFile.svelte +166 -0
  71. package/dist/components/Input/FieldFile.svelte.d.ts +41 -0
  72. package/dist/components/Input/FieldInput.svelte +143 -0
  73. package/dist/components/Input/FieldInput.svelte.d.ts +41 -0
  74. package/dist/components/Input/FieldLikeButton.svelte +206 -0
  75. package/dist/components/Input/FieldLikeButton.svelte.d.ts +41 -0
  76. package/dist/components/Input/FieldOptions.svelte +646 -0
  77. package/dist/components/Input/FieldOptions.svelte.d.ts +58 -0
  78. package/dist/components/Input/FieldRadios.svelte +126 -77
  79. package/dist/components/Input/FieldRadios.svelte.d.ts +23 -61
  80. package/dist/components/Input/FieldSelect.svelte +160 -239
  81. package/dist/components/Input/FieldSelect.svelte.d.ts +40 -88
  82. package/dist/components/Input/FieldSwitch.svelte +132 -0
  83. package/dist/components/Input/FieldSwitch.svelte.d.ts +41 -0
  84. package/dist/components/Input/FieldTextarea.svelte +146 -0
  85. package/dist/components/Input/FieldTextarea.svelte.d.ts +44 -0
  86. package/dist/components/Input/Fieldset.svelte +21 -17
  87. package/dist/components/Input/Fieldset.svelte.d.ts +10 -27
  88. package/dist/components/Input/_internal/FieldRadioInternal.svelte +186 -0
  89. package/dist/components/Input/_internal/FieldRadioInternal.svelte.d.ts +30 -0
  90. package/dist/components/Input/_internal/InputWrap.svelte +216 -0
  91. package/dist/components/Input/_internal/InputWrap.svelte.d.ts +36 -0
  92. package/dist/components/Input/index.css +134 -0
  93. package/dist/components/Input/index.d.ts +11 -0
  94. package/dist/components/Input/index.js +11 -0
  95. package/dist/components/Input/types.d.ts +11 -0
  96. package/dist/components/KbdShortcut/KbdShortcut.svelte +89 -0
  97. package/dist/components/KbdShortcut/KbdShortcut.svelte.d.ts +17 -0
  98. package/dist/components/KbdShortcut/index.d.ts +1 -0
  99. package/dist/components/KbdShortcut/index.js +1 -0
  100. package/dist/components/Modal/Modal.svelte +127 -0
  101. package/dist/components/Modal/Modal.svelte.d.ts +32 -0
  102. package/dist/components/Modal/index.d.ts +1 -0
  103. package/dist/components/Modal/index.js +1 -0
  104. package/dist/components/ModalDialog/ModalDialog.svelte +137 -81
  105. package/dist/components/ModalDialog/ModalDialog.svelte.d.ts +17 -38
  106. package/dist/components/ModalDialog/index.d.ts +1 -0
  107. package/dist/components/ModalDialog/index.js +1 -0
  108. package/dist/components/Notifications/Notifications.svelte +259 -173
  109. package/dist/components/Notifications/Notifications.svelte.d.ts +32 -60
  110. package/dist/components/Notifications/index.css +12 -0
  111. package/dist/components/Notifications/index.d.ts +2 -0
  112. package/dist/components/Notifications/index.js +2 -0
  113. package/dist/components/Notifications/notifications-icons.d.ts +1 -1
  114. package/dist/components/Notifications/notifications-icons.js +4 -4
  115. package/dist/components/Notifications/notifications-stack.svelte.d.ts +89 -0
  116. package/dist/components/Notifications/notifications-stack.svelte.js +161 -0
  117. package/dist/components/Progress/Progress.svelte +26 -0
  118. package/dist/components/Progress/Progress.svelte.d.ts +10 -0
  119. package/dist/components/Progress/_internal/Bar.svelte +31 -0
  120. package/dist/components/Progress/_internal/Bar.svelte.d.ts +10 -0
  121. package/dist/components/Progress/_internal/Circle.svelte +10 -0
  122. package/dist/components/Progress/_internal/Circle.svelte.d.ts +7 -0
  123. package/dist/components/Progress/index.css +7 -0
  124. package/dist/components/Progress/index.d.ts +1 -0
  125. package/dist/components/Progress/index.js +1 -0
  126. package/dist/components/Spinner/Spinner.svelte +52 -37
  127. package/dist/components/Spinner/Spinner.svelte.d.ts +10 -22
  128. package/dist/components/Spinner/index.d.ts +1 -0
  129. package/dist/components/Spinner/index.js +1 -0
  130. package/dist/components/Switch/Switch.svelte +158 -118
  131. package/dist/components/Switch/Switch.svelte.d.ts +25 -66
  132. package/dist/components/Switch/SwitchButton.svelte +131 -0
  133. package/dist/components/Switch/SwitchButton.svelte.d.ts +21 -0
  134. package/dist/components/Switch/index.css +7 -0
  135. package/dist/components/Switch/index.d.ts +2 -0
  136. package/dist/components/Switch/index.js +2 -0
  137. package/dist/components/Thc/Thc.svelte +67 -10
  138. package/dist/components/Thc/Thc.svelte.d.ts +18 -22
  139. package/dist/components/Thc/index.d.ts +1 -0
  140. package/dist/components/Thc/index.js +1 -0
  141. package/dist/components/TwCheck/TwCheck.svelte +34 -0
  142. package/dist/components/TwCheck/TwCheck.svelte.d.ts +10 -0
  143. package/dist/components/TwCheck/index.css +5 -0
  144. package/dist/components/TwCheck/index.d.ts +1 -0
  145. package/dist/components/TwCheck/index.js +1 -0
  146. package/dist/components/X/X.svelte +12 -5
  147. package/dist/components/X/X.svelte.d.ts +6 -18
  148. package/dist/components/X/index.d.ts +1 -0
  149. package/dist/components/X/index.js +1 -0
  150. package/dist/index.css +26 -0
  151. package/dist/index.d.ts +21 -39
  152. package/dist/index.js +23 -54
  153. package/dist/types.d.ts +251 -2
  154. package/dist/types.js +248 -0
  155. package/dist/utils/breakpoint.svelte.d.ts +19 -0
  156. package/dist/utils/breakpoint.svelte.js +42 -0
  157. package/dist/utils/debounce.d.ts +13 -0
  158. package/dist/utils/debounce.js +22 -0
  159. package/dist/utils/device-pointer.svelte.d.ts +11 -0
  160. package/dist/utils/device-pointer.svelte.js +26 -0
  161. package/dist/utils/event-modifiers.d.ts +4 -0
  162. package/dist/utils/event-modifiers.js +29 -0
  163. package/dist/utils/get-id.d.ts +1 -1
  164. package/dist/utils/get-id.js +3 -1
  165. package/dist/utils/index.d.ts +21 -0
  166. package/dist/utils/index.js +21 -0
  167. package/dist/utils/is-browser.d.ts +1 -0
  168. package/dist/utils/is-browser.js +5 -0
  169. package/dist/utils/is-mac.d.ts +1 -0
  170. package/dist/utils/is-mac.js +11 -0
  171. package/dist/utils/maybe-json-parse.d.ts +1 -0
  172. package/dist/utils/maybe-json-parse.js +12 -0
  173. package/dist/utils/maybe-json-stringify.d.ts +1 -0
  174. package/dist/utils/maybe-json-stringify.js +11 -0
  175. package/dist/utils/move-array-item.d.ts +4 -0
  176. package/dist/utils/move-array-item.js +20 -0
  177. package/dist/utils/omit-pick.d.ts +2 -2
  178. package/dist/utils/omit-pick.js +10 -8
  179. package/dist/utils/paint.d.ts +18 -0
  180. package/dist/utils/paint.js +32 -0
  181. package/dist/utils/persistent-state.svelte.d.ts +23 -0
  182. package/dist/utils/persistent-state.svelte.js +48 -0
  183. package/dist/utils/prefers-reduced-motion.svelte.d.ts +2 -0
  184. package/dist/utils/prefers-reduced-motion.svelte.js +4 -0
  185. package/dist/utils/qsa.d.ts +1 -0
  186. package/dist/utils/qsa.js +3 -0
  187. package/dist/utils/sleep.d.ts +28 -0
  188. package/dist/utils/sleep.js +33 -0
  189. package/dist/utils/storage-abstraction.d.ts +35 -0
  190. package/dist/utils/storage-abstraction.js +136 -0
  191. package/dist/utils/str-hash.d.ts +7 -0
  192. package/dist/utils/str-hash.js +35 -0
  193. package/dist/utils/throttle.d.ts +1 -0
  194. package/dist/utils/throttle.js +47 -0
  195. package/dist/utils/to-integer.d.ts +1 -0
  196. package/dist/utils/to-integer.js +11 -0
  197. package/dist/utils/tr.d.ts +5 -0
  198. package/dist/utils/tr.js +13 -0
  199. package/dist/utils/tw-merge.d.ts +10 -0
  200. package/dist/utils/tw-merge.js +16 -0
  201. package/dist/utils/ucfirst.d.ts +1 -0
  202. package/dist/utils/ucfirst.js +6 -0
  203. package/package.json +66 -73
  204. package/dist/actions/autogrow.d.ts +0 -8
  205. package/dist/actions/autogrow.js +0 -22
  206. package/dist/actions/autoscroll.d.ts +0 -21
  207. package/dist/actions/autoscroll.js +0 -60
  208. package/dist/actions/drag-drop.d.ts +0 -28
  209. package/dist/actions/drag-drop.js +0 -152
  210. package/dist/actions/on-outside.d.ts +0 -9
  211. package/dist/actions/on-outside.js +0 -27
  212. package/dist/actions/pre-submit-validity-check.d.ts +0 -3
  213. package/dist/actions/pre-submit-validity-check.js +0 -21
  214. package/dist/actions/tooltip/_make-visible.d.ts +0 -3
  215. package/dist/actions/tooltip/_make-visible.js +0 -25
  216. package/dist/actions/tooltip/_maybe-pick-safe-placement.d.ts +0 -3
  217. package/dist/actions/tooltip/_maybe-pick-safe-placement.js +0 -86
  218. package/dist/actions/tooltip/_set-position.d.ts +0 -2
  219. package/dist/actions/tooltip/_set-position.js +0 -125
  220. package/dist/actions/tooltip/tooltip.d.ts +0 -42
  221. package/dist/actions/tooltip/tooltip.js +0 -299
  222. package/dist/actions/trim.d.ts +0 -4
  223. package/dist/actions/trim.js +0 -18
  224. package/dist/actions/validate.js +0 -80
  225. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt.d.ts +0 -58
  226. package/dist/components/AlertConfirmPrompt/alert-confirm-prompt.js +0 -141
  227. package/dist/components/ColorScheme/LocalColorScheme.svelte.d.ts +0 -25
  228. package/dist/components/ColorScheme/SystemAwareColorScheme.svelte.d.ts +0 -25
  229. package/dist/components/Input/Field.svelte +0 -315
  230. package/dist/components/Input/Field.svelte.d.ts +0 -102
  231. package/dist/components/Input/PinInput.svelte +0 -151
  232. package/dist/components/Input/PinInput.svelte.d.ts +0 -51
  233. package/dist/components/Input/XFieldRadioInternal.svelte +0 -143
  234. package/dist/components/Input/XFieldRadioInternal.svelte.d.ts +0 -45
  235. package/dist/components/Notifications/notifications.d.ts +0 -78
  236. package/dist/components/Notifications/notifications.js +0 -215
  237. package/dist/components/Popover/Popover.svelte +0 -24
  238. package/dist/components/Popover/Popover.svelte.d.ts +0 -22
  239. package/dist/components/Spinner/Spinner.v5.svelte +0 -114
  240. package/dist/components/Spinner/Spinner.v5.svelte.d.ts +0 -16
  241. package/dist/utils/calculate-alignment.d.ts +0 -68
  242. package/dist/utils/calculate-alignment.js +0 -183
  243. package/dist/utils/device-pointer.d.ts +0 -5
  244. package/dist/utils/device-pointer.js +0 -10
  245. package/dist/utils/prefers-reduced-motion.d.ts +0 -6
  246. package/dist/utils/prefers-reduced-motion.js +0 -26
  247. package/dist/utils/tw-merge2.d.ts +0 -3
  248. package/dist/utils/tw-merge2.js +0 -9
  249. package/dist/utils/tw-types.d.ts +0 -1
  250. package/dist/utils/window-size.d.ts +0 -22
  251. package/dist/utils/window-size.js +0 -35
  252. /package/dist/{utils/tw-types.js → components/Input/types.js} +0 -0
package/README.md CHANGED
@@ -2,14 +2,8 @@
2
2
 
3
3
  *S*velte *T*ailwind _UI_ *C*omponents.
4
4
 
5
- OPINIONATED, UNSTABLE, AND IN PROGRESS...
5
+ 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
- other libs, mainly:
8
+ other libs -- cherry-picked, combined, adjusted and tweaked to my personal preference and needs.
9
9
 
10
- - https://www.skeleton.dev/
11
- - https://flowbite-svelte.com/
12
- - https://captaincodeman.github.io/svelte-headlessui/
13
- - https://www.svelteui.org/
14
-
15
- Cherry-picked, combined, adjusted and tweaked to my personal preference and needs.
@@ -0,0 +1,2 @@
1
+ @import "tailwindcss";
2
+ @custom-variant dark (&:where(.dark, .dark *));
@@ -0,0 +1,6 @@
1
+ export declare function autogrow(el: HTMLTextAreaElement, fn?: () => {
2
+ enabled?: boolean;
3
+ min?: number;
4
+ max?: number;
5
+ immediate?: boolean;
6
+ }): void;
@@ -0,0 +1,19 @@
1
+ export function autogrow(el, fn) {
2
+ $effect(() => {
3
+ let { enabled = true, max = 250, immediate = true } = fn?.() || {};
4
+ function set_height(e) {
5
+ if (enabled) {
6
+ el.style.height = "auto"; // Reset height to auto to correctly calculate scrollHeight
7
+ el.style.height = Math.min(el.scrollHeight, max) + "px";
8
+ }
9
+ }
10
+ if (immediate)
11
+ set_height(null);
12
+ el.addEventListener("input", set_height);
13
+ el.addEventListener("blur", set_height);
14
+ return () => {
15
+ el.removeEventListener("input", set_height);
16
+ el.removeEventListener("blur", set_height);
17
+ };
18
+ });
19
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Will just add classes to el when being dragged over
3
+ */
4
+ export declare function highlightDragover(el: HTMLElement, fn?: () => {
5
+ enabled?: boolean;
6
+ classes?: string[];
7
+ }): void;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Will just add classes to el when being dragged over
3
+ */
4
+ export function highlightDragover(el, fn) {
5
+ // function handle_drop(e: DragEvent) {
6
+ // const files = e?.dataTransfer?.files;
7
+ // // Update the file input with the dropped files
8
+ // el.files = files || null;
9
+ // // Trigger change event for any listeners
10
+ // el.dispatchEvent(new Event("change"));
11
+ // }
12
+ function prevent(e) {
13
+ e.preventDefault();
14
+ e.stopPropagation();
15
+ }
16
+ const HIGH = ["dragenter", "dragover"];
17
+ const UNHIGH = ["dragleave", "drop"];
18
+ // const ALL = [...HIGH, ...UNHIGH];
19
+ $effect(() => {
20
+ let { classes = ["dragover"], enabled = true } = fn?.() || {};
21
+ if (!enabled)
22
+ return;
23
+ if (!Array.isArray(classes))
24
+ classes = [classes];
25
+ const highlight = () => el.classList.add(...classes);
26
+ const unhighlight = () => el.classList.remove(...classes);
27
+ // ALL.forEach((name: any) => el.addEventListener(name, prevent, false));
28
+ HIGH.forEach((name) => el.addEventListener(name, highlight, false));
29
+ UNHIGH.forEach((name) => el.addEventListener(name, unhighlight, false));
30
+ // el.addEventListener("drop", handle_drop, false);
31
+ return () => {
32
+ // ALL.forEach((name: any) => el.removeEventListener(name, prevent));
33
+ HIGH.forEach((name) => el.removeEventListener(name, highlight));
34
+ UNHIGH.forEach((name) => el.removeEventListener(name, unhighlight));
35
+ // el.removeEventListener("drop", handle_drop);
36
+ };
37
+ });
38
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./autogrow.svelte.js";
2
+ export * from "./focus-trap.js";
3
+ export * from "./highlight-dragover.svelte.js";
4
+ export * from "./on-submit-validity-check.svelte.js";
5
+ export * from "./tooltip/tooltip.svelte.js";
6
+ export * from "./trim.svelte.js";
7
+ export * from "./validate.svelte.js";
@@ -0,0 +1,7 @@
1
+ export * from "./autogrow.svelte.js";
2
+ export * from "./focus-trap.js";
3
+ export * from "./highlight-dragover.svelte.js";
4
+ export * from "./on-submit-validity-check.svelte.js";
5
+ export * from "./tooltip/tooltip.svelte.js";
6
+ export * from "./trim.svelte.js";
7
+ export * from "./validate.svelte.js";
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The problem: custom validity checks via `validate` action are registered on
3
+ * "input" or "change" events. When a form is submitted without touching those custom
4
+ * validated elements, those will not be validity-checked...
5
+ * I'm not able to come up with better solution than to manually trigger events which will
6
+ * then trigger the custom validation... (utilizing the `requestSubmit` seems like
7
+ * a right direction, but that still is not good)
8
+ *
9
+ * Still, smells like a hack...
10
+ */
11
+ export declare function onSubmitValidityCheck(node: HTMLFormElement): void;
12
+ export declare namespace onSubmitValidityCheck {
13
+ var SUBMIT_VALID_EVENT_NAME: string;
14
+ var SUBMIT_INVALID_EVENT_NAME: string;
15
+ }
@@ -0,0 +1,58 @@
1
+ const SUBMIT_VALID_EVENT_NAME = "submit_valid";
2
+ const SUBMIT_INVALID_EVENT_NAME = "submit_invalid";
3
+ /**
4
+ * The problem: custom validity checks via `validate` action are registered on
5
+ * "input" or "change" events. When a form is submitted without touching those custom
6
+ * validated elements, those will not be validity-checked...
7
+ * I'm not able to come up with better solution than to manually trigger events which will
8
+ * then trigger the custom validation... (utilizing the `requestSubmit` seems like
9
+ * a right direction, but that still is not good)
10
+ *
11
+ * Still, smells like a hack...
12
+ */
13
+ export function onSubmitValidityCheck(node) {
14
+ const onSubmit = (e) => {
15
+ e.preventDefault();
16
+ // this will disable all other onsubmit listeners...
17
+ e.stopImmediatePropagation();
18
+ let invalid = [];
19
+ for (let i = 0; i < node.elements?.length; i++) {
20
+ let el = node.elements[i];
21
+ if (typeof el.checkValidity === "function") {
22
+ // hm... radios are tricky, as triggering change automatically checks the last
23
+ // input (last radio input), which is not desired
24
+ if (el.type === "radio")
25
+ continue;
26
+ el.dispatchEvent(new Event("input", { bubbles: true }));
27
+ el.dispatchEvent(new Event("change", { bubbles: true }));
28
+ // typeof el.checkValidity === "function" && !el.checkValidity();
29
+ // NOTE: el.checkValidity() returns true for hidden inputs event if they are invalid!
30
+ // if (!el.checkValidity()) {
31
+ if (!el.validity.valid) {
32
+ invalid.push(el);
33
+ }
34
+ }
35
+ }
36
+ // none invalid
37
+ if (!invalid.length) {
38
+ node.dispatchEvent(new CustomEvent(SUBMIT_VALID_EVENT_NAME, {
39
+ bubbles: true,
40
+ detail: { formData: new FormData(node) },
41
+ }));
42
+ }
43
+ else {
44
+ node.dispatchEvent(new CustomEvent(SUBMIT_INVALID_EVENT_NAME, {
45
+ bubbles: true,
46
+ detail: { invalid },
47
+ }));
48
+ }
49
+ };
50
+ $effect(() => {
51
+ node.addEventListener("submit", onSubmit, true);
52
+ return () => {
53
+ node.removeEventListener("submit", onSubmit, true);
54
+ };
55
+ });
56
+ }
57
+ onSubmitValidityCheck.SUBMIT_VALID_EVENT_NAME = SUBMIT_VALID_EVENT_NAME;
58
+ onSubmitValidityCheck.SUBMIT_INVALID_EVENT_NAME = SUBMIT_INVALID_EVENT_NAME;
@@ -0,0 +1,34 @@
1
+ /* prettier-ignore */
2
+ @theme inline {
3
+ /* style props will not work as with regular components, because tooltips are created outside of the anchor dom tree */
4
+ --color-tooltip-bg: var(--color-tooltip-bg, var(--color-neutral-800));
5
+ --color-tooltip-bg-dark: var(--color-tooltip-bg-dark, var(--color-neutral-300));
6
+ --color-tooltip-text: var(--color-tooltip-text, var(--color-white));
7
+ --color-tooltip-text-dark: var(--color-tooltip-text-dark, var(--color-black));
8
+
9
+ }
10
+
11
+ .stuic-tooltip {
12
+ position: fixed;
13
+ display: none;
14
+ opacity: 0;
15
+ transition-property: opacity;
16
+ }
17
+
18
+ @supports (anchor-name: --anchor) {
19
+ .stuic-tooltip {
20
+ position-area: top span-right;
21
+ position-try-fallbacks:
22
+ flip-inline,
23
+ flip-block,
24
+ flip-block flip-inline;
25
+
26
+ &.tt-block {
27
+ display: block;
28
+ opacity: 0;
29
+ &.tt-visible {
30
+ opacity: 1;
31
+ }
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,13 @@
1
+ import "./index.css";
2
+ export declare function isTooltipSupported(): boolean;
3
+ /**
4
+ *
5
+ */
6
+ export declare function tooltip(anchorEl: HTMLElement, fn?: () => {
7
+ enabled?: boolean;
8
+ content?: string | null;
9
+ debug?: boolean;
10
+ class?: string;
11
+ onShow?: CallableFunction;
12
+ onHide?: CallableFunction;
13
+ }): void;
@@ -0,0 +1,203 @@
1
+ import { twMerge } from "../../utils/tw-merge.js";
2
+ //
3
+ import "./index.css";
4
+ const TIMEOUT = 200;
5
+ const TRANSITION = 200;
6
+ export function isTooltipSupported() {
7
+ return (CSS.supports("anchor-name", "--anchor") &&
8
+ CSS.supports("position-area", "top") &&
9
+ CSS.supports("position-try", "top") &&
10
+ CSS.supports("position-try-fallbacks", "top"));
11
+ }
12
+ //
13
+ // let _initialized = false;
14
+ // function global_init_once() {
15
+ // if (!is_tooltip_supported()) {
16
+ // console.warn("Tooltips not supported...");
17
+ // return false;
18
+ // }
19
+ // if (!_initialized) {
20
+ // _initialized = true;
21
+ // // const sheet = new CSSStyleSheet();
22
+ // // sheet.replaceSync(`
23
+ // // .stuic-tooltip {
24
+ // // position: fixed;
25
+ // // display: none;
26
+ // // opacity: 0;
27
+ // // transition-property: opacity;
28
+ // // transition-duration: ${TRANSITION}ms;
29
+ // // }
30
+ // // @supports (anchor-name: --anchor) {
31
+ // // .stuic-tooltip {
32
+ // // position-area: top span-right;
33
+ // // position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
34
+ // // }
35
+ // // .stuic-tooltip.tt-block {
36
+ // // display: block;
37
+ // // opacity: 0;
38
+ // // }
39
+ // // .stuic-tooltip.tt-block.tt-visible {
40
+ // // display: block;
41
+ // // opacity: 1;
42
+ // // }
43
+ // // }
44
+ // // `);
45
+ // // document.adoptedStyleSheets = [sheet];
46
+ // }
47
+ // return true;
48
+ // }
49
+ const _classTooltip = `
50
+ bg-tooltip-bg dark:bg-tooltip-bg-dark text-tooltip-text dark:text-tooltip-text-dark
51
+ text-xs tracking-tight rounded my-1
52
+ px-2.5 py-1.5
53
+ max-w-64
54
+ z-50
55
+ `;
56
+ /**
57
+ *
58
+ */
59
+ export function tooltip(anchorEl, fn) {
60
+ // the node has been mounted in the DOM
61
+ if (!isTooltipSupported())
62
+ return;
63
+ //
64
+ let tooltipEl;
65
+ let hide_timer = null;
66
+ let show_timer = null;
67
+ let do_debug = false;
68
+ let on_show = null;
69
+ let on_hide = null;
70
+ let content = null;
71
+ let classTooltip = null;
72
+ let enabled = true;
73
+ //
74
+ const rnd = Math.random().toString(36).slice(2);
75
+ const id = `tooltip-${rnd}`;
76
+ const anchorName = `--anchor-${rnd}`;
77
+ // node once init
78
+ anchorEl.style.cssText += `anchor-name: ${anchorName};`;
79
+ anchorEl.setAttribute("aria-describedby", id);
80
+ anchorEl.setAttribute("aria-expanded", "false");
81
+ const debug = (...args) => {
82
+ do_debug && console.debug("[tooltip]", rnd, ...args);
83
+ };
84
+ function ensure_tooltip() {
85
+ debug("ensure_tooltip()", content, classTooltip);
86
+ if (!content)
87
+ return false;
88
+ // lazy factory init
89
+ if (!tooltipEl) {
90
+ debug("creating element...");
91
+ tooltipEl = document.createElement("div");
92
+ tooltipEl.setAttribute("id", id);
93
+ tooltipEl.setAttribute("role", "tooltip");
94
+ tooltipEl.style.cssText += `position-anchor: ${anchorName}; transition-duration: ${TRANSITION}ms;`;
95
+ tooltipEl.classList.add(...twMerge("stuic-tooltip", _classTooltip).split(/\s/));
96
+ document.body.appendChild(tooltipEl);
97
+ //
98
+ tooltipEl.addEventListener("mouseover", schedule_show);
99
+ tooltipEl.addEventListener("mouseout", schedule_hide);
100
+ }
101
+ // re/set based on params
102
+ set_content();
103
+ return true;
104
+ }
105
+ function set_content() {
106
+ if (tooltipEl) {
107
+ debug("set_content()", classTooltip, content);
108
+ if (classTooltip) {
109
+ let old = tooltipEl.className;
110
+ tooltipEl.className = ""; // reset
111
+ tooltipEl.classList.add(...twMerge(old, classTooltip).split(/\s/));
112
+ }
113
+ tooltipEl.textContent = "";
114
+ tooltipEl.innerHTML = `${content}`;
115
+ }
116
+ }
117
+ function clear_show() {
118
+ clearTimeout(show_timer);
119
+ show_timer = null;
120
+ }
121
+ function clear_hide() {
122
+ clearTimeout(hide_timer);
123
+ hide_timer = null;
124
+ }
125
+ function clear_both() {
126
+ clear_show();
127
+ clear_hide();
128
+ }
129
+ function schedule_show() {
130
+ debug("schedule_show()", enabled);
131
+ clear_both();
132
+ if (!enabled || !ensure_tooltip())
133
+ return;
134
+ show_timer = setTimeout(() => {
135
+ if (!hide_timer) {
136
+ debug("show...");
137
+ clear_show();
138
+ anchorEl.setAttribute("aria-expanded", "true");
139
+ //
140
+ tooltipEl.classList.add("tt-block");
141
+ setTimeout(() => {
142
+ tooltipEl.classList.add("tt-visible");
143
+ on_show?.();
144
+ }, TRANSITION);
145
+ // waitForTwoRepaints().then(() => {
146
+ // tooltipEl.classList.add("tt-visible");
147
+ // this approach is nicer, but I have a suspicion of the event handlers not being destroyed properly (maybe just a hot-reload issues...)
148
+ // waitForTransitionEnd(tooltipEl).then(() => on_show?.());
149
+ // });
150
+ }
151
+ }, TIMEOUT);
152
+ }
153
+ function schedule_hide() {
154
+ debug("scheduleHide()", enabled);
155
+ clear_both();
156
+ // legit - maybe there was no content available...
157
+ if (!tooltipEl)
158
+ return false;
159
+ hide_timer = setTimeout(() => {
160
+ debug("hide...");
161
+ clear_hide();
162
+ anchorEl.setAttribute("aria-expanded", "false");
163
+ tooltipEl.classList.remove("tt-visible");
164
+ setTimeout(() => {
165
+ tooltipEl.classList.remove("tt-block");
166
+ on_hide?.();
167
+ }, TRANSITION);
168
+ // this approach is nicer, but I have a suspicion of the event handlers not being destroyed properly (maybe just a hot-reload issues...)
169
+ // waitForTransitionEnd(tooltipEl).then(() => {
170
+ // tooltipEl.classList.remove("tt-block");
171
+ // on_hide?.();
172
+ // });
173
+ }, TIMEOUT);
174
+ }
175
+ // "reactive" params re/set
176
+ $effect(() => {
177
+ let { enabled: _enabled, content: _content, debug: debugParam, class: _classTooltip, onShow, onHide, } = fn?.() || {};
178
+ // re/assign new params
179
+ do_debug = !!debugParam;
180
+ on_show = onShow;
181
+ on_hide = onHide;
182
+ content = _content ||= anchorEl.getAttribute("aria-label");
183
+ classTooltip = _classTooltip;
184
+ enabled = _enabled ?? true;
185
+ // this will be effective here only if currently in open state, otherwise noop
186
+ set_content();
187
+ // do not return cleanups here - we want the tooltipEl to persist params change
188
+ });
189
+ // add/remove listeners effect ("non-reactive")
190
+ $effect(() => {
191
+ anchorEl.addEventListener("mouseover", schedule_show);
192
+ anchorEl.addEventListener("mouseout", schedule_hide);
193
+ return () => {
194
+ anchorEl.removeEventListener("mouseover", schedule_show);
195
+ anchorEl.removeEventListener("mouseout", schedule_hide);
196
+ // might not have been initialized
197
+ tooltipEl?.removeEventListener("mouseover", schedule_show);
198
+ tooltipEl?.removeEventListener("mouseout", schedule_hide);
199
+ tooltipEl?.remove();
200
+ clear_both();
201
+ };
202
+ });
203
+ }
@@ -0,0 +1,4 @@
1
+ export declare function trim(el: HTMLInputElement | HTMLTextAreaElement, fn?: () => {
2
+ enabled?: boolean;
3
+ setValue?: (v: string) => any;
4
+ }): void;
@@ -0,0 +1,17 @@
1
+ export function trim(el, fn) {
2
+ // the node has been mounted in the DOM
3
+ $effect(() => {
4
+ // setup goes here
5
+ let { enabled, setValue } = fn?.() || { enabled: true };
6
+ function trim(e) {
7
+ if (enabled && typeof el.value === "string") {
8
+ el.value = el.value.trim();
9
+ setValue?.(el.value);
10
+ }
11
+ }
12
+ el.addEventListener("change", trim);
13
+ return () => {
14
+ el.removeEventListener("change", trim);
15
+ };
16
+ });
17
+ }
@@ -5,18 +5,18 @@ export interface ValidationResult {
5
5
  message: string;
6
6
  }
7
7
  type ReasonTranslate = (reason: keyof ValidityStateFlags, value: any, fallback: string) => string;
8
+ /** */
8
9
  export interface ValidateOptions {
10
+ enabled?: boolean;
9
11
  context?: Record<string, any>;
10
12
  customValidator?: (value: any, context: Record<string, any> | undefined, el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement) => string | undefined;
11
- on?: 'input' | 'change';
13
+ on?: "input" | "change";
12
14
  setValidationResult?: (res: ValidationResult) => void;
13
15
  t?: false | ReasonTranslate;
14
16
  }
15
- export declare const validate: {
16
- (el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, options: undefined | ValidateOptions): {
17
- update(newOptions: undefined | ValidateOptions): void;
18
- destroy(): void;
19
- };
20
- t: null;
21
- };
17
+ /** Main action api */
18
+ export declare function validate(el: HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement, fn?: () => boolean | ValidateOptions): void;
19
+ export declare namespace validate {
20
+ var t: null;
21
+ }
22
22
  export {};
@@ -0,0 +1,90 @@
1
+ import { tick } from "svelte";
2
+ import { waitForNextRepaint, waitForTwoRepaints } from "../utils/paint.js";
3
+ /**
4
+ *
5
+ */
6
+ const KNOWN_REASONS = [
7
+ "badInput",
8
+ "customError",
9
+ "patternMismatch",
10
+ "rangeOverflow",
11
+ "rangeUnderflow",
12
+ "stepMismatch",
13
+ "tooLong",
14
+ "tooShort",
15
+ "typeMismatch",
16
+ "valueMissing",
17
+ ];
18
+ /** Main action api */
19
+ export function validate(el, fn) {
20
+ $effect(() => {
21
+ //
22
+ let fnResult = fn?.() ?? {};
23
+ let { enabled, context, customValidator, on = "change", setValidationResult, t, } = typeof fnResult === "boolean" ? { enabled: !!fnResult } : fnResult;
24
+ //
25
+ const _t = (reason, value, fallback) => {
26
+ // explicit false
27
+ if (!reason || t === false) {
28
+ return fallback;
29
+ }
30
+ // local t (if any)
31
+ else if (typeof t === "function") {
32
+ return t(reason, value, fallback);
33
+ }
34
+ // global t (if any)
35
+ else if (typeof validate.t === "function") {
36
+ return validate.t(reason, value, fallback);
37
+ }
38
+ return fallback;
39
+ };
40
+ const _doValidate = () => {
41
+ if (!enabled)
42
+ return;
43
+ el.checkValidity();
44
+ if (typeof customValidator === "function") {
45
+ el.setCustomValidity(customValidator(el.value, context, el) || "");
46
+ }
47
+ // this triggers the bubble, which is not what we want
48
+ // el.reportValidity();
49
+ const validityState = el.validity;
50
+ const reasons = KNOWN_REASONS.reduce((m, k) => {
51
+ if (validityState[k])
52
+ m.push(k);
53
+ return m;
54
+ }, []);
55
+ // console.log(1111, validityState, el);
56
+ // hm... Uncaught Svelte error: state_unsafe_mutation...
57
+ // the `tick` await helps, but I'm not really sure I understand the internals...
58
+ tick().then(() => {
59
+ setValidationResult?.({
60
+ validity: validityState,
61
+ reasons,
62
+ valid: validityState?.valid,
63
+ // use translate fn for first reason (if fn provided and allowed),
64
+ // otherwise fallback to native msg
65
+ message: _t(reasons?.[0], el.value, el.validationMessage ||
66
+ // PROBLEM: hidden inputs do not report validationMessage-s even
67
+ // if correctly reported as invalid. So all we can do, is
68
+ // put anything generically reasonable here...
69
+ "This field contains invalid data. Please review and try again."),
70
+ });
71
+ });
72
+ };
73
+ el.addEventListener(on, _doValidate);
74
+ //
75
+ let _touchCount = 0;
76
+ const onFocus = (e) => _touchCount++;
77
+ el.addEventListener("focus", onFocus);
78
+ // also validate on first blur
79
+ const onBlur = (e) => _touchCount === 1 && _doValidate();
80
+ el.addEventListener("blur", onBlur);
81
+ return () => {
82
+ el.removeEventListener(on, _doValidate);
83
+ el.removeEventListener("focus", onFocus);
84
+ el.removeEventListener("blur", onBlur);
85
+ };
86
+ });
87
+ }
88
+ // ReasonTranslate
89
+ const t = null;
90
+ validate.t = t;