fuma 2.1.6 → 2.2.7

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 (84) hide show
  1. package/dist/_doc/data.d.ts +3 -1
  2. package/dist/_doc/data.js +6 -2
  3. package/dist/command/index.d.ts +1 -1
  4. package/dist/command/index.js +1 -1
  5. package/dist/command/{command.svelte.js → useCommand.svelte.js} +1 -1
  6. package/dist/input/InputBoolean.svelte +25 -7
  7. package/dist/input/InputBoolean.svelte.d.ts +4 -0
  8. package/dist/input/InputCheckboxes.svelte +116 -0
  9. package/dist/input/InputCheckboxes.svelte.d.ts +16 -0
  10. package/dist/input/InputDateTime.svelte +194 -0
  11. package/dist/input/InputDateTime.svelte.d.ts +23 -0
  12. package/dist/input/InputMultiSelect.svelte +286 -0
  13. package/dist/input/{InputRelation.svelte.d.ts → InputMultiSelect.svelte.d.ts} +27 -13
  14. package/dist/input/InputNumber.svelte +36 -6
  15. package/dist/input/InputNumber.svelte.d.ts +5 -0
  16. package/dist/input/InputRadio.svelte +54 -23
  17. package/dist/input/InputRange.svelte +19 -4
  18. package/dist/input/InputRange.svelte.d.ts +6 -0
  19. package/dist/input/InputSelect.svelte +204 -62
  20. package/dist/input/InputSelect.svelte.d.ts +87 -6
  21. package/dist/input/InputSelectNative.svelte +44 -19
  22. package/dist/input/InputSelectNative.svelte.d.ts +5 -0
  23. package/dist/input/InputString.svelte +14 -6
  24. package/dist/input/InputString.svelte.d.ts +4 -0
  25. package/dist/input/InputTextarea.svelte +41 -12
  26. package/dist/input/InputTextarea.svelte.d.ts +5 -0
  27. package/dist/input/index.d.ts +4 -1
  28. package/dist/input/index.js +4 -1
  29. package/dist/input/useItems.svelte.d.ts +38 -0
  30. package/dist/input/useItems.svelte.js +142 -0
  31. package/dist/loading/Loading.svelte +3 -2
  32. package/dist/loading/Loading.svelte.d.ts +3 -2
  33. package/dist/popover/Popover.svelte +1 -2
  34. package/dist/popover/Popover.svelte.d.ts +13 -0
  35. package/dist/popover/index.d.ts +1 -1
  36. package/dist/popover/index.js +1 -1
  37. package/dist/popover/{popover.svelte.d.ts → usePopover.svelte.d.ts} +2 -1
  38. package/dist/popover/usePopover.svelte.js +145 -0
  39. package/dist/remote/useForm.d.ts +4 -5
  40. package/dist/remote/useForm.js +9 -4
  41. package/dist/state/index.d.ts +1 -1
  42. package/dist/state/index.js +1 -1
  43. package/dist/ui/button/ButtonDelete.svelte +4 -2
  44. package/dist/ui/dialog/Dialog.svelte +5 -5
  45. package/dist/ui/drawer/Drawer.svelte +74 -26
  46. package/dist/ui/drawer/Drawer.svelte.d.ts +10 -4
  47. package/dist/ui/drawer/index.d.ts +1 -0
  48. package/dist/ui/drawer/index.js +1 -0
  49. package/dist/ui/drawer/inertBackground.d.ts +13 -0
  50. package/dist/ui/drawer/inertBackground.js +59 -0
  51. package/dist/ui/drawer/useLayer.svelte.d.ts +1 -1
  52. package/dist/ui/drawer/useLayer.svelte.js +11 -7
  53. package/dist/ui/index.d.ts +1 -0
  54. package/dist/ui/index.js +1 -0
  55. package/dist/ui/menu/ContextMenu.svelte +30 -17
  56. package/dist/ui/menu/ContextMenu.svelte.d.ts +2 -3
  57. package/dist/ui/menu/DropDown.svelte +1 -1
  58. package/dist/ui/menu/DropDown.svelte.d.ts +1 -1
  59. package/dist/ui/menu/DropDownMenu.svelte +12 -10
  60. package/dist/ui/menu/DropDownMenu.svelte.d.ts +2 -3
  61. package/dist/ui/menu/index.d.ts +0 -1
  62. package/dist/ui/menu/index.js +0 -2
  63. package/dist/ui/range/RangePicker.svelte +25 -13
  64. package/dist/ui/range/RangePicker.svelte.d.ts +9 -25
  65. package/dist/ui/range/RangePickerButton.svelte +49 -32
  66. package/dist/ui/range/RangePickerButton.svelte.d.ts +1 -1
  67. package/dist/ui/table/Table.svelte +7 -10
  68. package/dist/ui/table/Table.svelte.d.ts +1 -1
  69. package/dist/ui/table/TableFieldsEdition.svelte +24 -22
  70. package/dist/ui/table/TableHead.svelte +5 -1
  71. package/dist/ui/table/TableViewSelect.svelte +52 -47
  72. package/dist/ui/table/cell/TableCellBoolean.svelte +2 -2
  73. package/dist/ui/table/head/TableHeadDate.svelte +62 -55
  74. package/dist/ui/table/head/TableHeadNumber.svelte +55 -19
  75. package/dist/ui/table/head/TableHeadSelect.svelte +30 -27
  76. package/dist/ui/table/head/TableHeadString.svelte +11 -7
  77. package/dist/ui/table/index.d.ts +1 -0
  78. package/dist/ui/table/index.js +1 -0
  79. package/package.json +7 -4
  80. package/dist/input/InputRelation.svelte +0 -200
  81. package/dist/popover/popover.svelte.js +0 -106
  82. /package/dist/command/{command.svelte.d.ts → useCommand.svelte.d.ts} +0 -0
  83. /package/dist/state/{param.svelte.d.ts → param.d.ts} +0 -0
  84. /package/dist/state/{param.svelte.js → param.js} +0 -0
