@r2digisolutions/ui 0.20.1 → 0.21.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.
@@ -21,4 +21,10 @@ import Checkbox from './ui/Checkbox/Checkbox.svelte';
21
21
  import Badge from './ui/Badge/Badge.svelte';
22
22
  import NoContent from './ui/NoContent/NoContent.svelte';
23
23
  import Tag from './ui/Tag/Tag.svelte';
24
- export { Tag, NoContent, Alert, Avatar, Button, Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, Container, Checkbox, Field, Section, Loading, TableList, Heading, Label, Input, InputRadio, Textarea, };
24
+ import Dialog from './ui/Dialog/Dialog.svelte';
25
+ import DialogHeader from './ui/Dialog/DialogHeader.svelte';
26
+ import DialogTitle from './ui/Dialog/DialogTitle.svelte';
27
+ import DialogDescription from './ui/Dialog/DialogDescription.svelte';
28
+ import DialogContent from './ui/Dialog/DialogContent.svelte';
29
+ import DialogFooter from './ui/Dialog/DialogFooter.svelte';
30
+ export { Dialog, DialogHeader, DialogTitle, DialogDescription, DialogContent, DialogFooter, Tag, NoContent, Alert, Avatar, Button, Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, Container, Checkbox, Field, Section, Loading, TableList, Heading, Label, Input, InputRadio, Textarea, };
@@ -21,4 +21,10 @@ import Checkbox from './ui/Checkbox/Checkbox.svelte';
21
21
  import Badge from './ui/Badge/Badge.svelte';
22
22
  import NoContent from './ui/NoContent/NoContent.svelte';
23
23
  import Tag from './ui/Tag/Tag.svelte';
