@stubber/form-fields 1.0.10 → 1.1.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.
@@ -279,7 +279,7 @@
279
279
  flex h-7 w-full items-center justify-between rounded px-3 py-2
280
280
  text-sm focus:outline-none
281
281
  [&>span]:line-clamp-1 aria-[invalid]:border-destructive
282
- placeholder:text-black
282
+ placeholder:text-muted-foreground
283
283
  {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-transparent'}"
284
284
  bind:value={filter_text}
285
285
  autocomplete="off"
@@ -183,12 +183,13 @@
183
183
  {label}
184
184
  </Label>
185
185
  <div
186
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select ring-offset-background focus-visible:ring-ring aria-[invalid]:border-destructive flex h-7 w-full items-center justify-between rounded px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 relative {!isValid
187
- ? 'ring-danger-500'
188
- : 'ring-surface-300 focus:ring-primary-400'} "
186
+ class="w-full flex items-center gap-2 border-input bg-white bg-opacity-[15] ring-offset-background placeholder:text-muted-foreground focus-within:ring-ring h-10 rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-within:outline-none focus-within:ring-2 focus-within:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 {!isValid
187
+ ? 'focus-within:ring-danger-500'
188
+ : 'ring-surface-300'}"
189
+ style="box-shadow: inset 0px 16px 16px -16px rgba(0, 0, 0, 0.1333);"
189
190
  >
190
- <div class="pointer-events-none flex items-center pl-3">
191
- <span class="text-label text-surface-600">
191
+ <div class="pointer-events-none flex items-center pl-2">
192
+ <span class="text-sm text-surface-600">
192
193
  {getSymbolFromCurrency($internal?.currencycode)}
193
194
  </span>
194
195
  </div>
@@ -198,10 +199,10 @@
198
199
  e.preventDefault();
199
200
  }
200
201
  }}
202
+ class="w-full focus-within:outline-none"
201
203
  use:inputRegexMask={currencyRegex}
202
204
  id="input_{state_key}"
203
205
  placeholder={label}
204
- class="bg-transparent w-full focus:outline-none text-surface-900 placeholder:text-surface-400 ml-2"
205
206
  name={state_key}
206
207
  inputmode="decimal"
207
208
  bind:value={$internal.raw}
@@ -2,6 +2,7 @@
2
2
  import _ from "lodash-es";
3
3
 
4
4
  import { Label } from "@stubber/ui/label";
5
+ import { Input } from "@stubber/ui/input";
5
6
 
6
7
  export let field;
7
8
 
@@ -18,16 +19,8 @@
18
19
  <Label for="input_{state_key}" class="block {hide_label ? 'hidden' : ''}">
19
20
  {label}
20
21
  </Label>
