lapikit 0.4.10 → 0.4.11

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,6 +4,8 @@ const lapikitComponents = [
4
4
  'btn',
5
5
  'icon',
6
6
  'avatar',
7
+ 'dialog',
8
+ 'modal',
7
9
  'accordion',
8
10
  'accordionItem',
9
11
  'alert',
@@ -0,0 +1,262 @@
1
+ <script lang="ts">
2
+ import { disabledScroll } from '../../../internal/helpers/scroll.js';
3
+ import { makeComponentProps } from '../../compiler/mapped-code.js';
4
+ import { useClassName, useStyles } from '../../utils/index.js';
5
+ import type { DialogDensity, DialogPosition, DialogProps, DialogSize } from './dialog.types.js';
6
+
7
+ function resolveSize(value: DialogSize | undefined): DialogSize {
8
+ return value === 'xs' || value === 'sm' || value === 'md' || value === 'lg' || value === 'xl'
9
+ ? value
10
+ : 'md';
11
+ }
12
+
13
+ function resolvePosition(value: DialogPosition | undefined): DialogPosition {
14
+ return value === 'top' || value === 'center' || value === 'bottom' ? value : 'center';
15
+ }
16
+
17
+ function resolveDensity(value: DialogDensity | undefined): DialogDensity {
18
+ return value === 'compact' || value === 'comfortable' || value === 'default'
19
+ ? value
20
+ : 'default';
21
+ }
22
+
23
+ let {
24
+ ref = $bindable(),
25
+ children = undefined,
26
+ class: className = '',
27
+ style: styleAttr = '',
28
+ 's-class': sClass,
29
+ 's-style': sStyle,
30
+ open = $bindable(false),
31
+ persistent = false,
32
+ size = 'md',
33
+ position = 'center',
34
+ density = 'default',
35
+ rounded = 'md',
36
+ classContent = '',
37
+ color = undefined,
38
+ background = undefined,
39
+ ...rest
40
+ }: DialogProps = $props();
41
+
42
+ let { classProps, styleProps, restProps } = $derived(
43
+ makeComponentProps(rest as Record<string, unknown>)
44
+ );
45
+
46
+ let componentClass = $derived(
47
+ useClassName({
48
+ baseClass: 'kit-dialog',
49
+ className: `${className ?? ''}`.trim(),
50
+ sClass,
51
+ classProps
52
+ })
53
+ );
54
+
55
+ let componentStyle = $derived(
56
+ useStyles({
57
+ styleAttr,
58
+ sStyle,
59
+ styleProps
60
+ })
61
+ );
62
+
63
+ let contentClass = $derived(
64
+ Array.isArray(classContent)
65
+ ? classContent.filter(Boolean).join(' ')
66
+ : `${classContent ?? ''}`.trim()
67
+ );
68
+
69
+ let safeSize = $derived(resolveSize(size));
70
+ let safePosition = $derived(resolvePosition(position));
71
+ let safeDensity = $derived(resolveDensity(density));
72
+ let mergedStyle = $derived(
73
+ [
74
+ componentStyle,
75
+ color ? `--kit-dialog-fg:${color}` : '',
76
+ background ? `--kit-dialog-bg:${background}` : ''
77
+ ]
78
+ .filter(Boolean)
79
+ .join('; ')
80
+ );
81
+
82
+ $effect(() => {
83
+ if (!ref) return;
84
+
85
+ if (open && !ref.open) {
86
+ ref.showModal();
87
+ }
88
+
89
+ if (!open && ref.open) {
90
+ ref.close();
91
+ }
92
+
93
+ disabledScroll(open);
94
+
95
+ return () => {
96
+ disabledScroll(false);
97
+ };
98
+ });
99
+
100
+ function handleClose() {
101
+ if (!persistent) {
102
+ open = false;
103
+ return;
104
+ }
105
+
106
+ if (ref && !ref.open && open) {
107
+ ref.showModal();
108
+ }
109
+ }
110
+
111
+ function handleCancel(event: Event) {
112
+ if (persistent) {
113
+ event.preventDefault();
114
+ return;
115
+ }
116
+
117
+ open = false;
118
+ }
119
+
120
+ function handleBackdropClick(event: MouseEvent) {
121
+ if (event.target !== ref || persistent) return;
122
+ open = false;
123
+ }
124
+ </script>
125
+
126
+ <dialog
127
+ bind:this={ref}
128
+ class={componentClass}
129
+ style={mergedStyle}
130
+ data-size={safeSize}
131
+ data-position={safePosition}
132
+ data-persistent={persistent}
133
+ onclose={handleClose}
134
+ oncancel={handleCancel}
135
+ onclick={handleBackdropClick}
136
+ >
137
+ <div
138
+ {...restProps}
139
+ class={['kit-dialog__content', contentClass]}
140
+ data-density={safeDensity}
141
+ data-rounded={rounded}
142
+ onclick={(event: MouseEvent) => event.stopPropagation()}
143
+ >
144
+ {@render children?.()}
145
+ </div>
146
+ </dialog>
147
+
148
+ <style>
149
+ .kit-dialog {
150
+ --kit-dialog-bg: var(--kit-surface-1);
151
+ --kit-dialog-fg: var(--kit-fg);
152
+ --kit-dialog-bd: var(--kit-border);
153
+ --kit-dialog-radius: 12px;
154
+ --kit-dialog-px: 1rem;
155
+ --kit-dialog-py: 1rem;
156
+ --kit-dialog-max: min(32rem, calc(100vw - 2rem));
157
+
158
+ border: 0;
159
+ padding: 0;
160
+ margin: auto;
161
+ width: 100%;
162
+ max-width: none;
163
+ background: transparent;
164
+ color: inherit;
165
+ overflow: visible;
166
+ }
167
+
168
+ .kit-dialog::backdrop {
169
+ background: rgb(15 23 42 / 0.42);
170
+ backdrop-filter: blur(2px);
171
+ }
172
+
173
+ .kit-dialog[data-position='top'] {
174
+ margin-top: 1rem;
175
+ margin-bottom: auto;
176
+ }
177
+
178
+ .kit-dialog[data-position='center'] {
179
+ margin-top: auto;
180
+ margin-bottom: auto;
181
+ }
182
+
183
+ .kit-dialog[data-position='bottom'] {
184
+ margin-top: auto;
185
+ margin-bottom: 1rem;
186
+ }
187
+
188
+ .kit-dialog[data-size='xs'] {
189
+ --kit-dialog-max: min(20rem, calc(100vw - 2rem));
190
+ }
191
+
192
+ .kit-dialog[data-size='sm'] {
193
+ --kit-dialog-max: min(24rem, calc(100vw - 2rem));
194
+ }
195
+
196
+ .kit-dialog[data-size='md'] {
197
+ --kit-dialog-max: min(32rem, calc(100vw - 2rem));
198
+ }
199
+
200
+ .kit-dialog[data-size='lg'] {
201
+ --kit-dialog-max: min(42rem, calc(100vw - 2rem));
202
+ }
203
+
204
+ .kit-dialog[data-size='xl'] {
205
+ --kit-dialog-max: min(56rem, calc(100vw - 2rem));
206
+ }
207
+
208
+ .kit-dialog__content {
209
+ box-sizing: border-box;
210
+ width: min(100%, var(--kit-dialog-max));
211
+ max-height: calc(100dvh - 2rem);
212
+ overflow: auto;
213
+ padding: var(--kit-dialog-py) var(--kit-dialog-px);
214
+ border: 1px solid var(--kit-dialog-bd);
215
+ border-radius: var(--kit-dialog-radius);
216
+ background: var(--kit-dialog-bg);
217
+ color: var(--kit-dialog-fg);
218
+ margin: 0 auto;
219
+ box-shadow:
220
+ 0 20px 50px rgb(15 23 42 / 0.18),
221
+ 0 4px 16px rgb(15 23 42 / 0.1);
222
+ }
223
+
224
+ .kit-dialog__content[data-density='compact'] {
225
+ --kit-dialog-px: 0.75rem;
226
+ --kit-dialog-py: 0.75rem;
227
+ }
228
+
229
+ .kit-dialog__content[data-density='default'] {
230
+ --kit-dialog-px: 1rem;
231
+ --kit-dialog-py: 1rem;
232
+ }
233
+
234
+ .kit-dialog__content[data-density='comfortable'] {
235
+ --kit-dialog-px: 1.25rem;
236
+ --kit-dialog-py: 1.25rem;
237
+ }
238
+
239
+ .kit-dialog__content[data-rounded='0'] {
240
+ --kit-dialog-radius: 0;
241
+ }
242
+
243
+ .kit-dialog__content[data-rounded='xs'] {
244
+ --kit-dialog-radius: 2px;
245
+ }
246
+
247
+ .kit-dialog__content[data-rounded='sm'] {
248
+ --kit-dialog-radius: 6px;
249
+ }
250
+
251
+ .kit-dialog__content[data-rounded='md'] {
252
+ --kit-dialog-radius: 12px;
253
+ }
254
+
255
+ .kit-dialog__content[data-rounded='lg'] {
256
+ --kit-dialog-radius: 18px;
257
+ }
258
+
259
+ .kit-dialog__content[data-rounded='xl'] {
260
+ --kit-dialog-radius: 9999px;
261
+ }
262
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { DialogProps } from './dialog.types.ts';
2
+ declare const Dialog: import("svelte").Component<DialogProps, {}, "ref" | "open">;
3
+ type Dialog = ReturnType<typeof Dialog>;
4
+ export default Dialog;
@@ -0,0 +1,16 @@
1
+ import type { Component, RoundedType } from '../../utils/types/index.js';
2
+ export type DialogSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
3
+ export type DialogPosition = 'top' | 'center' | 'bottom';
4
+ export type DialogDensity = 'compact' | 'comfortable' | 'default';
5
+ export interface DialogProps extends Component {
6
+ ref?: HTMLDialogElement | null;
7
+ open?: boolean;
8
+ persistent?: boolean;
9
+ size?: DialogSize;
10
+ position?: DialogPosition;
11
+ density?: DialogDensity;
12
+ rounded?: RoundedType;
13
+ classContent?: string | string[] | undefined;
14
+ color?: string;
15
+ background?: string;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -5,6 +5,8 @@ export { default as KitIcon } from './icon/icon.svelte';
5
5
  export { default as KitCard } from './card/card.svelte';
6
6
  export { default as KitChip } from './chip/chip.svelte';
7
7
  export { default as KitAvatar } from './avatar/avatar.svelte';
8
+ export { default as KitDialog } from './dialog/dialog.svelte';
9
+ export { default as KitModal } from './modal/modal.svelte';
8
10
  export { default as KitAccordion } from './accordion/accordion.svelte';
9
11
  export { default as KitAccordionItem } from './accordion/modules/accordion-item.svelte';
10
12
  export { default as KitAlert } from './alert/alert.svelte';
@@ -6,6 +6,8 @@ export { default as KitIcon } from './icon/icon.svelte';
6
6
  export { default as KitCard } from './card/card.svelte';
7
7
  export { default as KitChip } from './chip/chip.svelte';
8
8
  export { default as KitAvatar } from './avatar/avatar.svelte';
9
+ export { default as KitDialog } from './dialog/dialog.svelte';
10
+ export { default as KitModal } from './modal/modal.svelte';
9
11
  export { default as KitAccordion } from './accordion/accordion.svelte';
10
12
  export { default as KitAccordionItem } from './accordion/modules/accordion-item.svelte';
11
13
  export { default as KitAlert } from './alert/alert.svelte';
@@ -0,0 +1,317 @@
1
+ <script lang="ts">
2
+ import { onDestroy } from 'svelte';
3
+ import { get } from 'svelte/store';
4
+ import { makeComponentProps } from '../../compiler/mapped-code.js';
5
+ import { useClassName, useStyles } from '../../utils/index.js';
6
+ import { modalOpen, modalStack, popModal, pushModal, setOpenModal } from '../../../stores/index.js';
7
+ import type { ModalDensity, ModalPosition, ModalProps, ModalSize } from './modal.types.js';
8
+
9
+ function resolveSize(value: ModalSize | undefined): ModalSize {
10
+ return value === 'xs' ||
11
+ value === 'sm' ||
12
+ value === 'md' ||
13
+ value === 'lg' ||
14
+ value === 'xl' ||
15
+ value === 'full'
16
+ ? value
17
+ : 'md';
18
+ }
19
+
20
+ function resolvePosition(value: ModalPosition | undefined): ModalPosition {
21
+ return value === 'top' || value === 'center' || value === 'bottom' ? value : 'center';
22
+ }
23
+
24
+ function resolveDensity(value: ModalDensity | undefined): ModalDensity {
25
+ return value === 'compact' || value === 'comfortable' || value === 'default'
26
+ ? value
27
+ : 'default';
28
+ }
29
+
30
+ const modalId = crypto.randomUUID();
31
+ let wasPushed = $state(false);
32
+
33
+ let {
34
+ ref = $bindable(),
35
+ children = undefined,
36
+ class: className = '',
37
+ style: styleAttr = '',
38
+ 's-class': sClass,
39
+ 's-style': sStyle,
40
+ open = $bindable(false),
41
+ contain = false,
42
+ size = 'md',
43
+ persistent = false,
44
+ position = 'center',
45
+ rounded = 'md',
46
+ density = 'default',
47
+ classContent = '',
48
+ color = undefined,
49
+ background = undefined,
50
+ closeWithEsc = true,
51
+ ...rest
52
+ }: ModalProps = $props();
53
+
54
+ let { classProps, styleProps, restProps } = $derived(
55
+ makeComponentProps(rest as Record<string, unknown>)
56
+ );
57
+
58
+ let componentClass = $derived(
59
+ useClassName({
60
+ baseClass: 'kit-modal',
61
+ className: `${className ?? ''}`.trim(),
62
+ sClass,
63
+ classProps
64
+ })
65
+ );
66
+
67
+ let componentStyle = $derived(
68
+ useStyles({
69
+ styleAttr,
70
+ sStyle,
71
+ styleProps
72
+ })
73
+ );
74
+
75
+ let contentClass = $derived(
76
+ Array.isArray(classContent)
77
+ ? classContent.filter(Boolean).join(' ')
78
+ : `${classContent ?? ''}`.trim()
79
+ );
80
+
81
+ let safeSize = $derived(resolveSize(size));
82
+ let safePosition = $derived(resolvePosition(position));
83
+ let safeDensity = $derived(resolveDensity(density));
84
+ let mergedStyle = $derived(
85
+ [
86
+ componentStyle,
87
+ color ? `--kit-modal-fg:${color}` : '',
88
+ background ? `--kit-modal-bg:${background}` : ''
89
+ ]
90
+ .filter(Boolean)
91
+ .join('; ')
92
+ );
93
+
94
+ $effect(() => {
95
+ if (open && !wasPushed) {
96
+ pushModal(modalId);
97
+ wasPushed = true;
98
+ } else if (!open && wasPushed) {
99
+ popModal(modalId);
100
+ wasPushed = false;
101
+ }
102
+ });
103
+
104
+ $effect(() => {
105
+ if (open !== undefined && !contain) {
106
+ setOpenModal(open ? (persistent ? 'persistent' : true) : false);
107
+ }
108
+ });
109
+
110
+ $effect(() => {
111
+ if ($modalOpen === false && !contain) {
112
+ open = false;
113
+ }
114
+ });
115
+
116
+ $effect(() => {
117
+ if (!open || !closeWithEsc || persistent) return;
118
+
119
+ const onKeyDown = (event: KeyboardEvent) => {
120
+ const stack = get(modalStack);
121
+ const isTop = stack[stack.length - 1] === modalId;
122
+
123
+ if (event.key === 'Escape' && isTop) {
124
+ event.preventDefault();
125
+ open = false;
126
+ }
127
+ };
128
+
129
+ document.addEventListener('keydown', onKeyDown);
130
+ return () => {
131
+ document.removeEventListener('keydown', onKeyDown);
132
+ };
133
+ });
134
+
135
+ onDestroy(() => {
136
+ if (wasPushed) popModal(modalId);
137
+ });
138
+
139
+ function handleClose() {
140
+ if (!persistent) open = false;
141
+ }
142
+ </script>
143
+
144
+ {#if open}
145
+ <div
146
+ bind:this={ref}
147
+ class={componentClass}
148
+ style={mergedStyle}
149
+ role="dialog"
150
+ aria-modal={!contain}
151
+ data-contain={contain}
152
+ >
153
+ {#if contain}
154
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
155
+ <div class="kit-modal__overlay" onclick={handleClose}></div>
156
+ {/if}
157
+
158
+ <div
159
+ {...restProps}
160
+ class={['kit-modal__content', contentClass]}
161
+ data-size={safeSize}
162
+ data-position={safePosition}
163
+ data-density={safeDensity}
164
+ data-rounded={rounded}
165
+ onclick={(event: MouseEvent) => event.stopPropagation()}
166
+ >
167
+ {@render children?.()}
168
+ </div>
169
+ </div>
170
+ {/if}
171
+
172
+ <style>
173
+ .kit-modal {
174
+ --kit-modal-bg: var(--kit-surface-1);
175
+ --kit-modal-fg: var(--kit-fg);
176
+ --kit-modal-bd: var(--kit-border);
177
+ --kit-modal-radius: 12px;
178
+ --kit-modal-px: 1rem;
179
+ --kit-modal-py: 1rem;
180
+ --kit-modal-max: min(32rem, calc(100vw - 2rem));
181
+ --kit-modal-top: 50%;
182
+ --kit-modal-bottom: auto;
183
+ --kit-modal-translate-y: -50%;
184
+
185
+ position: fixed;
186
+ inset: 0;
187
+ z-index: 9100;
188
+ pointer-events: none;
189
+ }
190
+
191
+ .kit-modal[data-contain='true'] {
192
+ position: absolute;
193
+ }
194
+
195
+ .kit-modal__overlay {
196
+ position: absolute;
197
+ inset: 0;
198
+ background: rgb(15 23 42 / 0.42);
199
+ backdrop-filter: blur(2px);
200
+ pointer-events: auto;
201
+ }
202
+
203
+ .kit-modal__content {
204
+ position: fixed;
205
+ left: 50%;
206
+ top: var(--kit-modal-top);
207
+ bottom: var(--kit-modal-bottom);
208
+ translate: -50% var(--kit-modal-translate-y);
209
+ box-sizing: border-box;
210
+ width: min(calc(100vw - 2rem), var(--kit-modal-max));
211
+ max-height: calc(100dvh - 2rem);
212
+ overflow: auto;
213
+ padding: var(--kit-modal-py) var(--kit-modal-px);
214
+ border: 1px solid var(--kit-modal-bd);
215
+ border-radius: var(--kit-modal-radius);
216
+ background: var(--kit-modal-bg);
217
+ color: var(--kit-modal-fg);
218
+ box-shadow:
219
+ 0 20px 50px rgb(15 23 42 / 0.18),
220
+ 0 4px 16px rgb(15 23 42 / 0.1);
221
+ pointer-events: auto;
222
+ }
223
+
224
+ .kit-modal[data-contain='true'] .kit-modal__content {
225
+ position: absolute;
226
+ }
227
+
228
+ .kit-modal__content[data-size='xs'] {
229
+ --kit-modal-max: min(20rem, calc(100vw - 2rem));
230
+ }
231
+
232
+ .kit-modal__content[data-size='sm'] {
233
+ --kit-modal-max: min(24rem, calc(100vw - 2rem));
234
+ }
235
+
236
+ .kit-modal__content[data-size='md'] {
237
+ --kit-modal-max: min(32rem, calc(100vw - 2rem));
238
+ }
239
+
240
+ .kit-modal__content[data-size='lg'] {
241
+ --kit-modal-max: min(42rem, calc(100vw - 2rem));
242
+ }
243
+
244
+ .kit-modal__content[data-size='xl'] {
245
+ --kit-modal-max: min(56rem, calc(100vw - 2rem));
246
+ }
247
+
248
+ .kit-modal__content[data-size='full'] {
249
+ top: auto;
250
+ bottom: 0;
251
+ left: 0;
252
+ translate: 0 0;
253
+ width: 100%;
254
+ max-width: 100%;
255
+ max-height: 100dvh;
256
+ height: min(100dvh, 100%);
257
+ border-bottom-left-radius: 0;
258
+ border-bottom-right-radius: 0;
259
+ }
260
+
261
+ .kit-modal__content[data-position='top'] {
262
+ --kit-modal-top: 1rem;
263
+ --kit-modal-bottom: auto;
264
+ --kit-modal-translate-y: 0;
265
+ }
266
+
267
+ .kit-modal__content[data-position='center'] {
268
+ --kit-modal-top: 50%;
269
+ --kit-modal-bottom: auto;
270
+ --kit-modal-translate-y: -50%;
271
+ }
272
+
273
+ .kit-modal__content[data-position='bottom'] {
274
+ --kit-modal-top: auto;
275
+ --kit-modal-bottom: 1rem;
276
+ --kit-modal-translate-y: 0;
277
+ }
278
+
279
+ .kit-modal__content[data-density='compact'] {
280
+ --kit-modal-px: 0.75rem;
281
+ --kit-modal-py: 0.75rem;
282
+ }
283
+
284
+ .kit-modal__content[data-density='default'] {
285
+ --kit-modal-px: 1rem;
286
+ --kit-modal-py: 1rem;
287
+ }
288
+
289
+ .kit-modal__content[data-density='comfortable'] {
290
+ --kit-modal-px: 1.25rem;
291
+ --kit-modal-py: 1.25rem;
292
+ }
293
+
294
+ .kit-modal__content[data-rounded='0'] {
295
+ --kit-modal-radius: 0;
296
+ }
297
+
298
+ .kit-modal__content[data-rounded='xs'] {
299
+ --kit-modal-radius: 2px;
300
+ }
301
+
302
+ .kit-modal__content[data-rounded='sm'] {
303
+ --kit-modal-radius: 6px;
304
+ }
305
+
306
+ .kit-modal__content[data-rounded='md'] {
307
+ --kit-modal-radius: 12px;
308
+ }
309
+
310
+ .kit-modal__content[data-rounded='lg'] {
311
+ --kit-modal-radius: 18px;
312
+ }
313
+
314
+ .kit-modal__content[data-rounded='xl'] {
315
+ --kit-modal-radius: 9999px;
316
+ }
317
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ModalProps } from './modal.types.ts';
2
+ declare const Modal: import("svelte").Component<ModalProps, {}, "ref" | "open">;
3
+ type Modal = ReturnType<typeof Modal>;
4
+ export default Modal;
@@ -0,0 +1,18 @@
1
+ import type { Component, RoundedType } from '../../utils/types/index.js';
2
+ export type ModalSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
3
+ export type ModalPosition = 'top' | 'center' | 'bottom';
4
+ export type ModalDensity = 'compact' | 'comfortable' | 'default';
5
+ export interface ModalProps extends Component {
6
+ ref?: HTMLDivElement | null;
7
+ open?: boolean;
8
+ contain?: boolean;
9
+ size?: ModalSize;
10
+ persistent?: boolean;
11
+ position?: ModalPosition;
12
+ rounded?: RoundedType;
13
+ density?: ModalDensity;
14
+ classContent?: string | string[] | undefined;
15
+ color?: string;
16
+ background?: string;
17
+ closeWithEsc?: boolean;
18
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lapikit",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"