@urbicon-ui/blocks 6.43.2 → 6.44.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/dist/components/FileUpload/fileUpload.variants.js +6 -1
- package/dist/components/PinInput/PinInput.svelte +12 -20
- package/dist/components/TimeInput/TimeInput.svelte +12 -20
- package/dist/internal/core/CoreFieldMessage.svelte +81 -0
- package/dist/internal/core/CoreFieldMessage.svelte.d.ts +23 -0
- package/dist/internal/field-chrome.js +1 -1
- package/dist/primitives/Checkbox/Checkbox.svelte +10 -20
- package/dist/primitives/Checkbox/checkbox.variants.js +1 -1
- package/dist/primitives/Combobox/Combobox.svelte +16 -18
- package/dist/primitives/Combobox/combobox.variants.js +1 -1
- package/dist/primitives/Input/Input.svelte +10 -20
- package/dist/primitives/RadioGroup/RadioGroup.svelte +10 -20
- package/dist/primitives/RadioGroup/radioGroup.variants.js +1 -1
- package/dist/primitives/Select/Select.svelte +10 -20
- package/dist/primitives/Select/select.variants.js +1 -1
- package/dist/primitives/Slider/Slider.svelte +10 -20
- package/dist/primitives/Tab/tab.variants.js +1 -1
- package/dist/primitives/Textarea/Textarea.svelte +10 -15
- package/dist/primitives/Textarea/textarea.variants.js +1 -1
- package/dist/primitives/Toggle/Toggle.svelte +10 -20
- package/dist/style/semantic.css +10 -0
- package/package.json +3 -3
|
@@ -120,8 +120,13 @@ export const fileUploadVariants = tv({
|
|
|
120
120
|
},
|
|
121
121
|
disabled: {
|
|
122
122
|
true: {
|
|
123
|
+
// No `hover:` neutralisers here: `pointer-events-none` on the root
|
|
124
|
+
// already makes the dropzone unhoverable, so any hover class on it is
|
|
125
|
+
// unreachable. The two that used to sit here (`hover:border-border-default
|
|
126
|
+
// hover:bg-surface-base`) were dead, and `bg-surface-base` would have
|
|
127
|
+
// *lightened* a disabled dropzone resting on an elevated card.
|
|
123
128
|
root: 'opacity-50 pointer-events-none',
|
|
124
|
-
dropzone: 'cursor-not-allowed
|
|
129
|
+
dropzone: 'cursor-not-allowed'
|
|
125
130
|
},
|
|
126
131
|
false: {}
|
|
127
132
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte';
|
|
3
3
|
import { useBlocksI18n } from '../..';
|
|
4
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
4
5
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
5
6
|
import { getTierContext } from '../../utils';
|
|
6
7
|
import type { PinInputProps } from './index';
|
|
@@ -299,26 +300,17 @@
|
|
|
299
300
|
{/each}
|
|
300
301
|
</div>
|
|
301
302
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
<div
|
|
314
|
-
id={messageId}
|
|
315
|
-
class={unstyled
|
|
316
|
-
? (slotClasses?.message ?? '')
|
|
317
|
-
: styles.message({ class: slotClasses?.message })}
|
|
318
|
-
>
|
|
319
|
-
{helper}
|
|
320
|
-
</div>
|
|
321
|
-
{/if}
|
|
303
|
+
<!-- Both arms share one id: `describedBy` points at `messageId` regardless of
|
|
304
|
+
which arm renders, since only one ever does. -->
|
|
305
|
+
<CoreFieldMessage
|
|
306
|
+
{error}
|
|
307
|
+
{helper}
|
|
308
|
+
errorId={messageId}
|
|
309
|
+
helperId={messageId}
|
|
310
|
+
class={unstyled
|
|
311
|
+
? (slotClasses?.message ?? '')
|
|
312
|
+
: styles.message({ class: slotClasses?.message })}
|
|
313
|
+
/>
|
|
322
314
|
|
|
323
315
|
{#if name}
|
|
324
316
|
<input type="hidden" {name} {value} />
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack } from 'svelte';
|
|
3
3
|
import { useBlocksI18n } from '../..';
|
|
4
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
4
5
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
5
6
|
import { getTierContext } from '../../utils';
|
|
6
7
|
import { resolveIcon } from '../../icons';
|
|
@@ -509,26 +510,17 @@
|
|
|
509
510
|
{/if}
|
|
510
511
|
</div>
|
|
511
512
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
<div
|
|
524
|
-
id={messageId}
|
|
525
|
-
class={unstyled
|
|
526
|
-
? (slotClasses?.message ?? '')
|
|
527
|
-
: styles.message({ class: slotClasses?.message })}
|
|
528
|
-
>
|
|
529
|
-
{helper}
|
|
530
|
-
</div>
|
|
531
|
-
{/if}
|
|
513
|
+
<!-- Both arms share one id: `describedBy` points at `messageId` regardless of
|
|
514
|
+
which arm renders, since only one ever does. -->
|
|
515
|
+
<CoreFieldMessage
|
|
516
|
+
{error}
|
|
517
|
+
{helper}
|
|
518
|
+
errorId={messageId}
|
|
519
|
+
helperId={messageId}
|
|
520
|
+
class={unstyled
|
|
521
|
+
? (slotClasses?.message ?? '')
|
|
522
|
+
: styles.message({ class: slotClasses?.message })}
|
|
523
|
+
/>
|
|
532
524
|
|
|
533
525
|
{#if name}
|
|
534
526
|
<input type="hidden" {name} value={value ?? ''} />
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
CoreFieldMessage — the helper/error line under a form field, shared by every
|
|
3
|
+
component in the Form family WITHOUT any of them importing another public
|
|
4
|
+
component: Input, Textarea, Select, Combobox, Checkbox, Toggle, RadioGroup,
|
|
5
|
+
Slider, PinInput, TimeInput.
|
|
6
|
+
|
|
7
|
+
INTERNAL — never exported from the package barrel, no docs/MCP entry.
|
|
8
|
+
|
|
9
|
+
This is part (b) of the field-chrome de-duplication: part (a) moved the shared
|
|
10
|
+
tv() class STRINGS into `internal/field-chrome.ts` (debt-fix-wave-5), and the
|
|
11
|
+
same block of MARKUP stayed hand-copied in every `.svelte` file. The first cut
|
|
12
|
+
covered the three components the debt entry named; the block turned out to be
|
|
13
|
+
verbatim in seven more, which is where most of the copies actually were.
|
|
14
|
+
|
|
15
|
+
What it owns: the error-beats-helper precedence, `role="alert"` on the error
|
|
16
|
+
arm only, and wiring the right id onto the right arm. What it does NOT own:
|
|
17
|
+
the look. The call site resolves its own `message` slot (respecting `unstyled`
|
|
18
|
+
and `slotClasses`) and passes the finished class string, exactly as
|
|
19
|
+
CoreIconButton and CoreSpinner take theirs — a core carries behaviour, the
|
|
20
|
+
embedding component carries visual identity.
|
|
21
|
+
|
|
22
|
+
Only the error arm is a live region. The helper text is static descriptive
|
|
23
|
+
content that is already reachable through `aria-describedby`; announcing it
|
|
24
|
+
via `role="alert"` would interrupt the user for text that did not change.
|
|
25
|
+
|
|
26
|
+
Deliberately NOT extracted alongside it: the label. It looks like the same
|
|
27
|
+
kind of copy but it is not — the element is dictated by what the field is.
|
|
28
|
+
Input, Textarea and Combobox render a real `<label for={fieldId}>` because
|
|
29
|
+
each has exactly one focusable element; Select adds an `id` so its trigger
|
|
30
|
+
BUTTON can also be named by `aria-labelledby`; PinInput, TimeInput and
|
|
31
|
+
RadioGroup render a `<span id>` behind `aria-labelledby` on a `role="group"`,
|
|
32
|
+
having many focusable segments and no single field a `for` could point at;
|
|
33
|
+
Checkbox and Toggle put the text inside the wrapping `<label>` next to the
|
|
34
|
+
control, and Slider's sits in a header row beside the value read-out. Those
|
|
35
|
+
are five different a11y shapes, so unifying them would be a regression rather
|
|
36
|
+
than a de-duplication. The label stays at the call sites.
|
|
37
|
+
|
|
38
|
+
The one call site that wraps this component in markup of its own is Textarea:
|
|
39
|
+
its message shares a `justify-between` footer row with the character counter,
|
|
40
|
+
so it keeps an empty `<span>` for the no-message case to hold the counter
|
|
41
|
+
right. That spacer is layout, not scaffolding, and stays there.
|
|
42
|
+
-->
|
|
43
|
+
<script lang="ts">
|
|
44
|
+
let {
|
|
45
|
+
error,
|
|
46
|
+
helper,
|
|
47
|
+
errorId,
|
|
48
|
+
helperId,
|
|
49
|
+
class: className = '',
|
|
50
|
+
helperClass
|
|
51
|
+
}: {
|
|
52
|
+
/** Error text. Wins over `helper` when both are set. */
|
|
53
|
+
error?: string;
|
|
54
|
+
/** Helper text, shown only when there is no error. */
|
|
55
|
+
helper?: string;
|
|
56
|
+
/** Id for the error arm — must match what `aria-describedby` points at. */
|
|
57
|
+
errorId?: string;
|
|
58
|
+
/** Id for the helper arm — must match what `aria-describedby` points at. */
|
|
59
|
+
helperId?: string;
|
|
60
|
+
/** The resolved `message` slot class from the call site. */
|
|
61
|
+
class?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Resolved class for the helper arm, when the call site styles it through a
|
|
64
|
+
* slot of its own instead of reusing `message`. Only Combobox does — it
|
|
65
|
+
* exposes `slotClasses.helper` next to `slotClasses.message`, so the two
|
|
66
|
+
* tones are slot constants there rather than one `messageType` axis.
|
|
67
|
+
* Defaults to `class`, which is what every other field passes.
|
|
68
|
+
*/
|
|
69
|
+
helperClass?: string;
|
|
70
|
+
} = $props();
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
{#if error}
|
|
74
|
+
<div id={errorId} class={className} role="alert">
|
|
75
|
+
{error}
|
|
76
|
+
</div>
|
|
77
|
+
{:else if helper}
|
|
78
|
+
<div id={helperId} class={helperClass ?? className}>
|
|
79
|
+
{helper}
|
|
80
|
+
</div>
|
|
81
|
+
{/if}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
/** Error text. Wins over `helper` when both are set. */
|
|
3
|
+
error?: string;
|
|
4
|
+
/** Helper text, shown only when there is no error. */
|
|
5
|
+
helper?: string;
|
|
6
|
+
/** Id for the error arm — must match what `aria-describedby` points at. */
|
|
7
|
+
errorId?: string;
|
|
8
|
+
/** Id for the helper arm — must match what `aria-describedby` points at. */
|
|
9
|
+
helperId?: string;
|
|
10
|
+
/** The resolved `message` slot class from the call site. */
|
|
11
|
+
class?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Resolved class for the helper arm, when the call site styles it through a
|
|
14
|
+
* slot of its own instead of reusing `message`. Only Combobox does — it
|
|
15
|
+
* exposes `slotClasses.helper` next to `slotClasses.message`, so the two
|
|
16
|
+
* tones are slot constants there rather than one `messageType` axis.
|
|
17
|
+
* Defaults to `class`, which is what every other field passes.
|
|
18
|
+
*/
|
|
19
|
+
helperClass?: string;
|
|
20
|
+
};
|
|
21
|
+
declare const CoreFieldMessage: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
22
|
+
type CoreFieldMessage = ReturnType<typeof CoreFieldMessage>;
|
|
23
|
+
export default CoreFieldMessage;
|
|
@@ -58,7 +58,7 @@ export const fieldFocusRing = (f) => `${f}:border-primary ${f}:ring-2 ${f}:ring-
|
|
|
58
58
|
export const fieldSurfaceVariants = (f) => ({
|
|
59
59
|
outlined: 'border-border-subtle',
|
|
60
60
|
filled: `bg-surface-interactive border-transparent hover:bg-surface-interactive-hover ${f}:bg-surface-base`,
|
|
61
|
-
ghost: `bg-transparent hover:bg-surface-
|
|
61
|
+
ghost: `bg-transparent hover:bg-surface-hover ${f}:bg-surface-base ${f}:border-border-subtle`
|
|
62
62
|
});
|
|
63
63
|
/**
|
|
64
64
|
* The intent frame values (border + focus ring tint) for success/warning/danger,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
5
|
import { getTierContext, useFormField } from '../../utils';
|
|
5
6
|
import { checkboxVariants, type CheckboxVariants } from '..';
|
|
@@ -186,24 +187,13 @@
|
|
|
186
187
|
{/if}
|
|
187
188
|
</label>
|
|
188
189
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
</div>
|
|
199
|
-
{:else if ff.helperId}
|
|
200
|
-
<div
|
|
201
|
-
id={ff.helperId}
|
|
202
|
-
class={unstyled
|
|
203
|
-
? (slotClasses?.message ?? '')
|
|
204
|
-
: styles.message({ class: slotClasses?.message })}
|
|
205
|
-
>
|
|
206
|
-
{helper}
|
|
207
|
-
</div>
|
|
208
|
-
{/if}
|
|
190
|
+
<CoreFieldMessage
|
|
191
|
+
{error}
|
|
192
|
+
{helper}
|
|
193
|
+
errorId={ff.errorId}
|
|
194
|
+
helperId={ff.helperId}
|
|
195
|
+
class={unstyled
|
|
196
|
+
? (slotClasses?.message ?? '')
|
|
197
|
+
: styles.message({ class: slotClasses?.message })}
|
|
198
|
+
/>
|
|
209
199
|
</div>
|
|
@@ -115,7 +115,7 @@ export const checkboxVariants = tv({
|
|
|
115
115
|
checked: false,
|
|
116
116
|
indeterminate: false,
|
|
117
117
|
variant: 'ghost',
|
|
118
|
-
class: { box: 'bg-transparent border-transparent group-hover:bg-surface-
|
|
118
|
+
class: { box: 'bg-transparent border-transparent group-hover:bg-surface-hover' }
|
|
119
119
|
},
|
|
120
120
|
// ── Checked intent colors (identical across all variants) ──
|
|
121
121
|
// Hover/active darken through the intent interaction-layer tokens —
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends string | number | boolean = string">
|
|
2
2
|
import { useBlocksI18n, mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { tick } from 'svelte';
|
|
4
5
|
import { SvelteMap } from 'svelte/reactivity';
|
|
5
6
|
import { comboboxVariants, type ComboboxVariants } from './combobox.variants';
|
|
@@ -841,24 +842,21 @@
|
|
|
841
842
|
</div>
|
|
842
843
|
</div>
|
|
843
844
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
{helper}
|
|
860
|
-
</div>
|
|
861
|
-
{/if}
|
|
845
|
+
<!-- Combobox is the one field whose helper has a slot of its own: the two
|
|
846
|
+
tones are slot constants here, not a `messageType` axis, so the helper
|
|
847
|
+
arm keeps reading quiet while the field is invalid. -->
|
|
848
|
+
<CoreFieldMessage
|
|
849
|
+
{error}
|
|
850
|
+
{helper}
|
|
851
|
+
errorId={ff.errorId}
|
|
852
|
+
helperId={ff.helperId}
|
|
853
|
+
class={unstyled
|
|
854
|
+
? (slotClasses?.message ?? '')
|
|
855
|
+
: styles.message({ class: slotClasses?.message })}
|
|
856
|
+
helperClass={unstyled
|
|
857
|
+
? (slotClasses?.helper ?? '')
|
|
858
|
+
: styles.helper({ class: slotClasses?.helper })}
|
|
859
|
+
/>
|
|
862
860
|
</div>
|
|
863
861
|
|
|
864
862
|
<!--
|
|
@@ -146,7 +146,7 @@ export const comboboxVariants = tv({
|
|
|
146
146
|
control: 'bg-surface-interactive border-transparent hover:bg-surface-interactive-hover focus-within:bg-surface-base'
|
|
147
147
|
},
|
|
148
148
|
ghost: {
|
|
149
|
-
input: 'bg-transparent border-transparent hover:bg-surface-
|
|
149
|
+
input: 'bg-transparent border-transparent hover:bg-surface-hover focus-visible:bg-surface-base focus-visible:border-border-subtle',
|
|
150
150
|
control: 'bg-transparent border-transparent focus-within:bg-surface-base focus-within:border-border-subtle'
|
|
151
151
|
},
|
|
152
152
|
underline: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useBlocksI18n, mintRegistry, createPersistentState } from '../..';
|
|
3
3
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
4
5
|
import { useFormField, getTierContext } from '../../utils';
|
|
5
6
|
import type { InputProps } from '.';
|
|
6
7
|
import { inputVariants, type InputVariants } from './input.variants';
|
|
@@ -289,26 +290,15 @@
|
|
|
289
290
|
{/if}
|
|
290
291
|
</div>
|
|
291
292
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
</div>
|
|
302
|
-
{:else if ff.helperId}
|
|
303
|
-
<div
|
|
304
|
-
id={ff.helperId}
|
|
305
|
-
class={unstyled
|
|
306
|
-
? (slotClasses?.message ?? '')
|
|
307
|
-
: styles.message({ class: slotClasses?.message })}
|
|
308
|
-
>
|
|
309
|
-
{helper}
|
|
310
|
-
</div>
|
|
311
|
-
{/if}
|
|
293
|
+
<CoreFieldMessage
|
|
294
|
+
{error}
|
|
295
|
+
{helper}
|
|
296
|
+
errorId={ff.errorId}
|
|
297
|
+
helperId={ff.helperId}
|
|
298
|
+
class={unstyled
|
|
299
|
+
? (slotClasses?.message ?? '')
|
|
300
|
+
: styles.message({ class: slotClasses?.message })}
|
|
301
|
+
/>
|
|
312
302
|
|
|
313
303
|
{#if children}
|
|
314
304
|
<div class="mt-1.5">
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
2
3
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
3
4
|
import { getTierContext, useFormField } from '../../utils';
|
|
4
5
|
import type { RadioGroupProps } from './index';
|
|
@@ -177,24 +178,13 @@
|
|
|
177
178
|
{@render children()}
|
|
178
179
|
</div>
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
</div>
|
|
190
|
-
{:else if ff.helperId}
|
|
191
|
-
<div
|
|
192
|
-
id={ff.helperId}
|
|
193
|
-
class={unstyled
|
|
194
|
-
? (slotClasses?.message ?? '')
|
|
195
|
-
: styles.message({ class: slotClasses?.message })}
|
|
196
|
-
>
|
|
197
|
-
{helper}
|
|
198
|
-
</div>
|
|
199
|
-
{/if}
|
|
181
|
+
<CoreFieldMessage
|
|
182
|
+
{error}
|
|
183
|
+
{helper}
|
|
184
|
+
errorId={ff.errorId}
|
|
185
|
+
helperId={ff.helperId}
|
|
186
|
+
class={unstyled
|
|
187
|
+
? (slotClasses?.message ?? '')
|
|
188
|
+
: styles.message({ class: slotClasses?.message })}
|
|
189
|
+
/>
|
|
200
190
|
</div>
|
|
@@ -160,7 +160,7 @@ export const radioItemVariants = tv({
|
|
|
160
160
|
{
|
|
161
161
|
checked: false,
|
|
162
162
|
variant: 'ghost',
|
|
163
|
-
class: { indicator: 'bg-transparent border-transparent group-hover:bg-surface-
|
|
163
|
+
class: { indicator: 'bg-transparent border-transparent group-hover:bg-surface-hover' }
|
|
164
164
|
},
|
|
165
165
|
// Checked intent colors
|
|
166
166
|
// Hover/active darken through the intent interaction-layer tokens — the
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts" generics="T extends string | number | boolean = string">
|
|
2
2
|
import { useBlocksI18n, mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { useFormField, getTierContext, useFloatingPanel, floatingPanelHidden } from '../../utils';
|
|
4
5
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
5
6
|
import { resolveIcon } from '../../icons';
|
|
@@ -759,24 +760,13 @@
|
|
|
759
760
|
{/if}
|
|
760
761
|
{/if}
|
|
761
762
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
</div>
|
|
772
|
-
{:else if ff.helperId}
|
|
773
|
-
<div
|
|
774
|
-
id={ff.helperId}
|
|
775
|
-
class={unstyled
|
|
776
|
-
? (slotClasses?.message ?? '')
|
|
777
|
-
: styles.message({ class: slotClasses?.message })}
|
|
778
|
-
>
|
|
779
|
-
{helper}
|
|
780
|
-
</div>
|
|
781
|
-
{/if}
|
|
763
|
+
<CoreFieldMessage
|
|
764
|
+
{error}
|
|
765
|
+
{helper}
|
|
766
|
+
errorId={ff.errorId}
|
|
767
|
+
helperId={ff.helperId}
|
|
768
|
+
class={unstyled
|
|
769
|
+
? (slotClasses?.message ?? '')
|
|
770
|
+
: styles.message({ class: slotClasses?.message })}
|
|
771
|
+
/>
|
|
782
772
|
</div>
|
|
@@ -81,7 +81,7 @@ export const selectVariants = tv({
|
|
|
81
81
|
trigger: 'bg-surface-interactive border-transparent hover:bg-surface-interactive-hover focus-visible:bg-surface-base'
|
|
82
82
|
},
|
|
83
83
|
ghost: {
|
|
84
|
-
trigger: 'bg-transparent border-transparent hover:bg-surface-
|
|
84
|
+
trigger: 'bg-transparent border-transparent hover:bg-surface-hover focus-visible:bg-surface-base focus-visible:border-border-subtle'
|
|
85
85
|
},
|
|
86
86
|
underline: {
|
|
87
87
|
trigger: 'bg-transparent border-0 border-b-2 border-border-subtle rounded-none focus-visible:ring-0'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useBlocksI18n, mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
5
|
import { useFormField } from '../../utils';
|
|
5
6
|
import type { SliderProps } from './index';
|
|
@@ -558,24 +559,13 @@
|
|
|
558
559
|
</div>
|
|
559
560
|
{/if}
|
|
560
561
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
</div>
|
|
571
|
-
{:else if ff.helperId}
|
|
572
|
-
<div
|
|
573
|
-
id={ff.helperId}
|
|
574
|
-
class={unstyled
|
|
575
|
-
? (slotClasses?.message ?? '')
|
|
576
|
-
: styles.message({ class: slotClasses?.message })}
|
|
577
|
-
>
|
|
578
|
-
{helper}
|
|
579
|
-
</div>
|
|
580
|
-
{/if}
|
|
562
|
+
<CoreFieldMessage
|
|
563
|
+
{error}
|
|
564
|
+
{helper}
|
|
565
|
+
errorId={ff.errorId}
|
|
566
|
+
helperId={ff.helperId}
|
|
567
|
+
class={unstyled
|
|
568
|
+
? (slotClasses?.message ?? '')
|
|
569
|
+
: styles.message({ class: slotClasses?.message })}
|
|
570
|
+
/>
|
|
581
571
|
</div>
|
|
@@ -60,7 +60,7 @@ export const tabVariants = tv({
|
|
|
60
60
|
trigger: [
|
|
61
61
|
'px-4 py-2 border border-b-0 -mb-px',
|
|
62
62
|
'text-text-tertiary border-transparent',
|
|
63
|
-
'hover:text-text-primary hover:bg-surface-
|
|
63
|
+
'hover:text-text-primary hover:bg-surface-hover',
|
|
64
64
|
'data-[state=active]:bg-surface-base data-[state=active]:text-primary',
|
|
65
65
|
'data-[state=active]:border-border-subtle data-[state=active]:border-b-surface-base'
|
|
66
66
|
]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
5
|
import { useFormField, getTierContext } from '../../utils';
|
|
5
6
|
import type { TextareaProps } from './index';
|
|
@@ -165,26 +166,20 @@
|
|
|
165
166
|
<div
|
|
166
167
|
class={unstyled ? (slotClasses?.footer ?? '') : styles.footer({ class: slotClasses?.footer })}
|
|
167
168
|
>
|
|
168
|
-
{#if
|
|
169
|
-
<
|
|
170
|
-
id={ff.errorId}
|
|
171
|
-
class={unstyled
|
|
172
|
-
? (slotClasses?.message ?? '')
|
|
173
|
-
: styles.message({ class: slotClasses?.message })}
|
|
174
|
-
role="alert"
|
|
175
|
-
>
|
|
169
|
+
{#if error || helper}
|
|
170
|
+
<CoreFieldMessage
|
|
176
171
|
{error}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
id={ff.helperId}
|
|
172
|
+
{helper}
|
|
173
|
+
errorId={ff.errorId}
|
|
174
|
+
helperId={ff.helperId}
|
|
181
175
|
class={unstyled
|
|
182
176
|
? (slotClasses?.message ?? '')
|
|
183
177
|
: styles.message({ class: slotClasses?.message })}
|
|
184
|
-
|
|
185
|
-
{helper}
|
|
186
|
-
</div>
|
|
178
|
+
/>
|
|
187
179
|
{:else}
|
|
180
|
+
<!-- The footer is `justify-between`: without a first child the counter
|
|
181
|
+
would slide to the left edge. Unlike every other field, Textarea's
|
|
182
|
+
message shares a row, so the empty slot has to stay here. -->
|
|
188
183
|
<span></span>
|
|
189
184
|
{/if}
|
|
190
185
|
|
|
@@ -33,7 +33,7 @@ export const textareaVariants = tv({
|
|
|
33
33
|
base: 'bg-surface-interactive border-transparent hover:bg-surface-interactive-hover focus-visible:bg-surface-base'
|
|
34
34
|
},
|
|
35
35
|
ghost: {
|
|
36
|
-
base: 'bg-transparent border-transparent hover:bg-surface-
|
|
36
|
+
base: 'bg-transparent border-transparent hover:bg-surface-hover focus-visible:bg-surface-base focus-visible:border-border-subtle'
|
|
37
37
|
},
|
|
38
38
|
underline: {
|
|
39
39
|
base: 'bg-transparent border-0 border-b-2 border-border-subtle rounded-none focus-visible:ring-0'
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { useBlocksI18n, mintRegistry } from '../..';
|
|
3
|
+
import CoreFieldMessage from '../../internal/core/CoreFieldMessage.svelte';
|
|
3
4
|
import { getBlocksConfig, resolveSlotClasses } from '../../provider';
|
|
4
5
|
import { getTierContext, useFormField } from '../../utils';
|
|
5
6
|
import { toggleVariants, type ToggleVariants } from './toggle.variants';
|
|
@@ -152,24 +153,13 @@
|
|
|
152
153
|
{/if}
|
|
153
154
|
</label>
|
|
154
155
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
</div>
|
|
165
|
-
{:else if ff.helperId}
|
|
166
|
-
<div
|
|
167
|
-
id={ff.helperId}
|
|
168
|
-
class={unstyled
|
|
169
|
-
? (slotClasses?.message ?? '')
|
|
170
|
-
: styles.message({ class: slotClasses?.message })}
|
|
171
|
-
>
|
|
172
|
-
{helper}
|
|
173
|
-
</div>
|
|
174
|
-
{/if}
|
|
156
|
+
<CoreFieldMessage
|
|
157
|
+
{error}
|
|
158
|
+
{helper}
|
|
159
|
+
errorId={ff.errorId}
|
|
160
|
+
helperId={ff.helperId}
|
|
161
|
+
class={unstyled
|
|
162
|
+
? (slotClasses?.message ?? '')
|
|
163
|
+
: styles.message({ class: slotClasses?.message })}
|
|
164
|
+
/>
|
|
175
165
|
</div>
|
package/dist/style/semantic.css
CHANGED
|
@@ -69,6 +69,16 @@
|
|
|
69
69
|
--color-surface-active: light-dark(var(--color-neutral-200), var(--color-neutral-700));
|
|
70
70
|
--color-surface-disabled: light-dark(var(--color-neutral-100), var(--color-neutral-800));
|
|
71
71
|
--color-surface-selected: light-dark(var(--color-primary-50), var(--color-primary-900));
|
|
72
|
+
/* A RESTING tint only — never a hover step. It resolves to exactly
|
|
73
|
+
`surface-elevated`, so `hover:bg-surface-subtle` is invisible on every
|
|
74
|
+
elevated surface (Popover, Menu, Select dropdown, elevated Card). That
|
|
75
|
+
shipped across 8 components until 2026-07-26; the hover idiom moved to
|
|
76
|
+
`surface-hover`, and variants-lint now errors on any hover fill naming a
|
|
77
|
+
reading surface. Its in-page-zone role was superseded by `surface-quiet`
|
|
78
|
+
in v5 (MIGRATION-v5 "New tokens"), which is why it has no rung of its own
|
|
79
|
+
left — prefer `surface-quiet` for a tinted zone and `surface-elevated`
|
|
80
|
+
for a raised one. Kept for the resting uses that read correctly against
|
|
81
|
+
a border (readonly/disabled fields, list rows, code chips). */
|
|
72
82
|
--color-surface-subtle: light-dark(var(--color-neutral-50), var(--color-neutral-800));
|
|
73
83
|
--color-surface-inverted: light-dark(var(--color-neutral-900), var(--color-neutral-100));
|
|
74
84
|
/* Skeleton wave-shimmer highlight (Skeleton animation="wave"). A translucent
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@urbicon-ui/blocks",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.44.0",
|
|
4
4
|
"description": "Svelte 5 UI component library with Tailwind CSS 4, OKLCH design tokens and zero runtime dependencies",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
"@sveltejs/package": "^2.5.8",
|
|
94
94
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
95
95
|
"@tailwindcss/vite": "^4.3.1",
|
|
96
|
-
"@urbicon-ui/i18n": "6.
|
|
97
|
-
"@urbicon-ui/shared-types": "6.
|
|
96
|
+
"@urbicon-ui/i18n": "6.44.0",
|
|
97
|
+
"@urbicon-ui/shared-types": "6.44.0",
|
|
98
98
|
"prettier": "^3.8.4",
|
|
99
99
|
"prettier-plugin-svelte": "^4.1.1",
|
|
100
100
|
"prettier-plugin-tailwindcss": "^0.8.0",
|