lutra 0.0.11 → 0.0.12
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.
- package/dist/form/FieldContent.svelte +17 -2
- package/dist/form/FieldContent.svelte.d.ts +4 -0
- package/dist/form/Input.svelte +13 -13
- package/dist/form/Input.svelte.d.ts +1 -1
- package/dist/form/Select.svelte +97 -13
- package/dist/form/Select.svelte.d.ts +81 -5
- package/dist/form/client.svelte.js +3 -2
- package/dist/form/form.d.ts +3 -3
- package/dist/form/types.d.ts +2 -7
- package/package.json +2 -2
@@ -1,4 +1,5 @@
|
|
1
1
|
<script>import Label from "./Label.svelte";
|
2
|
+
import FieldError from "./FieldError.svelte";
|
2
3
|
let {
|
3
4
|
id,
|
4
5
|
contained,
|
@@ -7,12 +8,16 @@ let {
|
|
7
8
|
label,
|
8
9
|
labelTip,
|
9
10
|
type = "text",
|
10
|
-
|
11
|
+
direction = "column",
|
12
|
+
// 'row' | 'column'
|
13
|
+
children,
|
14
|
+
field,
|
15
|
+
issue
|
11
16
|
} = $props();
|
12
17
|
</script>
|
13
18
|
|
14
19
|
|
15
|
-
<div class="FieldContent {type}" class:contained>
|
20
|
+
<div class="FieldContent {type} {direction}" class:contained>
|
16
21
|
<Label {label} tip={labelTip} {id} />
|
17
22
|
{#if contained}
|
18
23
|
<div class="Field">
|
@@ -27,6 +32,10 @@ let {
|
|
27
32
|
{:else}
|
28
33
|
{@render children()}
|
29
34
|
{/if}
|
35
|
+
|
36
|
+
{#if field?.tainted && issue?.code}
|
37
|
+
<FieldError code={issue.code} message={issue.message} />
|
38
|
+
{/if}
|
30
39
|
</div>
|
31
40
|
|
32
41
|
<style>
|
@@ -75,4 +84,10 @@ let {
|
|
75
84
|
outline-offset: 3px;
|
76
85
|
border-radius: calc(var(--field-radius) - 2px);
|
77
86
|
}
|
87
|
+
/**
|
88
|
+
* Row
|
89
|
+
*/
|
90
|
+
.FieldContent.row {
|
91
|
+
flex-direction: row;
|
92
|
+
}
|
78
93
|
</style>
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
2
2
|
import type { Snippet } from "svelte";
|
3
|
+
import type { FormField, FormIssue } from "./types.js";
|
3
4
|
declare const __propDef: {
|
4
5
|
props: {
|
5
6
|
id: string;
|
@@ -17,7 +18,10 @@ declare const __propDef: {
|
|
17
18
|
labelTip?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
18
19
|
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
19
20
|
}) | undefined;
|
21
|
+
direction?: "row" | "column" | undefined;
|
20
22
|
children: Snippet;
|
23
|
+
field?: FormField | undefined;
|
24
|
+
issue?: FormIssue | undefined;
|
21
25
|
};
|
22
26
|
events: {
|
23
27
|
[evt: string]: CustomEvent<any>;
|
package/dist/form/Input.svelte
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
<script>import { getContext
|
2
|
-
import Label from "./Label.svelte";
|
1
|
+
<script>import { getContext } from "svelte";
|
3
2
|
import { createId } from "../utils/id.js";
|
4
3
|
import Copy from "../icons/Copy.svelte";
|
5
4
|
import Done from "../icons/Done.svelte";
|
@@ -11,6 +10,7 @@ import { fieldChange, fieldKeydown, ignoreKeys } from "./client.svelte.js";
|
|
11
10
|
import FieldError from "./FieldError.svelte";
|
12
11
|
import { getFromObjWithStringPath } from "./form.js";
|
13
12
|
import { ZodType } from "zod";
|
13
|
+
import FieldContent from "./FieldContent.svelte";
|
14
14
|
let {
|
15
15
|
alt,
|
16
16
|
autocapitalize,
|
@@ -136,9 +136,9 @@ function copy(e) {
|
|
136
136
|
{name}
|
137
137
|
{onblur}
|
138
138
|
{onclick}
|
139
|
-
onchange={fieldChange(form, name, () => el, validator)}
|
139
|
+
onchange={fieldChange(form, name, () => el, validator, onchange)}
|
140
140
|
{onfocus}
|
141
|
-
onkeydown={fieldKeydown(form, name, () => el, validator)}
|
141
|
+
onkeydown={fieldKeydown(form, name, () => el, validator, onkeydown)}
|
142
142
|
{onkeyup}
|
143
143
|
{onkeypress}
|
144
144
|
pattern={pattern ? pattern : field?.pattern}
|
@@ -155,12 +155,15 @@ function copy(e) {
|
|
155
155
|
{webkitdirectory}
|
156
156
|
/>
|
157
157
|
{/snippet}
|
158
|
-
<div
|
159
|
-
class="FieldContainer {type}"
|
160
|
-
class:checkOrRadio={type === "checkbox" || type === "radio"}
|
161
|
-
>
|
162
158
|
|
163
|
-
|
159
|
+
<FieldContent
|
160
|
+
{id}
|
161
|
+
{label}
|
162
|
+
{labelTip}
|
163
|
+
direction={(type === "checkbox" || type === "radio") ? 'row' : 'column'}
|
164
|
+
{field}
|
165
|
+
{issue}
|
166
|
+
>
|
164
167
|
|
165
168
|
{#if type === "checkbox" || type === "radio"}
|
166
169
|
{@render input()}
|
@@ -206,11 +209,8 @@ function copy(e) {
|
|
206
209
|
</div>
|
207
210
|
{/if}
|
208
211
|
</div>
|
209
|
-
{#if field?.tainted && issue?.code}
|
210
|
-
<FieldError code={issue.code} message={issue.message} />
|
211
|
-
{/if}
|
212
212
|
{/if}
|
213
|
-
</
|
213
|
+
</FieldContent>
|
214
214
|
|
215
215
|
<style>
|
216
216
|
.FieldContainer {
|
@@ -117,7 +117,7 @@ declare const __propDef: {
|
|
117
117
|
events: {
|
118
118
|
[evt: string]: CustomEvent<any>;
|
119
119
|
};
|
120
|
-
slots: {};
|
120
|
+
slots: {}; /** Onclick event handler */
|
121
121
|
};
|
122
122
|
export type InputProps = typeof __propDef.props;
|
123
123
|
export type InputEvents = typeof __propDef.events;
|
package/dist/form/Select.svelte
CHANGED
@@ -1,22 +1,106 @@
|
|
1
|
-
<script>import
|
1
|
+
<script>import { getContext } from "svelte";
|
2
|
+
import Label from "./Label.svelte";
|
3
|
+
import { createId } from "../utils/id.js";
|
4
|
+
import Copy from "../icons/Copy.svelte";
|
5
|
+
import Done from "../icons/Done.svelte";
|
6
|
+
import Show from "../icons/Show.svelte";
|
7
|
+
import Hide from "../icons/Hide.svelte";
|
8
|
+
import Tooltip from "../display/Tooltip.svelte";
|
9
|
+
import IconButton from "../display/IconButton.svelte";
|
10
|
+
import { fieldChange, fieldKeydown, ignoreKeys } from "./client.svelte.js";
|
11
|
+
import FieldError from "./FieldError.svelte";
|
12
|
+
import { getFromObjWithStringPath } from "./form.js";
|
13
|
+
import { ZodType } from "zod";
|
14
|
+
import FieldContent from "./FieldContent.svelte";
|
2
15
|
let {
|
16
|
+
alt,
|
17
|
+
checked,
|
18
|
+
children,
|
19
|
+
contained,
|
20
|
+
defaultValue,
|
21
|
+
dirname,
|
22
|
+
disabled,
|
23
|
+
help,
|
24
|
+
id = $bindable(createId()),
|
3
25
|
label,
|
4
26
|
labelTip,
|
5
|
-
|
6
|
-
|
27
|
+
list,
|
28
|
+
maxlength,
|
29
|
+
minlength,
|
30
|
+
max,
|
31
|
+
min,
|
32
|
+
multiple,
|
33
|
+
name,
|
34
|
+
pattern,
|
35
|
+
placeholder,
|
36
|
+
suffix,
|
37
|
+
onblur,
|
38
|
+
onchange,
|
39
|
+
onclick,
|
40
|
+
onfocus,
|
41
|
+
onkeydown,
|
42
|
+
onkeyup,
|
43
|
+
onkeypress,
|
44
|
+
options,
|
45
|
+
prefix,
|
46
|
+
readonly,
|
47
|
+
required,
|
48
|
+
results,
|
49
|
+
shape = "rounded",
|
50
|
+
src,
|
51
|
+
tabindex,
|
52
|
+
value = $bindable()
|
7
53
|
} = $props();
|
8
|
-
let
|
54
|
+
let el = $state();
|
55
|
+
let copyTitle = $state("Copy");
|
56
|
+
let viewTitle = $state("Show");
|
57
|
+
let copyTooltipOpen = $state(false);
|
58
|
+
let copyBtnIcon = $state(Copy);
|
59
|
+
let viewBtnIcon = $state(Show);
|
60
|
+
const form = getContext("form");
|
61
|
+
const field = $derived(form.fields[name]);
|
62
|
+
const issue = $derived(form?.issues?.find((issue2) => issue2.name === name));
|
63
|
+
const validator = getContext("form.validators")?.[name];
|
64
|
+
const data = form?.data;
|
65
|
+
const originalData = form?.originalData;
|
9
66
|
</script>
|
10
67
|
|
11
|
-
<FieldContent
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
{
|
68
|
+
<FieldContent
|
69
|
+
{id}
|
70
|
+
{label}
|
71
|
+
{labelTip}
|
72
|
+
{field}
|
73
|
+
{issue}
|
74
|
+
>
|
75
|
+
<select
|
76
|
+
bind:this={el}
|
77
|
+
{disabled}
|
78
|
+
{id}
|
79
|
+
{name}
|
80
|
+
{onblur}
|
81
|
+
{onclick}
|
82
|
+
onchange={fieldChange(form, name, () => el, validator, onchange)}
|
83
|
+
{onfocus}
|
84
|
+
onkeydown={fieldKeydown(form, name, () => el, validator, onkeydown)}
|
85
|
+
{onkeyup}
|
86
|
+
{onkeypress}
|
87
|
+
{placeholder}
|
88
|
+
required={required || field?.required}
|
89
|
+
{results}
|
90
|
+
{tabindex}
|
91
|
+
value={value || getFromObjWithStringPath(Object.assign(originalData, data), name) || form?.fields?.[name]?.defaultValue || ''}
|
92
|
+
>
|
93
|
+
{#if children}
|
94
|
+
{@render children()}
|
95
|
+
{:else if options}
|
96
|
+
{#each options as option}
|
97
|
+
{#if typeof option === 'string'}
|
98
|
+
<option value={option}>{option}</option>
|
99
|
+
{:else}
|
100
|
+
<option value={option.value}>{option.label}</option>
|
101
|
+
{/if}
|
102
|
+
{/each}
|
103
|
+
{/if}
|
20
104
|
</select>
|
21
105
|
</FieldContent>
|
22
106
|
|
@@ -1,19 +1,95 @@
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
2
2
|
declare const __propDef: {
|
3
3
|
props: {
|
4
|
-
|
4
|
+
/** alt attribute for the image type. Required for accessibility */
|
5
|
+
alt?: string | undefined;
|
6
|
+
/** Whether the input should be checked. */
|
7
|
+
checked?: boolean | undefined;
|
8
|
+
/** Options for the select element. */
|
9
|
+
children?: ((this: void) => typeof import("svelte").SnippetReturn & {
|
5
10
|
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
6
11
|
}) | undefined;
|
7
|
-
|
12
|
+
/** Whether the input should be contained. */
|
13
|
+
contained?: boolean | undefined;
|
14
|
+
/** The default value of the input element. */
|
15
|
+
defaultValue?: string | undefined;
|
16
|
+
/** Form field name for the directionality of the element's text content during form submission */
|
17
|
+
dirname?: string | undefined;
|
18
|
+
/** Whether the input should be disabled. */
|
19
|
+
disabled?: boolean | undefined;
|
20
|
+
/** Help text to display below the input. */
|
21
|
+
help?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
8
22
|
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
9
23
|
}) | undefined;
|
10
|
-
|
24
|
+
/** A random id is generated if not provided. */
|
25
|
+
id?: string | undefined;
|
26
|
+
/** The label for the input */
|
27
|
+
label?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
28
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
29
|
+
}) | undefined;
|
30
|
+
/** Context tooltip for a label. Renders with a questionmark using ContextTip. */
|
31
|
+
labelTip?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
11
32
|
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
12
33
|
}) | undefined;
|
13
|
-
options
|
34
|
+
/** The id of a datalist element that contains pre-defined options for the input element. */
|
35
|
+
list?: string | undefined;
|
36
|
+
/** The maximum number of characters (as UTF-16 code units) the user can enter into the input. Valid for text, search, url, tel, email, and password. */
|
37
|
+
maxlength?: number | undefined;
|
38
|
+
/** The minimum number of characters (as UTF-16 code units) the user can enter into the input. Valid for text, search, url, tel, email, and password. */
|
39
|
+
minlength?: number | undefined;
|
40
|
+
/** The maximum value of the input element. Valid for date, month, week, time, datetime-local, number, and range. */
|
41
|
+
max?: number | undefined;
|
42
|
+
/** The minimum value of the input element. Valid for date, month, week, time, datetime-local, number, and range. */
|
43
|
+
min?: number | undefined;
|
44
|
+
/** Whether the input should allow multiple values. Valid for email and file inputs. */
|
45
|
+
multiple?: boolean | undefined;
|
46
|
+
/** The name of the input element. */
|
47
|
+
name: string;
|
48
|
+
/** The onblur event handler */
|
49
|
+
onblur?: ((e: FocusEvent) => void) | undefined;
|
50
|
+
/** Onchange event handler */
|
51
|
+
onchange?: ((e: Event) => void) | undefined;
|
52
|
+
/** Onclick event handler */
|
53
|
+
onclick?: ((e: MouseEvent) => void) | undefined;
|
54
|
+
/** Onfocus event handler */
|
55
|
+
onfocus?: ((e: FocusEvent) => void) | undefined;
|
56
|
+
/** Keyup event handler */
|
57
|
+
onkeyup?: ((e: KeyboardEvent) => void) | undefined;
|
58
|
+
/** Keydown event handler */
|
59
|
+
onkeydown?: ((e: KeyboardEvent) => void) | undefined;
|
60
|
+
/** Keypress event handler */
|
61
|
+
onkeypress?: ((e: KeyboardEvent) => void) | undefined;
|
62
|
+
/** The options for the select element. */
|
63
|
+
options?: string[] | {
|
14
64
|
value: string;
|
15
65
|
label: string;
|
16
|
-
}[];
|
66
|
+
}[] | undefined;
|
67
|
+
/** A regular expression that the input's value is checked against. Valid for text, search, url, tel, email, and password. */
|
68
|
+
pattern?: string | undefined;
|
69
|
+
/** Placeholder text to display when the input is empty. */
|
70
|
+
placeholder?: string | undefined;
|
71
|
+
/** Suffix content, to display after the input. */
|
72
|
+
suffix?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
73
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
74
|
+
}) | undefined;
|
75
|
+
/** Prefix content, to display before the input. */
|
76
|
+
prefix?: string | ((this: void) => typeof import("svelte").SnippetReturn & {
|
77
|
+
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
78
|
+
}) | undefined;
|
79
|
+
/** Whether the input should be read-only. */
|
80
|
+
readonly?: boolean | undefined;
|
81
|
+
/** Whether the input should be required. */
|
82
|
+
required?: boolean | undefined;
|
83
|
+
/** The maximum number of items that should be displayed in the drop-down list of previous search queries. Safari only. */
|
84
|
+
results?: number | undefined;
|
85
|
+
/** The shape of the input element. */
|
86
|
+
shape?: "default" | "circle" | "rounded" | "pill" | undefined;
|
87
|
+
/** Source URL for the image type. */
|
88
|
+
src?: string | undefined;
|
89
|
+
/** An integer attribute indicating if the element can take input focus (is focusable), if it should participate to sequential keyboard navigation. */
|
90
|
+
tabindex?: number | undefined;
|
91
|
+
/** The value of the input element. */
|
92
|
+
value?: string | undefined;
|
17
93
|
};
|
18
94
|
events: {
|
19
95
|
[evt: string]: CustomEvent<any>;
|
@@ -34,8 +34,8 @@ export function fieldValidate(form, name, el, validator) {
|
|
34
34
|
form.valid = false;
|
35
35
|
form.issues = (form.issues || []).filter((issue) => issue.name !== name);
|
36
36
|
form.issues?.push({
|
37
|
-
name,
|
38
|
-
...result.error.issues[0],
|
37
|
+
name, // Include the path of the field.
|
38
|
+
...((result.error?.issues?.length ? result.error.issues : [])?.[0]), // Include the first issue as we only care about one at a time.
|
39
39
|
});
|
40
40
|
}
|
41
41
|
}
|
@@ -72,6 +72,7 @@ export function fieldKeydown(form, name, el, validator, onkeydown) {
|
|
72
72
|
*/
|
73
73
|
export function fieldChange(form, name, el, validator, onchange) {
|
74
74
|
return async function (e) {
|
75
|
+
console.log('fieldChange', name, el()?.value, validator);
|
75
76
|
form.data[name] = el()?.value || '';
|
76
77
|
form.fields[name].tainted = true;
|
77
78
|
fieldValidate(form, name, el(), validator);
|
package/dist/form/form.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { Bodyguard, type BodyguardFormConfig, type BodyguardResult, type JSONLike } from "@auth70/bodyguard";
|
1
|
+
import { Bodyguard, type BodyguardFormConfig, type BodyguardResult, type GenericIssue, type JSONLike } from "@auth70/bodyguard";
|
2
2
|
import type { RequestEvent } from "@sveltejs/kit";
|
3
|
-
import type { ZodType, infer as Infer
|
3
|
+
import type { ZodType, infer as Infer } from "zod";
|
4
4
|
import type { Form, FormField, FormIssue, ZodTypes } from "./types.js";
|
5
5
|
export declare const bodyguard: Bodyguard;
|
6
6
|
/**
|
@@ -22,7 +22,7 @@ export declare function loadForm<Z extends ZodTypes>(schema: Z, event: RequestEv
|
|
22
22
|
* @param {ZodIssue[]} issues - The issues to parse.
|
23
23
|
* @returns {FormIssue[]} - The parsed issues.
|
24
24
|
*/
|
25
|
-
export declare function parseFormIssues(issues:
|
25
|
+
export declare function parseFormIssues(issues: GenericIssue[]): FormIssue[];
|
26
26
|
/**
|
27
27
|
* Parse a form using a schema.
|
28
28
|
* @param {ZodType} schema - The schema to parse the form with.
|
package/dist/form/types.d.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import type { GenericIssue } from "@auth70/bodyguard";
|
1
2
|
import type { ZodType, infer as Infer, ZodTuple, ZodBigInt, ZodNaN, ZodSet, ZodVoid, ZodUndefined, ZodNull, ZodAny, ZodUnknown, ZodNever, ZodRecord, ZodMap, ZodDiscriminatedUnion, ZodUnion, ZodIntersection, ZodNativeEnum, ZodEnum, ZodFunction, ZodLazy, ZodLiteral, ZodCatch, ZodPipeline, ZodBranded, ZodPromise, ZodArray, ZodNullable, ZodOptional, ZodEffects, ZodObject, ZodDefault, ZodString, ZodNumber, ZodBoolean, ZodDate } from "zod";
|
2
3
|
export type Autocomplete = 'on' | 'off' | AutocompleteSingleToken | AutocompleteBilling | AutocompleteShipping;
|
3
4
|
export type AutocompleteBilling = 'billing' | `billing ${AutocompleteSingleToken}`;
|
@@ -12,14 +13,8 @@ export type ADTs = ZodUnion<readonly [ZodTypes, ...ZodTypes[]]> | ZodDiscriminat
|
|
12
13
|
}>[]> | ZodIntersection<ZodTypes, ZodTypes> | ZodNativeEnum<any> | ZodEnum<any>;
|
13
14
|
export type ZodTypes = Modifiers | Primitives | ListCollections | KVCollections | ADTs | ZodFunction<any, ZodTypes> | ZodLazy<ZodTypes> | ZodLiteral<any> | ZodEffects<any, any> | ZodCatch<ZodTypes> | ZodPromise<ZodTypes> | ZodBranded<ZodTypes, any> | ZodPipeline<ZodTypes, ZodTypes>;
|
14
15
|
export type ZTypeName<T extends ZodTypes> = T["_def"]["typeName"];
|
15
|
-
export type FormIssue = {
|
16
|
+
export type FormIssue = GenericIssue & {
|
16
17
|
name: string;
|
17
|
-
code: string;
|
18
|
-
message?: string;
|
19
|
-
minimum?: number;
|
20
|
-
maximum?: number;
|
21
|
-
exact?: boolean;
|
22
|
-
validation?: string;
|
23
18
|
};
|
24
19
|
export type Form<T extends ZodType<any, any>> = {
|
25
20
|
/** Whether the form is valid. */
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "lutra",
|
3
|
-
"version": "0.0.
|
3
|
+
"version": "0.0.12",
|
4
4
|
"scripts": {
|
5
5
|
"dev": "vite dev --host 0.0.0.0",
|
6
6
|
"props": "node read_props.js",
|
@@ -90,7 +90,7 @@
|
|
90
90
|
"types": "./dist/index.d.ts",
|
91
91
|
"type": "module",
|
92
92
|
"dependencies": {
|
93
|
-
"@auth70/bodyguard": "^1.
|
93
|
+
"@auth70/bodyguard": "^1.6.2",
|
94
94
|
"@auth70/zodex-esm": "^0.7.3",
|
95
95
|
"zod": "^3.22.4"
|
96
96
|
}
|