lutra 0.0.33 → 0.1.4

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 (274) hide show
  1. package/README.md +4 -24
  2. package/dist/components/AspectRatio.svelte +26 -0
  3. package/dist/components/AspectRatio.svelte.d.ts +8 -0
  4. package/dist/components/Avatar.svelte +105 -0
  5. package/dist/components/Avatar.svelte.d.ts +14 -0
  6. package/dist/{display → components}/Close.svelte +25 -7
  7. package/dist/components/Close.svelte.d.ts +7 -0
  8. package/dist/components/ContextTip.svelte +41 -0
  9. package/dist/components/ContextTip.svelte.d.ts +7 -0
  10. package/dist/components/Dialog.svelte +78 -0
  11. package/dist/components/Dialog.svelte.d.ts +14 -0
  12. package/dist/components/Icon.svelte +62 -0
  13. package/dist/components/Icon.svelte.d.ts +8 -0
  14. package/dist/{display → components}/IconButton.svelte +43 -14
  15. package/dist/components/IconButton.svelte.d.ts +16 -0
  16. package/dist/components/Image.svelte +172 -0
  17. package/dist/components/Image.svelte.d.ts +56 -0
  18. package/dist/{display → components}/Indicator.svelte +44 -9
  19. package/dist/components/Indicator.svelte.d.ts +12 -0
  20. package/dist/{display → components}/Inset.svelte +8 -3
  21. package/dist/components/Inset.svelte.d.ts +7 -0
  22. package/dist/components/Layout.svelte +33 -0
  23. package/dist/components/Layout.svelte.d.ts +11 -0
  24. package/dist/components/MenuDropdown.svelte +195 -0
  25. package/dist/components/MenuDropdown.svelte.d.ts +16 -0
  26. package/dist/{nav → components}/MenuItem.svelte +46 -38
  27. package/dist/components/MenuItem.svelte.d.ts +11 -0
  28. package/dist/components/MenuItemContent.svelte +25 -0
  29. package/dist/components/MenuItemContent.svelte.d.ts +10 -0
  30. package/dist/{nav → components}/MenuTypes.d.ts +19 -5
  31. package/dist/components/Modal.svelte +149 -0
  32. package/dist/components/Modal.svelte.d.ts +16 -0
  33. package/dist/{display → components}/Notification.svelte +33 -22
  34. package/dist/components/Notification.svelte.d.ts +12 -0
  35. package/dist/components/Overlay.svelte +31 -0
  36. package/dist/components/Overlay.svelte.d.ts +14 -0
  37. package/dist/{layout → components}/OverlayContainer.svelte +6 -3
  38. package/dist/{layout → components}/OverlayContainer.svelte.d.ts +4 -1
  39. package/dist/components/OverlayLayer.svelte +168 -0
  40. package/dist/components/OverlayLayer.svelte.d.ts +8 -0
  41. package/dist/components/PageContent.svelte +108 -0
  42. package/dist/components/PageContent.svelte.d.ts +38 -0
  43. package/dist/components/TabbedContent.svelte +74 -0
  44. package/dist/components/TabbedContent.svelte.d.ts +11 -0
  45. package/dist/components/TabbedContentItem.svelte +33 -0
  46. package/dist/components/TabbedContentItem.svelte.d.ts +10 -0
  47. package/dist/components/Table.svelte +41 -0
  48. package/dist/components/Table.svelte.d.ts +13 -0
  49. package/dist/{nav → components}/Tabs.svelte +99 -41
  50. package/dist/components/Tabs.svelte.d.ts +20 -0
  51. package/dist/components/Tag.svelte +120 -0
  52. package/dist/components/Tag.svelte.d.ts +21 -0
  53. package/dist/components/Theme.svelte +105 -0
  54. package/dist/components/Theme.svelte.d.ts +17 -0
  55. package/dist/{display → components}/Tooltip.svelte +41 -16
  56. package/dist/components/Tooltip.svelte.d.ts +12 -0
  57. package/dist/components/UIContent.svelte +19 -0
  58. package/dist/components/UIContent.svelte.d.ts +7 -0
  59. package/dist/components/index.d.ts +28 -0
  60. package/dist/components/index.js +29 -0
  61. package/dist/{display → components}/notifications.svelte.d.ts +1 -1
  62. package/dist/{display → components}/notifications.svelte.js +3 -4
  63. package/dist/{layout → components}/overlays.svelte.d.ts +4 -2
  64. package/dist/config.d.ts +30 -0
  65. package/dist/config.js +18 -0
  66. package/dist/css/1-props.css +440 -0
  67. package/dist/css/2-base.css +343 -0
  68. package/dist/css/3-typo.css +106 -0
  69. package/dist/css/4-layout.css +368 -0
  70. package/dist/css/5-media.css +116 -0
  71. package/dist/css/lutra.css +7 -0
  72. package/dist/css/themes/DefaultTheme.css +209 -0
  73. package/dist/form/Button.svelte +35 -16
  74. package/dist/form/Button.svelte.d.ts +8 -19
  75. package/dist/form/Datepicker.svelte +311 -0
  76. package/dist/form/Datepicker.svelte.d.ts +9 -0
  77. package/dist/form/FieldContent.svelte +69 -44
  78. package/dist/form/FieldContent.svelte.d.ts +7 -17
  79. package/dist/form/FieldError.svelte +16 -6
  80. package/dist/form/FieldError.svelte.d.ts +4 -15
  81. package/dist/form/Fieldset.svelte +48 -13
  82. package/dist/form/Fieldset.svelte.d.ts +5 -16
  83. package/dist/form/Form.svelte +158 -74
  84. package/dist/form/Form.svelte.d.ts +17 -17
  85. package/dist/form/{FieldActions.svelte → FormActions.svelte} +29 -17
  86. package/dist/form/FormActions.svelte.d.ts +9 -0
  87. package/dist/form/FormSection.svelte +96 -0
  88. package/dist/form/FormSection.svelte.d.ts +9 -0
  89. package/dist/form/ImageUpload.svelte +134 -94
  90. package/dist/form/ImageUpload.svelte.d.ts +5 -16
  91. package/dist/form/Input.svelte +254 -136
  92. package/dist/form/Input.svelte.d.ts +12 -21
  93. package/dist/form/InputLength.svelte +15 -5
  94. package/dist/form/InputLength.svelte.d.ts +4 -15
  95. package/dist/form/Label.svelte +55 -11
  96. package/dist/form/Label.svelte.d.ts +6 -15
  97. package/dist/form/LogoUpload.svelte +36 -21
  98. package/dist/form/LogoUpload.svelte.d.ts +4 -15
  99. package/dist/form/Select.svelte +100 -50
  100. package/dist/form/Select.svelte.d.ts +5 -16
  101. package/dist/form/Textarea.svelte +200 -98
  102. package/dist/form/Textarea.svelte.d.ts +11 -24
  103. package/dist/form/Toggle.svelte +3 -1
  104. package/dist/form/Toggle.svelte.d.ts +4 -1
  105. package/dist/form/client.svelte.d.ts +1 -0
  106. package/dist/form/client.svelte.js +6 -2
  107. package/dist/form/form.d.ts +10 -9
  108. package/dist/form/form.js +37 -32
  109. package/dist/form/index.d.ts +3 -4
  110. package/dist/form/index.js +3 -4
  111. package/dist/form/types.d.ts +9 -16
  112. package/dist/icons/IconAlert.svelte.d.ts +4 -1
  113. package/dist/icons/IconCopy.svelte.d.ts +4 -1
  114. package/dist/icons/IconDone.svelte.d.ts +4 -1
  115. package/dist/icons/IconError.svelte.d.ts +4 -1
  116. package/dist/icons/IconHelp.svelte.d.ts +4 -1
  117. package/dist/icons/IconHide.svelte.d.ts +4 -1
  118. package/dist/icons/IconInfo.svelte.d.ts +4 -1
  119. package/dist/icons/IconLink.svelte.d.ts +4 -1
  120. package/dist/icons/IconMenuBurger.svelte.d.ts +4 -1
  121. package/dist/icons/IconMenuDots.svelte.d.ts +4 -1
  122. package/dist/icons/IconSearch.svelte.d.ts +4 -1
  123. package/dist/icons/IconShow.svelte.d.ts +4 -1
  124. package/dist/icons/IconSuccess.svelte.d.ts +4 -1
  125. package/dist/icons/IconWarning.svelte.d.ts +4 -1
  126. package/dist/index.d.ts +3 -1
  127. package/dist/index.js +3 -2
  128. package/dist/types.d.ts +39 -0
  129. package/dist/types.js +25 -0
  130. package/dist/util/StringOrComponent.svelte +20 -0
  131. package/dist/util/StringOrComponent.svelte.d.ts +8 -0
  132. package/dist/util/StringOrSnippet.svelte +16 -0
  133. package/dist/util/StringOrSnippet.svelte.d.ts +8 -0
  134. package/dist/{utils → util}/dom.js +1 -2
  135. package/dist/util/locale.d.ts +1 -0
  136. package/dist/util/locale.js +47 -0
  137. package/dist/util/settings.d.ts +4 -0
  138. package/package.json +35 -79
  139. package/dist/color.css +0 -0
  140. package/dist/display/Avatar.svelte +0 -61
  141. package/dist/display/Avatar.svelte.d.ts +0 -19
  142. package/dist/display/Badge.svelte +0 -91
  143. package/dist/display/Badge.svelte.d.ts +0 -30
  144. package/dist/display/Callout.svelte +0 -109
  145. package/dist/display/Callout.svelte.d.ts +0 -28
  146. package/dist/display/Close.svelte.d.ts +0 -18
  147. package/dist/display/Code.svelte +0 -190
  148. package/dist/display/Code.svelte.d.ts +0 -32
  149. package/dist/display/ContextTip.svelte +0 -23
  150. package/dist/display/ContextTip.svelte.d.ts +0 -18
  151. package/dist/display/DataList.svelte +0 -16
  152. package/dist/display/DataList.svelte.d.ts +0 -21
  153. package/dist/display/Details.svelte +0 -49
  154. package/dist/display/Details.svelte.d.ts +0 -27
  155. package/dist/display/Hero.svelte +0 -50
  156. package/dist/display/Hero.svelte.d.ts +0 -26
  157. package/dist/display/Icon.svelte +0 -39
  158. package/dist/display/Icon.svelte.d.ts +0 -19
  159. package/dist/display/IconButton.svelte.d.ts +0 -27
  160. package/dist/display/Image.svelte +0 -91
  161. package/dist/display/Image.svelte.d.ts +0 -26
  162. package/dist/display/Indicator.svelte.d.ts +0 -23
  163. package/dist/display/Inset.svelte.d.ts +0 -18
  164. package/dist/display/LineChart.svelte +0 -385
  165. package/dist/display/LineChart.svelte.d.ts +0 -24
  166. package/dist/display/LoadingIndicator.svelte +0 -33
  167. package/dist/display/LoadingIndicator.svelte.d.ts +0 -15
  168. package/dist/display/Modal.svelte +0 -116
  169. package/dist/display/Modal.svelte.d.ts +0 -27
  170. package/dist/display/Notification.svelte.d.ts +0 -23
  171. package/dist/display/Panel.svelte +0 -23
  172. package/dist/display/Panel.svelte.d.ts +0 -19
  173. package/dist/display/Popup.svelte +0 -111
  174. package/dist/display/Popup.svelte.d.ts +0 -25
  175. package/dist/display/Stat.svelte +0 -81
  176. package/dist/display/Stat.svelte.d.ts +0 -30
  177. package/dist/display/Table.svelte +0 -28
  178. package/dist/display/Table.svelte.d.ts +0 -24
  179. package/dist/display/TablePaginator.svelte +0 -51
  180. package/dist/display/TablePaginator.svelte.d.ts +0 -21
  181. package/dist/display/Tag.svelte +0 -90
  182. package/dist/display/Tag.svelte.d.ts +0 -32
  183. package/dist/display/Tooltip.svelte.d.ts +0 -23
  184. package/dist/display/chart.d.ts +0 -78
  185. package/dist/display/chart.js +0 -212
  186. package/dist/display/index.d.ts +0 -24
  187. package/dist/display/index.js +0 -24
  188. package/dist/form/FieldActions.svelte.d.ts +0 -20
  189. package/dist/form/FieldContainer.svelte +0 -37
  190. package/dist/form/FieldContainer.svelte.d.ts +0 -19
  191. package/dist/form/FieldSection.svelte +0 -86
  192. package/dist/form/FieldSection.svelte.d.ts +0 -20
  193. package/dist/layout/Layout.svelte +0 -47
  194. package/dist/layout/Layout.svelte.d.ts +0 -22
  195. package/dist/layout/LayoutFooter.svelte +0 -21
  196. package/dist/layout/LayoutFooter.svelte.d.ts +0 -18
  197. package/dist/layout/LayoutGrid.svelte +0 -51
  198. package/dist/layout/LayoutGrid.svelte.d.ts +0 -27
  199. package/dist/layout/LayoutHeader.svelte +0 -97
  200. package/dist/layout/LayoutHeader.svelte.d.ts +0 -34
  201. package/dist/layout/LayoutSideMenu.svelte +0 -55
  202. package/dist/layout/LayoutSideMenu.svelte.d.ts +0 -21
  203. package/dist/layout/LayoutTypes.d.ts +0 -15
  204. package/dist/layout/LayoutTypes.js +0 -9
  205. package/dist/layout/Overlay.svelte +0 -20
  206. package/dist/layout/Overlay.svelte.d.ts +0 -25
  207. package/dist/layout/OverlayLayer.svelte +0 -140
  208. package/dist/layout/OverlayLayer.svelte.d.ts +0 -19
  209. package/dist/layout/PageContent.svelte +0 -82
  210. package/dist/layout/PageContent.svelte.d.ts +0 -25
  211. package/dist/layout/Theme.svelte +0 -243
  212. package/dist/layout/Theme.svelte.d.ts +0 -19
  213. package/dist/layout/UIContent.svelte +0 -15
  214. package/dist/layout/UIContent.svelte.d.ts +0 -18
  215. package/dist/layout/index.d.ts +0 -11
  216. package/dist/layout/index.js +0 -11
  217. package/dist/nav/Breadcrumb.svelte +0 -82
  218. package/dist/nav/Breadcrumb.svelte.d.ts +0 -28
  219. package/dist/nav/Menu.svelte +0 -170
  220. package/dist/nav/Menu.svelte.d.ts +0 -27
  221. package/dist/nav/MenuItem.svelte.d.ts +0 -22
  222. package/dist/nav/NavMenu.svelte +0 -181
  223. package/dist/nav/NavMenu.svelte.d.ts +0 -19
  224. package/dist/nav/TabbedContent.svelte +0 -43
  225. package/dist/nav/TabbedContent.svelte.d.ts +0 -23
  226. package/dist/nav/Tabs.svelte.d.ts +0 -25
  227. package/dist/nav/index.d.ts +0 -7
  228. package/dist/nav/index.js +0 -6
  229. package/dist/style.css +0 -950
  230. package/dist/typo/Clamp.svelte +0 -25
  231. package/dist/typo/Clamp.svelte.d.ts +0 -24
  232. package/dist/typo/H.svelte +0 -52
  233. package/dist/typo/H.svelte.d.ts +0 -28
  234. package/dist/typo/H1.svelte +0 -14
  235. package/dist/typo/H1.svelte.d.ts +0 -26
  236. package/dist/typo/H2.svelte +0 -14
  237. package/dist/typo/H2.svelte.d.ts +0 -26
  238. package/dist/typo/H3.svelte +0 -14
  239. package/dist/typo/H3.svelte.d.ts +0 -26
  240. package/dist/typo/H4.svelte +0 -14
  241. package/dist/typo/H4.svelte.d.ts +0 -26
  242. package/dist/typo/H5.svelte +0 -14
  243. package/dist/typo/H5.svelte.d.ts +0 -26
  244. package/dist/typo/H6.svelte +0 -14
  245. package/dist/typo/H6.svelte.d.ts +0 -26
  246. package/dist/typo/P.svelte +0 -34
  247. package/dist/typo/P.svelte.d.ts +0 -26
  248. package/dist/typo/index.d.ts +0 -9
  249. package/dist/typo/index.js +0 -9
  250. package/dist/utils/StringOrComponent.svelte +0 -14
  251. package/dist/utils/StringOrComponent.svelte.d.ts +0 -19
  252. package/dist/utils/StringOrSnippet.svelte +0 -11
  253. package/dist/utils/StringOrSnippet.svelte.d.ts +0 -19
  254. package/dist/utils/defaults.d.ts +0 -4
  255. package/dist/utils/hooks.server.d.ts +0 -2
  256. package/dist/utils/hooks.server.js +0 -16
  257. package/dist/utils/id.d.ts +0 -1
  258. package/dist/utils/id.js +0 -3
  259. package/dist/utils/index.d.ts +0 -9
  260. package/dist/utils/index.js +0 -6
  261. package/dist/utils/isSnippet.d.ts +0 -3
  262. package/dist/utils/isSnippet.js +0 -11
  263. /package/dist/{nav → components}/MenuTypes.js +0 -0
  264. /package/dist/{layout → components}/overlays.svelte.js +0 -0
  265. /package/dist/{utils → util}/attr.d.ts +0 -0
  266. /package/dist/{utils → util}/attr.js +0 -0
  267. /package/dist/{utils → util}/color.d.ts +0 -0
  268. /package/dist/{utils → util}/color.js +0 -0
  269. /package/dist/{utils → util}/dom.d.ts +0 -0
  270. /package/dist/{utils → util}/keyboard.svelte.d.ts +0 -0
  271. /package/dist/{utils → util}/keyboard.svelte.js +0 -0
  272. /package/dist/{utils/defaults.js → util/settings.js} +0 -0
  273. /package/dist/{utils → util}/transitions.d.ts +0 -0
  274. /package/dist/{utils → util}/transitions.js +0 -0
