@ainsleydev/sveltekit-helper 0.1.0 → 0.1.1

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 (36) hide show
  1. package/dist/components/Grid/Column.svelte +29 -0
  2. package/dist/components/Grid/Column.svelte.d.ts +52 -0
  3. package/dist/components/Grid/Column.svelte.d.ts.map +1 -0
  4. package/dist/components/Grid/Container.svelte +48 -0
  5. package/dist/components/Grid/Container.svelte.d.ts +55 -0
  6. package/dist/components/Grid/Container.svelte.d.ts.map +1 -0
  7. package/dist/components/Grid/Row.svelte +45 -0
  8. package/dist/components/Grid/Row.svelte.d.ts +47 -0
  9. package/dist/components/Grid/Row.svelte.d.ts.map +1 -0
  10. package/dist/components/Grid/index.js +0 -2
  11. package/dist/components/payload/PayloadForm.svelte +303 -0
  12. package/dist/components/payload/PayloadForm.svelte.d.ts +27 -0
  13. package/dist/components/payload/PayloadForm.svelte.d.ts.map +1 -0
  14. package/dist/components/payload/PayloadMedia.svelte +136 -0
  15. package/dist/components/payload/PayloadMedia.svelte.d.ts +26 -0
  16. package/dist/components/payload/PayloadMedia.svelte.d.ts.map +1 -0
  17. package/dist/components/payload/index.js +0 -2
  18. package/dist/components/payload/types.js +1 -3
  19. package/dist/index.js +2 -3
  20. package/dist/utils/forms/helpers.js +3 -4
  21. package/dist/utils/forms/index.js +0 -2
  22. package/dist/utils/forms/schema.js +22 -19
  23. package/dist/utils/forms/schema.test.js +27 -41
  24. package/dist/utils/strings/index.js +3 -4
  25. package/dist/utils/strings/index.test.js +6 -8
  26. package/package.json +9 -9
  27. package/dist/components/Grid/index.js.map +0 -1
  28. package/dist/components/payload/index.js.map +0 -1
  29. package/dist/components/payload/types.js.map +0 -1
  30. package/dist/index.js.map +0 -1
  31. package/dist/utils/forms/helpers.js.map +0 -1
  32. package/dist/utils/forms/index.js.map +0 -1
  33. package/dist/utils/forms/schema.js.map +0 -1
  34. package/dist/utils/forms/schema.test.js.map +0 -1
  35. package/dist/utils/strings/index.js.map +0 -1
  36. package/dist/utils/strings/index.test.js.map +0 -1
@@ -0,0 +1,29 @@
1
+ <!--
2
+ @component
3
+
4
+ Responsive column component.
5
+ Provides base column structure with customisable gap.
6
+ Consumers should define their own grid classes (col-12, col-tab-6, etc.) in their global styles.
7
+
8
+ @example
9
+ ```svelte
10
+ <Column class="col-12 col-tab-6 col-desk-4">
11
+ Content
12
+ </Column>
13
+ ```
14
+ -->
15
+ <div class="col" {...$$restProps}>
16
+ <slot />
17
+ </div>
18
+
19
+ <style>.col {
20
+ --col-gap: 1rem;
21
+ position: relative;
22
+ width: 100%;
23
+ padding-inline: var(--col-gap);
24
+ }
25
+ @media (max-width: 568px) {
26
+ .col {
27
+ --col-gap: 0.5rem;
28
+ }
29
+ }</style>
@@ -0,0 +1,52 @@
1
+ export default Column;
2
+ type Column = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
3
+ [x: string]: any;
4
+ }, {
5
+ default: {};
6
+ }>, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {
9
+ default: {};
10
+ }> & {
11
+ $$bindings?: string | undefined;
12
+ };
13
+ /**
14
+ * Responsive column component.
15
+ * Provides base column structure with customisable gap.
16
+ * Consumers should define their own grid classes (col-12, col-tab-6, etc.) in their global styles.
17
+ *
18
+ * @example
19
+ * ```svelte
20
+ * <Column class="col-12 col-tab-6 col-desk-4">
21
+ * Content
22
+ * </Column>
23
+ * ```
24
+ */
25
+ declare const Column: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
26
+ [x: string]: any;
27
+ }, {
28
+ default: {};
29
+ }>, {
30
+ [evt: string]: CustomEvent<any>;
31
+ }, {
32
+ default: {};
33
+ }, {}, string>;
34
+ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
35
+ default: any;
36
+ } ? Props extends Record<string, never> ? any : {
37
+ children?: any;
38
+ } : {});
39
+ 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> {
40
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
41
+ $$bindings?: Bindings;
42
+ } & Exports;
43
+ (internal: unknown, props: Props & {
44
+ $$events?: Events;
45
+ $$slots?: Slots;
46
+ }): Exports & {
47
+ $set?: any;
48
+ $on?: any;
49
+ };
50
+ z_$$bindings?: Bindings;
51
+ }
52
+ //# sourceMappingURL=Column.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Column.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/Grid/Column.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;AAyBA;;;;;;;;;;;GAWG;AACH;;;;;;;;eAAiI;sCArB3F,KAAK,EAAE,KAAK;;;;;6CALL,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,48 @@
1
+ <!--
2
+ @component
3
+
4
+ Centre content such as rows & columns horizontally with predefined max-width.
5
+ Uses CSS Grid to provide breakout and full-width layout options.
6
+
7
+ @example
8
+ ```svelte
9
+ <Container>
10
+ <Row></Row>
11
+ </Container>
12
+ ```
13
+
14
+ @example
15
+ ```svelte
16
+ <!-- Custom max width via CSS variable -->
17
+ <Container style="--container-max-width: 1400px">
18
+ <Row></Row>
19
+ </Container>
20
+ ```
21
+ -->
22
+ <div class="container" {...$$restProps}>
23
+ <slot />
24
+ </div>
25
+
26
+ <style>.container {
27
+ --container-padding: 1rem;
28
+ --container-max-width: 1328px;
29
+ --container-breakout-max-width: 1500px;
30
+ --container-breakout-size: calc(
31
+ (var(--container-breakout-max-width) - var(--container-max-width)) / 2
32
+ );
33
+ display: grid;
34
+ width: 100%;
35
+ position: relative;
36
+ grid-template-columns: [full-width-start] minmax(var(--container-padding), 1fr) [breakout-start] minmax(0, var(--container-breakout-size)) [content-start] min(100% - var(--container-padding) * 2, var(--container-max-width)) [content-end] minmax(0, var(--container-breakout-size)) [breakout-end] minmax(var(--container-padding), 1fr) [full-width-end];
37
+ }
38
+ .container :global(> *) {
39
+ grid-column: content;
40
+ }
41
+ .container :global(> .breakout) {
42
+ grid-column: breakout;
43
+ }
44
+ .container :global(> .full-width) {
45
+ display: grid;
46
+ grid-column: full-width;
47
+ grid-template-columns: inherit;
48
+ }</style>
@@ -0,0 +1,55 @@
1
+ export default Container;
2
+ type Container = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
3
+ [x: string]: any;
4
+ }, {
5
+ default: {};
6
+ }>, {
7
+ [evt: string]: CustomEvent<any>;
8
+ }, {
9
+ default: {};
10
+ }> & {
11
+ $$bindings?: string | undefined;
12
+ };
13
+ /**
14
+ * Centre content such as rows & columns horizontally with predefined max-width.
15
+ * Uses CSS Grid to provide breakout and full-width layout options.
16
+ *
17
+ * @example
18
+ * ```svelte
19
+ * <Container>
20
+ * <Row></Row>
21
+ * </Container>
22
+ * ```
23
+ *
24
+ * @example
25
+ * ```svelte
26
+ * <!-- Custom max width via CSS variable
27
+ */
28
+ declare const Container: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
29
+ [x: string]: any;
30
+ }, {
31
+ default: {};
32
+ }>, {
33
+ [evt: string]: CustomEvent<any>;
34
+ }, {
35
+ default: {};
36
+ }, {}, string>;
37
+ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
38
+ default: any;
39
+ } ? Props extends Record<string, never> ? any : {
40
+ children?: any;
41
+ } : {});
42
+ 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> {
43
+ new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
44
+ $$bindings?: Bindings;
45
+ } & Exports;
46
+ (internal: unknown, props: Props & {
47
+ $$events?: Events;
48
+ $$slots?: Slots;
49
+ }): Exports & {
50
+ $set?: any;
51
+ $on?: any;
52
+ };
53
+ z_$$bindings?: Bindings;
54
+ }
55
+ //# sourceMappingURL=Container.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Container.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/Grid/Container.svelte.js"],"names":[],"mappings":";;;;;;;;;;;;AA8BA;;;;;;;;;;;;;;GAcG;AACH;;;;;;;;eAAoI;sCAxB9F,KAAK,EAAE,KAAK;;;;;6CALL,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QAAQ,OAAO,OAAO,QAAQ;IAC3L,cAAc,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,WAAW,OAAO,SAAS,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,eAAe,QAAQ,CAAC"}
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ let noGaps = false;
3
+ </script>
4
+
5
+ <!--
6
+ @component
7
+
8
+ Flexbox row container for columns with gap management.
9
+
10
+ @example
11
+ ```svelte
12
+ <Row>
13
+ <Column></Column>
14
+ </Row>
15
+ ```
16
+
17
+ @example
18
+ ```svelte
19
+ <Row noGaps>
20
+ <Column></Column>
21
+ </Row>
22
+ ```
23
+ -->
24
+ <div class="row" class:row--no-gaps={noGaps} {...$$restProps}>
25
+ <slot />
26
+ </div>
27
+
28
+ <style>.row {
29
+ --row-gap: 1rem;
30
+ display: flex;
31
+ flex-wrap: wrap;
32
+ margin-inline: calc(var(--row-gap) * -1);
33
+ }
34
+ .row--no-gaps {
35
+ margin-inline: 0;
36
+ }
37
+ .row--no-gaps :global(.col),
38
+ .row--no-gaps :global([class*="col-"]) {
39
+ padding-inline: 0;
40
+ }
41
+ @media (max-width: 568px) {
42
+ .row {
43
+ --row-gap: 0.5rem;
44
+ }
45
+ }</style>
@@ -0,0 +1,47 @@
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
+ $set?: any;
10
+ $on?: any;
11
+ };
12
+ z_$$bindings?: Bindings;
13
+ }
14
+ type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
15
+ default: any;
16
+ } ? Props extends Record<string, never> ? any : {
17
+ children?: any;
18
+ } : {});
19
+ /**
20
+ * Flexbox row container for columns with gap management.
21
+ *
22
+ * @example
23
+ * ```svelte
24
+ * <Row>
25
+ * <Column></Column>
26
+ * </Row>
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```svelte
31
+ * <Row noGaps>
32
+ * <Column></Column>
33
+ * </Row>
34
+ * ```
35
+ */
36
+ declare const Row: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
37
+ [x: string]: any;
38
+ }, {
39
+ default: {};
40
+ }>, {
41
+ [evt: string]: CustomEvent<any>;
42
+ }, {
43
+ default: {};
44
+ }, {}, string>;
45
+ type Row = InstanceType<typeof Row>;
46
+ export default Row;
47
+ //# sourceMappingURL=Row.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Row.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/Grid/Row.svelte.ts"],"names":[],"mappings":"AAgBA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IAC9G,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AACD,KAAK,gCAAgC,CAAC,KAAK,EAAE,KAAK,IAAI,KAAK,GACvD,CAAC,KAAK,SAAS;IAAE,OAAO,EAAE,GAAG,CAAA;CAAE,GACzB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GACnC,GAAG,GACH;IAAE,QAAQ,CAAC,EAAE,GAAG,CAAA;CAAE,GAClB,EAAE,CAAC,CAAC;AAId;;;;;;;;;;;;;;;;GAgBG;AACH,QAAA,MAAM,GAAG;;;;;;;;cAA4G,CAAC;AACpG,KAAK,GAAG,GAAG,YAAY,CAAC,OAAO,GAAG,CAAC,CAAC;AACtC,eAAe,GAAG,CAAC"}
@@ -1,5 +1,3 @@
1
1
  export { default as Container } from './Container.svelte';
