@dorsk/tsumikit 0.44.1 → 0.45.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.
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
/** Muted, right-aligned secondary text (e.g. "62%"). */
|
|
10
10
|
hint?: string;
|
|
11
11
|
disabled?: boolean;
|
|
12
|
+
/** Section heading this option belongs under. Options sharing a group are
|
|
13
|
+
* emitted inside one `<optgroup label={group}>`, in first-seen group order.
|
|
14
|
+
* Ungrouped options render at the top level. */
|
|
15
|
+
group?: string;
|
|
12
16
|
};
|
|
13
17
|
</script>
|
|
14
18
|
|
|
@@ -42,6 +46,7 @@
|
|
|
42
46
|
import type { HTMLSelectAttributes } from 'svelte/elements';
|
|
43
47
|
import Icon from './Icon.svelte';
|
|
44
48
|
import { getFieldContext, warnUnlabelled } from '../../field-context';
|
|
49
|
+
import { sectionOptions } from '../../select-options';
|
|
45
50
|
|
|
46
51
|
// `size` shadows the native option-count attribute (unused in token layouts) to
|
|
47
52
|
// expose the sm|md height scale instead.
|
|
@@ -99,14 +104,26 @@
|
|
|
99
104
|
const selected = $derived(options?.find((o) => o.value === value));
|
|
100
105
|
const hasFace = $derived(!!options && variant !== 'ghost');
|
|
101
106
|
|
|
107
|
+
const sections = $derived(sectionOptions(options ?? []));
|
|
108
|
+
|
|
102
109
|
const optionText = (o: SelectOption) =>
|
|
103
110
|
[o.emoji, o.label, o.hint && `· ${o.hint}`].filter(Boolean).join(' ');
|
|
104
111
|
</script>
|
|
105
112
|
|
|
106
113
|
{#snippet optionList()}
|
|
107
114
|
{#if options}
|
|
108
|
-
{#each
|
|
109
|
-
|
|
115
|
+
{#each sections as section, i (section.group ?? `-${i}`)}
|
|
116
|
+
{#if section.group === undefined}
|
|
117
|
+
{#each section.options as o (o.value)}
|
|
118
|
+
<option value={o.value} disabled={o.disabled}>{optionText(o)}</option>
|
|
119
|
+
{/each}
|
|
120
|
+
{:else}
|
|
121
|
+
<optgroup label={section.group}>
|
|
122
|
+
{#each section.options as o (o.value)}
|
|
123
|
+
<option value={o.value} disabled={o.disabled}>{optionText(o)}</option>
|
|
124
|
+
{/each}
|
|
125
|
+
</optgroup>
|
|
126
|
+
{/if}
|
|
110
127
|
{/each}
|
|
111
128
|
{:else}
|
|
112
129
|
{@render children?.()}
|
|
@@ -251,7 +268,8 @@
|
|
|
251
268
|
.select.has-face {
|
|
252
269
|
color: transparent;
|
|
253
270
|
}
|
|
254
|
-
.select.has-face option
|
|
271
|
+
.select.has-face option,
|
|
272
|
+
.select.has-face optgroup {
|
|
255
273
|
color: var(--text);
|
|
256
274
|
background: var(--bg);
|
|
257
275
|
}
|
|
@@ -7,6 +7,10 @@ export type SelectOption = {
|
|
|
7
7
|
/** Muted, right-aligned secondary text (e.g. "62%"). */
|
|
8
8
|
hint?: string;
|
|
9
9
|
disabled?: boolean;
|
|
10
|
+
/** Section heading this option belongs under. Options sharing a group are
|
|
11
|
+
* emitted inside one `<optgroup label={group}>`, in first-seen group order.
|
|
12
|
+
* Ungrouped options render at the top level. */
|
|
13
|
+
group?: string;
|
|
10
14
|
};
|
|
11
15
|
import type { ControlSize } from '../../size';
|
|
12
16
|
import type { Snippet } from 'svelte';
|
package/dist/index.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ export { default as FilterSearchBar } from './components/organisms/FilterSearchB
|
|
|
83
83
|
export { FIELD_KEY, type FieldContext, getFieldContext, setFieldContext, warnUnlabelled, } from './field-context';
|
|
84
84
|
export * as filterQuery from './query';
|
|
85
85
|
export { type AndNode, activeToken, compilePredicate, defaultOperator, type ExprNode, type FieldDef, type FieldType, type FilterNode, filters, findField, freeText, type LeafNode, type NotNode, OPERATORS, type Operator, type OperatorId, type OrNode, operatorByCode, operatorById, operatorsFor, parse, type Query, type QueryNode, resolveValues, type Schema, type Suggestion, type SuggestKind, type SuggestState, serialize, serializeFilter, suggest, type TextNode, toSql, type ValueContext, type ValueOption, type ValueProvider, walk, } from './query';
|
|
86
|
+
export { type OptionSection, sectionOptions } from './select-options';
|
|
86
87
|
export type { ControlSize } from './size';
|
|
87
88
|
export { fontScale, SCALE_LEVELS, type ScaleLevel } from './stores/fontscale.svelte';
|
|
88
89
|
export { type Mode, THEMES, theme } from './stores/theme.svelte';
|
package/dist/index.js
CHANGED
|
@@ -94,6 +94,7 @@ export { FIELD_KEY, getFieldContext, setFieldContext, warnUnlabelled, } from './
|
|
|
94
94
|
// ---- query core (headless: schema / parser / AST / suggest / compilers) ----
|
|
95
95
|
export * as filterQuery from './query';
|
|
96
96
|
export { activeToken, compilePredicate, defaultOperator, filters, findField, freeText, OPERATORS, operatorByCode, operatorById, operatorsFor, parse, resolveValues, serialize, serializeFilter, suggest, toSql, walk, } from './query';
|
|
97
|
+
export { sectionOptions } from './select-options';
|
|
97
98
|
export { fontScale, SCALE_LEVELS } from './stores/fontscale.svelte';
|
|
98
99
|
// ---- stores / actions ----
|
|
99
100
|
export { THEMES, theme } from './stores/theme.svelte';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function sectionOptions(options) {
|
|
2
|
+
const sections = [];
|
|
3
|
+
const byGroup = new Map();
|
|
4
|
+
for (const option of options) {
|
|
5
|
+
if (option.group === undefined) {
|
|
6
|
+
const tail = sections.at(-1);
|
|
7
|
+
if (tail && tail.group === undefined)
|
|
8
|
+
tail.options.push(option);
|
|
9
|
+
else
|
|
10
|
+
sections.push({ options: [option] });
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
let section = byGroup.get(option.group);
|
|
14
|
+
if (!section) {
|
|
15
|
+
section = { group: option.group, options: [] };
|
|
16
|
+
byGroup.set(option.group, section);
|
|
17
|
+
sections.push(section);
|
|
18
|
+
}
|
|
19
|
+
section.options.push(option);
|
|
20
|
+
}
|
|
21
|
+
return sections;
|
|
22
|
+
}
|
package/package.json
CHANGED