lapikit 0.7.9 → 0.8.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.
Files changed (28) hide show
  1. package/dist/components/btn/btn.svelte +25 -4
  2. package/dist/components/btn/btn.types.d.ts +3 -0
  3. package/dist/components/card/card.svelte +6 -1
  4. package/dist/components/chip/chip.svelte +25 -4
  5. package/dist/components/chip/chip.types.d.ts +3 -0
  6. package/dist/components/dropdown/dropdown.svelte +120 -41
  7. package/dist/components/dropdown/dropdown.svelte.d.ts +1 -1
  8. package/dist/components/dropdown/dropdown.types.d.ts +19 -8
  9. package/dist/components/field/field.svelte +22 -0
  10. package/dist/components/field/field.types.d.ts +1 -0
  11. package/dist/components/icon/icon.svelte +11 -3
  12. package/dist/components/icon/icon.types.d.ts +3 -0
  13. package/dist/components/index.d.ts +3 -3
  14. package/dist/components/list/list.context.d.ts +7 -0
  15. package/dist/components/list/list.context.js +4 -0
  16. package/dist/components/list/list.svelte +18 -4
  17. package/dist/components/list/modules/list-item.svelte +68 -33
  18. package/dist/components/popover/popover.svelte +57 -10
  19. package/dist/components/popover/popover.types.d.ts +10 -4
  20. package/dist/components/textfield/textfield.svelte +5 -12
  21. package/dist/components/textfield/textfield.types.d.ts +1 -5
  22. package/dist/components/tooltip/tooltip-action.svelte.d.ts +9 -0
  23. package/dist/components/tooltip/tooltip-action.svelte.js +159 -0
  24. package/dist/components/tooltip/tooltip.svelte +71 -56
  25. package/dist/components/tooltip/tooltip.svelte.d.ts +4 -2
  26. package/dist/components/tooltip/tooltip.types.d.ts +28 -2
  27. package/dist/labs/sheet/sheet.svelte +6 -1
  28. package/package.json +1 -1
@@ -1,19 +1,23 @@
1
1
  <script lang="ts">
2
2
  import { onDestroy } from 'svelte';
3
+ import { DEV } from 'esm-env';
3
4
  import { floating, useComponentAttrs } from '../../utils';
4
- import type { TooltipProps } from './tooltip.types.js';
5
+ import type { TooltipProps, TooltipTriggerProps } from './tooltip.types.js';
5
6
 
6
7
  let {
7
8
  ref = $bindable(),
9
+ id,
8
10
  children,
11
+ trigger,
9
12
  tooltip,
10
13
  open = $bindable(false),
11
- forceMount = false,
12
14
  label,
15
+ asLabel = false,
13
16
  rounded = 'xs',
14
17
  color,
15
18
  location = 'bottom',
16
19
  delayDuration = 850,
20
+ closeDelay = 100,
17
21
  density = 'default',
18
22
  variant,
19
23
  disabled = false,
@@ -25,67 +29,96 @@
25
29
  ...rest
26
30
  }: TooltipProps = $props();
27
31
 
28
- const tooltipId = $props.id();
32
+ $effect(() => {
33
+ if (DEV && children)
34
+ console.warn('[lapikit] kit:tooltip: children is removed, use the trigger snippet');
35
+ });
36
+
37
+ const generatedId = $props.id();
38
+ let tooltipId = $derived(id || generatedId);
29
39
 
30
40
  let attrs = $derived(
31
41
  useComponentAttrs('kit-tooltip', { className, sClass, styleAttr, sStyle, color }, rest)
32
42
  );
33
43
 
34
- let triggerRef = $state<HTMLElement | null>(null);
44
+ let anchor = $state<HTMLElement | null>(null);
35
45
  let timer: ReturnType<typeof setTimeout> | null = null;
36
46
  let focused = false;
37
- let mounted = $derived(open || forceMount || !!tooltip);
47
+ let ariaAttribute = $derived(asLabel ? 'aria-labelledby' : 'aria-describedby');
38
48
 
39
49
  const clearTimer = () => {
40
50
  if (timer) clearTimeout(timer);
41
51
  timer = null;
42
52
  };
43
53
 
