fuma 2.1.5 → 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 +36 -6
  24. package/dist/input/InputString.svelte.d.ts +5 -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
@@ -12,6 +12,7 @@ export type User = {
12
12
  subscribeAt: string;
13
13
  gender: UserGender;
14
14
  gender2: UserGender;
15
+ friendIds: string[];
15
16
  loveId?: string | null;
16
17
  };
17
18
  export declare const userGenders: readonly ["male", "female", "other"];
@@ -21,7 +22,7 @@ export declare const schemaUser: z.ZodObject<{
21
22
  age: z.ZodNumber;
22
23
  level: z.ZodNumber;
23
24
  cv: z.ZodString;
24
- isValided: z.ZodLiteral<true>;
25
+ isValided: z.ZodPipe<z.ZodOptional<z.ZodBoolean>, z.ZodLiteral<true>>;
25
26
  subscribeAt: z.z.ZodISODate;
26
27
  gender: z.ZodEnum<{
27
28
  other: "other";
@@ -33,6 +34,7 @@ export declare const schemaUser: z.ZodObject<{
33
34
  female: "female";
34
35
  male: "male";
35
36
  }>;
37
+ friendIds: z.ZodArray<z.ZodString>;
36
38
  loveId: z.ZodOptional<z.ZodString>;
37
39
  }, z.z.core.$strip>;
38
40
  export declare const userGenderOptions: {
package/dist/_doc/data.js CHANGED
@@ -12,7 +12,8 @@ function createRandomUser() {
12
12
  isValided: Math.random() < 0.5,
13
13
  subscribeAt: faker.date.past().toISOString(),
14
14
  gender: faker.person.sexType(),
15
- gender2: faker.person.sexType()
15
+ gender2: faker.person.sexType(),
16
+ friendIds: []
16
17
  };
17
18
  }
18
19
  export const users = faker.helpers.multiple(createRandomUser, {
@@ -25,10 +26,13 @@ export const schemaUser = z.object({
25
26
  age: z.number().min(18).max(120),
26
27
  level: z.number().min(0).max(100),
27
28
  cv: z.string(),
28
- isValided: z.literal(true, 'Validation requise'),
29
+ // Une case non cochée n'envoie rien: `form()` de kit refuse au typage tout booléen non
30
+ // optionnel. L'entrée est donc optionnelle, et le `pipe` rétablit l'exigence à l'exécution.
31
+ isValided: z.boolean().optional().pipe(z.literal(true, 'Validation requise')),
29
32
  subscribeAt: z.iso.date(),
30
33
  gender: z.enum(userGenders),
31
34
  gender2: z.enum(userGenders),
35
+ friendIds: z.array(z.string()),
32
36
  loveId: z.string().optional()
33
37
  // tags: z.array(z.enum(userTags)).default([]),
34
38
  });
@@ -1 +1 @@
1
- export * from './command.svelte.js';
1
+ export * from './useCommand.svelte.js';
@@ -1 +1 @@
1
- export * from './command.svelte.js';
1
+ export * from './useCommand.svelte.js';
@@ -8,7 +8,7 @@ export function useCommand({ onSelect, onFocus, isEnable = () => true, hotKey }
8
8
  function onKeydown(event) {
9
9
  if (!isEnable())
10
10
  return;
11
- if (event.key === 'Enter' || event.key === ' ') {
11
+ if (event.key === 'Enter') {
12
12
  event.preventDefault();
13
13
  onSelect?.(focusIndex);
14
14
  selectedIndex = focusIndex;
@@ -14,6 +14,10 @@
14
14
  }: {
15
15
  label: string
16
16
  field?: RemoteFormField<boolean>
17
+ /**
18
+ * Sans `field`, l'état lié. Avec, l'état initial du champ — celui-ci prend ensuite
19
+ * le relais et devient la source de vérité.
20
+ */
17
21
  checked?: boolean
18
22
  hint?: string
19
23
  variant?: 'checkbox' | 'switch'
@@ -26,13 +30,23 @@
26
30
  <label
27
31
  class={[
28
32
  'input block not-disabled:cursor-pointer not-disabled:hover:bg-base-200',
29
- 'group h-auto min-h-10'
33
+ 'group h-auto min-h-10 w-full'
30
34
  ]}
31
35
  >
32
- <div class="flex h-(--size) items-center gap-2">
33
- <div class="grow">{label}</div>
36
+ <!-- `.input` de daisyUI pose `white-space: nowrap`: sans `text-wrap`, un libellé un peu
37
+ long déborde de la ligne au lieu de passer à la suivante. La hauteur suit donc le
38
+ contenu, `--size` n'étant plus qu'un plancher. -->
39
+ <div class="flex min-h-(--size) items-center gap-2 py-1.5">
40
+ <div class="grow text-wrap">{label}</div>
34
41
  {#if field}
35
- <input {...field.as('checkbox')} class={['peer w-0']} {...props} />
42
+ <!-- `as('checkbox')` sans valeur pose `checked: undefined`: la case d'un champ
43
+ déjà à `true` partirait décochée, alors que la coche dessinée, elle, suit
44
+ `checked`. Les deux ne se contredisent que si l'état initial n'est pas transmis. -->
45
+ {#if checked === undefined}
46
+ <input {...field.as('checkbox')} class={['peer w-0']} {...props} />
47
+ {:else}
48
+ <input {...field.as('checkbox', checked)} class={['peer w-0']} {...props} />
49
+ {/if}
36
50
  {:else}
37
51
  <input type="checkbox" class={['peer w-0']} bind:checked {...props} />
38
52
  {/if}
@@ -58,15 +72,15 @@
58
72
 
59
73
  {#snippet variantCheckbox()}
60
74
  <!-- https://developer.mozilla.org/en-US/docs/Web/CSS/corner-shape -->
61
- <div class={['h-5 w-5 rounded-full outline', 'bg-base-100']} style="corner-shape: squircle;">
75
+ <div class={['squircle', 'h-5 w-5 outline', 'bg-base-100']}>
62
76
  <div
63
77
  class={[
64
- 'squircle grid h-5 w-5 place-content-center',
78
+ 'squircle',
79
+ 'grid h-5 w-5 place-content-center',
65
80
  'bg-base-content',
66
81
  'ease scale-0 opacity-0',
67
82
  isChecked && 'scale-[80%] opacity-100'
68
83
  ]}
69
- style="corner-shape: squircle"
70
84
  >
71
85
  <CheckIcon size={18} class={['stroke-base-100']} strokeWidth={4} />
72
86
  </div>
@@ -93,6 +107,10 @@
93
107
  transition-timing-function: cubic-bezier(0.275, 0.485, 0.515, 1.45);
94
108
  transition-duration: 200ms;
95
109
  }
110
+ .squircle {
111
+ corner-shape: squircle;
112
+ border-radius: 100%;
113
+ }
96
114
 
97
115
  label:has(input[aria-invalid='true']) {
98
116
  --input-color: var(--color-error);
@@ -3,6 +3,10 @@ import type { InputProps } from './type.js';
3
3
  type $$ComponentProps = {
4
4
  label: string;
5
5
  field?: RemoteFormField<boolean>;
6
+ /**
7
+ * Sans `field`, l'état lié. Avec, l'état initial du champ — celui-ci prend ensuite
8
+ * le relais et devient la source de vérité.
9
+ */
6
10
  checked?: boolean;
7
11
  hint?: string;
8
12
  variant?: 'checkbox' | 'switch';
@@ -0,0 +1,116 @@
1
+ <script lang="ts">
2
+ import { CheckIcon } from '@lucide/svelte'
3
+ import type { RemoteFormField } from '@sveltejs/kit'
4
+ import { type Options, parseOptions } from '../utils/index.js'
5
+ import Issues from './Issues.svelte'
6
+ import type { InputProps } from './type.js'
7
+
8
+ let {
9
+ field,
10
+ label,
11
+ value = $bindable([]),
12
+ options: optionsProp,
13
+ ...props
14
+ }: {
15
+ field?: RemoteFormField<string[]>
16
+ label: string
17
+ /**
18
+ * Sans `field`, les valeurs liées. Avec, les valeurs initiales: les cases restent
19
+ * pilotées par `value`, `field.as('checkbox', …)` ne servant qu'à les nommer.
20
+ */
21
+ value?: string[]
22
+ options: Options
23
+ } & InputProps = $props()
24
+
25
+ const options = $derived(parseOptions(optionsProp))
26
+
27
+ function toggle(optionValue: string, checked: boolean) {
28
+ value = checked ? [...value, optionValue] : value.filter((v) => v !== optionValue)
29
+ // Les cases suffisent à soumettre; `set` garde la validation du formulaire à jour.
30
+ field?.set(value)
31
+ }
32
+ </script>
33
+
34
+ <div class="flex flex-col gap-1">
35
+ <span class="label px-3 text-sm text-wrap">{label}</span>
36
+ <div class="join join-vertical">
37
+ {#each options as option (option.value)}
38
+ {@const {
39
+ class: klass,
40
+ value: optionValue,
41
+ label: optionLabel,
42
+ icon: Icon,
43
+ ...optionProps
44
+ } = option}
45
+ {@const checked = value.includes(optionValue)}
46
+ <label
47
+ class={[
48
+ 'input join-item not-disabled:cursor-pointer not-disabled:hover:bg-base-200',
49
+ 'group h-auto min-h-10'
50
+ ]}
51
+ >
52
+ <div class="flex h-(--size) grow items-center gap-2">
53
+ {#if Icon}
54
+ <Icon size={18} opacity={0.8} />
55
+ {/if}
56
+ <span class="grow">{optionLabel}</span>
57
+ <!-- Le `checked` explicite prime sur celui de `as()`, qui lit `field.value()`:
58
+ sans lui les valeurs initiales ne partiraient pas tant que rien n'a été
59
+ coché, et le visuel ci-dessous s'en écarterait. -->
60
+ <input
61
+ {...field?.as('checkbox', optionValue)}
62
+ type="checkbox"
63
+ {checked}
64
+ onchange={({ currentTarget }) => toggle(optionValue, currentTarget.checked)}
65
+ class={['w-0']}
66
+ {...props}
67
+ {...optionProps}
68
+ />
69
+ <!-- https://developer.mozilla.org/en-US/docs/Web/CSS/corner-shape -->
70
+ <div
71
+ class={[
72
+ 'squircle',
73
+ 'ml-auto h-5 w-5 outline',
74
+ 'bg-base-100',
75
+ !checked && 'outline-base-content/20',
76
+ klass
77
+ ]}
78
+ >
79
+ <div
80
+ class={[
81
+ 'squircle',
82
+ 'grid h-5 w-5 place-content-center',
83
+ 'bg-base-content',
84
+ 'ease scale-0 opacity-0',
85
+ checked && 'scale-[80%] opacity-100'
86
+ ]}
87
+ >
88
+ <CheckIcon size={18} class={['stroke-base-100']} strokeWidth={4} />
89
+ </div>
90
+ </div>
91
+ </div>
92
+ </label>
93
+ {/each}
94
+ </div>
95
+ <Issues {field} />
96
+ </div>
97
+
98
+ <style>
99
+ .ease {
100
+ transition-property: translate background-color opacity;
101
+ transition-timing-function: cubic-bezier(0.275, 0.485, 0.515, 1.45);
102
+ transition-duration: 200ms;
103
+ }
104
+ .squircle {
105
+ corner-shape: squircle;
106
+ border-radius: 100%;
107
+ }
108
+
109
+ label:has(input[aria-invalid='true']) {
110
+ --input-color: var(--color-error);
111
+ }
112
+ label:has(input:disabled) {
113
+ cursor: not-allowed;
114
+ border-color: var(--input-color);
115
+ }
116
+ </style>
@@ -0,0 +1,16 @@
1
+ import type { RemoteFormField } from '@sveltejs/kit';
2
+ import { type Options } from '../utils/index.js';
3
+ import type { InputProps } from './type.js';
4
+ type $$ComponentProps = {
5
+ field?: RemoteFormField<string[]>;
6
+ label: string;
7
+ /**
8
+ * Sans `field`, les valeurs liées. Avec, les valeurs initiales: les cases restent
9
+ * pilotées par `value`, `field.as('checkbox', …)` ne servant qu'à les nommer.
10
+ */
11
+ value?: string[];
12
+ options: Options;
13
+ } & InputProps;
14
+ declare const InputCheckboxes: import("svelte").Component<$$ComponentProps, {}, "value">;
15
+ type InputCheckboxes = ReturnType<typeof InputCheckboxes>;
16
+ export default InputCheckboxes;
@@ -0,0 +1,194 @@
1
+ <script lang="ts">
2
+ import { MinusIcon, PlusIcon } from '@lucide/svelte'
3
+ import type { RemoteFormField } from '@sveltejs/kit'
4
+ import dayjs, { type Dayjs } from 'dayjs'
5
+ import timezonePlugin from 'dayjs/plugin/timezone.js'
6
+ import utcPlugin from 'dayjs/plugin/utc.js'
7
+ import Issues from './Issues.svelte'
8
+ import type { InputProps } from './type.js'
9
+
10
+ dayjs.extend(utcPlugin)
11
+ dayjs.extend(timezonePlugin)
12
+
13
+ let {
14
+ label,
15
+ field,
16
+ name,
17
+ value = $bindable(),
18
+ timezone,
19
+ layout = 'split',
20
+ variant = 'block',
21
+ hint,
22
+ transform = (v) => v,
23
+ onchange,
24
+ class: klass,
25
+ ...props
26
+ }: {
27
+ label: string
28
+ /** La date part en ISO dans un champ caché: au schéma de la reconstruire. */
29
+ field?: RemoteFormField<string>
30
+ /** Sans `field`, le nom du champ caché. Sans l'un ni l'autre, rien n'est soumis. */
31
+ name?: string
32
+ value?: Date | null
33
+ /** Zone IANA d'affichage et de saisie; à défaut, celle du navigateur. */
34
+ timezone?: string
35
+ /** `split`: l'heure au-dessus de la date, avec ses boutons ±jour. */
36
+ layout?: 'split' | 'datetime'
37
+ /** Sans effet sur `split`, dont la ligne de label porte le `hint`. */
38
+ variant?: 'floating' | 'block'
39
+ hint?: string
40
+ /** Ajuste la valeur avant qu'elle ne soit posée — borne, arrondi, décalage. */
41
+ transform?: (value: Date) => Date
42
+ onchange?: (value: Date) => void
43
+ } & InputProps = $props()
44
+
45
+ const inputId = $props.id()
46
+ const inputProps = $derived({ id: inputId, class: 'input w-full', ...props })
47
+
48
+ const current = $derived.by(() => {
49
+ if (!value) return null
50
+ const date = inZone(dayjs(value))
51
+ // Une date illisible se traite comme une absence de valeur: `format` rendrait
52
+ // « Invalid Date » dans les champs, et `toJSON` un `null` que le champ caché refuse.
53
+ return date.isValid() ? date : null
54
+ })
55
+
56
+ function inZone(date: Dayjs) {
57
+ return timezone ? date.tz(timezone) : date
58
+ }
59
+
60
+ /** Une saisie partielle sur un champ vide se raccroche à maintenant. */
61
+ function base() {
62
+ return current ?? inZone(dayjs())
63
+ }
64
+
65
+ function setTime(time: string) {
66
+ if (!time) return
67
+ const [h, m] = time.split(':').map(Number)
68
+ setValue(base().set('h', h).set('m', m))
69
+ }
70
+
71
+ function setDate(date: string) {
72
+ if (!date) return
73
+ const [y, m, d] = date.split('-').map(Number)
74
+ setValue(
75
+ base()
76
+ .set('y', y)
77
+ .set('M', m - 1)
78
+ .set('D', d)
79
+ )
80
+ }
81
+
82
+ function setDateTime(datetime: string) {
83
+ if (!datetime) return
84
+ const [date, time] = datetime.split('T')
85
+ const [y, M, d] = date.split('-').map(Number)
86
+ const [h, m] = time.split(':').map(Number)
87
+ setValue(
88
+ base()
89
+ .set('y', y)
90
+ .set('M', M - 1)
91
+ .set('D', d)
92
+ .set('h', h)
93
+ .set('m', m)
94
+ .startOf('m')
95
+ )
96
+ }
97
+
98
+ function setValue(newValue: Dayjs) {
99
+ const date = transform(newValue.toDate())
100
+ value = date
101
+ // Le champ caché suffit à soumettre; `set` garde la validation du formulaire à jour.
102
+ field?.set(date.toJSON())
103
+ onchange?.(date)
104
+ }
105
+ </script>
106
+
107
+ <!-- Par `current` et non `value`: la valeur passée n'est pas toujours la `Date` annoncée par le
108
+ type — une date qui a fait l'aller-retour par JSON revient en chaîne ISO. -->
109
+ {#if current}
110
+ {#if field}
111
+ <input {...field.as('hidden', current.toJSON())} />
112
+ {:else if name}
113
+ <input type="hidden" {name} value={current.toJSON()} />
114
+ {/if}
115
+ {/if}
116
+
117
+ {#snippet inputDateTime()}
118
+ <input
119
+ {...inputProps}
120
+ type="datetime-local"
121
+ value={current ? current.format('YYYY-MM-DDTHH:mm') : ''}
122
+ oninput={(event) => setDateTime(event.currentTarget.value)}
123
+ />
124
+ {/snippet}
125
+
126
+ {#snippet inputSplit()}
127
+ <div>
128
+ <input
129
+ {...inputProps}
130
+ type="time"
131
+ value={current ? current.format('HH:mm') : ''}
132
+ oninput={(event) => setTime(event.currentTarget.value)}
133
+ />
134
+
135
+ <div class="join mt-1 flex w-full">
136
+ <!-- `preventDefault` sur le `mousedown`: le bouton ne prend pas le focus, donc aucun
137
+ `focusout` n'est émis. Dans un popover, ce focus qui se déplace est ce qui déclenche
138
+ la fermeture; le focus reste sur le champ, ce qui permet aussi d'enchaîner les pas. -->
139
+ <button
140
+ type="button"
141
+ class="btn join-item btn-square bg-base-200/30 btn-xs"
142
+ disabled={!current}
143
+ onmousedown={(event) => event.preventDefault()}
144
+ onclick={() => current && setValue(current.add(-1, 'day'))}
145
+ >
146
+ <MinusIcon size={12} />
147
+ </button>
148
+ <input
149
+ type="date"
150
+ class="border-soft input join-item border-x-0 input-ghost input-xs"
151
+ value={current ? current.format('YYYY-MM-DD') : ''}
152
+ oninput={(event) => setDate(event.currentTarget.value)}
153
+ />
154
+ <button
155
+ type="button"
156
+ class="btn join-item btn-square bg-base-200/30 btn-xs"
157
+ disabled={!current}
158
+ onmousedown={(event) => event.preventDefault()}
159
+ onclick={() => current && setValue(current.add(1, 'day'))}
160
+ >
161
+ <PlusIcon size={12} />
162
+ </button>
163
+ </div>
164
+ </div>
165
+ {/snippet}
166
+
167
+ {#if layout === 'datetime' && variant === 'floating'}
168
+ <label class={['floating-label', klass]}>
169
+ <span>{label}</span>
170
+ {@render inputDateTime()}
171
+ <Issues {field} />
172
+ </label>
173
+ {:else}
174
+ <fieldset class={['fieldset', klass]}>
175
+ <label class="label text-wrap" for={inputId}>
176
+ <span>{label}</span>
177
+ {#if hint}
178
+ <span class="ml-auto">{hint}</span>
179
+ {/if}
180
+ </label>
181
+ {#if layout === 'datetime'}
182
+ {@render inputDateTime()}
183
+ {:else}
184
+ {@render inputSplit()}
185
+ {/if}
186
+ <Issues {field} />
187
+ </fieldset>
188
+ {/if}
189
+
190
+ <style>
191
+ input[aria-invalid='true'] {
192
+ --input-color: var(--color-error);
193
+ }
194
+ </style>
@@ -0,0 +1,23 @@
1
+ import type { RemoteFormField } from '@sveltejs/kit';
2
+ import type { InputProps } from './type.js';
3
+ type $$ComponentProps = {
4
+ label: string;
5
+ /** La date part en ISO dans un champ caché: au schéma de la reconstruire. */
6
+ field?: RemoteFormField<string>;
7
+ /** Sans `field`, le nom du champ caché. Sans l'un ni l'autre, rien n'est soumis. */
8
+ name?: string;
9
+ value?: Date | null;
10
+ /** Zone IANA d'affichage et de saisie; à défaut, celle du navigateur. */
11
+ timezone?: string;
12
+ /** `split`: l'heure au-dessus de la date, avec ses boutons ±jour. */
13
+ layout?: 'split' | 'datetime';
14
+ /** Sans effet sur `split`, dont la ligne de label porte le `hint`. */
15
+ variant?: 'floating' | 'block';
16
+ hint?: string;
17
+ /** Ajuste la valeur avant qu'elle ne soit posée — borne, arrondi, décalage. */
18
+ transform?: (value: Date) => Date;
19
+ onchange?: (value: Date) => void;
20
+ } & InputProps;
21
+ declare const InputDateTime: import("svelte").Component<$$ComponentProps, {}, "value">;
22
+ type InputDateTime = ReturnType<typeof InputDateTime>;
23
+ export default InputDateTime;