@threadlabs/looma 0.23.10 → 0.23.12
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/components/ui-badge/ui-badge.html +13 -2
- package/components/ui-combobox/ui-combobox.html +6 -0
- package/components/ui-combobox/ui-combobox.js +17 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/styles/ui-badge.css +15 -1
- package/vanilla/UiCombobox.d.ts +2 -0
- package/vanilla/UiCombobox.js +1 -1
- package/vue/UiBadge.vue +13 -2
- package/vue/UiCombobox.d.ts +18 -0
- package/vue/UiCombobox.vue +39 -0
- package/vue/chunks/UiBadge.js +2 -2
- package/vue/chunks/UiCombobox.js +46 -1
- package/vue/components.css +98 -87
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<defs>
|
|
3
3
|
<prop name="variant" type="keyword" values="solid, subtle, outline" default="subtle"
|
|
4
4
|
>Emphasis. subtle sets toned text over a soft wash; solid fills with the tone and uses contrasting text; outline keeps the surface with a toned edge.
|
|
5
|
-
Neutral looks the same in solid and subtle.</prop>
|
|
5
|
+
Neutral looks the same in solid and subtle. When space is constrained, the label truncates with an ellipsis while its full text remains available.</prop>
|
|
6
6
|
<prop name="tone" type="keyword" values="neutral, accent, info, success, warning, danger" default="neutral"
|
|
7
7
|
>Which colour the badge speaks in. neutral is a quiet grey for plain labels; accent draws the eye in the accent colour; info, success, warning, and danger
|
|
8
8
|
mark a status, so match the tone to what the badge says. For a category rather than a status, set the --ui-badge-color hook on the badge instead: any CSS
|
|
@@ -89,7 +89,9 @@
|
|
|
89
89
|
display: inline-flex;
|
|
90
90
|
align-items: center;
|
|
91
91
|
justify-content: center;
|
|
92
|
-
|
|
92
|
+
box-sizing: border-box;
|
|
93
|
+
min-inline-size: 0;
|
|
94
|
+
max-inline-size: 100%;
|
|
93
95
|
padding: var(--ui-badge-padding-block, var(--ui-space-0-5)) var(--ui-badge-padding-inline, var(--ui-space-2));
|
|
94
96
|
border: var(--ui-border-width) solid var(--ui-badge-border, var(--_badge-color-border, var(--_badge-border)));
|
|
95
97
|
border-radius: var(--ui-radius-round);
|
|
@@ -102,6 +104,15 @@
|
|
|
102
104
|
white-space: nowrap;
|
|
103
105
|
}
|
|
104
106
|
|
|
107
|
+
/* A constrained badge keeps its surface intact and ellipsizes only its label. The full
|
|
108
|
+
text stays in the DOM for accessible names and consumers' selected values. */
|
|
109
|
+
.label {
|
|
110
|
+
display: block;
|
|
111
|
+
min-inline-size: 0;
|
|
112
|
+
overflow: hidden;
|
|
113
|
+
text-overflow: ellipsis;
|
|
114
|
+
}
|
|
115
|
+
|
|
105
116
|
/* Centre the glyphs, not the line box: a label without descenders otherwise reads high.
|
|
106
117
|
* Trimming applies to block containers; an inline-block is one and, like the inline-flex it
|
|
107
118
|
* replaces, still sizes to its label rather than filling its container. */
|
|
@@ -54,6 +54,12 @@
|
|
|
54
54
|
>How the list narrows as the user types. label lists the options whose label contains the typed text, ignoring case. none lists every authored option, for
|
|
55
55
|
options already narrowed elsewhere, such as a server search, so a result that matched on data other than its label still shows. Leaving the field still
|
|
56
56
|
commits an option whose label matches the text, or the only one listed.</prop>
|
|
57
|
+
<prop name="autoHighlight" type="keyword" values="none, single" default="none"
|
|
58
|
+
>single highlights the only enabled authored suggestion while typing. Ambiguous results and an empty query stay unhighlighted. none preserves manual
|
|
59
|
+
highlighting with the arrow keys.</prop>
|
|
60
|
+
<prop name="selectOnTab" type="boolean" default="false"
|
|
61
|
+
>Commits a highlighted authored suggestion on forward Tab, then lets focus advance normally. In multiple mode a selected suggestion is retained without
|
|
62
|
+
duplication or removal. Shift+Tab does not commit, and Tab never chooses the create offer.</prop>
|
|
57
63
|
<prop name="allowFreeText" type="boolean" default="false">Allows values that do not match an authored option.</prop>
|
|
58
64
|
<prop name="allowCreate" type="boolean" default="false"
|
|
59
65
|
>Offers the current query as a new option, reported as create-item. When nothing else matches, the offer is highlighted, so Enter creates it; with nothing
|
|
@@ -174,6 +174,10 @@ export default function controller(host) {
|
|
|
174
174
|
// When nothing matches what was typed, the offer to create it is the only choice, so it is
|
|
175
175
|
// the one Enter makes, and it is highlighted as such.
|
|
176
176
|
if (query && !host.state.rows.some((row) => !row.disabled) && canCreate()) host.state.active = host.state.rows.length;
|
|
177
|
+
if (query && host.props.autoHighlight.value === "single") {
|
|
178
|
+
const enabled = host.state.rows.flatMap((row, index) => row.disabled ? [] : [index]);
|
|
179
|
+
if (enabled.length === 1) host.state.active = enabled[0];
|
|
180
|
+
}
|
|
177
181
|
// Options in their declared shape: a row's `selected` flag is the list's own view state.
|
|
178
182
|
host.dispatch("options-change", host.state.rows.map(asItem));
|
|
179
183
|
};
|
|
@@ -441,7 +445,19 @@ export default function controller(host) {
|
|
|
441
445
|
if (!host.state.raw && (input.selectionStart ?? 0) === 0 && event.key === "Backspace" && items().length) { event.preventDefault(); removeItemAt(items().length - 1, "keyboard"); return; }
|
|
442
446
|
}
|
|
443
447
|
if (event.key === "Escape" && host.state.expanded) { event.preventDefault(); event.stopPropagation(); close(); }
|
|
444
|
-
else if (event.key === "Tab") {
|
|
448
|
+
else if (event.key === "Tab") {
|
|
449
|
+
const highlighted = host.state.expanded ? (host.state.rows ?? [])[host.state.active] : undefined;
|
|
450
|
+
if (host.props.selectOnTab.value && !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey && highlighted && !highlighted.disabled) {
|
|
451
|
+
if (host.props.multiple.value) {
|
|
452
|
+
setMultiQuery("", "keyboard");
|
|
453
|
+
if (!selectedSet().has(highlighted.value)) addSelectedItem(highlighted, "keyboard");
|
|
454
|
+
} else {
|
|
455
|
+
commit(highlighted.value, highlighted.label, asItem(highlighted), "selection", "keyboard");
|
|
456
|
+
queueMicrotask(() => void validateCurrent());
|
|
457
|
+
}
|
|
458
|
+
} else if (!host.props.selectOnTab.value) resolveTyped("keyboard");
|
|
459
|
+
close();
|
|
460
|
+
}
|
|
445
461
|
else if (!event.altKey && !event.ctrlKey && !event.metaKey && !event.shiftKey && ["ArrowDown", "ArrowUp"].includes(event.key)) { event.preventDefault(); if (!host.state.expanded) open("disclosure"); move(event.key); }
|
|
446
462
|
else if (["Home", "End"].includes(event.key) && host.state.expanded && host.state.active >= 0) { event.preventDefault(); move(event.key); }
|
|
447
463
|
else if (event.key === "Enter" && host.state.expanded) {
|