@panneau/fields 5.0.0-alpha.1 → 5.0.0-alpha.10

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 (243) hide show
  1. package/README.md +101 -20
  2. package/dist/boolean/BooleanField.d.ts +1 -1
  3. package/dist/boolean/BooleanField.js +78 -17
  4. package/dist/boolean/BooleanField.js.map +1 -1
  5. package/dist/boolean/index.d.ts +1 -1
  6. package/dist/color/ColorField.css +5 -5
  7. package/dist/color/ColorField.d.ts +2 -2
  8. package/dist/color/ColorField.js.map +1 -1
  9. package/dist/color/ColorField.module.js +3 -3
  10. package/dist/color/index.d.ts +1 -1
  11. package/dist/date/DateField.d.ts +1 -1
  12. package/dist/date/DateField.js.map +1 -1
  13. package/dist/date/index.d.ts +1 -1
  14. package/dist/datetime/DateTimeField.d.ts +1 -1
  15. package/dist/datetime/DateTimeField.js +107 -20
  16. package/dist/datetime/DateTimeField.js.map +1 -1
  17. package/dist/datetime/index.d.ts +1 -1
  18. package/dist/duration/DurationField.css +11 -0
  19. package/dist/duration/DurationField.d.ts +26 -0
  20. package/dist/duration/DurationField.d.ts.map +1 -0
  21. package/dist/duration/DurationField.js +214 -0
  22. package/dist/duration/DurationField.js.map +1 -0
  23. package/dist/duration/DurationField.module.js +12 -0
  24. package/dist/duration/DurationField.module.js.map +1 -0
  25. package/dist/duration/index.d.ts +2 -0
  26. package/dist/duration/index.d.ts.map +1 -0
  27. package/dist/duration/index.js +1 -0
  28. package/dist/email/EmailField.d.ts +2 -2
  29. package/dist/email/EmailField.js.map +1 -1
  30. package/dist/email/index.d.ts +1 -1
  31. package/dist/embed/EmbedField.css +60 -0
  32. package/dist/embed/EmbedField.d.ts +20 -0
  33. package/dist/embed/EmbedField.d.ts.map +1 -0
  34. package/dist/embed/EmbedField.js +246 -0
  35. package/dist/embed/EmbedField.js.map +1 -0
  36. package/dist/embed/EmbedField.module.js +22 -0
  37. package/dist/embed/EmbedField.module.js.map +1 -0
  38. package/dist/embed/index.d.ts +3 -0
  39. package/dist/embed/index.d.ts.map +1 -0
  40. package/dist/embed/index.js +3 -0
  41. package/dist/file/FileField.css +54 -0
  42. package/dist/file/FileField.d.ts +50 -0
  43. package/dist/file/FileField.d.ts.map +1 -0
  44. package/dist/file/FileField.js +288 -0
  45. package/dist/file/FileField.js.map +1 -0
  46. package/dist/file/FileField.module.js +22 -0
  47. package/dist/file/FileField.module.js.map +1 -0
  48. package/dist/file/index.d.ts +3 -0
  49. package/dist/file/index.d.ts.map +1 -0
  50. package/dist/file/index.js +1 -0
  51. package/dist/group/GroupField.css +2 -2
  52. package/dist/group/GroupField.d.ts +1 -1
  53. package/dist/group/GroupField.js.map +1 -1
  54. package/dist/group/GroupField.module.js +1 -1
  55. package/dist/group/index.d.ts +1 -1
  56. package/dist/index.d.ts +18 -7
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +11 -2
  59. package/dist/json/JsonField.css +7 -0
  60. package/dist/json/JsonField.d.ts +22 -0
  61. package/dist/json/JsonField.d.ts.map +1 -0
  62. package/dist/json/JsonField.js +207 -0
  63. package/dist/json/JsonField.js.map +1 -0
  64. package/dist/json/JsonField.module.js +8 -0
  65. package/dist/json/JsonField.module.js.map +1 -0
  66. package/dist/json/index.d.ts +2 -0
  67. package/dist/json/index.d.ts.map +1 -0
  68. package/dist/json/index.js +1 -0
  69. package/dist/locales/index.js.map +1 -1
  70. package/dist/localized/LocalizedField.css +2 -2
  71. package/dist/localized/LocalizedField.d.ts +1 -1
  72. package/dist/localized/LocalizedField.d.ts.map +1 -1
  73. package/dist/localized/LocalizedField.js +1 -0
  74. package/dist/localized/LocalizedField.js.map +1 -1
  75. package/dist/localized/LocalizedField.module.js +2 -2
  76. package/dist/localized/index.d.ts +1 -1
  77. package/dist/location/LocationField.css +54 -0
  78. package/dist/location/LocationField.d.ts +31 -0
  79. package/dist/location/LocationField.d.ts.map +1 -0
  80. package/dist/location/LocationField.js +563 -0
  81. package/dist/location/LocationField.js.map +1 -0
  82. package/dist/location/LocationField.module.js +22 -0
  83. package/dist/location/LocationField.module.js.map +1 -0
  84. package/dist/location/LocationMap.d.ts +25 -0
  85. package/dist/location/LocationMap.d.ts.map +1 -0
  86. package/dist/location/LocationMap.js +205 -0
  87. package/dist/location/LocationMap.js.map +1 -0
  88. package/dist/location/index.d.ts +5 -0
  89. package/dist/location/index.d.ts.map +1 -0
  90. package/dist/location/index.js +4 -0
  91. package/dist/location/leafletCss.d.ts +2 -0
  92. package/dist/location/leafletCss.d.ts.map +1 -0
  93. package/dist/location/leafletCss.js +6 -0
  94. package/dist/location/leafletCss.js.map +1 -0
  95. package/dist/location/nominatim.d.ts +17 -0
  96. package/dist/location/nominatim.d.ts.map +1 -0
  97. package/dist/location/nominatim.js +50 -0
  98. package/dist/location/nominatim.js.map +1 -0
  99. package/dist/location/types.d.ts +40 -0
  100. package/dist/location/types.d.ts.map +1 -0
  101. package/dist/missing/MissingField.css +4 -3
  102. package/dist/missing/MissingField.d.ts +4 -3
  103. package/dist/missing/MissingField.d.ts.map +1 -1
  104. package/dist/missing/MissingField.js +3 -2
  105. package/dist/missing/MissingField.js.map +1 -1
  106. package/dist/missing/MissingField.module.js +3 -3
  107. package/dist/missing/MissingField.module.js.map +1 -1
  108. package/dist/number/NumberField.d.ts +1 -1
  109. package/dist/number/NumberField.js.map +1 -1
  110. package/dist/number/index.d.ts +1 -1
  111. package/dist/range/RangeField.d.ts +22 -0
  112. package/dist/range/RangeField.d.ts.map +1 -0
  113. package/dist/range/RangeField.js +203 -0
  114. package/dist/range/RangeField.js.map +1 -0
  115. package/dist/range/index.d.ts +2 -0
  116. package/dist/range/index.d.ts.map +1 -0
  117. package/dist/range/index.js +1 -0
  118. package/dist/relation/RelationField.css +7 -7
  119. package/dist/relation/RelationField.d.ts +2 -2
  120. package/dist/relation/RelationField.d.ts.map +1 -1
  121. package/dist/relation/RelationField.js +509 -169
  122. package/dist/relation/RelationField.js.map +1 -1
  123. package/dist/relation/RelationField.module.js +6 -6
  124. package/dist/relation/index.d.ts +2 -2
  125. package/dist/repeater/RepeaterField.css +12 -11
  126. package/dist/repeater/RepeaterField.d.ts +1 -1
  127. package/dist/repeater/RepeaterField.js +118 -34
  128. package/dist/repeater/RepeaterField.js.map +1 -1
  129. package/dist/repeater/RepeaterField.module.js +9 -9
  130. package/dist/repeater/RepeaterField.module.js.map +1 -1
  131. package/dist/repeater/index.d.ts +1 -1
  132. package/dist/select/SelectField.css +1 -1
  133. package/dist/select/SelectField.d.ts +1 -1
  134. package/dist/select/SelectField.js.map +1 -1
  135. package/dist/select/SelectField.module.js +1 -1
  136. package/dist/select/index.d.ts +1 -1
  137. package/dist/shared/DefinitionField.d.ts +4 -2
  138. package/dist/shared/DefinitionField.d.ts.map +1 -1
  139. package/dist/shared/DefinitionField.js +80 -72
  140. package/dist/shared/DefinitionField.js.map +1 -1
  141. package/dist/shared/builtIn.d.ts +5 -3
  142. package/dist/shared/builtIn.d.ts.map +1 -1
  143. package/dist/shared/builtIn.js +21 -3
  144. package/dist/shared/builtIn.js.map +1 -1
  145. package/dist/shared/check.d.ts +27 -0
  146. package/dist/shared/check.d.ts.map +1 -0
  147. package/dist/shared/check.js +18 -0
  148. package/dist/shared/check.js.map +1 -0
  149. package/dist/shared/context.d.ts +28 -5
  150. package/dist/shared/context.d.ts.map +1 -1
  151. package/dist/shared/context.js +35 -19
  152. package/dist/shared/context.js.map +1 -1
  153. package/dist/shared/cx.js.map +1 -1
  154. package/dist/shared/dates.js.map +1 -1
  155. package/dist/shared/embed.d.ts +19 -0
  156. package/dist/shared/embed.d.ts.map +1 -0
  157. package/dist/shared/embed.js +14 -0
  158. package/dist/shared/embed.js.map +1 -0
  159. package/dist/shared/entry.d.ts +11 -2
  160. package/dist/shared/entry.d.ts.map +1 -1
  161. package/dist/shared/entry.js +19 -3
  162. package/dist/shared/entry.js.map +1 -1
  163. package/dist/shared/relation.js.map +1 -1
  164. package/dist/shared/types.d.ts +2 -0
  165. package/dist/shared/types.d.ts.map +1 -1
  166. package/dist/slug/SlugField.css +18 -0
  167. package/dist/slug/SlugField.d.ts +33 -5
  168. package/dist/slug/SlugField.d.ts.map +1 -1
  169. package/dist/slug/SlugField.js +346 -126
  170. package/dist/slug/SlugField.js.map +1 -1
  171. package/dist/slug/SlugField.module.js +14 -0
  172. package/dist/slug/SlugField.module.js.map +1 -0
  173. package/dist/slug/index.d.ts +1 -1
  174. package/dist/slug/index.d.ts.map +1 -1
  175. package/dist/slug/index.js +1 -1
  176. package/dist/tags/TagsField.d.ts +17 -0
  177. package/dist/tags/TagsField.d.ts.map +1 -0
  178. package/dist/tags/TagsField.js +120 -0
  179. package/dist/tags/TagsField.js.map +1 -0
  180. package/dist/tags/index.d.ts +2 -0
  181. package/dist/tags/index.d.ts.map +1 -0
  182. package/dist/tags/index.js +1 -0
  183. package/dist/tel/TelField.d.ts +11 -0
  184. package/dist/tel/TelField.d.ts.map +1 -0
  185. package/dist/tel/TelField.js +87 -0
  186. package/dist/tel/TelField.js.map +1 -0
  187. package/dist/tel/index.d.ts +2 -0
  188. package/dist/tel/index.d.ts.map +1 -0
  189. package/dist/tel/index.js +1 -0
  190. package/dist/text/TextField.d.ts +12 -4
  191. package/dist/text/TextField.d.ts.map +1 -1
  192. package/dist/text/TextField.js +104 -60
  193. package/dist/text/TextField.js.map +1 -1
  194. package/dist/text/index.d.ts +1 -1
  195. package/dist/textarea/TextAreaField.d.ts +1 -1
  196. package/dist/textarea/TextAreaField.js.map +1 -1
  197. package/dist/textarea/index.d.ts +1 -1
  198. package/dist/time/TimeField.d.ts +1 -1
  199. package/dist/time/TimeField.js +64 -10
  200. package/dist/time/TimeField.js.map +1 -1
  201. package/dist/time/index.d.ts +1 -1
  202. package/dist/upload/FilePicker.css +24 -0
  203. package/dist/upload/FilePicker.d.ts +14 -0
  204. package/dist/upload/FilePicker.d.ts.map +1 -0
  205. package/dist/upload/FilePicker.js +130 -0
  206. package/dist/upload/FilePicker.js.map +1 -0
  207. package/dist/upload/FilePicker.module.js +12 -0
  208. package/dist/upload/FilePicker.module.js.map +1 -0
  209. package/dist/upload/UploadList.css +93 -0
  210. package/dist/upload/UploadList.d.ts +18 -0
  211. package/dist/upload/UploadList.d.ts.map +1 -0
  212. package/dist/upload/UploadList.js +144 -0
  213. package/dist/upload/UploadList.js.map +1 -0
  214. package/dist/upload/UploadList.module.js +32 -0
  215. package/dist/upload/UploadList.module.js.map +1 -0
  216. package/dist/upload/files.d.ts +5 -0
  217. package/dist/upload/files.d.ts.map +1 -0
  218. package/dist/upload/files.js +26 -0
  219. package/dist/upload/files.js.map +1 -0
  220. package/dist/upload/types.d.ts +58 -0
  221. package/dist/upload/types.d.ts.map +1 -0
  222. package/dist/upload/useRejectionMessage.d.ts +4 -0
  223. package/dist/upload/useRejectionMessage.d.ts.map +1 -0
  224. package/dist/upload/useRejectionMessage.js +25 -0
  225. package/dist/upload/useRejectionMessage.js.map +1 -0
  226. package/dist/upload/useUploads.d.ts +30 -0
  227. package/dist/upload/useUploads.d.ts.map +1 -0
  228. package/dist/upload/useUploads.js +115 -0
  229. package/dist/upload/useUploads.js.map +1 -0
  230. package/dist/uppy/index.d.ts +3 -0
  231. package/dist/uppy/index.d.ts.map +1 -0
  232. package/dist/uppy/index.js +1 -0
  233. package/dist/uppy/uploader.d.ts +44 -0
  234. package/dist/uppy/uploader.d.ts.map +1 -0
  235. package/dist/uppy/uploader.js +139 -0
  236. package/dist/uppy/uploader.js.map +1 -0
  237. package/dist/url/UrlField.css +2 -2
  238. package/dist/url/UrlField.d.ts +2 -2
  239. package/dist/url/UrlField.js +69 -14
  240. package/dist/url/UrlField.js.map +1 -1
  241. package/dist/url/UrlField.module.js +1 -1
  242. package/dist/url/index.d.ts +1 -1
  243. package/package.json +69 -7
