@antscorp/ui 0.1.2 → 0.1.4
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 +26 -2
- package/dist/atoms/AddButton.d.ts +3 -6
- package/dist/atoms/Chip.d.ts +2 -5
- package/dist/atoms/Chip.js +1 -1
- package/dist/atoms/InfoTip.js +2 -0
- package/dist/atoms/LabeledDivider.d.ts +1 -1
- package/dist/atoms/PanelSearchInput.d.ts +1 -1
- package/dist/atoms/RemoveButton.d.ts +2 -5
- package/dist/atoms/TextAction.d.ts +5 -6
- package/dist/atoms/TruncatedOption.d.ts +1 -1
- package/dist/cli.js +248 -0
- package/dist/doc/schema.d.ts +34 -0
- package/dist/doc/schema.js +33 -0
- package/dist/docs.json +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -51
- package/dist/lib/iso.d.ts +2 -2
- package/dist/lib/iso.js +16 -8
- package/dist/lib/tokenEditorExtensions.js +1 -1
- package/dist/lib/useLoadingShown.d.ts +1 -1
- package/dist/molecules/AccentCard.d.ts +2 -3
- package/dist/molecules/AccentCard.js +2 -2
- package/dist/molecules/CheckRow.d.ts +3 -8
- package/dist/molecules/ChoiceTiles.d.ts +1 -1
- package/dist/molecules/ChoiceTiles.js +1 -1
- package/dist/molecules/CommitTextField.d.ts +1 -19
- package/dist/molecules/CommitTextField.js +21 -18
- package/dist/molecules/ConfirmDialog.d.ts +2 -7
- package/dist/molecules/DateTimeInput.d.ts +6 -3
- package/dist/molecules/DateTimeInput.js +82 -73
- package/dist/molecules/FieldGroup.d.ts +1 -1
- package/dist/molecules/FieldRow.d.ts +1 -1
- package/dist/molecules/MetaTable.d.ts +1 -1
- package/dist/molecules/PhoneFrame.d.ts +1 -1
- package/dist/molecules/RemovableRow.d.ts +1 -1
- package/dist/molecules/RemovableRow.js +32 -32
- package/dist/molecules/RevealRadioGroup.d.ts +2 -9
- package/dist/molecules/RevealSwitch.d.ts +2 -7
- package/dist/molecules/Select.d.ts +8 -24
- package/dist/molecules/Select.js +50 -44
- package/dist/molecules/SideLabelRow.d.ts +1 -1
- package/dist/molecules/SplitButton.d.ts +1 -1
- package/dist/molecules/StatusButton.d.ts +2 -7
- package/dist/molecules/TagSelect.d.ts +2 -2
- package/dist/molecules/TransferLayout.d.ts +1 -1
- package/dist/molecules/TreeOptions.d.ts +4 -3
- package/dist/molecules/TreeOptions.js +67 -44
- package/dist/organisms/HourOfDayRow.js +2 -2
- package/dist/organisms/HourOfWeekGrid.js +2 -2
- package/dist/organisms/RuleGroups.d.ts +3 -3
- package/dist/organisms/SearchableGroupedList.d.ts +1 -1
- package/dist/organisms/TransferPicker.d.ts +1 -1
- package/dist/organisms/TreeSearchPanel.js +50 -47
- package/dist/organisms/TreeSelect.d.ts +3 -3
- package/dist/ui.css +1 -1
- package/package.json +36 -19
- package/src/atoms/AddButton.tsx +3 -7
- package/src/atoms/Chip.tsx +7 -9
- package/src/atoms/InfoTip.tsx +2 -2
- package/src/atoms/LabeledDivider.tsx +1 -1
- package/src/atoms/PanelSearchInput.tsx +1 -1
- package/src/atoms/RemoveButton.tsx +2 -6
- package/src/atoms/TextAction.tsx +6 -8
- package/src/atoms/TruncatedOption.tsx +1 -1
- package/src/doc/schema.ts +67 -0
- package/src/index.ts +2 -0
- package/src/lib/iso.ts +15 -3
- package/src/lib/tokenEditorExtensions.ts +1 -1
- package/src/lib/useLoadMore.ts +1 -2
- package/src/lib/useLoadingShown.ts +1 -1
- package/src/molecules/AccentCard.tsx +11 -10
- package/src/molecules/CheckRow.tsx +3 -9
- package/src/molecules/ChoiceTiles.tsx +6 -4
- package/src/molecules/CommitTextField.tsx +15 -20
- package/src/molecules/ConfirmDialog.tsx +2 -8
- package/src/molecules/DateTimeInput.tsx +86 -68
- package/src/molecules/DurationInput.tsx +2 -2
- package/src/molecules/FieldGroup.tsx +1 -1
- package/src/molecules/FieldRow.tsx +1 -1
- package/src/molecules/FrequencyLimitRow.tsx +1 -1
- package/src/molecules/MetaTable.tsx +1 -1
- package/src/molecules/PhoneFrame.tsx +2 -2
- package/src/molecules/RemovableRow.tsx +3 -3
- package/src/molecules/RevealRadioGroup.tsx +5 -10
- package/src/molecules/RevealSwitch.tsx +2 -8
- package/src/molecules/Select.tsx +23 -23
- package/src/molecules/SideLabelRow.tsx +2 -2
- package/src/molecules/SplitButton.tsx +1 -1
- package/src/molecules/StatusButton.tsx +2 -8
- package/src/molecules/TagSelect.tsx +5 -5
- package/src/molecules/TransferLayout.tsx +2 -3
- package/src/molecules/TreeOptions.tsx +89 -65
- package/src/organisms/HourOfDayRow.tsx +5 -3
- package/src/organisms/HourOfWeekGrid.tsx +5 -3
- package/src/organisms/RuleGroups.tsx +3 -3
- package/src/organisms/SearchableGroupedList.tsx +2 -2
- package/src/organisms/TransferPicker.tsx +3 -3
- package/src/organisms/TreeSearchPanel.tsx +2 -2
- package/src/organisms/TreeSelect.tsx +4 -4
|
@@ -40,7 +40,7 @@ export type TransferLayoutProps = {
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* Two columns side by side in one frame
|
|
43
|
+
* Two columns side by side in one frame: a header strip over two
|
|
44
44
|
* equal columns of a fixed height whose lists scroll on their own, 1px lines between the parts
|
|
45
45
|
* and no gap, and an optional footer under the start column. The headers and the lists' titles
|
|
46
46
|
* sit outside the scrolling areas. Pure layout: every part is a slot. It holds no state.
|
|
@@ -126,8 +126,7 @@ export function TransferLayout({
|
|
|
126
126
|
|
|
127
127
|
const LINE_COLOR = "var(--ants-mh-gray-200)";
|
|
128
128
|
|
|
129
|
-
//
|
|
130
|
-
// lines of its platinum grey, a 41px header strip, columns of a fixed height.
|
|
129
|
+
// Platinum grey grid lines, a 41px header strip, columns of a fixed height.
|
|
131
130
|
const styles = stylex.create({
|
|
132
131
|
frame: {
|
|
133
132
|
gridTemplateColumns: "minmax(0, 1fr) minmax(0, 1fr)",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useTreeFocus } from "@astryxdesign/core/hooks";
|
|
1
2
|
import { Icon } from "@astryxdesign/core/Icon";
|
|
2
3
|
import { useIndicator } from "@astryxdesign/core/Indicator";
|
|
3
4
|
import { Text } from "@astryxdesign/core/Text";
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
} from "@astryxdesign/core/theme/tokens.stylex";
|
|
10
11
|
import { themeProps } from "@astryxdesign/core/utils";
|
|
11
12
|
import * as stylex from "@stylexjs/stylex";
|
|
12
|
-
import {
|
|
13
|
+
import { Fragment, type ReactNode, useId, useState } from "react";
|
|
13
14
|
|
|
14
15
|
/** One row of a two-level tree to pick from: a leaf, or a group of leaves. */
|
|
15
16
|
export type TreeItem = {
|
|
@@ -53,17 +54,20 @@ type Row = {
|
|
|
53
54
|
};
|
|
54
55
|
|
|
55
56
|
/**
|
|
56
|
-
* The rows of a two-level tree to pick from
|
|
57
|
+
* The rows of a two-level tree to pick from: a group row shows its chevron
|
|
57
58
|
* at the end (right when closed, down when open) and only opens and closes; a leaf is picked; a
|
|
58
59
|
* disabled row does neither. Rows are the Selector's option rows (its styles, its option-row and
|
|
59
60
|
* check theme targets, its check on the picked leaf at the end, where a group shows its chevron),
|
|
60
61
|
* so a theme styles both alike: the picked row's look and whether a check shows are the theme's.
|
|
61
|
-
* Tab reaches the picked leaf (else the first enabled row),
|
|
62
|
-
*
|
|
62
|
+
* Tab initially reaches the picked leaf (else the first enabled row); arrows, Home and End move
|
|
63
|
+
* through enabled rows, Right opens or enters a group, Left collapses or returns to its parent,
|
|
64
|
+
* and Enter and Space act. Its state is which groups are open and which row has focus.
|
|
63
65
|
*/
|
|
64
66
|
export function TreeOptions(props: TreeOptionsProps): ReactNode {
|
|
65
67
|
const { items, value } = props;
|
|
66
68
|
const size = props.size ?? "md";
|
|
69
|
+
const id = useId();
|
|
70
|
+
const [active, setActive] = useState<string>();
|
|
67
71
|
const [open, setOpen] = useState<ReadonlySet<string>>(
|
|
68
72
|
() =>
|
|
69
73
|
new Set(
|
|
@@ -87,7 +91,9 @@ export function TreeOptions(props: TreeOptionsProps): ReactNode {
|
|
|
87
91
|
const Check = useIndicator("check");
|
|
88
92
|
const enabled = rows.filter((row) => row.item.isDisabled !== true);
|
|
89
93
|
const tabbable =
|
|
90
|
-
enabled.find((row) => row.
|
|
94
|
+
enabled.find((row) => row.item.value === active) ??
|
|
95
|
+
enabled.find((row) => row.isOpen === undefined && row.item.value === value) ??
|
|
96
|
+
enabled[0];
|
|
91
97
|
const act = (row: Row): void => {
|
|
92
98
|
if (row.item.isDisabled === true) return;
|
|
93
99
|
if (row.isOpen === undefined) {
|
|
@@ -98,56 +104,84 @@ export function TreeOptions(props: TreeOptionsProps): ReactNode {
|
|
|
98
104
|
if (!next.delete(row.item.value)) next.add(row.item.value);
|
|
99
105
|
setOpen(next);
|
|
100
106
|
};
|
|
107
|
+
const activate = (key: string | undefined): void => {
|
|
108
|
+
const row = rows.find((candidate) => candidate.item.value === key);
|
|
109
|
+
if (row !== undefined) act(row);
|
|
110
|
+
};
|
|
111
|
+
const { treeRef, handleKeyDown } = useTreeFocus({
|
|
112
|
+
itemSelector: '[role="treeitem"]:not([aria-disabled="true"])',
|
|
113
|
+
onToggleExpand: activate,
|
|
114
|
+
onActivate: (_item, key) => {
|
|
115
|
+
activate(key);
|
|
116
|
+
return true;
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
const groupId = (row: Row): string => `${id}-${encodeURIComponent(row.item.value)}`;
|
|
120
|
+
const renderRow = (row: Row): ReactNode => (
|
|
121
|
+
<div
|
|
122
|
+
key={row.item.value}
|
|
123
|
+
role="treeitem"
|
|
124
|
+
aria-label={row.item.label}
|
|
125
|
+
data-tree-id={row.item.value}
|
|
126
|
+
aria-level={row.level}
|
|
127
|
+
aria-expanded={row.isOpen}
|
|
128
|
+
aria-owns={row.isOpen === true ? groupId(row) : undefined}
|
|
129
|
+
aria-selected={row.isOpen === undefined ? row.item.value === value : undefined}
|
|
130
|
+
aria-disabled={row.item.isDisabled === true || undefined}
|
|
131
|
+
tabIndex={row.item === tabbable?.item ? 0 : -1}
|
|
132
|
+
onFocus={() => {
|
|
133
|
+
setActive(row.item.value);
|
|
134
|
+
}}
|
|
135
|
+
onClick={() => {
|
|
136
|
+
act(row);
|
|
137
|
+
}}
|
|
138
|
+
{...rowProps(row, size, value)}
|
|
139
|
+
>
|
|
140
|
+
{/* The option's content and mark column, as `Selector.tsx:1407-1431`. */}
|
|
141
|
+
{/* One line cut with an ellipsis, with Text's tooltip for the whole label;
|
|
142
|
+
Astryx's SelectorOption would run under the mark. */}
|
|
143
|
+
<span {...stylex.props(styles.content)}>
|
|
144
|
+
<Text type="inherit" color="inherit" maxLines={1}>
|
|
145
|
+
{row.item.label}
|
|
146
|
+
</Text>
|
|
147
|
+
</span>
|
|
148
|
+
{/* A leaf's column sets no display of its own: the theme may hide it with its check. */}
|
|
149
|
+
<span {...stylex.props(styles.mark, row.isOpen !== undefined && styles.markCentred)}>
|
|
150
|
+
{row.isOpen === undefined ? (
|
|
151
|
+
<Check
|
|
152
|
+
state={row.item.value === value ? "checked" : "unchecked"}
|
|
153
|
+
size="sm"
|
|
154
|
+
isDisabled={row.item.isDisabled === true}
|
|
155
|
+
{...themeProps("selector-check")}
|
|
156
|
+
/>
|
|
157
|
+
) : (
|
|
158
|
+
<Icon icon={row.isOpen ? "chevronDown" : "chevronRight"} size="sm" color="secondary" />
|
|
159
|
+
)}
|
|
160
|
+
</span>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
101
163
|
return (
|
|
102
|
-
// Raw
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
{
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
act(row);
|
|
121
|
-
}}
|
|
122
|
-
{...rowProps(row, size, value)}
|
|
123
|
-
>
|
|
124
|
-
{/* The option's content and mark column, as `Selector.tsx:1407-1431`. */}
|
|
125
|
-
{/* One line cut with an ellipsis, the whole label in Text's tooltip when cut, as
|
|
126
|
-
fe-app's tree (`Tree/Item.jsx:235`); Astryx's SelectorOption would run under the mark. */}
|
|
127
|
-
<span {...stylex.props(styles.content)}>
|
|
128
|
-
<Text type="inherit" color="inherit" maxLines={1}>
|
|
129
|
-
{row.item.label}
|
|
130
|
-
</Text>
|
|
131
|
-
</span>
|
|
132
|
-
{/* A leaf's column sets no display of its own: the theme may hide it with its check. */}
|
|
133
|
-
<span {...stylex.props(styles.mark, row.isOpen !== undefined && styles.markCentred)}>
|
|
134
|
-
{row.isOpen === undefined ? (
|
|
135
|
-
<Check
|
|
136
|
-
state={row.item.value === value ? "checked" : "unchecked"}
|
|
137
|
-
size="sm"
|
|
138
|
-
isDisabled={row.item.isDisabled === true}
|
|
139
|
-
{...themeProps("selector-check")}
|
|
140
|
-
/>
|
|
141
|
-
) : (
|
|
142
|
-
<Icon
|
|
143
|
-
icon={row.isOpen ? "chevronDown" : "chevronRight"}
|
|
144
|
-
size="sm"
|
|
145
|
-
color="secondary"
|
|
146
|
-
/>
|
|
164
|
+
// Raw tree roles preserve the trailing chevron layout; each parent owns its sibling group.
|
|
165
|
+
<div
|
|
166
|
+
role="tree"
|
|
167
|
+
aria-label={props.label}
|
|
168
|
+
ref={(element) => {
|
|
169
|
+
treeRef.current = element;
|
|
170
|
+
}}
|
|
171
|
+
onKeyDown={handleKeyDown}
|
|
172
|
+
>
|
|
173
|
+
{rows
|
|
174
|
+
.filter((row) => row.level === 1)
|
|
175
|
+
.map((row) => (
|
|
176
|
+
<Fragment key={row.item.value}>
|
|
177
|
+
{renderRow(row)}
|
|
178
|
+
{row.isOpen === true && (
|
|
179
|
+
<div role="group" id={groupId(row)}>
|
|
180
|
+
{row.item.children?.map((child) => renderRow({ item: child, level: 2 }))}
|
|
181
|
+
</div>
|
|
147
182
|
)}
|
|
148
|
-
</
|
|
149
|
-
|
|
150
|
-
))}
|
|
183
|
+
</Fragment>
|
|
184
|
+
))}
|
|
151
185
|
</div>
|
|
152
186
|
);
|
|
153
187
|
}
|
|
@@ -178,22 +212,12 @@ function rowProps(
|
|
|
178
212
|
};
|
|
179
213
|
}
|
|
180
214
|
|
|
181
|
-
// Up and Down move the keyboard to the row above or below.
|
|
182
|
-
function moveFocus(event: KeyboardEvent<HTMLDivElement>): void {
|
|
183
|
-
const step = event.key === "ArrowDown" ? 1 : event.key === "ArrowUp" ? -1 : 0;
|
|
184
|
-
if (step === 0) return;
|
|
185
|
-
event.preventDefault();
|
|
186
|
-
const rows = [...event.currentTarget.querySelectorAll<HTMLElement>('[role="treeitem"]')];
|
|
187
|
-
const at = rows.findIndex((row) => row === event.target);
|
|
188
|
-
rows[Math.min(Math.max(at + step, 0), rows.length - 1)]?.focus();
|
|
189
|
-
}
|
|
190
|
-
|
|
191
215
|
// Astryx `Selector/Selector.tsx` styles: `item` (345-366, without its radius), `itemContent`
|
|
192
216
|
// (367-373), `itemMarkColumn` (379-389), `itemHighlighted` (395-397, here on hover and keyboard
|
|
193
217
|
// focus, as the rows take focus, never on the picked row), `itemDisabled` (401-404) and
|
|
194
218
|
// `itemSizeStyles` (452-460). The radius and the picked row's background and weight
|
|
195
219
|
// (`itemSelected`) are left to the theme's `selector-option-row`. Only `child` is ours: a
|
|
196
|
-
// group's leaves one indent step in
|
|
220
|
+
// group's leaves one indent step in.
|
|
197
221
|
const styles = stylex.create({
|
|
198
222
|
row: {
|
|
199
223
|
boxSizing: "border-box",
|
|
@@ -250,7 +274,7 @@ export function leafOf(items: readonly TreeItem[], value: string): TreeItem | un
|
|
|
250
274
|
return undefined;
|
|
251
275
|
}
|
|
252
276
|
|
|
253
|
-
// The rows a search leaves
|
|
277
|
+
// The rows a search leaves: a case-insensitive substring of the label.
|
|
254
278
|
// A leaf stays when it matches; a group when its label or a child's matches, keeping only the
|
|
255
279
|
// children that match.
|
|
256
280
|
export function matchTree(items: readonly TreeItem[], search: string): TreeItem[] {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccentRole } from "@antscorp/astryx-theme-antsomi/palette";
|
|
1
2
|
import { FieldStatus } from "@astryxdesign/core/FieldStatus";
|
|
2
3
|
import { ScrollableArea } from "@astryxdesign/core/ScrollableArea";
|
|
3
4
|
import { colorVars } from "@astryxdesign/core/theme/tokens.stylex";
|
|
@@ -115,6 +116,7 @@ export function HourOfDayRow(props: HourOfDayRowProps): ReactNode {
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
// As the week grid's: 24px cells, 11px text.
|
|
119
|
+
const accentHover: AccentRole = "var(--ants-accent-hover)";
|
|
118
120
|
const styles = stylex.create({
|
|
119
121
|
grid: { width: "max-content", userSelect: "none", cursor: "pointer" },
|
|
120
122
|
locked: { cursor: "default" },
|
|
@@ -133,18 +135,18 @@ const styles = stylex.create({
|
|
|
133
135
|
},
|
|
134
136
|
on: { backgroundColor: colorVars["--color-accent"] },
|
|
135
137
|
off: { backgroundColor: colorVars["--color-neutral"] },
|
|
136
|
-
//
|
|
138
|
+
// Cells turn hover blue under the pointer, picked or not,
|
|
137
139
|
// while they can be changed.
|
|
138
140
|
liveOn: {
|
|
139
141
|
backgroundColor: {
|
|
140
142
|
default: colorVars["--color-accent"],
|
|
141
|
-
":hover": { default: null, "@media (hover: hover)":
|
|
143
|
+
":hover": { default: null, "@media (hover: hover)": accentHover },
|
|
142
144
|
},
|
|
143
145
|
},
|
|
144
146
|
liveOff: {
|
|
145
147
|
backgroundColor: {
|
|
146
148
|
default: colorVars["--color-neutral"],
|
|
147
|
-
":hover": { default: null, "@media (hover: hover)":
|
|
149
|
+
":hover": { default: null, "@media (hover: hover)": accentHover },
|
|
148
150
|
},
|
|
149
151
|
},
|
|
150
152
|
axis: { color: colorVars["--color-text-secondary"], fontSize: 11, whiteSpace: "nowrap" },
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AccentRole } from "@antscorp/astryx-theme-antsomi/palette";
|
|
1
2
|
import { FieldStatus } from "@astryxdesign/core/FieldStatus";
|
|
2
3
|
import { ScrollableArea } from "@astryxdesign/core/ScrollableArea";
|
|
3
4
|
import { Text } from "@astryxdesign/core/Text";
|
|
@@ -239,6 +240,7 @@ export function HourOfWeekGrid(props: HourOfWeekGridProps): ReactNode {
|
|
|
239
240
|
}
|
|
240
241
|
|
|
241
242
|
// Sizes follow the form it came from: 24px cells, a 76px column of day names, 11px text.
|
|
243
|
+
const accentHover: AccentRole = "var(--ants-accent-hover)";
|
|
242
244
|
const styles = stylex.create({
|
|
243
245
|
// Every cell picks, as in the form it came from; the cells inherit it.
|
|
244
246
|
grid: { width: "max-content", userSelect: "none", cursor: "pointer" },
|
|
@@ -283,18 +285,18 @@ const styles = stylex.create({
|
|
|
283
285
|
},
|
|
284
286
|
on: { backgroundColor: colorVars["--color-accent"] },
|
|
285
287
|
off: { backgroundColor: colorVars["--color-neutral"] },
|
|
286
|
-
//
|
|
288
|
+
// Cells turn hover blue under the pointer, picked or not,
|
|
287
289
|
// while they can be changed.
|
|
288
290
|
liveOn: {
|
|
289
291
|
backgroundColor: {
|
|
290
292
|
default: colorVars["--color-accent"],
|
|
291
|
-
":hover": { default: null, "@media (hover: hover)":
|
|
293
|
+
":hover": { default: null, "@media (hover: hover)": accentHover },
|
|
292
294
|
},
|
|
293
295
|
},
|
|
294
296
|
liveOff: {
|
|
295
297
|
backgroundColor: {
|
|
296
298
|
default: colorVars["--color-neutral"],
|
|
297
|
-
":hover": { default: null, "@media (hover: hover)":
|
|
299
|
+
":hover": { default: null, "@media (hover: hover)": accentHover },
|
|
298
300
|
},
|
|
299
301
|
},
|
|
300
302
|
axis: {
|
|
@@ -55,11 +55,11 @@ export type RuleGroupsProps<R> = {
|
|
|
55
55
|
};
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* Rules in groups
|
|
58
|
+
* Rules in groups: each rule a card with an accent stripe, a title
|
|
59
59
|
* and a close button; the word "and" under each card but a group's last, and a pill button adding
|
|
60
60
|
* a rule at the end of the group; a dashed divider with "or" between groups, and a pill button
|
|
61
|
-
* adding a group after the last; each word in capitals
|
|
62
|
-
* `maxGroups`) is
|
|
61
|
+
* adding a group after the last; each word in capitals. Unlike a list's add, an add at its limit (`maxRules`,
|
|
62
|
+
* `maxGroups`) is hidden. The only rule left has no close button, so the groups are
|
|
63
63
|
* never emptied from here; with no group at all only the button adding one shows. It holds no
|
|
64
64
|
* state.
|
|
65
65
|
*/
|
|
@@ -66,7 +66,7 @@ export type SearchableGroupedListProps<I> = {
|
|
|
66
66
|
/**
|
|
67
67
|
* Caps the height, the groups scrolling under the search box, in a pop-over say; with no
|
|
68
68
|
* `maxHeight` it fills its parent's height, in a side panel say. The list then pads its own edges,
|
|
69
|
-
* so the search row (its magnifier at the end
|
|
69
|
+
* so the search row (its magnifier at the end) and the rule under it reach the
|
|
70
70
|
* edges of a flush (unpadded) surface, and so does the scrollbar.
|
|
71
71
|
*/
|
|
72
72
|
readonly scroll?: { readonly maxHeight?: number | undefined; readonly label: string } | undefined;
|
|
@@ -271,7 +271,7 @@ const styles = stylex.create({
|
|
|
271
271
|
framed: { minHeight: 0 },
|
|
272
272
|
capped: (maxHeight: number) => ({ maxHeight }),
|
|
273
273
|
scroll: { minHeight: 0 },
|
|
274
|
-
// A folding group's row
|
|
274
|
+
// A folding group's row: 10px sides, 36px high when folded.
|
|
275
275
|
fold: { paddingInline: 10, paddingBlock: 6 },
|
|
276
276
|
flush: { marginInline: -10 },
|
|
277
277
|
title: { fontSize: typeScaleVars["--text-label-size"] },
|
|
@@ -142,7 +142,7 @@ export type TransferPickerProps<V extends string> = Pick<
|
|
|
142
142
|
const LOADING_ROWS = 6;
|
|
143
143
|
|
|
144
144
|
/**
|
|
145
|
-
* Picks options in two columns of one frame
|
|
145
|
+
* Picks options in two columns of one frame: a header strip with
|
|
146
146
|
* the search (and the host's controls) over the options to tick, and the host's controls with
|
|
147
147
|
* "Remove all" over the picked ones in framed rows with a remove button. Searching matches every
|
|
148
148
|
* word, in any case; it stays cheap for thousands of options, and a new search scrolls the
|
|
@@ -177,7 +177,7 @@ export function TransferPicker<V extends string>(props: TransferPickerProps<V>):
|
|
|
177
177
|
<HStack gap={2} align="center" justify={props.endHeader === undefined ? "end" : "between"}>
|
|
178
178
|
{props.endHeader}
|
|
179
179
|
{removeAll !== undefined && (
|
|
180
|
-
//
|
|
180
|
+
// Keep the clear action pressable while nothing is picked.
|
|
181
181
|
<TextAction
|
|
182
182
|
label={removeAll}
|
|
183
183
|
isDisabled={isDisabled}
|
|
@@ -365,7 +365,7 @@ function OptionsHeading<V extends string>(
|
|
|
365
365
|
isLabelHidden
|
|
366
366
|
isDisabled={props.isDisabled ?? false}
|
|
367
367
|
isReadOnly={props.isReadOnly ?? false}
|
|
368
|
-
//
|
|
368
|
+
// One mark for "some or all picked", and a click clears them.
|
|
369
369
|
value={props.value.length > 0 ? "indeterminate" : false}
|
|
370
370
|
onChange={props.onSelectAll}
|
|
371
371
|
/>
|
|
@@ -14,7 +14,7 @@ import { LoadMoreRow } from "../molecules/LoadMoreRow";
|
|
|
14
14
|
import { matchTree, TreeOptions } from "../molecules/TreeOptions";
|
|
15
15
|
import type { TreeSelectItem, TreeSelectProps } from "./TreeSelect";
|
|
16
16
|
|
|
17
|
-
//
|
|
17
|
+
// Cap the tree list at 200px so longer results scroll inside the panel.
|
|
18
18
|
const LIST_HEIGHT = 200;
|
|
19
19
|
|
|
20
20
|
/** What `TreeSearchPanel` takes. */
|
|
@@ -64,7 +64,7 @@ export function TreeSearchPanel(props: TreeSearchPanelProps): ReactNode {
|
|
|
64
64
|
const { rootRef, sentinelRef } = useLoadMore({
|
|
65
65
|
...more,
|
|
66
66
|
hasLoadMoreError: labels.loadMoreError !== undefined,
|
|
67
|
-
itemCount: shown.length,
|
|
67
|
+
itemCount: shown.reduce((count, item) => count + 1 + (item.children?.length ?? 0), 0),
|
|
68
68
|
});
|
|
69
69
|
const groups = shown.filter((item) => item.children !== undefined).length;
|
|
70
70
|
return (
|
|
@@ -88,7 +88,7 @@ export type TreeSelectProps = Pick<LoadMoreOptions, "onLoadMore" | "hasMore" | "
|
|
|
88
88
|
readonly isLoading?: boolean | undefined;
|
|
89
89
|
/** The trigger's width, in pixels or any CSS length such as `"100%"`; as wide as its content without it. */
|
|
90
90
|
readonly width?: number | string | undefined;
|
|
91
|
-
/** The trigger's size, `md` by default (
|
|
91
|
+
/** The trigger's size, `md` by default (the theme's 30px control height). */
|
|
92
92
|
readonly size?: "sm" | "md" | undefined;
|
|
93
93
|
/** Dims the trigger and blocks it. */
|
|
94
94
|
readonly isDisabled?: boolean | undefined;
|
|
@@ -105,8 +105,8 @@ export type TreeSelectProps = Pick<LoadMoreOptions, "onLoadMore" | "hasMore" | "
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
* A Selector-like trigger opening a popover with a search box over a two-level tree
|
|
109
|
-
*
|
|
108
|
+
* A Selector-like trigger opening a popover with a search box over a two-level tree:
|
|
109
|
+
* a group row (its chevron at the end) only opens and closes, a
|
|
110
110
|
* leaf is picked and closes the popover, a disabled row is not picked. The search keeps a leaf
|
|
111
111
|
* whose label matches and a group whose label or a child's matches, with only its matching
|
|
112
112
|
* children, every group open; with `onSearchChange` the host searches instead. With
|
|
@@ -289,7 +289,7 @@ const styles = stylex.create({
|
|
|
289
289
|
cursor: { default: "pointer", ":disabled": "default" },
|
|
290
290
|
},
|
|
291
291
|
// With an addon the frame has the input look and lays out the addon, the line and the trigger;
|
|
292
|
-
//
|
|
292
|
+
// The tag's inset: 5px before the tag, the line 6px after it and 1px before the
|
|
293
293
|
// select (no spacing step is 5px, 6px or 1px).
|
|
294
294
|
frame: {
|
|
295
295
|
display: "flex",
|