@@ -1,5 +1,6 @@
1
1
  <script lang="ts" module>
2
- export const transitionX = writable(0)
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.svelte.js'
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?: string
33
+ class?: ClassValue
31
34
  maxWidth?: string
32
- classHeader?: string
33
- classBody?: string
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), { ...options, replaceState: true, noScroll: true })
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
- role="button"
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="fixed inset-0 bg-black/15 backdrop-blur-[1.5px] dark:bg-white/15"
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
- <aside
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
- $transitionX = pos.x
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:border-l={noOverlay}
86
- class="{klass} fixed
87
- top-0 right-0 bottom-0 z-10 flex
88
- w-full flex-col overflow-y-scroll bg-base-100
89
- transition-transform
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="{classHeader}
94
- sticky top-0 z-20 flex items-center
95
- justify-between gap-2 border-b bg-base-100 p-4 pl-8
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="{classBody} grow pr-4 pl-8">
141
+ <div class={['grow px-4', classBody]}>
105
142
  {@render children({ open, close })}
106
143
  </div>
107
- </aside>
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
- export declare const transitionX: import("svelte/store").Writable<number>;
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?: string;
10
+ class?: ClassValue;
7
11
  maxWidth?: string;
8
- classHeader?: string;
9
- classBody?: string;
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;
@@ -1,2 +1,3 @@
1
1
  export { default as Drawer, transitionX } from './Drawer.svelte';
2
2
  export * from './drawerFly.js';
3
+ export * from './inertBackground.js';
@@ -1,2 +1,3 @@
1
1
  export { default as Drawer, transitionX } from './Drawer.svelte';
2
2
  export * from './drawerFly.js';
3
+ export * from './inertBackground.js';
@@ -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,5 +1,5 @@
1
1
  export declare function useLayer(key: string): {
2
2
  readonly index: number;
3
- readonly offset: number | false;
3
+ readonly offset: number;
4
4
  readonly isActive: boolean;
5
5
  };
@@ -1,6 +1,10 @@
1
- import { untrack } from 'svelte';
1
+ import { SvelteSet } from 'svelte/reactivity';
2
2
  import { page } from '$app/state';