package/README.md CHANGED
@@ -4,6 +4,7 @@ Controlled field components for the protocol's built-in field types, built on [`
4
4
 
5
5
  ```bash
6
6
  npm install @panneau/fields@^5.0.0-alpha.0 @panneau/ui@^5.0.0-alpha.0 react-aria-components react-intl
7
+ npm install @uppy/core@^6.3.0 @uppy/aws-s3@^6.3.0 # only for @panneau/fields/uppy
7
8
  ```
8
9
 
9
10
  ```tsx
@@ -19,25 +20,34 @@ import { PanneauRoot } from '@panneau/ui';
19
20
 
20
21
  Every field takes `value`, `onChange`, `onBlur`, `errors`, `disabled`, `readOnly`, `required`, `label` and `description`, plus `className` and `xxxClassName` props for its inner elements. Fields keep no value of their own, and an empty value is `null`.
21
22
 
22
- | Import | Components | Value |
23
- | --------------------------- | -------------------------------------------- | ---------------------------------------------- |
24
- | `@panneau/fields/text` | `TextField` | `string` |
25
- | `@panneau/fields/textarea` | `TextAreaField` | `string` |
26
- | `@panneau/fields/number` | `NumberField` | `number` |
27
- | `@panneau/fields/boolean` | `BooleanField` (checkbox, switch) | `boolean` |
28
- | `@panneau/fields/date` | `DateField` | `'2026-10-15'` |
29
- | `@panneau/fields/datetime` | `DateTimeField` | `'2026-10-15T13:30:00Z'`, or without an offset |
30
- | `@panneau/fields/time` | `TimeField` | `'09:30'` |
31
- | `@panneau/fields/select` | `SelectField` (dropdown, radios, checkboxes) | an option's value, or a list with `multiple` |
32
- | `@panneau/fields/email` | `EmailField` | `string` |
33
- | `@panneau/fields/url` | `UrlField` | `string`, with `https://` added on blur |
34
- | `@panneau/fields/color` | `ColorField` | `'#1d4ed8'` |
35
- | `@panneau/fields/slug` | `SlugField`, `slugify()` | `string`, following a `source` until edited |
36
- | `@panneau/fields/localized` | `LocalizedField` | `{ fr: …, en: … }` |
37
- | `@panneau/fields/group` | `GroupField` | an object |
38
- | `@panneau/fields/repeater` | `RepeaterField` (items or typed blocks) | a list of objects; blocks have a `type` |
39
- | `@panneau/fields/relation` | `RelationField`, `createRelationSource()` | `{ id, label }`, or a list with `multiple` |
40
- | `@panneau/fields/locales` | `en`, `fr` | deprecated: use `@panneau/intl` |
23
+ | Import | Components | Value |
24
+ | --------------------------- | -------------------------------------------- | ------------------------------------------------------------------- |
25
+ | `@panneau/fields/text` | `TextField` | `string` |
26
+ | `@panneau/fields/textarea` | `TextAreaField` | `string` |
27
+ | `@panneau/fields/number` | `NumberField` | `number` |
28
+ | `@panneau/fields/boolean` | `BooleanField` (checkbox, switch) | `boolean` |
29
+ | `@panneau/fields/date` | `DateField` | `'2026-10-15'` |
30
+ | `@panneau/fields/datetime` | `DateTimeField` | `'2026-10-15T13:30:00Z'`, or without an offset |
31
+ | `@panneau/fields/time` | `TimeField` | `'09:30'` |
32
+ | `@panneau/fields/select` | `SelectField` (dropdown, radios, checkboxes) | an option's value, or a list with `multiple` |
33
+ | `@panneau/fields/email` | `EmailField` | `string` |
34
+ | `@panneau/fields/url` | `UrlField` | `string`, with `https://` added on blur |
35
+ | `@panneau/fields/color` | `ColorField` | `'#1d4ed8'` |
36
+ | `@panneau/fields/slug` | `SlugField`, `slugify()`, `sourceText()` | `string`, following a `source` until edited, checked with `onCheck` |
37
+ | `@panneau/fields/tel` | `TelField` | `string`, as typed |
38
+ | `@panneau/fields/range` | `RangeField` (a slider) | `number`, `null` until moved |
39
+ | `@panneau/fields/duration` | `DurationField`, `formatDuration()` | seconds, typed in hours, minutes and seconds |
40
+ | `@panneau/fields/json` | `JsonField`, `parseJson()` | an object or an array; the text while it doesn't parse |
41
+ | `@panneau/fields/tags` | `TagsField` | a list of strings, free or among suggestions |
42
+ | `@panneau/fields/embed` | `EmbedField` | `{ url, title, thumbnailUrl, … }`, from the backend (below) |
43
+ | `@panneau/fields/location` | `LocationField`, `createNominatimSource()` | `{ lat, lng, address }`, on a map (below) |
44
+ | `@panneau/fields/localized` | `LocalizedField` | `{ fr: …, en: … }` |
45
+ | `@panneau/fields/group` | `GroupField` | an object |
46
+ | `@panneau/fields/repeater` | `RepeaterField` (items or typed blocks) | a list of objects; blocks have a `type` |
47
+ | `@panneau/fields/relation` | `RelationField`, `createRelationSource()` | `{ id, label }`, or a list with `multiple` |
48
+ | `@panneau/fields/file` | `FileField` | a file, or a list with `multiple` (below) |
49
+ | `@panneau/fields/uppy` | `createUppyUploadSource()` | the upload source on Uppy 6 (below) |
50
+ | `@panneau/fields/locales` | `en`, `fr` | deprecated: use `@panneau/intl` |
41
51
 
