fuma 2.1.6 → 2.5.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.
- package/dist/_doc/data.d.ts +3 -1
- package/dist/_doc/data.js +6 -2
- package/dist/command/index.d.ts +1 -1
- package/dist/command/index.js +1 -1
- package/dist/command/{command.svelte.js → useCommand.svelte.js} +1 -1
- package/dist/input/InputBoolean.svelte +41 -8
- package/dist/input/InputBoolean.svelte.d.ts +7 -0
- package/dist/input/InputCheckboxes.svelte +123 -0
- package/dist/input/InputCheckboxes.svelte.d.ts +19 -0
- package/dist/input/InputDateTime.svelte +199 -0
- package/dist/input/InputDateTime.svelte.d.ts +26 -0
- package/dist/input/InputMultiSelect.svelte +324 -0
- package/dist/input/{InputRelation.svelte.d.ts → InputMultiSelect.svelte.d.ts} +32 -13
- package/dist/input/InputNumber.svelte +43 -6
- package/dist/input/InputNumber.svelte.d.ts +8 -0
- package/dist/input/InputRadio.svelte +62 -24
- package/dist/input/InputRadio.svelte.d.ts +3 -0
- package/dist/input/InputRange.svelte +24 -4
- package/dist/input/InputRange.svelte.d.ts +9 -0
- package/dist/input/InputSelect.svelte +216 -62
- package/dist/input/InputSelect.svelte.d.ts +91 -6
- package/dist/input/InputSelectNative.svelte +51 -19
- package/dist/input/InputSelectNative.svelte.d.ts +8 -0
- package/dist/input/InputString.svelte +21 -6
- package/dist/input/InputString.svelte.d.ts +7 -0
- package/dist/input/InputTextarea.svelte +58 -11
- package/dist/input/InputTextarea.svelte.d.ts +14 -0
- package/dist/input/index.d.ts +4 -1
- package/dist/input/index.js +4 -1
- package/dist/input/useItems.svelte.d.ts +38 -0
- package/dist/input/useItems.svelte.js +142 -0
- package/dist/loading/Loading.svelte +3 -2
- package/dist/loading/Loading.svelte.d.ts +3 -2
- package/dist/popover/Popover.svelte +1 -2
- package/dist/popover/Popover.svelte.d.ts +13 -0
- package/dist/popover/index.d.ts +1 -1
- package/dist/popover/index.js +1 -1
- package/dist/popover/{popover.svelte.d.ts → usePopover.svelte.d.ts} +2 -1
- package/dist/popover/usePopover.svelte.js +145 -0
- package/dist/remote/useForm.d.ts +4 -5
- package/dist/remote/useForm.js +9 -4
- package/dist/state/index.d.ts +1 -1
- package/dist/state/index.js +1 -1
- package/dist/ui/button/ButtonDelete.svelte +6 -3
- package/dist/ui/button/ButtonDelete.svelte.d.ts +1 -1
- package/dist/ui/dialog/Dialog.svelte +5 -5
- package/dist/ui/drawer/Drawer.svelte +74 -26
- package/dist/ui/drawer/Drawer.svelte.d.ts +10 -4
- package/dist/ui/drawer/index.d.ts +1 -0
- package/dist/ui/drawer/index.js +1 -0
- package/dist/ui/drawer/inertBackground.d.ts +13 -0
- package/dist/ui/drawer/inertBackground.js +59 -0
- package/dist/ui/drawer/useLayer.svelte.d.ts +1 -1
- package/dist/ui/drawer/useLayer.svelte.js +11 -7
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/menu/ContextMenu.svelte +30 -17
- package/dist/ui/menu/ContextMenu.svelte.d.ts +2 -3
- package/dist/ui/menu/DropDown.svelte +1 -1
- package/dist/ui/menu/DropDown.svelte.d.ts +1 -1
- package/dist/ui/menu/DropDownMenu.svelte +12 -10
- package/dist/ui/menu/DropDownMenu.svelte.d.ts +2 -3
- package/dist/ui/menu/index.d.ts +0 -1
- package/dist/ui/menu/index.js +0 -2
- package/dist/ui/range/RangePicker.svelte +25 -13
- package/dist/ui/range/RangePicker.svelte.d.ts +9 -25
- package/dist/ui/range/RangePickerButton.svelte +49 -32
- package/dist/ui/range/RangePickerButton.svelte.d.ts +1 -1
- package/dist/ui/table/Table.svelte +16 -16
- package/dist/ui/table/Table.svelte.d.ts +1 -1
- package/dist/ui/table/TableFieldsEdition.svelte +25 -23
- package/dist/ui/table/TableHead.svelte +5 -1
- package/dist/ui/table/cell/TableCellBoolean.svelte +2 -2
- package/dist/ui/table/head/OrderButtons.svelte +21 -20
- package/dist/ui/table/head/OrderButtons.svelte.d.ts +2 -0
- package/dist/ui/table/head/TableHeadDate.svelte +66 -57
- package/dist/ui/table/head/TableHeadNumber.svelte +58 -22
- package/dist/ui/table/head/TableHeadSelect.svelte +31 -28
- package/dist/ui/table/head/TableHeadString.svelte +12 -8
- package/dist/ui/table/index.d.ts +1 -1
- package/dist/ui/table/index.js +1 -1
- package/package.json +7 -4
- package/dist/input/InputRelation.svelte +0 -200
- package/dist/popover/popover.svelte.js +0 -106
- package/dist/ui/table/TableViewSelect.svelte +0 -142
- package/dist/ui/table/TableViewSelect.svelte.d.ts +0 -11
- /package/dist/command/{command.svelte.d.ts → useCommand.svelte.d.ts} +0 -0
- /package/dist/state/{param.svelte.d.ts → param.d.ts} +0 -0
- /package/dist/state/{param.svelte.js → param.js} +0 -0
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
{@render activator?.({ showModal: () => dialog?.showModal() })}
|
|
70
70
|
|
|
71
71
|
<dialog bind:this={dialog} class="modal" tabindex="-1">
|
|
72
|
-
<div class="
|
|
73
|
-
<div class="relative flex items-center border-b p-4">
|
|
72
|
+
<div class="border-hard modal-box flex flex-col rounded-lg border p-0">
|
|
73
|
+
<div class="border-hard relative flex items-center border-b p-4">
|
|
74
74
|
<div class="grow">
|
|
75
75
|
{@render header?.()}
|
|
76
76
|
</div>
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
|
|
92
92
|
{@render footer?.()}
|
|
93
93
|
</div>
|
|
94
|
-
<
|
|
95
|
-
<button>close</button>
|
|
96
|
-
</
|
|
94
|
+
<div class="modal-backdrop">
|
|
95
|
+
<button type="button" onclick={() => dialog?.close()}>close</button>
|
|
96
|
+
</div>
|
|
97
97
|
</dialog>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" module>
|
|
2
|
-
|
|
2
|
+
/** Décalage horizontal courant (px) du tiroir `noOverlay` pendant sa transition. */
|
|
3
|
+
export const transitionX = $state({ current: 0 })
|
|
3
4
|
</script>
|
|
4
5
|
|
|
5
6
|
<script lang="ts">
|
|
@@ -8,10 +9,11 @@
|
|
|
8
9
|
import { XIcon } from '@lucide/svelte'
|
|
9
10
|
|
|
10
11
|
import { goto } from '$app/navigation'
|
|
11
|
-
import { urlParam } from '../../state/param.
|
|
12
|
+
import { urlParam } from '../../state/param.js'
|
|
12
13
|
import { drawerFly } from './drawerFly.js'
|
|
13
|
-
import { writable } from 'svelte/store'
|
|
14
14
|
import { useLayer } from './useLayer.svelte.js'
|
|
15
|
+
import { inertBackground } from './inertBackground.js'
|
|
16
|
+
import type { ClassValue } from 'svelte/elements'
|
|
15
17
|
|
|
16
18
|
let {
|
|
17
19
|
key,
|
|
@@ -23,57 +25,91 @@
|
|
|
23
25
|
duration = 180,
|
|
24
26
|
noOverlay = false,
|
|
25
27
|
zIndex = 50,
|
|
28
|
+
inertSkip = '[data-sonner-toaster], :has(> [data-sonner-toaster])',
|
|
26
29
|
children
|
|
27
30
|
}: {
|
|
28
31
|
key: string
|
|
29
32
|
title?: string
|
|
30
|
-
class?:
|
|
33
|
+
class?: ClassValue
|
|
31
34
|
maxWidth?: string
|
|
32
|
-
classHeader?:
|
|
33
|
-
classBody?:
|
|
35
|
+
classHeader?: ClassValue
|
|
36
|
+
classBody?: ClassValue
|
|
34
37
|
duration?: number
|
|
35
38
|
noOverlay?: boolean
|
|
36
39
|
zIndex?: number
|
|
40
|
+
/** Sélecteur des éléments d'arrière-plan qui restent interactifs quand le tiroir est ouvert. */
|
|
41
|
+
inertSkip?: string
|
|
37
42
|
children: Snippet<[{ open: typeof open; close: typeof close }]>
|
|
38
43
|
} = $props()
|
|
39
44
|
|
|
40
45
|
type GotoOptions = Parameters<typeof goto>[1]
|
|
46
|
+
// `keepFocus`: sans lui SvelteKit renvoie le focus sur `<body>` après chaque navigation
|
|
47
|
+
// client, ce qui écraserait le focus placé dans le tiroir (et sa restauration à la fermeture).
|
|
41
48
|
export function open(value = 1, options: GotoOptions = {}) {
|
|
42
49
|
return goto(urlParam.with({ [key]: value }), {
|
|
43
50
|
...options,
|
|
44
51
|
replaceState: true,
|
|
45
|
-
noScroll: true
|
|
52
|
+
noScroll: true,
|
|
53
|
+
keepFocus: true
|
|
46
54
|
})
|
|
47
55
|
}
|
|
48
56
|
|
|
49
57
|
export function close(options: GotoOptions = {}) {
|
|
50
|
-
return goto(urlParam.without(key), {
|
|
58
|
+
return goto(urlParam.without(key), {
|
|
59
|
+
...options,
|
|
60
|
+
replaceState: true,
|
|
61
|
+
noScroll: true,
|
|
62
|
+
keepFocus: true
|
|
63
|
+
})
|
|
51
64
|
}
|
|
52
65
|
let { offset, index, isActive } = $derived(useLayer(key))
|
|
53
66
|
let clientWidth = $state(0)
|
|
67
|
+
|
|
68
|
+
function onkeydown(event: KeyboardEvent) {
|
|
69
|
+
if (event.key !== 'Escape' || noOverlay) return
|
|
70
|
+
// `offset === 0`: seul le tiroir du dessus se ferme. Et une modale native ouverte *dans* le
|
|
71
|
+
// tiroir (`Dialog`, `ContextMenu`) doit consommer l'échappement en premier.
|
|
72
|
+
if (!isActive || offset !== 0 || document.querySelector('dialog[open]')) return
|
|
73
|
+
event.preventDefault()
|
|
74
|
+
close()
|
|
75
|
+
}
|
|
54
76
|
</script>
|
|
55
77
|
|
|
78
|
+
<svelte:window {onkeydown} />
|
|
79
|
+
|
|
56
80
|
{#if !noOverlay && isActive}
|
|
81
|
+
<!-- La fermeture au clavier passe par Échap et par le bouton de l'en-tête: l'overlay n'a pas
|
|
82
|
+
besoin d'un rôle `button` factice, et reste masqué aux technologies d'assistance. -->
|
|
57
83
|
<div
|
|
58
|
-
|
|
84
|
+
data-drawer={key}
|
|
85
|
+
data-drawer-overlay
|
|
86
|
+
aria-hidden="true"
|
|
59
87
|
onclick={() => close()}
|
|
60
|
-
onkeyup={() => close()}
|
|
61
|
-
tabindex={-1}
|
|
62
88
|
transition:fade={{ duration }}
|
|
63
89
|
style="z-index: {zIndex + index};"
|
|
64
|
-
class="
|
|
90
|
+
class="
|
|
91
|
+
fixed inset-0 bg-black/15 backdrop-blur-[1.5px]
|
|
92
|
+
"
|
|
65
93
|
></div>
|
|
66
94
|
{/if}
|
|
67
95
|
|
|
68
96
|
{#if isActive}
|
|
69
|
-
|
|
97
|
+
<!-- `<div>` et non `<aside>`: `role="dialog"` remplace de toute façon le rôle implicite, et
|
|
98
|
+
Svelte refuse un rôle interactif sur un élément qui ne l'est pas. -->
|
|
99
|
+
<div
|
|
100
|
+
data-drawer={key}
|
|
101
|
+
role="dialog"
|
|
102
|
+
aria-modal={!noOverlay}
|
|
103
|
+
aria-label={title}
|
|
104
|
+
tabindex={-1}
|
|
105
|
+
{@attach noOverlay ? () => {} : inertBackground({ key, skip: inertSkip })}
|
|
70
106
|
bind:clientWidth
|
|
71
107
|
transition:drawerFly|local={{
|
|
72
108
|
x: clientWidth,
|
|
73
109
|
duration,
|
|
74
110
|
opacity: 1,
|
|
75
111
|
onTransition(pos) {
|
|
76
|
-
|
|
112
|
+
if (noOverlay) transitionX.current = pos.x
|
|
77
113
|
}
|
|
78
114
|
}}
|
|
79
115
|
style="
|
|
@@ -82,18 +118,19 @@
|
|
|
82
118
|
transform: translateX({-offset * 4}rem);
|
|
83
119
|
transition-duration: {duration}ms;
|
|
84
120
|
"
|
|
85
|
-
class
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
121
|
+
class={[
|
|
122
|
+
'fixed top-0 right-0 bottom-0 z-10 flex',
|
|
123
|
+
'w-full flex-col overflow-y-scroll overscroll-contain bg-base-100',
|
|
124
|
+
'transition-transform',
|
|
125
|
+
klass
|
|
126
|
+
]}
|
|
91
127
|
>
|
|
92
128
|
<div
|
|
93
|
-
class=
|
|
94
|
-
sticky top-0 z-20 flex items-center
|
|
95
|
-
justify-between gap-2
|
|
96
|
-
|
|
129
|
+
class={[
|
|
130
|
+
'sticky top-0 z-20 flex items-center',
|
|
131
|
+
'justify-between gap-2 bg-base-100 p-4',
|
|
132
|
+
classHeader
|
|
133
|
+
]}
|
|
97
134
|
>
|
|
98
135
|
<h2 class="title min-w-0 overflow-hidden">{title}</h2>
|
|
99
136
|
<button onclick={() => close()} class="btn btn-square btn-sm">
|
|
@@ -101,8 +138,19 @@
|
|
|
101
138
|
</button>
|
|
102
139
|
</div>
|
|
103
140
|
|
|
104
|
-
<div class=
|
|
141
|
+
<div class={['grow px-4', classBody]}>
|
|
105
142
|
{@render children({ open, close })}
|
|
106
143
|
</div>
|
|
107
|
-
</
|
|
144
|
+
</div>
|
|
108
145
|
{/if}
|
|
146
|
+
|
|
147
|
+
<style>
|
|
148
|
+
/* Verrou de défilement porté par l'overlay lui-même: il se pose et se lève sans compteur,
|
|
149
|
+
tiroirs empilés et transition de sortie compris, et un tiroir `noOverlay` ne verrouille rien. */
|
|
150
|
+
:global(html:has([data-drawer-overlay])) {
|
|
151
|
+
overflow: hidden;
|
|
152
|
+
/* Passer `<html>` en `overflow: hidden` coupe la propagation du `overflow-y: scroll` de
|
|
153
|
+
`<body>` vers le viewport: la gouttière réservée évite le saut horizontal. */
|
|
154
|
+
scrollbar-gutter: stable;
|
|
155
|
+
}
|
|
156
|
+
</style>
|
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
|
|
1
|
+
/** Décalage horizontal courant (px) du tiroir `noOverlay` pendant sa transition. */
|
|
2
|
+
export declare const transitionX: {
|
|
3
|
+
current: number;
|
|
4
|
+
};
|
|
2
5
|
import { type Snippet } from 'svelte';
|
|
6
|
+
import type { ClassValue } from 'svelte/elements';
|
|
3
7
|
declare const Drawer: import("svelte").Component<{
|
|
4
8
|
key: string;
|
|
5
9
|
title?: string;
|
|
6
|
-
class?:
|
|
10
|
+
class?: ClassValue;
|
|
7
11
|
maxWidth?: string;
|
|
8
|
-
classHeader?:
|
|
9
|
-
classBody?:
|
|
12
|
+
classHeader?: ClassValue;
|
|
13
|
+
classBody?: ClassValue;
|
|
10
14
|
duration?: number;
|
|
11
15
|
noOverlay?: boolean;
|
|
12
16
|
zIndex?: number;
|
|
17
|
+
/** Sélecteur des éléments d'arrière-plan qui restent interactifs quand le tiroir est ouvert. */
|
|
18
|
+
inertSkip?: string;
|
|
13
19
|
children: Snippet<[{
|
|
14
20
|
open: (value?: number, options?: {
|
|
15
21
|
replaceState?: boolean | undefined;
|
package/dist/ui/drawer/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Attachment } from 'svelte/attachments';
|
|
2
|
+
export type InertBackgroundOptions = {
|
|
3
|
+
/** Les frères portant `data-drawer` de cette valeur sont préservés (overlay et tiroir courant). */
|
|
4
|
+
key: string;
|
|
5
|
+
/** Sélecteur des frères à laisser interactifs, par ex. le conteneur des toasts. */
|
|
6
|
+
skip?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Rend inerte tout le document sauf la branche qui mène au nœud attaché: à chaque niveau on marque
|
|
10
|
+
* les frères, jusqu'à `<body>`. Aucun nœud n'est déplacé — poser `inert` sur un conteneur racine
|
|
11
|
+
* serait impossible ici, le tiroir étant rendu à l'intérieur de ce conteneur.
|
|
12
|
+
*/
|
|
13
|
+
export declare function inertBackground({ key, skip }: InertBackgroundOptions): Attachment<HTMLElement>;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Compteur par élément: deux tiroirs empilés marquent les mêmes frères, et le second à se fermer
|
|
2
|
+
// ne doit lever `inert` que si le premier l'a déjà relâché. Un `WeakMap` évite de retenir les
|
|
3
|
+
// nœuds détachés entre-temps.
|
|
4
|
+
const marks = new WeakMap();
|
|
5
|
+
/**
|
|
6
|
+
* Rend inerte tout le document sauf la branche qui mène au nœud attaché: à chaque niveau on marque
|
|
7
|
+
* les frères, jusqu'à `<body>`. Aucun nœud n'est déplacé — poser `inert` sur un conteneur racine
|
|
8
|
+
* serait impossible ici, le tiroir étant rendu à l'intérieur de ce conteneur.
|
|
9
|
+
*/
|
|
10
|
+
export function inertBackground({ key, skip }) {
|
|
11
|
+
return (node) => {
|
|
12
|
+
const marked = [];
|
|
13
|
+
for (let el = node; el && el !== document.body; el = el.parentElement) {
|
|
14
|
+
for (const sibling of el.parentElement?.children ?? []) {
|
|
15
|
+
if (sibling === el || !(sibling instanceof HTMLElement))
|
|
16
|
+
continue;
|
|
17
|
+
if (sibling.dataset.drawer === key)
|
|
18
|
+
continue;
|
|
19
|
+
if (skip && sibling.matches(skip))
|
|
20
|
+
continue;
|
|
21
|
+
const count = marks.get(sibling) ?? 0;
|
|
22
|
+
marks.set(sibling, count + 1);
|
|
23
|
+
if (count === 0)
|
|
24
|
+
sibling.inert = true;
|
|
25
|
+
marked.push(sibling);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Relevé avant la mise en `inert`: le focus courant est souvent sur le déclencheur, qui
|
|
29
|
+
// appartient à l'arrière-plan et perdrait le focus au profit de `<body>`.
|
|
30
|
+
const previous = document.activeElement;
|
|
31
|
+
node.focus({ preventScroll: true });
|
|
32
|
+
// SvelteKit remet le focus sur `<body>` à la fin de la navigation qui ouvre le tiroir. Les
|
|
33
|
+
// `goto` de `open()`/`close()` passent `keepFocus`, mais un tiroir ouvert par un simple
|
|
34
|
+
// `<a href>` n'en profite pas: on repasse après coup, et seulement si personne d'autre n'a
|
|
35
|
+
// pris le focus entre-temps.
|
|
36
|
+
const timer = setTimeout(() => {
|
|
37
|
+
const active = document.activeElement;
|
|
38
|
+
if (!active || active === document.body)
|
|
39
|
+
node.focus({ preventScroll: true });
|
|
40
|
+
});
|
|
41
|
+
return () => {
|
|
42
|
+
clearTimeout(timer);
|
|
43
|
+
for (const el of marked) {
|
|
44
|
+
const count = (marks.get(el) ?? 1) - 1;
|
|
45
|
+
if (count > 0)
|
|
46
|
+
marks.set(el, count);
|
|
47
|
+
else {
|
|
48
|
+
marks.delete(el);
|
|
49
|
+
el.inert = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// `closest` et non `previous.inert`: la propriété ne reflète que l'attribut posé sur
|
|
53
|
+
// l'élément lui-même, pas l'inertie héritée d'un tiroir resté ouvert au-dessus.
|
|
54
|
+
if (previous instanceof HTMLElement && previous.isConnected && !previous.closest('[inert]')) {
|
|
55
|
+
previous.focus({ preventScroll: true });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
2
2
|
import { page } from '$app/state';
|
|
3
|
-
|
|
3
|
+
// Un ensemble et non un compteur: chaque tiroir monté fait tourner son effet, et des
|
|
4
|
+
// incréments/décréments dans un ordre non garanti finissaient à zéro au chargement direct
|
|
5
|
+
// d'une URL portant déjà un tiroir ouvert — `offset` valait alors -1 et poussait le tiroir
|
|
6
|
+
// hors de l'écran par la droite.
|
|
7
|
+
const activeKeys = new SvelteSet();
|
|
4
8
|
export function useLayer(key) {
|
|
5
9
|
const index = $derived.by(() => {
|
|
6
10
|
let i = 0;
|
|
@@ -12,12 +16,12 @@ export function useLayer(key) {
|
|
|
12
16
|
return -1;
|
|
13
17
|
});
|
|
14
18
|
const isActive = $derived(index !== -1);
|
|
15
|
-
const offset = $derived(isActive
|
|
19
|
+
const offset = $derived(isActive ? Math.max(activeKeys.size - index - 1, 0) : 0);
|
|
16
20
|
$effect(() => {
|
|
17
|
-
if (isActive)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
if (!isActive)
|
|
22
|
+
return;
|
|
23
|
+
activeKeys.add(key);
|
|
24
|
+
return () => activeKeys.delete(key);
|
|
21
25
|
});
|
|
22
26
|
return {
|
|
23
27
|
get index() {
|
package/dist/ui/index.d.ts
CHANGED
package/dist/ui/index.js
CHANGED
|
@@ -1,45 +1,50 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte'
|
|
3
3
|
import { MediaQuery } from 'svelte/reactivity'
|
|
4
|
+
import { type PopoverOptions, usePopover } from '../../popover/index.js'
|
|
4
5
|
import { Dialog } from '../dialog/index.js'
|
|
5
|
-
import { DropDown } from './index.js'
|
|
6
|
-
import type { TippyProps } from '../../utils/tippy.js'
|
|
7
6
|
|
|
8
7
|
let {
|
|
9
|
-
tippyProps = {},
|
|
10
8
|
class: klass = '',
|
|
11
9
|
onShow,
|
|
12
10
|
onHide,
|
|
13
|
-
children
|
|
11
|
+
children,
|
|
12
|
+
...popoverOptions
|
|
14
13
|
}: {
|
|
15
|
-
tippyProps?: Partial<TippyProps>
|
|
16
14
|
class?: string
|
|
17
15
|
onShow?: () => void
|
|
18
16
|
onHide?: () => void
|
|
19
17
|
children: Snippet
|
|
20
|
-
} = $props()
|
|
18
|
+
} & PopoverOptions = $props()
|
|
21
19
|
|
|
22
20
|
const isSmallScreen = new MediaQuery('max-width: 600px;')
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
// Le menu s'ouvre sur le curseur: un point invisible sert d'ancre et il n'y a aucun
|
|
22
|
+
// élément déclencheur à écouter, l'ouverture passe uniquement par `show()`.
|
|
23
|
+
const popover = usePopover({
|
|
24
|
+
...(() => popoverOptions)(),
|
|
25
|
+
listenClick: false,
|
|
26
|
+
listenFocus: false
|
|
27
|
+
})
|
|
28
|
+
let dialog = $state<HTMLDialogElement>()
|
|
29
|
+
let anchor = $state<HTMLElement>()
|
|
25
30
|
|
|
26
31
|
export function show(event: MouseEvent) {
|
|
27
32
|
if (isSmallScreen.current) {
|
|
28
33
|
dialog?.showModal()
|
|
29
34
|
} else {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
35
|
+
if (!anchor) return
|
|
36
|
+
// Positionné dans la foulée plutôt que via un `$state`: `showPopover()` lit la
|
|
37
|
+
// position de l'ancre avant qu'un effet Svelte ait eu le temps de s'appliquer.
|
|
38
|
+
anchor.style.left = `${event.clientX}px`
|
|
39
|
+
anchor.style.top = `${event.clientY}px`
|
|
40
|
+
popover.show()
|
|
36
41
|
}
|
|
37
42
|
onShow?.()
|
|
38
43
|
}
|
|
39
44
|
|
|
40
45
|
export function hide() {
|
|
41
46
|
if (isSmallScreen.current) dialog?.close()
|
|
42
|
-
else
|
|
47
|
+
else popover.hide()
|
|
43
48
|
onHide?.()
|
|
44
49
|
}
|
|
45
50
|
</script>
|
|
@@ -49,7 +54,15 @@
|
|
|
49
54
|
{@render children()}
|
|
50
55
|
</Dialog>
|
|
51
56
|
{:else}
|
|
52
|
-
<
|
|
57
|
+
<div bind:this={anchor} {...popover.trigger} class="pointer-events-none fixed h-0 w-0"></div>
|
|
58
|
+
|
|
59
|
+
<div {...popover.content} class={['rounded-box border bg-base-100 p-1 shadow-xl', klass]}>
|
|
53
60
|
{@render children()}
|
|
54
|
-
</
|
|
61
|
+
</div>
|
|
55
62
|
{/if}
|
|
63
|
+
|
|
64
|
+
<style>
|
|
65
|
+
div[popover] {
|
|
66
|
+
border-color: color-mix(in oklab, var(--color-base-content) 20%, #0000);
|
|
67
|
+
}
|
|
68
|
+
</style>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
-
import type
|
|
2
|
+
import { type PopoverOptions } from '../../popover/index.js';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
|
-
tippyProps?: Partial<TippyProps>;
|
|
5
4
|
class?: string;
|
|
6
5
|
onShow?: () => void;
|
|
7
6
|
onHide?: () => void;
|
|
8
7
|
children: Snippet;
|
|
9
|
-
};
|
|
8
|
+
} & PopoverOptions;
|
|
10
9
|
declare const ContextMenu: import("svelte").Component<$$ComponentProps, {
|
|
11
10
|
show: (event: MouseEvent) => void;
|
|
12
11
|
hide: () => void;
|
|
@@ -29,6 +29,6 @@ declare const DropDown: import("svelte").Component<$$ComponentProps, {
|
|
|
29
29
|
hide: () => void;
|
|
30
30
|
show: () => void;
|
|
31
31
|
setTippyProps: (props: Partial<TippyProps>) => void;
|
|
32
|
-
}, "">;
|
|
32
|
+
}, "tip">;
|
|
33
33
|
type DropDown = ReturnType<typeof DropDown>;
|
|
34
34
|
export default DropDown;
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { ChevronsUpDownIcon } from '@lucide/svelte'
|
|
3
3
|
import type { Snippet } from 'svelte'
|
|
4
|
-
import {
|
|
5
|
-
import type { TippyProps } from '../../utils/tippy.js'
|
|
4
|
+
import { Popover, type PopoverOptions } from '../../popover/index.js'
|
|
6
5
|
|
|
7
6
|
let {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
children: childrenProp,
|
|
8
|
+
...popoverOptions
|
|
10
9
|
}: {
|
|
11
|
-
tippyProps?: Partial<TippyProps>
|
|
12
10
|
children?: Snippet
|
|
13
|
-
} = $props()
|
|
11
|
+
} & PopoverOptions = $props()
|
|
14
12
|
</script>
|
|
15
13
|
|
|
16
|
-
<
|
|
17
|
-
{#snippet
|
|
18
|
-
<button
|
|
14
|
+
<Popover {...popoverOptions} class="p-1">
|
|
15
|
+
{#snippet trigger(popover)}
|
|
16
|
+
<button
|
|
17
|
+
type="button"
|
|
18
|
+
class="flex h-12 items-center gap-2 rounded-lg border pr-2 pl-4"
|
|
19
|
+
{...popover.trigger}
|
|
20
|
+
>
|
|
19
21
|
{#if childrenProp}
|
|
20
22
|
{@render childrenProp()}
|
|
21
23
|
{:else}
|
|
@@ -43,4 +45,4 @@
|
|
|
43
45
|
<span class="pr-4 whitespace-nowrap">{item.label}</span>
|
|
44
46
|
{/snippet}
|
|
45
47
|
</SelectorList> -->
|
|
46
|
-
</
|
|
48
|
+
</Popover>
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
|
-
import type
|
|
2
|
+
import { type PopoverOptions } from '../../popover/index.js';
|
|
3
3
|
type $$ComponentProps = {
|
|
4
|
-
tippyProps?: Partial<TippyProps>;
|
|
5
4
|
children?: Snippet;
|
|
6
|
-
};
|
|
5
|
+
} & PopoverOptions;
|
|
7
6
|
declare const DropDownMenu: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
7
|
type DropDownMenu = ReturnType<typeof DropDownMenu>;
|
|
9
8
|
export default DropDownMenu;
|
package/dist/ui/menu/index.d.ts
CHANGED
package/dist/ui/menu/index.js
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import dayjs from 'dayjs'
|
|
3
3
|
import type { Litepicker } from 'litepicker'
|
|
4
|
-
import {
|
|
4
|
+
import { onDestroy, onMount } from 'svelte'
|
|
5
5
|
import type { RangeAsDate, RangeDate } from './types.js'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
let {
|
|
8
|
+
numberOfMonths = 3,
|
|
9
|
+
numberOfColumns = numberOfMonths,
|
|
10
|
+
showWeekNumbers = true,
|
|
11
|
+
range = $bindable(),
|
|
12
|
+
minDate,
|
|
13
|
+
maxDate,
|
|
14
|
+
onchange
|
|
15
|
+
}: {
|
|
16
|
+
numberOfMonths?: number
|
|
17
|
+
numberOfColumns?: number
|
|
18
|
+
showWeekNumbers?: boolean
|
|
19
|
+
range?: RangeAsDate
|
|
20
|
+
minDate?: Date | number | string
|
|
21
|
+
maxDate?: Date | number | string
|
|
22
|
+
onchange?: (range: RangeAsDate) => void
|
|
23
|
+
} = $props()
|
|
13
24
|
|
|
14
|
-
let startElement: HTMLInputElement
|
|
15
|
-
let endElement: HTMLInputElement
|
|
25
|
+
let startElement: HTMLInputElement = $state()!
|
|
26
|
+
let endElement: HTMLInputElement = $state()!
|
|
27
|
+
let parentEl: HTMLDivElement = $state()!
|
|
16
28
|
let picker: Litepicker
|
|
17
|
-
let parentEl: HTMLDivElement
|
|
18
|
-
const dispatch = createEventDispatcher<{ change: RangeAsDate }>()
|
|
19
29
|
|
|
20
30
|
onMount(() => {
|
|
21
31
|
initTimePicker()
|
|
@@ -58,7 +68,7 @@
|
|
|
58
68
|
`${getAbsoluteDate(date2.dateInstance)}T${getAbsoluteTime(range?.end, '23:59:00')}`
|
|
59
69
|
)
|
|
60
70
|
}
|
|
61
|
-
|
|
71
|
+
onchange?.(range)
|
|
62
72
|
})
|
|
63
73
|
}
|
|
64
74
|
})
|
|
@@ -78,4 +88,6 @@
|
|
|
78
88
|
<input type="hidden" bind:this={startElement} />
|
|
79
89
|
<input type="hidden" bind:this={endElement} />
|
|
80
90
|
|
|
81
|
-
|
|
91
|
+
<!-- Litepicker se pose en `inline-block`: sans conteneur flex il se colle à gauche dès que le
|
|
92
|
+
parent est plus large que le calendrier. -->
|
|
93
|
+
<div class="flex justify-center" bind:this={parentEl}></div>
|
|
@@ -1,31 +1,15 @@
|
|
|
1
1
|
import type { RangeAsDate } from './types.js';
|
|
2
|
-
|
|
3
|
-
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
-
$$bindings?: Bindings;
|
|
5
|
-
} & Exports;
|
|
6
|
-
(internal: unknown, props: Props & {
|
|
7
|
-
$$events?: Events;
|
|
8
|
-
$$slots?: Slots;
|
|
9
|
-
}): Exports & {
|
|
10
|
-
$set?: any;
|
|
11
|
-
$on?: any;
|
|
12
|
-
};
|
|
13
|
-
z_$$bindings?: Bindings;
|
|
14
|
-
}
|
|
15
|
-
declare const RangePicker: $$__sveltets_2_IsomorphicComponent<{
|
|
2
|
+
type $$ComponentProps = {
|
|
16
3
|
numberOfMonths?: number;
|
|
17
4
|
numberOfColumns?: number;
|
|
18
5
|
showWeekNumbers?: boolean;
|
|
19
|
-
range?: RangeAsDate
|
|
20
|
-
minDate?: Date | number | string
|
|
21
|
-
maxDate?: Date | number | string
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
} & {
|
|
26
|
-
[evt: string]: CustomEvent<any>;
|
|
27
|
-
}, {}, {
|
|
6
|
+
range?: RangeAsDate;
|
|
7
|
+
minDate?: Date | number | string;
|
|
8
|
+
maxDate?: Date | number | string;
|
|
9
|
+
onchange?: (range: RangeAsDate) => void;
|
|
10
|
+
};
|
|
11
|
+
declare const RangePicker: import("svelte").Component<$$ComponentProps, {
|
|
28
12
|
clear: () => void;
|
|
29
|
-
},
|
|
30
|
-
type RangePicker =
|
|
13
|
+
}, "range">;
|
|
14
|
+
type RangePicker = ReturnType<typeof RangePicker>;
|
|
31
15
|
export default RangePicker;
|