@stubber/form-fields 2.2.6 → 3.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.
Files changed (126) hide show
  1. package/README.md +63 -25
  2. package/dist/form-fields/Autocomplete.svelte +261 -0
  3. package/dist/form-fields/Autocomplete.svelte.d.ts +43 -0
  4. package/dist/form-fields/CollapsibleSection.svelte +127 -0
  5. package/dist/form-fields/CollapsibleSection.svelte.d.ts +26 -0
  6. package/dist/form-fields/FieldLabel.svelte +18 -3
  7. package/dist/form-fields/FieldLabel.svelte.d.ts +1 -0
  8. package/dist/form-fields/FieldMessage.svelte +20 -9
  9. package/dist/form-fields/Form.svelte +19 -2
  10. package/dist/form-fields/Form.svelte.d.ts +2 -0
  11. package/dist/form-fields/UploadStatus.svelte +76 -0
  12. package/dist/form-fields/UploadStatus.svelte.d.ts +18 -0
  13. package/dist/form-fields/fields/_field-builder-reorder.svelte +35 -0
  14. package/dist/form-fields/fields/_field-builder-reorder.svelte.d.ts +22 -0
  15. package/dist/form-fields/{sub → fields}/array-builder-field.svelte +104 -38
  16. package/dist/form-fields/fields/checkbox-autocomplete.svelte +153 -0
  17. package/dist/form-fields/fields/checkbox-field.svelte +69 -0
  18. package/dist/form-fields/{sub → fields}/contact-selector-field.svelte +9 -6
  19. package/dist/form-fields/{sub → fields}/currency-field.svelte +108 -70
  20. package/dist/form-fields/fields/data-indication-field.svelte +39 -0
  21. package/dist/form-fields/fields/date-field.svelte +31 -0
  22. package/dist/form-fields/fields/date-time-field.svelte +31 -0
  23. package/dist/form-fields/{sub → fields}/email-field.svelte +25 -11
  24. package/dist/form-fields/fields/field-builder-field.svelte +568 -0
  25. package/dist/form-fields/fields/file-field.svelte +284 -0
  26. package/dist/form-fields/{sub → fields}/file-field.svelte.d.ts +2 -0
  27. package/dist/form-fields/fields/grid-field.svelte +152 -0
  28. package/dist/form-fields/{sub → fields}/heading-field.svelte +7 -4
  29. package/dist/form-fields/{sub → fields}/html-field.svelte +6 -4
  30. package/dist/form-fields/{sub → fields}/map-field.svelte +121 -78
  31. package/dist/form-fields/{sub → fields}/multi-checkbox-field.svelte +35 -20
  32. package/dist/form-fields/fields/multistep-field.svelte +135 -0
  33. package/dist/form-fields/fields/note-field.svelte +35 -0
  34. package/dist/form-fields/{sub → fields}/number-field.svelte +29 -14
  35. package/dist/form-fields/fields/object-builder-field.svelte +176 -0
  36. package/dist/form-fields/fields/qr-code-scanner-field.svelte +203 -0
  37. package/dist/form-fields/fields/radio-field.svelte +82 -0
  38. package/dist/form-fields/{sub → fields}/radio-field.svelte.d.ts +1 -1
  39. package/dist/form-fields/fields/screenrecorder-field.svelte +255 -0
  40. package/dist/form-fields/{sub → fields}/screenshot-field.svelte +101 -40
  41. package/dist/form-fields/{sub → fields}/scroll-and-read-display-field.svelte +43 -27
  42. package/dist/form-fields/fields/section-field.svelte +73 -0
  43. package/dist/form-fields/fields/select-field.svelte +104 -0
  44. package/dist/form-fields/{sub → fields}/signature-field.svelte +78 -22
  45. package/dist/form-fields/fields/slider-field.svelte +53 -0
  46. package/dist/form-fields/{sub → fields}/smart-text-field.svelte +62 -82
  47. package/dist/form-fields/fields/telephone-field.svelte +108 -0
  48. package/dist/form-fields/{sub → fields}/telephone-field.svelte.d.ts +1 -1
  49. package/dist/form-fields/{sub → fields}/text-field.svelte +28 -11
  50. package/dist/form-fields/{sub → fields}/voicenote-field.svelte +117 -46
  51. package/dist/form-fields/file_creation_options.d.ts +1 -1
  52. package/dist/form-fields/form-field.svelte +8 -1
  53. package/dist/form-fields/icons/ChevronDownIcon.svelte +21 -0
  54. package/dist/form-fields/icons/ChevronDownIcon.svelte.d.ts +20 -0
  55. package/dist/form-fields/icons/QrCodeScannerIcon.svelte +25 -0
  56. package/dist/form-fields/icons/QrCodeScannerIcon.svelte.d.ts +19 -0
  57. package/dist/form-fields/icons/ScreenRecordingIcon.svelte +21 -0
  58. package/dist/form-fields/icons/ScreenRecordingIcon.svelte.d.ts +19 -0
  59. package/dist/form-fields/icons/ScreenshotIcon.svelte +22 -0
  60. package/dist/form-fields/icons/ScreenshotIcon.svelte.d.ts +19 -0
  61. package/dist/form-fields/index.d.ts +5 -1
  62. package/dist/form-fields/index.js +3 -1
  63. package/dist/form-fields/interfaces.d.ts +63 -63
  64. package/dist/form-fields/interfaces.js +42 -39
  65. package/dist/form-fields/intl-tel-input.css +1 -0
  66. package/dist/form-fields/styles.d.ts +17 -0
  67. package/dist/form-fields/styles.js +4 -0
  68. package/package.json +2 -4
  69. package/dist/form-fields/sub/checkbox-autocomplete.svelte +0 -56
  70. package/dist/form-fields/sub/checkbox-field.svelte +0 -42
  71. package/dist/form-fields/sub/data-indication-field.svelte +0 -19
  72. package/dist/form-fields/sub/date-field.svelte +0 -31
  73. package/dist/form-fields/sub/date-time-field.svelte +0 -31
  74. package/dist/form-fields/sub/field-builder-field.svelte +0 -657
  75. package/dist/form-fields/sub/file-field.svelte +0 -159
  76. package/dist/form-fields/sub/grid-field.svelte +0 -69
  77. package/dist/form-fields/sub/multistep-field.svelte +0 -70
  78. package/dist/form-fields/sub/note-field.svelte +0 -18
  79. package/dist/form-fields/sub/object-builder-field.svelte +0 -134
  80. package/dist/form-fields/sub/qr-code-scanner-field.svelte +0 -84
  81. package/dist/form-fields/sub/radio-field.svelte +0 -69
  82. package/dist/form-fields/sub/screenrecorder-field.svelte +0 -178
  83. package/dist/form-fields/sub/section-field.svelte +0 -50
  84. package/dist/form-fields/sub/select-field.svelte +0 -150
  85. package/dist/form-fields/sub/slider-field.svelte +0 -28
  86. package/dist/form-fields/sub/telephone-field.svelte +0 -64
  87. /package/dist/form-fields/{sub → fields}/array-builder-field.svelte.d.ts +0 -0
  88. /package/dist/form-fields/{sub → fields}/checkbox-autocomplete.svelte.d.ts +0 -0
  89. /package/dist/form-fields/{sub → fields}/checkbox-field.svelte.d.ts +0 -0
  90. /package/dist/form-fields/{sub → fields}/code-field.svelte +0 -0
  91. /package/dist/form-fields/{sub → fields}/code-field.svelte.d.ts +0 -0
  92. /package/dist/form-fields/{sub → fields}/contact-selector-field.svelte.d.ts +0 -0
  93. /package/dist/form-fields/{sub → fields}/currency-field.svelte.d.ts +0 -0
  94. /package/dist/form-fields/{sub → fields}/data-indication-field.svelte.d.ts +0 -0
  95. /package/dist/form-fields/{sub → fields}/date-field.svelte.d.ts +0 -0
  96. /package/dist/form-fields/{sub → fields}/date-time-field.svelte.d.ts +0 -0
  97. /package/dist/form-fields/{sub → fields}/email-field.svelte.d.ts +0 -0
  98. /package/dist/form-fields/{sub → fields}/field-builder-field.svelte.d.ts +0 -0
  99. /package/dist/form-fields/{sub → fields}/grid-field.svelte.d.ts +0 -0
  100. /package/dist/form-fields/{sub → fields}/heading-field.svelte.d.ts +0 -0
  101. /package/dist/form-fields/{sub → fields}/hidden-field.svelte +0 -0
  102. /package/dist/form-fields/{sub → fields}/hidden-field.svelte.d.ts +0 -0
  103. /package/dist/form-fields/{sub → fields}/hidden-location-field.svelte +0 -0
  104. /package/dist/form-fields/{sub → fields}/hidden-location-field.svelte.d.ts +0 -0
  105. /package/dist/form-fields/{sub → fields}/html-field.svelte.d.ts +0 -0
  106. /package/dist/form-fields/{sub → fields}/jsoneditor-field.svelte +0 -0
  107. /package/dist/form-fields/{sub → fields}/jsoneditor-field.svelte.d.ts +0 -0
  108. /package/dist/form-fields/{sub → fields}/map-field.svelte.d.ts +0 -0
  109. /package/dist/form-fields/{sub → fields}/multi-checkbox-field.svelte.d.ts +0 -0
  110. /package/dist/form-fields/{sub → fields}/multistep-field.svelte.d.ts +0 -0
  111. /package/dist/form-fields/{sub → fields}/note-field.svelte.d.ts +0 -0
  112. /package/dist/form-fields/{sub → fields}/number-field.svelte.d.ts +0 -0
  113. /package/dist/form-fields/{sub → fields}/object-builder-field.svelte.d.ts +0 -0
  114. /package/dist/form-fields/{sub → fields}/qr-code-scanner-field.svelte.d.ts +0 -0
  115. /package/dist/form-fields/{sub → fields}/screenrecorder-field.svelte.d.ts +0 -0
  116. /package/dist/form-fields/{sub → fields}/screenshot-field.svelte.d.ts +0 -0
  117. /package/dist/form-fields/{sub → fields}/scroll-and-read-display-field.svelte.d.ts +0 -0
  118. /package/dist/form-fields/{sub → fields}/section-field.svelte.d.ts +0 -0
  119. /package/dist/form-fields/{sub → fields}/select-field.svelte.d.ts +0 -0
  120. /package/dist/form-fields/{sub → fields}/selectresource-field.svelte +0 -0
  121. /package/dist/form-fields/{sub → fields}/selectresource-field.svelte.d.ts +0 -0
  122. /package/dist/form-fields/{sub → fields}/signature-field.svelte.d.ts +0 -0
  123. /package/dist/form-fields/{sub → fields}/slider-field.svelte.d.ts +0 -0
  124. /package/dist/form-fields/{sub → fields}/smart-text-field.svelte.d.ts +0 -0
  125. /package/dist/form-fields/{sub → fields}/text-field.svelte.d.ts +0 -0
  126. /package/dist/form-fields/{sub → fields}/voicenote-field.svelte.d.ts +0 -0
