@functionalcms/svelte-components 4.10.23 → 4.10.25

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.
@@ -1,7 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../../utils.js';
3
3
  import type { Snippet } from 'svelte';
4
- import type { EventHandler } from 'svelte/elements';
5
4
 
6
5
  interface Props {
7
6
  children: Snippet;
@@ -36,7 +36,7 @@
36
36
  size = '',
37
37
  // Provides bind:checked capabilities that consumer can use
38
38
  checked = $bindable([]),
39
- ...restProps
39
+ ...restProps
40
40
  }: Partial<Props & HtmlParts> = $props();
41
41
 
42
42
  let labelClasses = $derived(
@@ -96,29 +96,31 @@
96
96
  };
97
97
  </script>
98
98
 
99
- <fieldset class={fieldsetClasses}>
100
- <legend class={legendClasses}>{label}</legend>
101
- {#each options as { value, label }, index}
102
- <label
103
- class={labelClasses}
104
- class:disabled={isDisabled || disabledOptions.includes(value) || undefined}
105
- >
106
- <input
107
- class={inputClasses}
108
- id="{id}-{name}-{index}"
109
- {type}
110
- {name}
111
- {value}
112
- disabled={isDisabled || disabledOptions.includes(value)}
113
- checked={checkedOptions.includes(value)}
114
- onchange={onChange}
115
- {...restProps}
116
- />
117
- <span class={labelSpanClasses} aria-hidden="true"></span>
118
- <span class={labelCopyClasses}>{label}</span>
119
- </label>
120
- {/each}
121
- </fieldset>
99
+ <div class="w-100">
100
+ <fieldset class={fieldsetClasses}>
101
+ <legend class={legendClasses}>{label}</legend>
102
+ {#each options as { value, label }, index}
103
+ <label
104
+ class={labelClasses}
105
+ class:disabled={isDisabled || disabledOptions.includes(value) || undefined}
106
+ >
107
+ <input
108
+ class={inputClasses}
109
+ id="{id}-{name}-{index}"
110
+ {type}
111
+ {name}
112
+ {value}
113
+ disabled={isDisabled || disabledOptions.includes(value)}
114
+ checked={checkedOptions.includes(value)}
115
+ onchange={onChange}
116
+ {...restProps}
117
+ />
118
+ <span class={labelSpanClasses} aria-hidden="true"></span>
119
+ <span class={labelCopyClasses}>{label}</span>
120
+ </label>
121
+ {/each}
122
+ </fieldset>
123
+ </div>
122
124
 
123
125
  <style>
124
126
  /**
@@ -1,100 +1,48 @@
1
1
  <script lang="ts">
2
+ import { mapEntiresToOptions, type Field } from "./form.js";
2
3
  import ChoiceInput from "./ChoiceInput.svelte";
3
- import type { Field, Validation } from "./form.js";
4
4
  import Input from "./Input.svelte";
5
5
  import Select from "./Select.svelte";
6
6
  import Switch from "./Switch.svelte";
7
7
 
8
+ interface Props {
9
+ action: string;
10
+ schema: Array<Field>;
11
+ }
8
12
 
9
- interface Props {
10
- schema: Validation;
11
- }
12
-
13
- let { schema }: Props = $props();
14
-
15
- const fields = Object.keys(schema.shape).map((key) => ({
16
- name: key,
17
- type:
18
- schema.shape[key].def.type == 'optional'
19
- ? schema.shape[key].def.innerType._def.type
20
- : schema.shape[key].def.type,
21
- subType: schema.shape[key].def.format,
22
- meta: { ...schema.shape[key].meta() },
23
- entries: schema.shape[key]._def.innerType
24
- ? schema.shape[key]._def.innerType._def.entries
25
- : schema.shape[key]._def.entries,
26
- field: schema.shape[key]
27
- }));
28
-
29
- function getFieldType(field: Field) {
30
- if (field.type === 'number') {
31
- return 'number';
32
- }
33
- if (field.meta.multiline) {
34
- return 'textarea';
35
- }
36
- if (field.meta.secure) {
37
- return 'password';
38
- }
39
- switch (field.subType) {
40
- case 'email':
41
- return 'email';
42
- case 'url':
43
- return 'url';
44
- case 'tel':
45
- return 'tel';
46
- case 'password':
47
- return 'password';
48
- case 'email':
49
- return 'email';
50
- }
51
- return 'string';
52
- }
53
-
54
- function mapEntiresToOptions(field: Field) {
55
- if (field.entries) {
56
- let result = Object.keys(field.entries).map((key) => ({
57
- label: key,
58
- value: field.entries[key]
59
- }));
60
- return result;
61
- } else {
62
- return [];
63
- }
64
- }
13
+ let { action, schema }: Props = $props();
65
14
  </script>
66
15
 
67
- <form method="POST">
68
- <fieldset>
69
- {#each fields as field}
70
- <div>
71
- {#if field.type === 'boolean'}
72
- <Switch name={field.name} id={field.name} label={field.name} />
73
- {:else if field.type === 'enum' && field.meta.type === 'select'}
74
- <Select
75
- name={field.name}
76
- id={field.name}
77
- label={field.name}
78
- options={mapEntiresToOptions(field)}
79
- />
80
- {:else if field.type === 'enum'}
81
- <ChoiceInput
82
- name={field.name}
83
- id={field.name}
84
- label={field.name}
85
- type={field.meta.type}
86
- options={mapEntiresToOptions(field)}
87
- />
88
- {:else if field.type === 'string' || field.type === 'number'}
89
- <Input
90
- name={field.name}
91
- id={field.name}
92
- label={field.name}
93
- type={getFieldType(field)}
94
- required
95
- />
96
- {/if}
97
- </div>
98
- {/each}
99
- </fieldset>
16
+ <form method="POST" {action}>
17
+ <fieldset>
18
+ {#each schema as field}
19
+ {#if field.type === "boolean"}
20
+ <Switch name={field.name} id={field.name} label={field.name} />
21
+ {:else if field.type === "enum" && field.meta.type === "select"}
22
+ <Select
23
+ name={field.name}
24
+ id={field.name}
25
+ label={field.name}
26
+ options={mapEntiresToOptions(field)}
27
+ singleSelected="LOW"
28
+ />
29
+ {:else if field.type === "enum"}
30
+ <ChoiceInput
31
+ name={field.name}
32
+ id={field.name}
33
+ label={field.name}
34
+ type={field.meta.type}
35
+ options={mapEntiresToOptions(field)}
36
+ />
37
+ {:else if field.type === "string" || field.type === "number"}
38
+ <Input
39
+ name={field.name}
40
+ id={field.name}
41
+ label={field.name}
42
+ type={field.meta.type}
43
+ isRequired={field.isRequired}
44
+ />
45
+ {/if}
46
+ {/each}
47
+ </fieldset>
100
48
  </form>
@@ -1,6 +1,7 @@
1
- import type { Validation } from "./form.js";
1
+ import { type Field } from "./form.js";
2
2
  interface Props {
3
- schema: Validation;
3
+ action: string;
4
+ schema: Array<Field>;
4
5
  }
5
6
  declare const Form: import("svelte").Component<Props, {}, "">;
6
7
  type Form = ReturnType<typeof Form>;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import { cn } from "../../utils.js";
2
+ import { cn } from '../../utils.js';
3
3
 
4
4
  interface Props {
5
5
  id: string;
@@ -32,7 +32,7 @@
32
32
  css = '',
33
33
  singleSelected = $bindable(''),
34
34
  multiSelected = $bindable([]), // multiSelected can be used for two-way bindings
35
- selected = () => {},
35
+ selected = () => {}
36
36
  }: Partial<Props> = $props();
37
37
 
38
38
  const changeHandler = () => {
@@ -42,45 +42,45 @@
42
42
 
43
43
  let disable = isDisabled;
44
44
  let classes = $derived(
45
- cn(
46
- isSkinned ? 'select' : 'select-base',
47
- size ? `select-${size}` : '',
48
- css ? `${css}` : ''));
45
+ cn(isSkinned ? 'select' : 'select-base', size ? `select-${size}` : '', css ? `${css}` : '')
46
+ );
49
47
  </script>
50
48
 
51
- <label class="screenreader-only" for={id}> {label} </label>
52
- {#if isMultiple}
53
- <select
54
- id={id}
55
- class={classes}
56
- {name}
57
- disabled={disable}
58
- multiple
59
- size={multipleSize}
60
- bind:value={multiSelected}
61
- onchange={changeHandler}
62
- >
63
- {#each options as { value, label }}
64
- <option {value}>{label}</option>
65
- {/each}
66
- </select>
67
- {:else}
68
- <select
69
- id={id}
70
- class={classes}
71
- {name}
72
- disabled={disable}
73
- bind:value={singleSelected}
74
- onchange={changeHandler}
75
- >
76
- <option value="" disabled selected>
77
- {defaultOptionLabel}
78
- </option>
79
- {#each options as { value, label }}
80
- <option {value}>{label}</option>
81
- {/each}
82
- </select>
83
- {/if}
49
+ <div class="w-100">
50
+ <label class="label" for={id}> {label} </label>
51
+ {#if isMultiple}
52
+ <select
53
+ {id}
54
+ class={classes}
55
+ {name}
56
+ disabled={disable}
57
+ multiple
58
+ size={multipleSize}
59
+ bind:value={multiSelected}
60
+ onchange={changeHandler}
61
+ >
62
+ {#each options as { value, label }}
63
+ <option {value}>{label}</option>
64
+ {/each}
65
+ </select>
66
+ {:else}
67
+ <select
68
+ {id}
69
+ class={classes}
70
+ {name}
71
+ disabled={disable}
72
+ bind:value={singleSelected}
73
+ onchange={changeHandler}
74
+ >
75
+ <option value="" disabled selected>
76
+ {defaultOptionLabel}
77
+ </option>
78
+ {#each options as { value, label }}
79
+ <option {value}>{label}</option>
80
+ {/each}
81
+ </select>
82
+ {/if}
83
+ </div>
84
84
 
85
85
  <style>
86
86
  .select,
@@ -160,4 +160,38 @@
160
160
  padding-left: var(--fluid-16);
161
161
  font-size: var(--fluid-18);
162
162
  }
163
+ .field-help,
164
+ .field-help-large,
165
+ .field-help-small,
166
+ .field-error,
167
+ .field-error-large,
168
+ .field-error-small,
169
+ .label-skin,
170
+ .label,
171
+ .input-addon-container,
172
+ .input-small,
173
+ .input-large,
174
+ .input-skin,
175
+ .input-underlined,
176
+ .input-underlined-bg,
177
+ .input {
178
+ color: var(--font-color, var(--dark));
179
+ font-family: var(--font-family-body);
180
+ font-weight: var(--font-weight, 300);
181
+ font-size: var(--font-size, 1rem);
182
+ line-height: var(--line-height, var(--fluid-20, 1.25rem));
183
+ width: 100%;
184
+ max-width: 100%;
185
+ }
186
+ .label {
187
+ display: inline-block;
188
+
189
+ /* Provided --input-vertical-pad isn't overriden we'll get 20px
190
+ label w/a 6px margin then a 38px input = 64 which is on the 8pt grid */
191
+ margin-block-start: 0;
192
+ margin-inline-start: 0;
193
+ margin-inline-end: 0;
194
+ margin-block-end: var(--input-label-pad, 0.375rem);
195
+ vertical-align: initial;
196
+ }
163
197
  </style>
@@ -15,7 +15,7 @@
15
15
  }