@@ -1,18 +1,7 @@
1
- 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> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: Props & {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports;
9
- z_$$bindings?: Bindings;
10
- }
11
- declare const FieldError: $$__sveltets_2_IsomorphicComponent<{
1
+ type $$ComponentProps = {
12
2
  code: string;
13
3
  message?: string;
14
- }, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, "">;
17
- type FieldError = InstanceType<typeof FieldError>;
4
+ };
5
+ declare const FieldError: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type FieldError = ReturnType<typeof FieldError>;
18
7
  export default FieldError;
@@ -1,16 +1,51 @@
1
- <script lang="ts">let {
2
- fullWidth,
3
- description,
4
- contained,
5
- rounded,
6
- legend,
7
- columns = 1,
8
- children
9
- } = $props();
10
- let columnsArray = Array.isArray(columns) ? columns : [columns, columns, columns];
11
- let lgColumns = columnsArray[0];
12
- let mdColumns = columnsArray[1] || lgColumns;
13
- let smColumns = columnsArray[2] || mdColumns;
1
+ <script lang="ts">
2
+ import { getContext, type Snippet } from "svelte";
3
+
4
+ /**
5
+ * @description
6
+ * A fieldset is a group of related form elements that can be disabled or enabled.
7
+ * @example
8
+ * <script>
9
+ * import Input from "lutra/Input.svelte";
10
+ * <\/script>
11
+ * <Fieldset legend="Personal Information">
12
+ * <Input label="First Name" />
13
+ * <Input label="Last Name" />
14
+ * </Fieldset>
15
+ */
16
+
17
+ let {
18
+ fullWidth,
19
+ description,
20
+ contained,
21
+ rounded,
22
+ legend,
23
+ columns = 1,
24
+ children,
25
+ }: {
26
+ /** Whether the fieldset should be full width. */
27
+ fullWidth?: boolean;
28
+ /** The description of the fieldset. */
29
+ description?: string | Snippet;
30
+ /** Whether the fieldset should be contained. */
31
+ contained?: boolean;
32
+ /** Whether the fieldset should be rounded. */
33
+ rounded?: boolean;
34
+ /** The legend of the fieldset. */
35
+ legend?: string | Snippet;
36
+ /** The number of columns to display the fieldset in. You can pass a single number or an array of numbers. The array will be used to set the number of columns at different breakpoints (lg, md, sm). */
37
+ columns?: number | [number] | [number, number] | [number, number, number];
38
+ /** Content to be rendered inside the fieldset. */
39
+ children: Snippet;
40
+ } = $props();
41
+
42
+ if(contained === undefined) { contained = getContext('lutra.form.contained') ?? getContext('lutra.contained') ?? false; }
43
+
44
+ let columnsArray = Array.isArray(columns) ? columns : [columns, columns, columns];
45
+ let lgColumns = columnsArray[0];
46
+ let mdColumns = columnsArray[1] || lgColumns;
47
+ let smColumns = columnsArray[2] || mdColumns;
48
+
14
49
  </script>
