@ibobbyts/svelte-ui-utils 0.3.8 → 0.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 (39) hide show
  1. package/README.md +97 -21
  2. package/dist/data-table/BaseDataTable.svelte +5 -0
  3. package/dist/data-table/BaseDataTable.svelte.d.ts +1 -0
  4. package/dist/data-table/BaseDataTable.svelte.d.ts.map +1 -1
  5. package/dist/data-table/DataTable.svelte +141 -22
  6. package/dist/data-table/DataTable.svelte.d.ts +3 -8
  7. package/dist/data-table/DataTable.svelte.d.ts.map +1 -1
  8. package/dist/data-table/FilterControl.svelte +64 -18
  9. package/dist/data-table/FilterControl.svelte.d.ts.map +1 -1
  10. package/dist/data-table/FilterTable.svelte +2 -1
  11. package/dist/data-table/FilterTable.svelte.d.ts +1 -0
  12. package/dist/data-table/FilterTable.svelte.d.ts.map +1 -1
  13. package/dist/data-table/filter.d.ts +3 -1
  14. package/dist/data-table/filter.d.ts.map +1 -1
  15. package/dist/data-table/filter.js +4 -0
  16. package/dist/data-table/index.d.ts +1 -1
  17. package/dist/data-table/index.d.ts.map +1 -1
  18. package/dist/data-table/types.d.ts +37 -3
  19. package/dist/data-table/types.d.ts.map +1 -1
  20. package/dist/dropdown/DropdownMultiSelect.svelte +1 -1
  21. package/dist/dropdown-search/DropdownSearch.svelte +30 -0
  22. package/dist/dropdown-search/DropdownSearch.svelte.d.ts.map +1 -1
  23. package/dist/index.d.ts +1 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +1 -0
  26. package/dist/ordered-list/OrderedListEditor.svelte +1 -1
  27. package/dist/pagination/Pagination.svelte +9 -0
  28. package/dist/pagination/Pagination.svelte.d.ts +1 -0
  29. package/dist/pagination/Pagination.svelte.d.ts.map +1 -1
  30. package/dist/sortable-list/SortableList.svelte +1 -1
  31. package/dist/sortable-table/SortableTable.svelte +1 -1
  32. package/dist/style.css +101 -23
  33. package/dist/tooltip/Tooltip.svelte +149 -0
  34. package/dist/tooltip/Tooltip.svelte.d.ts +22 -0
  35. package/dist/tooltip/Tooltip.svelte.d.ts.map +1 -0
  36. package/dist/tooltip/index.d.ts +2 -0
  37. package/dist/tooltip/index.d.ts.map +1 -0
  38. package/dist/tooltip/index.js +1 -0
  39. package/package.json +1 -1
