lapikit 0.7.4 → 0.7.6

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.
@@ -4,8 +4,6 @@ export type AccordionOptions = {
4
4
  multiple?: boolean;
5
5
  readOnly?: boolean;
6
6
  };
7
- /**Modal */
8
- export type ModalState = boolean | 'persistent';
9
7
  /**Theme */
10
8
  export type ThemeOptions = {
11
9
  name?: string;
@@ -102,7 +102,7 @@
102
102
  type={type || 'button'}
103
103
  {checked}
104
104
  {value}
105
- aria-label={String(label || value)}
105
+ aria-label={label || (value != null ? String(value) : undefined)}
106
106
  disabled={isDisabled}
107
107
  />
108
108
  {:else}
@@ -1,5 +1,11 @@
1
1
  <script lang="ts">
2
- import { disabledScroll, splitAriaAttrs, useComponentAttrs, useElevation } from '../../utils';
2
+ import {
3
+ lockScroll,
4
+ splitAriaAttrs,
5
+ unlockScroll,
6
+ useComponentAttrs,
7
+ useElevation
8
+ } from '../../utils';
3
9
  import type { DialogProps } from './dialog.types.js';
4
10
 
5
11
  let {
@@ -48,12 +54,12 @@
48
54
  if (!open && ref.open) {
49
55
  ref.close();
50
56
  }
57
+ });
51
58
 
52
- disabledScroll(open);
53
-
54
- return () => {
55
- disabledScroll(false);
56
- };
59
+ $effect(() => {
60
+ if (!open) return;
61
+ lockScroll();
62
+ return unlockScroll;
57
63
  });
58
64
 
59
65
  function handleClose() {
@@ -1,7 +1,3 @@
1
- import type { ModalState } from '../../@types';
2
- import { type Writable } from 'svelte/store';
3
- export declare const modalOpen: Writable<ModalState>;
4
- export declare const modalStack: Writable<string[]>;
5
- export declare function setOpenModal(state: boolean | 'persistent'): void;
1
+ export declare const modalStack: import("svelte/store").Writable<string[]>;
6
2
  export declare const pushModal: (id: string) => void;
7
3
  export declare const popModal: (id: string) => void;
@@ -1,26 +1,8 @@
1
- import { disabledScroll } from '../../utils';
2
1
  import { writable } from 'svelte/store';
3
- // presets
4
- const refModal = false;
5
- // states
6
- export const modalOpen = writable(refModal);
7
2
  export const modalStack = writable([]);
8
- export function setOpenModal(state) {
9
- modalOpen.set(state);
10
- }
11
3
  export const pushModal = (id) => {
12
- modalStack.update((stack) => {
13
- let values = stack;
14
- if (!stack.includes(id))
15
- values = [...stack, id];
16
- disabledScroll(values.length !== 0 ? true : false);
17
- return values;
18
- });
4
+ modalStack.update((stack) => (stack.includes(id) ? stack : [...stack, id]));
19
5
  };
20
6
  export const popModal = (id) => {
21
- modalStack.update((stack) => {
22
- const newStack = stack.filter((m) => m !== id);
23
- disabledScroll(newStack.length !== 0 ? true : false);
24
- return newStack.length === 0 ? [] : newStack;
25
- });
7
+ modalStack.update((stack) => stack.filter((m) => m !== id));
26
8
  };
@@ -1,8 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { onDestroy } from 'svelte';
3
3
  import { get } from 'svelte/store';
4
- import { splitAriaAttrs, useComponentAttrs, useElevation } from '../../utils';
5
- import { modalOpen, modalStack, popModal, pushModal, setOpenModal } from './modal.js';
4
+ import { useComponentAttrs, useElevation } from '../../utils';
5
+ import { modalStack, popModal, pushModal } from './modal.js';
6
6
  import type { ModalProps } from './modal.types.js';
7
7
 
8
8
  const modalId = $props.id();
@@ -44,7 +44,6 @@
44
44
  )
45
45
  );
46
46
  let elevationState = $derived(useElevation(elevation));
47
- let split = $derived(splitAriaAttrs(attrs.rest));
48
47
 
49
48
  $effect(() => {
50
49
  if (open && !wasPushed) {
@@ -56,18 +55,6 @@
56
55
  }
57
56
  });
58
57
 