42
52
  ## From a definition
43
53
 
@@ -65,10 +75,81 @@ import {
65
75
  - **Relations** search a `RelationSource`. `createRelationSource()` makes one from any adapter with a `list()` method, such as the `DataAdapter` of `@panneau/data`. Labels come from the resource's `itemTitle`. Without a source, a relation field shows its references, read-only.
66
76
  - **Plain ids.** Values can be ids (`"12"`, `["12", "13"]`), as a product's own API gives them. The field shows their labels once the source's optional `resolve(resource, ids)` gives them (`createRelationSource()` implements it with the adapter's `get()`), and their ids until then. Fields that show the same ids share one request. `useRelationReferences()` does the same for other components.
67
77
  - **Creating from the picker.** When the source has `create(resource, text)`, the picker offers "Create “…”" for a text that matches no item, and adds the new item. `createRelationSource(adapter, { create: true })` creates it with the adapter's `create()`, with the text as its `itemTitle` (in every locale when it is localized), on the resources that allow `create`; a function gives other values. A field's `onCreate` prop replaces the source's, and can open a dialog with a full form: it resolves with the new reference, or `null`. `onCreate={null}` turns creating off.
68
- - **Plugin slot:** a type without an entry, such as `richtext` and `media` until Phase 2, renders a placeholder that names it. A plugin that provides the type replaces it.
78
+ - **Files** upload through the `uploadSource` of the provider (below). Without one, the value holds the files themselves.
79
+ - **Plugin slot:** a type without an entry, such as `richtext` and `media` without their plugins (`@panneau/editor`, `@panneau/media`), renders a placeholder that names it. A plugin that provides the type replaces it.
80
+
81
+ ## Files and uploads
82
+
83
+ `FileField` (the `file` type) holds files that belong to an item, outside the media library: an attachment, a PDF, a CSV ([decision 0025](../../docs/decisions/0025-presigned-uploads.md)). Its value is a file, or a list of them with `multiple`:
84
+
85
+ - a **stored file**, `{ name, url, mime, size }`, as items give it: the field shows it with a link;
86
+ - an **uploaded file**, `{ upload, name, mime, size }`, once the browser sent the file to storage: requests send its `upload`;
87
+ - the **`File` itself**, without an upload source: the adapter sends it in `multipart/form-data`.
88
+
89
+ A new file replaces the file of a single value, and is added to a multiple one. `accept` and `maxSize` (from the field's `accept`, its `accept` rule and its `maxSize` rule) refuse files before they are sent. A read-only field only shows its files.
90
+
91
+ **Upload sources.** An `UploadSource` makes an uploader for each field, which reports each file's progress and gives its upload once it is done. `createUppyUploadSource()` of `@panneau/fields/uppy` makes one on Uppy 6: files go to S3-compatible storage with URLs that the backend signs, in parts when they are large (they can pause and resume), and each upload is completed with the backend. `@uppy/core` and `@uppy/aws-s3` 6 are optional peer dependencies, only for that entry point: nothing else in the package imports Uppy. Make the source once, and pass it as `uploadSource` to `FieldsProvider`, or to `FormView` of `@panneau/forms`, when the definition announces direct uploads:
92
+
93
+ ```tsx
94
+ import { createUppyUploadSource } from '@panneau/fields/uppy';
95
+
96
+ const uploadSource =
97
+ definition.uploads?.mode === 'presigned' && adapter.presignedUploads !== undefined
98
+ ? createUppyUploadSource(
99
+ adapter.presignedUploads({ endpoint: definition.uploads.endpoint }),
100
+ )
101
+ : null;
102
+
103
+ <FieldsProvider components={builtInFields} uploadSource={uploadSource}>
104
+ …
105
+ </FieldsProvider>;
106
+ ```
107
+
108
+ `adapter.presignedUploads()` comes from `@panneau/data`; `createUppyUploadSource()` only needs an object with its `signRequest()` and `complete()` (`PresignedUploadsLike`), so fields don't depend on `@panneau/data`. A field's `uploadSource` prop overrides the provider's, and `null` turns uploads off.
109
+
110
+ **Building blocks.** `@panneau/fields` also exports what the file field is made of, for other fields that take files (the media field of `@panneau/media`): `useUploads()` (checks files, uploads them through a source, and gives their state), `UploadList` (a progress bar per file, with pause, resume, cancel and retry), `FilePicker` (a button and a drop zone), and `formatSize()`, `matchesMime()`, `getAccept()`, `getMaxSize()`.
69
111
 
70
112
  ## Messages
71
113
 
72
114
  Strings go through react-intl, with English defaults. Add the messages of every Panneau package to the app's with `withPanneauMessages()` from [`@panneau/intl`](../intl), or use `fieldsPlugin`, which carries the French messages of every package (`ui`, `fields` and `forms`).
73
115
 
74
116
  The package layout, scripts and API reports are explained in [`docs/packages.md`](../../docs/packages.md).
117
+
118
+ ## Checking a value
119
+
120
+ A field with `check` in the definition, such as a `slug`, checks its value with the backend as it is typed ([decision 0032](../../docs/decisions/0032-field-checks-and-slugs.md)). The slug field then shows the URL the backend gives, says when the slug is taken with a free one to use, and is read-only when the backend says the field doesn't apply to the item. Give forms a check source for the item they edit:
121
+
122
+ ```tsx
123
+ import { createFieldCheckSource } from '@panneau/fields';
124
+
125
+ <FormView form={form} checkSource={createFieldCheckSource(adapter, 'pages', item?.id ?? null)} />;
126
+ ```
127
+
128
+ Without one, fields don't check, and the slug shows its fixed `settings.prefix`.
129
+
130
+ ## Embeds and places
131
+
132
+ An `embed` field shows the title and the thumbnail of a URL's video, sound or post. It gets them from the backend (`GET /embeds`), through the embed source of the provider; without one, it keeps the URL alone:
133
+
134
+ ```tsx
135
+ import { createEmbedSource } from '@panneau/fields';
136
+
137
+ <FieldsProvider embedSource={createEmbedSource(adapter)}>…</FieldsProvider>;
138
+ ```
139
+
140
+ A `location` field places a point on a Leaflet map, loaded when the field is first shown. The tiles are OpenStreetMap's by default. `maps` sets other tiles and an address search, a `GeocodingSource`: `createNominatimSource()` searches OpenStreetMap's Nominatim, whose [usage policy](https://operations.osmfoundation.org/policies/nominatim/) suits small volumes; a product with more uses its own service. Without a geocoding source, the field has no address search, and the latitude and longitude are typed or picked on the map.
141
+
142
+ ```tsx
143
+ import { createNominatimSource } from '@panneau/fields';
144
+
145
+ <FieldsProvider
146
+ maps={{
147
+ tiles: { url: 'https://tiles.example.com/{z}/{x}/{y}.png', attribution: '© Example' },
148
+ geocoding: createNominatimSource({ email: 'dev@example.com', countryCodes: ['ca'] }),
149
+ }}
150
+ >
151
+ …
152
+ </FieldsProvider>;
153
+ ```
154
+
155
+ `<Panneau>` and `createPanneauApp()` give the embed source of their adapter, and take `maps`.
@@ -1,4 +1,4 @@
1
- import type { FieldEntryProps, FieldProps } from '../shared/types';
1
+ import type { FieldEntryProps, FieldProps } from '../shared/types.js';
2
2
  export interface BooleanFieldProps extends Omit<FieldProps<boolean>, 'labelClassName'> {
3
3
  /** `checkbox` (default) for a choice saved with the form, `switch` for an on and off setting. */
4
4
  widget?: 'checkbox' | 'switch';
@@ -4,23 +4,84 @@ import { Checkbox, Switch } from "@panneau/ui";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  //#region src/boolean/BooleanField.tsx
6
6
  /** A yes or no value, as a checkbox or a switch with its label. An empty value is `false`. */
7
- function BooleanField({ value, onChange, label, widget = "checkbox", disabled, readOnly, required, controlClassName, ...props }) {
8
- const shared = {
9
- ...props,
10
- isSelected: value === true,
11
- onChange: (next) => onChange?.(next),
12
- isDisabled: disabled,
13
- isReadOnly: readOnly,
14
- isRequired: required,
15
- children: label
16
- };
17
- return widget === "switch" ? /* @__PURE__ */ jsx(Switch, {
18
- ...shared,
19
- switchClassName: controlClassName
20
- }) : /* @__PURE__ */ jsx(Checkbox, {
21
- ...shared,
22
- checkboxClassName: controlClassName
23
- });
7
+ function BooleanField(t0) {
8
+ const $ = c(24);
9
+ let controlClassName;
10
+ let disabled;
11
+ let label;
12
+ let onChange;
13
+ let props;
14
+ let readOnly;
15
+ let required;
16
+ let t1;
17
+ let value;
18
+ if ($[0] !== t0) {
19
+ ({value, onChange, label, widget: t1, disabled, readOnly, required, controlClassName, ...props} = t0);
20
+ $[0] = t0;
21
+ $[1] = controlClassName;
22
+ $[2] = disabled;
23
+ $[3] = label;
24
+ $[4] = onChange;
25
+ $[5] = props;
26
+ $[6] = readOnly;
27
+ $[7] = required;
28
+ $[8] = t1;
29
+ $[9] = value;
30
+ } else {
31
+ controlClassName = $[1];
32
+ disabled = $[2];
33
+ label = $[3];
34
+ onChange = $[4];
35
+ props = $[5];
36
+ readOnly = $[6];
37
+ required = $[7];
38
+ t1 = $[8];
39
+ value = $[9];
40
+ }
41
+ const widget = t1 === void 0 ? "checkbox" : t1;
42
+ const t2 = value === true;
43
+ let t3;
44
+ if ($[10] !== onChange) {
45
+ t3 = (next) => onChange?.(next);
46
+ $[10] = onChange;
47
+ $[11] = t3;
48
+ } else t3 = $[11];
49
+ let t4;
50
+ if ($[12] !== disabled || $[13] !== label || $[14] !== props || $[15] !== readOnly || $[16] !== required || $[17] !== t2 || $[18] !== t3) {
51
+ t4 = {
52
+ ...props,
53
+ isSelected: t2,
54
+ onChange: t3,
55
+ isDisabled: disabled,
56
+ isReadOnly: readOnly,
57
+ isRequired: required,
58
+ children: label
59
+ };
60
+ $[12] = disabled;
61
+ $[13] = label;
62
+ $[14] = props;
63
+ $[15] = readOnly;
64
+ $[16] = required;
65
+ $[17] = t2;
66
+ $[18] = t3;
67
+ $[19] = t4;
68
+ } else t4 = $[19];
69
+ const shared = t4;
70
+ let t5;
71
+ if ($[20] !== controlClassName || $[21] !== shared || $[22] !== widget) {
72
+ t5 = widget === "switch" ? /* @__PURE__ */ jsx(Switch, {
73
+ ...shared,
74
+ switchClassName: controlClassName
75
+ }) : /* @__PURE__ */ jsx(Checkbox, {
76
+ ...shared,
77
+ checkboxClassName: controlClassName
78
+ });
79
+ $[20] = controlClassName;
80
+ $[21] = shared;
81
+ $[22] = widget;
82
+ $[23] = t5;
83
+ } else t5 = $[23];
84
+ return t5;
24
85
  }
25
86
  /** The `boolean` type: setting `widget` (`checkbox` or `switch`). */
26
87
  function BooleanFieldEntry(props) {
@@ -1 +1 @@
1
- {"version":3,"file":"BooleanField.js","names":["_c"],"sources":["../../src/boolean/BooleanField.tsx"],"sourcesContent":["import { Checkbox, Switch } from '@panneau/ui';\n\nimport { getFieldProps, getSetting, isString } from '../shared/entry';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\n\nexport interface BooleanFieldProps extends Omit<FieldProps<boolean>, 'labelClassName'> {\n /** `checkbox` (default) for a choice saved with the form, `switch` for an on and off setting. */\n widget?: 'checkbox' | 'switch';\n controlClassName?: string;\n}\n\n/** A yes or no value, as a checkbox or a switch with its label. An empty value is `false`. */\nexport function BooleanField({\n value,\n onChange,\n label,\n widget = 'checkbox',\n disabled,\n readOnly,\n required,\n controlClassName,\n ...props\n}: BooleanFieldProps) {\n const shared = {\n ...props,\n isSelected: value === true,\n onChange: (next: boolean) => onChange?.(next),\n isDisabled: disabled,\n isReadOnly: readOnly,\n isRequired: required,\n children: label,\n };\n return widget === 'switch' ? (\n <Switch {...shared} switchClassName={controlClassName} />\n ) : (\n <Checkbox {...shared} checkboxClassName={controlClassName} />\n );\n}\n\n/** The `boolean` type: setting `widget` (`checkbox` or `switch`). */\nexport function BooleanFieldEntry(props: FieldEntryProps) {\n const widget = getSetting(props.field, 'widget', isString);\n return (\n <BooleanField\n {...getFieldProps(props)}\n value={props.value === true}\n onChange={props.onChange}\n {...(widget === 'switch' || widget === 'checkbox' ? { widget } : {})}\n />\n );\n}\n"],"mappings":";;;;;;AAYA,SAAgB,aAAa,EACzB,OACA,UACA,OACA,SAAS,YACT,UACA,UACA,UACA,kBACA,GAAG,SACe;CAClB,MAAM,SAAS;EACX,GAAG;EACH,YAAY,UAAU;EACtB,WAAW,SAAkB,WAAW,IAAI;EAC5C,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,UAAU;CACd;CACA,OAAO,WAAW,WACd,oBAAC,QAAD;EAAQ,GAAI;EAAQ,iBAAiB;CAAiB,CAAA,IAEtD,oBAAC,UAAD;EAAU,GAAI;EAAQ,mBAAmB;CAAiB,CAAA;AAElE;;AAGA,SAAO,kBAAA,OAAA;CAAA,MAAA,IAAAA,EAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,OAAA;EACY,KAAA,WAAW,MAAK,OAAQ,UAAU,QAAQ;EAAC,EAAA,KAAA,MAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAA1D,MAAA,SAAe;CAA4C,IAAA;CAAA,IAAA,EAAA,OAAA,OAAA;EAG/C,KAAA,cAAc,KAAK;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CACjB,MAAA,KAAA,MAAK,UAAW;CAAI,IAAA;CAAA,IAAA,EAAA,OAAA,QAAA;EAEtB,KAAA,WAAW,YAAY,WAAW,aAAlC,EAAA,OAA6D,IAA7D,CAA6D;EAAC,EAAA,KAAA;EAAA,EAAA,KAAA;CAAA,OAAA,KAAA,EAAA;CAAA,IAAA;CAAA,IAAA,EAAA,OAAA,MAAA,YAAA,EAAA,OAAA,MAAA,EAAA,OAAA,MAAA,EAAA,OAAA,IAAA;EAJvE,KAAA,oBAAC,cAAD;GAAa,GACL;GACG,OAAA;GACG,UAAA,MAAK;GAAS,GACnB;EAA8D,CAAA;EACrE,EAAA,KAAA,MAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,KAAA;EAAA,EAAA,MAAA;CAAA,OAAA,KAAA,EAAA;CAAA,OALF;AAKE"}
1
+ {"version":3,"file":"BooleanField.js","names":["Checkbox","Switch","getFieldProps","getSetting","isString","FieldEntryProps","FieldProps","BooleanFieldProps","Omit","widget","controlClassName","BooleanField","t0","$","_c","disabled","label","onChange","props","readOnly","required","t1","value","undefined","t2","t3","next","t4","isSelected","isDisabled","isReadOnly","isRequired","children","shared","t5","BooleanFieldEntry","field","_c"],"sources":["../../src/boolean/BooleanField.tsx"],"sourcesContent":["import { Checkbox, Switch } from '@panneau/ui';\n\nimport { getFieldProps, getSetting, isString } from '../shared/entry';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\n\nexport interface BooleanFieldProps extends Omit<FieldProps<boolean>, 'labelClassName'> {\n /** `checkbox` (default) for a choice saved with the form, `switch` for an on and off setting. */\n widget?: 'checkbox' | 'switch';\n controlClassName?: string;\n}\n\n/** A yes or no value, as a checkbox or a switch with its label. An empty value is `false`. */\nexport function BooleanField({\n value,\n onChange,\n label,\n widget = 'checkbox',\n disabled,\n readOnly,\n required,\n controlClassName,\n ...props\n}: BooleanFieldProps) {\n const shared = {\n ...props,\n isSelected: value === true,\n onChange: (next: boolean) => onChange?.(next),\n isDisabled: disabled,\n isReadOnly: readOnly,\n isRequired: required,\n children: label,\n };\n return widget === 'switch' ? (\n <Switch {...shared} switchClassName={controlClassName} />\n ) : (\n <Checkbox {...shared} checkboxClassName={controlClassName} />\n );\n}\n\n/** The `boolean` type: setting `widget` (`checkbox` or `switch`). */\nexport function BooleanFieldEntry(props: FieldEntryProps) {\n const widget = getSetting(props.field, 'widget', isString);\n return (\n <BooleanField\n {...getFieldProps(props)}\n value={props.value === true}\n onChange={props.onChange}\n {...(widget === 'switch' || widget === 'checkbox' ? { widget } : {})}\n />\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export { BooleanField, BooleanFieldEntry, type BooleanFieldProps } from './BooleanField';
1
+ export { BooleanField, BooleanFieldEntry, type BooleanFieldProps } from './BooleanField.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- .panneau-swatch-J24Ak3 {
1
+ .panneau-color-field-swatch {
2
2
  position: relative;
3
3
  display: inline-flex;
4
4
  width: 1.5rem;
@@ -8,12 +8,12 @@
8
8
  border-radius: var(--panneau-radius-sm);
9
9
  }
10
10
 
11
- .panneau-swatch-J24Ak3:focus-within {
11
+ .panneau-color-field-swatch:focus-within {
12
12
  outline: var(--panneau-focus-width) solid var(--panneau-color-focus);
13
13
  outline-offset: 2px;
14
14
  }
15
15
 
16
- .panneau-picker-b7gdnM {
16
+ .panneau-color-field-picker {
17
17
  position: absolute;
18
18
  inset: -0.5rem;
19
19
  width: calc(100% + 1rem);
@@ -24,10 +24,10 @@
24
24
  border: 0;
25
25
  }
26
26
 
27
- .panneau-picker-b7gdnM:disabled {
27
+ .panneau-color-field-picker:disabled {
28
28
  cursor: not-allowed;
29
29
  }
30
30
 
31
- .panneau-input-1t8LLx {
31
+ .panneau-color-field-input {
32
32
  font-family: var(--panneau-font-family-mono);
33
33
  }
@@ -1,5 +1,5 @@
1
- import type { FieldEntryProps } from '../shared/types';
2
- import { type TextFieldProps } from '../text/TextField';
1
+ import type { FieldEntryProps } from '../shared/types.js';
2
+ import { type TextFieldProps } from '../text/TextField.js';
3
3
  export type ColorFieldProps = Omit<TextFieldProps, 'type' | 'prefix' | 'maxLength'>;
4
4
  /**
5
5
  * Normalizes a hexadecimal color: `#` prefix, lowercase, and 3 digits expanded to 6. Returns the
@@ -1 +1 @@
1
- {"version":3,"file":"ColorField.js","names":["value","onChange","disabled","readOnly","_c","styles"],"sources":["../../src/color/ColorField.tsx"],"sourcesContent":["import { usePanneauIntl } from '@panneau/ui';\n\nimport { cx } from '../shared/cx';\nimport { getFieldProps, isString } from '../shared/entry';\nimport { messages } from '../shared/messages';\nimport type { FieldEntryProps } from '../shared/types';\nimport { TextField, type TextFieldProps } from '../text/TextField';\nimport styles from './ColorField.module.css';\n\nexport type ColorFieldProps = Omit<TextFieldProps, 'type' | 'prefix' | 'maxLength'>;\n\n/**\n * Normalizes a hexadecimal color: `#` prefix, lowercase, and 3 digits expanded to 6. Returns the\n * text as is when it isn't a hexadecimal color.\n */\nexport function normalizeColor(value: string): string {\n const trimmed = value.trim().toLowerCase();\n const digits = trimmed.replace(/^#/, '');\n if (/^[0-9a-f]{3}$/.test(digits)) {\n return `#${[...digits].map((digit) => digit + digit).join('')}`;\n }\n if (/^[0-9a-f]{6}$/.test(digits) || /^[0-9a-f]{8}$/.test(digits)) {\n return `#${digits}`;\n }\n return trimmed;\n}\n\n/**\n * A color as a hexadecimal value (`#1d4ed8`): typed, or picked with the browser's color picker.\n * The value is normalized on blur.\n */\nexport function ColorField({\n value,\n onChange,\n onBlur,\n disabled,\n readOnly,\n inputClassName,\n ...props\n}: ColorFieldProps) {\n const intl = usePanneauIntl();\n const valid = value !== null && value !== undefined && /^#[0-9a-f]{6}$/i.test(value);\n return (\n <TextField\n autoComplete=\"off\"\n {...props}\n value={value}\n onChange={onChange}\n disabled={disabled}\n readOnly={readOnly}\n inputClassName={cx(styles.input, inputClassName)}\n onBlur={() => {\n if (value !== null && value !== undefined) {\n const next = normalizeColor(value);\n if (next !== value) {\n onChange?.(next === '' ? null : next);\n }\n }\n onBlur?.();\n }}\n prefix={\n <span\n className={styles.swatch}\n style={{ backgroundColor: valid ? value : 'transparent' }}\n >\n <input\n type=\"color\"\n className={styles.picker}\n value={valid ? value.toLowerCase() : '#000000'}\n onChange={(event) => onChange?.(event.target.value)}\n disabled={disabled === true || readOnly === true}\n aria-label={intl.formatMessage(messages.pickColor)}\n />\n </span>\n }\n />\n );\n}\n\n/** The `color` type. */\nexport function ColorFieldEntry(props: FieldEntryProps) {\n return (\n <ColorField\n {...getFieldProps(props)}\n value={isString(props.value) ? props.value : null}\n onChange={props.onChange}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ColorField.js","names":["usePanneauIntl","cx","getFieldProps","isString","messages","FieldEntryProps","TextField","TextFieldProps","styles","ColorFieldProps","Omit","normalizeColor","value","trimmed","trim","toLowerCase","digits","replace","test","map","digit","join","ColorField","t0","$","_c","disabled","inputClassName","onBlur","onChange","props","readOnly","intl","t1","undefined","valid","t2","input","t3","next","t4","t5","backgroundColor","t6","t7","event","target","t8","t9","formatMessage","pickColor","t10","picker","t11","swatch","t12","ColorFieldEntry","_c","styles"],"sources":["../../src/color/ColorField.tsx"],"sourcesContent":["import { usePanneauIntl } from '@panneau/ui';\n\nimport { cx } from '../shared/cx';\nimport { getFieldProps, isString } from '../shared/entry';\nimport { messages } from '../shared/messages';\nimport type { FieldEntryProps } from '../shared/types';\nimport { TextField, type TextFieldProps } from '../text/TextField';\nimport styles from './ColorField.module.css';\n\nexport type ColorFieldProps = Omit<TextFieldProps, 'type' | 'prefix' | 'maxLength'>;\n\n/**\n * Normalizes a hexadecimal color: `#` prefix, lowercase, and 3 digits expanded to 6. Returns the\n * text as is when it isn't a hexadecimal color.\n */\nexport function normalizeColor(value: string): string {\n const trimmed = value.trim().toLowerCase();\n const digits = trimmed.replace(/^#/, '');\n if (/^[0-9a-f]{3}$/.test(digits)) {\n return `#${[...digits].map((digit) => digit + digit).join('')}`;\n }\n if (/^[0-9a-f]{6}$/.test(digits) || /^[0-9a-f]{8}$/.test(digits)) {\n return `#${digits}`;\n }\n return trimmed;\n}\n\n/**\n * A color as a hexadecimal value (`#1d4ed8`): typed, or picked with the browser's color picker.\n * The value is normalized on blur.\n */\nexport function ColorField({\n value,\n onChange,\n onBlur,\n disabled,\n readOnly,\n inputClassName,\n ...props\n}: ColorFieldProps) {\n const intl = usePanneauIntl();\n const valid = value !== null && value !== undefined && /^#[0-9a-f]{6}$/i.test(value);\n return (\n <TextField\n autoComplete=\"off\"\n {...props}\n value={value}\n onChange={onChange}\n disabled={disabled}\n readOnly={readOnly}\n inputClassName={cx(styles.input, inputClassName)}\n onBlur={() => {\n if (value !== null && value !== undefined) {\n const next = normalizeColor(value);\n if (next !== value) {\n onChange?.(next === '' ? null : next);\n }\n }\n onBlur?.();\n }}\n prefix={\n <span\n className={styles.swatch}\n style={{ backgroundColor: valid ? value : 'transparent' }}\n >\n <input\n type=\"color\"\n className={styles.picker}\n value={valid ? value.toLowerCase() : '#000000'}\n onChange={(event) => onChange?.(event.target.value)}\n disabled={disabled === true || readOnly === true}\n aria-label={intl.formatMessage(messages.pickColor)}\n />\n </span>\n }\n />\n );\n}\n\n/** The `color` type. */\nexport function ColorFieldEntry(props: FieldEntryProps) {\n return (\n <ColorField\n {...getFieldProps(props)}\n value={isString(props.value) ? props.value : null}\n onChange={props.onChange}\n />\n );\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import "./ColorField.css";
2
2
  //#region src/color/ColorField.module.css
3
- var swatch = "panneau-swatch-J24Ak3";
4
- var picker = "panneau-picker-b7gdnM";
5
- var input = "panneau-input-1t8LLx";
3
+ var swatch = "panneau-color-field-swatch";
4
+ var picker = "panneau-color-field-picker";
5
+ var input = "panneau-color-field-input";
6
6
  var ColorField_module_default = {
7
7
  swatch,
8
8
  picker,
@@ -1,2 +1,2 @@
1
- export { ColorField, ColorFieldEntry, type ColorFieldProps, normalizeColor } from './ColorField';
1
+ export { ColorField, ColorFieldEntry, type ColorFieldProps, normalizeColor } from './ColorField.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- import type { FieldEntryProps, FieldProps } from '../shared/types';
1
+ import type { FieldEntryProps, FieldProps } from '../shared/types.js';
2
2
  export interface DateFieldProps extends FieldProps<string> {
3
3
  /** Earliest date (`2026-01-01`). */
4
4
  min?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"DateField.js","names":["disabled","readOnly","required","_c"],"sources":["../../src/date/DateField.tsx"],"sourcesContent":["import { DatePicker } from '@panneau/ui';\n\nimport { toCalendarDate } from '../shared/dates';\nimport { getFieldProps, isString } from '../shared/entry';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\n\nexport interface DateFieldProps extends FieldProps<string> {\n /** Earliest date (`2026-01-01`). */\n min?: string;\n /** Latest date. */\n max?: string;\n controlClassName?: string;\n}\n\n/**\n * A date as an ISO string (`2026-10-15`), typed in the order of the locale or picked in a\n * calendar.\n */\nexport function DateField({\n value,\n onChange,\n min,\n max,\n disabled,\n readOnly,\n required,\n ...props\n}: DateFieldProps) {\n const minValue = toCalendarDate(min);\n const maxValue = toCalendarDate(max);\n return (\n <DatePicker\n {...props}\n granularity=\"day\"\n value={toCalendarDate(value)}\n onChange={(date) => onChange?.(date === null ? null : date.toString().slice(0, 10))}\n {...(minValue !== null ? { minValue } : {})}\n {...(maxValue !== null ? { maxValue } : {})}\n isDisabled={disabled}\n isReadOnly={readOnly}\n isRequired={required}\n />\n );\n}\n\n/** The `date` type. */\nexport function DateFieldEntry(props: FieldEntryProps) {\n return (\n <DateField\n {...getFieldProps(props)}\n value={isString(props.value) ? props.value : null}\n onChange={props.onChange}\n />\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DateField.js","names":["DatePicker","toCalendarDate","getFieldProps","isString","FieldEntryProps","FieldProps","DateFieldProps","min","max","controlClassName","DateField","t0","$","_c","disabled","onChange","props","readOnly","required","value","t1","minValue","t2","maxValue","t3","t4","date","toString","slice","t5","t6","t7","DateFieldEntry","_c"],"sources":["../../src/date/DateField.tsx"],"sourcesContent":["import { DatePicker } from '@panneau/ui';\n\nimport { toCalendarDate } from '../shared/dates';\nimport { getFieldProps, isString } from '../shared/entry';\nimport type { FieldEntryProps, FieldProps } from '../shared/types';\n\nexport interface DateFieldProps extends FieldProps<string> {\n /** Earliest date (`2026-01-01`). */\n min?: string;\n /** Latest date. */\n max?: string;\n controlClassName?: string;\n}\n\n/**\n * A date as an ISO string (`2026-10-15`), typed in the order of the locale or picked in a\n * calendar.\n */\nexport function DateField({\n value,\n onChange,\n min,\n max,\n disabled,\n readOnly,\n required,\n ...props\n}: DateFieldProps) {\n const minValue = toCalendarDate(min);\n const maxValue = toCalendarDate(max);\n return (\n <DatePicker\n {...props}\n granularity=\"day\"\n value={toCalendarDate(value)}\n onChange={(date) => onChange?.(date === null ? null : date.toString().slice(0, 10))}\n {...(minValue !== null ? { minValue } : {})}\n {...(maxValue !== null ? { maxValue } : {})}\n isDisabled={disabled}\n isReadOnly={readOnly}\n isRequired={required}\n />\n );\n}\n\n/** The `date` type. */\nexport function DateFieldEntry(props: FieldEntryProps) {\n return (\n <DateField\n {...getFieldProps(props)}\n value={isString(props.value) ? props.value : null}\n onChange={props.onChange}\n />\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export { DateField, DateFieldEntry, type DateFieldProps } from './DateField';
1
+ export { DateField, DateFieldEntry, type DateFieldProps } from './DateField.js';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1,4 +1,4 @@
1
- import type { FieldEntryProps, FieldProps } from '../shared/types';
1
+ import type { FieldEntryProps, FieldProps } from '../shared/types.js';
2
2
  export interface DateTimeFieldProps extends FieldProps<string> {
3
3
  /**
4
4
  * Time zone the date and time are shown and typed in, for values with an offset. Defaults to
@@ -10,28 +10,115 @@ import { getLocalTimeZone, now } from "@internationalized/date";
10
10
  * the time zone of the browser and written back in UTC. Values without one
11
11
  * (`2026-10-15T09:30:00`) are kept without one.
12
12
  */
13
- function DateTimeField({ value, onChange, timeZone = getLocalTimeZone(), withSeconds = false, disabled, readOnly, required, ...props }) {
14
- const current = toDateTime(value, timeZone);
15
- return /* @__PURE__ */ jsx(DatePicker, {
16
- ...props,
17
- granularity: withSeconds ? "second" : "minute",
18
- hideTimeZone: true,
19
- value: current,
20
- onChange: (next) => {
21
- if (next === null) {
22
- onChange?.(null);
23
- return;
24
- }
25
- if ("hour" in next) onChange?.(fromDateTime(next));
26
- },
27
- placeholderValue: current ?? now(timeZone).set({
13
+ function DateTimeField(t0) {
14
+ const $ = c(34);
15
+ let disabled;
16
+ let onChange;
17
+ let props;
18
+ let readOnly;
19
+ let required;
20
+ let t1;
21
+ let t2;
22
+ let value;
23
+ if ($[0] !== t0) {
24
+ ({value, onChange, timeZone: t1, withSeconds: t2, disabled, readOnly, required, ...props} = t0);
25
+ $[0] = t0;
26
+ $[1] = disabled;
27
+ $[2] = onChange;
28
+ $[3] = props;
29
+ $[4] = readOnly;
30
+ $[5] = required;
31
+ $[6] = t1;
32
+ $[7] = t2;
33
+ $[8] = value;
34
+ } else {
35
+ disabled = $[1];
36
+ onChange = $[2];
37
+ props = $[3];
38
+ readOnly = $[4];
39
+ required = $[5];
40
+ t1 = $[6];
41
+ t2 = $[7];
42
+ value = $[8];
43
+ }
44
+ let T0;
45
+ let t3;
46
+ let t4;
47
+ let t5;
48
+ let t6;
49
+ let t7;
50
+ let t8;
51
+ if ($[9] !== onChange || $[10] !== props || $[11] !== t1 || $[12] !== t2 || $[13] !== value) {
52
+ const timeZone = t1 === void 0 ? getLocalTimeZone() : t1;
53
+ const withSeconds = t2 === void 0 ? false : t2;
54
+ const current = toDateTime(value, timeZone);
55
+ T0 = DatePicker;
56
+ t3 = props;
57
+ t4 = withSeconds ? "second" : "minute";
58
+ t5 = true;
59
+ t6 = current;
60
+ if ($[21] !== onChange) {
61
+ t7 = (next) => {
62
+ if (next === null) {
63
+ onChange?.(null);
64
+ return;
65
+ }
66
+ if ("hour" in next) onChange?.(fromDateTime(next));
67
+ };
68
+ $[21] = onChange;
69
+ $[22] = t7;
70
+ } else t7 = $[22];
71
+ t8 = current ?? now(timeZone).set({
28
72
  second: 0,
29
73
  millisecond: 0
30
- }),
31
- isDisabled: disabled,
32
- isReadOnly: readOnly,
33
- isRequired: required
34
- });
74
+ });
75
+ $[9] = onChange;
76
+ $[10] = props;
77
+ $[11] = t1;
78
+ $[12] = t2;
79
+ $[13] = value;
80
+ $[14] = T0;
81
+ $[15] = t3;
82
+ $[16] = t4;
83
+ $[17] = t5;
84
+ $[18] = t6;
85
+ $[19] = t7;
86
+ $[20] = t8;
87
+ } else {
88
+ T0 = $[14];
89
+ t3 = $[15];
90
+ t4 = $[16];
91
+ t5 = $[17];
92
+ t6 = $[18];
93
+ t7 = $[19];
94
+ t8 = $[20];
95
+ }
96
+ let t9;
97
+ if ($[23] !== T0 || $[24] !== disabled || $[25] !== readOnly || $[26] !== required || $[27] !== t3 || $[28] !== t4 || $[29] !== t5 || $[30] !== t6 || $[31] !== t7 || $[32] !== t8) {
98
+ t9 = /* @__PURE__ */ jsx(T0, {
99
+ ...t3,
100
+ granularity: t4,
101
+ hideTimeZone: t5,
102
+ value: t6,
103
+ onChange: t7,
104
+ placeholderValue: t8,
105
+ isDisabled: disabled,
106
+ isReadOnly: readOnly,
107
+ isRequired: required
108
+ });
109
+ $[23] = T0;
110
+ $[24] = disabled;
111
+ $[25] = readOnly;
112
+ $[26] = required;
113
+ $[27] = t3;
114
+ $[28] = t4;
115
+ $[29] = t5;
116
+ $[30] = t6;
117
+ $[31] = t7;
118
+ $[32] = t8;
119
+ $[33] = t9;
120
+ } else t9 = $[33];
121
+ return t9;
35
122
  }
36
123
  /** The `datetime` type: setting `timeZone`. */
37
124
  function DateTimeFieldEntry(props) {