@streamscloud/kit 0.90.0 → 0.90.1
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/ui/_internal/form-field-label-context/form-field-label-context.svelte.d.ts +2 -0
- package/dist/ui/_internal/form-field-label-context/form-field-label-context.svelte.js +2 -0
- package/dist/ui/_internal/form-field-label-context/index.d.ts +1 -1
- package/dist/ui/_internal/form-field-label-context/index.js +1 -1
- package/dist/ui/color-picker/cmp.color-picker.svelte +4 -1
- package/dist/ui/date-picker/cmp.date-picker.svelte +6 -3
- package/dist/ui/popover/cmp.popover.svelte +5 -3
- package/dist/ui/popover/cmp.popover.svelte.d.ts +1 -0
- package/dist/ui/select/cmp.singleselect-async.svelte +5 -2
- package/dist/ui/select/multiselect-base.svelte +5 -2
- package/dist/ui/select/select-listbox.svelte +3 -2
- package/dist/ui/tree/cmp.tree-node-view.svelte +13 -15
- package/package.json +1 -1
|
@@ -11,5 +11,7 @@ export declare const getFormFieldLabel: () => FormFieldLabelContext | undefined;
|
|
|
11
11
|
export declare const claimFormFieldLabel: (controlId: () => string) => void;
|
|
12
12
|
/** The `aria-labelledby` of a control that is not a text input: the explicit one, else the FormField label's id — unless an explicit `aria-label` names it. */
|
|
13
13
|
export declare const resolveAriaLabelledby: (formFieldLabel: FormFieldLabelContext | undefined, ariaLabel: string | undefined, ariaLabelledby: string | undefined) => string | undefined;
|
|
14
|
+
/** Whether `target` sits in a `<label>` whose `for` control lies inside `controlRoot` — a press there belongs to that control, not outside it. */
|
|
15
|
+
export declare const isInsideLabelOf: (target: Node, controlRoot: HTMLElement | undefined) => boolean;
|
|
14
16
|
/** Below the calling component no control is named by the surrounding FormField label — for a field that renders other fields in its own panel. */
|
|
15
17
|
export declare const stopFormFieldLabelHere: () => void;
|
|
@@ -14,6 +14,8 @@ export const claimFormFieldLabel = (controlId) => {
|
|
|
14
14
|
};
|
|
15
15
|
/** The `aria-labelledby` of a control that is not a text input: the explicit one, else the FormField label's id — unless an explicit `aria-label` names it. */
|
|
16
16
|
export const resolveAriaLabelledby = (formFieldLabel, ariaLabel, ariaLabelledby) => ariaLabelledby ?? (ariaLabel ? undefined : formFieldLabel?.labelId);
|
|
17
|
+
/** Whether `target` sits in a `<label>` whose `for` control lies inside `controlRoot` — a press there belongs to that control, not outside it. */
|
|
18
|
+
export const isInsideLabelOf = (target, controlRoot) => target instanceof Element && !!controlRoot?.contains(target.closest('label')?.control ?? null);
|
|
17
19
|
/** Below the calling component no control is named by the surrounding FormField label — for a field that renders other fields in its own panel. */
|
|
18
20
|
export const stopFormFieldLabelHere = () => {
|
|
19
21
|
setContext(KEY, undefined);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { claimFormFieldLabel, getFormFieldLabel, provideFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere, type FormFieldLabelContext } from './form-field-label-context.svelte';
|
|
1
|
+
export { claimFormFieldLabel, getFormFieldLabel, isInsideLabelOf, provideFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere, type FormFieldLabelContext } from './form-field-label-context.svelte';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { claimFormFieldLabel, getFormFieldLabel, provideFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from './form-field-label-context.svelte';
|
|
1
|
+
export { claimFormFieldLabel, getFormFieldLabel, isInsideLabelOf, provideFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from './form-field-label-context.svelte';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">import { ColorHelper } from '../../core/utils';
|
|
2
|
-
import { getFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from '../_internal/form-field-label-context';
|
|
2
|
+
import { claimFormFieldLabel, getFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from '../_internal/form-field-label-context';
|
|
3
3
|
import { Icon } from '../icon';
|
|
4
4
|
import { Input } from '../input';
|
|
5
5
|
import { Popover } from '../popover';
|
|
@@ -11,6 +11,8 @@ import { colord } from 'colord';
|
|
|
11
11
|
import AwesomeColorPicker from 'svelte-awesome-color-picker';
|
|
12
12
|
let { value, variant = 'fill', label, size = 'md', defaultColor, clearable = false, disabled = false, placeholder, on, children, previewIcon, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby } = $props();
|
|
13
13
|
const formFieldLabel = getFormFieldLabel();
|
|
14
|
+
const triggerId = $props.id();
|
|
15
|
+
claimFormFieldLabel(() => triggerId);
|
|
14
16
|
stopFormFieldLabelHere();
|
|
15
17
|
const loc = new ColorPickerLocalization();
|
|
16
18
|
const displayColor = $derived(value || defaultColor || '');
|
|
@@ -54,6 +56,7 @@ const onColorPickerInput = ({ hex }) => {
|
|
|
54
56
|
panel={false}
|
|
55
57
|
fixedPosition
|
|
56
58
|
disabled={disabled}
|
|
59
|
+
id={triggerId}
|
|
57
60
|
aria-label={ariaLabel}
|
|
58
61
|
aria-labelledby={resolveAriaLabelledby(formFieldLabel, ariaLabel, ariaLabelledby)}>
|
|
59
62
|
{#snippet trigger()}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<script lang="ts">import { getFormFieldLabel, resolveAriaLabelledby } from '../_internal/form-field-label-context';
|
|
1
|
+
<script lang="ts">import { claimFormFieldLabel, getFormFieldLabel, isInsideLabelOf, resolveAriaLabelledby } from '../_internal/form-field-label-context';
|
|
2
2
|
import { InputClearButton } from '../_internal/input-clear-button';
|
|
3
3
|
import { Icon, IconSlot } from '../icon';
|
|
4
4
|
import DatePickerCalendar from './cmp.date-picker-calendar.svelte';
|
|
@@ -7,6 +7,9 @@ import { autoUpdate, computePosition, flip, offset, shift } from '@floating-ui/d
|
|
|
7
7
|
import IconCalendar from '@fluentui/svg-icons/icons/calendar_16_regular.svg?raw';
|
|
8
8
|
const { size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, min, max, locale, name, id = null, autofocus = false, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, icon, ...mode } = $props();
|
|
9
9
|
const formFieldLabel = getFormFieldLabel();
|
|
10
|
+
const fallbackId = $props.id();
|
|
11
|
+
const controlId = $derived(id ?? fallbackId);
|
|
12
|
+
claimFormFieldLabel(() => controlId);
|
|
10
13
|
const localization = new DatePickerLocalization();
|
|
11
14
|
/** Resolved locale: explicit prop or `'en-US'` default. */
|
|
12
15
|
const resolvedLocale = $derived(locale ?? 'en-US');
|
|
@@ -95,7 +98,7 @@ $effect(() => {
|
|
|
95
98
|
if (!target) {
|
|
96
99
|
return;
|
|
97
100
|
}
|
|
98
|
-
if (triggerEl?.contains(target) || panelEl?.contains(target)) {
|
|
101
|
+
if (triggerEl?.contains(target) || panelEl?.contains(target) || isInsideLabelOf(target, triggerEl)) {
|
|
99
102
|
return;
|
|
100
103
|
}
|
|
101
104
|
open = false;
|
|
@@ -129,7 +132,7 @@ $effect(() => {
|
|
|
129
132
|
bind:this={triggerEl}
|
|
130
133
|
type="button"
|
|
131
134
|
class="date-picker__trigger"
|
|
132
|
-
id={
|
|
135
|
+
id={controlId}
|
|
133
136
|
disabled={disabled}
|
|
134
137
|
inert={inert}
|
|
135
138
|
autofocus={autofocus}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
<script lang="ts">import {
|
|
1
|
+
<script lang="ts">import { isInsideLabelOf } from '../_internal/form-field-label-context';
|
|
2
|
+
import { Icon } from '../icon';
|
|
2
3
|
import { isIgnored } from './popover-ignore';
|
|
3
4
|
import { validateTrigger } from './validate-trigger';
|
|
4
5
|
import { autoUpdate, computePosition, flip, offset as offsetMiddleware, shift, size } from '@floating-ui/dom';
|
|
5
6
|
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
|
|
6
7
|
import { tick } from 'svelte';
|
|
7
|
-
let { position = 'bottom-start', disabled = false, fixedPosition = false, offset = 4, boundaryMargin = 8, backdrop = false, matchWidth = false, panel = true, keepOpen = false, fillContainer = false, tabbable = true, on, children, trigger, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby } = $props();
|
|
8
|
+
let { position = 'bottom-start', disabled = false, fixedPosition = false, offset = 4, boundaryMargin = 8, backdrop = false, matchWidth = false, panel = true, keepOpen = false, fillContainer = false, tabbable = true, on, children, trigger, id, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby } = $props();
|
|
8
9
|
let opened = $state(false);
|
|
9
10
|
let triggerEl = $state.raw(undefined);
|
|
10
11
|
let contentEl = $state.raw(undefined);
|
|
@@ -106,7 +107,7 @@ $effect(() => {
|
|
|
106
107
|
if (!target) {
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
109
|
-
if (triggerEl?.contains(target) || contentEl?.contains(target)) {
|
|
110
|
+
if (triggerEl?.contains(target) || contentEl?.contains(target) || isInsideLabelOf(target, triggerEl)) {
|
|
110
111
|
return;
|
|
111
112
|
}
|
|
112
113
|
close();
|
|
@@ -179,6 +180,7 @@ const handleBackdropClick = (e) => {
|
|
|
179
180
|
type="button"
|
|
180
181
|
class="popover__trigger"
|
|
181
182
|
class:popover__trigger--fill={fillContainer}
|
|
183
|
+
id={id}
|
|
182
184
|
disabled={disabled}
|
|
183
185
|
tabindex={tabbable ? undefined : -1}
|
|
184
186
|
aria-label={ariaLabel}
|
|
@@ -29,6 +29,7 @@ type Props = {
|
|
|
29
29
|
children: Snippet;
|
|
30
30
|
/** Content of the trigger `<button>`, so non-interactive only — `Button type="presentational"` for a button look. @default chevron-down icon */
|
|
31
31
|
trigger?: Snippet;
|
|
32
|
+
id?: string;
|
|
32
33
|
'aria-label'?: string;
|
|
33
34
|
'aria-labelledby'?: string;
|
|
34
35
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>export {};
|
|
2
2
|
</script>
|
|
3
3
|
|
|
4
|
-
<script lang="ts" generics="T">import { getFormFieldLabel, resolveAriaLabelledby } from '../_internal/form-field-label-context';
|
|
4
|
+
<script lang="ts" generics="T">import { claimFormFieldLabel, getFormFieldLabel, resolveAriaLabelledby } from '../_internal/form-field-label-context';
|
|
5
5
|
import { InputClearButton } from '../_internal/input-clear-button';
|
|
6
6
|
import { Spinner } from '../_internal/spinner';
|
|
7
7
|
import { Icon, IconSlot } from '../icon';
|
|
@@ -12,6 +12,9 @@ import { SingleselectLocalization } from './singleselect-localization';
|
|
|
12
12
|
import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_16_regular.svg?raw';
|
|
13
13
|
const { loadOptions, debounceMs = 400, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = true, groupHeader = 'static', compare = defaultCompare, createOptions, icon, chevronIcon, optionSnippet, selectionSnippet, listbox, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, ...mode } = $props();
|
|
14
14
|
const formFieldLabel = getFormFieldLabel();
|
|
15
|
+
const fallbackId = $props.id();
|
|
16
|
+
const controlId = $derived(id ?? fallbackId);
|
|
17
|
+
claimFormFieldLabel(() => controlId);
|
|
15
18
|
const localization = new SingleselectLocalization();
|
|
16
19
|
const selectedOption = $derived(mode.value ?? null);
|
|
17
20
|
const selectionLabel = $derived(selectedOption?.label ?? '');
|
|
@@ -107,7 +110,7 @@ const showClear = $derived(mode.clearable && hasValue && isInteractive && !core.
|
|
|
107
110
|
aria-describedby={ariaDescribedby}
|
|
108
111
|
aria-required={ariaRequired}
|
|
109
112
|
aria-invalid={error ? 'true' : undefined}
|
|
110
|
-
id={
|
|
113
|
+
id={controlId}
|
|
111
114
|
name={name}
|
|
112
115
|
autocomplete={autocomplete}
|
|
113
116
|
placeholder={inputPlaceholder}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts" module>export {};
|
|
2
2
|
</script>
|
|
3
3
|
|
|
4
|
-
<script lang="ts" generics="T">import { getFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from '../_internal/form-field-label-context';
|
|
4
|
+
<script lang="ts" generics="T">import { claimFormFieldLabel, getFormFieldLabel, resolveAriaLabelledby, stopFormFieldLabelHere } from '../_internal/form-field-label-context';
|
|
5
5
|
import { Spinner } from '../_internal/spinner';
|
|
6
6
|
import { Button } from '../button';
|
|
7
7
|
import { Icon, IconSlot } from '../icon';
|
|
@@ -16,6 +16,9 @@ import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_16_regular.s
|
|
|
16
16
|
import { dndzone } from 'svelte-dnd-action';
|
|
17
17
|
const { loadOptions, debounceMs = 400, value, size = 'md', placeholder = '', disabled = false, readonly = false, inert = false, error = false, borderless = false, searchable = true, groupHeader = 'static', compare = defaultCompare, selectionMode = 'children-only', selectedDisplay = 'checkmark', createOptions, chipMode = 'inline', reorderable = false, maxVisible = Infinity, showFullItem = false, chipVariant, showChevron = true, hideSelected = false, icon, chevronIcon, optionSnippet, chipSnippet, selectionSnippet, parentSource, id, name, autocomplete = 'off', 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, 'aria-describedby': ariaDescribedby, 'aria-required': ariaRequired, on } = $props();
|
|
18
18
|
const formFieldLabel = getFormFieldLabel();
|
|
19
|
+
const fallbackId = $props.id();
|
|
20
|
+
const controlId = $derived(id ?? fallbackId);
|
|
21
|
+
claimFormFieldLabel(() => controlId);
|
|
19
22
|
stopFormFieldLabelHere();
|
|
20
23
|
const localization = new MultiselectLocalization();
|
|
21
24
|
const isPicked = (v) => value.some((existing) => compare(existing.value, v));
|
|
@@ -232,7 +235,7 @@ const handleDndFinalize = (e) => {
|
|
|
232
235
|
aria-describedby={ariaDescribedby}
|
|
233
236
|
aria-required={ariaRequired}
|
|
234
237
|
aria-invalid={error ? 'true' : undefined}
|
|
235
|
-
id={
|
|
238
|
+
id={controlId}
|
|
236
239
|
name={name}
|
|
237
240
|
autocomplete={autocomplete}
|
|
238
241
|
placeholder={!hasValue && !core.isFiltering ? placeholder : ''}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<script lang="ts" generics="T">import {
|
|
1
|
+
<script lang="ts" generics="T">import { isInsideLabelOf } from '../_internal/form-field-label-context';
|
|
2
|
+
import { Icon } from '../icon';
|
|
2
3
|
import { SelectListboxLocalization } from './select-listbox-localization';
|
|
3
4
|
import { autoUpdate, computePosition, flip, shift, size as floatingSize } from '@floating-ui/dom';
|
|
4
5
|
import IconAdd from '@fluentui/svg-icons/icons/add_16_regular.svg?raw';
|
|
@@ -71,7 +72,7 @@ $effect(() => {
|
|
|
71
72
|
if (!target) {
|
|
72
73
|
return;
|
|
73
74
|
}
|
|
74
|
-
if (triggerEl?.contains(target) || panelEl?.contains(target)) {
|
|
75
|
+
if (triggerEl?.contains(target) || panelEl?.contains(target) || isInsideLabelOf(target, triggerEl)) {
|
|
75
76
|
return;
|
|
76
77
|
}
|
|
77
78
|
on.dismiss();
|
|
@@ -195,6 +195,7 @@ const handleActionsClosed = () => {
|
|
|
195
195
|
class:tree-node__leaf--draggable={node.drag}
|
|
196
196
|
class:tree-node__leaf--expandable={children.length}
|
|
197
197
|
class:tree-node__leaf--drag-over={dragOver}
|
|
198
|
+
class:tree-node__leaf--with-actions={actionsShown}
|
|
198
199
|
draggable={!!node.drag && !node.renaming}
|
|
199
200
|
ondragstart={handleDragStart}
|
|
200
201
|
ondragend={handleDragEnd}
|
|
@@ -307,7 +308,6 @@ const handleActionsClosed = () => {
|
|
|
307
308
|
--_tree-node--padding-inline: var(--sc-kit--tree-node--padding-inline, 0.5rem);
|
|
308
309
|
--_tree-node--padding-block: var(--sc-kit--tree-node--padding-block, 0.375rem);
|
|
309
310
|
--_tree-node--indent: var(--sc-kit--tree-node--indent, 1rem);
|
|
310
|
-
--_tree-node--action-opacity: 0;
|
|
311
311
|
position: relative;
|
|
312
312
|
width: 100%;
|
|
313
313
|
color: var(--sc-kit--color--text--primary);
|
|
@@ -325,17 +325,25 @@ const handleActionsClosed = () => {
|
|
|
325
325
|
transition: background-color var(--sc-kit--duration--base) var(--sc-kit--ease--default), color var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
326
326
|
}
|
|
327
327
|
.tree-node__leaf:hover {
|
|
328
|
-
--_tree-node--action-opacity: 1;
|
|
329
328
|
color: var(--sc-kit--color--text--primary);
|
|
330
329
|
background: var(--sc-kit--color--bg--hover);
|
|
331
330
|
}
|
|
332
331
|
.tree-node__leaf--active {
|
|
333
|
-
--_tree-node--action-opacity: 1;
|
|
334
332
|
color: var(--sc-kit--color--text--primary);
|
|
335
333
|
background: var(--sc-kit--color--bg--active);
|
|
336
334
|
}
|
|
337
|
-
|
|
338
|
-
--
|
|
335
|
+
@media (any-hover: hover) {
|
|
336
|
+
.tree-node__leaf--with-actions:not(:hover, :has(:global(:focus-visible)), :has(.node-actions--opened)) .node-actions, .tree-node__leaf--with-actions:is(:hover, :has(:global(:focus-visible)), :has(.node-actions--opened)) .tree-node__count {
|
|
337
|
+
position: absolute;
|
|
338
|
+
width: 1px;
|
|
339
|
+
height: 1px;
|
|
340
|
+
margin: -1px;
|
|
341
|
+
padding: 0;
|
|
342
|
+
overflow: hidden;
|
|
343
|
+
clip-path: inset(50%);
|
|
344
|
+
white-space: nowrap;
|
|
345
|
+
border: 0;
|
|
346
|
+
}
|
|
339
347
|
}
|
|
340
348
|
.tree-node__leaf:has(.tree-node__anchor:focus-visible) {
|
|
341
349
|
outline: 2px solid var(--sc-kit--color--border--focus);
|
|
@@ -433,11 +441,6 @@ const handleActionsClosed = () => {
|
|
|
433
441
|
flex-shrink: 0;
|
|
434
442
|
align-items: center;
|
|
435
443
|
margin-left: var(--sc-kit--space--1);
|
|
436
|
-
opacity: var(--_tree-node--action-opacity);
|
|
437
|
-
transition: opacity var(--sc-kit--duration--base) var(--sc-kit--ease--default);
|
|
438
|
-
}
|
|
439
|
-
.node-actions--opened {
|
|
440
|
-
opacity: 1;
|
|
441
444
|
}
|
|
442
445
|
.node-actions__trigger {
|
|
443
446
|
--sc-kit--icon--size: 1rem;
|
|
@@ -452,9 +455,4 @@ const handleActionsClosed = () => {
|
|
|
452
455
|
.node-actions__trigger:hover {
|
|
453
456
|
background: var(--sc-kit--color--bg--active);
|
|
454
457
|
color: var(--sc-kit--color--text--primary);
|
|
455
|
-
}
|
|
456
|
-
@media (any-hover: none) {
|
|
457
|
-
.node-actions {
|
|
458
|
-
opacity: 1;
|
|
459
|
-
}
|
|
460
458
|
}</style>
|