@thi.ng/rdom-forms 0.1.0 → 0.2.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.
- package/CHANGELOG.md +13 -1
- package/README.md +12 -7
- package/api.d.ts +35 -9
- package/api.js +0 -1
- package/compile.d.ts +4 -4
- package/compile.js +455 -286
- package/package.json +24 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2023-12-
|
|
3
|
+
- **Last updated**: 2023-12-12T15:03:05Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -9,6 +9,18 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
9
9
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
10
|
and/or version bumps of transitive dependencies.
|
|
11
11
|
|
|
12
|
+
## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rdom-forms@0.2.0) (2023-12-11)
|
|
13
|
+
|
|
14
|
+
#### 🚀 Features
|
|
15
|
+
|
|
16
|
+
- update range() value label handling ([41f97d3](https://github.com/thi-ng/umbrella/commit/41f97d3))
|
|
17
|
+
- add value type generics for selectXX/multiSelectXX ([55d9897](https://github.com/thi-ng/umbrella/commit/55d9897))
|
|
18
|
+
- make attribs type-specifc ([5c6de7f](https://github.com/thi-ng/umbrella/commit/5c6de7f))
|
|
19
|
+
|
|
20
|
+
#### 🩹 Bug fixes
|
|
21
|
+
|
|
22
|
+
- fix trigger() event handler ([9faaf26](https://github.com/thi-ng/umbrella/commit/9faaf26))
|
|
23
|
+
|
|
12
24
|
## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rdom-forms@0.1.0) (2023-12-09)
|
|
13
25
|
|
|
14
26
|
#### 🚀 Features
|
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ For Node.js REPL:
|
|
|
68
68
|
const rdomForms = await import("@thi.ng/rdom-forms");
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
Package sizes (brotli'd, pre-treeshake): ESM: 2.
|
|
71
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 2.18 KB
|
|
72
72
|
|
|
73
73
|
## Dependencies
|
|
74
74
|
|
|
@@ -81,13 +81,18 @@ Package sizes (brotli'd, pre-treeshake): ESM: 2.13 KB
|
|
|
81
81
|
|
|
82
82
|
## Usage examples
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
Several projects in this repo's
|
|
85
85
|
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
|
|
86
|
-
directory
|
|
87
|
-
|
|
88
|
-
| Screenshot
|
|
89
|
-
|
|
90
|
-
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/
|
|
86
|
+
directory are using this package:
|
|
87
|
+
|
|
88
|
+
| Screenshot | Description | Live demo | Source |
|
|
89
|
+
|:-------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------|:--------------------------------------------------------|:-------------------------------------------------------------------------------------|
|
|
90
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/big-font.png" width="240"/> | Large ASCII font text generator using @thi.ng/rdom | [Demo](https://demo.thi.ng/umbrella/big-font/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/big-font) |
|
|
91
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/dominant-colors.png" width="240"/> | Color palette generation via dominant color extraction from uploaded images | [Demo](https://demo.thi.ng/umbrella/dominant-colors/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/dominant-colors) |
|
|
92
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-colormatrix.jpg" width="240"/> | Matrix-based image color adjustments | [Demo](https://demo.thi.ng/umbrella/pixel-colormatrix/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/pixel-colormatrix) |
|
|
93
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/pixel-sorting.png" width="240"/> | Interactive pixel sorting tool using thi.ng/color & thi.ng/pixel | [Demo](https://demo.thi.ng/umbrella/pixel-sorting/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/pixel-sorting) |
|
|
94
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-formgen.jpg" width="240"/> | Basic usage of the declarative rdom-forms generator | [Demo](https://demo.thi.ng/umbrella/rdom-formgen/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-formgen) |
|
|
95
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-lissajous.png" width="240"/> | rdom & hiccup-canvas interop test | [Demo](https://demo.thi.ng/umbrella/rdom-lissajous/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-lissajous) |
|
|
91
96
|
|
|
92
97
|
## API
|
|
93
98
|
|
package/api.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Predicate } from "@thi.ng/api";
|
|
2
|
-
import type { Attribs, FormAttribs, InputFileAttribs, InputRadioAttribs } from "@thi.ng/hiccup-html";
|
|
1
|
+
import type { Fn, Predicate } from "@thi.ng/api";
|
|
2
|
+
import type { Attribs, FormAttribs, InputAttribs, InputCheckboxAttribs, InputFileAttribs, InputNumericAttribs, InputRadioAttribs, InputTextAttribs, SelectAttribs, TextAreaAttribs } from "@thi.ng/hiccup-html";
|
|
3
3
|
import type { ComponentLike } from "@thi.ng/rdom";
|
|
4
4
|
import type { ISubscriber, ISubscription } from "@thi.ng/rstream";
|
|
5
5
|
export interface CommonAttribs {
|
|
@@ -42,6 +42,7 @@ export interface Value extends FormItem, Partial<CommonAttribs> {
|
|
|
42
42
|
desc?: any;
|
|
43
43
|
required?: boolean;
|
|
44
44
|
readonly?: boolean;
|
|
45
|
+
attribs?: Partial<InputAttribs>;
|
|
45
46
|
}
|
|
46
47
|
export interface WithPresets<T> {
|
|
47
48
|
/**
|
|
@@ -57,11 +58,11 @@ export interface Num extends Value, WithPresets<number> {
|
|
|
57
58
|
size?: number;
|
|
58
59
|
step?: number;
|
|
59
60
|
value?: ISubscription<number, number>;
|
|
61
|
+
attribs?: Partial<InputNumericAttribs>;
|
|
60
62
|
}
|
|
61
63
|
export interface Range extends Omit<Num, "type" | "placeholder" | "size"> {
|
|
62
64
|
type: "range";
|
|
63
|
-
vlabel?: boolean
|
|
64
|
-
vlabelPrec?: number;
|
|
65
|
+
vlabel?: boolean | number | Fn<number, string>;
|
|
65
66
|
}
|
|
66
67
|
export interface Str extends Value, WithPresets<string> {
|
|
67
68
|
type: "str";
|
|
@@ -71,6 +72,7 @@ export interface Str extends Value, WithPresets<string> {
|
|
|
71
72
|
placeholder?: string;
|
|
72
73
|
size?: number;
|
|
73
74
|
value?: ISubscription<string, string>;
|
|
75
|
+
attribs?: Partial<InputTextAttribs>;
|
|
74
76
|
}
|
|
75
77
|
export interface Email extends Omit<Str, "type"> {
|
|
76
78
|
type: "email";
|
|
@@ -93,6 +95,7 @@ export interface Text extends Value {
|
|
|
93
95
|
rows?: number;
|
|
94
96
|
placeholder?: string;
|
|
95
97
|
value?: ISubscription<string, string>;
|
|
98
|
+
attribs?: Partial<TextAreaAttribs>;
|
|
96
99
|
}
|
|
97
100
|
export interface Color extends Value, WithPresets<string> {
|
|
98
101
|
type: "color";
|
|
@@ -120,6 +123,7 @@ export interface Month extends Omit<DateTime, "type" | "list"> {
|
|
|
120
123
|
export interface Select<T> extends Value {
|
|
121
124
|
items: (T | SelectItem<T> | SelectItemGroup<T>)[];
|
|
122
125
|
value?: ISubscription<T, T>;
|
|
126
|
+
attribs?: Partial<Omit<SelectAttribs, "multiple">>;
|
|
123
127
|
}
|
|
124
128
|
export interface SelectItemGroup<T> {
|
|
125
129
|
name: string;
|
|
@@ -130,21 +134,22 @@ export interface SelectItem<T> {
|
|
|
130
134
|
label?: string;
|
|
131
135
|
desc?: string;
|
|
132
136
|
}
|
|
133
|
-
export interface SelectStr extends Select<
|
|
137
|
+
export interface SelectStr<T extends string = string> extends Select<T> {
|
|
134
138
|
type: "selectStr";
|
|
135
139
|
}
|
|
136
|
-
export interface SelectNum extends Select<
|
|
140
|
+
export interface SelectNum<T extends number = number> extends Select<T> {
|
|
137
141
|
type: "selectNum";
|
|
138
142
|
}
|
|
139
143
|
export interface MultiSelect<T> extends Value {
|
|
140
144
|
items: (T | SelectItem<T> | SelectItemGroup<T>)[];
|
|
141
145
|
value?: ISubscription<T[], T[]>;
|
|
142
146
|
size?: number;
|
|
147
|
+
attribs?: Partial<Omit<SelectAttribs, "multiple">>;
|
|
143
148
|
}
|
|
144
|
-
export interface MultiSelectStr extends MultiSelect<
|
|
149
|
+
export interface MultiSelectStr<T extends string = string> extends MultiSelect<T> {
|
|
145
150
|
type: "multiSelectStr";
|
|
146
151
|
}
|
|
147
|
-
export interface MultiSelectNum extends MultiSelect<
|
|
152
|
+
export interface MultiSelectNum<T extends number = number> extends MultiSelect<T> {
|
|
148
153
|
type: "multiSelectNum";
|
|
149
154
|
}
|
|
150
155
|
export interface Toggle extends Value {
|
|
@@ -155,10 +160,12 @@ export interface Trigger extends Value {
|
|
|
155
160
|
type: "trigger";
|
|
156
161
|
title: string;
|
|
157
162
|
value?: ISubscriber<boolean>;
|
|
163
|
+
attribs?: Partial<InputCheckboxAttribs>;
|
|
158
164
|
}
|
|
159
165
|
export interface Radio<T> extends Value {
|
|
160
166
|
items: (T | SelectItem<T>)[];
|
|
161
167
|
value?: ISubscription<T, T>;
|
|
168
|
+
attribs?: Partial<InputRadioAttribs>;
|
|
162
169
|
}
|
|
163
170
|
export interface RadioNum extends Radio<number> {
|
|
164
171
|
type: "radioNum";
|
|
@@ -171,11 +178,13 @@ export interface FileVal extends Value {
|
|
|
171
178
|
accept?: string[];
|
|
172
179
|
capture?: InputFileAttribs["capture"];
|
|
173
180
|
value?: ISubscriber<File>;
|
|
181
|
+
attribs?: Partial<InputFileAttribs>;
|
|
174
182
|
}
|
|
175
183
|
export interface MultiFileVal extends Value {
|
|
176
184
|
type: "multiFile";
|
|
177
185
|
accept?: string[];
|
|
178
186
|
value?: ISubscriber<FileList>;
|
|
187
|
+
attribs?: Partial<InputFileAttribs>;
|
|
179
188
|
}
|
|
180
189
|
type KnownTypes = Color | Container | DateTime | DateVal | Email | FileVal | Group | Month | MultiFileVal | MultiSelectNum | MultiSelectStr | Num | Password | Phone | Range | SelectNum | SelectStr | Str | Text | Time | Toggle | Trigger | UrlVal | Week;
|
|
181
190
|
/**
|
|
@@ -212,7 +221,12 @@ export interface TypeAttribs extends Record<KnownTypes["type"], Partial<Attribs>
|
|
|
212
221
|
/**
|
|
213
222
|
* Attribs for {@link range} label elements
|
|
214
223
|
*/
|
|
215
|
-
|
|
224
|
+
rangeLabel: Partial<Attribs>;
|
|
225
|
+
/**
|
|
226
|
+
* Attribs for the wrapper element of a single {@link range} widget (incl.
|
|
227
|
+
* input element and optional value label)
|
|
228
|
+
*/
|
|
229
|
+
rangeWrapper: Partial<Attribs>;
|
|
216
230
|
[id: string]: Partial<Attribs>;
|
|
217
231
|
}
|
|
218
232
|
export interface FormOpts extends CommonAttribs {
|
|
@@ -271,6 +285,18 @@ export interface BehaviorOpts {
|
|
|
271
285
|
* @defaultValue false
|
|
272
286
|
*/
|
|
273
287
|
radioLabelBefore: boolean;
|
|
288
|
+
/**
|
|
289
|
+
* Number of fractional digits for range sliders.
|
|
290
|
+
*
|
|
291
|
+
* @defaultValue 2
|
|
292
|
+
*/
|
|
293
|
+
rangeLabelFmt: number | Fn<number, string>;
|
|
294
|
+
/**
|
|
295
|
+
* If true, the label for toggle widgets will come before the actual
|
|
296
|
+
* input element. By default, the order is reversed.
|
|
297
|
+
*
|
|
298
|
+
* @defaultValue false
|
|
299
|
+
*/
|
|
274
300
|
toggleLabelBefore: boolean;
|
|
275
301
|
}
|
|
276
302
|
export {};
|
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/compile.d.ts
CHANGED
|
@@ -24,8 +24,6 @@ export declare const email: (spec: PartialSpec<Email> | ReadonlyPartialSpec<Emai
|
|
|
24
24
|
export declare const file: (spec: PartialSpec<FileVal> | ReadonlyPartialSpec<FileVal, never>) => FileVal;
|
|
25
25
|
export declare const month: (spec: PartialSpec<Month> | ReadonlyPartialSpec<Month, string>) => Month;
|
|
26
26
|
export declare const multiFile: (spec: PartialSpec<MultiFileVal> | ReadonlyPartialSpec<MultiFileVal, never>) => MultiFileVal;
|
|
27
|
-
export declare const multiSelectNum: (spec: PartialSpec<MultiSelectNum> | ReadonlyPartialSpec<MultiSelectNum, number>) => MultiSelectNum;
|
|
28
|
-
export declare const multiSelectStr: (spec: PartialSpec<MultiSelectStr> | ReadonlyPartialSpec<MultiSelectStr, string>) => MultiSelectStr;
|
|
29
27
|
export declare const num: (spec: PartialSpec<Num> | ReadonlyPartialSpec<Num, number>) => Num;
|
|
30
28
|
export declare const password: (spec: PartialSpec<Password> | ReadonlyPartialSpec<Password, string>) => Password;
|
|
31
29
|
export declare const phone: (spec: PartialSpec<Email> | ReadonlyPartialSpec<Email, string>) => Email;
|
|
@@ -33,8 +31,6 @@ export declare const radioNum: (spec: PartialSpec<RadioNum> | ReadonlyPartialSpe
|
|
|
33
31
|
export declare const radioStr: (spec: PartialSpec<RadioStr> | ReadonlyPartialSpec<RadioStr, string>) => RadioStr;
|
|
34
32
|
export declare const range: (spec: PartialSpec<Range> | ReadonlyPartialSpec<Range, number>) => Range;
|
|
35
33
|
export declare const search: (spec: PartialSpec<Str> | ReadonlyPartialSpec<Str, string>) => Str;
|
|
36
|
-
export declare const selectNum: (spec: PartialSpec<SelectNum> | ReadonlyPartialSpec<SelectNum, number>) => SelectNum;
|
|
37
|
-
export declare const selectStr: (spec: PartialSpec<SelectStr> | ReadonlyPartialSpec<SelectStr, string>) => SelectStr;
|
|
38
34
|
export declare const str: (spec: PartialSpec<Str> | ReadonlyPartialSpec<Str, string>) => Str;
|
|
39
35
|
export declare const text: (spec: PartialSpec<Text> | ReadonlyPartialSpec<Text, string>) => Text;
|
|
40
36
|
export declare const time: (spec: PartialSpec<Time> | ReadonlyPartialSpec<Time, string>) => Time;
|
|
@@ -42,6 +38,10 @@ export declare const toggle: (spec: PartialSpec<Toggle> | ReadonlyPartialSpec<To
|
|
|
42
38
|
export declare const trigger: (spec: PartialSpec<Trigger> | ReadonlyPartialSpec<Trigger, string>) => Trigger;
|
|
43
39
|
export declare const url: (spec: PartialSpec<UrlVal> | ReadonlyPartialSpec<UrlVal, string>) => UrlVal;
|
|
44
40
|
export declare const week: (spec: PartialSpec<Week> | ReadonlyPartialSpec<Week, string>) => Week;
|
|
41
|
+
export declare const selectNum: <T extends number = number>(spec: PartialSpec<SelectNum<T>> | ReadonlyPartialSpec<SelectNum<T>, string>) => SelectNum<T>;
|
|
42
|
+
export declare const selectStr: <T extends string = string>(spec: PartialSpec<SelectStr<T>> | ReadonlyPartialSpec<SelectStr<T>, string>) => SelectStr<T>;
|
|
43
|
+
export declare const multiSelectNum: <T extends number = number>(spec: PartialSpec<MultiSelectNum<T>> | ReadonlyPartialSpec<MultiSelectNum<T>, string>) => MultiSelectNum<T>;
|
|
44
|
+
export declare const multiSelectStr: <T extends string = string>(spec: PartialSpec<MultiSelectStr<T>> | ReadonlyPartialSpec<MultiSelectStr<T>, string>) => MultiSelectStr<T>;
|
|
45
45
|
/**
|
|
46
46
|
* Compiles given {@link FormItem} spec into a hiccup/rdom component, using
|
|
47
47
|
* provided options to customize attributes and behaviors.
|
package/compile.js
CHANGED
|
@@ -4,136 +4,157 @@ import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
|
4
4
|
import { isString } from "@thi.ng/checks/is-string";
|
|
5
5
|
import { defmulti } from "@thi.ng/defmulti/defmulti";
|
|
6
6
|
import { div } from "@thi.ng/hiccup-html/blocks";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
form as $form,
|
|
9
|
+
button,
|
|
10
|
+
checkbox,
|
|
11
|
+
fieldset,
|
|
12
|
+
inputColor,
|
|
13
|
+
inputFile,
|
|
14
|
+
inputNumber,
|
|
15
|
+
inputRange,
|
|
16
|
+
inputText,
|
|
17
|
+
label,
|
|
18
|
+
legend,
|
|
19
|
+
optGroup,
|
|
20
|
+
option,
|
|
21
|
+
radio,
|
|
22
|
+
select,
|
|
23
|
+
textArea
|
|
24
|
+
} from "@thi.ng/hiccup-html/forms";
|
|
8
25
|
import { span } from "@thi.ng/hiccup-html/inline";
|
|
9
26
|
import { datalist } from "@thi.ng/hiccup-html/lists";
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
27
|
+
import {
|
|
28
|
+
$attribs,
|
|
29
|
+
$input,
|
|
30
|
+
$inputCheckbox,
|
|
31
|
+
$inputFile,
|
|
32
|
+
$inputFiles,
|
|
33
|
+
$inputNum,
|
|
34
|
+
$inputTrigger,
|
|
35
|
+
$replace
|
|
36
|
+
} from "@thi.ng/rdom";
|
|
37
|
+
const form = (attribs, ...items) => ({
|
|
38
|
+
type: "form",
|
|
39
|
+
attribs,
|
|
40
|
+
items
|
|
15
41
|
});
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
42
|
+
const container = (attribs, ...items) => ({
|
|
43
|
+
type: "container",
|
|
44
|
+
attribs,
|
|
45
|
+
items
|
|
20
46
|
});
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
const group = (spec, ...items) => ({
|
|
48
|
+
...spec,
|
|
49
|
+
type: "group",
|
|
50
|
+
items
|
|
25
51
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
52
|
+
const custom = (body) => ({
|
|
53
|
+
type: "custom",
|
|
54
|
+
body
|
|
29
55
|
});
|
|
30
56
|
let __nextID = 0;
|
|
31
57
|
const $ = (type, defaults) => (spec) => ({
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
58
|
+
id: spec.id || `${type}-${__nextID++}`,
|
|
59
|
+
type,
|
|
60
|
+
...defaults,
|
|
61
|
+
...spec
|
|
36
62
|
});
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
/** @internal */
|
|
63
|
+
const color = $("color");
|
|
64
|
+
const date = $("date");
|
|
65
|
+
const dateTime = $("dateTime");
|
|
66
|
+
const email = $("email", { autocomplete: true });
|
|
67
|
+
const file = $("file");
|
|
68
|
+
const month = $("month");
|
|
69
|
+
const multiFile = $("multiFile");
|
|
70
|
+
const num = $("num");
|
|
71
|
+
const password = $("password", { autocomplete: true });
|
|
72
|
+
const phone = $("tel", { autocomplete: true });
|
|
73
|
+
const radioNum = $("radioNum");
|
|
74
|
+
const radioStr = $("radioStr");
|
|
75
|
+
const range = $("range");
|
|
76
|
+
const search = $("search");
|
|
77
|
+
const str = $("str");
|
|
78
|
+
const text = $("text");
|
|
79
|
+
const time = $("time");
|
|
80
|
+
const toggle = $("toggle");
|
|
81
|
+
const trigger = $("trigger");
|
|
82
|
+
const url = $("url");
|
|
83
|
+
const week = $("week");
|
|
84
|
+
const selectNum = (spec) => $("selectNum")(spec);
|
|
85
|
+
const selectStr = (spec) => $("selectStr")(spec);
|
|
86
|
+
const multiSelectNum = (spec) => $("multiSelectNum")(spec);
|
|
87
|
+
const multiSelectStr = (spec) => $("multiSelectStr")(spec);
|
|
63
88
|
const __genID = (id, opts) => opts.prefix ? opts.prefix + id : id;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
89
|
+
const __genLabel = (x, opts) => label(
|
|
90
|
+
{ ...opts.labelAttribs, ...x.labelAttribs, for: __genID(x.id, opts) },
|
|
91
|
+
x.label ?? x.id,
|
|
92
|
+
x.desc ? span({ ...opts.descAttribs, ...x.descAttribs }, x.desc) : null
|
|
93
|
+
);
|
|
67
94
|
const __genList = (id, list) => datalist({ id: id + "--list" }, ...list.map((value) => option({ value })));
|
|
68
|
-
/** @internal */
|
|
69
95
|
const __genCommon = (val, opts) => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
96
|
+
const res = [];
|
|
97
|
+
if (val.label !== false && opts.behaviors?.labels !== false) {
|
|
98
|
+
res.push(__genLabel(val, opts));
|
|
99
|
+
}
|
|
100
|
+
if (val.list) {
|
|
101
|
+
res.push(__genList(__genID(val.id, opts), val.list));
|
|
102
|
+
}
|
|
103
|
+
return res;
|
|
78
104
|
};
|
|
79
|
-
/** @internal */
|
|
80
105
|
const __attribs = (attribs, events, val, opts, value = "value") => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
106
|
+
const id = __genID(val.id, opts);
|
|
107
|
+
Object.assign(
|
|
108
|
+
attribs,
|
|
109
|
+
{
|
|
110
|
+
id,
|
|
111
|
+
name: val.name || val.id,
|
|
112
|
+
list: val.list ? id + "--list" : void 0,
|
|
113
|
+
required: val.required,
|
|
114
|
+
readonly: val.readonly
|
|
115
|
+
},
|
|
116
|
+
val.attribs
|
|
117
|
+
);
|
|
118
|
+
if (__useValues(opts)) {
|
|
119
|
+
if (!val.readonly) {
|
|
120
|
+
Object.assign(attribs, events);
|
|
121
|
+
}
|
|
122
|
+
if (value !== false) {
|
|
123
|
+
attribs[value] = val.value;
|
|
96
124
|
}
|
|
97
|
-
|
|
125
|
+
}
|
|
126
|
+
return attribs;
|
|
98
127
|
};
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
const __component = (val, opts, el, attribs, events, value = "value", ...body) => div(
|
|
129
|
+
{ ...opts.wrapperAttribs, ...val.wrapperAttribs },
|
|
130
|
+
...__genCommon(val, opts),
|
|
131
|
+
// @ts-ignore extra args
|
|
132
|
+
el(__attribs(attribs, events, val, opts, value), ...body)
|
|
133
|
+
);
|
|
104
134
|
const __edit = (val) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
? new RegExp(val.pattern)
|
|
113
|
-
: val.pattern;
|
|
114
|
-
match = (x) => re.test(x);
|
|
115
|
-
}
|
|
116
|
-
return (e) => {
|
|
117
|
-
const target = e.target;
|
|
118
|
-
const body = target.value;
|
|
119
|
-
const ok = match(body);
|
|
120
|
-
if (ok)
|
|
121
|
-
val.value.next(body);
|
|
122
|
-
$attribs(target, { invalid: !ok });
|
|
123
|
-
};
|
|
135
|
+
if (val.pattern) {
|
|
136
|
+
let match;
|
|
137
|
+
if (isFunction(val.pattern)) {
|
|
138
|
+
match = val.pattern;
|
|
139
|
+
} else {
|
|
140
|
+
const re = isString(val.pattern) ? new RegExp(val.pattern) : val.pattern;
|
|
141
|
+
match = (x) => re.test(x);
|
|
124
142
|
}
|
|
125
|
-
return
|
|
143
|
+
return (e) => {
|
|
144
|
+
const target = e.target;
|
|
145
|
+
const body = target.value;
|
|
146
|
+
const ok = match(body);
|
|
147
|
+
if (ok)
|
|
148
|
+
val.value.next(body);
|
|
149
|
+
$attribs(target, { invalid: !ok });
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return $input(val.value);
|
|
126
153
|
};
|
|
127
154
|
const __useValues = (opts) => opts.behaviors?.values !== false;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
*
|
|
132
|
-
* @remarks
|
|
133
|
-
* This function is polymorphic and dynamically extensible for new/custom form
|
|
134
|
-
* element types. See thi.ng/defmulti readme for instructions.
|
|
135
|
-
*/
|
|
136
|
-
export const compileForm = defmulti((x) => x.type, {
|
|
155
|
+
const compileForm = defmulti(
|
|
156
|
+
(x) => x.type,
|
|
157
|
+
{
|
|
137
158
|
multiFile: "file",
|
|
138
159
|
dateTime: "date",
|
|
139
160
|
time: "date",
|
|
@@ -149,205 +170,353 @@ export const compileForm = defmulti((x) => x.type, {
|
|
|
149
170
|
selectNum: "select",
|
|
150
171
|
selectStr: "select",
|
|
151
172
|
multiSelectNum: "multiSelect",
|
|
152
|
-
multiSelectStr: "multiSelect"
|
|
153
|
-
},
|
|
173
|
+
multiSelectStr: "multiSelect"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
154
176
|
form: ($val, opts) => {
|
|
155
|
-
|
|
156
|
-
|
|
177
|
+
const val = $val;
|
|
178
|
+
return $form(
|
|
179
|
+
{ ...opts.typeAttribs?.form, ...val.attribs },
|
|
180
|
+
...val.items.map((x) => compileForm(x, opts))
|
|
181
|
+
);
|
|
157
182
|
},
|
|
158
183
|
container: ($val, opts) => {
|
|
159
|
-
|
|
160
|
-
|
|
184
|
+
const val = $val;
|
|
185
|
+
return div(
|
|
186
|
+
{ ...opts.typeAttribs?.container, ...val.attribs },
|
|
187
|
+
...val.items.map((x) => compileForm(x, opts))
|
|
188
|
+
);
|
|
161
189
|
},
|
|
162
190
|
group: ($val, opts) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
191
|
+
const val = $val;
|
|
192
|
+
const children = [];
|
|
193
|
+
if (val.label) {
|
|
194
|
+
children.push(
|
|
195
|
+
legend({ ...opts.typeAttribs?.groupLabel }, val.label)
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return fieldset(
|
|
199
|
+
{ ...opts.typeAttribs?.group, ...val.attribs },
|
|
200
|
+
...children,
|
|
201
|
+
...val.items.map((x) => compileForm(x, opts))
|
|
202
|
+
);
|
|
169
203
|
},
|
|
170
204
|
custom: (val) => val.body,
|
|
171
205
|
toggle: ($val, opts) => {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
206
|
+
const val = $val;
|
|
207
|
+
const label2 = __genLabel(val, opts);
|
|
208
|
+
const ctrl = checkbox(
|
|
209
|
+
__attribs(
|
|
210
|
+
{ ...opts.typeAttribs?.toggle },
|
|
211
|
+
{ onchange: $inputCheckbox($val.value) },
|
|
212
|
+
val,
|
|
213
|
+
opts,
|
|
214
|
+
"checked"
|
|
215
|
+
)
|
|
216
|
+
);
|
|
217
|
+
return div(
|
|
218
|
+
{ ...opts.wrapperAttribs, ...val.wrapperAttribs },
|
|
219
|
+
...opts.behaviors?.toggleLabelBefore !== false ? [label2, ctrl] : [ctrl, label2]
|
|
220
|
+
);
|
|
178
221
|
},
|
|
179
|
-
trigger: ($val, opts) => __component(
|
|
222
|
+
trigger: ($val, opts) => __component(
|
|
223
|
+
$val,
|
|
224
|
+
opts,
|
|
225
|
+
button,
|
|
226
|
+
{ ...opts.typeAttribs?.trigger },
|
|
227
|
+
{ onclick: $inputTrigger($val.value) },
|
|
228
|
+
false,
|
|
229
|
+
$val.title
|
|
230
|
+
),
|
|
180
231
|
radio: ($val, opts) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
232
|
+
const val = $val;
|
|
233
|
+
const labelAttribs = {
|
|
234
|
+
...opts.typeAttribs?.radioItemLabel,
|
|
235
|
+
...val.labelAttribs
|
|
236
|
+
};
|
|
237
|
+
const $option = ($item) => {
|
|
238
|
+
const item = isPlainObject($item) ? $item : { value: $item };
|
|
239
|
+
const id = val.id + "-" + item.value;
|
|
240
|
+
const label2 = __genLabel(
|
|
241
|
+
{
|
|
242
|
+
id,
|
|
243
|
+
label: item.label || item.value,
|
|
244
|
+
desc: item.desc,
|
|
245
|
+
labelAttribs,
|
|
246
|
+
descAttribs: val.descAttribs
|
|
247
|
+
},
|
|
248
|
+
opts
|
|
249
|
+
);
|
|
250
|
+
const ctrl = radio({
|
|
251
|
+
...opts.typeAttribs?.radio,
|
|
252
|
+
...val.attribs,
|
|
253
|
+
onchange: val.value && __useValues(opts) ? () => val.value.next(item.value) : void 0,
|
|
254
|
+
id: __genID(id, opts),
|
|
255
|
+
name: val.name || val.id,
|
|
256
|
+
checked: val.value && __useValues(opts) ? val.value.map((x) => x === item.value) : void 0,
|
|
257
|
+
value: item.value
|
|
258
|
+
});
|
|
259
|
+
return div(
|
|
260
|
+
{ ...opts.typeAttribs?.radioItem },
|
|
261
|
+
...opts.behaviors?.radioLabelBefore ? [label2, ctrl] : [ctrl, label2]
|
|
262
|
+
);
|
|
263
|
+
};
|
|
264
|
+
return div(
|
|
265
|
+
{
|
|
266
|
+
...opts.wrapperAttribs,
|
|
267
|
+
...opts.typeAttribs?.radioWrapper,
|
|
268
|
+
...val.wrapperAttribs
|
|
269
|
+
},
|
|
270
|
+
...__genCommon(val, opts),
|
|
271
|
+
div(
|
|
272
|
+
{ ...opts.typeAttribs?.radioItems },
|
|
273
|
+
...val.items.map($option)
|
|
274
|
+
)
|
|
275
|
+
);
|
|
218
276
|
},
|
|
219
|
-
color: ($val, opts) => __component(
|
|
277
|
+
color: ($val, opts) => __component(
|
|
278
|
+
$val,
|
|
279
|
+
opts,
|
|
280
|
+
inputColor,
|
|
281
|
+
{ ...opts.typeAttribs?.color },
|
|
282
|
+
{ onchange: $input($val.value) }
|
|
283
|
+
),
|
|
220
284
|
file: ($val, opts) => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
},
|
|
285
|
+
const val = $val;
|
|
286
|
+
const isMulti = val.id.startsWith("multi");
|
|
287
|
+
return __component(
|
|
288
|
+
val,
|
|
289
|
+
opts,
|
|
290
|
+
inputFile,
|
|
291
|
+
{
|
|
292
|
+
...opts.typeAttribs?.num,
|
|
293
|
+
accept: val.accept,
|
|
294
|
+
capture: val.capture,
|
|
295
|
+
multiple: isMulti
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
onchange: isMulti ? $inputFiles($val.value) : $inputFile(val.value)
|
|
299
|
+
},
|
|
300
|
+
false
|
|
301
|
+
);
|
|
233
302
|
},
|
|
234
303
|
num: ($val, opts) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
304
|
+
const val = $val;
|
|
305
|
+
return __component(
|
|
306
|
+
val,
|
|
307
|
+
opts,
|
|
308
|
+
inputNumber,
|
|
309
|
+
{
|
|
310
|
+
...opts.typeAttribs?.num,
|
|
311
|
+
min: val.min,
|
|
312
|
+
max: val.max,
|
|
313
|
+
step: val.step,
|
|
314
|
+
placeholder: val.placeholder,
|
|
315
|
+
size: val.size
|
|
316
|
+
},
|
|
317
|
+
{ onchange: $inputNum(val.value) }
|
|
318
|
+
);
|
|
244
319
|
},
|
|
245
320
|
range: ($val, opts) => {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
321
|
+
const val = $val;
|
|
322
|
+
const edit = opts.behaviors?.rangeOnInput === false ? "onchange" : "oninput";
|
|
323
|
+
const children = [
|
|
324
|
+
inputRange(
|
|
325
|
+
__attribs(
|
|
326
|
+
{
|
|
327
|
+
...opts.typeAttribs?.range,
|
|
328
|
+
min: val.min,
|
|
329
|
+
max: val.max,
|
|
330
|
+
step: val.step
|
|
331
|
+
},
|
|
332
|
+
{ [edit]: $inputNum(val.value) },
|
|
333
|
+
val,
|
|
334
|
+
opts
|
|
335
|
+
)
|
|
336
|
+
)
|
|
337
|
+
];
|
|
338
|
+
if (val.value && val.vlabel !== false && __useValues(opts)) {
|
|
339
|
+
const fmt = val.vlabel === true || val.vlabel === void 0 ? opts.behaviors?.rangeLabelFmt ?? 2 : val.vlabel;
|
|
340
|
+
children.push(
|
|
341
|
+
span(
|
|
342
|
+
{ ...opts.typeAttribs?.rangeLabel },
|
|
343
|
+
val.value.map(
|
|
344
|
+
isFunction(fmt) ? fmt : (x) => x.toFixed(fmt)
|
|
345
|
+
)
|
|
346
|
+
)
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
return div(
|
|
350
|
+
{ ...opts.wrapperAttribs, ...val.wrapperAttribs },
|
|
351
|
+
...__genCommon(val, opts),
|
|
352
|
+
div({ ...opts.typeAttribs?.rangeWrapper }, ...children)
|
|
353
|
+
);
|
|
256
354
|
},
|
|
257
355
|
str: ($val, opts) => {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
356
|
+
const val = $val;
|
|
357
|
+
const type = { dateTime: "datetime-local" }[$val.type] || ($val.type !== "str" ? $val.type : "text");
|
|
358
|
+
const edit = opts.behaviors?.strOnInput === false ? "onchange" : "oninput";
|
|
359
|
+
return __component(
|
|
360
|
+
val,
|
|
361
|
+
opts,
|
|
362
|
+
inputText,
|
|
363
|
+
{
|
|
364
|
+
...opts.typeAttribs?.[val.type] || opts.typeAttribs?.str,
|
|
365
|
+
type,
|
|
366
|
+
autocomplete: val.autocomplete,
|
|
367
|
+
minlength: val.min,
|
|
368
|
+
maxlength: val.max,
|
|
369
|
+
placeholder: val.placeholder,
|
|
370
|
+
pattern: isString(val.pattern) ? val.pattern : void 0,
|
|
371
|
+
size: val.size
|
|
372
|
+
},
|
|
373
|
+
{ [edit]: __edit(val) }
|
|
374
|
+
);
|
|
272
375
|
},
|
|
273
376
|
text: ($val, opts) => {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
377
|
+
const val = $val;
|
|
378
|
+
const edit = opts.behaviors?.textOnInput === false ? "onchange" : "oninput";
|
|
379
|
+
return __component(
|
|
380
|
+
val,
|
|
381
|
+
opts,
|
|
382
|
+
textArea,
|
|
383
|
+
{
|
|
384
|
+
...opts.typeAttribs?.text,
|
|
385
|
+
cols: val.cols,
|
|
386
|
+
rows: val.rows,
|
|
387
|
+
placeholder: val.placeholder
|
|
388
|
+
},
|
|
389
|
+
{ [edit]: $input(val.value) }
|
|
390
|
+
);
|
|
282
391
|
},
|
|
283
392
|
date: ($val, opts) => {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
393
|
+
const val = $val;
|
|
394
|
+
const type = { dateTime: "datetime-local" }[$val.type] || $val.type;
|
|
395
|
+
return __component(
|
|
396
|
+
val,
|
|
397
|
+
opts,
|
|
398
|
+
inputText,
|
|
399
|
+
{
|
|
400
|
+
...opts.typeAttribs?.[$val.type] || opts.typeAttribs?.date,
|
|
401
|
+
type,
|
|
402
|
+
min: val.min,
|
|
403
|
+
max: val.max,
|
|
404
|
+
step: val.step
|
|
405
|
+
},
|
|
406
|
+
{ onchange: $input(val.value) }
|
|
407
|
+
);
|
|
294
408
|
},
|
|
295
409
|
select: ($val, opts) => {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
: $
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
410
|
+
const val = $val;
|
|
411
|
+
const isNumeric = val.type.endsWith("Num");
|
|
412
|
+
const $option = ($item, sel) => {
|
|
413
|
+
const item = isPlainObject($item) ? $item : { value: $item };
|
|
414
|
+
return option(
|
|
415
|
+
{
|
|
416
|
+
value: item.value,
|
|
417
|
+
selected: sel === item.value
|
|
418
|
+
},
|
|
419
|
+
item.label || item.value
|
|
420
|
+
);
|
|
421
|
+
};
|
|
422
|
+
const $select = (sel) => select(
|
|
423
|
+
__attribs(
|
|
424
|
+
{
|
|
425
|
+
...opts.typeAttribs?.[val.type] || opts.typeAttribs?.select
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
onchange: isNumeric ? $inputNum(val.value) : $input(val.value)
|
|
429
|
+
},
|
|
430
|
+
val,
|
|
431
|
+
opts,
|
|
432
|
+
false
|
|
433
|
+
),
|
|
434
|
+
...val.items.map(
|
|
435
|
+
(item) => isPlainObject(item) && "items" in item ? optGroup(
|
|
436
|
+
{ label: item.name },
|
|
437
|
+
...item.items.map((i) => $option(i, sel))
|
|
438
|
+
) : $option(item, sel)
|
|
439
|
+
)
|
|
440
|
+
);
|
|
441
|
+
return div(
|
|
442
|
+
{ ...opts.wrapperAttribs, ...val.wrapperAttribs },
|
|
443
|
+
...__genCommon(val, opts),
|
|
444
|
+
val.value && __useValues(opts) ? $replace(val.value.map($select)) : $select()
|
|
445
|
+
);
|
|
318
446
|
},
|
|
319
447
|
multiSelect: ($val, opts) => {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
},
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
448
|
+
const val = $val;
|
|
449
|
+
const isNumeric = val.type.endsWith("Num");
|
|
450
|
+
const coerce = isNumeric ? (x) => parseFloat(x.value) : (x) => x.value;
|
|
451
|
+
const sel = val.value && __useValues(opts) ? val.value.map((x) => isArray(x) ? x : [x]) : null;
|
|
452
|
+
const $option = ($item) => {
|
|
453
|
+
const item = isPlainObject($item) ? $item : { value: $item };
|
|
454
|
+
return option(
|
|
455
|
+
{
|
|
456
|
+
value: item.value,
|
|
457
|
+
selected: sel ? sel.map(($sel) => $sel.includes(item.value)) : false
|
|
458
|
+
},
|
|
459
|
+
item.label || item.value
|
|
460
|
+
);
|
|
461
|
+
};
|
|
462
|
+
return __component(
|
|
463
|
+
val,
|
|
464
|
+
opts,
|
|
465
|
+
select,
|
|
466
|
+
{
|
|
467
|
+
...opts.typeAttribs?.[val.type] || opts.typeAttribs?.multiSelect,
|
|
468
|
+
multiple: true,
|
|
469
|
+
size: val.size
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
onchange: (e) => {
|
|
473
|
+
val.value.next(
|
|
474
|
+
[
|
|
475
|
+
...e.target.selectedOptions
|
|
476
|
+
].map(coerce)
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
false,
|
|
481
|
+
...val.items.map(
|
|
482
|
+
(item) => isPlainObject(item) && "items" in item ? optGroup(
|
|
483
|
+
{ label: item.name },
|
|
484
|
+
...item.items.map($option)
|
|
485
|
+
) : $option(item)
|
|
486
|
+
)
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
);
|
|
491
|
+
export {
|
|
492
|
+
color,
|
|
493
|
+
compileForm,
|
|
494
|
+
container,
|
|
495
|
+
custom,
|
|
496
|
+
date,
|
|
497
|
+
dateTime,
|
|
498
|
+
email,
|
|
499
|
+
file,
|
|
500
|
+
form,
|
|
501
|
+
group,
|
|
502
|
+
month,
|
|
503
|
+
multiFile,
|
|
504
|
+
multiSelectNum,
|
|
505
|
+
multiSelectStr,
|
|
506
|
+
num,
|
|
507
|
+
password,
|
|
508
|
+
phone,
|
|
509
|
+
radioNum,
|
|
510
|
+
radioStr,
|
|
511
|
+
range,
|
|
512
|
+
search,
|
|
513
|
+
selectNum,
|
|
514
|
+
selectStr,
|
|
515
|
+
str,
|
|
516
|
+
text,
|
|
517
|
+
time,
|
|
518
|
+
toggle,
|
|
519
|
+
trigger,
|
|
520
|
+
url,
|
|
521
|
+
week
|
|
522
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/rdom-forms",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Data-driven declarative & extensible HTML form generation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,22 +35,34 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/checks": "^3.4.
|
|
38
|
-
"@thi.ng/defmulti": "^3.0.
|
|
39
|
-
"@thi.ng/hiccup-html": "^2.3.
|
|
40
|
-
"@thi.ng/rdom": "^0.13.
|
|
41
|
-
"@thi.ng/rstream": "^8.2.
|
|
38
|
+
"@thi.ng/api": "^8.9.12",
|
|
39
|
+
"@thi.ng/checks": "^3.4.12",
|
|
40
|
+
"@thi.ng/defmulti": "^3.0.10",
|
|
41
|
+
"@thi.ng/hiccup-html": "^2.3.1",
|
|
42
|
+
"@thi.ng/rdom": "^0.13.4",
|
|
43
|
+
"@thi.ng/rstream": "^8.2.14"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@microsoft/api-extractor": "^7.38.3",
|
|
47
|
+
"esbuild": "^0.19.8",
|
|
45
48
|
"rimraf": "^5.0.5",
|
|
46
49
|
"tools": "^0.0.1",
|
|
47
50
|
"typedoc": "^0.25.4",
|
|
48
51
|
"typescript": "^5.3.2"
|
|
49
52
|
},
|
|
50
53
|
"keywords": [
|
|
51
|
-
"
|
|
54
|
+
"browser",
|
|
55
|
+
"component",
|
|
56
|
+
"declarative",
|
|
57
|
+
"dom",
|
|
58
|
+
"form",
|
|
59
|
+
"hiccup",
|
|
60
|
+
"html",
|
|
61
|
+
"rdom",
|
|
62
|
+
"rstream",
|
|
63
|
+
"reactive",
|
|
64
|
+
"typescript",
|
|
65
|
+
"ui"
|
|
52
66
|
],
|
|
53
67
|
"publishConfig": {
|
|
54
68
|
"access": "public"
|
|
@@ -83,5 +97,5 @@
|
|
|
83
97
|
"status": "alpha",
|
|
84
98
|
"year": 2023
|
|
85
99
|
},
|
|
86
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "22e36fa838e5431d40165384918b395603bbd92f\n"
|
|
87
101
|
}
|