@lotics/ui 7.14.0 → 7.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -1
- package/package.json +1 -1
- package/src/member_select.tsx +20 -3
package/AGENTS.md
CHANGED
|
@@ -50,7 +50,9 @@ Pick by capability, not by name. (→ the source file for the API.)
|
|
|
50
50
|
`useOptionList` engine; `Picker` is the only one that's a native dropdown.
|
|
51
51
|
- **Pick member(s)** — `MemberSelect` (a `Select` that renders each option as a `MemberChip`,
|
|
52
52
|
single or multi) — the ready member picker; pass it the roster (`members={useMembers().members}`).
|
|
53
|
-
Don't re-wire `Select` + `renderOptionContent` + a directory by hand.
|
|
53
|
+
Don't re-wire `Select` + `renderOptionContent` + a directory by hand. For an assignee FILTER that
|
|
54
|
+
also matches unassigned records, pass `unassignedLabel` → it prepends a muted "unassigned" option
|
|
55
|
+
(value `MEMBER_UNASSIGNED`), so you never hand-roll a mixed member+none `Select`. To edit a `select_member`
|
|
54
56
|
field IN PLACE (chip at rest → picker on click) use its inline-edit twin `InlineMemberSelect`.
|
|
55
57
|
- **A person / member (display)** — `MemberChip` (avatar + name + optional secondary line) — the
|
|
56
58
|
ONE way to show a member inline: a picker option, an assignee, a `select_member` value. Pure:
|
package/package.json
CHANGED
package/src/member_select.tsx
CHANGED
|
@@ -8,6 +8,12 @@ import {
|
|
|
8
8
|
type PickerOnClose,
|
|
9
9
|
} from "./picker";
|
|
10
10
|
import { MemberChip } from "./member_chip";
|
|
11
|
+
import { Text } from "./text";
|
|
12
|
+
|
|
13
|
+
/** The `value` of {@link MemberSelect}'s "unassigned" option (present only when
|
|
14
|
+
* `unassignedLabel` is set). Check a `MemberSelect` value against it to detect
|
|
15
|
+
* "no member assigned" — e.g. `value.includes(MEMBER_UNASSIGNED)` in a filter. */
|
|
16
|
+
export const MEMBER_UNASSIGNED = "__unassigned__";
|
|
11
17
|
|
|
12
18
|
/** A candidate member for {@link MemberSelect}. Shaped to accept a `useMembers`
|
|
13
19
|
* row from `@lotics/app-sdk` (or any roster) directly. */
|
|
@@ -35,6 +41,13 @@ interface MemberSelectProps<MULTI extends boolean = false> {
|
|
|
35
41
|
/** Show an in-menu search box to filter the roster; default false. */
|
|
36
42
|
searchable?: boolean;
|
|
37
43
|
includeEmptyOption?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* When set, prepend a selectable "unassigned" option (value {@link MEMBER_UNASSIGNED}),
|
|
46
|
+
* rendered as muted text — for an assignee FILTER that also matches "no one assigned".
|
|
47
|
+
* Distinct from `includeEmptyOption` (a single-select CLEAR row that unsets the value):
|
|
48
|
+
* this is a real, filterable value the consumer detects in `value`.
|
|
49
|
+
*/
|
|
50
|
+
unassignedLabel?: string;
|
|
38
51
|
enableSelectAll?: boolean;
|
|
39
52
|
/** Label for the "select all" link in multi-select mode. Pass a translated string. */
|
|
40
53
|
selectAllLabel?: string;
|
|
@@ -61,16 +74,20 @@ interface MemberSelectProps<MULTI extends boolean = false> {
|
|
|
61
74
|
* ```
|
|
62
75
|
*/
|
|
63
76
|
export function MemberSelect<MULTI extends boolean = false>(props: MemberSelectProps<MULTI>) {
|
|
64
|
-
const { members, ...picker } = props;
|
|
77
|
+
const { members, unassignedLabel, ...picker } = props;
|
|
65
78
|
|
|
66
79
|
const byId = useMemo(() => new Map(members.map((m) => [m.id, m])), [members]);
|
|
67
80
|
const options = useMemo<PickerOption<string>[]>(
|
|
68
|
-
() =>
|
|
69
|
-
|
|
81
|
+
() => [
|
|
82
|
+
...(unassignedLabel ? [{ value: MEMBER_UNASSIGNED, label: unassignedLabel }] : []),
|
|
83
|
+
...members.map((m) => ({ value: m.id, label: m.name || m.email || m.id })),
|
|
84
|
+
],
|
|
85
|
+
[members, unassignedLabel],
|
|
70
86
|
);
|
|
71
87
|
|
|
72
88
|
const renderOptionContent = useCallback(
|
|
73
89
|
(option: PickerOption<string>) => {
|
|
90
|
+
if (option.value === MEMBER_UNASSIGNED) return <Text size="sm" color="muted">{option.label}</Text>;
|
|
74
91
|
const member = byId.get(option.value);
|
|
75
92
|
if (!member) return null;
|
|
76
93
|
return <MemberChip name={member.name || member.email} image={member.image} />;
|