@lyeve-labs/ui-kit 0.23.0 → 0.23.1

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.
@@ -27,13 +27,63 @@
27
27
 
28
28
  const id = $props.id();
29
29
 
30
+ /**
31
+ * The box is positioned from the trigger's bounding box, fixed to the
32
+ * viewport, rather than absolutely inside the wrapper.
33
+ *
34
+ * Inside the wrapper it took the wrapper's width, so a hint on an icon
35
+ * button broke one character per line, and any ancestor that scrolls cut
36
+ * it off: a Table's scroller is overflow-x auto, which makes its vertical
37
+ * overflow auto as well, so a hint on a row action was clipped at the
38
+ * header. Nothing between a fixed box and the viewport can clip it. The
39
+ * translate carries the half of the geometry that depends on the box's own
40
+ * size, which is not known until it renders.
41
+ */
30
42
  const pos: Record<Position, string> = {
31
- top: 'bottom-full left-1/2 -translate-x-1/2 mb-2',
32
- bottom: 'top-full left-1/2 -translate-x-1/2 mt-2',
33
- left: 'right-full top-1/2 -translate-y-1/2 mr-2',
34
- right: 'left-full top-1/2 -translate-y-1/2 ml-2',
43
+ top: '-translate-x-1/2 -translate-y-full',
44
+ bottom: '-translate-x-1/2',
45
+ left: '-translate-x-full -translate-y-1/2',
46
+ right: '-translate-y-1/2',
35
47
  };
36
48
 
49
+ /** The distance between the trigger's edge and the box. */
50
+ const GAP = 8;
51
+
52
+ let anchor = $state({ top: 0, left: 0 });
53
+
54
+ function place() {
55
+ const r = wrapper?.getBoundingClientRect();
56
+ if (!r) return;
57
+ switch (position) {
58
+ case 'top':
59
+ anchor = { top: r.top - GAP, left: r.left + r.width / 2 };
60
+ break;
61
+ case 'bottom':
62
+ anchor = { top: r.bottom + GAP, left: r.left + r.width / 2 };
63
+ break;
64
+ case 'left':
65
+ anchor = { top: r.top + r.height / 2, left: r.left - GAP };
66
+ break;
67
+ case 'right':
68
+ anchor = { top: r.top + r.height / 2, left: r.right + GAP };
69
+ break;
70
+ }
71
+ }
72
+
73
+ function show() {
74
+ place();
75
+ visible = true;
76
+ }
77
+
78
+ // A fixed box does not follow a trigger that scrolls away from under it,
79
+ // so a scroll anywhere closes the hint rather than leaving it stranded.
80
+ $effect(() => {
81
+ if (!visible) return;
82
+ const close = () => (visible = false);
83
+ window.addEventListener('scroll', close, { capture: true, passive: true });
84
+ return () => window.removeEventListener('scroll', close, { capture: true });
85
+ });
86
+
37
87
  /**
38
88
  * `role="tooltip"` on its own is inert: assistive technology reads a tooltip
39
89
  * only because the element it describes points at it. The trigger arrives as
@@ -68,9 +118,9 @@
68
118
  <span
69
119
  bind:this={wrapper}
70
120
  class="relative inline-flex {cls}"
71
- onmouseenter={() => (visible = true)}
121
+ onmouseenter={show}
72
122
  onmouseleave={() => (visible = false)}
73
- onfocusin={() => (visible = true)}
123
+ onfocusin={show}
74
124
  onfocusout={() => (visible = false)}
75
125
  {onkeydown}
76
126
  >
@@ -84,7 +134,8 @@
84
134
  role={describe ? 'tooltip' : undefined}
85
135
  aria-hidden={describe ? undefined : 'true'}
86
136
  hidden={!visible}
87
- class="absolute {pos[position]} z-tooltip max-w-[min(16rem,calc(100vw-2rem))]
137
+ style="top: {anchor.top}px; left: {anchor.left}px"
138
+ class="fixed {pos[position]} z-tooltip w-max max-w-[min(16rem,calc(100vw-2rem))]
88
139
  rounded-lg border border-line bg-surface-2 px-2.5 py-1.5 text-xs text-fg shadow-xl"
89
140
  >
90
141
  {text}
package/dist/index.d.ts CHANGED
@@ -89,4 +89,4 @@ export type { ConfirmOptions } from './components/dialog/dialog-manager.svelte.j
89
89
  export type { DialogOptions, DialogEntry, DialogSize } from './components/dialog/types.js';
90
90
  export { cn, type ClassValue } from './utils/cn.js';
91
91
  export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setTheme, setThemePreference, systemTheme, themeBootScript, toggleTheme, watchSystemTheme, THEME_PREFERENCES, type Theme, type ThemePreference, } from './utils/theme.js';
92
- export declare const VERSION = "0.23.0";
92
+ export declare const VERSION = "0.23.1";
package/dist/index.js CHANGED
@@ -96,4 +96,4 @@ export { getTheme, getThemePreference, nextThemePreference, resolveTheme, setThe
96
96
  // ── Version ────────────────────────────────────────────────────────────────
97
97
  // Generated from package.json by `pnpm version:sync`. Bump package.json, never
98
98
  // this line; the build and the test suite fail when the two disagree.
99
- export const VERSION = '0.23.0';
99
+ export const VERSION = '0.23.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lyeve-labs/ui-kit",
3
- "version": "0.23.0",
3
+ "version": "0.23.1",
4
4
  "description": "A clean, accessible, palette-aware Svelte 5 component library. The design system behind LyEve.",
5
5
  "license": "MIT",
6
6
  "author": "LyEve Labs <hello@lyeve.com>",