@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
@@ -30,12 +30,13 @@ export const map_field_param_spec = {
30
30
  </script>
31
31
 
32
32
  <script>import { controls, Geocoder, Map, Marker } from "@beyonk/svelte-mapbox";
33
+ import { getContext } from "svelte";
33
34
  import FieldLabel from "../FieldLabel.svelte";
34
35
  import { mapValues, omit } from "lodash-es";
35
- import { Input } from "@stubber/ui/input";
36
- import { Label } from "@stubber/ui/label";
36
+ import { STYLES_CONTEXT, classNames } from "../styles";
37
37
  const { GeolocateControl } = controls;
38
38
  export let fieldStore;
39
+ const styles = getContext(STYLES_CONTEXT);
39
40
  const initial_value = $fieldStore.value;
40
41
  let params = $fieldStore.params;
41
42
  let reverse_geocode_enabled = params?.address_mode && params?.address_mode !== "none";
@@ -133,7 +134,7 @@ function handle_geolocate(o) {
133
134
  }
134
135
  function handle_address_change(e) {
135
136
  const new_address = e?.target?.value || "";
136
- if (new_address && $fieldStore.value.address.full_address !== new_address) {
137
+ if (new_address && $fieldStore.value?.address?.full_address !== new_address) {
137
138
  $fieldStore.value = {
138
139
  ...$fieldStore.value,
139
140
  address: {
@@ -145,93 +146,135 @@ function handle_address_change(e) {
145
146
  }
146
147
  </script>
147
148
 
148
- <FieldLabel {fieldStore} />
149
- {#if mapboxAccessToken}
150
- <div class="flex w-full flex-col">
151
- <div>
149
+ <div class="map-field">
150
+ <FieldLabel {fieldStore} />
151
+ {#if mapboxAccessToken}
152
+ <div class="map-actions">
152
153
  <button
153
154
  type="button"
154
155
  on:click={resetValues}
155
- class="text-sm text-surface-300 hover:text-surface-500 hover:underline"
156
+ class={classNames("map-reset", $styles.button)}
157
+ data-variant="destructive">Reset</button
156
158
  >
157
- <i class="fa-regular fa-undo" /> Reset
158
- </button>
159
159
  </div>
160
- <div class="relative mt-2 rounded-md">
161
- <div class="h-72 w-full">
162
- <Map
163
- bind:center
164
- zoom={14}
165
- accessToken={mapboxAccessToken}
166
- style={mapboxStylesheetUrl}
167
- bind:this={mapComponent}
168
- on:click={handle_map_click}
169
- >
170
- <div class="absolute left-2 top-2">
171
- <Geocoder
172
- on:result={handle_geocoder_result}
173
- accessToken={mapboxAccessToken}
174
- {geocoder}
175
- />
176
- </div>
177
- {#if !hide_geolocate_button}
178
- <GeolocateControl position="top-right" on:geolocate={handle_geolocate} />
179
- {/if}
180
- {#if browserLocation}
181
- <Marker
182
- lat={browserLocation.lat}
183
- lng={browserLocation.lng}
184
- markerOptions={{ anchor: "center" }}
185
- >
186
- <div class="relative flex flex-col items-center">
187
- <span class="fa-stack fa-2x">
188
- <i
189
- class="fa-solid fa-circle fa-stack-2x text-[1.3em] leading-[inherit] text-white"
190
- />
191
- <i class="fa-solid fa-user fa-stack-1x text-blue-600" />
192
- </span>
160
+ <div
161
+ class="map-viewport"
162
+ id={params?.address_mode === "editable" ? undefined : $fieldStore.id}
163
+ aria-invalid={$fieldStore.validation_result?.type === "error" ? true : undefined}
164
+ aria-describedby="message-{$fieldStore.id}"
165
+ >
166
+ <Map
167
+ bind:center
168
+ zoom={14}
169
+ accessToken={mapboxAccessToken}
170
+ style={mapboxStylesheetUrl}
171
+ bind:this={mapComponent}
172
+ on:click={handle_map_click}
173
+ >
174
+ <div class="map-search">
175
+ <Geocoder on:result={handle_geocoder_result} accessToken={mapboxAccessToken} {geocoder} />
176
+ </div>
177
+ {#if !hide_geolocate_button}
178
+ <GeolocateControl position="top-right" on:geolocate={handle_geolocate} />
179
+ {/if}
180
+ {#if browserLocation}
181
+ <Marker
182
+ lat={browserLocation.lat}
183
+ lng={browserLocation.lng}
184
+ markerOptions={{ anchor: "center" }}
185
+ >
186
+ <span class="map-browser-marker" aria-hidden="true">
187
+ <svg class="map-browser-marker-icon" viewBox="0 0 24 24">
188
+ <circle cx="12" cy="12" r="10" fill="currentColor" />
189
+ <circle cx="12" cy="9" r="3" fill="white" />
190
+ <path d="M6.5 18c.8-3 2.6-4.5 5.5-4.5s4.7 1.5 5.5 4.5" fill="white" />
191
+ </svg>
192
+ </span>
193
+ </Marker>
194
+ {/if}
195
+ {#if $fieldStore.value?.lat && $fieldStore.value?.lng}
196
+ <Marker
197
+ lat={$fieldStore.value.lat}
198
+ lng={$fieldStore.value.lng}
199
+ popup={false}
200
+ markerOptions={{ anchor: "bottom" }}
201
+ >
202
+ <div class="map-location-marker">
203
+ <div class="map-coordinates">
204
+ <div>lat: {$fieldStore.value.lat?.toString()?.substring(0, 7)}</div>
205
+ <div>lng: {$fieldStore.value.lng?.toString()?.substring(0, 7)}</div>
193
206
  </div>
194
- </Marker>
195
- {/if}
196
- {#if $fieldStore.value?.lat && $fieldStore.value?.lng}
197
- <Marker
198
- lat={$fieldStore.value.lat}
199
- lng={$fieldStore.value.lng}
200
- popup={false}
201
- markerOptions={{ anchor: "bottom" }}
202
- >
203
- <div class="relative flex flex-col items-center">
204
- <div
205
- class="rounded-xl bg-white px-2 py-1 text-sm font-medium text-slate-800 shadow-lg ring-1 ring-black/20"
206
- >
207
- <div>lat: {$fieldStore.value.lat?.toString()?.substring(0, 7)}</div>
208
- <div>lng: {$fieldStore.value.lng?.toString()?.substring(0, 7)}</div>
209
- </div>
210
-
211
- <span class="fa-stack fa-2x h-[1.5em]">
212
- <i
213
- class="fa-solid fa-location-pin fa-stack-2x text-[1.2em] leading-[inherit] text-white"
207
+ <span aria-hidden="true">
208
+ <svg class="map-location-marker-icon" viewBox="0 0 24 32">
209
+ <path
210
+ d="M12 31s10-10.2 10-19A10 10 0 0 0 2 12c0 8.8 10 19 10 19Z"
211
+ fill="currentColor"
214
212
  />
215
- <i class="fa-solid fa-location-dot fa-stack-1x text-green-600" />
216
- </span>
217
- </div>
218
- </Marker>
219
- {/if}
220
- </Map>
221
- </div>
213
+ <circle cx="12" cy="12" r="4" fill="white" />
214
+ </svg>
215
+ </span>
216
+ </div>
217
+ </Marker>
218
+ {/if}
219
+ </Map>
222
220
  </div>
223
221
  {#if params?.address_mode === "editable"}
224
- <Input
222
+ <input
223
+ id={$fieldStore.id}
225
224
  type="text"
226
- class="mt-1"
225
+ class={classNames("map-address-input", $styles.input)}
227
226
  value={$fieldStore.value?.address?.full_address || ".."}
228
227
  on:change={handle_address_change}
228
+ aria-invalid={$fieldStore.validation_result?.type === "error" ? true : undefined}
229
+ aria-describedby="message-{$fieldStore.id}"
229
230
  />
230
231
  {:else if params?.address_mode === "readonly"}
231
- <Label class="mt-1 block text-sm font-medium text-surface-700"
232
- >{$fieldStore.value?.address?.full_address || ".."}</Label
233
- >
232
+ <p class="map-address">{$fieldStore.value?.address?.full_address || ".."}</p>
234
233
  {/if}
235
- </div>
236
- {/if}
237
- <FieldMessage {fieldStore} />
234
+ {/if}
235
+ <FieldMessage {fieldStore} />
236
+ </div>
237
+
238
+ <style>
239
+ .map-field,
240
+ .map-viewport,
241
+ :where(.map-address-input) {
242
+ box-sizing: border-box;
243
+ width: 100%;
244
+ min-width: 0;
245
+ }
246
+
247
+ .map-viewport {
248
+ position: relative;
249
+ height: 24rem;
250
+ overflow: hidden;
251
+ }
252
+
253
+ .map-search {
254
+ position: absolute;
255
+ z-index: 1;
256
+ inset-block-start: 0;
257
+ inset-inline-start: 0;
258
+ max-width: 100%;
259
+ }
260
+
261
+ .map-browser-marker-icon,
262
+ .map-location-marker-icon {
263
+ display: block;
264
+ width: 1.5rem;
265
+ }
266
+
267
+ .map-browser-marker-icon {
268
+ height: 1.5rem;
269
+ }
270
+
271
+ .map-location-marker {
272
+ display: flex;
273
+ flex-direction: column;
274
+ align-items: center;
275
+ }
276
+
277
+ .map-location-marker-icon {
278
+ height: 2rem;
279
+ }
280
+ </style>
@@ -25,12 +25,13 @@ export const multi_checkbox_field_param_spec = {
25
25
  };
26
26
  </script>
27
27
 
28
- <script>import { Checkbox } from "@stubber/ui/checkbox";
29
- import { Label } from "@stubber/ui/label";
30
- import { cloneDeep, startCase } from "lodash-es";
28
+ <script>import { cloneDeep, startCase } from "lodash-es";
29
+ import { getContext } from "svelte";
31
30
  import FieldLabel from "../FieldLabel.svelte";
32
31
  import FieldMessage from "../FieldMessage.svelte";
32
+ import { STYLES_CONTEXT, classNames } from "../styles";
33
33
  export let fieldStore;
34
+ const styles = getContext(STYLES_CONTEXT);
34
35
  let options = $fieldStore.params?.options || {};
35
36
  if ($fieldStore.value) {
36
37
  const newValue = {};
@@ -62,22 +63,36 @@ const handle_check_change = (key, item, checked) => {
62
63
  };
63
64
  $fieldStore.value = cloneDeep({ ...$fieldStore.value });
64
65
  };
66
+ const handle_change = (key, item, event) => {
67
+ handle_check_change(key, item, event.currentTarget.checked);
68
+ };
65
69
  </script>
66
70
 
67
- <FieldLabel {fieldStore} />
68
- {#each Object.entries(options) as [key, item] (key)}
69
- {@const checked = $fieldStore.value?.[key]?.checked ?? false}
70
- <div class="flex space-x-3 relative mt-2">
71
- <Checkbox
72
- id="{$fieldStore.id}_{key}"
73
- name={key}
74
- {checked}
75
- onCheckedChange={(checked) => handle_check_change(key, item, checked)}
76
- />
77
-
78
- <Label for="{$fieldStore.id}_{key}">
79
- {item.label || startCase(key)}
80
- </Label>
81
- </div>
82
- {/each}
83
- <FieldMessage {fieldStore} />
71
+ <div class="multi-checkbox-field">
72
+ <FieldLabel {fieldStore} />
73
+ <fieldset
74
+ class="multi-checkbox-options"
75
+ class:multi-checkbox-options-invalid={$fieldStore.validation_result?.type === "error"}
76
+ aria-label={$fieldStore.label}
77
+ aria-describedby="message-{$fieldStore.id}"
78
+ >
79
+ {#each Object.entries(options) as [key, item] (key)}
80
+ {@const checked = Boolean($fieldStore.value?.[key]?.checked)}
81
+ <div class="multi-checkbox-option" class:multi-checkbox-option-checked={checked}>
82
+ <input
83
+ class={classNames("multi-checkbox-input", $styles.choice)}
84
+ id="{$fieldStore.id}_{key}"
85
+ name={key}
86
+ type="checkbox"
87
+ {checked}
88
+ aria-invalid={$fieldStore.validation_result?.type === "error" ? true : undefined}
89
+ on:change={(event) => handle_change(key, item, event)}
90
+ />
91
+ <label class="multi-checkbox-label" for="{$fieldStore.id}_{key}">
92
+ {item.label || startCase(key)}
93
+ </label>
94
+ </div>
95
+ {/each}
96
+ </fieldset>
97
+ <FieldMessage {fieldStore} />
98
+ </div>
@@ -0,0 +1,135 @@
1
+ <script context="module">import { get } from "svelte/store";
2
+ import {} from "../interfaces";
3
+ </script>
4
+
5
+ <script>import { getContext, tick } from "svelte";
6
+ import FieldLabel from "../FieldLabel.svelte";
7
+ import FieldMessage from "../FieldMessage.svelte";
8
+ import FormField from "../form-field.svelte";
9
+ import { STYLES_CONTEXT, classNames } from "../styles";
10
+ export let fieldStore;
11
+ const styles = getContext(STYLES_CONTEXT);
12
+ $: fields = $fieldStore.sub_fields || [];
13
+ let allChildrenConditionsChecked = true;
14
+ let current_page_index = 0;
15
+ let stepButtons = [];
16
+ $: if (fields.length && current_page_index >= fields.length) {
17
+ current_page_index = fields.length - 1;
18
+ }
19
+ async function focus_page(index) {
20
+ current_page_index = index;
21
+ await tick();
22
+ stepButtons[index]?.focus();
23
+ }
24
+ function handle_step_keydown(event, index) {
25
+ let nextIndex;
26
+ if (event.key === "ArrowRight") nextIndex = (index + 1) % fields.length;
27
+ if (event.key === "ArrowLeft") nextIndex = (index - 1 + fields.length) % fields.length;
28
+ if (event.key === "Home") nextIndex = 0;
29
+ if (event.key === "End") nextIndex = fields.length - 1;
30
+ if (nextIndex !== void 0) {
31
+ event.preventDefault();
32
+ void focus_page(nextIndex);
33
+ }
34
+ }
35
+ </script>
36
+
37
+ <FieldLabel {fieldStore} />
38
+
39
+ {#if fields?.length}
40
+ <div
41
+ class="multistep-field"
42
+ class:multistep-field-hidden={!allChildrenConditionsChecked}
43
+ hidden={!allChildrenConditionsChecked}
44
+ >
45
+ <div class="multistep-steps" role="tablist" aria-label={`${$fieldStore.label} steps`}>
46
+ {#each fields as page, index (get(page).id)}
47
+ <button
48
+ bind:this={stepButtons[index]}
49
+ type="button"
50
+ id="tab-{$fieldStore.id}-{index}"
51
+ class={classNames("multistep-step", $styles.button)}
52
+ class:multistep-step-current={current_page_index === index}
53
+ role="tab"
54
+ aria-selected={current_page_index === index}
55
+ aria-controls="panel-{$fieldStore.id}-{index}"
56
+ tabindex={current_page_index === index ? 0 : -1}
57
+ on:click={() => (current_page_index = index)}
58
+ on:keydown={(event) => handle_step_keydown(event, index)}
59
+ >
60
+ <span
61
+ class="multistep-marker"
62
+ class:multistep-marker-current={current_page_index === index}
63
+ aria-hidden="true"
64
+ >
65
+ {index + 1}
66
+ </span>
67
+ <span class="multistep-step-label">{get(page).label}</span>
68
+ </button>
69
+ {/each}
70
+ </div>
71
+
72
+ <div class="multistep-panels">
73
+ {#each fields as sub_field, index (get(sub_field).id)}
74
+ <div
75
+ id="panel-{$fieldStore.id}-{index}"
76
+ class="multistep-panel"
77
+ class:multistep-panel-hidden={current_page_index !== index}
78
+ role="tabpanel"
79
+ aria-labelledby="tab-{$fieldStore.id}-{index}"
80
+ hidden={current_page_index !== index}
81
+ tabindex="0"
82
+ >
83
+ <FormField fieldStore={sub_field} />
84
+ </div>
85
+ {/each}
86
+ </div>
87
+
88
+ <div class="multistep-actions">
89
+ {#if current_page_index > 0}
90
+ <button
91
+ type="button"
92
+ class={classNames("multistep-back", $styles.button)}
93
+ on:click={() => (current_page_index = current_page_index - 1)}
94
+ >
95
+ Back
96
+ </button>
97
+ {/if}
98
+ {#if current_page_index < fields.length - 1}
99
+ <button
100
+ type="button"
101
+ class={classNames("multistep-next", $styles.button)}
102
+ data-variant="primary"
103
+ on:click={() => (current_page_index = current_page_index + 1)}
104
+ >
105
+ Next
106
+ </button>
107
+ {/if}
108
+ </div>
109
+ <FieldMessage {fieldStore} />
110
+ </div>
111
+ {/if}
112
+
113
+ <style>
114
+ .multistep-field,
115
+ .multistep-panels,
116
+ .multistep-panel {
117
+ box-sizing: border-box;
118
+ width: 100%;
119
+ min-width: 0;
120
+ }
121
+
122
+ .multistep-steps {
123
+ display: flex;
124
+ width: 100%;
125
+ overflow-x: auto;
126
+ }
127
+
128
+ .multistep-step {
129
+ flex: none;
130
+ }
131
+
132
+ .multistep-actions {
133
+ display: flex;
134
+ }
135
+ </style>
@@ -0,0 +1,35 @@
1
+ <script context="module">import {} from "../interfaces";
2
+ </script>
3
+
4
+ <script>import { getContext } from "svelte";
5
+ import FieldLabel from "../FieldLabel.svelte";
6
+ import FieldMessage from "../FieldMessage.svelte";
7
+ import { STYLES_CONTEXT, classNames } from "../styles";
8
+ export let fieldStore;
9
+ const styles = getContext(STYLES_CONTEXT);
10
+ </script>
11
+
12
+ <div class="note-field">
13
+ <FieldLabel {fieldStore} />
14
+ <textarea
15
+ class={classNames("note-input", $styles?.input)}
16
+ id={$fieldStore.id}
17
+ bind:value={$fieldStore.value}
18
+ placeholder={$fieldStore.label}
19
+ aria-invalid={$fieldStore.validation_result?.type === "error" ? true : undefined}
20
+ aria-describedby={$fieldStore.validation_result ? `message-${$fieldStore.id}` : undefined}
21
+ />
22
+ <FieldMessage {fieldStore} />
23
+ </div>
24
+
25
+ <style>
26
+ .note-field,
27
+ .note-input {
28
+ box-sizing: border-box;
29
+ width: 100%;
30
+ }
31
+
32
+ .note-input {
33
+ min-height: 100px;
34
+ }
35
+ </style>
@@ -36,10 +36,12 @@
36
36
  };
37
37
  </script>
38
38
 
39
- <script>import { Input } from "@stubber/ui/input";
39
+ <script>import { getContext } from "svelte";
40
40
  import FieldLabel from "../FieldLabel.svelte";
41
41
  import FieldMessage from "../FieldMessage.svelte";
42
+ import { STYLES_CONTEXT, classNames } from "../styles";
42
43
  export let fieldStore;
44
+ const styles = getContext(STYLES_CONTEXT);
43
45
  function onInput(e) {
44
46
  const input_element = e.target;
45
47
  let { value } = input_element;
@@ -62,16 +64,29 @@ function onBlur() {
62
64
  }
63
65
  </script>
64
66
 
65
- <FieldLabel {fieldStore} />
66
- <Input
67
- id={$fieldStore.id}
68
- value={$fieldStore.value}
69
- on:input={onInput}
70
- on:blur={onBlur}
71
- aria-invalid={$fieldStore.validation_result?.type == "error" ? true : undefined}
72
- type="number"
73
- step={$fieldStore.step || 0}
74
- max={$fieldStore.max}
75
- min={$fieldStore.min}
76
- />
77
- <FieldMessage {fieldStore} />
67
+ <div class="number-field">
68
+ <FieldLabel {fieldStore} />
69
+ <input
70
+ class={classNames("number-input", $styles.input)}
71
+ id={$fieldStore.id}
72
+ value={$fieldStore.value ?? ""}
73
+ placeholder={$fieldStore.label}
74
+ on:input={onInput}
75
+ on:blur={onBlur}
76
+ aria-invalid={$fieldStore.validation_result?.type == "error" ? true : undefined}
77
+ aria-describedby="message-{$fieldStore.id}"
78
+ type="number"
79
+ step={$fieldStore.step}
80
+ max={$fieldStore.max}
81
+ min={$fieldStore.min}
82
+ />
83
+ <FieldMessage {fieldStore} />
84
+ </div>
85
+
86
+ <style>
87
+ .number-field,
88
+ .number-input {
89
+ box-sizing: border-box;
90
+ width: 100%;
91
+ }
92
+ </style>