44
- const handleHoverOpen = () => {
45
- if (disabled) return;
46
- clearTimer();
47
- if (open) return;
48
- timer = setTimeout(() => {
49
- open = true;
50
- timer = null;
51
- }, delayDuration);
52
- };
53
-
54
- const handleFocusOpen = () => {
55
- if (disabled) return;
56
- focused = true;
54
+ const show = () => {
57
55
  clearTimer();
58
56
  open = true;
59
57
  };
60
58
 
61
- const handleClose = () => {
59
+ const hide = () => {
62
60
  clearTimer();
63
61
  open = false;
64
62
  };
65
63
 
66
- const handleHoverClose = () => {
64
+ const scheduleHide = () => {
67
65
  clearTimer();
68
66
  if (focused) return;
69
- timer = setTimeout(handleClose, 100);
67
+ timer = setTimeout(hide, closeDelay);
70
68
  };
71
69
 
72
- const handleFocusClose = () => {
73
- focused = false;
74
- handleClose();
70
+ const isFocusVisible = (element: HTMLElement) => {
71
+ try {
72
+ return element.matches(':focus-visible');
73
+ } catch {
74
+ return true;
75
+ }
75
76
  };
76
77
 
78
+ // the trigger, when open is set without a pointer or a focus event
79
+ const findAnchor = () =>
80
+ document.querySelector<HTMLElement>(`[${ariaAttribute}~="${CSS.escape(tooltipId)}"]`);
81
+
82
+ let triggerProps: TooltipTriggerProps = $derived({
83
+ [ariaAttribute]: tooltipId,
84
+ onpointerenter: (event: PointerEvent) => {
85
+ if (disabled || event.pointerType === 'touch') return;
86
+ anchor = event.currentTarget as HTMLElement;
87
+ clearTimer();
88
+ if (open) return;
89
+ timer = setTimeout(show, delayDuration);
90
+ },
91
+ onpointerleave: scheduleHide,
92
+ onpointerdown: hide,
93
+ onfocus: (event: FocusEvent) => {
94
+ if (disabled) return;
95
+ anchor = event.currentTarget as HTMLElement;
96
+ focused = true;
97
+ if (isFocusVisible(event.target as HTMLElement)) show();
98
+ },
99
+ onblur: () => {
100
+ focused = false;
101
+ hide();
102
+ }
103
+ });
104
+
105
+ /** the handlers of the trigger, for the tooltip prop of kit:btn, kit:chip and kit:icon */
106
+ export function triggerHandlers() {
107
+ return triggerProps;
108
+ }
109
+
77
110
  $effect(() => {
78
111
  if (disabled) open = false;
79
112
  });
80
113
 
81
114
  $effect(() => {
82
- ref = triggerRef;
115
+ if (open && !anchor?.isConnected) anchor = findAnchor();
83
116
  });
84
117
 
85
118
  $effect(() => {
86
119
  if (!open) return;
87
120
  const onKeyDown = (event: KeyboardEvent) => {
88
- if (event.key === 'Escape') handleClose();
121
+ if (event.key === 'Escape') hide();
89
122
  };
90
123
  document.addEventListener('keydown', onKeyDown);
91
124
  return () => document.removeEventListener('keydown', onKeyDown);
@@ -94,33 +127,22 @@
94
127
  onDestroy(clearTimer);
95
128
  </script>
96
129
 
97
- <!-- svelte-ignore a11y_no_static_element_interactions -->
98
- <span
99
- bind:this={triggerRef}
100
- class="kit-tooltip-trigger"
101
- aria-describedby={open ? tooltipId : undefined}
102
- onmouseenter={handleHoverOpen}
103
- onmouseleave={handleHoverClose}
104
- onfocusin={handleFocusOpen}
105
- onfocusout={handleFocusClose}
106
- >
107
- {@render children?.()}
108
- </span>
109
-
110
- {#if mounted}
130
+ {@render trigger?.(triggerProps)}
131
+
132
+ {#if label || tooltip}
111
133
  <div
134
+ bind:this={ref}
112
135
  id={tooltipId}
113
136
  popover="manual"
114
137
  role="tooltip"
115
- aria-label={label}
116
138
  class={attrs.class}
117
139
  style={attrs.style}
118
140
  data-density={density}
119
141
  data-variant={variant}
120
142
  data-rounded={rounded}
121
143
  use:floating={{
122
- anchor: triggerRef,
123
- open,
144
+ anchor,
145
+ open: open && !!anchor,
124
146
  side: location,
125
147
  align: 'center',
126
148
  offset: 6,
@@ -128,7 +150,7 @@
128
150
  }}
129
151
  {...attrs.rest}
130
152
  onmouseenter={clearTimer}
131
- onmouseleave={handleHoverClose}
153
+ onmouseleave={scheduleHide}
132
154
  >
133
155
  {#if tooltip}
134
156
  {@render tooltip()}
@@ -167,18 +189,6 @@
167
189
  --kit-tooltip-arrow: 0.35rem;
168
190
  }
169
191
 
170
- .kit-tooltip-trigger {
171
- display: inline-flex;
172
- align-self: start;
173
- justify-self: start;
174
- width: fit-content;
175
- max-width: max-content;
176
- }
177
- .kit-tooltip-trigger:focus-visible {
178
- outline: 2px solid var(--kit-color-focus);
179
- outline-offset: 2px;
180
- }
181
-
182
192
  .kit-tooltip {
183
193
  position: fixed;
184
194
  inset: auto;
@@ -307,4 +317,9 @@
307
317
  .kit-tooltip {
308
318
  animation: none;
309
319
  }
320
+ }
321
+ @media (forced-colors: active) {
322
+ .kit-tooltip {
323
+ border: 1px solid CanvasText;
324
+ }
310
325
  }</style>
@@ -1,4 +1,6 @@
1
- import type { TooltipProps } from './tooltip.types.ts';
2
- declare const Tooltip: import("svelte").Component<TooltipProps, {}, "ref" | "open">;
1
+ import type { TooltipProps, TooltipTriggerProps } from './tooltip.types.ts';
2
+ declare const Tooltip: import("svelte").Component<TooltipProps, {
3
+ triggerHandlers: () => TooltipTriggerProps;
4
+ }, "ref" | "open">;
3
5
  type Tooltip = ReturnType<typeof Tooltip>;
4
6
  export default Tooltip;
@@ -1,17 +1,43 @@
1
1
  import type { ColorProps, Component, RoundedType } from '../../@types';
2
2
  import type { Snippet } from 'svelte';
3
- export interface TooltipProps extends Component {
3
+ /** The attributes to spread on the element that shows the tooltip */
4
+ export interface TooltipTriggerProps {
5
+ 'aria-describedby'?: string;
6
+ 'aria-labelledby'?: string;
7
+ onpointerenter: (event: PointerEvent) => void;
8
+ onpointerleave: (event: PointerEvent) => void;
9
+ onpointerdown: (event: PointerEvent) => void;
10
+ onfocus: (event: FocusEvent) => void;
11
+ onblur: (event: FocusEvent) => void;
12
+ }
13
+ export interface TooltipProps extends Omit<Component, 'children'> {
4
14
  ref?: HTMLElement | null;
5
15
  open?: boolean;
6
- forceMount?: boolean;
7
16
  rounded?: RoundedType | 'full';
8
17
  label?: string;
18
+ /** the tooltip names the trigger (aria-labelledby) instead of describing it */
19
+ asLabel?: boolean;
9
20
  location?: 'top' | 'bottom' | 'left' | 'right';
10
21
  color?: ColorProps;
11
22
  delayDuration?: number;
23
+ closeDelay?: number;
12
24
  variant?: 'arrow';
13
25
  density?: 'dense' | 'compact' | 'default' | 'comfortable' | 'spacious';
14
26
  disabled?: boolean;
15
27
  avoidCollisions?: boolean;
28
+ trigger?: Snippet<[TooltipTriggerProps]>;
16
29
  tooltip?: Snippet;
30
+ /** removed in 0.8.0: use the trigger snippet */
31
+ children?: never;
32
+ }
33
+ /** The tooltip prop of kit:btn, kit:chip and kit:icon */
34
+ export interface TooltipOptions {
35
+ label: string;
36
+ location?: TooltipProps['location'];
37
+ variant?: TooltipProps['variant'];
38
+ density?: TooltipProps['density'];
39
+ rounded?: TooltipProps['rounded'];
40
+ delayDuration?: number;
41
+ closeDelay?: number;
17
42
  }
43
+ export type TooltipValue = string | TooltipOptions | null | undefined | false;
@@ -203,7 +203,7 @@ button.kit-sheet {
203
203
  color: var(--kit-sheet-pressed-fg, var(--kit-sheet-fg));
204
204
  }
205
205
 
206
- .kit-sheet:not([data-disabled=true]):focus-visible {
206
+ .kit-sheet:is(:not([data-disabled=true]), [data-disabled-focusable=true]):focus-visible {
207
207
  outline: 2px solid var(--kit-color-focus);
208
208
  outline-offset: 2px;
209
209
  }
@@ -214,6 +214,11 @@ button.kit-sheet {
214
214
  user-select: none;
215
215
  }
216
216
 
217
+ .kit-sheet[data-disabled-focusable=true] {
218
+ pointer-events: auto;
219
+ cursor: not-allowed;
220
+ }
221
+
217
222
  /**
218
223
  * rounded
219
224
  * @link https://lapikit.dev/docs/customize
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lapikit",
3
- "version": "0.7.9",
3
+ "version": "0.8.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"