3
- let nbActives = $state(0);
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 && nbActives - index - 1);
19
+ const offset = $derived(isActive ? Math.max(activeKeys.size - index - 1, 0) : 0);
16
20
  $effect(() => {
17
- if (isActive)
18
- untrack(() => nbActives++);
19
- else
20
- untrack(() => (nbActives = Math.max(nbActives - 1, 0)));
21
+ if (!isActive)
22
+ return;
23
+ activeKeys.add(key);
24
+ return () => activeKeys.delete(key);
21
25
  });
22
26
  return {
23
27
  get index() {
@@ -1,4 +1,5 @@
1
1
  export * from './button/index.js';
2
+ export * from './copy/index.js';
2
3
  export * from './dialog/index.js';
3
4
  export * from './drawer/index.js';
4
5
  export * from './menu/index.js';
package/dist/ui/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './button/index.js';
2
+ export * from './copy/index.js';
2
3
  export * from './dialog/index.js';
3
4
  export * from './drawer/index.js';
4
5
  export * from './menu/index.js';
@@ -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
- let dropdown: DropDown | undefined = $state()
24
- let dialog: HTMLDialogElement | undefined = $state()
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
- const target = event.target as HTMLElement
31
- if (!target || !(target instanceof HTMLElement)) return
32
- dropdown?.setTippyProps({
33
- getReferenceClientRect: () => new DOMRect(event.clientX, event.clientY)
34
- })
35
- dropdown?.show()
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 dropdown?.hide()
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
- <DropDown class={klass} bind:this={dropdown} tippyProps={{ offset: [0, -5], ...tippyProps }}>
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
- </DropDown>
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 { TippyProps } from '../../utils/tippy.js';
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;
@@ -22,7 +22,7 @@
22
22
  hideOnBlur = false,
23
23
  hideOnNav = true,
24
24
  disable = false,
25
- tip,
25
+ tip = $bindable(),
26
26
  content,
27
27
  activator,
28
28
  children
@@ -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 { DropDown } from './index.js'
5
- import type { TippyProps } from '../../utils/tippy.js'
4
+ import { Popover, type PopoverOptions } from '../../popover/index.js'
6
5
 
7
6
  let {
8
- tippyProps = {},
9
- children: childrenProp
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
- <DropDown {tippyProps}>
17
- {#snippet activator()}
18
- <button type="button" class="flex h-12 items-center gap-2 rounded-lg border pr-2 pl-4">
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
- </DropDown>
48
+ </Popover>
@@ -1,9 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
- import type { TippyProps } from '../../utils/tippy.js';
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;
@@ -1,3 +1,2 @@
1
1
  export { default as ContextMenu } from './ContextMenu.svelte';
2
2
  export { default as DropDown } from './DropDown.svelte';
3
- export { default as DropDownMenu } from './DropDownMenu.svelte';
@@ -1,4 +1,2 @@
1
1
  export { default as ContextMenu } from './ContextMenu.svelte';
2
2
  export { default as DropDown } from './DropDown.svelte';
3
- export { default as DropDownMenu } from './DropDownMenu.svelte';
4
- // TODO: probably replaced by Popover
@@ -1,21 +1,31 @@
1
1
  <script lang="ts">
2
2
  import dayjs from 'dayjs'
3
3
  import type { Litepicker } from 'litepicker'
4
- import { createEventDispatcher, onDestroy, onMount } from 'svelte'
4
+ import { onDestroy, onMount } from 'svelte'
5
5
  import type { RangeAsDate, RangeDate } from './types.js'
6
6
 
7
- export let numberOfMonths = 3
8
- export let numberOfColumns = numberOfMonths
9
- export let showWeekNumbers = true
10
- export let range: RangeAsDate | undefined = undefined
11
- export let minDate: Date | number | string | undefined = undefined
12
- export let maxDate: Date | number | string | undefined = undefined
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
- dispatch('change', range)
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
- <div bind:this={parentEl}></div>
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
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
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 | undefined;
20
- minDate?: Date | number | string | undefined;
21
- maxDate?: Date | number | string | undefined;
22
- clear?: () => void;
23
- }, {
24
- change: CustomEvent<RangeAsDate>;
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
- }, string>;
30
- type RangePicker = InstanceType<typeof RangePicker>;
13
+ }, "range">;
14
+ type RangePicker = ReturnType<typeof RangePicker>;
31
15
  export default RangePicker;