21
- <div class="relative mt-2 rounded-md">
22
- <div
23
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select flex items-center h-7 w-full rounded px-3 py-2 text-sm focus:outline-none placeholder:text-black"
24
- >
25
- {#if value_is_string}
26
- {value}
27
- {:else}
28
- <pre>{value}</pre>
29
- {/if}
30
- </div>
22
+ <div class="relative mt-2 rounded-md bg-surface-100 p-2">
23
+ <pre class="rounded-md">{value}</pre>
31
24
  </div>
32
25
 
33
26
  {#if validationMessage}
@@ -80,9 +80,10 @@
80
80
  type="date"
81
81
  id="input_{state_key}"
82
82
  placeholder={label}
83
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select block h-7 w-full rounded px-3 py-2 text-sm focus:outline-none
84
- placeholder:text-black
85
- {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-transparent'}"
83
+ class="block w-full border-input bg-white bg-opacity-[15] ring-0 ring-offset-background focus-visible:ring-ring h-10 rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50
84
+ {!isValid ? 'ring-danger-500' : 'ring-surface-300'}
85
+ {$internal?.raw ? 'text-surface-900' : 'text-muted-foreground'}"
86
+ style="box-shadow: inset 0px 16px 16px -16px rgba(0, 0, 0, 0.1333);"
86
87
  name={state_key}
87
88
  bind:value={$internal.raw}
88
89
  />
@@ -80,9 +80,10 @@
80
80
  type="datetime-local"
81
81
  id="input_{state_key}"
82
82
  placeholder={label}
83
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select block h-7 w-full rounded px-3 py-2 text-sm focus:outline-none
84
- placeholder:text-black
85
- {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-transparent'}"
83
+ class="block w-full border-input bg-white bg-opacity-[15] ring-0 ring-offset-background focus-visible:ring-ring h-10 rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50
84
+ {!isValid ? 'ring-danger-500' : 'ring-surface-300'}
85
+ {$internal?.raw ? 'text-surface-900' : 'text-muted-foreground'}"
86
+ style="box-shadow: inset 0px 16px 16px -16px rgba(0, 0, 0, 0.1333);"
86
87
  name={state_key}
87
88
  bind:value={$internal.raw}
88
89
  />
@@ -111,9 +111,7 @@
111
111
  type="text"
112
112
  id="input_{state_key}"
113
113
  placeholder={label}
114
- class="block w-full placeholder:opacity-30 {!isValid
115
- ? 'ring-danger-500'
116
- : 'ring-surface-300 focus:ring-primary-400'} focus:outline-none placeholder:text-surface-400 focus:ring-2 focus:ring-inset"
114
+ class="block w-full {!isValid ? 'ring-danger-500' : 'ring-surface-300'}"
117
115
  name={state_key}
118
116
  bind:value={$internal.raw}
119
117
  />
@@ -80,9 +80,7 @@
80
80
  rows="3"
81
81
  id="input_{state_key}"
82
82
  placeholder={label}
83
- class="block w-full placeholder:opacity-30 {!isValid
84
- ? 'ring-danger-500'
85
- : 'ring-surface-300 '} "
83
+ class="block w-full {!isValid ? 'ring-danger-500' : 'ring-surface-300 '} "
86
84
  name={state_key}
87
85
  bind:value={$internal.raw}
88
86
  />
@@ -102,7 +102,7 @@
102
102
  type="number"
103
103
  id="input_{state_key}"
104
104
  placeholder={label}
105
- class="block w-full placeholder:opacity-30 {!isValid
105
+ class="block w-full {!isValid
106
106
  ? 'ring-danger-500'
107
107
  : 'ring-surface-300 focus:ring-primary-400'} "
108
108
  name={state_key}
@@ -7,7 +7,7 @@
7
7
  import { fade } from "svelte/transition";
8
8
  import { Html5Qrcode } from "html5-qrcode";
9
9
  import { Button } from "@stubber/ui/button";
10
-
10
+ import { Input } from "@stubber/ui/input";
11
11
  import { Label } from "@stubber/ui/label";
12
12
 
13
13
  export let field;
@@ -170,20 +170,20 @@
170
170
  <div class="relative mt-2 rounded-md">
171
171
  <div class="flex items-center space-x-3">
172
172
  {#if $internal.raw}
173
- <input
173
+ <Input
174
174
  readonly
175
175
  type="text"
176
176
  id="input_{state_key}"
177
177
  placeholder={label}
178
- class="block w-full text-field rounded-md border-0 py-2 pl-3 text-surface-900 ring-1 ring-inset {!isValid
179
- ? 'ring-danger-500'
180
- : 'ring-surface-300 focus:ring-primary-400'} focus:outline-none placeholder:text-surface-400 focus:ring-2 focus:ring-inset"
181
178
  name={state_key}
182
179
  value={$internal.raw}
183
180
  />
184
181
  {/if}
185
182
  <div class="shrink-0">
186
- <Button icon="camera" label="Scan code" on:click={openScannerModal} />
183
+ <Button on:click={openScannerModal}>
184
+ <i class="fa-solid fa-qrcode" />
185
+ Scan Code
186
+ </Button>
187
187
  </div>
188
188
  </div>
189
189
  </div>
@@ -1,29 +1,20 @@
1
1
  <script>
2
- import { syncStoreToStore } from "../../utils/syncing";
3
- import { deepEqual } from "fast-equals";
4
- import _ from "lodash-es";
5
- import { onMount, onDestroy } from "svelte";
6
- import { writable } from "svelte/store";
7
- import * as utils from "../../utils/index.js";
2
+ import { onMount, tick } from "svelte";
8
3
 
9
4
  import { Label } from "@stubber/ui/label";
10
- import { scale } from "svelte/transition";
5
+ import * as Command from "@stubber/ui/command";
6
+ import * as Popover from "@stubber/ui/popover";
7
+ import { Button } from "@stubber/ui/button";
8
+ import { isArray, isEqual } from "lodash-es";
11
9
 
12
10
  export let field;
13
11
 
14
- const internal = writable();
15
- const { clickOutside } = utils;
16
-
17
- let is_focused = false;
18
- let filter_text = "";
19
- let input;
20
-
21
12
  $: state_key = $field.state?.state_key;
22
13
  $: label = $field.spec?.title;
23
14
  $: hide_label = $field.spec?.hide_label;
24
15
  $: isValid = !$field.state?.validation || $field.state?.validation?.valid;
25
16
  $: validationMessage = $field.state?.validation?.message;
26
- $: items = _.isArray($field.spec?.params?.options)
17
+ $: items = isArray($field.spec?.params?.options)
27
18
  ? $field.spec?.params?.options?.map((o, index) => {
28
19
  let { label, value } = o || {};
29
20
  let _value = value !== undefined ? value : label;
@@ -32,222 +23,85 @@
32
23
  return { _key, _label, _value };
33
24
  })
34
25
  : [];
35
- $: filteritems = items.filter((i) => {
36
- let _filter_text = filter_text?.toLowerCase();
37
- if (!_filter_text) return true;
38
- let _label = i?._label?.toLowerCase();
39
- return _label?.includes(_filter_text);
40
- });
41
26
 
42
27
  onMount(() => {
43
- // set field values that aren't set yet
44
- let f = _.cloneDeep($field);
45
- let initial_item = items?.find((i) => deepEqual($field.data.base, i._value));
46
- let initial_data = {
47
- ...f?.data,
48
- base: initial_item?._value ?? null,
49
- };
50
- if (!f?.spec?.without_value_details) initial_data.base_label = initial_item?._label;
51
- let initial_state_internal = {
52
- ...f?.state?.internal,
53
- focused_index: -1,
54
- selected_item_key: initial_item?._key,
55
- };
56
- _.set(f, "data", initial_data);
57
- _.set(f, "state.internal", initial_state_internal);
58
- if (!deepEqual(f, $field)) $field = f;
59
-
60
- syncStoreToStore(
61
- field,
62
- internal,
63
- (a, b) => {
64
- let _clone = _.cloneDeep(a.state?.internal) || {};
65
-
66
- // get parts from data
67
- let item = items.find((i) => i._value === a?.data?.base);
68
- if (item) {
69
- filter_text = item?._label;
70
- _clone.selected_item_key = item?._key;
71
-
72
- // set field_label if changed
73
- if (!deepEqual(a?.data?.base_label, item?._label) && !a?.spec?.without_value_details) {
74
- $field.data.base_label = item?._label;
75
- }
76
-
77
- // set field state if changed
78
- if (!deepEqual(a?.state?.internal, _clone)) {
79
- $field.state.internal = _clone;
80
- }
81
- }
82
-
83
- return _clone;
84
- },
85
- (a, b) => {
86
- let _clone = _.cloneDeep(a) || {};
87
- // update the state
88
- _.set(_clone, "state.internal", _.cloneDeep(b));
89
- // update the data
90
- let item = items.find((i) => i._key === b?.selected_item_key);
91
- _.set(_clone, "data.base", item?._value);
92
- if (!a?.spec?.without_value_details) _.set(_clone, "data.base_label", item?._label);
93
- return _clone;
28
+ if ($field.data.base && !$field.spec?.without_value_details) {
29
+ // If the field has a base value, we need to find the corresponding label
30
+ const item = items.find((i) => isEqual(i._value, $field.data.base));
31
+ if (item) {
32
+ $field.data.base_label = item._label;
94
33
  }
95
- );
96
- });
97
-
98
- let teleportedNode = null;
99
- onDestroy(() => {
100
- if (teleportedNode) {
101
- teleportedNode.remove();
102
- teleportedNode = null;
103
34
  }
104
35
  });
105
36
 
106
- // used to show the dropdown panel in the body instead of inside the component
107
- // fixes an issue where the dropdown panel would be cut off by the parent container
108
- function teleport(node) {
109
- // Get the original position and width
110
- let rect = node.getBoundingClientRect();
111
- let originalWidth = node.offsetWidth;
112
- let originalHeight = node.offsetHeight;
113
-
114
- // Teleport to the body
115
- let teleportContainer = document.body;
116
- teleportContainer.appendChild(node);
117
-
118
- teleportedNode = node;
37
+ function simpleSetSelected(item_key) {
38
+ const item = items.find((i) => i._key === item_key);
39
+ if (!item) return;
119
40
 
120
- // Apply the original width and position to the teleported element
121
- node.style.width = originalWidth + "px";
122
- node.style.height = originalHeight + "px";
123
- node.style.position = "absolute";
124
- node.style.top = rect.top + window.scrollY + "px";
125
- node.style.left = rect.left + "px";
126
-
127
- // set z-index to 1000
128
- node.style.zIndex = 1000;
41
+ field.update((f) => {
42
+ f.data.base = item?._value;
43
+ if (!f.spec?.without_value_details) {
44
+ f.data.base_label = item?._label;
45
+ }
46
+ return f;
47
+ });
129
48
  }
130
49
 
131
- function setSelected(item) {
132
- filter_text = item._label;
133
- let comparison = _.cloneDeep($internal);
134
- comparison.focused_index = -1;
135
- comparison.selected_item_key = item._key;
136
-
137
- if (!deepEqual(comparison, $internal)) {
138
- $internal = _.cloneDeep(comparison);
139
- }
140
-
141
- is_focused = false;
142
- input.blur();
50
+ let open = false;
51
+
52
+ $: dropdownLabel = items.find((i) => isEqual(i._value, $field.data.base))?._label ?? "Select...";
53
+ // We want to refocus the trigger button when the user selects
54
+ // an item from the list so users can continue navigating the
55
+ // rest of the form with the keyboard.
56
+ function closeAndFocusTrigger(triggerId) {
57
+ open = false;
58
+ tick().then(() => {
59
+ document.getElementById(triggerId)?.focus();
60
+ });
143
61
  }
144
62
  </script>
145
63
 
146
- {#if $internal}
147
- <div
148
- use:clickOutside={() => {
149
- if (is_focused) {
150
- is_focused = false;
151
- filter_text = $field?.data?.base_label ?? "";
152
- }
153
- }}
154
- class="relative flex flex-col w-full text-surface-900 my-2"
155
- >
156
- <Label for="input_{state_key}" class="block py-2{hide_label ? 'hidden' : ''}">
157
- {label}
158
- </Label>
159
- <div class="relative flex rounded-md">
160
- <input
161
- on:keydown={(e) => {
162
- switch (e.key) {
163
- case "Enter":
164
- if ($internal.focused_index >= 0 && $internal.focused_index < items.length) {
165
- setSelected(filteritems[$internal.focused_index]);
166
- }
167
- e.preventDefault();
168
- break;
169
- case "ArrowDown":
170
- $internal.focused_index = ($internal.focused_index + 1) % items.length;
171
- e.preventDefault();
172
- break;
173
- case "ArrowUp":
174
- $internal.focused_index = ($internal.focused_index - 1 + items.length) % items.length;
175
- e.preventDefault();
176
- break;
177
- }
178
- }}
179
- on:focus={() => {
180
- if (!is_focused) {
181
- is_focused = true;
182
- filter_text = "";
183
- }
184
- }}
185
- bind:this={input}
186
- type="select"
187
- id="input_{state_key}"
188
- placeholder={label}
189
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select
190
- flex h-7 w-full items-center justify-between rounded px-3 py-2
191
- text-sm focus:outline-none
192
- [&>span]:line-clamp-1 aria-[invalid]:border-destructive
193
- placeholder:text-black
194
- {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-transparent'}"
195
- name={state_key}
196
- bind:value={filter_text}
197
- autocomplete="off"
198
- />
199
- <div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
200
- <i class="text-surface-300 fa-regular fa-arrows-up-down fa-fw" />
201
- </div>
202
- </div>
203
- {#if is_focused}
204
- <div use:teleport class="z-10 w-full inset-y-[70px] mt-1">
205
- <div
206
- transition:scale={{
207
- start: 0.95,
208
- opacity: 0,
209
- duration: 50,
210
- }}
211
- class="bg-popover text-popover-foreground relative min-w-[8rem]
212
- overflow-hidden rounded-md border shadow-md outline-none
213
- max-h-[200px] overflow-y-auto w-full p-1"
214
- >
215
- {#if filteritems.length > 0}
216
- <ul>
217
- {#each filteritems as item, index (item._key)}
218
- <li class="group {$internal.focused_index === index ? 'bg-primary-400' : ''} ">
219
- <button
220
- type="button"
221
- on:click|preventDefault={() => setSelected(item)}
222
- class="selectitem relative flex w-full cursor-default
223
- select-none items-center rounded-sm py-1 pl-8 pr-2
224
- text-sm outline-none hover:bg-accent
225
- hover:text-accent-foreground
226
- data-[highlighted]:bg-accent
227
- data-[highlighted]:text-accent-foreground
228
- data-[disabled]:pointer-events-none
229
- data-[disabled]:opacity-50"
230
- >
231
- {item._label}
232
- {#if item._key === $internal?.selected_item_key}
233
- <i class="absolute left-2 h-3.5 w-3.5 fa-regular fa-check" />
234
- {/if}
235
- </button>
236
- </li>
237
- {/each}
238
- </ul>
239
- {:else}
240
- <div class="flex items-center justify-center py-4">
241
- <span class="text-sm text-surface-400">
242
- {filter_text ? "No results found" : "Start typing to search..."}
243
- </span>
244
- </div>
245
- {/if}
246
- </div>
247
- </div>
248
- {/if}
249
- {#if validationMessage}
250
- <Label class={!isValid ? `text-danger-500` : `text-success-500`}>{validationMessage}</Label>
251
- {/if}
252
- </div>
253
- {/if}
64
+ <div class="flex flex-col w-full text-surface-900 my-2">
65
+ <Label for="input_{state_key}" class="block py-2 {hide_label ? 'hidden' : ''}">
66
+ {label}
67
+ </Label>
68
+ <Popover.Root bind:open let:ids>
69
+ <Popover.Trigger asChild let:builder>
70
+ <Button
71
+ builders={[builder]}
72
+ variant="outline"
73
+ role="combobox"
74
+ aria-expanded={open}
75
+ class="border-input bg-white bg-opacity-[15] ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex h-10 w-[200px] rounded-md border px-3 py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 justify-between"
76
+ style="box-shadow: inset 0px 16px 16px -16px rgba(0, 0, 0, 0.1333);"
77
+ >
78
+ {dropdownLabel}
79
+ <i class="fas fa-sort ml-2 h-4 w-4 shrink-0 opacity-50" />
80
+ </Button>
81
+ </Popover.Trigger>
82
+ <Popover.Content class="w-[200px] p-0">
83
+ <Command.Root>
84
+ <Command.Input placeholder="Search..." />
85
+ <Command.Empty>No results found.</Command.Empty>
86
+ <Command.Group>
87
+ {#each items as item}
88
+ <Command.Item
89
+ value={item._key}
90
+ onSelect={(item_key) => {
91
+ simpleSetSelected(item_key);
92
+ closeAndFocusTrigger(ids.trigger);
93
+ }}
94
+ class={$field.data.base === item._value ? "bg-primary-100" : ""}
95
+ >
96
+ {item._label}
97
+ </Command.Item>
98
+ {/each}
99
+ </Command.Group>
100
+ </Command.Root>
101
+ </Popover.Content>
102
+ </Popover.Root>
103
+
104
+ {#if validationMessage}
105
+ <Label class={!isValid ? `text-danger-500` : `text-success-500`}>{validationMessage}</Label>
106
+ {/if}
107
+ </div>
@@ -236,7 +236,7 @@
236
236
  flex h-7 w-full items-center justify-between rounded px-3 py-2
237
237
  text-sm focus:outline-none
238
238
  [&>span]:line-clamp-1 aria-[invalid]:border-destructive
239
- placeholder:text-black
239
+ placeholder:text-muted-foreground
240
240
  {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-transparent'}"
241
241
  bind:value={filter_text}
242
242
  autocomplete="off"
@@ -290,7 +290,7 @@
290
290
  .stubber-cm :global(.cm-editor.cm-focused) {
291
291
  outline: none;
292
292
  border-width: 1px;
293
- border-color: var(--ring);
293
+ border-color: hsl(var(--input) / var(--tw-border-opacity, 1));
294
294
  }
295
295
 
296
296
  .stubber-cm.stubber-valid :global(.cm-editor.cm-focused) {
@@ -318,18 +318,10 @@
318
318
  }
319
319
 
320
320
  .stubber-cm :global(.cm-editor .cm-placeholder) {
321
- color: var(--muted-foreground, rgb(165 169 173));
321
+ color: hsl(var(--muted-foreground) / var(--tw-text-opacity, 1));
322
322
  }
323
323
 
324
324
  .stubber-cm :global(.curly-braces-highlight) {
325
325
  color: rgb(9 103 210);
326
326
  }
327
-
328
- /* CSS Custom Properties */
329
- :root {
330
- --ring: rgb(98, 98, 98);
331
- --muted-foreground: rgb(165 169 173);
332
- --input: 214.3 31.8% 91.4%;
333
- --border: 214.3 31.8% 91.4%;
334
- }
335
327
  </style>
@@ -141,12 +141,10 @@
141
141
  bind:value={$internal.raw}
142
142
  type="tel"
143
143
  id="input_{state_key}"
144
- class="bg-gradient-to-b from-[#2727271F] to-[#27272719] shadow-select
145
- flex h-7 w-full items-center justify-between rounded px-3 py-2
146
- text-sm
147
- [&>span]:line-clamp-1 aria-[invalid]:border-destructive
148
- placeholder:text-black
149
- {!isValid ? 'ring-danger-500' : 'ring-surface-300 focus:ring-primary-400'}"
144
+ class="w-full pl-12 border-input bg-white bg-opacity-[15] ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring h-10 rounded-md border py-2 text-sm file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 {!isValid
145
+ ? 'ring-danger-500'
146
+ : 'ring-surface-300'}"
147
+ style="box-shadow: inset 0px 16px 16px -16px rgba(0, 0, 0, 0.1333);"
150
148
  />
151
149
  </div>
152
150
  {#if validationMessage}
@@ -93,9 +93,7 @@
93
93
  type="text"
94
94
  id="input_{state_key}"
95
95
  placeholder={label}
96
- class="block w-full placeholder:opacity-30 {!isValid
97
- ? 'ring-danger-500'
98
- : 'ring-surface-300 '} "
96
+ class="block w-full {!isValid ? 'ring-danger-500' : 'ring-surface-300 '}"
99
97
  name={state_key}
100
98
  bind:value={$internal.raw}
101
99
  />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stubber/form-fields",
3
- "version": "1.0.10",
3
+ "version": "1.1.0",
4
4
  "description": "An automatic form builder based on field specifications",
5
5
  "keywords": [
6
6
  "components",
@@ -57,7 +57,7 @@
57
57
  "@codemirror/commands": "^6.7.1",
58
58
  "@codemirror/state": "^6.4.1",
59
59
  "@codemirror/view": "^6.34.1",
60
- "@stubber/ui": "^1.0.18",
60
+ "@stubber/ui": "^1.1.1",
61
61
  "ag-grid-community": "^31.0.2",
62
62
  "ag-grid-enterprise": "^31.0.2",
63
63
  "currency-symbol-map": "^5.1.0",