@kerfjs/ui 5.0.0-beta.8 → 5.0.0-beta.9
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/README.md +20 -20
- package/ai/component-catalog.json +123 -80
- package/ai/public-api-signatures-v1.md +181 -26
- package/ai/skill.md +12 -12
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/list-action-row.js +4 -0
- package/dist/browser/{menu-header.js → list-header.js} +2 -2
- package/dist/browser/{menu-item.js → list-item.js} +2 -2
- package/dist/catalog.d.ts +119 -0
- package/dist/catalog.js +128 -0
- package/dist/catalog.js.map +1 -0
- package/dist/{chunk-BNQ2YDV4.js → chunk-2TS7ZSYX.js} +2 -2
- package/dist/{chunk-BNQ2YDV4.js.map → chunk-2TS7ZSYX.js.map} +1 -1
- package/dist/{chunk-PONXLV5U.js → chunk-37T3VNIZ.js} +1 -1
- package/dist/{chunk-PONXLV5U.js.map → chunk-37T3VNIZ.js.map} +1 -1
- package/dist/{chunk-3YD6ZNRA.js → chunk-7JB7VPRI.js} +8 -8
- package/dist/{chunk-3YD6ZNRA.js.map → chunk-7JB7VPRI.js.map} +1 -1
- package/dist/{chunk-YKUUZPED.js → chunk-L4OKFDJY.js} +7 -7
- package/dist/{chunk-YKUUZPED.js.map → chunk-L4OKFDJY.js.map} +1 -1
- package/dist/{chunk-H6URQGJI.js → chunk-W5EQ3HYQ.js} +11 -11
- package/dist/{chunk-H6URQGJI.js.map → chunk-W5EQ3HYQ.js.map} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +10 -10
- package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +7 -7
- package/dist/list-action-row.js +5 -0
- package/dist/list-action-row.js.map +1 -0
- package/dist/{menu-header.d.ts → list-header.d.ts} +9 -9
- package/dist/list-header.js +7 -0
- package/dist/list-header.js.map +1 -0
- package/dist/{menu-item.d.ts → list-item.d.ts} +5 -5
- package/dist/list-item.js +5 -0
- package/dist/list-item.js.map +1 -0
- package/dist/panel-header.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js.map +1 -1
- package/dist/styles/catalog.css +482 -0
- package/dist/styles/list-action-row.css +160 -0
- package/dist/styles/{menu-header.css → list-header.css} +33 -33
- package/dist/styles/list-item.css +123 -0
- package/dist/styles/styles.css +4 -3
- package/dist/value-table.js +1 -1
- package/dist/wire-catalog.d.ts +26 -0
- package/dist/wire-catalog.js +50 -0
- package/dist/wire-catalog.js.map +1 -0
- package/docs/accessibility.md +5 -5
- package/docs/catalog.md +154 -0
- package/docs/component-contract.md +12 -12
- package/docs/component-selection.md +12 -11
- package/docs/design-philosophy.md +4 -4
- package/docs/layout.md +8 -8
- package/docs/recipes.md +17 -5
- package/docs/split-view.md +1 -1
- package/docs/ux-demo.md +5 -5
- package/llms.txt +12 -8
- package/package.json +25 -16
- package/ux-demo/recipes/app-shell.tsx +3 -3
- package/ux-demo/recipes/list-detail-dialog.tsx +45 -0
- package/ux-demo/recipes/loaders.ts +4 -2
- package/ux-demo/recipes/loading-inspector.tsx +79 -0
- package/ux-demo/recipes/navigation-sidebar.tsx +5 -5
- package/ux-demo/recipes/navigation-stack.tsx +4 -4
- package/ux-demo/recipes/recipes.css +13 -7
- package/dist/browser/menu-action-row.js +0 -4
- package/dist/menu-action-row.js +0 -5
- package/dist/menu-action-row.js.map +0 -1
- package/dist/menu-header.js +0 -7
- package/dist/menu-header.js.map +0 -1
- package/dist/menu-item.js +0 -5
- package/dist/menu-item.js.map +0 -1
- package/dist/styles/menu-action-row.css +0 -160
- package/dist/styles/menu-item.css +0 -123
- package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
.kui-list-action-row {
|
|
2
|
+
--kui-list-action-row-color: var(--kui-color-neutral-on-normal);
|
|
3
|
+
--kui-list-action-row-border: transparent;
|
|
4
|
+
--kui-list-action-row-background: transparent;
|
|
5
|
+
--kui-list-action-row-hover-border: var(--kui-color-neutral-border-normal);
|
|
6
|
+
--kui-list-action-row-hover-background: var(--kui-color-neutral-fill-quiet);
|
|
7
|
+
--kui-list-action-row-selected-color: var(--kui-color-brand-on-quiet);
|
|
8
|
+
--kui-list-action-row-selected-border: var(--kui-color-brand-border-quiet);
|
|
9
|
+
--kui-list-action-row-selected-background: var(--kui-color-brand-fill-normal);
|
|
10
|
+
--kui-list-action-row-trailing-hover-background: var(
|
|
11
|
+
--kui-color-neutral-fill-normal
|
|
12
|
+
);
|
|
13
|
+
display: flex;
|
|
14
|
+
width: calc(100% - (2 * var(--kui-layout-inline-margin, 0.5rem)));
|
|
15
|
+
min-height: 2.75rem;
|
|
16
|
+
margin-inline: var(--kui-layout-inline-margin, 0.5rem);
|
|
17
|
+
border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
|
|
18
|
+
color: var(--kui-list-action-row-color);
|
|
19
|
+
background: var(--kui-list-action-row-background);
|
|
20
|
+
box-shadow: inset 0 0 0 1px var(--kui-list-action-row-border);
|
|
21
|
+
align-items: stretch;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.kui-list-action-row:has(.kui-list-action-row__primary:hover) {
|
|
25
|
+
--kui-list-action-row-border: var(--kui-list-action-row-hover-border);
|
|
26
|
+
--kui-list-action-row-background: var(--kui-list-action-row-hover-background);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.kui-list-action-row[data-selected="true"],
|
|
30
|
+
.kui-list-action-row[data-pressed="true"] {
|
|
31
|
+
--kui-list-action-row-border: var(--kui-list-action-row-selected-border);
|
|
32
|
+
--kui-list-action-row-background: var(
|
|
33
|
+
--kui-list-action-row-selected-background
|
|
34
|
+
);
|
|
35
|
+
color: var(--kui-list-action-row-selected-color);
|
|
36
|
+
font-weight: 650;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.kui-list-action-row:has(.kui-list-action-row__primary:focus-visible) {
|
|
40
|
+
outline: var(--kui-focus-ring);
|
|
41
|
+
outline-offset: 1px;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.kui-list-action-row__primary,
|
|
45
|
+
.kui-list-action-row__trailing-action {
|
|
46
|
+
height: auto !important;
|
|
47
|
+
min-height: 2.75rem;
|
|
48
|
+
padding: 0;
|
|
49
|
+
border: 0;
|
|
50
|
+
appearance: none;
|
|
51
|
+
color: inherit;
|
|
52
|
+
background: transparent;
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
font: inherit;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.kui-list-action-row__primary {
|
|
58
|
+
position: relative;
|
|
59
|
+
display: block;
|
|
60
|
+
flex: 1 1 auto;
|
|
61
|
+
min-width: 2.75rem;
|
|
62
|
+
padding: var(--kui-layout-item-padding, 0.5rem);
|
|
63
|
+
padding-inline-start: calc(1px + var(--kui-layout-item-padding, 0.5rem));
|
|
64
|
+
text-align: start;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.kui-list-action-row__primary:focus-visible {
|
|
68
|
+
outline: none;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.kui-list-action-row__primary:disabled,
|
|
72
|
+
.kui-list-action-row__trailing-action:disabled {
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
opacity: 0.58;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.kui-list-action-row__icon {
|
|
78
|
+
position: absolute;
|
|
79
|
+
inset-block-start: 50%;
|
|
80
|
+
inset-inline-start: calc(1px + var(--kui-layout-item-padding, 0.5rem));
|
|
81
|
+
display: grid;
|
|
82
|
+
width: 1.5rem;
|
|
83
|
+
height: 1.5rem;
|
|
84
|
+
color: currentColor;
|
|
85
|
+
transform: translateY(-50%);
|
|
86
|
+
place-items: center;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.kui-list-action-row__icon svg {
|
|
90
|
+
display: block;
|
|
91
|
+
width: 1.5rem;
|
|
92
|
+
height: 1.5rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.kui-list-action-row__label {
|
|
96
|
+
display: grid;
|
|
97
|
+
min-width: 0;
|
|
98
|
+
min-height: calc(
|
|
99
|
+
2.75rem - (2 * var(--kui-layout-item-padding, 0.5rem))
|
|
100
|
+
);
|
|
101
|
+
overflow: hidden;
|
|
102
|
+
text-overflow: ellipsis;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.kui-list-action-row[data-has-icon="true"] .kui-list-action-row__label {
|
|
108
|
+
margin-inline-start: calc(
|
|
109
|
+
1.5rem + var(--kui-layout-item-gap, 0.5rem)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.kui-list-action-row[data-multiline="true"] .kui-list-action-row__label {
|
|
114
|
+
display: block;
|
|
115
|
+
overflow: visible;
|
|
116
|
+
overflow-wrap: anywhere;
|
|
117
|
+
white-space: normal;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.kui-list-action-row[data-multiline="true"] .kui-list-action-row__icon {
|
|
121
|
+
inset-block-start: calc(
|
|
122
|
+
var(--kui-layout-item-padding, 0.5rem) + (1lh / 2)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.kui-list-action-row__trailing-action {
|
|
127
|
+
display: grid;
|
|
128
|
+
width: 2.75rem;
|
|
129
|
+
min-width: 2.75rem;
|
|
130
|
+
border-radius: var(--kui-radius-pill);
|
|
131
|
+
place-items: center;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.kui-list-action-row__trailing-action:hover:not(:disabled) {
|
|
135
|
+
background: var(--kui-list-action-row-trailing-hover-background);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.kui-list-action-row__trailing-action:focus-visible {
|
|
139
|
+
outline: var(--kui-focus-ring);
|
|
140
|
+
outline-offset: -2px;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.kui-list-action-row__trailing-action > svg {
|
|
144
|
+
width: 1rem;
|
|
145
|
+
height: 1rem;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
@media (forced-colors: active) {
|
|
149
|
+
.kui-list-action-row {
|
|
150
|
+
--kui-list-action-row-border: ButtonText;
|
|
151
|
+
outline: 1px solid ButtonText;
|
|
152
|
+
outline-offset: -1px;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.kui-list-action-row[data-selected="true"],
|
|
156
|
+
.kui-list-action-row[data-pressed="true"] {
|
|
157
|
+
--kui-list-action-row-selected-color: HighlightText;
|
|
158
|
+
--kui-list-action-row-selected-background: Highlight;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
.kui-
|
|
2
|
-
--kui-
|
|
3
|
-
--kui-
|
|
4
|
-
--_kui-
|
|
5
|
-
--kui-
|
|
1
|
+
.kui-list-header {
|
|
2
|
+
--kui-list-header-color: var(--kui-color-neutral-on-quiet);
|
|
3
|
+
--kui-list-header-hover-background: var(--kui-color-neutral-border-quiet);
|
|
4
|
+
--_kui-list-header-action-icon-size: var(
|
|
5
|
+
--kui-list-header-action-icon-size,
|
|
6
6
|
1.125rem
|
|
7
7
|
);
|
|
8
8
|
display: flex;
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
margin-inline: var(--kui-layout-inline-margin, 0.5rem);
|
|
13
13
|
padding: 0;
|
|
14
14
|
box-sizing: border-box;
|
|
15
|
-
color: var(--kui-
|
|
15
|
+
color: var(--kui-list-header-color);
|
|
16
16
|
background: transparent;
|
|
17
17
|
align-items: stretch;
|
|
18
18
|
gap: var(--kui-layout-item-gap, 0.5rem);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.kui-
|
|
22
|
-
.kui-
|
|
21
|
+
.kui-list-header__title,
|
|
22
|
+
.kui-list-header__action {
|
|
23
23
|
box-sizing: border-box;
|
|
24
24
|
border: 1px solid transparent;
|
|
25
25
|
border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
background: transparent;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
.kui-
|
|
30
|
+
.kui-list-header__title {
|
|
31
31
|
display: flex;
|
|
32
32
|
min-width: 0;
|
|
33
33
|
min-height: 2.75rem;
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
text-align: start;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
.kui-
|
|
42
|
+
.kui-list-header__label {
|
|
43
43
|
min-width: 0;
|
|
44
44
|
margin: 0;
|
|
45
45
|
overflow: hidden;
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
white-space: nowrap;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
.kui-
|
|
54
|
+
.kui-list-header__badge {
|
|
55
55
|
display: inline-flex;
|
|
56
56
|
min-height: 1.5rem;
|
|
57
57
|
padding-inline: var(--kui-layout-item-padding, 0.5rem);
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
line-height: 1;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
.kui-
|
|
69
|
+
.kui-list-header__count {
|
|
70
70
|
display: inline-grid;
|
|
71
71
|
min-width: 1.35rem;
|
|
72
72
|
height: 1.35rem;
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
place-items: center;
|
|
79
79
|
flex: none;
|
|
80
80
|
font-size: var(
|
|
81
|
-
--kui-
|
|
81
|
+
--kui-list-header-count-font-size,
|
|
82
82
|
var(--wa-font-size-3xs, 0.625rem)
|
|
83
83
|
);
|
|
84
84
|
font-weight: 700;
|
|
@@ -86,26 +86,26 @@
|
|
|
86
86
|
line-height: 1;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
.kui-
|
|
90
|
-
.kui-
|
|
89
|
+
.kui-list-header__action,
|
|
90
|
+
.kui-list-header__action-layer {
|
|
91
91
|
display: grid;
|
|
92
92
|
place-items: center;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
.kui-
|
|
95
|
+
.kui-list-header__action {
|
|
96
96
|
/* A fitted square: the icon size plus its padding and 1px border, instead of a
|
|
97
97
|
forced 44px box that left an oversized halo around the ~18px icon and, via the
|
|
98
98
|
parent's align-items: stretch, a vertically stretched oval. `align-self:
|
|
99
99
|
center` keeps it centered in the header's 44px row without stretching. Sizing
|
|
100
100
|
off the icon variable keeps it square and correct at any icon size. */
|
|
101
|
-
--_kui-
|
|
102
|
-
var(--_kui-
|
|
101
|
+
--_kui-list-header-action-size: calc(
|
|
102
|
+
var(--_kui-list-header-action-icon-size) +
|
|
103
103
|
(2 * var(--kui-layout-item-padding, 0.5rem)) + 2px
|
|
104
104
|
);
|
|
105
105
|
appearance: none;
|
|
106
106
|
display: inline-flex;
|
|
107
|
-
width: var(--_kui-
|
|
108
|
-
height: var(--_kui-
|
|
107
|
+
width: var(--_kui-list-header-action-size);
|
|
108
|
+
height: var(--_kui-list-header-action-size);
|
|
109
109
|
padding: var(--kui-layout-item-padding, 0.5rem);
|
|
110
110
|
align-items: center;
|
|
111
111
|
justify-content: center;
|
|
@@ -114,47 +114,47 @@
|
|
|
114
114
|
flex: none;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
.kui-
|
|
117
|
+
.kui-list-header__toggle {
|
|
118
118
|
appearance: none;
|
|
119
119
|
width: 100%;
|
|
120
120
|
cursor: pointer;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
.kui-
|
|
123
|
+
.kui-list-header__action-layer {
|
|
124
124
|
width: 1.5rem;
|
|
125
125
|
height: 1.5rem;
|
|
126
126
|
margin-inline-start: auto;
|
|
127
127
|
flex: none;
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
.kui-
|
|
131
|
-
.kui-
|
|
130
|
+
.kui-list-header__action:hover,
|
|
131
|
+
.kui-list-header__toggle:hover {
|
|
132
132
|
border-color: var(--kui-color-neutral-border-normal);
|
|
133
|
-
background: var(--kui-
|
|
133
|
+
background: var(--kui-list-header-hover-background);
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
.kui-
|
|
137
|
-
.kui-
|
|
136
|
+
.kui-list-header__action:focus-visible,
|
|
137
|
+
.kui-list-header__toggle:focus-visible {
|
|
138
138
|
outline: var(--kui-focus-ring);
|
|
139
139
|
outline-offset: 1px;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
.kui-
|
|
142
|
+
.kui-list-header__action:disabled {
|
|
143
143
|
cursor: not-allowed;
|
|
144
144
|
opacity: 0.48;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
.kui-
|
|
147
|
+
.kui-list-header__action:disabled:hover {
|
|
148
148
|
border-color: transparent;
|
|
149
149
|
background: transparent;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
.kui-
|
|
153
|
-
.kui-
|
|
152
|
+
.kui-list-header__action > svg,
|
|
153
|
+
.kui-list-header__action-layer > svg {
|
|
154
154
|
/* min-block-size: 0 overrides the flex item's automatic minimum, which would
|
|
155
155
|
otherwise resolve to the icon SVG's intrinsic 24px viewBox height and stretch
|
|
156
156
|
the button past its used icon size. */
|
|
157
|
-
width: var(--_kui-
|
|
158
|
-
height: var(--_kui-
|
|
157
|
+
width: var(--_kui-list-header-action-icon-size);
|
|
158
|
+
height: var(--_kui-list-header-action-icon-size);
|
|
159
159
|
min-block-size: 0;
|
|
160
160
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
.kui-list-item {
|
|
2
|
+
--kui-list-item-color: var(--kui-color-neutral-on-normal);
|
|
3
|
+
--kui-list-item-border: transparent;
|
|
4
|
+
--kui-list-item-background: transparent;
|
|
5
|
+
--kui-list-item-hover-border: var(--kui-color-neutral-border-normal);
|
|
6
|
+
--kui-list-item-hover-background: var(--kui-color-neutral-fill-quiet);
|
|
7
|
+
--kui-list-item-selected-color: var(--kui-color-brand-on-quiet);
|
|
8
|
+
--kui-list-item-selected-border: var(--kui-color-brand-border-quiet);
|
|
9
|
+
--kui-list-item-selected-background: var(--kui-color-brand-fill-normal);
|
|
10
|
+
display: grid;
|
|
11
|
+
width: calc(100% - (2 * var(--kui-layout-inline-margin, 0.5rem)));
|
|
12
|
+
min-height: 2.75rem;
|
|
13
|
+
margin-inline: var(--kui-layout-inline-margin, 0.5rem);
|
|
14
|
+
padding: var(--kui-layout-item-padding, 0.5rem);
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
border: 1px solid var(--kui-list-item-border);
|
|
17
|
+
border-radius: var(--kui-layout-rounded-radius, calc(1px + 0.6875rem));
|
|
18
|
+
color: var(--kui-list-item-color);
|
|
19
|
+
background: var(--kui-list-item-background);
|
|
20
|
+
cursor: pointer;
|
|
21
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
22
|
+
align-items: center;
|
|
23
|
+
column-gap: var(--kui-layout-item-gap, 0.5rem);
|
|
24
|
+
font: inherit;
|
|
25
|
+
text-align: start;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.kui-list-item[data-has-icon="true"] {
|
|
29
|
+
grid-template-columns: 1.5rem minmax(0, 1fr) auto;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.kui-list-item[data-has-icon="true"] .kui-list-item__icon {
|
|
33
|
+
grid-column: 1;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.kui-list-item[data-has-icon="true"] .kui-list-item__label {
|
|
37
|
+
grid-column: 2;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.kui-list-item[data-has-icon="true"] .kui-list-item__trailing {
|
|
41
|
+
grid-column: 3;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.kui-list-item[data-has-icon="false"] .kui-list-item__label {
|
|
45
|
+
grid-column: 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.kui-list-item[data-has-icon="false"] .kui-list-item__trailing {
|
|
49
|
+
grid-column: 2;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.kui-list-item:hover {
|
|
53
|
+
border-color: var(--kui-list-item-hover-border);
|
|
54
|
+
background: var(--kui-list-item-hover-background);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.kui-list-item:disabled {
|
|
58
|
+
color: var(--kui-color-neutral-on-quiet);
|
|
59
|
+
cursor: not-allowed;
|
|
60
|
+
opacity: 0.58;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.kui-list-item[aria-current="page"],
|
|
64
|
+
.kui-list-item[aria-pressed="true"] {
|
|
65
|
+
border-color: var(--kui-list-item-selected-border);
|
|
66
|
+
color: var(--kui-list-item-selected-color);
|
|
67
|
+
background: var(--kui-list-item-selected-background);
|
|
68
|
+
font-weight: 650;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.kui-list-item:focus-visible {
|
|
72
|
+
outline: var(--kui-focus-ring);
|
|
73
|
+
outline-offset: 1px;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.kui-list-item__icon {
|
|
77
|
+
display: grid;
|
|
78
|
+
width: 1.5rem;
|
|
79
|
+
height: 1.5rem;
|
|
80
|
+
color: currentColor;
|
|
81
|
+
place-items: center;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.kui-list-item__icon svg {
|
|
85
|
+
display: block;
|
|
86
|
+
width: 1.5rem;
|
|
87
|
+
height: 1.5rem;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.kui-list-item__label {
|
|
91
|
+
min-width: 0;
|
|
92
|
+
overflow: hidden;
|
|
93
|
+
text-overflow: ellipsis;
|
|
94
|
+
white-space: nowrap;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.kui-list-item[data-multiline="true"] {
|
|
98
|
+
height: fit-content;
|
|
99
|
+
white-space: normal;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.kui-list-item[data-multiline="true"] .kui-list-item__label {
|
|
103
|
+
overflow: visible;
|
|
104
|
+
white-space: normal;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.kui-list-item[data-multiline="true"] .kui-list-item__icon {
|
|
108
|
+
align-self: start;
|
|
109
|
+
margin-block-start: calc((1lh - 1.5rem) / 2);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.kui-list-item__trailing {
|
|
113
|
+
display: inline-flex;
|
|
114
|
+
min-width: 0;
|
|
115
|
+
align-items: center;
|
|
116
|
+
justify-content: flex-end;
|
|
117
|
+
gap: var(--kui-layout-item-gap, 0.5rem);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.kui-list-item__trailing > svg {
|
|
121
|
+
width: 1rem;
|
|
122
|
+
height: 1rem;
|
|
123
|
+
}
|
package/dist/styles/styles.css
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
@import "./toolbar.css";
|
|
6
6
|
@import "./toolbar-control-group.css";
|
|
7
7
|
@import "./toolbar-text.css";
|
|
8
|
-
@import "./
|
|
9
|
-
@import "./
|
|
10
|
-
@import "./
|
|
8
|
+
@import "./list-action-row.css";
|
|
9
|
+
@import "./list-item.css";
|
|
10
|
+
@import "./list-header.css";
|
|
11
11
|
@import "./resizable-region.css";
|
|
12
12
|
@import "./app-tab.css";
|
|
13
|
+
@import "./catalog.css";
|
|
13
14
|
@import "./tab-bar.css";
|
|
14
15
|
@import "./loading-spinner.css";
|
|
15
16
|
@import "./skeleton.css";
|
package/dist/value-table.js
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface WireCatalogOptions {
|
|
2
|
+
/** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */
|
|
3
|
+
onSelect: (id: string) => void;
|
|
4
|
+
/** Invoked when the sidebar collapse/expand control is activated. */
|
|
5
|
+
onToggleSidebar?: () => void;
|
|
6
|
+
/** Invoked when the theme toggle is activated. */
|
|
7
|
+
onToggleTheme?: () => void;
|
|
8
|
+
/** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */
|
|
9
|
+
onToggleSecondary?: () => void;
|
|
10
|
+
/** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */
|
|
11
|
+
urlParam?: string;
|
|
12
|
+
selectAction?: string;
|
|
13
|
+
toggleSidebarAction?: string;
|
|
14
|
+
toggleThemeAction?: string;
|
|
15
|
+
toggleSecondaryAction?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar
|
|
19
|
+
* item selection (and the related-entry selector), the sidebar collapse toggle, and
|
|
20
|
+
* the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates
|
|
21
|
+
* them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
|
|
22
|
+
* Returns a disposer.
|
|
23
|
+
*/
|
|
24
|
+
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
|
|
25
|
+
|
|
26
|
+
export { type WireCatalogOptions, wireCatalog };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { delegate } from 'kerfjs';
|
|
2
|
+
|
|
3
|
+
// src/wire-catalog.ts
|
|
4
|
+
function wireCatalog(root, {
|
|
5
|
+
onSelect,
|
|
6
|
+
onToggleSidebar,
|
|
7
|
+
onToggleTheme,
|
|
8
|
+
onToggleSecondary,
|
|
9
|
+
urlParam,
|
|
10
|
+
selectAction = "catalog-select",
|
|
11
|
+
toggleSidebarAction = "catalog-toggle-sidebar",
|
|
12
|
+
toggleThemeAction = "catalog-toggle-theme",
|
|
13
|
+
toggleSecondaryAction = "catalog-toggle-secondary"
|
|
14
|
+
}) {
|
|
15
|
+
const select = (id) => {
|
|
16
|
+
onSelect(id);
|
|
17
|
+
const view = root.ownerDocument.defaultView;
|
|
18
|
+
if (urlParam && view) {
|
|
19
|
+
const url = new URL(view.location.href);
|
|
20
|
+
url.searchParams.set(urlParam, id);
|
|
21
|
+
view.history.replaceState(null, "", url);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const disposers = [
|
|
25
|
+
delegate(root, "click", `[data-action="${selectAction}"]`, (_event, element) => {
|
|
26
|
+
const id = element.dataset.itemId;
|
|
27
|
+
if (id) select(id);
|
|
28
|
+
}),
|
|
29
|
+
delegate(root, "change", '[data-catalog-related] [data-component="select"]', (event) => {
|
|
30
|
+
const value = event.target.value;
|
|
31
|
+
if (value) select(value);
|
|
32
|
+
})
|
|
33
|
+
];
|
|
34
|
+
if (onToggleSidebar) {
|
|
35
|
+
disposers.push(delegate(root, "click", `[data-action="${toggleSidebarAction}"]`, () => onToggleSidebar()));
|
|
36
|
+
}
|
|
37
|
+
if (onToggleTheme) {
|
|
38
|
+
disposers.push(delegate(root, "click", `[data-action="${toggleThemeAction}"]`, () => onToggleTheme()));
|
|
39
|
+
}
|
|
40
|
+
if (onToggleSecondary) {
|
|
41
|
+
disposers.push(delegate(root, "click", `[data-action="${toggleSecondaryAction}"]`, () => onToggleSecondary()));
|
|
42
|
+
}
|
|
43
|
+
return () => {
|
|
44
|
+
for (const dispose of disposers.splice(0)) dispose();
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { wireCatalog };
|
|
49
|
+
|
|
50
|
+
//# sourceMappingURL=wire-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wire-catalog.ts"],"names":[],"mappings":";;;AA0BO,SAAS,YACd,IAAA,EACA;AAAA,EACE,QAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,iBAAA;AAAA,EACA,QAAA;AAAA,EACA,YAAA,GAAe,gBAAA;AAAA,EACf,mBAAA,GAAsB,wBAAA;AAAA,EACtB,iBAAA,GAAoB,sBAAA;AAAA,EACpB,qBAAA,GAAwB;AAC1B,CAAA,EACY;AACZ,EAAA,MAAM,MAAA,GAAS,CAAC,EAAA,KAAe;AAC7B,IAAA,QAAA,CAAS,EAAE,CAAA;AACX,IAAA,MAAM,IAAA,GAAO,KAAK,aAAA,CAAc,WAAA;AAChC,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,CAAK,SAAS,IAAI,CAAA;AACtC,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,QAAA,EAAU,EAAE,CAAA;AACjC,MAAA,IAAA,CAAK,OAAA,CAAQ,YAAA,CAAa,IAAA,EAAM,EAAA,EAAI,GAAG,CAAA;AAAA,IACzC;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAA+B;AAAA,IACnC,QAAA,CAAS,MAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,YAAY,CAAA,EAAA,CAAA,EAAM,CAAC,QAAQ,OAAA,KAAY;AAC9E,MAAA,MAAM,EAAA,GAAM,QAAwB,OAAA,CAAQ,MAAA;AAC5C,MAAA,IAAI,EAAA,SAAW,EAAE,CAAA;AAAA,IACnB,CAAC,CAAA;AAAA,IACD,QAAA,CAAS,IAAA,EAAM,QAAA,EAAU,kDAAA,EAAoD,CAAC,KAAA,KAAU;AACtF,MAAA,MAAM,KAAA,GAAS,MAAM,MAAA,CAA4C,KAAA;AACjE,MAAA,IAAI,KAAA,SAAc,KAAK,CAAA;AAAA,IACzB,CAAC;AAAA,GACH;AACA,EAAA,IAAI,eAAA,EAAiB;AACnB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,mBAAmB,CAAA,EAAA,CAAA,EAAM,MAAM,eAAA,EAAiB,CAAC,CAAA;AAAA,EAC3G;AACA,EAAA,IAAI,aAAA,EAAe;AACjB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,iBAAiB,CAAA,EAAA,CAAA,EAAM,MAAM,aAAA,EAAe,CAAC,CAAA;AAAA,EACvG;AACA,EAAA,IAAI,iBAAA,EAAmB;AACrB,IAAA,SAAA,CAAU,IAAA,CAAK,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,CAAA,cAAA,EAAiB,qBAAqB,CAAA,EAAA,CAAA,EAAM,MAAM,iBAAA,EAAmB,CAAC,CAAA;AAAA,EAC/G;AACA,EAAA,OAAO,MAAM;AACX,IAAA,KAAA,MAAW,OAAA,IAAW,SAAA,CAAU,MAAA,CAAO,CAAC,GAAG,OAAA,EAAQ;AAAA,EACrD,CAAA;AACF","file":"wire-catalog.js","sourcesContent":["import { delegate } from 'kerfjs';\n\nexport interface WireCatalogOptions {\n /** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */\n onSelect: (id: string) => void;\n /** Invoked when the sidebar collapse/expand control is activated. */\n onToggleSidebar?: () => void;\n /** Invoked when the theme toggle is activated. */\n onToggleTheme?: () => void;\n /** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */\n onToggleSecondary?: () => void;\n /** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */\n urlParam?: string;\n selectAction?: string;\n toggleSidebarAction?: string;\n toggleThemeAction?: string;\n toggleSecondaryAction?: string;\n}\n\n/**\n * Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar\n * item selection (and the related-entry selector), the sidebar collapse toggle, and\n * the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates\n * them in the callbacks; optionally mirror the active id into the URL via `urlParam`.\n * Returns a disposer.\n */\nexport function wireCatalog(\n root: HTMLElement,\n {\n onSelect,\n onToggleSidebar,\n onToggleTheme,\n onToggleSecondary,\n urlParam,\n selectAction = 'catalog-select',\n toggleSidebarAction = 'catalog-toggle-sidebar',\n toggleThemeAction = 'catalog-toggle-theme',\n toggleSecondaryAction = 'catalog-toggle-secondary',\n }: WireCatalogOptions,\n): () => void {\n const select = (id: string) => {\n onSelect(id);\n const view = root.ownerDocument.defaultView;\n if (urlParam && view) {\n const url = new URL(view.location.href);\n url.searchParams.set(urlParam, id);\n view.history.replaceState(null, '', url);\n }\n };\n\n const disposers: Array<() => void> = [\n delegate(root, 'click', `[data-action=\"${selectAction}\"]`, (_event, element) => {\n const id = (element as HTMLElement).dataset.itemId;\n if (id) select(id);\n }),\n delegate(root, 'change', '[data-catalog-related] [data-component=\"select\"]', (event) => {\n const value = (event.target as HTMLElement & { value?: string }).value;\n if (value) select(value);\n }),\n ];\n if (onToggleSidebar) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleSidebarAction}\"]`, () => onToggleSidebar()));\n }\n if (onToggleTheme) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleThemeAction}\"]`, () => onToggleTheme()));\n }\n if (onToggleSecondary) {\n disposers.push(delegate(root, 'click', `[data-action=\"${toggleSecondaryAction}\"]`, () => onToggleSecondary()));\n }\n return () => {\n for (const dispose of disposers.splice(0)) dispose();\n };\n}\n"]}
|
package/docs/accessibility.md
CHANGED
|
@@ -6,18 +6,18 @@ These are normative contracts for package components and consuming applications.
|
|
|
6
6
|
|
|
7
7
|
- All controls have accessible names and visible `:focus-visible` treatment.
|
|
8
8
|
- Decorative `LucideIcon` output is `aria-hidden`; pass `label` only when the SVG itself conveys meaning.
|
|
9
|
-
- `
|
|
10
|
-
- `
|
|
11
|
-
- In any `.kui-pane`, menu rows, `
|
|
9
|
+
- `ListItem` uses native button Enter/Space behavior. `selected` maps to `aria-current="page"`; `pressed` maps to `aria-pressed`. Its `trailing` content is dormant and must not contain controls. Its `rootAttributes` slot accepts only application `data-*` metadata and deliberately cannot emit `role="menuitem"` in isolation—a true ARIA menu must own arrow, Home/End, Escape, and focus behavior as one widget.
|
|
10
|
+
- `ListHeader` owns action naming, disabled state, and disclosure `aria-expanded`. Toggle mode supplies one decorative 18px `DisclosureArrow` when `actionIcon` is omitted; it mirrors `expanded` while the native button's accessible name stays stable. The application must update that controlled state and reveal or hide real content. A valid `count` is visually rendered in an `aria-hidden` neutral pill while the required localized `countLabel` becomes part of the owning heading or disclosure button's accessible name; zero remains a real count. Its narrow `triggerAttributes` slot may describe a native popover or controlled-content relationship with `popoverTarget`, `popoverTargetAction`, `aria-controls`, and `aria-haspopup`; the application owns the target surface and its focus/dismissal behavior.
|
|
11
|
+
- In any `.kui-pane`, menu rows, `ListHeader` actions, and toolbar groups keep a minimum 44px target in both dimensions. A `ListHeader` fills the available inline width and keeps that action at the logical end, including in RTL. Its action visual defaults to 18px through `--kui-list-header-action-icon-size`; do not reduce the target to the visible icon.
|
|
12
12
|
- `LoadingSpinner` is either labeled (`role="img"`) or hidden. Its rotation stops for reduced motion.
|
|
13
13
|
- `StateBanner` defaults to polite `role="status"`; use `urgency="alert"` only for an attention-requiring failure.
|
|
14
14
|
- `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
|
|
15
15
|
- `Select` follows the Web Awesome host's standard `input`/`change` events. Application tests verify the live `value`, focus, and events—not attributes alone. Its decorative option icons and value-dependent selected content remain present after controlled rerenders, so the visible choice does not silently lose its non-text cue.
|
|
16
16
|
- `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may override `--kui-disclosure-arrow-size` without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
17
17
|
|
|
18
|
-
##
|
|
18
|
+
## ListActionRow
|
|
19
19
|
|
|
20
|
-
`
|
|
20
|
+
`ListActionRow` renders a noninteractive visual root containing primary and
|
|
21
21
|
trailing native buttons as siblings. The primary comes first in DOM and Tab
|
|
22
22
|
order and alone receives `aria-current` or `aria-pressed`; the trailing button
|
|
23
23
|
has its own required accessible name and disabled state. Both controls carry
|