59
- $effect(() => {
60
- if (open !== undefined && !contain) {
61
- setOpenModal(open ? (persistent ? 'persistent' : true) : false);
62
- }
63
- });
64
-
65
- $effect(() => {
66
- if ($modalOpen === false && !contain) {
67
- open = false;
68
- }
69
- });
70
-
71
58
  $effect(() => {
72
59
  if (!open || !closeWithEsc || persistent) return;
73
60
 
@@ -94,16 +81,21 @@
94
81
  function handleClose() {
95
82
  if (!persistent) open = false;
96
83
  }
84
+
85
+ function show(node: HTMLDialogElement) {
86
+ node.show();
87
+ return {
88
+ destroy() {
89
+ node.close();
90
+ }
91
+ };
92
+ }
97
93
  </script>
98
94
 
99
95
  {#if open}
100
96
  <div
101
- bind:this={ref}
102
97
  class={attrs.class}
103
98
  style={attrs.style}
104
- role="dialog"
105
- aria-modal={!contain}
106
- {...split.aria}
107
99
  data-contain={contain}
108
100
  data-density={density}
109
101
  data-rounded={rounded}
@@ -112,18 +104,19 @@
112
104
  <div class="kit-modal__overlay" role="presentation" onclick={handleClose}></div>
113
105
  {/if}
114
106
 
115
- <div
116
- {...split.others}
107
+ <dialog
108
+ bind:this={ref}
109
+ use:show
110
+ {...attrs.rest}
117
111
  class={['kit-modal__content', classContent]}
118
112
  data-size={size}
119
113
  data-position={position}
120
114
  data-elevation={elevationState.base}
121
115
  data-elevation-hover={elevationState.hover}
122
116
  data-elevation-active={elevationState.active}
123
- onclick={(event: MouseEvent) => event.stopPropagation()}
124
117
  >
125
118
  {@render children?.()}
126
- </div>
119
+ </dialog>
127
120
  </div>
128
121
  {/if}
129
122
 
@@ -188,6 +181,7 @@
188
181
  }
189
182
  .kit-modal__content {
190
183
  position: fixed;
184
+ margin: 0;
191
185
  top: var(--kit-modal-top);
192
186
  right: var(--kit-modal-right);
193
187
  bottom: var(--kit-modal-bottom);
@@ -3,7 +3,7 @@ import type { ColorProps, Component, ElevationProps, RoundedType } from '../../@
3
3
  type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
4
4
  type ModalPosition = 'top' | 'center' | 'bottom' | 'top-left' | 'top-right' | 'center-left' | 'center-right' | 'bottom-left' | 'bottom-right';
5
5
  export interface ModalProps extends Component {
6
- ref?: HTMLDivElement | null;
6
+ ref?: HTMLDialogElement | null;
7
7
  open?: boolean;
8
8
  contain?: boolean;
9
9
  size?: ModalSize;
@@ -33,6 +33,7 @@
33
33
 
34
34
  let triggerRef = $state<HTMLElement | null>(null);
35
35
  let timer: ReturnType<typeof setTimeout> | null = null;
36
+ let focused = false;
36
37
  let mounted = $derived(open || forceMount || !!tooltip);
37
38
 
38
39
  const clearTimer = () => {
@@ -43,6 +44,7 @@
43
44
  const handleHoverOpen = () => {
44
45
  if (disabled) return;
45
46
  clearTimer();
47
+ if (open) return;
46
48
  timer = setTimeout(() => {
47
49
  open = true;
48
50
  timer = null;
@@ -51,6 +53,7 @@
51
53
 
52
54
  const handleFocusOpen = () => {
53
55
  if (disabled) return;
56
+ focused = true;
54
57
  clearTimer();
55
58
  open = true;
56
59
  };
@@ -60,6 +63,17 @@
60
63
  open = false;
61
64
  };
62
65
 
66
+ const handleHoverClose = () => {
67
+ clearTimer();
68
+ if (focused) return;
69
+ timer = setTimeout(handleClose, 100);
70
+ };
71
+
72
+ const handleFocusClose = () => {
73
+ focused = false;
74
+ handleClose();
75
+ };
76
+
63
77
  $effect(() => {
64
78
  if (disabled) open = false;
65
79
  });
@@ -68,6 +82,15 @@
68
82
  ref = triggerRef;
69
83
  });
70
84
 
85
+ $effect(() => {
86
+ if (!open) return;
87
+ const onKeyDown = (event: KeyboardEvent) => {
88
+ if (event.key === 'Escape') handleClose();
89
+ };
90
+ document.addEventListener('keydown', onKeyDown);
91
+ return () => document.removeEventListener('keydown', onKeyDown);
92
+ });
93
+
71
94
  onDestroy(clearTimer);
72
95
  </script>
73
96
 
@@ -77,10 +100,9 @@
77
100
  class="kit-tooltip-trigger"
78
101
  aria-describedby={open ? tooltipId : undefined}
79
102
  onmouseenter={handleHoverOpen}
80
- onmouseleave={handleClose}
103
+ onmouseleave={handleHoverClose}
81
104
  onfocusin={handleFocusOpen}
82
- onfocusout={handleClose}
83
- onkeydown={(event) => event.key === 'Escape' && handleClose()}
105
+ onfocusout={handleFocusClose}
84
106
  >
85
107
  {@render children?.()}
86
108
  </span>
@@ -105,6 +127,8 @@
105
127
  flip: avoidCollisions
106
128
  }}
107
129
  {...attrs.rest}
130
+ onmouseenter={clearTimer}
131
+ onmouseleave={handleHoverClose}
108
132
  >
109
133
  {#if tooltip}
110
134
  {@render tooltip()}
@@ -171,7 +195,6 @@
171
195
  color: var(--kit-tooltip-fg);
172
196
  font-size: 0.875rem;
173
197
  overflow-wrap: break-word;
174
- pointer-events: none;
175
198
  box-shadow: 0 16px 29px -10px color-mix(in oklab, var(--kit-color-shadow) 18%, transparent);
176
199
  animation: kit-tooltip-enter 150ms ease;
177
200
  }
package/dist/escaping.js CHANGED
@@ -93,7 +93,6 @@ export const decodeSourceMap = (content, componentInfo) => {
93
93
  // class: / style: are refused by Svelte on a component: they become s-class_ / s-style_ props
94
94
  parts.push(`<${info.name}${rewriteDirectives(content.slice(nameEnd, tagEnd + 1))}`);
95
95
  changed = true;
96
- changed = true;
97
96
  }
98
97
  else {
99
98
  parts.push(content.slice(nextLt, tagEnd + 1));
@@ -3,4 +3,6 @@ export declare function clickOutside(node: HTMLElement, options: ClickOutsideOpt
3
3
  update(newOptions: ClickOutsideOptions): void;
4
4
  destroy(): void;
5
5
  };
6
- export declare function disabledScroll(state: boolean): void;
6
+ /** Blocks the scroll of the page; each call needs its own unlockScroll() */
7
+ export declare function lockScroll(): void;
8
+ export declare function unlockScroll(): void;
@@ -32,8 +32,20 @@ export function clickOutside(node, options) {
32
32
  }
33
33
  };
34
34
  }
35
- export function disabledScroll(state) {
36
- if (typeof window !== 'undefined' && typeof document !== 'undefined') {
37
- document.body.style.overflow = state ? 'hidden' : '';
35
+ let scrollLocks = 0;
36
+ let previousOverflow = '';
37
+ /** Blocks the scroll of the page; each call needs its own unlockScroll() */
38
+ export function lockScroll() {
39
+ if (typeof document === 'undefined')
40
+ return;
41
+ if (scrollLocks++ === 0) {
42
+ previousOverflow = document.body.style.overflow;
43
+ document.body.style.overflow = 'hidden';
38
44
  }
39
45
  }
46
+ export function unlockScroll() {
47
+ if (typeof document === 'undefined' || scrollLocks === 0)
48
+ return;
49
+ if (--scrollLocks === 0)
50
+ document.body.style.overflow = previousOverflow;
51
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lapikit",
3
- "version": "0.7.4",
3
+ "version": "0.7.6",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -80,6 +80,9 @@
80
80
  "default": "./dist/hooks/actions.js"
81
81
  }
82
82
  },
83
+ "dependencies": {
84
+ "esm-env": "^1.2.2"
85
+ },
83
86
  "peerDependencies": {
84
87
  "svelte": "^5.20.0"
85
88
  },