@threadlabs/looma 0.13.6 → 0.14.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/components/ui-button/ui-button.html +2 -1
- package/components/ui-checkbox/ui-checkbox.html +35 -0
- package/components/ui-combobox/ui-combobox.html +38 -3
- package/components/ui-description-list/ui-description-list.html +54 -9
- package/components/ui-input/ui-input.html +27 -0
- package/components/ui-input-group/ui-input-group.html +15 -0
- package/components/ui-radio/ui-radio.html +35 -0
- package/components/ui-select/ui-select.html +29 -3
- package/components/ui-switch/ui-switch.html +36 -0
- package/components/ui-table/ui-table.html +131 -0
- package/components/ui-table/ui-table.js +55 -0
- package/components/ui-textarea/ui-textarea.html +20 -0
- package/dist/index.js +8 -7
- package/package.json +1 -1
- package/styles/ui-button.css +3 -1
- package/styles/ui-checkbox.css +38 -0
- package/styles/ui-combobox.css +38 -1
- package/styles/ui-description-list.css +52 -7
- package/styles/ui-input-group.css +20 -0
- package/styles/ui-input.css +29 -0
- package/styles/ui-radio.css +38 -0
- package/styles/ui-select.css +29 -3
- package/styles/ui-switch.css +41 -0
- package/styles/ui-table.css +134 -0
- package/styles/ui-textarea.css +21 -0
- package/vanilla/UiCheckbox.d.ts +1 -0
- package/vanilla/UiCheckbox.js +1 -1
- package/vanilla/UiCombobox.d.ts +1 -1
- package/vanilla/UiCombobox.js +1 -1
- package/vanilla/UiDescriptionList.d.ts +3 -1
- package/vanilla/UiDescriptionList.js +6 -2
- package/vanilla/UiInput.d.ts +1 -0
- package/vanilla/UiInput.js +1 -1
- package/vanilla/UiRadio.d.ts +1 -0
- package/vanilla/UiRadio.js +1 -1
- package/vanilla/UiSelect.d.ts +1 -0
- package/vanilla/UiSelect.js +1 -1
- package/vanilla/UiSwitch.d.ts +1 -0
- package/vanilla/UiSwitch.js +1 -1
- package/vanilla/UiTable.d.ts +15 -0
- package/vanilla/UiTable.js +30 -0
- package/vanilla/UiTextarea.d.ts +1 -0
- package/vanilla/UiTextarea.js +1 -1
- package/vanilla/index.js +1 -0
- package/vue/UiButton.vue +2 -1
- package/vue/UiCheckbox.d.ts +2 -0
- package/vue/UiCheckbox.vue +34 -0
- package/vue/UiCombobox.d.ts +2 -2
- package/vue/UiCombobox.vue +39 -2
- package/vue/UiDescriptionList.d.ts +5 -2
- package/vue/UiDescriptionList.vue +51 -7
- package/vue/UiInput.d.ts +2 -0
- package/vue/UiInput.vue +41 -0
- package/vue/UiInputGroup.vue +15 -0
- package/vue/UiList.d.ts +1 -1
- package/vue/UiRadio.d.ts +2 -0
- package/vue/UiRadio.vue +34 -0
- package/vue/UiSelect.d.ts +2 -0
- package/vue/UiSelect.vue +34 -3
- package/vue/UiSwitch.d.ts +2 -0
- package/vue/UiSwitch.vue +35 -0
- package/vue/UiTable.d.ts +20 -0
- package/vue/UiTable.js +2 -0
- package/vue/UiTable.vue +172 -0
- package/vue/UiTextarea.d.ts +2 -0
- package/vue/UiTextarea.vue +27 -0
- package/vue/chunks/UiButton.js +1 -1
- package/vue/chunks/UiCheckbox.js +3 -2
- package/vue/chunks/UiCombobox.js +1 -1
- package/vue/chunks/UiDescriptionList.js +11 -3
- package/vue/chunks/UiInput.js +7 -2
- package/vue/chunks/UiInputGroup.js +1 -1
- package/vue/chunks/UiRadio.js +3 -2
- package/vue/chunks/UiSelect.js +7 -2
- package/vue/chunks/UiSwitch.js +3 -2
- package/vue/chunks/UiTable.js +40 -0
- package/vue/chunks/UiTextarea.js +7 -2
- package/vue/components.css +522 -174
- package/vue/index.d.ts +1 -0
- package/vue/index.js +2 -1
package/vanilla/index.js
CHANGED
|
@@ -55,6 +55,7 @@ export * from "./UiStack.js";
|
|
|
55
55
|
export * from "./UiStatusMessage.js";
|
|
56
56
|
export * from "./UiSwitch.js";
|
|
57
57
|
export * from "./UiSwitcher.js";
|
|
58
|
+
export * from "./UiTable.js";
|
|
58
59
|
export * from "./UiTabs.js";
|
|
59
60
|
export * from "./UiText.js";
|
|
60
61
|
export * from "./UiTextarea.js";
|
package/vue/UiButton.vue
CHANGED
|
@@ -357,8 +357,9 @@ function attribute(value: unknown): any {
|
|
|
357
357
|
border-color: transparent;
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
/* The size states outrank :host, so sm is named too, or a small button would stay small. */
|
|
360
361
|
@media (pointer: coarse) {
|
|
361
|
-
[data-component~="ui-button"] {
|
|
362
|
+
[data-component~="ui-button"], [data-component~="ui-button"][data-ui-button-state~="size=sm"] {
|
|
362
363
|
min-block-size: var(--ui-control-min-block-size);
|
|
363
364
|
}
|
|
364
365
|
}
|
package/vue/UiCheckbox.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ type __VLS_Props = {
|
|
|
4
4
|
indeterminate?: boolean;
|
|
5
5
|
name?: string;
|
|
6
6
|
required?: boolean;
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
8
|
value?: string;
|
|
8
9
|
};
|
|
9
10
|
declare var __VLS_1: {}, __VLS_3: {};
|
|
@@ -30,6 +31,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
30
31
|
"onUpdate:value"?: ((value: string) => any) | undefined;
|
|
31
32
|
}>, {
|
|
32
33
|
name: string;
|
|
34
|
+
size: "sm" | "md" | "lg";
|
|
33
35
|
value: string;
|
|
34
36
|
disabled: boolean;
|
|
35
37
|
checked: boolean;
|
package/vue/UiCheckbox.vue
CHANGED
|
@@ -13,6 +13,7 @@ const props = withDefaults(
|
|
|
13
13
|
indeterminate?: boolean
|
|
14
14
|
name?: string
|
|
15
15
|
required?: boolean
|
|
16
|
+
size?: 'sm' | 'md' | 'lg'
|
|
16
17
|
value?: string
|
|
17
18
|
}>(),
|
|
18
19
|
{
|
|
@@ -21,6 +22,7 @@ const props = withDefaults(
|
|
|
21
22
|
indeterminate: false,
|
|
22
23
|
name: '',
|
|
23
24
|
required: false,
|
|
25
|
+
size: 'md',
|
|
24
26
|
value: 'on',
|
|
25
27
|
},
|
|
26
28
|
)
|
|
@@ -45,6 +47,7 @@ const internalChecked = ref(false)
|
|
|
45
47
|
const hostState = computed(() =>
|
|
46
48
|
[
|
|
47
49
|
props.disabled && 'disabled',
|
|
50
|
+
props.size && `size size=${props.size}`,
|
|
48
51
|
].filter(Boolean).join(' ')
|
|
49
52
|
)
|
|
50
53
|
|
|
@@ -215,6 +218,37 @@ input:focus-visible {
|
|
|
215
218
|
cursor: not-allowed;
|
|
216
219
|
}
|
|
217
220
|
|
|
221
|
+
/* A sized choice keeps its box and aligns instead: the label takes that size's field type size,
|
|
222
|
+
and the first line centres in that control height, so the label shares a row's baseline.
|
|
223
|
+
Multi-line labels and descriptions still grow downward from that first line. */
|
|
224
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=sm"] {
|
|
225
|
+
--_font: var(--ui-font-size-sm);
|
|
226
|
+
--_row: var(--ui-control-size-sm);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=lg"] {
|
|
230
|
+
--_font: var(--ui-font-size-md);
|
|
231
|
+
--_row: var(--ui-control-size-lg);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=sm"],
|
|
235
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=lg"] {
|
|
236
|
+
--_line: calc(var(--_font) * var(--ui-line-height-md));
|
|
237
|
+
font-size: var(--_font);
|
|
238
|
+
padding-block: calc((var(--_row) - var(--_line)) / 2);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=sm"] input,
|
|
242
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=lg"] input {
|
|
243
|
+
margin-top: calc((var(--_line) - var(--_ui-checkbox-size, 1.125rem)) / 2);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@media (pointer: coarse) {
|
|
247
|
+
[data-component~="ui-checkbox"][data-ui-checkbox-state~="size=sm"] {
|
|
248
|
+
--_row: var(--ui-control-min-block-size);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
218
252
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
219
253
|
[data-component~="ui-checkbox"][hidden] {
|
|
220
254
|
display: none;
|
package/vue/UiCombobox.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ type __VLS_Props = {
|
|
|
21
21
|
readonly?: boolean;
|
|
22
22
|
required?: boolean;
|
|
23
23
|
selectedValues?: readonly (string)[];
|
|
24
|
-
size?: 'sm' | 'md';
|
|
24
|
+
size?: 'sm' | 'md' | 'lg';
|
|
25
25
|
tokenSeparators?: readonly (string)[];
|
|
26
26
|
value?: string | null;
|
|
27
27
|
};
|
|
@@ -247,7 +247,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {
|
|
|
247
247
|
}>, {
|
|
248
248
|
label: string;
|
|
249
249
|
name: string;
|
|
250
|
-
size: "sm" | "md";
|
|
250
|
+
size: "sm" | "md" | "lg";
|
|
251
251
|
disabled: boolean;
|
|
252
252
|
required: boolean;
|
|
253
253
|
allowCreate: boolean;
|
package/vue/UiCombobox.vue
CHANGED
|
@@ -33,7 +33,7 @@ const props = withDefaults(
|
|
|
33
33
|
readonly?: boolean
|
|
34
34
|
required?: boolean
|
|
35
35
|
selectedValues?: readonly (string)[]
|
|
36
|
-
size?: 'sm' | 'md'
|
|
36
|
+
size?: 'sm' | 'md' | 'lg'
|
|
37
37
|
tokenSeparators?: readonly (string)[]
|
|
38
38
|
value?: string | null
|
|
39
39
|
}>(),
|
|
@@ -834,9 +834,18 @@ input {
|
|
|
834
834
|
margin: 0;
|
|
835
835
|
outline: none;
|
|
836
836
|
}
|
|
837
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"] {
|
|
838
|
+
--_row: var(--ui-control-size-sm);
|
|
839
|
+
}
|
|
837
840
|
[data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"] input {
|
|
838
|
-
min-block-size: calc(var(--
|
|
841
|
+
min-block-size: calc(var(--_row) - 2px);
|
|
839
842
|
padding: var(--ui-space-1) var(--ui-space-2);
|
|
843
|
+
font-size: var(--ui-font-size-sm);
|
|
844
|
+
}
|
|
845
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="size=lg"] input {
|
|
846
|
+
min-block-size: calc(var(--ui-control-size-lg) - 2px);
|
|
847
|
+
padding: var(--ui-space-3) var(--ui-space-4);
|
|
848
|
+
font-size: var(--ui-font-size-md);
|
|
840
849
|
}
|
|
841
850
|
button {
|
|
842
851
|
appearance: none;
|
|
@@ -937,6 +946,14 @@ input:disabled, button:disabled {
|
|
|
937
946
|
min-inline-size: 2.75rem;
|
|
938
947
|
min-block-size: 2.75rem;
|
|
939
948
|
}
|
|
949
|
+
/* Under touch a small field is still a touch-sized target, as a small button is, and keeps
|
|
950
|
+
body-size text: below 16px, iOS zooms the page into the focused field. */
|
|
951
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"] {
|
|
952
|
+
--_row: var(--ui-control-min-block-size);
|
|
953
|
+
}
|
|
954
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"] input {
|
|
955
|
+
font-size: inherit;
|
|
956
|
+
}
|
|
940
957
|
}
|
|
941
958
|
@media (forced-colors: active) {
|
|
942
959
|
.field, .popup {
|
|
@@ -995,6 +1012,26 @@ input:disabled, button:disabled {
|
|
|
995
1012
|
min-block-size: 1.75rem;
|
|
996
1013
|
padding: var(--ui-space-0-5) var(--ui-space-1);
|
|
997
1014
|
}
|
|
1015
|
+
/* A small multiple field starts at the small control height; chosen items still wrap it taller. */
|
|
1016
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="multiple"][data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"]
|
|
1017
|
+
.field {
|
|
1018
|
+
min-block-size: 0;
|
|
1019
|
+
padding: var(--ui-space-0-5);
|
|
1020
|
+
}
|
|
1021
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="multiple"][data-component~="ui-combobox"][data-ui-combobox-state~="size=sm"]
|
|
1022
|
+
input {
|
|
1023
|
+
min-block-size: calc(var(--_row) - 2px - 2 * var(--ui-space-0-5));
|
|
1024
|
+
padding: 0 var(--ui-space-1);
|
|
1025
|
+
}
|
|
1026
|
+
/* A large multiple field starts at the large control height, as sm starts at the small one. */
|
|
1027
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="multiple"][data-component~="ui-combobox"][data-ui-combobox-state~="size=lg"]
|
|
1028
|
+
.field {
|
|
1029
|
+
min-block-size: 0;
|
|
1030
|
+
}
|
|
1031
|
+
[data-component~="ui-combobox"][data-ui-combobox-state~="multiple"][data-component~="ui-combobox"][data-ui-combobox-state~="size=lg"]
|
|
1032
|
+
input {
|
|
1033
|
+
min-block-size: calc(var(--ui-control-size-lg) - 2px - 2 * var(--ui-space-1));
|
|
1034
|
+
}
|
|
998
1035
|
.item {
|
|
999
1036
|
appearance: none;
|
|
1000
1037
|
display: inline-flex;
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
type __VLS_Props = {
|
|
2
|
-
|
|
2
|
+
columns?: '2' | '3' | '4';
|
|
3
|
+
density?: 'comfortable' | 'compact';
|
|
4
|
+
layout?: 'rows' | 'stacked' | 'grid' | 'tiles';
|
|
3
5
|
};
|
|
4
6
|
declare var __VLS_1: {};
|
|
5
7
|
type __VLS_Slots = {} & {
|
|
6
8
|
default?: (props: typeof __VLS_1) => any;
|
|
7
9
|
};
|
|
8
10
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
9
|
-
|
|
11
|
+
density: "comfortable" | "compact";
|
|
12
|
+
layout: "rows" | "stacked" | "grid" | "tiles";
|
|
10
13
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
14
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
12
15
|
declare const _default: typeof __VLS_export;
|
|
@@ -6,9 +6,12 @@ defineOptions({ inheritAttrs: false })
|
|
|
6
6
|
|
|
7
7
|
const props = withDefaults(
|
|
8
8
|
defineProps<{
|
|
9
|
-
|
|
9
|
+
columns?: '2' | '3' | '4'
|
|
10
|
+
density?: 'comfortable' | 'compact'
|
|
11
|
+
layout?: 'rows' | 'stacked' | 'grid' | 'tiles'
|
|
10
12
|
}>(),
|
|
11
13
|
{
|
|
14
|
+
density: 'comfortable',
|
|
12
15
|
layout: 'rows',
|
|
13
16
|
},
|
|
14
17
|
)
|
|
@@ -17,6 +20,8 @@ const props = withDefaults(
|
|
|
17
20
|
const hostState = computed(() =>
|
|
18
21
|
[
|
|
19
22
|
props.layout && `layout layout=${props.layout}`,
|
|
23
|
+
props.columns && `columns columns=${props.columns}`,
|
|
24
|
+
props.density && `density density=${props.density}`,
|
|
20
25
|
].filter(Boolean).join(' ')
|
|
21
26
|
)
|
|
22
27
|
</script>
|
|
@@ -35,24 +40,63 @@ const hostState = computed(() =>
|
|
|
35
40
|
/* Named values: a term and what it is, for each item (ui-description-item). */
|
|
36
41
|
/* Rows line every term up in one column and every value in the next, through subgrid. */
|
|
37
42
|
[data-component~="ui-description-list"] {
|
|
43
|
+
--_gap: var(--ui-space-2);
|
|
44
|
+
--_gap-compact: var(--ui-space-1);
|
|
45
|
+
--_column-gap: var(--ui-space-6);
|
|
46
|
+
--_min: 10rem;
|
|
47
|
+
--_track: var(--_min);
|
|
48
|
+
--_tile-padding: var(--ui-space-3);
|
|
38
49
|
display: grid;
|
|
39
50
|
grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
|
|
40
|
-
gap: var(--
|
|
51
|
+
gap: var(--_gap) var(--_column-gap);
|
|
41
52
|
min-inline-size: 0;
|
|
42
53
|
margin: 0;
|
|
43
54
|
}
|
|
44
55
|
|
|
45
|
-
/*
|
|
56
|
+
/* Stacked, grid, and tiles set each term above its value, passing the shape to the items through
|
|
57
|
+
private properties, which cross into each item. */
|
|
58
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=stacked"],
|
|
59
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=grid"],
|
|
46
60
|
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=tiles"] {
|
|
47
61
|
--_ui-description-display: flex;
|
|
48
62
|
--_ui-description-column: auto;
|
|
63
|
+
--_ui-description-align: stretch;
|
|
64
|
+
--_gap: var(--ui-space-4);
|
|
65
|
+
--_gap-compact: var(--ui-space-2);
|
|
66
|
+
grid-template-columns: minmax(0, 1fr);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* A column is at least --_min wide; with columns set, at least its share of the width, so no more
|
|
70
|
+
than that many fit. */
|
|
71
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=grid"],
|
|
72
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=tiles"] {
|
|
73
|
+
grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_track)), 1fr));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="layout=tiles"] {
|
|
49
77
|
--_ui-description-align: flex-start;
|
|
50
78
|
--_ui-description-value-size: var(--ui-font-size-lg);
|
|
51
|
-
--_ui-description-padding: var(--
|
|
79
|
+
--_ui-description-padding: var(--_tile-padding);
|
|
52
80
|
--_ui-description-border-width: 1px;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
gap: var(--
|
|
81
|
+
--_gap: var(--ui-space-3);
|
|
82
|
+
--_gap-compact: var(--ui-space-2);
|
|
83
|
+
--_column-gap: var(--_gap);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="columns=2"] {
|
|
87
|
+
--_track: max(var(--_min), (100% - var(--_column-gap)) / 2);
|
|
88
|
+
}
|
|
89
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="columns=3"] {
|
|
90
|
+
--_track: max(var(--_min), (100% - 2 * var(--_column-gap)) / 3);
|
|
91
|
+
}
|
|
92
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="columns=4"] {
|
|
93
|
+
--_track: max(var(--_min), (100% - 3 * var(--_column-gap)) / 4);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Compact takes each layout's closer spacing. */
|
|
97
|
+
[data-component~="ui-description-list"][data-ui-description-list-state~="density=compact"] {
|
|
98
|
+
--_gap: var(--_gap-compact);
|
|
99
|
+
--_tile-padding: var(--ui-space-2);
|
|
56
100
|
}
|
|
57
101
|
|
|
58
102
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
package/vue/UiInput.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ type __VLS_Props = {
|
|
|
3
3
|
invalid?: boolean;
|
|
4
4
|
readonly?: boolean;
|
|
5
5
|
required?: boolean;
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
7
|
value?: string;
|
|
7
8
|
modelValue?: string | null;
|
|
8
9
|
};
|
|
@@ -12,6 +13,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
12
13
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
13
14
|
}>, {
|
|
14
15
|
invalid: boolean;
|
|
16
|
+
size: "sm" | "md" | "lg";
|
|
15
17
|
disabled: boolean;
|
|
16
18
|
required: boolean;
|
|
17
19
|
readonly: boolean;
|
package/vue/UiInput.vue
CHANGED
|
@@ -12,6 +12,7 @@ const props = withDefaults(
|
|
|
12
12
|
invalid?: boolean
|
|
13
13
|
readonly?: boolean
|
|
14
14
|
required?: boolean
|
|
15
|
+
size?: 'sm' | 'md' | 'lg'
|
|
15
16
|
value?: string
|
|
16
17
|
modelValue?: string | null
|
|
17
18
|
}>(),
|
|
@@ -20,6 +21,7 @@ const props = withDefaults(
|
|
|
20
21
|
invalid: false,
|
|
21
22
|
readonly: false,
|
|
22
23
|
required: false,
|
|
24
|
+
size: 'md',
|
|
23
25
|
},
|
|
24
26
|
)
|
|
25
27
|
const emit = defineEmits<{
|
|
@@ -32,6 +34,13 @@ const model = computed({
|
|
|
32
34
|
|
|
33
35
|
const root = ref<HTMLElement | null>(null)
|
|
34
36
|
|
|
37
|
+
/** The values the styles' :host-state() rules test. */
|
|
38
|
+
const hostState = computed(() =>
|
|
39
|
+
[
|
|
40
|
+
props.size && `size size=${props.size}`,
|
|
41
|
+
].filter(Boolean).join(' ')
|
|
42
|
+
)
|
|
43
|
+
|
|
35
44
|
const dispatch = createDispatch(root)
|
|
36
45
|
|
|
37
46
|
useComponentHost(controllerModule.default, {
|
|
@@ -50,6 +59,7 @@ useComponentHost(controllerModule.default, {
|
|
|
50
59
|
:required="required"
|
|
51
60
|
:aria-invalid="invalid"
|
|
52
61
|
v-model="model"
|
|
62
|
+
:data-ui-input-state="hostState || undefined"
|
|
53
63
|
ref="root"
|
|
54
64
|
>
|
|
55
65
|
</template>
|
|
@@ -138,6 +148,37 @@ useComponentHost(controllerModule.default, {
|
|
|
138
148
|
background-color var(--ui-motion-fast) var(--ui-motion-ease);
|
|
139
149
|
}
|
|
140
150
|
|
|
151
|
+
/* Each size reads the hook and then an Input Group's default first, so a group, which draws the frame, can zero it. */
|
|
152
|
+
[data-component~="ui-input"][data-ui-input-state~="size=sm"] {
|
|
153
|
+
min-block-size: var(
|
|
154
|
+
--ui-input-min-block-size,
|
|
155
|
+
var(--_ui-default-input-min-block-size, var(--ui-control-size-sm))
|
|
156
|
+
);
|
|
157
|
+
padding: var(--ui-space-1) var(--ui-space-2);
|
|
158
|
+
font-size: var(--ui-font-size-sm);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
[data-component~="ui-input"][data-ui-input-state~="size=lg"] {
|
|
162
|
+
min-block-size: var(
|
|
163
|
+
--ui-input-min-block-size,
|
|
164
|
+
var(--_ui-default-input-min-block-size, var(--ui-control-size-lg))
|
|
165
|
+
);
|
|
166
|
+
padding: var(--ui-space-3) var(--ui-space-4);
|
|
167
|
+
font-size: var(--ui-font-size-md);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Under touch a small field is still a touch-sized target, as a small button is, and keeps
|
|
171
|
+
body-size text: below 16px, iOS zooms the page into the focused field. */
|
|
172
|
+
@media (pointer: coarse) {
|
|
173
|
+
[data-component~="ui-input"][data-ui-input-state~="size=sm"] {
|
|
174
|
+
min-block-size: var(
|
|
175
|
+
--ui-input-min-block-size,
|
|
176
|
+
var(--_ui-default-input-min-block-size, var(--ui-control-min-block-size))
|
|
177
|
+
);
|
|
178
|
+
font-size: inherit;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
141
182
|
/* Tabbing into a field selects its text; tint that selection softly instead of the page highlight. */
|
|
142
183
|
[data-component~="ui-input"]::selection {
|
|
143
184
|
background: color-mix(in srgb, var(--ui-accent-solid) 20%, transparent);
|
package/vue/UiInputGroup.vue
CHANGED
|
@@ -91,6 +91,21 @@ useComponentHost(controllerModule.default, {
|
|
|
91
91
|
box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
/* The frame takes its input's size, so a small group lines up with small buttons and fields. */
|
|
95
|
+
[data-component~="ui-input-group"]:has(.field [data-ui-input-state~="size=sm"]) {
|
|
96
|
+
min-block-size: var(--ui-control-size-sm);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
[data-component~="ui-input-group"]:has(.field [data-ui-input-state~="size=lg"]) {
|
|
100
|
+
min-block-size: var(--ui-control-size-lg);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@media (pointer: coarse) {
|
|
104
|
+
[data-component~="ui-input-group"]:has(.field [data-ui-input-state~="size=sm"]) {
|
|
105
|
+
min-block-size: var(--ui-control-min-block-size);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
94
109
|
[data-component~="ui-input-group"]:hover:not(:has(input:focus, input:disabled)) {
|
|
95
110
|
border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
|
|
96
111
|
}
|
package/vue/UiList.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ type __VLS_Slots = {} & {
|
|
|
7
7
|
default?: (props: typeof __VLS_1) => any;
|
|
8
8
|
};
|
|
9
9
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
10
|
-
layout: "rows" | "grid";
|
|
11
10
|
density: "comfortable" | "compact";
|
|
11
|
+
layout: "rows" | "grid";
|
|
12
12
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
13
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
14
|
declare const _default: typeof __VLS_export;
|
package/vue/UiRadio.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ type __VLS_Props = {
|
|
|
3
3
|
disabled?: boolean;
|
|
4
4
|
name?: string;
|
|
5
5
|
required?: boolean;
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
7
|
value?: string;
|
|
7
8
|
};
|
|
8
9
|
declare var __VLS_1: {}, __VLS_3: {};
|
|
@@ -29,6 +30,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
29
30
|
"onUpdate:value"?: ((value: string) => any) | undefined;
|
|
30
31
|
}>, {
|
|
31
32
|
name: string;
|
|
33
|
+
size: "sm" | "md" | "lg";
|
|
32
34
|
value: string;
|
|
33
35
|
disabled: boolean;
|
|
34
36
|
checked: boolean;
|
package/vue/UiRadio.vue
CHANGED
|
@@ -12,6 +12,7 @@ const props = withDefaults(
|
|
|
12
12
|
disabled?: boolean
|
|
13
13
|
name?: string
|
|
14
14
|
required?: boolean
|
|
15
|
+
size?: 'sm' | 'md' | 'lg'
|
|
15
16
|
value?: string
|
|
16
17
|
}>(),
|
|
17
18
|
{
|
|
@@ -19,6 +20,7 @@ const props = withDefaults(
|
|
|
19
20
|
disabled: false,
|
|
20
21
|
name: '',
|
|
21
22
|
required: false,
|
|
23
|
+
size: 'md',
|
|
22
24
|
value: 'on',
|
|
23
25
|
},
|
|
24
26
|
)
|
|
@@ -43,6 +45,7 @@ const internalChecked = ref(false)
|
|
|
43
45
|
const hostState = computed(() =>
|
|
44
46
|
[
|
|
45
47
|
props.disabled && 'disabled',
|
|
48
|
+
props.size && `size size=${props.size}`,
|
|
46
49
|
].filter(Boolean).join(' ')
|
|
47
50
|
)
|
|
48
51
|
|
|
@@ -159,6 +162,37 @@ input:focus-visible {
|
|
|
159
162
|
cursor: not-allowed;
|
|
160
163
|
}
|
|
161
164
|
|
|
165
|
+
/* A sized choice keeps its box and aligns instead: the label takes that size's field type size,
|
|
166
|
+
and the first line centres in that control height, so the label shares a row's baseline.
|
|
167
|
+
Multi-line labels and descriptions still grow downward from that first line. */
|
|
168
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=sm"] {
|
|
169
|
+
--_font: var(--ui-font-size-sm);
|
|
170
|
+
--_row: var(--ui-control-size-sm);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=lg"] {
|
|
174
|
+
--_font: var(--ui-font-size-md);
|
|
175
|
+
--_row: var(--ui-control-size-lg);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=sm"],
|
|
179
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=lg"] {
|
|
180
|
+
--_line: calc(var(--_font) * var(--ui-line-height-md));
|
|
181
|
+
font-size: var(--_font);
|
|
182
|
+
padding-block: calc((var(--_row) - var(--_line)) / 2);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=sm"] input,
|
|
186
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=lg"] input {
|
|
187
|
+
margin-top: calc((var(--_line) - var(--_ui-radio-size, 1.125rem)) / 2);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@media (pointer: coarse) {
|
|
191
|
+
[data-component~="ui-radio"][data-ui-radio-state~="size=sm"] {
|
|
192
|
+
--_row: var(--ui-control-min-block-size);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
162
196
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
163
197
|
[data-component~="ui-radio"][hidden] {
|
|
164
198
|
display: none;
|
package/vue/UiSelect.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ type __VLS_Props = {
|
|
|
2
2
|
disabled?: boolean;
|
|
3
3
|
invalid?: boolean;
|
|
4
4
|
required?: boolean;
|
|
5
|
+
size?: 'sm' | 'md' | 'lg';
|
|
5
6
|
value?: string;
|
|
6
7
|
modelValue?: string | null;
|
|
7
8
|
};
|
|
@@ -15,6 +16,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
15
16
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
16
17
|
}>, {
|
|
17
18
|
invalid: boolean;
|
|
19
|
+
size: "sm" | "md" | "lg";
|
|
18
20
|
disabled: boolean;
|
|
19
21
|
required: boolean;
|
|
20
22
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
package/vue/UiSelect.vue
CHANGED
|
@@ -11,6 +11,7 @@ const props = withDefaults(
|
|
|
11
11
|
disabled?: boolean
|
|
12
12
|
invalid?: boolean
|
|
13
13
|
required?: boolean
|
|
14
|
+
size?: 'sm' | 'md' | 'lg'
|
|
14
15
|
value?: string
|
|
15
16
|
modelValue?: string | null
|
|
16
17
|
}>(),
|
|
@@ -18,6 +19,7 @@ const props = withDefaults(
|
|
|
18
19
|
disabled: false,
|
|
19
20
|
invalid: false,
|
|
20
21
|
required: false,
|
|
22
|
+
size: 'md',
|
|
21
23
|
},
|
|
22
24
|
)
|
|
23
25
|
const emit = defineEmits<{
|
|
@@ -30,6 +32,13 @@ const model = computed({
|
|
|
30
32
|
|
|
31
33
|
const root = ref<HTMLElement | null>(null)
|
|
32
34
|
|
|
35
|
+
/** The values the styles' :host-state() rules test. */
|
|
36
|
+
const hostState = computed(() =>
|
|
37
|
+
[
|
|
38
|
+
props.size && `size size=${props.size}`,
|
|
39
|
+
].filter(Boolean).join(' ')
|
|
40
|
+
)
|
|
41
|
+
|
|
33
42
|
const dispatch = createDispatch(root)
|
|
34
43
|
|
|
35
44
|
useComponentHost(controllerModule.default, {
|
|
@@ -47,6 +56,7 @@ useComponentHost(controllerModule.default, {
|
|
|
47
56
|
:required="required"
|
|
48
57
|
:aria-invalid="invalid"
|
|
49
58
|
v-model="model"
|
|
59
|
+
:data-ui-select-state="hostState || undefined"
|
|
50
60
|
ref="root"
|
|
51
61
|
>
|
|
52
62
|
<slot />
|
|
@@ -137,9 +147,30 @@ useComponentHost(controllerModule.default, {
|
|
|
137
147
|
cursor: not-allowed;
|
|
138
148
|
}
|
|
139
149
|
|
|
140
|
-
[data-component~="ui-select"][size
|
|
141
|
-
min-block-size:
|
|
142
|
-
padding: var(--ui-space-2);
|
|
150
|
+
[data-component~="ui-select"][data-ui-select-state~="size=sm"] {
|
|
151
|
+
min-block-size: var(--ui-control-size-sm);
|
|
152
|
+
padding: var(--ui-space-1) var(--ui-space-2);
|
|
153
|
+
padding-inline-end: calc(var(--ui-space-2) + var(--ui-icon-size-sm) + var(--ui-space-1));
|
|
154
|
+
background-position: right var(--ui-space-2) center;
|
|
155
|
+
background-size: var(--ui-icon-size-sm) var(--ui-icon-size-sm);
|
|
156
|
+
font-size: var(--ui-font-size-sm);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
[data-component~="ui-select"][data-ui-select-state~="size=lg"] {
|
|
160
|
+
min-block-size: var(--ui-control-size-lg);
|
|
161
|
+
padding: var(--ui-space-3) var(--ui-space-4);
|
|
162
|
+
padding-inline-end: calc(var(--ui-space-4) + 1.5rem);
|
|
163
|
+
background-position: right var(--ui-space-4) center;
|
|
164
|
+
font-size: var(--ui-font-size-md);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* Under touch a small field is still a touch-sized target, as a small button is, and keeps
|
|
168
|
+
body-size text: below 16px, iOS zooms the page into the focused field. */
|
|
169
|
+
@media (pointer: coarse) {
|
|
170
|
+
[data-component~="ui-select"][data-ui-select-state~="size=sm"] {
|
|
171
|
+
min-block-size: var(--ui-control-min-block-size);
|
|
172
|
+
font-size: inherit;
|
|
173
|
+
}
|
|
143
174
|
}
|
|
144
175
|
|
|
145
176
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
package/vue/UiSwitch.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ type __VLS_Props = {
|
|
|
3
3
|
disabled?: boolean;
|
|
4
4
|
name?: string;
|
|
5
5
|
required?: boolean;
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
6
7
|
value?: string;
|
|
7
8
|
};
|
|
8
9
|
declare var __VLS_1: {}, __VLS_3: {};
|
|
@@ -29,6 +30,7 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {},
|
|
|
29
30
|
"onUpdate:value"?: ((value: string) => any) | undefined;
|
|
30
31
|
}>, {
|
|
31
32
|
name: string;
|
|
33
|
+
size: "sm" | "md" | "lg";
|
|
32
34
|
value: string;
|
|
33
35
|
disabled: boolean;
|
|
34
36
|
checked: boolean;
|
package/vue/UiSwitch.vue
CHANGED
|
@@ -12,6 +12,7 @@ const props = withDefaults(
|
|
|
12
12
|
disabled?: boolean
|
|
13
13
|
name?: string
|
|
14
14
|
required?: boolean
|
|
15
|
+
size?: 'sm' | 'md' | 'lg'
|
|
15
16
|
value?: string
|
|
16
17
|
}>(),
|
|
17
18
|
{
|
|
@@ -19,6 +20,7 @@ const props = withDefaults(
|
|
|
19
20
|
disabled: false,
|
|
20
21
|
name: '',
|
|
21
22
|
required: false,
|
|
23
|
+
size: 'md',
|
|
22
24
|
value: 'on',
|
|
23
25
|
},
|
|
24
26
|
)
|
|
@@ -43,6 +45,7 @@ const internalChecked = ref(false)
|
|
|
43
45
|
const hostState = computed(() =>
|
|
44
46
|
[
|
|
45
47
|
props.disabled && 'disabled',
|
|
48
|
+
props.size && `size size=${props.size}`,
|
|
46
49
|
].filter(Boolean).join(' ')
|
|
47
50
|
)
|
|
48
51
|
|
|
@@ -206,6 +209,38 @@ input:focus-visible {
|
|
|
206
209
|
}
|
|
207
210
|
}
|
|
208
211
|
|
|
212
|
+
/* A sized switch keeps its track and aligns instead: the label takes that size's field type size,
|
|
213
|
+
and the first line centres in that control height, so the label shares a row's baseline.
|
|
214
|
+
Multi-line labels and descriptions still grow downward from that first line. */
|
|
215
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=sm"] {
|
|
216
|
+
--_font: var(--ui-font-size-sm);
|
|
217
|
+
--_row: var(--ui-control-size-sm);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=lg"] {
|
|
221
|
+
--_font: var(--ui-font-size-md);
|
|
222
|
+
--_row: var(--ui-control-size-lg);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=sm"],
|
|
226
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=lg"] {
|
|
227
|
+
--_line: calc(var(--_font) * var(--ui-line-height-md));
|
|
228
|
+
font-size: var(--_font);
|
|
229
|
+
padding-block: calc((var(--_row) - var(--ui-switch-track-height, 1.5rem)) / 2);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* The label centres on the track. */
|
|
233
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=sm"] .text,
|
|
234
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=lg"] .text {
|
|
235
|
+
margin-top: calc((var(--_ui-switch-track-height, 1.5rem) - var(--_line)) / 2);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@media (pointer: coarse) {
|
|
239
|
+
[data-component~="ui-switch"][data-ui-switch-state~="size=sm"] {
|
|
240
|
+
--_row: var(--ui-control-min-block-size);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
209
244
|
/* A component that sets its display still honours the hidden attribute on its root. */
|
|
210
245
|
[data-component~="ui-switch"][hidden] {
|
|
211
246
|
display: none;
|