@@ -1,159 +0,0 @@
1
- <script context="module">import {
2
- } from "../interfaces";
3
- export const file_field_param_spec = {
4
- spec: {
5
- fields: {
6
- max_files: {
7
- fieldtype: "number",
8
- __order: 0
9
- },
10
- file_creation_options: file_creation_options_field_spec
11
- }
12
- }
13
- };
14
- </script>
15
-
16
- <script>import { Button } from "@stubber/ui/button";
17
- import { isEmpty, isEqual, isUndefined } from "lodash-es";
18
- import Dropzone from "svelte-file-dropzone";
19
- import FieldLabel from "../FieldLabel.svelte";
20
- import FieldMessage from "../FieldMessage.svelte";
21
- import { append_attachment, remove_attachment, uploadFiles } from "../fileserver";
22
- import { file_creation_options_field_spec } from "../file_creation_options";
23
- export let fieldStore;
24
- $: validation_result = $fieldStore.validation_result;
25
- $: validation_type = validation_result?.type;
26
- async function handle_files_select(e) {
27
- const { acceptedFiles, fileRejections } = e.detail;
28
- if (limit_remaining < acceptedFiles.length) {
29
- alert("You have reached the maximum number of files allowed");
30
- return;
31
- }
32
- selected_files = [
33
- ...selected_files,
34
- ...acceptedFiles.map((f) => ({
35
- filename: f.name,
36
- f_id: Math.random().toString(36).substring(7)
37
- }))
38
- ];
39
- const upload_res = await uploadFiles(
40
- acceptedFiles,
41
- $fieldStore.formDependencies,
42
- file_creation_options
43
- );
44
- const { uploaded_files: newly_uploaded, failed_files: newly_failed } = upload_res || {
45
- uploaded_files: [],
46
- failed_files: []
47
- };
48
- const newly_uploaded_with_f_id = newly_uploaded.map((f) => ({
49
- filename: f.filename,
50
- fileuuid: f.fileuuid,
51
- f_id: Math.random().toString(36).substring(7),
52
- originalname: f.originalname,
53
- contentType: f.contentType
54
- }));
55
- for (const f of newly_uploaded) {
56
- append_attachment(f, $fieldStore.attachmentsStore);
57
- }
58
- uploaded_files = [...uploaded_files, ...newly_uploaded_with_f_id];
59
- failed_files = [
60
- ...failed_files,
61
- ...newly_failed.map((f) => ({
62
- filename: f.name,
63
- f_id: Math.random().toString(36).substring(7)
64
- }))
65
- ];
66
- selected_files = [];
67
- }
68
- let uploaded_files = Array.isArray($fieldStore.value) ? $fieldStore.value : [];
69
- let failed_files = [];
70
- let selected_files = [];
71
- $: update_fieldStore(uploaded_files);
72
- function update_fieldStore(uploaded_files2) {
73
- if (isEmpty(uploaded_files2) && isUndefined($fieldStore.value)) return;
74
- $fieldStore.value = uploaded_files2;
75
- }
76
- $: update_uploaded_files($fieldStore.value);
77
- function update_uploaded_files(value) {
78
- if (isEmpty(value)) {
79
- uploaded_files = [];
80
- } else if (Array.isArray(value) && !isEqual(value, uploaded_files)) {
81
- uploaded_files = value;
82
- }
83
- }
84
- $: all_files = [
85
- ...uploaded_files.map((f) => ({ ...f, is_uploaded: true, is_failed: false })),
86
- ...failed_files.map((f) => ({ ...f, is_failed: true, is_uploaded: false })),
87
- ...selected_files.map((f) => ({ ...f, is_uploaded: false, is_failed: false }))
88
- ];
89
- let max_files = isNaN(Number($fieldStore.params?.max_files)) ? Infinity : Number($fieldStore.params?.max_files);
90
- $: limit_remaining = max_files - selected_files.length - uploaded_files.length;
91
- let file_creation_options = $fieldStore.params?.file_creation_options;
92
- function remove_file(item) {
93
- uploaded_files = uploaded_files?.filter((f) => f.f_id !== item.f_id);
94
- failed_files = failed_files?.filter((f) => f.f_id !== item.f_id);
95
- selected_files = selected_files?.filter((f) => f.f_id !== item.f_id);
96
- if ("fileuuid" in item) {
97
- remove_attachment(item.fileuuid, $fieldStore.attachmentsStore);
98
- }
99
- }
100
- </script>
101
-
102
- <FieldLabel {fieldStore} />
103
- <div class="flex w-full flex-col {validation_type == 'error' ? 'border-b border-warning-500' : ''}">
104
- <Dropzone on:drop={handle_files_select} disabled={limit_remaining <= 0}>
105
- <div class="flex h-full flex-col justify-center rounded-sm text-center">
106
- <div>
107
- <p class=" text-surface-800">Drop files to upload</p>
108
- <p class=" text-surface-800">
109
- Or click <span
110
- class="cursor-pointer text-primary-500 hover:text-primary-400 hover:underline"
111
- >here</span
112
- >
113
- to browse
114
- </p>
115
- {#if limit_remaining <= 0}
116
- <p class="text-field text-sm italic text-danger-600">
117
- You have reached the maximum number of files allowed
118
- </p>
119
- {/if}
120
- </div>
121
- </div>
122
- </Dropzone>
123
- <div class="mt-2 flex w-full flex-col gap-2">
124
- {#each all_files as item}
125
- <div class="flex w-full flex-row items-center gap-2">
126
- {#if item.is_uploaded}
127
- <div class="flex h-6 w-6 items-center justify-center text-success-500">
128
- <i class="fa fa-check" />
129
- </div>
130
- {:else if item.is_failed}
131
- <div class="flex h-6 w-6 items-center justify-center text-danger-400">
132
- <i class="fa-regular fa-triangle-exclamation" />
133
- </div>
134
- {:else}
135
- <div class="flex h-6 w-6 items-center justify-center text-surface-500">
136
- <i class="fa fa-pulse fa-spinner" />
137
- </div>
138
- {/if}
139
- <div class="flex-1 truncate rounded-sm border border-surface-200 py-1 pl-2">
140
- <p class="text-surface-800">
141
- {item?.filename}
142
- </p>
143
- </div>
144
- <Button
145
- type="button"
146
- variant="destructive"
147
- size="icon"
148
- class="h-8 w-8 shrink-0"
149
- on:click={() => {
150
- remove_file(item);
151
- }}
152
- >
153
- <i class="fa-solid fa-x text-xs" />
154
- </Button>
155
- </div>
156
- {/each}
157
- </div>
158
- </div>
159
- <FieldMessage {fieldStore} />
@@ -1,69 +0,0 @@
1
- <script context="module">export const grid_field_param_spec = {
2
- spec: {
3
- fields: {
4
- columnDefs: {
5
- fieldtype: "arraybuilder",
6
- params: {
7
- new_entry_field: {
8
- fieldtype: "jsoneditor"
9
- }
10
- },
11
- help: "See https://www.ag-grid.com/javascript-data-grid/column-definitions/"
12
- }
13
- }
14
- }
15
- };
16
- </script>
17
-
18
- <script>import { onMount } from "svelte";
19
- import FieldLabel from "../FieldLabel.svelte";
20
- import FieldMessage from "../FieldMessage.svelte";
21
- export let fieldStore;
22
- let gridDiv;
23
- let gridApi;
24
- const gridOptions = {
25
- autoSizeStrategy: {
26
- type: "fitGridWidth",
27
- defaultMinWidth: 100
28
- },
29
- defaultColDef: {
30
- suppressMovable: true
31
- },
32
- onGridReady: (params) => {
33
- gridApi = params.api;
34
- },
35
- onCellValueChanged: () => {
36
- let rowData = [];
37
- gridApi.forEachNode((node) => rowData.push(node.data));
38
- $fieldStore.value = rowData;
39
- },
40
- // Row Data: The data to be displayed.
41
- rowData: [],
42
- // Column Definitions: Defines & controls grid columns.
43
- columnDefs: []
44
- };
45
- async function initializeGrid(cancelled) {
46
- const [{ createGrid }] = await Promise.all([
47
- import("ag-grid-community"),
48
- import("ag-grid-community/styles/ag-grid.css"),
49
- import("ag-grid-community/styles/ag-theme-material.css")
50
- ]);
51
- if (cancelled()) return;
52
- let columnDefs = $fieldStore.params?.columnDefs;
53
- if (columnDefs) gridOptions.columnDefs = columnDefs;
54
- let rowData = $fieldStore.value;
55
- if (Array.isArray(rowData)) gridOptions.rowData = rowData;
56
- createGrid(gridDiv, gridOptions);
57
- }
58
- onMount(() => {
59
- let cancelled = false;
60
- void initializeGrid(() => cancelled);
61
- return () => {
62
- cancelled = true;
63
- };
64
- });
65
- </script>
66
-
67
- <FieldLabel {fieldStore} />
68
- <div bind:this={gridDiv} class="ag-theme-material h-96 w-full" />
69
- <FieldMessage {fieldStore} />
@@ -1,70 +0,0 @@
1
- <script context="module">import { get } from "svelte/store";
2
- import {} from "../interfaces";
3
- </script>
4
-
5
- <script>import { Button } from "@stubber/ui/button";
6
- import FieldLabel from "../FieldLabel.svelte";
7
- import FieldMessage from "../FieldMessage.svelte";
8
- import FormField from "../form-field.svelte";
9
- export let fieldStore;
10
- $: fields = $fieldStore.sub_fields || [];
11
- let allChildrenConditionsChecked = true;
12
- let current_page_index = 0;
13
- </script>
14
-
15
- <FieldLabel {fieldStore} />
16
-
17
- {#if fields?.length}
18
- <div class={!allChildrenConditionsChecked ? "invisible absolute" : ""}>
19
- <div class="border border-surface-200">
20
- <div class="p-2 py-3 overflow-x-auto whitespace-nowrap">
21
- <div class="flex items-center">
22
- {#each fields as p, i}
23
- <button
24
- type="button"
25
- on:click={() => (current_page_index = i)}
26
- class="flex items-center mr-4 {current_page_index === i
27
- ? 'text-surface-900'
28
- : 'text-surface-500'}"
29
- >
30
- <span
31
- class="mr-1 flex items-center justify-center w-6 h-6 rounded-full {current_page_index ===
32
- i
33
- ? 'bg-primary-500 text-surface-0'
34
- : 'bg-surface-100 text-surface-700'}"
35
- >
36
- {i + 1}
37
- </span>
38
- </button>
39
- {/each}
40
- </div>
41
- </div>
42
- {#each $fieldStore.sub_fields || [] as sub_field, index (get(sub_field).id)}
43
- <div
44
- class="p-6 border-y border-surface-200 {current_page_index !== index
45
- ? 'invisible absolute'
46
- : ''}"
47
- >
48
- <FormField fieldStore={sub_field} />
49
- </div>
50
- {/each}
51
- <div class="flex items-center justify-between text-sm p-2">
52
- {#if current_page_index > 0}
53
- <Button variant="outline" on:click={() => (current_page_index = current_page_index - 1)}>
54
- Back
55
- </Button>
56
- {/if}
57
- {#if current_page_index < fields.length - 1}
58
- <Button
59
- class="ml-auto"
60
- variant="outline"
61
- on:click={() => (current_page_index = current_page_index + 1)}
62
- >
63
- Next
64
- </Button>
65
- {/if}
66
- </div>
67
- </div>
68
- <FieldMessage {fieldStore} />
69
- </div>
70
- {/if}
@@ -1,18 +0,0 @@
1
- <script context="module">import {} from "../interfaces";
2
- </script>
3
-
4
- <script>import { Textarea } from "@stubber/ui/textarea";
5
- import FieldLabel from "../FieldLabel.svelte";
6
- import FieldMessage from "../FieldMessage.svelte";
7
- export let fieldStore;
8
- </script>
9
-
10
- <FieldLabel {fieldStore} />
11
- <Textarea
12
- id={$fieldStore.id}
13
- bind:value={$fieldStore.value}
14
- placeholder={$fieldStore.label}
15
- aria-invalid={$fieldStore.validation_result?.type == "error" ? true : undefined}
16
- aria-describedby="message-{$fieldStore.id}"
17
- />
18
- <FieldMessage {fieldStore} />
@@ -1,134 +0,0 @@
1
- <script context="module">import {} from "svelte/store";
2
- import {} from "../interfaces";
3
- export const object_builder_field_param_spec = {
4
- spec: {
5
- fields: {
6
- value_field_spec: {
7
- fieldtype: "fieldbuilder",
8
- help: "Field specification for the object values",
9
- params: {}
10
- }
11
- }
12
- }
13
- };
14
- </script>
15
-
16
- <script>import * as Collapsible from "@stubber/ui/collapsible";
17
- import { Button } from "@stubber/ui/button";
18
- import { Input } from "@stubber/ui/input";
19
- import { Label } from "@stubber/ui/label";
20
- import { cloneDeep } from "lodash-es";
21
- import FieldExprToggle from "../FieldExprToggle.svelte";
22
- import FieldMessage from "../FieldMessage.svelte";
23
- import FormField from "../form-field.svelte";
24
- import { build_field } from "../utils";
25
- export let fieldStore;
26
- let key_field_spec = $fieldStore.params?.key_field_spec;
27
- let value_field_spec = $fieldStore.params?.value_field_spec;
28
- const update_field_value = (new_value_inner_value) => {
29
- console.log("updated value", new_value_inner_value);
30
- const new_value_object = {};
31
- new_value_inner_value.forEach(({ key, value }) => {
32
- new_value_object[key] = value;
33
- });
34
- };
35
- const handle_key_input = (old_key, e) => {
36
- const target = e.target;
37
- const new_key = make_key_unique(target.value);
38
- if (new_key === old_key) return;
39
- const prev_value = $fieldStore.value || {};
40
- const new_value = {};
41
- for (const [key, value] of Object.entries(prev_value)) {
42
- if (key === old_key) {
43
- new_value[new_key] = value;
44
- } else {
45
- new_value[key] = value;
46
- }
47
- }
48
- $fieldStore.value = new_value;
49
- };
50
- const add_value = () => {
51
- const unique_key = make_key_unique("");
52
- const field_value = cloneDeep($fieldStore.value || {});
53
- field_value[unique_key] = null;
54
- $fieldStore.value = field_value;
55
- };
56
- const remove_value = (key) => {
57
- const field_value = cloneDeep($fieldStore.value || {});
58
- delete field_value[key];
59
- $fieldStore.value = field_value;
60
- };
61
- const make_key_unique = (key) => {
62
- let unique_key = key;
63
- let counter = 1;
64
- const keys = Object.keys($fieldStore.value || {});
65
- while (keys.includes(unique_key)) {
66
- unique_key = `${key}_${counter}`;
67
- counter++;
68
- }
69
- return unique_key;
70
- };
71
- let open = true;
72
- </script>
73
-
74
- <Collapsible.Root bind:open class="w-full">
75
- <Collapsible.Trigger asChild let:builder>
76
- <Button builders={[builder]} variant="ghost" class="w-full justify-between px-0">
77
- <Label>{$fieldStore.label}</Label>
78
- <FieldMessage {fieldStore} />
79
-
80
- <div class="flex items-center">
81
- {#if open}
82
- <i class="fa fa-caret-down pr-1" />
83
- {:else}
84
- <i class="fa fa-caret-right pr-1" />
85
- {/if}
86
- <FieldExprToggle {fieldStore} />
87
- </div>
88
- </Button>
89
- </Collapsible.Trigger>
90
- <Collapsible.Content class="flex flex-col gap-y-1 pl-2">
91
- {#each Object.keys($fieldStore.value || {}) as key}
92
- <Collapsible.Root open={true}>
93
- <div class="flex flex-row items-center gap-2">
94
- <Collapsible.Trigger let:builder class="">
95
- {#if builder["data-state"] === "open"}
96
- <i class="fa fa-chevron-down" />
97
- {:else}
98
- <i class="fa fa-chevron-right w-4" />
99
- {/if}
100
- </Collapsible.Trigger>
101
- <div class="flex w-full items-center gap-2">
102
- <Input
103
- class="w-full"
104
- placeholder="Key"
105
- value={key}
106
- on:input={(e) => handle_key_input(key, e)}
107
- />
108
- <Button variant="destructive" class="h-6 w-6 p-2" on:click={() => remove_value(key)}>
109
- <i class="fa fa-trash" />
110
- </Button>
111
- </div>
112
- </div>
113
- <Collapsible.Content class="mt-2 pl-6">
114
- {@const built_value_field = build_field(
115
- $fieldStore.formStore,
116
- $fieldStore.attachmentsStore,
117
- $fieldStore.formDependencies,
118
- key,
119
- value_field_spec || { fieldtype: "text", title: "Value", hide_label: true },
120
- $fieldStore.data_path
121
- )}
122
- <FormField fieldStore={built_value_field} />
123
- </Collapsible.Content>
124
- </Collapsible.Root>
125
- <!-- <Separator class="my-2" /> -->
126
- {/each}
127
-
128
- <div class="flex items-center justify-between">
129
- <Button size="icon" variant="outline" on:click={add_value}>
130
- <i class="fa fa-plus" />
131
- </Button>
132
- </div>
133
- </Collapsible.Content>
134
- </Collapsible.Root>
@@ -1,84 +0,0 @@
1
- <script context="module">import {} from "../interfaces";
2
- </script>
3
-
4
- <script>import { Button } from "@stubber/ui/button";
5
- import * as Dialog from "@stubber/ui/dialog";
6
- import FieldLabel from "../FieldLabel.svelte";
7
- import FieldMessage from "../FieldMessage.svelte";
8
- export let fieldStore;
9
- let qr_code_lib;
10
- let is_cameras_available = false;
11
- let scan_success = false;
12
- let scanned_text = "";
13
- const open_scanner_modal = (is_open) => {
14
- if (is_open) {
15
- setup_scanner();
16
- } else {
17
- qr_code_lib?.stop();
18
- }
19
- };
20
- const setup_scanner = async () => {
21
- const { Html5Qrcode } = await import("html5-qrcode");
22
- let cameras = await Html5Qrcode.getCameras();
23
- if (!cameras) {
24
- is_cameras_available = false;
25
- return;
26
- }
27
- is_cameras_available = true;
28
- let cameraId = cameras[0].id;
29
- qr_code_lib = new Html5Qrcode("reader");
30
- qr_code_lib.start(cameraId, { fps: 2 }, on_scan_success, on_scan_failure);
31
- };
32
- function on_scan_success(decodedText, decodedResult) {
33
- scanned_text = decodedText;
34
- scan_success = true;
35
- }
36
- function on_scan_failure(errorString) {
37
- }
38
- let open = false;
39
- function confirm_scan() {
40
- $fieldStore.value = scanned_text;
41
- open = false;
42
- }
43
- </script>
44
-
45
- <FieldLabel {fieldStore} />
46
- <Dialog.Root bind:open onOpenChange={open_scanner_modal}>
47
- <Dialog.Trigger asChild let:builder>
48
- <Button builders={[builder]} class="flex">
49
- <i class="fa-solid fa-qrcode" />
50
- Scan Code
51
- </Button>
52
- </Dialog.Trigger>
53
- <Dialog.Content>
54
- <Dialog.Header>
55
- <Dialog.Title>Scan Code</Dialog.Title>
56
- <div class="flex w-full flex-col gap-2">
57
- <div id="reader" class="flex w-[250px] flex-col items-center sm:w-[310px]" />
58
- {#if is_cameras_available}
59
- {#if scan_success}
60
- <div class="flex items-center space-x-2">
61
- <i class="fas fa-circle fa-2xs text-success-400" />
62
- <p class="text-label text-surface-800">{scanned_text}</p>
63
- </div>
64
- {:else}
65
- <div class="flex items-center space-x-2">
66
- <i class="fas fa-circle fa-2xs text-surface-200" />
67
- <p class="text-label text-surface-800">Searching for code ...</p>
68
- </div>
69
- {/if}
70
- <div class="flex">
71
- <div class="ml-auto flex">
72
- <Button disabled={!scan_success} on:click={confirm_scan}>Confirm</Button>
73
- </div>
74
- </div>
75
- {:else}
76
- <div class="flex aspect-square w-[250px] items-center justify-center sm:w-[310px]">
77
- <p class="text-label text-surface-800">No camera found</p>
78
- </div>
79
- {/if}
80
- </div>
81
- </Dialog.Header>
82
- </Dialog.Content>
83
- </Dialog.Root>
84
- <FieldMessage {fieldStore} />
@@ -1,69 +0,0 @@
1
- <script context="module">import { get } from "svelte/store";
2
- import {} from "../interfaces";
3
- export const radio_field_param_spec = {
4
- spec: {
5
- fields: {
6
- options: {
7
- fieldtype: "arraybuilder",
8
- params: {
9
- new_entry_field: {
10
- fieldtype: "section",
11
- fields: {
12
- label: {
13
- fieldtype: "text"
14
- },
15
- value: {
16
- fieldtype: "jsoneditor"
17
- }
18
- }
19
- }
20
- }
21
- }
22
- }
23
- }
24
- };
25
- </script>
26
-
27
- <script>import { Label } from "@stubber/ui/label";
28
- import * as RadioGroup from "@stubber/ui/radio-group";
29
- import { isEqual } from "lodash-es";
30
- import FieldLabel from "../FieldLabel.svelte";
31
- import FieldMessage from "../FieldMessage.svelte";
32
- import { set_value_details } from "../utils";
33
- export let fieldStore;
34
- let options = $fieldStore.params?.options || [];
35
- let mapped_options = options.map((option, index) => {
36
- const key = `${option.label}${index}`;
37
- return {
38
- label: option.label || index,
39
- value: option.value || option.label || index,
40
- key
41
- };
42
- });
43
- $: selected_option = mapped_options.find((o) => isEqual(o.value, $fieldStore.value));
44
- $: update_value_details(selected_option);
45
- const update_value_details = (newly_set_option) => {
46
- set_value_details($fieldStore, "label", newly_set_option?.label);
47
- };
48
- const handle_radio_change = (new_key) => {
49
- const selected_option2 = mapped_options.find((o) => o.key === new_key);
50
- if (selected_option2) {
51
- $fieldStore.value = selected_option2.value;
52
- }
53
- };
54
- </script>
55
-
56
- <FieldLabel {fieldStore} />
57
- <RadioGroup.Root
58
- value={selected_option?.key}
59
- onValueChange={handle_radio_change}
60
- class="border rounded-md px-2 py-1"
61
- >
62
- {#each mapped_options as option}
63
- <div class="flex items-center space-x-2">
64
- <RadioGroup.Item value={option.key} id={option.key} />
65
- <Label for={option.key}>{option.label}</Label>
66
- </div>
67
- {/each}
68
- </RadioGroup.Root>
69
- <FieldMessage {fieldStore} />