@@ -0,0 +1,149 @@
1
+ <svelte:options runes={false} />
2
+
3
+ <script lang="ts">
4
+ import { afterUpdate, onDestroy } from 'svelte';
5
+
6
+ let rootElement: HTMLSpanElement | undefined;
7
+ let panelElement: HTMLDivElement | undefined;
8
+ let hovered = false;
9
+ let focused = false;
10
+ let visible = false;
11
+ let panelId = `suu-tooltip-${Math.random().toString(36).slice(2)}`;
12
+ let frame = 0;
13
+ let triggerElement: HTMLElement | undefined;
14
+ let panelObserver: ResizeObserver | undefined;
15
+
16
+ $: visible = hovered || focused;
17
+
18
+ function updatePosition() {
19
+ if (!visible || !rootElement || !panelElement || typeof window === 'undefined') {
20
+ return;
21
+ }
22
+
23
+ const trigger = rootElement.getBoundingClientRect();
24
+ const panel = panelElement.getBoundingClientRect();
25
+ const gap = 8;
26
+ const canPlaceAbove = trigger.top >= panel.height + gap;
27
+ const preferredTop = canPlaceAbove ? trigger.top - panel.height - gap : trigger.bottom + gap;
28
+ const maxTop = Math.max(gap, window.innerHeight - panel.height - gap);
29
+ const top = Math.min(maxTop, Math.max(gap, preferredTop));
30
+ const maxLeft = Math.max(gap, window.innerWidth - panel.width - gap);
31
+ const left = Math.min(
32
+ Math.max(gap, trigger.left + (trigger.width - panel.width) / 2),
33
+ maxLeft,
34
+ );
35
+
36
+ panelElement.style.setProperty('--suu-tooltip-top', `${top}px`);
37
+ panelElement.style.setProperty('--suu-tooltip-left', `${left}px`);
38
+ }
39
+
40
+ function schedulePosition() {
41
+ if (typeof window === 'undefined') return;
42
+ cancelAnimationFrame(frame);
43
+ frame = requestAnimationFrame(updatePosition);
44
+ }
45
+
46
+ function showFromHover() {
47
+ hovered = true;
48
+ triggerElement = findTrigger();
49
+ schedulePosition();
50
+ }
51
+
52
+ function hideFromHover() {
53
+ hovered = false;
54
+ }
55
+
56
+ function focusIn(event: FocusEvent) {
57
+ focused = true;
58
+ triggerElement = event.target instanceof HTMLElement ? event.target : findTrigger();
59
+ schedulePosition();
60
+ }
61
+
62
+ function focusOut(event: FocusEvent) {
63
+ const next = event.relatedTarget;
64
+ if (next instanceof Node && rootElement?.contains(next)) return;
65
+ focused = false;
66
+ }
67
+
68
+ function handleViewportChange() {
69
+ schedulePosition();
70
+ }
71
+
72
+ function findTrigger() {
73
+ return rootElement?.querySelector<HTMLElement>(
74
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
75
+ ) ?? undefined;
76
+ }
77
+
78
+ function syncDescription() {
79
+ if (!rootElement || !$$slots.content) return;
80
+ const nextTrigger = triggerElement ?? findTrigger();
81
+ if (triggerElement && triggerElement !== nextTrigger) {
82
+ removePanelDescription(triggerElement);
83
+ }
84
+ triggerElement = nextTrigger;
85
+ if (triggerElement) {
86
+ if (visible) addPanelDescription(triggerElement);
87
+ else removePanelDescription(triggerElement);
88
+ }
89
+ }
90
+
91
+ function addPanelDescription(element: HTMLElement) {
92
+ const ids = new Set((element.getAttribute('aria-describedby') ?? '').split(/\s+/).filter(Boolean));
93
+ ids.add(panelId);
94
+ element.setAttribute('aria-describedby', [...ids].join(' '));
95
+ }
96
+
97
+ function removePanelDescription(element: HTMLElement) {
98
+ const ids = (element.getAttribute('aria-describedby') ?? '')
99
+ .split(/\s+/)
100
+ .filter((id) => id && id !== panelId);
101
+ if (ids.length > 0) element.setAttribute('aria-describedby', ids.join(' '));
102
+ else element.removeAttribute('aria-describedby');
103
+ }
104
+
105
+ function syncPanelObserver() {
106
+ panelObserver?.disconnect();
107
+ panelObserver = undefined;
108
+ if (visible && panelElement && typeof ResizeObserver !== 'undefined') {
109
+ panelObserver = new ResizeObserver(() => schedulePosition());
110
+ panelObserver.observe(panelElement);
111
+ }
112
+ syncDescription();
113
+ }
114
+
115
+ if (typeof window !== 'undefined') {
116
+ window.addEventListener('resize', handleViewportChange);
117
+ window.addEventListener('scroll', handleViewportChange, true);
118
+ }
119
+
120
+ afterUpdate(syncPanelObserver);
121
+
122
+ onDestroy(() => {
123
+ if (typeof window !== 'undefined') {
124
+ window.removeEventListener('resize', handleViewportChange);
125
+ window.removeEventListener('scroll', handleViewportChange, true);
126
+ cancelAnimationFrame(frame);
127
+ }
128
+ panelObserver?.disconnect();
129
+ if (triggerElement) removePanelDescription(triggerElement);
130
+ });
131
+ </script>
132
+
133
+ <span
134
+ bind:this={rootElement}
135
+ class="suu-tooltip"
136
+ role="group"
137
+ on:mouseenter={showFromHover}
138
+ on:mouseleave={hideFromHover}
139
+ on:focusin={focusIn}
140
+ on:focusout={focusOut}
141
+ >
142
+ <slot />
143
+
144
+ {#if visible && $$slots.content}
145
+ <div bind:this={panelElement} class="suu-tooltip__panel" id={panelId} role="tooltip">
146
+ <slot name="content" />
147
+ </div>
148
+ {/if}
149
+ </span>
@@ -0,0 +1,22 @@
1
+ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
+ new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
+ $$bindings?: Bindings;
4
+ } & Exports;
5
+ (internal: unknown, props: {
6
+ $$events?: Events;
7
+ $$slots?: Slots;
8
+ }): Exports & {
9
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ declare const Tooltip: $$__sveltets_2_IsomorphicComponent<any, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {
17
+ default: {};
18
+ content: {};
19
+ }, {}, string>;
20
+ type Tooltip = InstanceType<typeof Tooltip>;
21
+ export default Tooltip;
22
+ //# sourceMappingURL=Tooltip.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Tooltip.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/tooltip/Tooltip.svelte.ts"],"names":[],"mappings":"AAqJA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAUD,QAAA,MAAM,OAAO;;;;;cAAqF,CAAC;AACjF,KAAK,OAAO,GAAG,YAAY,CAAC,OAAO,OAAO,CAAC,CAAC;AAC9C,eAAe,OAAO,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { default as Tooltip } from './Tooltip.svelte';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/tooltip/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1 @@
1
+ export { default as Tooltip } from './Tooltip.svelte';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ibobbyts/svelte-ui-utils",
3
- "version": "0.3.8",
3
+ "version": "0.4.0",
4
4
  "description": "Reusable Svelte 5 UI utilities for dialogs, toast notifications, dropdown search, and data tables.",
5
5
  "type": "module",
6
6
  "license": "MIT",