15
50
 
16
51
  <div class="FieldsetContainer">
@@ -1,15 +1,5 @@
1
- import type { Snippet } from "svelte";
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
- z_$$bindings?: Bindings;
11
- }
12
- declare const Fieldset: $$__sveltets_2_IsomorphicComponent<{
1
+ import { type Snippet } from "svelte";
2
+ type $$ComponentProps = {
13
3
  /** Whether the fieldset should be full width. */
14
4
  fullWidth?: boolean;
15
5
  /** The description of the fieldset. */
@@ -24,8 +14,7 @@ declare const Fieldset: $$__sveltets_2_IsomorphicComponent<{
24
14
  columns?: number | [number] | [number, number] | [number, number, number];
25
15
  /** Content to be rendered inside the fieldset. */
26
16
  children: Snippet;
27
- }, {
28
- [evt: string]: CustomEvent<any>;
29
- }, {}, {}, "">;
30
- type Fieldset = InstanceType<typeof Fieldset>;
17
+ };
18
+ declare const Fieldset: import("svelte").Component<$$ComponentProps, {}, "">;
19
+ type Fieldset = ReturnType<typeof Fieldset>;
31
20
  export default Fieldset;
@@ -1,65 +1,148 @@
1
- <script lang="ts">import { enhance } from "$app/forms";
2
- import UiContent from "../layout/UIContent.svelte";
3
- import { Bodyguard } from "@auth70/bodyguard";
4
- import { onMount, setContext } from "svelte";
5
- import { get } from "svelte/store";
6
- import { dezerialize } from "@auth70/zodex-esm";
7
- import { array } from "zod";
8
- import { arrayPathToStringPath, getIndividualValidators, parseFormIssues } from "./form.js";
9
- import { useForm } from "./client.svelte.js";
10
- let {
11
- name = "form",
12
- form: _form,
13
- action,
14
- enctype = "multipart/form-data",
15
- method = "POST",
16
- beforeSubmit,
17
- fullWidth = false,
18
- onResult,
19
- resetOnUpdate,
20
- children
21
- } = $props();
22
- let form = $state(_form ? useForm(_form) : null);
23
- setContext("form", form);
24
- setContext("form.validators", form ? getIndividualValidators(form) : null);
25
- const beforeSubmitFunctions = [];
26
- const addBeforeSubmit = (id, fn) => {
27
- if (beforeSubmitFunctions.find((f) => f.id === id)) {
28
- return;
29
- }
30
- beforeSubmitFunctions.push({ id, fn });
31
- };
32
- setContext("form.beforeSubmit", addBeforeSubmit);
33
- const schema = form?.schema ? dezerialize(form?.schema) : null;
34
- const bodyguard = new Bodyguard();
35
- let formEl;
36
- function setFormIssuesAndFields(issues, fields) {
37
- console.log("setFormIssuesAndFields", issues, fields);
38
- if (form) {
39
- form.issues = issues;
40
- form.fields = fields;
41
- }
42
- }
43
- async function validate() {
44
- if (form && schema) {
45
- form.tainted = true;
46
- const req = new Request("localhost", {
47
- method: "POST",
48
- body: new FormData(formEl)
49
- });
50
- const result = await bodyguard.softForm(req, schema.parse);
51
- if (result.success === true) {
52
- form.valid = true;
53
- form.issues = [];
54
- } else {
55
- form.valid = false;
56
- form.issues = parseFormIssues(result.error.issues);
1
+ <script lang="ts">
2
+ import { enhance } from "$app/forms";
3
+ import { goto } from '$app/navigation';
4
+ import UiContent from "../components/UIContent.svelte";
5
+ import { Bodyguard, type BodyguardValidator } from "@auth70/bodyguard";
6
+ import type { ActionResult } from "@sveltejs/kit";
7
+ import { onMount, setContext } from "svelte";
8
+ import type { Snippet } from "svelte";
9
+ import { dezerialize } from "zodex";
10
+ import type { AddBeforeSubmitFn, BeforeSubmitFn, LutraForm } from "./types.js";
11
+ import { type ZodObject } from "zod";
12
+ import { getIndividualValidators, parseFormIssues } from "./form.js";
13
+ import { useForm } from "./client.svelte.js";
14
+
15
+ let {
16
+ name = 'form',
17
+ form: _form,
18
+ formEl = $bindable(null),
19
+ action,
20
+ enctype = "multipart/form-data",
21
+ method = "POST",
22
+ beforesubmit,
23
+ fullWidth = false,
24
+ onresult,
25
+ resetOnUpdate,
26
+ children,
27
+ contained,
28
+ spacing,
29
+ actionGap,
30
+ fieldGap,
31
+ labelGap,
32
+ titleGap,
33
+ sectionGap,
34
+ padding,
35
+ paddingBlock,
36
+ paddingInline,
37
+ }: {
38
+ name?: string;
39
+ form?: LutraForm<any>;
40
+ formEl?: HTMLFormElement | null;
41
+ action?: string;
42
+ enctype?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain";
43
+ method?: "GET" | "POST";
44
+ beforesubmit?: BeforeSubmitFn;
45
+ fullWidth?: boolean;
46
+ resetOnUpdate?: boolean;
47
+ onresult?: (args: {
48
+ formData: FormData;
49
+ formElement: HTMLFormElement;
50
+ action: URL;
51
+ result: ActionResult<Record<string, unknown> | undefined, Record<string, unknown> | undefined>;
52
+ update: (options?: {
53
+ reset?: boolean | undefined;
54
+ invalidateAll?: boolean | undefined;
55
+ } | undefined) => void;
56
+ }) => void;
57
+ children: Snippet;
58
+ contained?: boolean;
59
+ spacing?: string;
60
+ actionGap?: string;
61
+ fieldGap?: string;
62
+ labelGap?: string;
63
+ titleGap?: string;
64
+ sectionGap?: string;
65
+ padding?: string;
66
+ paddingBlock?: string;
67
+ paddingInline?: string;
68
+ } = $props();
69
+
70
+ let form = $state(_form ? useForm(_form) : null);
71
+
72
+ setContext('form', form);
73
+ setContext('form.validators', form ? getIndividualValidators(form) : null);
74
+
75
+ const beforesubmitFunctions: { id: string, fn: BeforeSubmitFn }[] = [];
76
+ const addBeforeSubmit: AddBeforeSubmitFn = (id, fn) => {
77
+ if(beforesubmitFunctions.find((f) => f.id === id)) {
78
+ return;
79
+ }
80
+ beforesubmitFunctions.push({ id, fn });
57
81
  }
58
- }
59
- }
60
- onMount(() => {
61
- validate();
62
- });
82
+ setContext('form.beforesubmit', addBeforeSubmit);
83
+
84
+ const schema = form?.schema ? dezerialize(form?.schema) as ZodObject<any> : null;
85
+ const bodyguard = new Bodyguard();
86
+
87
+ function setFormIssuesAndFields(issues: any, fields: any) {
88
+ console.log('setFormIssuesAndFields', issues, fields)
89
+ if(form) {
90
+ form.issues = issues;
91
+ form.fields = fields;
92
+ }
93
+ }
94
+
95
+ async function validate() {
96
+ if(form && schema) {
97
+ form.tainted = true;
98
+ const req = new Request('localhost', {
99
+ method: 'POST',
100
+ body: new FormData(formEl!),
101
+ });
102
+ const result = await bodyguard.softForm(req, schema.parse as BodyguardValidator);
103
+ if(result.success === true) {
104
+ form.valid = true;
105
+ form.issues = [];
106
+ } else {
107
+ form.valid = false;
108
+ form.issues = parseFormIssues((result.error as any).issues);
109
+ }
110
+ }
111
+ }
112
+
113
+ onMount(() => {
114
+ validate();
115
+ });
116
+
117
+ const styleParams = {
118
+ actionGap,
119
+ fieldGap,
120
+ labelGap,
121
+ titleGap,
122
+ sectionGap,
123
+ padding,
124
+ paddingBlock,
125
+ paddingInline,
126
+ };
127
+
128
+ const style = `
129
+ ${actionGap ? `--form-action-gap: ${actionGap};` : ''}
130
+ ${fieldGap ? `--form-field-gap: ${fieldGap};` : ''}
131
+ ${labelGap ? `--form-label-gap: ${labelGap};` : ''}
132
+ ${titleGap ? `--form-title-gap: ${titleGap};` : ''}
133
+ ${sectionGap ? `--form-section-gap: ${sectionGap};` : ''}
134
+ ${
135
+ paddingBlock || paddingInline
136
+ ? `
137
+ ${paddingBlock ? `--form-padding-block: ${paddingBlock};` : ''}
138
+ ${paddingInline ? `--form-padding-inline: ${paddingInline};` : ''}
139
+ `
140
+ : padding
141
+ ? `--form-padding-block: ${padding}; --form-padding-inline: ${padding};`
142
+ : ''
143
+ }
144
+ `;
145
+
63
146
  </script>
64
147
 
65
148
  <UiContent>
@@ -67,6 +150,7 @@ onMount(() => {
67
150
  {method}
68
151
  {action}
69
152
  {enctype}
153
+ style={style}
70
154
  bind:this={formEl}
71
155
  onchange={validate}
72
156
  use:enhance={async ({ formElement, formData, action, cancel, submitter }) => {
@@ -76,12 +160,12 @@ onMount(() => {
76
160
  // calling `cancel()` will prevent the submission
77
161
  // `submitter` is the `HTMLElement` that caused the form to be submitted
78
162
  if(form) form.state = 'loading';
79
- //await Promise.resolve(beforeSubmit(form));
80
- if(beforeSubmit) await Promise.resolve(beforeSubmit({ form: formElement, data: formData, cancel: () => {
163
+ //await Promise.resolve(beforesubmit(form));
164
+ if(beforesubmit) await Promise.resolve(beforesubmit({ form: formElement, data: formData, cancel: () => {
81
165
  if(form) form.state = 'error';
82
166
  cancel();
83
167
  }}));
84
- for(const { id, fn } of beforeSubmitFunctions) {
168
+ for(const { id, fn } of beforesubmitFunctions) {
85
169
  await Promise.resolve(fn({ form: formElement, data: formData, cancel: () => {
86
170
  if(form) form.state = 'error';
87
171
  cancel();
@@ -93,21 +177,21 @@ onMount(() => {
93
177
  // `result` is an `ActionResult` object
94
178
  // `update` is a function which triggers the default logic that would be triggered if this callback wasn't set
95
179
  console.log('form result', opts);
96
- if(onResult) {
97
- console.log('calling onResult')
98
- onResult(opts);
180
+ if(onresult) {
181
+ console.log('calling onresult', opts);
182
+ onresult(opts);
99
183
  }
100
184
  const resultForm = result.type !== "redirect" && result.type !== "error" ? result?.data![name] : null;
101
- console.log('resultForm', resultForm, form)
185
+ console.log('resultForm', resultForm, form);
102
186
  if(result.type === "success") {
103
187
  if(resultForm && form) {
104
188
  form.valid = Object.assign({ valid: false }, resultForm).valid ?? false;
105
189
  }
106
190
  if(form) form.state = 'success';
107
- console.log('form state', form?.state);
191
+ console.log('form state', form?.state, resetOnUpdate, opts);
108
192
  update({ reset: !!resetOnUpdate });
109
193
  } else if(result.type === "failure") {
110
- console.log('FAILURE')
194
+ console.log('FAILURE', opts);
111
195
  if(resultForm && form) {
112
196
  console.log('setting form issues and fields')
113
197
  setFormIssuesAndFields(
@@ -117,11 +201,13 @@ onMount(() => {
117
201
  }
118
202
  if(form) form.state = 'error';
119
203
  } else if(result.type === "error") {
120
- console.error('[lutra] Error from form enhance call', result.error);
204
+ console.error('[lutra] Error from form enhance call', result.error, opts);
121
205
  if(form) form.state = 'error';
122
206
  } else if(result.type === "redirect") {
123
- window.location.href = result.location;
207
+ console.log('redirect', opts);
208
+ //window.location.href = result.location;
124
209
  if(form) form.state = 'success';
210
+ await goto(result.location);
125
211
  }
126
212
  };
127
213
  }}
@@ -131,6 +217,4 @@ onMount(() => {
131
217
  </UiContent>
132
218
 
133
219
  <style>
134
- form {
135
- }
136
220
  </style>
@@ -1,26 +1,17 @@
1
1
  import type { ActionResult } from "@sveltejs/kit";
2
2
  import type { Snippet } from "svelte";
3
3
  import type { BeforeSubmitFn, LutraForm } from "./types.js";
4
- 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> {
5
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
- $$bindings?: Bindings;
7
- } & Exports;
8
- (internal: unknown, props: Props & {
9
- $$events?: Events;
10
- $$slots?: Slots;
11
- }): Exports;
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const Form: $$__sveltets_2_IsomorphicComponent<{
4
+ type $$ComponentProps = {
15
5
  name?: string;
16
6
  form?: LutraForm<any>;
7
+ formEl?: HTMLFormElement | null;
17
8
  action?: string;
18
9
  enctype?: "application/x-www-form-urlencoded" | "multipart/form-data" | "text/plain";
19
10
  method?: "GET" | "POST";
20
- beforeSubmit?: BeforeSubmitFn;
11
+ beforesubmit?: BeforeSubmitFn;
21
12
  fullWidth?: boolean;
22
13
  resetOnUpdate?: boolean;
23
- onResult?: (args: {
14
+ onresult?: (args: {
24
15
  formData: FormData;
25
16
  formElement: HTMLFormElement;
26
17
  action: URL;
@@ -31,8 +22,17 @@ declare const Form: $$__sveltets_2_IsomorphicComponent<{
31
22
  } | undefined) => void;
32
23
  }) => void;
33
24
  children: Snippet;
34
- }, {
35
- [evt: string]: CustomEvent<any>;
36
- }, {}, {}, "">;
37
- type Form = InstanceType<typeof Form>;
25
+ contained?: boolean;
26
+ spacing?: string;
27
+ actionGap?: string;
28
+ fieldGap?: string;
29
+ labelGap?: string;
30
+ titleGap?: string;
31
+ sectionGap?: string;
32
+ padding?: string;
33
+ paddingBlock?: string;
34
+ paddingInline?: string;
35
+ };
36
+ declare const Form: import("svelte").Component<$$ComponentProps, {}, "formEl">;
37
+ type Form = ReturnType<typeof Form>;
38
38
  export default Form;
@@ -1,12 +1,21 @@
1
- <script lang="ts">import StringOrSnippet from "../utils/StringOrSnippet.svelte";
2
- let {
3
- align = "end",
4
- children,
5
- info
6
- } = $props();
1
+ <script lang="ts">
2
+ import StringOrSnippet from "../util/StringOrSnippet.svelte";
3
+ import { setContext, type Snippet } from "svelte";
4
+
5
+ let {
6
+ align = 'end',
7
+ children,
8
+ info,
9
+ }: {
10
+ align?: 'justified' | 'start' | 'center' | 'end' | 'full';
11
+ children: Snippet;
12
+ info?: string | Snippet;
13
+ } = $props();
14
+
15
+ setContext('form.actions.align', align);
7
16
  </script>
8
17
 
9
- <div class="FieldActions {align}" class:hasInfo={!!info}>
18
+ <div class="FormActions {align}" class:hasInfo={!!info}>
10
19
  {#if info}
11
20
  <div class="Info">
12
21
  <StringOrSnippet content={info} />
@@ -18,10 +27,10 @@ let {
18
27
  </div>
19
28
 
20
29
  <style>
21
- .FieldActions {
30
+ .FormActions {
22
31
  display: grid;
23
- background: color-mix(in srgb, var(--bg-subtle) calc(var(--fcc) * 100%), transparent);
24
- padding: calc(1.5em * var(--fcc)) calc(3em * var(--fcc));
32
+ background: color-mix(in srgb, var(--form-background-actions) calc(var(--fcc) * 100%), transparent);
33
+ padding: calc(var(--space-md) * var(--fcc)) calc(var(--space-lg) * var(--fcc));
25
34
  grid-column: 1 / -1;
26
35
  grid-template-columns: subgrid;
27
36
  border-bottom-left-radius: inherit;
@@ -33,28 +42,31 @@ let {
33
42
  flex-direction: row;
34
43
  align-items: center;
35
44
  justify-content: space-between;
36
- gap: 1.35em;
45
+ gap: var(--space-md);
37
46
  grid-column: 2 / -1;
38
47
  }
39
- .FieldActions.start .Actions {
48
+ .FormActions.start .Actions {
40
49
  justify-content: start;
41
50
  grid-column: 1 / -1;
42
51
  }
43
- .FieldActions.middle .Actions {
52
+ .FormActions.center .Actions {
44
53
  justify-content: center;
45
54
  grid-column: 1 / -1;
46
55
  }
47
- .FieldActions.end .Actions {
56
+ .FormActions.end .Actions {
48
57
  justify-content: end;
49
58
  grid-column: 1 / -1;
50
59
  }
51
- .FieldActions.hasInfo .Actions {
60
+ .FormActions.hasInfo .Actions {
52
61
  grid-column: 2 / -1;
53
62
  }
63
+ .FormActions.full .Actions {
64
+ grid-column: 1 / -1;
65
+ }
54
66
  @container (max-width: 480px) {
55
- .FieldActions {
67
+ .FormActions {
56
68
  justify-content: center;
57
- gap: 1rem;
69
+ gap: var(--space-sm);
58
70
  }
59
71
  .Info {
60
72
  order: 1;
@@ -0,0 +1,9 @@
1
+ import { type Snippet } from "svelte";
2
+ type $$ComponentProps = {
3
+ align?: 'justified' | 'start' | 'center' | 'end' | 'full';
4
+ children: Snippet;
5
+ info?: string | Snippet;
6
+ };
7
+ declare const FormActions: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type FormActions = ReturnType<typeof FormActions>;
9
+ export default FormActions;
@@ -0,0 +1,96 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from "svelte";
3
+
4
+ /**
5
+ * @description
6
+ * A field section is a group of related form elements.
7
+ */
8
+ let {
9
+ title,
10
+ description,
11
+ children,
12
+ }: {
13
+ title?: string | Snippet;
14
+ description?: string | Snippet;
15
+ children: Snippet;
16
+ } = $props();
17
+ </script>
18
+
19
+ <div class="FormSection" class:noTitle={!title && !description}>
20
+ {#if title || description}
21
+ <div class="FormSectionTitle">
22
+ {#if title}
23
+ {#if typeof title === "string"}
24
+ <h5>{title}</h5>
25
+ {:else}
26
+ {@render title()}
27
+ {/if}
28
+ {/if}
29
+ {#if description}
30
+ {#if typeof description === "string"}
31
+ <small>{description}</small>
32
+ {:else}
33
+ {@render description()}
34
+ {/if}
35
+ {/if}
36
+ </div>
37
+ {/if}
38
+ <div class="FormSectionContent">
39
+ {@render children()}
40
+ </div>
41
+ </div>
42
+
43
+ <style>
44
+ .FormSection {
45
+ padding: 0;
46
+ display: grid;
47
+ grid-template-columns: subgrid;
48
+ grid-column: 1 / -1;
49
+ padding-block: calc(var(--fcc) * var(--form-padding-block));
50
+ padding-inline: calc(var(--fcc) * var(--form-padding-inline));
51
+ gap: var(--form-section-gap, var(--space-lg));
52
+ }
53
+ .FormSectionTitle {
54
+ display: flex;
55
+ flex-direction: column;
56
+ background-color: var(--base);
57
+ gap: var(--form-title-gap, var(--space-md));
58
+ text-wrap: balance;
59
+ }
60
+ .FormSection:not(:first-child) {
61
+ border-top: calc(var(--fcc) * var(--border-size)) var(--border-style) var(--border-color);
62
+ }
63
+ .FormSectionContent {
64
+ display: grid;
65
+ gap: var(--form-field-gap, var(--space-lg));
66
+ }
67
+ .FormSection.noTitle .FormSectionContent {
68
+ grid-column: 1 / -1;
69
+ }
70
+ @media(max-width: 1280px) {
71
+ .FormSection {
72
+ padding: var(--space-lg);
73
+ gap: var(--space-md);
74
+ }
75
+ .FormSectionTitle {
76
+ gap: var(--space-sm);
77
+ padding-block-end: var(--space-md);
78
+ }
79
+ }
80
+ @media(max-width: 640px) {
81
+ .FormSection {
82
+ padding: var(--space-md);
83
+ gap: var(--space-md);
84
+ }
85
+ .FormSectionTitle {
86
+ gap: var(--space-sm);
87
+ padding-block-end: var(--space-md);
88
+ }
89
+ }
90
+ @container (max-width: 800px) {
91
+ .FormSectionTitle,
92
+ .FormSectionContent {
93
+ grid-column: 1 / -1;
94
+ }
95
+ }
96
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from "svelte";
2
+ type $$ComponentProps = {
3
+ title?: string | Snippet;
4
+ description?: string | Snippet;
5
+ children: Snippet;
6
+ };
7
+ declare const FormSection: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type FormSection = ReturnType<typeof FormSection>;
9
+ export default FormSection;