2
2
  export { default as Row } from './Row.svelte';
3
3
  export { default as Column } from './Column.svelte';
4
-
5
- //# sourceMappingURL=index.js.map
@@ -0,0 +1,303 @@
1
+ <script lang="ts">
2
+ import type { PayloadFormField } from '../../utils/forms/schema';
3
+
4
+ /**
5
+ * Payload form configuration
6
+ */
7
+ export let form: {
8
+ id: number | string;
9
+ fields?: PayloadFormField[] | null;
10
+ confirmationMessage?: string | null;
11
+ submitButtonLabel?: string | null;
12
+ };
13
+
14
+ /**
15
+ * API endpoint to submit form data to (defaults to '/api/forms')
16
+ */
17
+ export let apiEndpoint = '/api/forms';
18
+
19
+ /**
20
+ * Custom submit handler (overrides default API submission)
21
+ */
22
+ export let onSubmit: ((data: Record<string, unknown>) => Promise<void>) | undefined = undefined;
23
+
24
+ let formData = $state<Record<string, unknown>>({});
25
+ let errors: Record<string, string> = $state({});
26
+ let success = $state(false);
27
+ let error: string | null = $state(null);
28
+ let submitting = $state(false);
29
+
30
+ const typeMap = { text: 'text', email: 'email', number: 'number' };
31
+
32
+ async function handleSubmit(event: SubmitEvent) {
33
+ event.preventDefault();
34
+ errors = {};
35
+ error = null;
36
+ submitting = true;
37
+
38
+ try {
39
+ if (onSubmit) {
40
+ await onSubmit(formData);
41
+ } else {
42
+ const response = await fetch(apiEndpoint, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ },
47
+ body: JSON.stringify({
48
+ formID: form.id,
49
+ data: formData,
50
+ }),
51
+ });
52
+
53
+ const result = await response.json();
54
+ if (!result.success) {
55
+ error = result.error || 'Failed to submit form';
56
+ return;
57
+ }
58
+ }
59
+
60
+ success = true;
61
+ } catch (err) {
62
+ error = err instanceof Error ? err.message : 'Failed to submit form';
63
+ success = false;
64
+ } finally {
65
+ submitting = false;
66
+ }
67
+ }
68
+ </script>
69
+
70
+ <!--
71
+ @component
72
+
73
+ PayloadForm renders a form dynamically from Payload CMS form builder fields.
74
+ Uses basic HTML elements that can be styled via CSS variables or custom classes.
75
+
76
+ @example
77
+ ```svelte
78
+ <PayloadForm
79
+ form={payloadFormData}
80
+ apiEndpoint="/api/forms"
81
+ />
82
+ ```
83
+
84
+ @example
85
+ ```svelte
86
+ <PayloadForm
87
+ form={payloadFormData}
88
+ onSubmit={async (data) => {
89
+ // Custom submission logic
90
+ await customAPI.submit(data)
91
+ }}
92
+ />
93
+ ```
94
+ -->
95
+ <form method="POST" onsubmit={handleSubmit} class="payload-form">
96
+ {#if form.fields?.length}
97
+ {#each form.fields as field, index (index)}
98
+ {@const required = field.required ?? false}
99
+ {@const name = field.name}
100
+ <div class="payload-form__group" class:payload-form__group--error={errors[name]}>
101
+ {#if field.blockType === 'text' || field.blockType === 'email' || field.blockType === 'number'}
102
+ <label for={field.id || name} class="payload-form__label">
103
+ {field.label}
104
+ {#if required}
105
+ <span class="payload-form__required">*</span>
106
+ {/if}
107
+ </label>
108
+ <input
109
+ id={field.id || name}
110
+ {name}
111
+ type={typeMap[field.blockType]}
112
+ placeholder={field.placeholder ?? ''}
113
+ bind:value={formData[name]}
114
+ disabled={success}
115
+ class="payload-form__input"
116
+ class:payload-form__input--error={errors[name]}
117
+ />
118
+ {:else if field.blockType === 'textarea'}
119
+ <label for={field.id || name} class="payload-form__label">
120
+ {field.label}
121
+ {#if required}
122
+ <span class="payload-form__required">*</span>
123
+ {/if}
124
+ </label>
125
+ <textarea
126
+ id={field.id || name}
127
+ {name}
128
+ placeholder={field.placeholder ?? ''}
129
+ rows={8}
130
+ bind:value={formData[name]}
131
+ disabled={success}
132
+ class="payload-form__textarea"
133
+ class:payload-form__textarea--error={errors[name]}
134
+ />
135
+ {:else if field.blockType === 'checkbox'}
136
+ <div class="payload-form__checkbox-wrapper">
137
+ <input
138
+ id={field.id || name}
139
+ type="checkbox"
140
+ {name}
141
+ bind:checked={formData[name]}
142
+ disabled={success}
143
+ class="payload-form__checkbox"
144
+ class:payload-form__checkbox--error={errors[name]}
145
+ />
146
+ <label for={field.id || name} class="payload-form__label payload-form__label--checkbox">
147
+ {field.label}
148
+ {#if required}
149
+ <span class="payload-form__required">*</span>
150
+ {/if}
151
+ </label>
152
+ </div>
153
+ {/if}
154
+
155
+ {#if errors[name]}
156
+ <span class="payload-form__error">{errors[name]}</span>
157
+ {/if}
158
+ </div>
159
+ {/each}
160
+ {/if}
161
+
162
+ {#if success}
163
+ <div class="payload-form__success">
164
+ {form.confirmationMessage ?? 'Form submitted successfully!'}
165
+ </div>
166
+ {/if}
167
+
168
+ {#if error}
169
+ <div class="payload-form__alert">
170
+ {error}
171
+ </div>
172
+ {/if}
173
+
174
+ <button type="submit" disabled={success || submitting} class="payload-form__submit">
175
+ {#if submitting}
176
+ <span class="payload-form__loader"></span>
177
+ {/if}
178
+ {form.submitButtonLabel ?? 'Send'}
179
+ </button>
180
+ </form>
181
+
182
+ <style>.payload-form {
183
+ --form-gap: 1rem;
184
+ --form-input-padding: 0.75rem;
185
+ --form-input-border: 1px solid #d1d5db;
186
+ --form-input-border-radius: 0.375rem;
187
+ --form-input-bg: #ffffff;
188
+ --form-input-text: #111827;
189
+ --form-error-color: #ef4444;
190
+ --form-error-bg: #fee2e2;
191
+ --form-success-color: #10b981;
192
+ --form-success-bg: #d1fae5;
193
+ --form-button-bg: #3b82f6;
194
+ --form-button-text: #ffffff;
195
+ --form-button-hover-bg: #2563eb;
196
+ --form-button-disabled-bg: #9ca3af;
197
+ display: flex;
198
+ flex-direction: column;
199
+ gap: var(--form-gap);
200
+ }
201
+ .payload-form__group {
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 0.5rem;
205
+ }
206
+ .payload-form__label {
207
+ font-size: 0.875rem;
208
+ font-weight: 500;
209
+ color: var(--form-input-text);
210
+ }
211
+ .payload-form__label--checkbox {
212
+ font-weight: 400;
213
+ cursor: pointer;
214
+ }
215
+ .payload-form__required {
216
+ color: var(--form-error-color);
217
+ margin-left: 0.25rem;
218
+ }
219
+ .payload-form__input, .payload-form__textarea {
220
+ padding: var(--form-input-padding);
221
+ border: var(--form-input-border);
222
+ border-radius: var(--form-input-border-radius);
223
+ background: var(--form-input-bg);
224
+ color: var(--form-input-text);
225
+ font-size: 1rem;
226
+ font-family: inherit;
227
+ }
228
+ .payload-form__input:focus, .payload-form__textarea:focus {
229
+ outline: 2px solid var(--form-button-bg);
230
+ outline-offset: 2px;
231
+ }
232
+ .payload-form__input--error, .payload-form__textarea--error {
233
+ border-color: var(--form-error-color);
234
+ }
235
+ .payload-form__textarea {
236
+ resize: vertical;
237
+ min-height: 8rem;
238
+ }
239
+ .payload-form__checkbox-wrapper {
240
+ display: flex;
241
+ align-items: flex-start;
242
+ gap: 0.5rem;
243
+ }
244
+ .payload-form__checkbox {
245
+ margin-top: 0.25rem;
246
+ width: 1rem;
247
+ height: 1rem;
248
+ cursor: pointer;
249
+ }
250
+ .payload-form__error {
251
+ font-size: 0.875rem;
252
+ color: var(--form-error-color);
253
+ }
254
+ .payload-form__success {
255
+ padding: 1rem;
256
+ background-color: var(--form-success-bg);
257
+ color: var(--form-success-color);
258
+ border-radius: var(--form-input-border-radius);
259
+ font-weight: 500;
260
+ }
261
+ .payload-form__alert {
262
+ padding: 1rem;
263
+ background-color: var(--form-error-bg);
264
+ color: var(--form-error-color);
265
+ border-radius: var(--form-input-border-radius);
266
+ font-weight: 500;
267
+ }
268
+ .payload-form__submit {
269
+ padding: var(--form-input-padding) 1.5rem;
270
+ background-color: var(--form-button-bg);
271
+ color: var(--form-button-text);
272
+ border: none;
273
+ border-radius: var(--form-input-border-radius);
274
+ font-size: 1rem;
275
+ font-weight: 500;
276
+ cursor: pointer;
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ gap: 0.5rem;
281
+ transition: background-color 0.2s;
282
+ }
283
+ .payload-form__submit:hover:not(:disabled) {
284
+ background-color: var(--form-button-hover-bg);
285
+ }
286
+ .payload-form__submit:disabled {
287
+ background-color: var(--form-button-disabled-bg);
288
+ cursor: not-allowed;
289
+ }
290
+ .payload-form__loader {
291
+ width: 1rem;
292
+ height: 1rem;
293
+ border: 2px solid currentColor;
294
+ border-top-color: transparent;
295
+ border-radius: 50%;
296
+ animation: spin 0.6s linear infinite;
297
+ }
298
+
299
+ @keyframes spin {
300
+ to {
301
+ transform: rotate(360deg);
302
+ }
303
+ }</style>
@@ -0,0 +1,27 @@
1
+ /**
2
+ * PayloadForm renders a form dynamically from Payload CMS form builder fields.
3
+ * Uses basic HTML elements that can be styled via CSS variables or custom classes.
4
+ *
5
+ * @example
6
+ * ```svelte
7
+ * <PayloadForm
8
+ * form={payloadFormData}
9
+ * apiEndpoint="/api/forms"
10
+ * />
11
+ * ```
12
+ *
13
+ * @example
14
+ * ```svelte
15
+ * <PayloadForm
16
+ * form={payloadFormData}
17
+ * onSubmit={async (data) => {
18
+ * // Custom submission logic
19
+ * await customAPI.submit(data)
20
+ * }}
21
+ * />
22
+ * ```
23
+ */
24
+ declare const PayloadForm: import("svelte").Component<Record<string, never>, {}, "">;
25
+ type PayloadForm = ReturnType<typeof PayloadForm>;
26
+ export default PayloadForm;
27
+ //# sourceMappingURL=PayloadForm.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PayloadForm.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/payload/PayloadForm.svelte.ts"],"names":[],"mappings":"AA4IA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,QAAA,MAAM,WAAW,2DAAwC,CAAC;AAC1D,KAAK,WAAW,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAC;AAClD,eAAe,WAAW,CAAC"}
@@ -0,0 +1,136 @@
1
+ <script lang="ts">
2
+ import type { Media, MediaSizes, PayloadMediaProps } from './types.js';
3
+
4
+ const {
5
+ data,
6
+ loading = undefined,
7
+ className = '',
8
+ breakpointBuffer = 50,
9
+ maxWidth = undefined,
10
+ onload = () => null,
11
+ ...restProps
12
+ }: PayloadMediaProps = $props();
13
+
14
+ /**
15
+ * Returns sources grouped by breakpoint/width, then sorted by mime priority within each group:
16
+ * For each width: avif → webp → jpeg/png → others
17
+ */
18
+ const getSources = (sizesMap?: MediaSizes) => {
19
+ if (!sizesMap) return [];
20
+
21
+ const arr = Object.values(sizesMap)
22
+ .filter((s) => s?.url && s?.width)
23
+ .map((s) => ({
24
+ url: s.url as string,
25
+ width: s.width as number,
26
+ mimeType: s.mimeType ?? '',
27
+ }));
28
+
29
+ const filtered = maxWidth ? arr.filter((s) => s.width <= maxWidth) : arr;
30
+
31
+ const mimePriority = (mime: string, url: string) => {
32
+ if (/avif/i.test(mime) || /\.avif$/i.test(url)) return 1;
33
+ if (/webp/i.test(mime) || /\.webp$/i.test(url)) return 2;
34
+ if (/jpe?g|png/i.test(mime) || /\.(jpe?g|png)$/i.test(url)) return 3;
35
+ return 4;
36
+ };
37
+
38
+ return filtered.sort((a, b) => {
39
+ if (a.width !== b.width) return a.width - b.width;
40
+ return mimePriority(a.mimeType, a.url) - mimePriority(b.mimeType, b.url);
41
+ });
42
+ };
43
+
44
+ const isImage = $derived((data?.mimeType ?? '').startsWith('image'));
45
+ const isVideo = $derived((data?.mimeType ?? '').startsWith('video'));
46
+ const isSVG = $derived(!!(data?.filename && /\.svg$/i.test(data.filename)));
47
+
48
+ const sources = $derived(isImage && !isSVG ? getSources(data.sizes) : []);
49
+ const fallbackSource = $derived(sources[sources.length - 1]);
50
+ const imgAlt = $derived(data?.alt ?? '');
51
+ const imgLoading = $derived(loading ?? undefined);
52
+ const imgWidth = $derived(fallbackSource?.width ?? data?.width ?? undefined);
53
+ const imgHeight = $derived(
54
+ fallbackSource && data?.width && data?.height
55
+ ? Math.round((fallbackSource.width / data.width) * data.height)
56
+ : data?.height ?? undefined,
57
+ );
58
+ const fallbackUrl = $derived(sources[sources.length - 1]?.url ?? data?.url ?? '');
59
+ </script>
60
+
61
+ <!--
62
+ @component
63
+
64
+ PayloadMedia renders responsive images and videos from Payload CMS media fields.
65
+ Handles multiple image sizes with automatic AVIF/WebP format prioritisation.
66
+
67
+ @example
68
+ ```svelte
69
+ <PayloadMedia
70
+ data={media}
71
+ loading="lazy"
72
+ maxWidth={1200}
73
+ />
74
+ ```
75
+
76
+ @example
77
+ ```svelte
78
+ <PayloadMedia
79
+ data={videoMedia}
80
+ className="custom-video"
81
+ />
82
+ ```
83
+ -->
84
+ {#if isImage}
85
+ {#if isSVG}
86
+ <img
87
+ src={data.url}
88
+ alt={imgAlt}
89
+ width={imgWidth}
90
+ height={imgHeight}
91
+ loading={imgLoading}
92
+ class={className}
93
+ {onload}
94
+ {...restProps}
95
+ />
96
+ {:else}
97
+ <picture class={className} {...restProps}>
98
+ {#each sources as source, index (index)}
99
+ <source
100
+ media={`(max-width: ${source.width + breakpointBuffer}px)`}
101
+ srcset={source.url}
102
+ type={source.mimeType}
103
+ />
104
+ {/each}
105
+ <img
106
+ src={fallbackUrl}
107
+ alt={imgAlt}
108
+ width={imgWidth}
109
+ height={imgHeight}
110
+ loading={imgLoading}
111
+ {onload}
112
+ />
113
+ </picture>
114
+ {/if}
115
+ {:else if isVideo}
116
+ <video
117
+ controls
118
+ width={imgWidth}
119
+ height={imgHeight}
120
+ preload={loading === 'lazy' ? 'metadata' : 'auto'}
121
+ poster={data.thumbnailURL}
122
+ class={className}
123
+ {onload}
124
+ {...restProps}
125
+ >
126
+ <source src={data.url} type={data.mimeType} />
127
+ <track kind="captions" />
128
+ </video>
129
+ {/if}
130
+
131
+ <style>img,
132
+ video {
133
+ max-width: 100%;
134
+ height: auto;
135
+ display: block;
136
+ }</style>
@@ -0,0 +1,26 @@
1
+ import type { PayloadMediaProps } from './types.js';
2
+ /**
3
+ * PayloadMedia renders responsive images and videos from Payload CMS media fields.
4
+ * Handles multiple image sizes with automatic AVIF/WebP format prioritisation.
5
+ *
6
+ * @example
7
+ * ```svelte
8
+ * <PayloadMedia
9
+ * data={media}
10
+ * loading="lazy"
11
+ * maxWidth={1200}
12
+ * />
13
+ * ```
14
+ *
15
+ * @example
16
+ * ```svelte
17
+ * <PayloadMedia
18
+ * data={videoMedia}
19
+ * className="custom-video"
20
+ * />
21
+ * ```
22
+ */
23
+ declare const PayloadMedia: import("svelte").Component<PayloadMediaProps, {}, "">;
24
+ type PayloadMedia = ReturnType<typeof PayloadMedia>;
25
+ export default PayloadMedia;
26
+ //# sourceMappingURL=PayloadMedia.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PayloadMedia.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/payload/PayloadMedia.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAqB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAqFvE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -1,4 +1,2 @@
1
1
  export { default as PayloadForm } from './PayloadForm.svelte';
2
2
  export { default as PayloadMedia } from './PayloadMedia.svelte';
3
-
4
- //# sourceMappingURL=index.js.map
@@ -1,3 +1 @@
1
- export { };
2
-
3
- //# sourceMappingURL=types.js.map
1
+ export {};
package/dist/index.js CHANGED
@@ -3,9 +3,8 @@
3
3
  *
4
4
  * SvelteKit utilities, components and helpers for ainsley.dev builds.
5
5
  * Provides form utilities, grid components, and Payload CMS integrations.
6
- */ // Re-export all exports from submodules
6
+ */
7
+ // Re-export all exports from submodules
7
8
  export * from './components/Grid/index.js';
8
9
  export * from './components/payload/index.js';
9
10
  export * from './utils/forms/index.js';
10
-
11
- //# sourceMappingURL=index.js.map
@@ -17,9 +17,10 @@
17
17
  * // { email: 'Invalid email' }
18
18
  * }
19
19
  * ```
20
- */ export const flattenZodErrors = (error)=>{
20
+ */
21
+ export const flattenZodErrors = (error) => {
21
22
  const errors = {};
22
- for (const issue of error.issues){
23
+ for (const issue of error.issues) {
23
24
  const path = issue.path.join('.');
24
25
  if (!errors[path]) {
25
26
  errors[path] = issue.message;
@@ -27,5 +28,3 @@
27
28
  }
28
29
  return errors;
29
30
  };
30
-
31
- //# sourceMappingURL=helpers.js.map
@@ -1,4 +1,2 @@
1
1
  export { flattenZodErrors } from './helpers.js';
2
2
  export { generateFormSchema } from './schema.js';
3
-
4
- //# sourceMappingURL=index.js.map
@@ -25,29 +25,32 @@ import { z } from 'zod';
25
25
  * // message: z.string().optional()
26
26
  * // })
27
27
  * ```
28
- */ export const generateFormSchema = (fields)=>{
29
- if (!fields?.length) return z.object({});
28
+ */
29
+ export const generateFormSchema = (fields) => {
30
+ if (!fields?.length)
31
+ return z.object({});
30
32
  const shape = {};
31
- for (const field of fields){
33
+ for (const field of fields) {
32
34
  if (field.blockType === 'text' || field.blockType === 'textarea') {
33
- shape[field.name] = field.required ? z.string().min(1, {
34
- message: `${field.label || field.name} is required`
35
- }) : z.string().optional();
36
- } else if (field.blockType === 'email') {
37
- shape[field.name] = field.required ? z.string().email({
38
- message: 'Invalid email'
39
- }) : z.string().email({
40
- message: 'Invalid email'
41
- }).optional();
42
- } else if (field.blockType === 'number') {
35
+ shape[field.name] = field.required
36
+ ? z.string().min(1, { message: `${field.label || field.name} is required` })
37
+ : z.string().optional();
38
+ }
39
+ else if (field.blockType === 'email') {
40
+ shape[field.name] = field.required
41
+ ? z.string().email({ message: 'Invalid email' })
42
+ : z.string().email({ message: 'Invalid email' }).optional();
43
+ }
44
+ else if (field.blockType === 'number') {
43
45
  shape[field.name] = field.required ? z.number() : z.number().optional();
44
- } else if (field.blockType === 'checkbox') {
45
- shape[field.name] = field.required ? z.boolean().refine((val)=>val === true, {
46
- message: `${field.label || field.name} must be checked`
47
- }) : z.boolean().optional();
46
+ }
47
+ else if (field.blockType === 'checkbox') {
48
+ shape[field.name] = field.required
49
+ ? z.boolean().refine((val) => val === true, {
50
+ message: `${field.label || field.name} must be checked`,
51
+ })
52
+ : z.boolean().optional();
48
53
  }
49
54
  }
50
55
  return z.object(shape);
51
56
  };
52
-
53
- //# sourceMappingURL=schema.js.map
@@ -1,115 +1,101 @@
1
1
  import { describe, expect, test } from 'vitest';
2
2
  import { z } from 'zod';
3
3
  import { generateFormSchema } from './schema';
4
- describe('generateFormSchema', ()=>{
5
- test('returns empty object schema when no fields provided', ()=>{
4
+ describe('generateFormSchema', () => {
5
+ test('returns empty object schema when no fields provided', () => {
6
6
  const schema = generateFormSchema(null);
7
7
  expect(schema).toBeInstanceOf(z.ZodObject);
8
8
  expect(schema.shape).toEqual({});
9
9
  });
10
- test('returns empty object schema for empty array', ()=>{
10
+ test('returns empty object schema for empty array', () => {
11
11
  const schema = generateFormSchema([]);
12
12
  expect(schema).toBeInstanceOf(z.ZodObject);
13
13
  expect(schema.shape).toEqual({});
14
14
  });
15
- test('generates required text field schema', ()=>{
15
+ test('generates required text field schema', () => {
16
16
  const fields = [
17
17
  {
18
18
  blockType: 'text',
19
19
  name: 'firstName',
20
20
  label: 'First Name',
21
- required: true
22
- }
21
+ required: true,
22
+ },
23
23
  ];
24
24
  const schema = generateFormSchema(fields);
25
- const result = schema.safeParse({
26
- firstName: ''
27
- });
25
+ const result = schema.safeParse({ firstName: '' });
28
26
  expect(result.success).toBe(false);
29
- const validResult = schema.safeParse({
30
- firstName: 'John'
31
- });
27
+ const validResult = schema.safeParse({ firstName: 'John' });
32
28
  expect(validResult.success).toBe(true);
33
29
  });
34
- test('generates optional text field schema', ()=>{
30
+ test('generates optional text field schema', () => {
35
31
  const fields = [
36
32
  {
37
33
  blockType: 'text',
38
34
  name: 'middleName',
39
35
  label: 'Middle Name',
40
- required: false
41
- }
36
+ required: false,
37
+ },
42
38
  ];
43
39
  const schema = generateFormSchema(fields);
44
40
  const result = schema.safeParse({});
45
41
  expect(result.success).toBe(true);
46
42
  });
47
- test('generates required email field schema', ()=>{
43
+ test('generates required email field schema', () => {
48
44
  const fields = [
49
45
  {
50
46
  blockType: 'email',
51
47
  name: 'email',
52
48
  label: 'Email',
53
- required: true
54
- }
49
+ required: true,
50
+ },
55
51
  ];
56
52
  const schema = generateFormSchema(fields);
57
- const invalidResult = schema.safeParse({
58
- email: 'not-an-email'
59
- });
53
+ const invalidResult = schema.safeParse({ email: 'not-an-email' });
60
54
  expect(invalidResult.success).toBe(false);
61
- const validResult = schema.safeParse({
62
- email: 'test@example.com'
63
- });
55
+ const validResult = schema.safeParse({ email: 'test@example.com' });
64
56
  expect(validResult.success).toBe(true);
65
57
  });
66
- test('generates required checkbox field schema', ()=>{
58
+ test('generates required checkbox field schema', () => {
67
59
  const fields = [
68
60
  {
69
61
  blockType: 'checkbox',
70
62
  name: 'terms',
71
63
  label: 'Accept Terms',
72
- required: true
73
- }
64
+ required: true,
65
+ },
74
66
  ];
75
67
  const schema = generateFormSchema(fields);
76
- const falseResult = schema.safeParse({
77
- terms: false
78
- });
68
+ const falseResult = schema.safeParse({ terms: false });
79
69
  expect(falseResult.success).toBe(false);
80
- const trueResult = schema.safeParse({
81
- terms: true
82
- });
70
+ const trueResult = schema.safeParse({ terms: true });
83
71
  expect(trueResult.success).toBe(true);
84
72
  });
85
- test('generates schema with multiple fields', ()=>{
73
+ test('generates schema with multiple fields', () => {
86
74
  const fields = [
87
75
  {
88
76
  blockType: 'text',
89
77
  name: 'name',
90
78
  label: 'Name',
91
- required: true
79
+ required: true,
92
80
  },
93
81
  {
94
82
  blockType: 'email',
95
83
  name: 'email',
96
84
  label: 'Email',
97
- required: true
85
+ required: true,
98
86
  },
99
87
  {
100
88
  blockType: 'textarea',
101
89
  name: 'message',
102
90
  label: 'Message',
103
- required: false
104
- }
91
+ required: false,
92
+ },
105
93
  ];
106
94
  const schema = generateFormSchema(fields);
107
95
  const result = schema.safeParse({
108
96
  name: 'John',
109
- email: 'john@example.com'
97
+ email: 'john@example.com',
110
98
  });
111
99
  expect(result.success).toBe(true);
112
100
  });
113
101
  });
114
-
115
- //# sourceMappingURL=schema.test.js.map
@@ -9,12 +9,11 @@
9
9
  * const id = generateRandomString(10)
10
10
  * // Returns something like: "a3k9mxp2q1"
11
11
  * ```
12
- */ export const generateRandomString = (length)=>{
12
+ */
13
+ export const generateRandomString = (length) => {
13
14
  let result = '';
14
- while(result.length < length){
15
+ while (result.length < length) {
15
16
  result += (Math.random() + 1).toString(36).substring(2);
16
17
  }
17
18
  return result.substring(0, length);
18
19
  };
19
-
20
- //# sourceMappingURL=index.js.map
@@ -1,28 +1,26 @@
1
1
  import { describe, expect, test } from 'vitest';
2
2
  import { generateRandomString } from './index';
3
- describe('generateRandomString', ()=>{
4
- test('generates a string of the specified length', ()=>{
3
+ describe('generateRandomString', () => {
4
+ test('generates a string of the specified length', () => {
5
5
  const length = 10;
6
6
  const result = generateRandomString(length);
7
7
  expect(result).toHaveLength(length);
8
8
  });
9
- test('generates alphanumeric characters only', ()=>{
9
+ test('generates alphanumeric characters only', () => {
10
10
  const result = generateRandomString(100);
11
11
  expect(result).toMatch(/^[a-z0-9]+$/);
12
12
  });
13
- test('generates different strings on multiple calls', ()=>{
13
+ test('generates different strings on multiple calls', () => {
14
14
  const first = generateRandomString(20);
15
15
  const second = generateRandomString(20);
16
16
  expect(first).not.toBe(second);
17
17
  });
18
- test('handles length of 0', ()=>{
18
+ test('handles length of 0', () => {
19
19
  const result = generateRandomString(0);
20
20
  expect(result).toBe('');
21
21
  });
22
- test('handles length of 1', ()=>{
22
+ test('handles length of 1', () => {
23
23
  const result = generateRandomString(1);
24
24
  expect(result).toHaveLength(1);
25
25
  });
26
26
  });
27
-
28
- //# sourceMappingURL=index.test.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainsleydev/sveltekit-helper",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "SvelteKit utilities, components and helpers for ainsley.dev builds",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,16 +26,18 @@
26
26
  "exports": {
27
27
  ".": {
28
28
  "types": "./dist/index.d.ts",
29
- "import": "./dist/index.js",
29
+ "svelte": "./dist/index.js",
30
30
  "default": "./dist/index.js"
31
31
  },
32
32
  "./components/Grid": {
33
33
  "types": "./dist/components/Grid/index.d.ts",
34
- "import": "./dist/components/Grid/index.js"
34
+ "svelte": "./dist/components/Grid/index.js",
35
+ "default": "./dist/components/Grid/index.js"
35
36
  },
36
37
  "./components/payload": {
37
38
  "types": "./dist/components/payload/index.d.ts",
38
- "import": "./dist/components/payload/index.js"
39
+ "svelte": "./dist/components/payload/index.js",
40
+ "default": "./dist/components/payload/index.js"
39
41
  },
40
42
  "./utils/forms": {
41
43
  "types": "./dist/utils/forms/index.d.ts",
@@ -69,13 +71,13 @@
69
71
  "devDependencies": {
70
72
  "@sveltejs/kit": "^2.0.0",
71
73
  "@sveltejs/package": "^2.0.0",
72
- "@swc/cli": "^0.7.8",
73
- "@swc/core": "^1.7.2",
74
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
74
75
  "@types/node": "^24.10.1",
75
76
  "payload": "3.63.0",
76
77
  "rimraf": "6.1.0",
77
78
  "svelte": "^5.0.0",
78
79
  "typescript": "^5.5.4",
80
+ "vite": "^6.0.0",
79
81
  "vitest": "^2.0.5",
80
82
  "zod": "^3.24.3",
81
83
  "@ainsleydev/eslint-config": "0.0.9"
@@ -85,9 +87,7 @@
85
87
  "pnpm": ">=9"
86
88
  },
87
89
  "scripts": {
88
- "build": "pnpm clean && pnpm build:types && pnpm build:swc",
89
- "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths",
90
- "build:types": "tsc --emitDeclarationOnly --outDir dist",
90
+ "build": "pnpm clean && svelte-kit sync && svelte-package -i src",
91
91
  "format": "biome check --write --unsafe .",
92
92
  "lint": "biome lint --write .",
93
93
  "clean": "rimraf {dist,*.tsbuildinfo}",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/Grid/index.ts"],"sourcesContent":["export { default as Container } from './Container.svelte';\nexport { default as Row } from './Row.svelte';\nexport { default as Column } from './Column.svelte';\n"],"names":["default","Container","Row","Column"],"mappings":"AAAA,SAASA,WAAWC,SAAS,QAAQ,qBAAqB;AAC1D,SAASD,WAAWE,GAAG,QAAQ,eAAe;AAC9C,SAASF,WAAWG,MAAM,QAAQ,kBAAkB"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/payload/index.ts"],"sourcesContent":["export { default as PayloadForm } from './PayloadForm.svelte';\nexport { default as PayloadMedia } from './PayloadMedia.svelte';\nexport type { Media, MediaSizes, PayloadMediaProps } from './types.js';\n"],"names":["default","PayloadForm","PayloadMedia"],"mappings":"AAAA,SAASA,WAAWC,WAAW,QAAQ,uBAAuB;AAC9D,SAASD,WAAWE,YAAY,QAAQ,wBAAwB"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/components/payload/types.ts"],"sourcesContent":["import type { HTMLAttributes } from 'svelte/elements';\n\nexport type MediaSizes = Record<\n\tstring,\n\t| Partial<{\n\t\t\turl?: string | null;\n\t\t\twidth?: number | null;\n\t\t\theight?: number | null;\n\t\t\tmimeType?: string | null;\n\t }>\n\t| undefined\n>;\n\nexport type PayloadMediaProps = HTMLAttributes<HTMLElement> & {\n\tdata: Media;\n\tloading?: 'lazy' | 'eager' | undefined;\n\tclassName?: string;\n\tbreakpointBuffer?: number;\n\tmaxWidth?: number | undefined;\n\tonload?: (event: Event) => void;\n};\n\nexport type Media = {\n\tid: number;\n\talt?: string;\n\tupdatedAt: string;\n\tcreatedAt: string;\n\tdeletedAt?: string | null;\n\turl?: string | null;\n\tthumbnailURL?: string | null;\n\tfilename?: string | null;\n\tmimeType?: string | null;\n\tfilesize?: number | null;\n\twidth?: number | null;\n\theight?: number | null;\n\tfocalX?: number | null;\n\tfocalY?: number | null;\n\tsizes?: MediaSizes;\n};\n"],"names":[],"mappings":"AAsBA,WAgBE"}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @ainsleydev/sveltekit-helper\n *\n * SvelteKit utilities, components and helpers for ainsley.dev builds.\n * Provides form utilities, grid components, and Payload CMS integrations.\n */\n\n// Re-export all exports from submodules\nexport * from './components/Grid/index.js';\nexport * from './components/payload/index.js';\nexport * from './utils/forms/index.js';\n"],"names":[],"mappings":"AAAA;;;;;CAKC,GAED,wCAAwC;AACxC,cAAc,6BAA6B;AAC3C,cAAc,gCAAgC;AAC9C,cAAc,yBAAyB"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/forms/helpers.ts"],"sourcesContent":["import type { z } from 'zod';\n\nexport type FormErrors = Record<string, string>;\n\n/**\n * Flattens Zod validation errors into a simple key-value object.\n * Takes only the first error message for each field.\n *\n * @param error - ZodError from validation failure.\n * @returns Object mapping field names to error messages.\n *\n * @example\n * ```typescript\n * import { flattenZodErrors } from '@ainsleydev/sveltekit-helper/utils/forms'\n *\n * const schema = z.object({ email: z.string().email() })\n * const result = schema.safeParse({ email: 'invalid' })\n *\n * if (!result.success) {\n * const errors = flattenZodErrors(result.error)\n * // { email: 'Invalid email' }\n * }\n * ```\n */\nexport const flattenZodErrors = (error: z.ZodError): FormErrors => {\n\tconst errors: FormErrors = {};\n\n\tfor (const issue of error.issues) {\n\t\tconst path = issue.path.join('.');\n\t\tif (!errors[path]) {\n\t\t\terrors[path] = issue.message;\n\t\t}\n\t}\n\n\treturn errors;\n};\n"],"names":["flattenZodErrors","error","errors","issue","issues","path","join","message"],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;CAmBC,GACD,OAAO,MAAMA,mBAAmB,CAACC;IAChC,MAAMC,SAAqB,CAAC;IAE5B,KAAK,MAAMC,SAASF,MAAMG,MAAM,CAAE;QACjC,MAAMC,OAAOF,MAAME,IAAI,CAACC,IAAI,CAAC;QAC7B,IAAI,CAACJ,MAAM,CAACG,KAAK,EAAE;YAClBH,MAAM,CAACG,KAAK,GAAGF,MAAMI,OAAO;QAC7B;IACD;IAEA,OAAOL;AACR,EAAE"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/forms/index.ts"],"sourcesContent":["export { flattenZodErrors, type FormErrors } from './helpers.js';\nexport { generateFormSchema, type PayloadFormField } from './schema.js';\n"],"names":["flattenZodErrors","generateFormSchema"],"mappings":"AAAA,SAASA,gBAAgB,QAAyB,eAAe;AACjE,SAASC,kBAAkB,QAA+B,cAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/forms/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\n/**\n * Represents a form field from Payload CMS form builder.\n * This is a simplified type that covers the most common field types.\n */\nexport type PayloadFormField =\n\t| {\n\t\t\tname: string;\n\t\t\tlabel?: string | null;\n\t\t\tplaceholder?: string | null;\n\t\t\tdefaultValue?: string | null;\n\t\t\trequired?: boolean | null;\n\t\t\tid?: string | null;\n\t\t\tblockName?: string | null;\n\t\t\tblockType: 'text';\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tlabel?: string | null;\n\t\t\tplaceholder?: string | null;\n\t\t\tdefaultValue?: string | null;\n\t\t\trequired?: boolean | null;\n\t\t\tid?: string | null;\n\t\t\tblockName?: string | null;\n\t\t\tblockType: 'email';\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tlabel?: string | null;\n\t\t\tplaceholder?: string | null;\n\t\t\tdefaultValue?: number | null;\n\t\t\trequired?: boolean | null;\n\t\t\tid?: string | null;\n\t\t\tblockName?: string | null;\n\t\t\tblockType: 'number';\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tlabel?: string | null;\n\t\t\tplaceholder?: string | null;\n\t\t\tdefaultValue?: string | null;\n\t\t\trequired?: boolean | null;\n\t\t\tid?: string | null;\n\t\t\tblockName?: string | null;\n\t\t\tblockType: 'textarea';\n\t }\n\t| {\n\t\t\tname: string;\n\t\t\tlabel?: string | null;\n\t\t\tdefaultValue?: boolean | null;\n\t\t\trequired?: boolean | null;\n\t\t\tid?: string | null;\n\t\t\tblockName?: string | null;\n\t\t\tblockType: 'checkbox';\n\t };\n\n/**\n * Generates a dynamic Zod schema from Payload CMS Form Fields.\n *\n * This utility automatically creates validation schemas for Payload form fields,\n * respecting required flags and field types.\n *\n * @param fields - Array of form fields from Payload CMS form builder.\n * @returns Zod object schema for validating the form.\n *\n * @example\n * ```typescript\n * import { generateFormSchema } from '@ainsleydev/sveltekit-helper/utils/forms'\n *\n * const fields = [\n * { blockType: 'text', name: 'name', label: 'Name', required: true },\n * { blockType: 'email', name: 'email', label: 'Email', required: true },\n * { blockType: 'textarea', name: 'message', label: 'Message', required: false }\n * ]\n *\n * const schema = generateFormSchema(fields)\n * // Returns z.object({\n * // name: z.string().min(1, { message: 'Name is required' }),\n * // email: z.string().email({ message: 'Invalid email' }),\n * // message: z.string().optional()\n * // })\n * ```\n */\nexport const generateFormSchema = (\n\tfields?: PayloadFormField[] | null,\n): z.ZodObject<Record<string, z.ZodTypeAny>> => {\n\tif (!fields?.length) return z.object({}) as z.ZodObject<Record<string, z.ZodTypeAny>>;\n\n\tconst shape: Record<string, z.ZodTypeAny> = {};\n\n\tfor (const field of fields) {\n\t\tif (field.blockType === 'text' || field.blockType === 'textarea') {\n\t\t\tshape[field.name] = field.required\n\t\t\t\t? z.string().min(1, { message: `${field.label || field.name} is required` })\n\t\t\t\t: z.string().optional();\n\t\t} else if (field.blockType === 'email') {\n\t\t\tshape[field.name] = field.required\n\t\t\t\t? z.string().email({ message: 'Invalid email' })\n\t\t\t\t: z.string().email({ message: 'Invalid email' }).optional();\n\t\t} else if (field.blockType === 'number') {\n\t\t\tshape[field.name] = field.required ? z.number() : z.number().optional();\n\t\t} else if (field.blockType === 'checkbox') {\n\t\t\tshape[field.name] = field.required\n\t\t\t\t? z.boolean().refine((val) => val === true, {\n\t\t\t\t\t\tmessage: `${field.label || field.name} must be checked`,\n\t\t\t\t\t})\n\t\t\t\t: z.boolean().optional();\n\t\t}\n\t}\n\n\treturn z.object(shape) as z.ZodObject<Record<string, z.ZodTypeAny>>;\n};\n"],"names":["z","generateFormSchema","fields","length","object","shape","field","blockType","name","required","string","min","message","label","optional","email","number","boolean","refine","val"],"mappings":"AAAA,SAASA,CAAC,QAAQ,MAAM;AAyDxB;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BC,GACD,OAAO,MAAMC,qBAAqB,CACjCC;IAEA,IAAI,CAACA,QAAQC,QAAQ,OAAOH,EAAEI,MAAM,CAAC,CAAC;IAEtC,MAAMC,QAAsC,CAAC;IAE7C,KAAK,MAAMC,SAASJ,OAAQ;QAC3B,IAAII,MAAMC,SAAS,KAAK,UAAUD,MAAMC,SAAS,KAAK,YAAY;YACjEF,KAAK,CAACC,MAAME,IAAI,CAAC,GAAGF,MAAMG,QAAQ,GAC/BT,EAAEU,MAAM,GAAGC,GAAG,CAAC,GAAG;gBAAEC,SAAS,GAAGN,MAAMO,KAAK,IAAIP,MAAME,IAAI,CAAC,YAAY,CAAC;YAAC,KACxER,EAAEU,MAAM,GAAGI,QAAQ;QACvB,OAAO,IAAIR,MAAMC,SAAS,KAAK,SAAS;YACvCF,KAAK,CAACC,MAAME,IAAI,CAAC,GAAGF,MAAMG,QAAQ,GAC/BT,EAAEU,MAAM,GAAGK,KAAK,CAAC;gBAAEH,SAAS;YAAgB,KAC5CZ,EAAEU,MAAM,GAAGK,KAAK,CAAC;gBAAEH,SAAS;YAAgB,GAAGE,QAAQ;QAC3D,OAAO,IAAIR,MAAMC,SAAS,KAAK,UAAU;YACxCF,KAAK,CAACC,MAAME,IAAI,CAAC,GAAGF,MAAMG,QAAQ,GAAGT,EAAEgB,MAAM,KAAKhB,EAAEgB,MAAM,GAAGF,QAAQ;QACtE,OAAO,IAAIR,MAAMC,SAAS,KAAK,YAAY;YAC1CF,KAAK,CAACC,MAAME,IAAI,CAAC,GAAGF,MAAMG,QAAQ,GAC/BT,EAAEiB,OAAO,GAAGC,MAAM,CAAC,CAACC,MAAQA,QAAQ,MAAM;gBAC1CP,SAAS,GAAGN,MAAMO,KAAK,IAAIP,MAAME,IAAI,CAAC,gBAAgB,CAAC;YACxD,KACCR,EAAEiB,OAAO,GAAGH,QAAQ;QACxB;IACD;IAEA,OAAOd,EAAEI,MAAM,CAACC;AACjB,EAAE"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/forms/schema.test.ts"],"sourcesContent":["import { describe, expect, test } from 'vitest';\nimport { z } from 'zod';\n\nimport { generateFormSchema } from './schema';\n\ndescribe('generateFormSchema', () => {\n\ttest('returns empty object schema when no fields provided', () => {\n\t\tconst schema = generateFormSchema(null);\n\t\texpect(schema).toBeInstanceOf(z.ZodObject);\n\t\texpect(schema.shape).toEqual({});\n\t});\n\n\ttest('returns empty object schema for empty array', () => {\n\t\tconst schema = generateFormSchema([]);\n\t\texpect(schema).toBeInstanceOf(z.ZodObject);\n\t\texpect(schema.shape).toEqual({});\n\t});\n\n\ttest('generates required text field schema', () => {\n\t\tconst fields = [\n\t\t\t{\n\t\t\t\tblockType: 'text' as const,\n\t\t\t\tname: 'firstName',\n\t\t\t\tlabel: 'First Name',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t];\n\n\t\tconst schema = generateFormSchema(fields);\n\t\tconst result = schema.safeParse({ firstName: '' });\n\t\texpect(result.success).toBe(false);\n\n\t\tconst validResult = schema.safeParse({ firstName: 'John' });\n\t\texpect(validResult.success).toBe(true);\n\t});\n\n\ttest('generates optional text field schema', () => {\n\t\tconst fields = [\n\t\t\t{\n\t\t\t\tblockType: 'text' as const,\n\t\t\t\tname: 'middleName',\n\t\t\t\tlabel: 'Middle Name',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t];\n\n\t\tconst schema = generateFormSchema(fields);\n\t\tconst result = schema.safeParse({});\n\t\texpect(result.success).toBe(true);\n\t});\n\n\ttest('generates required email field schema', () => {\n\t\tconst fields = [\n\t\t\t{\n\t\t\t\tblockType: 'email' as const,\n\t\t\t\tname: 'email',\n\t\t\t\tlabel: 'Email',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t];\n\n\t\tconst schema = generateFormSchema(fields);\n\t\tconst invalidResult = schema.safeParse({ email: 'not-an-email' });\n\t\texpect(invalidResult.success).toBe(false);\n\n\t\tconst validResult = schema.safeParse({ email: 'test@example.com' });\n\t\texpect(validResult.success).toBe(true);\n\t});\n\n\ttest('generates required checkbox field schema', () => {\n\t\tconst fields = [\n\t\t\t{\n\t\t\t\tblockType: 'checkbox' as const,\n\t\t\t\tname: 'terms',\n\t\t\t\tlabel: 'Accept Terms',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t];\n\n\t\tconst schema = generateFormSchema(fields);\n\t\tconst falseResult = schema.safeParse({ terms: false });\n\t\texpect(falseResult.success).toBe(false);\n\n\t\tconst trueResult = schema.safeParse({ terms: true });\n\t\texpect(trueResult.success).toBe(true);\n\t});\n\n\ttest('generates schema with multiple fields', () => {\n\t\tconst fields = [\n\t\t\t{\n\t\t\t\tblockType: 'text' as const,\n\t\t\t\tname: 'name',\n\t\t\t\tlabel: 'Name',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tblockType: 'email' as const,\n\t\t\t\tname: 'email',\n\t\t\t\tlabel: 'Email',\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\tblockType: 'textarea' as const,\n\t\t\t\tname: 'message',\n\t\t\t\tlabel: 'Message',\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t];\n\n\t\tconst schema = generateFormSchema(fields);\n\t\tconst result = schema.safeParse({\n\t\t\tname: 'John',\n\t\t\temail: 'john@example.com',\n\t\t});\n\t\texpect(result.success).toBe(true);\n\t});\n});\n"],"names":["describe","expect","test","z","generateFormSchema","schema","toBeInstanceOf","ZodObject","shape","toEqual","fields","blockType","name","label","required","result","safeParse","firstName","success","toBe","validResult","invalidResult","email","falseResult","terms","trueResult"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,IAAI,QAAQ,SAAS;AAChD,SAASC,CAAC,QAAQ,MAAM;AAExB,SAASC,kBAAkB,QAAQ,WAAW;AAE9CJ,SAAS,sBAAsB;IAC9BE,KAAK,uDAAuD;QAC3D,MAAMG,SAASD,mBAAmB;QAClCH,OAAOI,QAAQC,cAAc,CAACH,EAAEI,SAAS;QACzCN,OAAOI,OAAOG,KAAK,EAAEC,OAAO,CAAC,CAAC;IAC/B;IAEAP,KAAK,+CAA+C;QACnD,MAAMG,SAASD,mBAAmB,EAAE;QACpCH,OAAOI,QAAQC,cAAc,CAACH,EAAEI,SAAS;QACzCN,OAAOI,OAAOG,KAAK,EAAEC,OAAO,CAAC,CAAC;IAC/B;IAEAP,KAAK,wCAAwC;QAC5C,MAAMQ,SAAS;YACd;gBACCC,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;SACA;QAED,MAAMT,SAASD,mBAAmBM;QAClC,MAAMK,SAASV,OAAOW,SAAS,CAAC;YAAEC,WAAW;QAAG;QAChDhB,OAAOc,OAAOG,OAAO,EAAEC,IAAI,CAAC;QAE5B,MAAMC,cAAcf,OAAOW,SAAS,CAAC;YAAEC,WAAW;QAAO;QACzDhB,OAAOmB,YAAYF,OAAO,EAAEC,IAAI,CAAC;IAClC;IAEAjB,KAAK,wCAAwC;QAC5C,MAAMQ,SAAS;YACd;gBACCC,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;SACA;QAED,MAAMT,SAASD,mBAAmBM;QAClC,MAAMK,SAASV,OAAOW,SAAS,CAAC,CAAC;QACjCf,OAAOc,OAAOG,OAAO,EAAEC,IAAI,CAAC;IAC7B;IAEAjB,KAAK,yCAAyC;QAC7C,MAAMQ,SAAS;YACd;gBACCC,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;SACA;QAED,MAAMT,SAASD,mBAAmBM;QAClC,MAAMW,gBAAgBhB,OAAOW,SAAS,CAAC;YAAEM,OAAO;QAAe;QAC/DrB,OAAOoB,cAAcH,OAAO,EAAEC,IAAI,CAAC;QAEnC,MAAMC,cAAcf,OAAOW,SAAS,CAAC;YAAEM,OAAO;QAAmB;QACjErB,OAAOmB,YAAYF,OAAO,EAAEC,IAAI,CAAC;IAClC;IAEAjB,KAAK,4CAA4C;QAChD,MAAMQ,SAAS;YACd;gBACCC,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;SACA;QAED,MAAMT,SAASD,mBAAmBM;QAClC,MAAMa,cAAclB,OAAOW,SAAS,CAAC;YAAEQ,OAAO;QAAM;QACpDvB,OAAOsB,YAAYL,OAAO,EAAEC,IAAI,CAAC;QAEjC,MAAMM,aAAapB,OAAOW,SAAS,CAAC;YAAEQ,OAAO;QAAK;QAClDvB,OAAOwB,WAAWP,OAAO,EAAEC,IAAI,CAAC;IACjC;IAEAjB,KAAK,yCAAyC;QAC7C,MAAMQ,SAAS;YACd;gBACCC,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;YACA;gBACCH,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;YACA;gBACCH,WAAW;gBACXC,MAAM;gBACNC,OAAO;gBACPC,UAAU;YACX;SACA;QAED,MAAMT,SAASD,mBAAmBM;QAClC,MAAMK,SAASV,OAAOW,SAAS,CAAC;YAC/BJ,MAAM;YACNU,OAAO;QACR;QACArB,OAAOc,OAAOG,OAAO,EAAEC,IAAI,CAAC;IAC7B;AACD"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/strings/index.ts"],"sourcesContent":["/**\n * Generates an alphanumeric random string.\n *\n * @param length - The length of the string to generate.\n * @returns The generated random string.\n *\n * @example\n * ```typescript\n * const id = generateRandomString(10)\n * // Returns something like: \"a3k9mxp2q1\"\n * ```\n */\nexport const generateRandomString = (length: number): string => {\n\tlet result = '';\n\twhile (result.length < length) {\n\t\tresult += (Math.random() + 1).toString(36).substring(2);\n\t}\n\treturn result.substring(0, length);\n};\n"],"names":["generateRandomString","length","result","Math","random","toString","substring"],"mappings":"AAAA;;;;;;;;;;;CAWC,GACD,OAAO,MAAMA,uBAAuB,CAACC;IACpC,IAAIC,SAAS;IACb,MAAOA,OAAOD,MAAM,GAAGA,OAAQ;QAC9BC,UAAU,AAACC,CAAAA,KAAKC,MAAM,KAAK,CAAA,EAAGC,QAAQ,CAAC,IAAIC,SAAS,CAAC;IACtD;IACA,OAAOJ,OAAOI,SAAS,CAAC,GAAGL;AAC5B,EAAE"}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/utils/strings/index.test.ts"],"sourcesContent":["import { describe, expect, test } from 'vitest';\n\nimport { generateRandomString } from './index';\n\ndescribe('generateRandomString', () => {\n\ttest('generates a string of the specified length', () => {\n\t\tconst length = 10;\n\t\tconst result = generateRandomString(length);\n\t\texpect(result).toHaveLength(length);\n\t});\n\n\ttest('generates alphanumeric characters only', () => {\n\t\tconst result = generateRandomString(100);\n\t\texpect(result).toMatch(/^[a-z0-9]+$/);\n\t});\n\n\ttest('generates different strings on multiple calls', () => {\n\t\tconst first = generateRandomString(20);\n\t\tconst second = generateRandomString(20);\n\t\texpect(first).not.toBe(second);\n\t});\n\n\ttest('handles length of 0', () => {\n\t\tconst result = generateRandomString(0);\n\t\texpect(result).toBe('');\n\t});\n\n\ttest('handles length of 1', () => {\n\t\tconst result = generateRandomString(1);\n\t\texpect(result).toHaveLength(1);\n\t});\n});\n"],"names":["describe","expect","test","generateRandomString","length","result","toHaveLength","toMatch","first","second","not","toBe"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,IAAI,QAAQ,SAAS;AAEhD,SAASC,oBAAoB,QAAQ,UAAU;AAE/CH,SAAS,wBAAwB;IAChCE,KAAK,8CAA8C;QAClD,MAAME,SAAS;QACf,MAAMC,SAASF,qBAAqBC;QACpCH,OAAOI,QAAQC,YAAY,CAACF;IAC7B;IAEAF,KAAK,0CAA0C;QAC9C,MAAMG,SAASF,qBAAqB;QACpCF,OAAOI,QAAQE,OAAO,CAAC;IACxB;IAEAL,KAAK,iDAAiD;QACrD,MAAMM,QAAQL,qBAAqB;QACnC,MAAMM,SAASN,qBAAqB;QACpCF,OAAOO,OAAOE,GAAG,CAACC,IAAI,CAACF;IACxB;IAEAP,KAAK,uBAAuB;QAC3B,MAAMG,SAASF,qBAAqB;QACpCF,OAAOI,QAAQM,IAAI,CAAC;IACrB;IAEAT,KAAK,uBAAuB;QAC3B,MAAMG,SAASF,qBAAqB;QACpCF,OAAOI,QAAQC,YAAY,CAAC;IAC7B;AACD"}