@stubber/form-fields 1.0.0
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/README.md +303 -0
- package/dist/Field.svelte +36 -0
- package/dist/Field.svelte.d.ts +31 -0
- package/dist/Form.svelte +34 -0
- package/dist/Form.svelte.d.ts +29 -0
- package/dist/NullFieldWrapper.svelte +6 -0
- package/dist/NullFieldWrapper.svelte.d.ts +25 -0
- package/dist/fields/component_parts/arraybuilder/FieldWrapper.svelte +69 -0
- package/dist/fields/component_parts/arraybuilder/FieldWrapper.svelte.d.ts +29 -0
- package/dist/fields/component_parts/fieldbuilder/FieldWrapper.svelte +8 -0
- package/dist/fields/component_parts/fieldbuilder/FieldWrapper.svelte.d.ts +25 -0
- package/dist/fields/components/AgGrid.svelte +53 -0
- package/dist/fields/components/AgGrid.svelte.d.ts +18 -0
- package/dist/fields/components/Arraybuilder.svelte +101 -0
- package/dist/fields/components/Arraybuilder.svelte.d.ts +25 -0
- package/dist/fields/components/Checkbox.svelte +100 -0
- package/dist/fields/components/Checkbox.svelte.d.ts +23 -0
- package/dist/fields/components/CheckboxAutocomplete.svelte +92 -0
- package/dist/fields/components/CheckboxAutocomplete.svelte.d.ts +23 -0
- package/dist/fields/components/Contactselector.svelte +348 -0
- package/dist/fields/components/Contactselector.svelte.d.ts +25 -0
- package/dist/fields/components/Currency.svelte +258 -0
- package/dist/fields/components/Currency.svelte.d.ts +23 -0
- package/dist/fields/components/Dataindication.svelte +35 -0
- package/dist/fields/components/Dataindication.svelte.d.ts +23 -0
- package/dist/fields/components/Date.svelte +94 -0
- package/dist/fields/components/Date.svelte.d.ts +23 -0
- package/dist/fields/components/Datetime.svelte +94 -0
- package/dist/fields/components/Datetime.svelte.d.ts +23 -0
- package/dist/fields/components/Email.svelte +124 -0
- package/dist/fields/components/Email.svelte.d.ts +23 -0
- package/dist/fields/components/Fieldbuilder.svelte +340 -0
- package/dist/fields/components/Fieldbuilder.svelte.d.ts +25 -0
- package/dist/fields/components/Fieldsbuilder.svelte +122 -0
- package/dist/fields/components/Fieldsbuilder.svelte.d.ts +25 -0
- package/dist/fields/components/File.svelte +230 -0
- package/dist/fields/components/File.svelte.d.ts +25 -0
- package/dist/fields/components/Heading.svelte +17 -0
- package/dist/fields/components/Heading.svelte.d.ts +23 -0
- package/dist/fields/components/Hidden.svelte +7 -0
- package/dist/fields/components/Hidden.svelte.d.ts +23 -0
- package/dist/fields/components/Hiddenlocation.svelte +28 -0
- package/dist/fields/components/Hiddenlocation.svelte.d.ts +23 -0
- package/dist/fields/components/Html.svelte +13 -0
- package/dist/fields/components/Html.svelte.d.ts +23 -0
- package/dist/fields/components/Jsoneditor.svelte +94 -0
- package/dist/fields/components/Jsoneditor.svelte.d.ts +23 -0
- package/dist/fields/components/Map.svelte +192 -0
- package/dist/fields/components/Map.svelte.d.ts +25 -0
- package/dist/fields/components/Multicheckbox.svelte +119 -0
- package/dist/fields/components/Multicheckbox.svelte.d.ts +23 -0
- package/dist/fields/components/Multistep.svelte +86 -0
- package/dist/fields/components/Multistep.svelte.d.ts +25 -0
- package/dist/fields/components/Note.svelte +92 -0
- package/dist/fields/components/Note.svelte.d.ts +23 -0
- package/dist/fields/components/Number.svelte +118 -0
- package/dist/fields/components/Number.svelte.d.ts +23 -0
- package/dist/fields/components/Objectbuilder.svelte +152 -0
- package/dist/fields/components/Objectbuilder.svelte.d.ts +25 -0
- package/dist/fields/components/Qrcodescanner.svelte +198 -0
- package/dist/fields/components/Qrcodescanner.svelte.d.ts +23 -0
- package/dist/fields/components/Radio.svelte +116 -0
- package/dist/fields/components/Radio.svelte.d.ts +23 -0
- package/dist/fields/components/Renderfield.svelte +58 -0
- package/dist/fields/components/Renderfield.svelte.d.ts +25 -0
- package/dist/fields/components/Screenrecorder.svelte +277 -0
- package/dist/fields/components/Screenrecorder.svelte.d.ts +25 -0
- package/dist/fields/components/Screenshot.svelte +270 -0
- package/dist/fields/components/Screenshot.svelte.d.ts +25 -0
- package/dist/fields/components/Scrollandreaddisplay.svelte +122 -0
- package/dist/fields/components/Scrollandreaddisplay.svelte.d.ts +23 -0
- package/dist/fields/components/Section.svelte +64 -0
- package/dist/fields/components/Section.svelte.d.ts +25 -0
- package/dist/fields/components/Select.svelte +229 -0
- package/dist/fields/components/Select.svelte.d.ts +23 -0
- package/dist/fields/components/Selectresource.svelte +291 -0
- package/dist/fields/components/Selectresource.svelte.d.ts +25 -0
- package/dist/fields/components/Signature.svelte +153 -0
- package/dist/fields/components/Signature.svelte.d.ts +25 -0
- package/dist/fields/components/Slider.svelte +101 -0
- package/dist/fields/components/Slider.svelte.d.ts +23 -0
- package/dist/fields/components/SmartText.svelte +330 -0
- package/dist/fields/components/SmartText.svelte.d.ts +23 -0
- package/dist/fields/components/Telephone.svelte +153 -0
- package/dist/fields/components/Telephone.svelte.d.ts +23 -0
- package/dist/fields/components/Text.svelte +106 -0
- package/dist/fields/components/Text.svelte.d.ts +23 -0
- package/dist/fields/components/Voicenote.svelte +268 -0
- package/dist/fields/components/Voicenote.svelte.d.ts +25 -0
- package/dist/fields/components/index.d.ts +81 -0
- package/dist/fields/components/index.js +82 -0
- package/dist/fields/definitions/_all.json +38 -0
- package/dist/fields/definitions/_valid_fieldtype.json +220 -0
- package/dist/fields/definitions/arraybuilder.json +39 -0
- package/dist/fields/definitions/checkbox.json +44 -0
- package/dist/fields/definitions/contactselector.json +15 -0
- package/dist/fields/definitions/currency.json +42 -0
- package/dist/fields/definitions/dataindication.json +16 -0
- package/dist/fields/definitions/date.json +16 -0
- package/dist/fields/definitions/datetime.json +15 -0
- package/dist/fields/definitions/email.json +16 -0
- package/dist/fields/definitions/fieldbuilder.json +64 -0
- package/dist/fields/definitions/fieldsbuilder.json +38 -0
- package/dist/fields/definitions/file.json +42 -0
- package/dist/fields/definitions/grid.json +47 -0
- package/dist/fields/definitions/heading.json +38 -0
- package/dist/fields/definitions/hidden.json +89 -0
- package/dist/fields/definitions/hiddenlocation.json +15 -0
- package/dist/fields/definitions/html.json +34 -0
- package/dist/fields/definitions/index.d.ts +86 -0
- package/dist/fields/definitions/index.js +96 -0
- package/dist/fields/definitions/jsoneditor.json +33 -0
- package/dist/fields/definitions/map.json +36 -0
- package/dist/fields/definitions/multicheckbox.json +47 -0
- package/dist/fields/definitions/multistep.json +35 -0
- package/dist/fields/definitions/note.json +16 -0
- package/dist/fields/definitions/number.json +42 -0
- package/dist/fields/definitions/objectbuilder.json +39 -0
- package/dist/fields/definitions/qrcodescanner.json +16 -0
- package/dist/fields/definitions/radio.json +47 -0
- package/dist/fields/definitions/renderfield.json +36 -0
- package/dist/fields/definitions/richtext.json +16 -0
- package/dist/fields/definitions/screenrecorder.json +42 -0
- package/dist/fields/definitions/screenshot.json +42 -0
- package/dist/fields/definitions/scrollandreaddisplay.json +49 -0
- package/dist/fields/definitions/section.json +50 -0
- package/dist/fields/definitions/select.json +47 -0
- package/dist/fields/definitions/selectresource.json +48 -0
- package/dist/fields/definitions/signature.json +16 -0
- package/dist/fields/definitions/slider.json +78 -0
- package/dist/fields/definitions/smart_text.json +101 -0
- package/dist/fields/definitions/telephone.json +16 -0
- package/dist/fields/definitions/text.json +35 -0
- package/dist/fields/definitions/voicenote.json +43 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/dist/thirdparty/mapbox/GeoCoder.svelte +10 -0
- package/dist/thirdparty/mapbox/GeoCoder.svelte.d.ts +25 -0
- package/dist/thirdparty/mapbox/Map.svelte +30 -0
- package/dist/thirdparty/mapbox/Map.svelte.d.ts +20 -0
- package/dist/thirdparty/mapbox/MapMarker.svelte +13 -0
- package/dist/thirdparty/mapbox/MapMarker.svelte.d.ts +31 -0
- package/dist/utils/createField.d.ts +6 -0
- package/dist/utils/createField.js +33 -0
- package/dist/utils/createForm.d.ts +1 -0
- package/dist/utils/createForm.js +501 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.js +126 -0
- package/dist/utils/syncing.d.ts +11 -0
- package/dist/utils/syncing.js +134 -0
- package/package.json +78 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { syncStoreToStore } from "../../utils/syncing";
|
|
3
|
+
import { deepEqual } from "fast-equals";
|
|
4
|
+
import _ from "lodash-es";
|
|
5
|
+
import { onMount } from "svelte";
|
|
6
|
+
import { writable } from "svelte/store";
|
|
7
|
+
|
|
8
|
+
export let field;
|
|
9
|
+
|
|
10
|
+
const internal = writable();
|
|
11
|
+
|
|
12
|
+
$: state_key = $field.state?.state_key;
|
|
13
|
+
$: label = $field.spec?.title;
|
|
14
|
+
$: hide_label = $field.spec?.hide_label;
|
|
15
|
+
$: isValid = !$field.state?.validation || $field.state?.validation?.valid;
|
|
16
|
+
$: validationMessage = $field.state?.validation?.message;
|
|
17
|
+
$: min_setting = $field.spec.params.min ?? false;
|
|
18
|
+
$: max_setting = $field.spec.params.max ?? false;
|
|
19
|
+
$: step_setting = $field.spec.params.step ?? 1;
|
|
20
|
+
$: has_step = $field.spec.params.step ?? false;
|
|
21
|
+
|
|
22
|
+
onMount(() => {
|
|
23
|
+
// set field values that aren't set yet
|
|
24
|
+
let f = _.cloneDeep($field);
|
|
25
|
+
let initial_value = f?.data?.base ?? "";
|
|
26
|
+
let initial_data = {
|
|
27
|
+
...f?.data,
|
|
28
|
+
base: initial_value,
|
|
29
|
+
};
|
|
30
|
+
let initial_state_internal = {
|
|
31
|
+
...f?.state?.internal,
|
|
32
|
+
raw: initial_value,
|
|
33
|
+
};
|
|
34
|
+
_.set(f, "data", initial_data);
|
|
35
|
+
_.set(f, "state.internal", initial_state_internal);
|
|
36
|
+
if (!deepEqual(f, $field)) $field = f;
|
|
37
|
+
|
|
38
|
+
syncStoreToStore(
|
|
39
|
+
field,
|
|
40
|
+
internal,
|
|
41
|
+
(a, b) => {
|
|
42
|
+
let _clone = _.cloneDeep(a.state?.internal) || {};
|
|
43
|
+
|
|
44
|
+
// get parts from data
|
|
45
|
+
_clone.raw = a?.data?.base;
|
|
46
|
+
|
|
47
|
+
// set field state if changed
|
|
48
|
+
if (!deepEqual(a?.state?.internal, _clone)) {
|
|
49
|
+
$field.state.internal = _clone;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return _clone;
|
|
53
|
+
},
|
|
54
|
+
(a, b) => {
|
|
55
|
+
let _clone = _.cloneDeep(a) || {};
|
|
56
|
+
|
|
57
|
+
let raw = b.raw;
|
|
58
|
+
|
|
59
|
+
// check if raw is valid
|
|
60
|
+
if (max_setting != false && raw > max_setting) {
|
|
61
|
+
raw = max_setting;
|
|
62
|
+
}
|
|
63
|
+
if (min_setting != false && raw < min_setting) {
|
|
64
|
+
raw = min_setting;
|
|
65
|
+
}
|
|
66
|
+
if (has_step) {
|
|
67
|
+
raw = Math.round(raw / step_setting) * step_setting;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// if raw is different to b.raw, update internal
|
|
71
|
+
if (raw !== b.raw) $internal.raw = raw;
|
|
72
|
+
|
|
73
|
+
b.raw = raw;
|
|
74
|
+
|
|
75
|
+
// update the state
|
|
76
|
+
_.set(_clone, "state.internal", _.cloneDeep(b));
|
|
77
|
+
// update the data
|
|
78
|
+
_.set(_clone, "data.base", raw);
|
|
79
|
+
return _clone;
|
|
80
|
+
},
|
|
81
|
+
null,
|
|
82
|
+
300
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
{#if $internal}
|
|
88
|
+
<div class="flex flex-col w-full text-surface-900">
|
|
89
|
+
<label for="input_{state_key}" class="block text-label {hide_label ? 'hidden' : ''}">
|
|
90
|
+
{label}
|
|
91
|
+
</label>
|
|
92
|
+
<div class="relative rounded-md">
|
|
93
|
+
<input
|
|
94
|
+
on:keydown={(e) => {
|
|
95
|
+
if (e.key === "Enter") {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
}
|
|
98
|
+
}}
|
|
99
|
+
type="number"
|
|
100
|
+
id="input_{state_key}"
|
|
101
|
+
placeholder={label}
|
|
102
|
+
class="block w-full text-field rounded-md border-0 py-2 pl-3 text-surface-900 ring-1 ring-inset {!isValid
|
|
103
|
+
? 'ring-danger-500'
|
|
104
|
+
: 'ring-surface-300 focus:ring-primary-400'} focus:outline-none placeholder:text-surface-400 focus:ring-2 focus:ring-inset"
|
|
105
|
+
name={state_key}
|
|
106
|
+
min={min_setting}
|
|
107
|
+
max={max_setting}
|
|
108
|
+
step={step_setting}
|
|
109
|
+
bind:value={$internal.raw}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
{#if validationMessage}
|
|
113
|
+
<p class="text-label {!isValid ? `text-danger-500` : `text-success-500`}">
|
|
114
|
+
{validationMessage}
|
|
115
|
+
</p>
|
|
116
|
+
{/if}
|
|
117
|
+
</div>
|
|
118
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} NumberProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} NumberEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} NumberSlots */
|
|
4
|
+
export default class Number extends SvelteComponentTyped<{
|
|
5
|
+
field: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type NumberProps = typeof __propDef.props;
|
|
11
|
+
export type NumberEvents = typeof __propDef.events;
|
|
12
|
+
export type NumberSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
field: any;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { Form } from "../..";
|
|
3
|
+
import _ from "lodash-es";
|
|
4
|
+
import { syncStoreToStore } from "../../utils/syncing";
|
|
5
|
+
import { writable } from "svelte/store";
|
|
6
|
+
import { onMount } from "svelte";
|
|
7
|
+
import { deepEqual } from "fast-equals";
|
|
8
|
+
|
|
9
|
+
export let form;
|
|
10
|
+
export let field;
|
|
11
|
+
|
|
12
|
+
let dependencies = form.dependencies;
|
|
13
|
+
|
|
14
|
+
$: state_key = $field.state?.state_key;
|
|
15
|
+
$: label = $field.spec?.title;
|
|
16
|
+
$: hide_label = $field.spec?.hide_label;
|
|
17
|
+
$: with_order = $field.spec?.params?.with_order;
|
|
18
|
+
$: key_field_spec = $field.spec?.params?.key_field_spec || {};
|
|
19
|
+
$: value_field_spec = $field.spec?.params?.value_field_spec || {};
|
|
20
|
+
$: isValid = !$field.state?.validation || $field.state?.validation?.valid;
|
|
21
|
+
$: validationMessage = $field.state?.validation?.message;
|
|
22
|
+
|
|
23
|
+
let initial_form;
|
|
24
|
+
let settings_form = writable();
|
|
25
|
+
onMount(() => {
|
|
26
|
+
// set field values that aren't set yet
|
|
27
|
+
let f = _.cloneDeep($field);
|
|
28
|
+
let initial_value = f?.data?.base ?? {};
|
|
29
|
+
let initial_data = _.merge(
|
|
30
|
+
{
|
|
31
|
+
base: initial_value,
|
|
32
|
+
},
|
|
33
|
+
f?.data
|
|
34
|
+
);
|
|
35
|
+
_.set(f, "data", initial_data);
|
|
36
|
+
if (!deepEqual(f, $field)) $field = f;
|
|
37
|
+
|
|
38
|
+
initial_form = {
|
|
39
|
+
spec: {
|
|
40
|
+
fields: {
|
|
41
|
+
entries: {
|
|
42
|
+
fieldtype: "arraybuilder",
|
|
43
|
+
hide_label: true,
|
|
44
|
+
params: {
|
|
45
|
+
new_entry_field: {
|
|
46
|
+
fieldtype: "section",
|
|
47
|
+
fields: {
|
|
48
|
+
key: _.merge({}, { title: "Key" }, key_field_spec),
|
|
49
|
+
value: _.merge({}, { title: "Value" }, value_field_spec),
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
data: {
|
|
57
|
+
entries: _.cloneDeep(
|
|
58
|
+
Object.entries(initial_value ?? {})
|
|
59
|
+
.sort((a, b) => {
|
|
60
|
+
let a_order = a[1]?.__order ?? 0;
|
|
61
|
+
let b_order = b[1]?.__order ?? 0;
|
|
62
|
+
return a_order - b_order;
|
|
63
|
+
})
|
|
64
|
+
.map((e) => {
|
|
65
|
+
return {
|
|
66
|
+
value: e[1],
|
|
67
|
+
key: e[0],
|
|
68
|
+
};
|
|
69
|
+
})
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
syncStoreToStore(
|
|
75
|
+
field,
|
|
76
|
+
settings_form,
|
|
77
|
+
(a, b) => {
|
|
78
|
+
let _clone = _.cloneDeep(b) || {};
|
|
79
|
+
|
|
80
|
+
let internal_entries = _.cloneDeep(a?.state?.internal || []);
|
|
81
|
+
let entries = Object.entries(a?.data?.base || {})
|
|
82
|
+
.sort((a, b) => {
|
|
83
|
+
let a_order = a[1]?.__order ?? 0;
|
|
84
|
+
let b_order = b[1]?.__order ?? 0;
|
|
85
|
+
return a_order - b_order;
|
|
86
|
+
})
|
|
87
|
+
.map((e, index) => {
|
|
88
|
+
let internal_state = internal_entries[index] || {};
|
|
89
|
+
return {
|
|
90
|
+
...internal_state,
|
|
91
|
+
value: e[1],
|
|
92
|
+
key: e[0],
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
_.set(_clone, "data.entries", entries);
|
|
97
|
+
|
|
98
|
+
if (!deepEqual(entries, a?.state?.internal)) {
|
|
99
|
+
$field.state.internal = _.cloneDeep(entries);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return _clone;
|
|
103
|
+
},
|
|
104
|
+
(a, b) => {
|
|
105
|
+
let _clone = _.cloneDeep(a) || {};
|
|
106
|
+
|
|
107
|
+
let uentries = _.cloneDeep(b.data.entries || []);
|
|
108
|
+
let entries = [];
|
|
109
|
+
uentries.forEach((curr, index) => {
|
|
110
|
+
let key = curr.key ?? "";
|
|
111
|
+
if (_.isObject(key)) key = JSON.stringify(key);
|
|
112
|
+
key = key.toString().trim();
|
|
113
|
+
let value = curr.value ?? null;
|
|
114
|
+
if (_.isObject(value) && with_order) {
|
|
115
|
+
value.__order = index;
|
|
116
|
+
}
|
|
117
|
+
let key_exists = entries.find((e) => e.key === key);
|
|
118
|
+
if (key_exists) key = key + " (copy)";
|
|
119
|
+
entries.push({ ...curr, key, value });
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (!deepEqual(entries, b.data.entries)) {
|
|
123
|
+
$settings_form.data.entries = _.cloneDeep(entries);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let base = entries.reduce((acc, curr) => {
|
|
127
|
+
acc[curr.key] = curr.value;
|
|
128
|
+
return acc;
|
|
129
|
+
}, {});
|
|
130
|
+
|
|
131
|
+
_.set(_clone, "data.base", _.cloneDeep(base));
|
|
132
|
+
_.set(_clone, "state.internal", _.cloneDeep(entries));
|
|
133
|
+
|
|
134
|
+
return _clone;
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<div class="flex flex-col w-full text-surface-900">
|
|
141
|
+
<label for="input_{state_key}" class="block text-label {hide_label ? 'hidden' : ''}">
|
|
142
|
+
{label}
|
|
143
|
+
</label>
|
|
144
|
+
{#if initial_form}
|
|
145
|
+
<Form bind:form={settings_form} {initial_form} {dependencies} />
|
|
146
|
+
{/if}
|
|
147
|
+
{#if validationMessage}
|
|
148
|
+
<p class="text-label {!isValid ? `text-danger-500` : `text-success-500`}">
|
|
149
|
+
{validationMessage}
|
|
150
|
+
</p>
|
|
151
|
+
{/if}
|
|
152
|
+
</div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} ObjectbuilderProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} ObjectbuilderEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} ObjectbuilderSlots */
|
|
4
|
+
export default class Objectbuilder extends SvelteComponentTyped<{
|
|
5
|
+
form: any;
|
|
6
|
+
field: any;
|
|
7
|
+
}, {
|
|
8
|
+
[evt: string]: CustomEvent<any>;
|
|
9
|
+
}, {}> {
|
|
10
|
+
}
|
|
11
|
+
export type ObjectbuilderProps = typeof __propDef.props;
|
|
12
|
+
export type ObjectbuilderEvents = typeof __propDef.events;
|
|
13
|
+
export type ObjectbuilderSlots = typeof __propDef.slots;
|
|
14
|
+
import { SvelteComponentTyped } from "svelte";
|
|
15
|
+
declare const __propDef: {
|
|
16
|
+
props: {
|
|
17
|
+
form: any;
|
|
18
|
+
field: any;
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {};
|
|
24
|
+
};
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { syncStoreToStore } from "../../utils/syncing";
|
|
3
|
+
import { deepEqual } from "fast-equals";
|
|
4
|
+
import _ from "lodash-es";
|
|
5
|
+
import { onMount } from "svelte";
|
|
6
|
+
import { writable } from "svelte/store";
|
|
7
|
+
import { fade } from "svelte/transition";
|
|
8
|
+
import { Html5Qrcode } from "html5-qrcode";
|
|
9
|
+
import { Button } from "@stubber/ui";
|
|
10
|
+
|
|
11
|
+
export let field;
|
|
12
|
+
|
|
13
|
+
const internal = writable();
|
|
14
|
+
let html5Qrcode;
|
|
15
|
+
let isScannerModalOpen = false;
|
|
16
|
+
let isCameraAvailable = false;
|
|
17
|
+
let scansuccess = false;
|
|
18
|
+
let scannedResult = "";
|
|
19
|
+
|
|
20
|
+
async function openScannerModal() {
|
|
21
|
+
if (isScannerModalOpen == false) {
|
|
22
|
+
isScannerModalOpen = true;
|
|
23
|
+
scannedResult = "";
|
|
24
|
+
scansuccess = false;
|
|
25
|
+
let cameras = await Html5Qrcode.getCameras();
|
|
26
|
+
if (!cameras) {
|
|
27
|
+
isCameraAvailable = false;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
isCameraAvailable = true;
|
|
31
|
+
let cameraId = cameras[0].id;
|
|
32
|
+
html5Qrcode = new Html5Qrcode("reader");
|
|
33
|
+
html5Qrcode.start(cameraId, { fps: 2 }, onScanSuccess, onScanFailure);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function closeScannerModal() {
|
|
38
|
+
isScannerModalOpen = false;
|
|
39
|
+
html5Qrcode.stop();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function onScanSuccess(decodedText, decodedResult) {
|
|
43
|
+
scannedResult = decodedText;
|
|
44
|
+
scansuccess = true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function onScanFailure(error) {
|
|
48
|
+
// handle scan failure, usually better to ignore and keep scanning.
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
$: state_key = $field.state?.state_key;
|
|
52
|
+
$: label = $field.spec?.title;
|
|
53
|
+
$: hide_label = $field.spec?.hide_label;
|
|
54
|
+
$: isValid = !$field.state?.validation || $field.state?.validation?.valid;
|
|
55
|
+
$: validationMessage = $field.state?.validation?.message;
|
|
56
|
+
|
|
57
|
+
function confirmScan() {
|
|
58
|
+
closeScannerModal();
|
|
59
|
+
$internal.raw = scannedResult;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
onMount(() => {
|
|
63
|
+
// set field values that aren't set yet
|
|
64
|
+
let f = _.cloneDeep($field);
|
|
65
|
+
let initial_value = f?.data?.base ?? "";
|
|
66
|
+
let initial_data = {
|
|
67
|
+
...f?.data,
|
|
68
|
+
base: initial_value,
|
|
69
|
+
};
|
|
70
|
+
let initial_state_internal = {
|
|
71
|
+
...f?.state?.internal,
|
|
72
|
+
raw: initial_value,
|
|
73
|
+
};
|
|
74
|
+
_.set(f, "data", initial_data);
|
|
75
|
+
_.set(f, "state.internal", initial_state_internal);
|
|
76
|
+
if (!deepEqual(f, $field)) $field = f;
|
|
77
|
+
|
|
78
|
+
syncStoreToStore(
|
|
79
|
+
field,
|
|
80
|
+
internal,
|
|
81
|
+
(a, b) => {
|
|
82
|
+
let _clone = _.cloneDeep(a.state?.internal) || {};
|
|
83
|
+
|
|
84
|
+
// get parts from data
|
|
85
|
+
_clone.raw = a?.data?.base;
|
|
86
|
+
|
|
87
|
+
// set field state if changed
|
|
88
|
+
if (!deepEqual(a?.state?.internal, _clone)) {
|
|
89
|
+
$field.state.internal = _clone;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return _clone;
|
|
93
|
+
},
|
|
94
|
+
(a, b) => {
|
|
95
|
+
let _clone = _.cloneDeep(a) || {};
|
|
96
|
+
// update the state
|
|
97
|
+
_.set(_clone, "state.internal", _.cloneDeep(b));
|
|
98
|
+
// update the data
|
|
99
|
+
_.set(_clone, "data.base", b?.raw);
|
|
100
|
+
return _clone;
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
{#if $internal}
|
|
107
|
+
{#if isScannerModalOpen}
|
|
108
|
+
<div class="fixed inset-0 w-screen h-screen bg-black/50 z-30">
|
|
109
|
+
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
110
|
+
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
111
|
+
<div
|
|
112
|
+
in:fade|global
|
|
113
|
+
out:fade|global={{ duration: 100 }}
|
|
114
|
+
on:click|self={() => {
|
|
115
|
+
closeScannerModal();
|
|
116
|
+
}}
|
|
117
|
+
class="fixed inset-0 flex justify-center items-center z-30 my-6"
|
|
118
|
+
>
|
|
119
|
+
<div
|
|
120
|
+
class="max-w-full max-h-full overflow-auto bg-surface-0 p-6 pt-4 rounded-2xl border shadow-2xl"
|
|
121
|
+
>
|
|
122
|
+
<button
|
|
123
|
+
type="button"
|
|
124
|
+
class="block ml-auto text-surface-700 font-bold text-lg"
|
|
125
|
+
on:click={closeScannerModal}
|
|
126
|
+
>
|
|
127
|
+
<i class="fa-regular fa-xmark" />
|
|
128
|
+
</button>
|
|
129
|
+
<div class="px-2 space-y-3">
|
|
130
|
+
<h4
|
|
131
|
+
class="text-start text-surface-900 text-heading-6 font-medium border-b border-surface-200"
|
|
132
|
+
>
|
|
133
|
+
Scan code
|
|
134
|
+
</h4>
|
|
135
|
+
<div id="reader" class="w-[250px] sm:w-[310px] flex flex-col items-center" />
|
|
136
|
+
{#if isCameraAvailable}
|
|
137
|
+
{#if scansuccess}
|
|
138
|
+
<div class="flex items-center space-x-2">
|
|
139
|
+
<i class="fas fa-circle text-success-400 fa-2xs" />
|
|
140
|
+
<p class="text-label text-surface-800">{scannedResult}</p>
|
|
141
|
+
</div>
|
|
142
|
+
{:else}
|
|
143
|
+
<div class="flex items-center space-x-2">
|
|
144
|
+
<i class="fas fa-circle text-surface-200 fa-2xs" />
|
|
145
|
+
<p class="text-label text-surface-800">Searching for code ...</p>
|
|
146
|
+
</div>
|
|
147
|
+
{/if}
|
|
148
|
+
<div class="flex">
|
|
149
|
+
<div class="flex ml-auto">
|
|
150
|
+
<Button
|
|
151
|
+
disabled={!scansuccess}
|
|
152
|
+
on:click={confirmScan}>
|
|
153
|
+
Confirm
|
|
154
|
+
</Button>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
{:else}
|
|
158
|
+
<div class="w-[250px] sm:w-[310px] aspect-square flex items-center justify-center">
|
|
159
|
+
<p class="text-surface-800 text-label">No camera found</p>
|
|
160
|
+
</div>
|
|
161
|
+
{/if}
|
|
162
|
+
</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</div>
|
|
166
|
+
{/if}
|
|
167
|
+
|
|
168
|
+
<div class="flex flex-col w-full text-surface-900">
|
|
169
|
+
<label for="input_{state_key}" class="block text-label {hide_label ? 'hidden' : ''}">
|
|
170
|
+
{label}
|
|
171
|
+
</label>
|
|
172
|
+
<div class="relative mt-2 rounded-md">
|
|
173
|
+
<div class="flex items-center space-x-3">
|
|
174
|
+
{#if $internal.raw}
|
|
175
|
+
<input
|
|
176
|
+
readonly
|
|
177
|
+
type="text"
|
|
178
|
+
id="input_{state_key}"
|
|
179
|
+
placeholder={label}
|
|
180
|
+
class="block w-full text-field rounded-md border-0 py-2 pl-3 text-surface-900 ring-1 ring-inset {!isValid
|
|
181
|
+
? 'ring-danger-500'
|
|
182
|
+
: 'ring-surface-300 focus:ring-primary-400'} focus:outline-none placeholder:text-surface-400 focus:ring-2 focus:ring-inset"
|
|
183
|
+
name={state_key}
|
|
184
|
+
value={$internal.raw}
|
|
185
|
+
/>
|
|
186
|
+
{/if}
|
|
187
|
+
<div class="shrink-0">
|
|
188
|
+
<Button icon="camera" label="Scan code" on:click={openScannerModal} />
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
</div>
|
|
192
|
+
{#if validationMessage}
|
|
193
|
+
<p class="text-label {!isValid ? `text-danger-500` : `text-success-500`}">
|
|
194
|
+
{validationMessage}
|
|
195
|
+
</p>
|
|
196
|
+
{/if}
|
|
197
|
+
</div>
|
|
198
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} QrcodescannerProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} QrcodescannerEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} QrcodescannerSlots */
|
|
4
|
+
export default class Qrcodescanner extends SvelteComponentTyped<{
|
|
5
|
+
field: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type QrcodescannerProps = typeof __propDef.props;
|
|
11
|
+
export type QrcodescannerEvents = typeof __propDef.events;
|
|
12
|
+
export type QrcodescannerSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
field: any;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { syncStoreToStore } from "../../utils/syncing";
|
|
3
|
+
import { deepEqual } from "fast-equals";
|
|
4
|
+
import _ from "lodash-es";
|
|
5
|
+
import { onMount } from "svelte";
|
|
6
|
+
import { writable } from "svelte/store";
|
|
7
|
+
|
|
8
|
+
export let field;
|
|
9
|
+
|
|
10
|
+
const internal = writable();
|
|
11
|
+
|
|
12
|
+
$: state_key = $field.state?.state_key;
|
|
13
|
+
$: label = $field.spec?.title;
|
|
14
|
+
$: hide_label = $field.spec?.hide_label;
|
|
15
|
+
$: isValid = !$field.state?.validation || $field.state?.validation?.valid;
|
|
16
|
+
$: validationMessage = $field.state?.validation?.message;
|
|
17
|
+
$: items = _.isArray($field.spec?.params?.options)
|
|
18
|
+
? $field.spec?.params?.options?.map((o, index) => {
|
|
19
|
+
let { label, value } = o || {};
|
|
20
|
+
let _value = value !== undefined ? value : label;
|
|
21
|
+
let _label = label ?? value;
|
|
22
|
+
let _key = `${state_key}${label}${index}`;
|
|
23
|
+
return { _key, _label, _value };
|
|
24
|
+
})
|
|
25
|
+
: [];
|
|
26
|
+
|
|
27
|
+
onMount(() => {
|
|
28
|
+
// set field values that aren't set yet
|
|
29
|
+
let f = _.cloneDeep($field);
|
|
30
|
+
let initial_item = items?.find((i) => deepEqual($field.data.base, i._value));
|
|
31
|
+
if (!initial_item) initial_item = items[0];
|
|
32
|
+
let initial_data = {
|
|
33
|
+
...f?.data,
|
|
34
|
+
base: initial_item?._value,
|
|
35
|
+
};
|
|
36
|
+
if (!f?.spec?.without_value_details) initial_data.base_label = initial_item?._label;
|
|
37
|
+
let initial_state_internal = {
|
|
38
|
+
...f?.state?.internal,
|
|
39
|
+
selected_item_key: initial_item?._key,
|
|
40
|
+
};
|
|
41
|
+
_.set(f, "data", initial_data);
|
|
42
|
+
_.set(f, "state.internal", initial_state_internal);
|
|
43
|
+
if (!deepEqual(f, $field)) $field = f;
|
|
44
|
+
|
|
45
|
+
syncStoreToStore(
|
|
46
|
+
field,
|
|
47
|
+
internal,
|
|
48
|
+
(a, b) => {
|
|
49
|
+
let _clone = _.cloneDeep(a.state?.internal) || {};
|
|
50
|
+
|
|
51
|
+
// get parts from data
|
|
52
|
+
let item = items.find((i) => i._value === a?.data?.base);
|
|
53
|
+
if (!item) item = items[0];
|
|
54
|
+
if (item) {
|
|
55
|
+
_clone.selected_item_key = item?._key;
|
|
56
|
+
|
|
57
|
+
// set field_label if changed
|
|
58
|
+
if (!deepEqual(a?.data?.base_label, item?._label) && !a?.spec?.without_value_details) {
|
|
59
|
+
$field.data.base_label = item?._label;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// set field state if changed
|
|
63
|
+
if (!deepEqual(a?.state?.internal, _clone)) {
|
|
64
|
+
$field.state.internal = _clone;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return _clone;
|
|
69
|
+
},
|
|
70
|
+
(a, b) => {
|
|
71
|
+
let _clone = _.cloneDeep(a) || {};
|
|
72
|
+
// update the state
|
|
73
|
+
_.set(_clone, "state.internal", _.cloneDeep(b));
|
|
74
|
+
// update the data
|
|
75
|
+
let item = items.find((i) => i._key === b?.selected_item_key);
|
|
76
|
+
_.set(_clone, "data.base", item?._value);
|
|
77
|
+
if (!a?.spec?.without_value_details) _.set(_clone, "data.base_label", item?._label);
|
|
78
|
+
return _clone;
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
</script>
|
|
83
|
+
|
|
84
|
+
{#if $internal}
|
|
85
|
+
<div class="flex flex-col w-full text-surface-900">
|
|
86
|
+
<label for="input_{state_key}" class="block text-label {hide_label ? 'hidden' : ''}">
|
|
87
|
+
{label}
|
|
88
|
+
</label>
|
|
89
|
+
{#if items?.length}
|
|
90
|
+
<fieldset
|
|
91
|
+
class="flex flex-col border {!isValid
|
|
92
|
+
? 'border-warning-500'
|
|
93
|
+
: 'border-surface-300'} rounded-md px-2 py-1"
|
|
94
|
+
id="input_{state_key}"
|
|
95
|
+
>
|
|
96
|
+
{#each items as item}
|
|
97
|
+
<div class="py-1">
|
|
98
|
+
<input
|
|
99
|
+
id="input_{item._key}"
|
|
100
|
+
name={state_key}
|
|
101
|
+
bind:group={$internal.selected_item_key}
|
|
102
|
+
type="radio"
|
|
103
|
+
value={item._key}
|
|
104
|
+
/>
|
|
105
|
+
<label for="input_{item._key}" class="text-field">{item._label}</label>
|
|
106
|
+
</div>
|
|
107
|
+
{/each}
|
|
108
|
+
</fieldset>
|
|
109
|
+
{/if}
|
|
110
|
+
{#if validationMessage}
|
|
111
|
+
<p class="text-label {!isValid ? `text-danger-500` : `text-success-500`}">
|
|
112
|
+
{validationMessage}
|
|
113
|
+
</p>
|
|
114
|
+
{/if}
|
|
115
|
+
</div>
|
|
116
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @typedef {typeof __propDef.props} RadioProps */
|
|
2
|
+
/** @typedef {typeof __propDef.events} RadioEvents */
|
|
3
|
+
/** @typedef {typeof __propDef.slots} RadioSlots */
|
|
4
|
+
export default class Radio extends SvelteComponentTyped<{
|
|
5
|
+
field: any;
|
|
6
|
+
}, {
|
|
7
|
+
[evt: string]: CustomEvent<any>;
|
|
8
|
+
}, {}> {
|
|
9
|
+
}
|
|
10
|
+
export type RadioProps = typeof __propDef.props;
|
|
11
|
+
export type RadioEvents = typeof __propDef.events;
|
|
12
|
+
export type RadioSlots = typeof __propDef.slots;
|
|
13
|
+
import { SvelteComponentTyped } from "svelte";
|
|
14
|
+
declare const __propDef: {
|
|
15
|
+
props: {
|
|
16
|
+
field: any;
|
|
17
|
+
};
|
|
18
|
+
events: {
|
|
19
|
+
[evt: string]: CustomEvent<any>;
|
|
20
|
+
};
|
|
21
|
+
slots: {};
|
|
22
|
+
};
|
|
23
|
+
export {};
|