24
- export { Tag, NoContent, Alert, Avatar, Button, Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, Container, Checkbox, Field, Section, Loading, TableList, Heading, Label, Input, InputRadio, Textarea, };
24
+ import Dialog from './ui/Dialog/Dialog.svelte';
25
+ import DialogHeader from './ui/Dialog/DialogHeader.svelte';
26
+ import DialogTitle from './ui/Dialog/DialogTitle.svelte';
27
+ import DialogDescription from './ui/Dialog/DialogDescription.svelte';
28
+ import DialogContent from './ui/Dialog/DialogContent.svelte';
29
+ import DialogFooter from './ui/Dialog/DialogFooter.svelte';
30
+ export { Dialog, DialogHeader, DialogTitle, DialogDescription, DialogContent, DialogFooter, Tag, NoContent, Alert, Avatar, Button, Badge, Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, Container, Checkbox, Field, Section, Loading, TableList, Heading, Label, Input, InputRadio, Textarea, };
@@ -0,0 +1,85 @@
1
+ <script lang="ts">
2
+ import { fly } from 'svelte/transition';
3
+ import type { DialogProps } from './type.js';
4
+ import { createDialogContext } from './context.svelte';
5
+ import { tick } from 'svelte';
6
+
7
+ let {
8
+ open = $bindable(),
9
+ padding = 'md',
10
+ children,
11
+ header,
12
+ footer,
13
+ onclose,
14
+ size = 'lg',
15
+ onOpenChange,
16
+ closedby = 'any',
17
+ ...props
18
+ }: DialogProps = $props();
19
+
20
+ const cx = createDialogContext(() => open, { onOpenChange });
21
+
22
+ const _onclose = async () => {
23
+ open = false;
24
+ await tick();
25
+ onclose?.();
26
+ };
27
+
28
+ const paddings: Record<typeof padding, string> = {
29
+ none: 'p-0',
30
+ sm: 'md:p-4 p-4',
31
+ md: 'md:p-6 p-4',
32
+ lg: 'md:p-8 p-4'
33
+ };
34
+
35
+ const sizes: Record<typeof size, string> = {
36
+ auto: 'w-auto',
37
+ sm: 'w-full md:max-w-sm',
38
+ md: 'w-full md:max-w-md',
39
+ lg: 'w-full md:max-w-lg',
40
+ xl: 'w-full md:max-w-xl',
41
+ '2xl': 'w-full md:max-w-2xl',
42
+ '3xl': 'w-full md:max-w-3xl',
43
+ '4xl': 'w-full md:max-w-4xl',
44
+ '5xl': 'w-full md:max-w-5xl',
45
+ '6xl': 'w-full md:max-w-6xl',
46
+ '7xl': 'w-full md:max-w-7xl',
47
+ full: 'w-full md:max-w-full h-full md:h-full'
48
+ };
49
+
50
+ $effect(() => {
51
+ if (open) {
52
+ document.body.style.overflow = 'hidden';
53
+ } else {
54
+ document.body.style.overflow = 'auto';
55
+ }
56
+ });
57
+ </script>
58
+
59
+ {#if cx.open}
60
+ <dialog
61
+ {...props}
62
+ {closedby}
63
+ onclose={_onclose}
64
+ transition:fly={{ y: 100, duration: 200 }}
65
+ bind:this={cx.ref_dialog}
66
+ aria-modal="true"
67
+ class={[
68
+ 'fixed inset-0 flex h-full max-h-full w-full max-w-full flex-col gap-4 overflow-hidden bg-white shadow-lg duration-200 backdrop:bg-black/50 backdrop:backdrop-blur-xs md:m-auto md:h-fit dark:border-gray-600 dark:bg-gray-800',
69
+ props.class,
70
+ // paddings[padding],
71
+ sizes[size],
72
+ {
73
+ 'sm:rounded-lg': size !== 'full'
74
+ }
75
+ ]}
76
+ >
77
+ {#if header}
78
+ {@render header()}
79
+ {/if}
80
+ {@render children()}
81
+ {#if footer}
82
+ {@render footer()}
83
+ {/if}
84
+ </dialog>
85
+ {/if}
@@ -0,0 +1,4 @@
1
+ import type { DialogProps } from './type.js';
2
+ declare const Dialog: import("svelte").Component<DialogProps, {}, "open">;
3
+ type Dialog = ReturnType<typeof Dialog>;
4
+ export default Dialog;
@@ -0,0 +1,20 @@
1
+ <script lang="ts">
2
+ import type { DialogContentProps } from './type.js';
3
+
4
+ let { children, padding = 'md', onkeydown, ...props }: DialogContentProps = $props();
5
+
6
+ const paddings: Record<typeof padding, string> = {
7
+ none: 'p-0',
8
+ sm: 'md:px-4 px-4 pb-4',
9
+ md: 'md:px-6 px-4 pb-4',
10
+ lg: 'md:px-8 px-4 pb-4'
11
+ };
12
+ </script>
13
+
14
+ <section
15
+ {...props}
16
+ class={['flex flex-1 flex-col gap-2 overflow-auto', props.class, paddings[padding]]}
17
+ {onkeydown}
18
+ >
19
+ {@render children()}
20
+ </section>
@@ -0,0 +1,4 @@
1
+ import type { DialogContentProps } from './type.js';
2
+ declare const DialogContent: import("svelte").Component<DialogContentProps, {}, "">;
3
+ type DialogContent = ReturnType<typeof DialogContent>;
4
+ export default DialogContent;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ import type { DialogDescriptionProps } from './type.js';
3
+
4
+ const { children, ...props }: DialogDescriptionProps = $props();
5
+ </script>
6
+
7
+ <p class={['text-md text-center text-pretty sm:text-left dark:text-gray-300', props.class]}>
8
+ {@render children()}
9
+ </p>
@@ -0,0 +1,4 @@
1
+ import type { DialogDescriptionProps } from './type.js';
2
+ declare const DialogDescription: import("svelte").Component<DialogDescriptionProps, {}, "">;
3
+ type DialogDescription = ReturnType<typeof DialogDescription>;
4
+ export default DialogDescription;
@@ -0,0 +1,17 @@
1
+ <script lang="ts">
2
+ import type { DialogFooterProps } from './type.js';
3
+
4
+ let { children, position = 'start', ...props }: DialogFooterProps = $props();
5
+ </script>
6
+
7
+ <footer
8
+ class={[
9
+ 'flex gap-2 px-6 pb-6',
10
+ props.class,
11
+ position === 'start' && 'justify-start',
12
+ position === 'center' && 'justify-center',
13
+ position === 'end' && 'justify-end'
14
+ ]}
15
+ >
16
+ {@render children()}
17
+ </footer>
@@ -0,0 +1,4 @@
1
+ import type { DialogFooterProps } from './type.js';
2
+ declare const DialogFooter: import("svelte").Component<DialogFooterProps, {}, "">;
3
+ type DialogFooter = ReturnType<typeof DialogFooter>;
4
+ export default DialogFooter;
@@ -0,0 +1,19 @@
1
+ <script lang="ts">
2
+ import { X } from 'lucide-svelte';
3
+ import type { DialogPropsgHeaderProps } from './type.js';
4
+
5
+ let { children, ...props }: DialogPropsgHeaderProps = $props();
6
+ </script>
7
+
8
+ <header class={['flex flex-col px-6 text-center sm:text-left', props.class, children && 'pt-6']}>
9
+ {@render children?.()}
10
+ <form method="dialog" class="absolute top-0 right-0">
11
+ <button
12
+ type="submit"
13
+ class="cursor-pointer p-2 text-gray-400 hover:text-gray-500 focus:outline-none"
14
+ aria-label="Close"
15
+ >
16
+ <X class="h-6 w-6" />
17
+ </button>
18
+ </form>
19
+ </header>
@@ -0,0 +1,4 @@
1
+ import type { DialogPropsgHeaderProps } from './type.js';
2
+ declare const DialogHeader: import("svelte").Component<DialogPropsgHeaderProps, {}, "">;
3
+ type DialogHeader = ReturnType<typeof DialogHeader>;
4
+ export default DialogHeader;
@@ -0,0 +1,9 @@
1
+ <script lang="ts">
2
+ import type { DialogTitleProps } from './type.js';
3
+
4
+ const { children, ...props }: DialogTitleProps = $props();
5
+ </script>
6
+
7
+ <h2 class={['text-center text-2xl font-bold sm:text-left dark:text-white', props.class]}>
8
+ {@render children()}
9
+ </h2>
@@ -0,0 +1,4 @@
1
+ import type { DialogTitleProps } from './type.js';
2
+ declare const DialogTitle: import("svelte").Component<DialogTitleProps, {}, "">;
3
+ type DialogTitle = ReturnType<typeof DialogTitle>;
4
+ export default DialogTitle;
@@ -0,0 +1,9 @@
1
+ export declare class ModalContext {
2
+ #private;
3
+ constructor(initialOpen?: boolean);
4
+ onclose(): void;
5
+ get open(): boolean;
6
+ set open(value: boolean);
7
+ get ref_dialog(): HTMLDialogElement | undefined;
8
+ set ref_dialog(value: HTMLDialogElement | undefined);
9
+ }
@@ -0,0 +1,34 @@
1
+ export class ModalContext {
2
+ #open = $state(false);
3
+ #ref_dialog = $state();
4
+ constructor(initialOpen = false) {
5
+ this.#open = initialOpen;
6
+ $effect(() => {
7
+ if (this.#open) {
8
+ this.#ref_dialog?.showModal();
9
+ }
10
+ else {
11
+ this.#ref_dialog?.close();
12
+ }
13
+ });
14
+ }
15
+ onclose() {
16
+ this.#open = false;
17
+ this.#ref_dialog?.close();
18
+ }
19
+ get open() {
20
+ return this.#open;
21
+ }
22
+ set open(value) {
23
+ this.#open = value;
24
+ }
25
+ get ref_dialog() {
26
+ return this.#ref_dialog;
27
+ }
28
+ set ref_dialog(value) {
29
+ this.#ref_dialog = value;
30
+ if (value) {
31
+ value.showModal();
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,7 @@
1
+ import { ModalContext } from './ModalContext.svelte';
2
+ export declare const KEY: unique symbol;
3
+ export interface DialogActions {
4
+ onOpenChange?(open: boolean): void;
5
+ }
6
+ export declare function createDialogContext(fn_open: any, actions?: DialogActions): ModalContext;
7
+ export declare function useDialogContext(): ModalContext;
@@ -0,0 +1,19 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ import { ModalContext } from './ModalContext.svelte';
3
+ export const KEY = Symbol('Dialog');
4
+ export function createDialogContext(fn_open, actions = {}) {
5
+ const context = new ModalContext(fn_open());
6
+ setContext(KEY, context);
7
+ $effect(() => {
8
+ context.open = fn_open();
9
+ actions.onOpenChange?.(context.open);
10
+ return () => {
11
+ context.open = false;
12
+ actions.onOpenChange?.(context.open);
13
+ };
14
+ });
15
+ return context;
16
+ }
17
+ export function useDialogContext() {
18
+ return getContext(KEY);
19
+ }
@@ -0,0 +1,39 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ export interface DialogProps {
4
+ closedby?: 'none' | 'closerequest' | 'any';
5
+ size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | '6xl' | '7xl' | 'full' | 'auto';
6
+ padding?: 'none' | 'sm' | 'md' | 'lg';
7
+ class?: ClassValue;
8
+ children: Snippet;
9
+ open?: boolean;
10
+ header?: Snippet;
11
+ footer?: Snippet;
12
+ onclose?(): void;
13
+ onpointermove?(e: PointerEvent): void;
14
+ onOpenChange?(open: boolean): void;
15
+ }
16
+ export interface DialogPropsgHeaderProps {
17
+ children?: Snippet;
18
+ class?: ClassValue;
19
+ }
20
+ export interface DialogTitleProps {
21
+ class?: ClassValue;
22
+ children: Snippet;
23
+ }
24
+ export interface DialogDescriptionProps {
25
+ class?: ClassValue;
26
+ children: Snippet;
27
+ }
28
+ export interface DialogFooterProps {
29
+ position?: 'start' | 'center' | 'end';
30
+ class?: ClassValue;
31
+ children: Snippet;
32
+ }
33
+ export interface DialogContentProps {
34
+ onkeydown?(e: KeyboardEvent): void;
35
+ padding?: DialogProps['padding'];
36
+ class?: ClassValue;
37
+ children: Snippet;
38
+ [key: string]: any;
39
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@r2digisolutions/ui",
3
- "version": "0.20.1",
3
+ "version": "0.21.0",
4
4
  "private": false,
5
5
  "packageManager": "bun@1.2.19",
6
6
  "publishConfig": {