16
16
  let {
17
17
  id = '',
18
- name= '',
18
+ name = '',
19
19
  label = '',
20
20
  css = '',
21
21
  labelPosition = 'left',
@@ -64,22 +64,24 @@
64
64
  };
65
65
  </script>
66
66
 
67
- <label class={switchContainer} for={id}>
68
- {#if labelPosition === 'left'}<span class="switch-label">{label}</span>{/if}
69
- <input
70
- type="checkbox"
71
- class="switch-input"
72
- {id}
73
- {name}
74
- bind:checked={isChecked}
75
- disabled={isDisabled}
76
- onclick={handleClick}
77
- onkeypress={handleKeypress}
78
- role="switch"
79
- />
80
- <span class={switchSpan()} aria-hidden="true"></span>
81
- {#if labelPosition === 'right'}<span class="switch-label">{label}</span>{/if}
82
- </label>
67
+ <div class="w-100">
68
+ <label class={switchContainer} for={id}>
69
+ {#if labelPosition === 'left'}<span class="switch-label">{label}</span>{/if}
70
+ <input
71
+ type="checkbox"
72
+ class="switch-input"
73
+ {id}
74
+ {name}
75
+ bind:checked={isChecked}
76
+ disabled={isDisabled}
77
+ onclick={handleClick}
78
+ onkeypress={handleKeypress}
79
+ role="switch"
80
+ />
81
+ <span class={switchSpan()} aria-hidden="true"></span>
82
+ {#if labelPosition === 'right'}<span class="switch-label">{label}</span>{/if}
83
+ </label>
84
+ </div>
83
85
 
84
86
  <style>
85
87
  /**
@@ -1,11 +1,12 @@
1
1
  export interface Field {
2
2
  name: string;
3
3
  type: string;
4
- subType?: string;
4
+ entries: Array<string>;
5
5
  meta: any;
6
- entries?: any[];
7
- field: any;
8
- }
9
- export interface Validation {
10
- shape: any;
6
+ isRequired: boolean;
11
7
  }
8
+ export declare function serialize(schema: any): Array<Field>;
9
+ export declare function mapEntiresToOptions(field: Field): {
10
+ label: string;
11
+ value: string;
12
+ }[];
@@ -1 +1,22 @@
1
- export {};
1
+ export function serialize(schema) {
2
+ const keys = schema._nodes.reverse();
3
+ const fields = keys.map((key) => {
4
+ const field = schema.fields[key];
5
+ const hasEntries = field._whitelist.size > 0;
6
+ const isOptional = field.spec.optional ?? true;
7
+ return {
8
+ name: key,
9
+ type: hasEntries ? "enum" : field.type,
10
+ entries: hasEntries ? [...field._whitelist] : [],
11
+ meta: field.spec.meta ?? {},
12
+ isRequired: !isOptional,
13
+ };
14
+ });
15
+ return fields;
16
+ }
17
+ export function mapEntiresToOptions(field) {
18
+ return (field?.entries?.map((entry) => ({
19
+ label: entry,
20
+ value: entry,
21
+ })) ?? []);
22
+ }
@@ -1,11 +1,8 @@
1
1
  <script lang="ts">
2
- import { HeaderNavigationItem, defaultCss } from './types.js';
3
- import { afterNavigate } from '$app/navigation';
2
+ import { HeaderNavigationItem } from './types.js';
4
3
  import { cn } from '../../utils.js';
5
4
  import { Placement } from '../Styling.js';
6
5
  import Button from '../form/Button.svelte';
7
- import Drawer from '../presentation/Drawer.svelte';
8
- import ListMenu from './ListMenu.svelte';
9
6
  import type { Snippet } from 'svelte';
10
7
 
11
8
  interface Css {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionalcms/svelte-components",
3
- "version": "4.10.23",
3
+ "version": "4.10.25",
4
4
  "watch": {
5
5
  "build": {
6
6
  "patterns": [
@@ -70,7 +70,8 @@
70
70
  "ioredis": "^5.6.1",
71
71
  "marked": "^15.0.11",
72
72
  "oauth4webapi": "^3.5.0",
73
- "sveltekit-superforms": "^2.25.0"
73
+ "sveltekit-superforms": "^2.25.0",
74
+ "yup": "^1.6.1"
74
75
  },
75
76
  "peerDependencies": {
76
77
  "@sveltejs/kit": "^2.20.8",