@crewlethq/ui 0.8.1 → 0.9.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.
Files changed (62) hide show
  1. package/README.md +12 -2
  2. package/dist/Avatar/Avatar.d.ts +23 -2
  3. package/dist/Avatar/AvatarStack.d.ts +6 -0
  4. package/dist/Avatar/index.d.ts +1 -1
  5. package/dist/Avatar/index.js +2 -1
  6. package/dist/{Avatar-XID7Z74C.css → Avatar-JAU77SHZ.css} +73 -9
  7. package/dist/CharacterPicker/CharacterPicker.d.ts +38 -0
  8. package/dist/CharacterPicker/index.d.ts +3 -0
  9. package/dist/CharacterPicker/index.js +4 -0
  10. package/dist/CharacterPicker-ZEYIKUNQ.css +42 -0
  11. package/dist/CommandPalette/index.js +2 -2
  12. package/dist/DataTable/index.js +2 -2
  13. package/dist/DataView/index.js +6 -6
  14. package/dist/EntityChip/index.js +3 -2
  15. package/dist/HuePicker/HuePicker.d.ts +26 -0
  16. package/dist/HuePicker/index.d.ts +3 -0
  17. package/dist/HuePicker/index.js +8 -0
  18. package/dist/HuePicker-5QIUR6L7.css +18 -0
  19. package/dist/ImageUpload/index.js +3 -2
  20. package/dist/ListInput/index.js +2 -2
  21. package/dist/OrgLabel/index.js +3 -2
  22. package/dist/OrgNode/index.js +4 -3
  23. package/dist/OrgTable/index.js +4 -3
  24. package/dist/SegmentedControl/index.js +4 -2
  25. package/dist/Tabs/index.js +2 -1
  26. package/dist/Tabs/roving.d.ts +9 -1
  27. package/dist/TagsInput/index.js +2 -2
  28. package/dist/ThemeSwitcher/index.js +5 -3
  29. package/dist/TimeWindowPicker/index.js +3 -3
  30. package/dist/TreeCanvas/TreeCanvas.d.ts +5 -13
  31. package/dist/chunk-26TXVHN2.js +31 -0
  32. package/dist/chunk-AYKXMIOR.js +13 -0
  33. package/dist/chunk-CBOICT64.js +74 -0
  34. package/dist/{chunk-W4GQWFRX.js → chunk-E3HDS4F7.js} +1 -1
  35. package/dist/{chunk-A3K56LY6.js → chunk-EUT7VBQG.js} +4 -4
  36. package/dist/{chunk-DRHXRGB6.js → chunk-HEOVQZL7.js} +3 -62
  37. package/dist/chunk-IKH3Y4MP.js +73 -0
  38. package/dist/{chunk-B47YUQGM.js → chunk-J3IS2TOA.js} +1 -1
  39. package/dist/{chunk-6SIG5I72.js → chunk-JB6AN4ZC.js} +1 -1
  40. package/dist/{chunk-VCOELPCT.js → chunk-K7OS4O2U.js} +1 -1
  41. package/dist/{chunk-N5KCGFWI.js → chunk-LPHHDCN3.js} +2 -3
  42. package/dist/chunk-OAH4IEQJ.js +68 -0
  43. package/dist/{chunk-IA232OTU.js → chunk-UDW3DAP5.js} +31 -62
  44. package/dist/chunk-UI6HWAWE.js +2 -0
  45. package/dist/{chunk-RHHGLTXJ.js → chunk-X6K6OZ47.js} +1 -1
  46. package/dist/{chunk-WSOFKOLP.js → chunk-Y2V3TSQC.js} +1 -1
  47. package/dist/generated/index.d.ts +2 -0
  48. package/dist/generated/index.js +38 -32
  49. package/dist/index.js +38 -32
  50. package/dist/styles.css +140 -10
  51. package/dist/utils/index.d.ts +2 -0
  52. package/dist/utils/index.js +2 -1
  53. package/dist/utils/nodeHue.d.ts +25 -0
  54. package/dist/utils/tone.d.ts +4 -1
  55. package/package.json +3 -3
  56. package/dist/{chunk-4JHWMJZI.js → chunk-6HXH57BL.js} +1 -1
  57. package/dist/{chunk-IJ7QXNIJ.js → chunk-AER7UDD4.js} +0 -0
  58. package/dist/{chunk-KTIEJ5Q5.js → chunk-CVB7O3SZ.js} +1 -1
  59. package/dist/{chunk-BXPLX7YU.js → chunk-IGWPZZIB.js} +1 -1
  60. package/dist/{chunk-HVPC2GHY.js → chunk-IZHN5I3H.js} +1 -1
  61. package/dist/{chunk-DBUGBINU.js → chunk-MPXI6FM6.js} +1 -1
  62. /package/dist/{chunk-PKIN4IMB.js → chunk-YPTC4TX5.js} +0 -0
@@ -0,0 +1,31 @@
1
+ import { NODE_HUES, NODE_HUE_NAMES } from './chunk-AYKXMIOR.js';
2
+ import { SegmentedControl } from './chunk-LPHHDCN3.js';
3
+ import { cx } from './chunk-ODEQTPFM.js';
4
+ import './HuePicker-5QIUR6L7.css';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ var optionsFor = (disabled) => NODE_HUES.map((hue) => ({
8
+ value: hue,
9
+ label: NODE_HUE_NAMES[hue],
10
+ icon: /* @__PURE__ */ jsx("span", { className: `crewlet-hue-picker__swatch crewlet-hue-picker__swatch--${hue}` }),
11
+ disabled
12
+ }));
13
+ var ENABLED = optionsFor(false);
14
+ var DISABLED = optionsFor(true);
15
+ function HuePicker({ label, value, onValueChange, size, disabled = false, className }) {
16
+ return /* @__PURE__ */ jsx(
17
+ SegmentedControl,
18
+ {
19
+ semantics: "radio",
20
+ layout: "chips",
21
+ label,
22
+ options: disabled ? DISABLED : ENABLED,
23
+ value,
24
+ onValueChange,
25
+ size,
26
+ className: cx("crewlet-hue-picker", className)
27
+ }
28
+ );
29
+ }
30
+
31
+ export { HuePicker };
@@ -0,0 +1,13 @@
1
+ // src/utils/nodeHue.ts
2
+ var NODE_HUES = ["purple", "cyan", "green", "amber", "rose", "blue"];
3
+ var NODE_HUE_NAMES = {
4
+ purple: "Purple",
5
+ cyan: "Cyan",
6
+ green: "Green",
7
+ amber: "Amber",
8
+ rose: "Rose",
9
+ blue: "Blue"
10
+ };
11
+ var isNodeHue = (value) => typeof value === "string" && NODE_HUES.includes(value);
12
+
13
+ export { NODE_HUES, NODE_HUE_NAMES, isNodeHue };
@@ -0,0 +1,74 @@
1
+ import { useRef, useState } from 'react';
2
+
3
+ // src/Tabs/roving.ts
4
+ function tabStop(items, selected) {
5
+ if (selected >= 0 && !items[selected]?.disabled) return selected;
6
+ return items.findIndex((item) => !item.disabled);
7
+ }
8
+ function useRoving(count, select, { followFocus = false, columns } = {}) {
9
+ const buttons = useRef([]);
10
+ const [landed, setLanded] = useState(null);
11
+ function step(from, by) {
12
+ for (let i = 0; i < count; i += 1) {
13
+ const at = ((from + by * i) % count + count) % count;
14
+ const el = buttons.current[at];
15
+ if (el && !el.disabled) return at;
16
+ }
17
+ return null;
18
+ }
19
+ function rowStep(at, by, across) {
20
+ const target = at + by * across;
21
+ if (target < 0 || target >= count) return null;
22
+ const el = buttons.current[target];
23
+ return el && !el.disabled ? target : null;
24
+ }
25
+ function moveTo(key, at, vertical) {
26
+ if (count === 0) return null;
27
+ if (columns !== void 0 && (key === "ArrowDown" || key === "ArrowUp")) {
28
+ return rowStep(at, key === "ArrowDown" ? 1 : -1, columns);
29
+ }
30
+ switch (key) {
31
+ case "ArrowRight":
32
+ return step(at + 1, 1);
33
+ case "ArrowLeft":
34
+ return step(at - 1, -1);
35
+ case "ArrowDown":
36
+ return vertical ? step(at + 1, 1) : null;
37
+ case "ArrowUp":
38
+ return vertical ? step(at - 1, -1) : null;
39
+ case "Home":
40
+ return step(0, 1);
41
+ case "End":
42
+ return step(count - 1, -1);
43
+ default:
44
+ return null;
45
+ }
46
+ }
47
+ const onFocusAt = (index) => {
48
+ if (followFocus) setLanded(index);
49
+ };
50
+ const onKeyDown = (event, vertical) => {
51
+ const at = buttons.current.findIndex((button) => button === document.activeElement);
52
+ if (at < 0) return;
53
+ const next = moveTo(event.key, at, vertical);
54
+ if (next === null) return;
55
+ event.preventDefault();
56
+ buttons.current[next]?.focus();
57
+ onFocusAt(next);
58
+ select?.(next);
59
+ };
60
+ return {
61
+ buttons,
62
+ onKeyDown,
63
+ onFocusAt,
64
+ /*
65
+ * Where the stop belongs, or null for "on the caller's selection, as
66
+ * ever". Bounded by the CURRENT count, because a row whose options
67
+ * changed under a remembered index would otherwise put its only stop past
68
+ * its own end, where Tab finds nothing at all.
69
+ */
70
+ focused: followFocus && landed !== null && landed < count ? landed : null
71
+ };
72
+ }
73
+
74
+ export { tabStop, useRoving };
@@ -1,4 +1,4 @@
1
- import { avatarCorner, Avatar } from './chunk-IA232OTU.js';
1
+ import { avatarCorner, Avatar } from './chunk-UDW3DAP5.js';
2
2
  import './ImageUpload-L2GE4JUM.css';
3
3
  import { useRef } from 'react';
4
4
  import { CameraGlyph, XGlyph } from '@crewlethq/icons/glyphs';
@@ -1,13 +1,13 @@
1
1
  import { Toolbar } from './chunk-PGRPNDWM.js';
2
- import { PageHeader } from './chunk-HOXGBLEY.js';
3
2
  import { RelativeTime } from './chunk-3CZ7XAVY.js';
3
+ import { PageHeader } from './chunk-HOXGBLEY.js';
4
4
  import { Kbd } from './chunk-SMBKXWML.js';
5
- import { DataTable } from './chunk-KTIEJ5Q5.js';
5
+ import { useListbox, useOptionKeys } from './chunk-6MU7HNB4.js';
6
+ import { Input } from './chunk-ZGX2DP7F.js';
7
+ import { DataTable } from './chunk-CVB7O3SZ.js';
6
8
  import { Menu } from './chunk-LSB3EHBW.js';
7
9
  import { DateTimePicker } from './chunk-5I56UXBJ.js';
8
10
  import { Popover } from './chunk-PDUZO35I.js';
9
- import { useListbox, useOptionKeys } from './chunk-6MU7HNB4.js';
10
- import { Input } from './chunk-ZGX2DP7F.js';
11
11
  import { Count } from './chunk-BHHIIK3M.js';
12
12
  import { IconButton } from './chunk-4FQT6ZAY.js';
13
13
  import { Button } from './chunk-OG6CL3EB.js';
@@ -1,69 +1,10 @@
1
+ import { useRoving, tabStop } from './chunk-CBOICT64.js';
1
2
  import { Count } from './chunk-BHHIIK3M.js';
2
3
  import { cx } from './chunk-ODEQTPFM.js';
3
4
  import './Tabs-BWFQSWY3.css';
4
- import React, { useRef, useState, useLayoutEffect } from 'react';
5
+ import React, { useRef, useLayoutEffect } from 'react';
5
6
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
7
 
7
- function tabStop(items, selected) {
8
- if (selected >= 0 && !items[selected]?.disabled) return selected;
9
- return items.findIndex((item) => !item.disabled);
10
- }
11
- function useRoving(count, select, { followFocus = false } = {}) {
12
- const buttons = useRef([]);
13
- const [landed, setLanded] = useState(null);
14
- function step(from, by) {
15
- for (let i = 0; i < count; i += 1) {
16
- const at = ((from + by * i) % count + count) % count;
17
- const el = buttons.current[at];
18
- if (el && !el.disabled) return at;
19
- }
20
- return null;
21
- }
22
- function moveTo(key, at, vertical) {
23
- if (count === 0) return null;
24
- switch (key) {
25
- case "ArrowRight":
26
- return step(at + 1, 1);
27
- case "ArrowLeft":
28
- return step(at - 1, -1);
29
- case "ArrowDown":
30
- return vertical ? step(at + 1, 1) : null;
31
- case "ArrowUp":
32
- return vertical ? step(at - 1, -1) : null;
33
- case "Home":
34
- return step(0, 1);
35
- case "End":
36
- return step(count - 1, -1);
37
- default:
38
- return null;
39
- }
40
- }
41
- const onFocusAt = (index) => {
42
- if (followFocus) setLanded(index);
43
- };
44
- const onKeyDown = (event, vertical) => {
45
- const at = buttons.current.findIndex((button) => button === document.activeElement);
46
- if (at < 0) return;
47
- const next = moveTo(event.key, at, vertical);
48
- if (next === null) return;
49
- event.preventDefault();
50
- buttons.current[next]?.focus();
51
- onFocusAt(next);
52
- select?.(next);
53
- };
54
- return {
55
- buttons,
56
- onKeyDown,
57
- onFocusAt,
58
- /*
59
- * Where the stop belongs, or null for "on the caller's selection, as
60
- * ever". Bounded by the CURRENT count, because a row whose options
61
- * changed under a remembered index would otherwise put its only stop past
62
- * its own end, where Tab finds nothing at all.
63
- */
64
- focused: followFocus && landed !== null && landed < count ? landed : null
65
- };
66
- }
67
8
  function tabId(panelId, value) {
68
9
  return `${panelId}-tab-${value}`;
69
10
  }
@@ -184,4 +125,4 @@ function TabPanel({ id, value, children, className }) {
184
125
  );
185
126
  }
186
127
 
187
- export { TabPanel, Tabs, tabId, tabStop, useRoving };
128
+ export { TabPanel, Tabs, tabId };
@@ -0,0 +1,73 @@
1
+ import { useRoving, tabStop } from './chunk-CBOICT64.js';
2
+ import { Avatar } from './chunk-UDW3DAP5.js';
3
+ import { cx } from './chunk-ODEQTPFM.js';
4
+ import './CharacterPicker-ZEYIKUNQ.css';
5
+ import { CREWLET_CHARACTERS, CREWLET_CHARACTER_GEOMETRY } from '@crewlethq/icons/characters';
6
+ import { jsx } from 'react/jsx-runtime';
7
+
8
+ var CHARACTER_PICKER_COLUMNS = 6;
9
+ function CharacterPicker({
10
+ label,
11
+ value,
12
+ onValueChange,
13
+ hue,
14
+ characters = CREWLET_CHARACTERS,
15
+ disabled = false,
16
+ className,
17
+ ...rest
18
+ }) {
19
+ const { buttons, onKeyDown, onFocusAt } = useRoving(
20
+ characters.length,
21
+ disabled ? null : (index) => onValueChange(characters[index]),
22
+ { columns: CHARACTER_PICKER_COLUMNS }
23
+ );
24
+ const options = characters.map(() => ({ disabled }));
25
+ const stop = tabStop(options, characters.indexOf(value));
26
+ return /* @__PURE__ */ jsx(
27
+ "div",
28
+ {
29
+ ...rest,
30
+ role: "radiogroup",
31
+ "aria-label": label,
32
+ "aria-disabled": disabled || void 0,
33
+ className: cx("crewlet-character-picker", className),
34
+ children: characters.map((character, index) => {
35
+ const chosen = character === value;
36
+ const { name } = CREWLET_CHARACTER_GEOMETRY[character];
37
+ return /* @__PURE__ */ jsx(
38
+ "button",
39
+ {
40
+ ref: (el) => {
41
+ buttons.current[index] = el;
42
+ },
43
+ type: "button",
44
+ role: "radio",
45
+ "aria-checked": chosen,
46
+ "aria-label": name,
47
+ title: name,
48
+ tabIndex: index === stop ? 0 : -1,
49
+ disabled,
50
+ className: cx("crewlet-character-picker__option", chosen && "is-chosen"),
51
+ onClick: () => onValueChange(character),
52
+ onFocus: () => onFocusAt(index),
53
+ onKeyDown: (event) => onKeyDown(event, true),
54
+ children: /* @__PURE__ */ jsx(
55
+ Avatar,
56
+ {
57
+ kind: "agent",
58
+ character,
59
+ hue,
60
+ size: "lg",
61
+ ring: chosen ? "brand" : void 0,
62
+ decorative: true
63
+ }
64
+ )
65
+ },
66
+ character
67
+ );
68
+ })
69
+ }
70
+ );
71
+ }
72
+
73
+ export { CHARACTER_PICKER_COLUMNS, CharacterPicker };
@@ -1,4 +1,4 @@
1
- import { Avatar } from './chunk-IA232OTU.js';
1
+ import { Avatar } from './chunk-UDW3DAP5.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './OrgLabel-6WSKJQOT.css';
4
4
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -1,6 +1,6 @@
1
1
  import { TreeGrid } from './chunk-SX2DFTQV.js';
2
2
  import { createTreeModel, treeParent } from './chunk-S3BCVWTU.js';
3
- import { OrgLabel } from './chunk-B47YUQGM.js';
3
+ import { OrgLabel } from './chunk-J3IS2TOA.js';
4
4
  import { AddPill } from './chunk-74WGARJE.js';
5
5
  import { IconButton } from './chunk-4FQT6ZAY.js';
6
6
  import { cx } from './chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- import { OrgLabel } from './chunk-B47YUQGM.js';
1
+ import { OrgLabel } from './chunk-J3IS2TOA.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './OrgNode-TCHJH5FO.css';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
@@ -1,9 +1,8 @@
1
- import { useRoving, tabStop, tabId } from './chunk-DRHXRGB6.js';
1
+ import { tabId } from './chunk-HEOVQZL7.js';
2
+ import { useRoving, tabStop } from './chunk-CBOICT64.js';
2
3
  import { Count } from './chunk-BHHIIK3M.js';
3
4
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
4
5
  import { cx } from './chunk-ODEQTPFM.js';
5
- import './Tabs-BWFQSWY3.css';
6
- import './SegmentedControl-76HODRBT.css';
7
6
  import { useId } from 'react';
8
7
  import { jsxs, jsx } from 'react/jsx-runtime';
9
8
 
@@ -0,0 +1,68 @@
1
+ import { AVATAR_SIZES, Avatar } from './chunk-UDW3DAP5.js';
2
+ import { cx } from './chunk-ODEQTPFM.js';
3
+ import './Avatar-JAU77SHZ.css';
4
+ import './AvatarStack-GEJBNV7E.css';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ function counted(count, one, many) {
8
+ return `${count} ${count === 1 ? one : many}`;
9
+ }
10
+ function avatarStackLabel(members) {
11
+ const humans = members.filter((member) => member.kind === "human").length;
12
+ const agents = members.length - humans;
13
+ const agentWords = counted(agents, "agent", "agents");
14
+ const humanWords = counted(humans, "person", "people");
15
+ const who = humans === 0 ? agentWords : agents === 0 ? humanWords : `${agentWords} and ${humanWords}`;
16
+ return `${who}: ${members.map((member) => member.name).join(", ")}`;
17
+ }
18
+ function AvatarStack({
19
+ members,
20
+ max = 4,
21
+ size = "sm",
22
+ label,
23
+ decorative = false,
24
+ className,
25
+ style,
26
+ ...rest
27
+ }) {
28
+ if (!Number.isInteger(max) || max < 1) {
29
+ throw new RangeError(`AvatarStack max must be a whole number of at least 1; it was ${max}`);
30
+ }
31
+ if (members.length === 0) return null;
32
+ const shown = members.slice(0, max);
33
+ const overflow = members.length - shown.length;
34
+ return /* @__PURE__ */ jsxs(
35
+ "span",
36
+ {
37
+ ...rest,
38
+ className: cx("crewlet-avatar-stack", className),
39
+ style: { "--crewlet-avatar-stack-size": `${AVATAR_SIZES[size]}px`, ...style },
40
+ role: decorative ? void 0 : "img",
41
+ "aria-label": decorative ? void 0 : label ?? avatarStackLabel(members),
42
+ "aria-hidden": decorative ? true : void 0,
43
+ children: [
44
+ shown.map((member) => /* @__PURE__ */ jsx(
45
+ Avatar,
46
+ {
47
+ className: "crewlet-avatar-stack__member",
48
+ name: member.name,
49
+ kind: member.kind,
50
+ src: member.src,
51
+ ring: member.ring,
52
+ character: member.character,
53
+ hue: member.hue,
54
+ size,
55
+ decorative: true
56
+ },
57
+ member.id ?? member.name
58
+ )),
59
+ overflow > 0 ? /* @__PURE__ */ jsxs("span", { className: "crewlet-avatar-stack__member crewlet-avatar-stack__more", "aria-hidden": "true", children: [
60
+ "+",
61
+ overflow
62
+ ] }) : null
63
+ ]
64
+ }
65
+ );
66
+ }
67
+
68
+ export { AvatarStack, avatarStackLabel };
@@ -1,11 +1,11 @@
1
1
  import { cx } from './chunk-ODEQTPFM.js';
2
- import './Avatar-XID7Z74C.css';
3
- import './AvatarStack-GEJBNV7E.css';
4
2
  import { useState, useEffect } from 'react';
5
- import { jsx, jsxs } from 'react/jsx-runtime';
3
+ import { CrewletCharacter } from '@crewlethq/icons/characters';
4
+ import { jsx } from 'react/jsx-runtime';
6
5
 
7
6
  var AVATAR_SIZES = { xs: 20, sm: 26, md: 32, lg: 40 };
8
7
  var AVATAR_CORNER_RATIO = 0.29;
8
+ var AVATAR_CHARACTER_FULL_DETAIL = 56;
9
9
  var getInitials = (name) => {
10
10
  if (!name) return "?";
11
11
  const words = name.trim().split(/[\s\-_.]+/).filter(Boolean);
@@ -40,6 +40,8 @@ var Avatar = ({
40
40
  ring,
41
41
  decorative = false,
42
42
  colorSeed,
43
+ character,
44
+ hue,
43
45
  className,
44
46
  style,
45
47
  ...rest
@@ -62,6 +64,31 @@ var Avatar = ({
62
64
  ring === void 0 ? null : `crewlet-avatar--ring-${ring}`,
63
65
  className
64
66
  );
67
+ if (character !== void 0 && kind === "agent") {
68
+ return /* @__PURE__ */ jsx(
69
+ "span",
70
+ {
71
+ ...rest,
72
+ className: cx(
73
+ classes,
74
+ "crewlet-avatar--character",
75
+ hue === void 0 ? "crewlet-avatar--neutral" : `crewlet-avatar--hue-${hue}`
76
+ ),
77
+ style: { ...measured, ...style },
78
+ role: decorative ? void 0 : "img",
79
+ "aria-hidden": decorative ? true : void 0,
80
+ "aria-label": decorative ? void 0 : name ? `${name} avatar` : "Avatar",
81
+ children: /* @__PURE__ */ jsx(
82
+ CrewletCharacter,
83
+ {
84
+ className: "crewlet-avatar__character",
85
+ character,
86
+ detail: pixels >= AVATAR_CHARACTER_FULL_DETAIL ? "full" : "compact"
87
+ }
88
+ )
89
+ }
90
+ );
91
+ }
65
92
  if (src && !imageFailed) {
66
93
  return /* @__PURE__ */ jsx(
67
94
  "img",
@@ -94,63 +121,5 @@ var Avatar = ({
94
121
  }
95
122
  );
96
123
  };
97
- function counted(count, one, many) {
98
- return `${count} ${count === 1 ? one : many}`;
99
- }
100
- function avatarStackLabel(members) {
101
- const humans = members.filter((member) => member.kind === "human").length;
102
- const agents = members.length - humans;
103
- const agentWords = counted(agents, "agent", "agents");
104
- const humanWords = counted(humans, "person", "people");
105
- const who = humans === 0 ? agentWords : agents === 0 ? humanWords : `${agentWords} and ${humanWords}`;
106
- return `${who}: ${members.map((member) => member.name).join(", ")}`;
107
- }
108
- function AvatarStack({
109
- members,
110
- max = 4,
111
- size = "sm",
112
- label,
113
- decorative = false,
114
- className,
115
- style,
116
- ...rest
117
- }) {
118
- if (!Number.isInteger(max) || max < 1) {
119
- throw new RangeError(`AvatarStack max must be a whole number of at least 1; it was ${max}`);
120
- }
121
- if (members.length === 0) return null;
122
- const shown = members.slice(0, max);
123
- const overflow = members.length - shown.length;
124
- return /* @__PURE__ */ jsxs(
125
- "span",
126
- {
127
- ...rest,
128
- className: cx("crewlet-avatar-stack", className),
129
- style: { "--crewlet-avatar-stack-size": `${AVATAR_SIZES[size]}px`, ...style },
130
- role: decorative ? void 0 : "img",
131
- "aria-label": decorative ? void 0 : label ?? avatarStackLabel(members),
132
- "aria-hidden": decorative ? true : void 0,
133
- children: [
134
- shown.map((member) => /* @__PURE__ */ jsx(
135
- Avatar,
136
- {
137
- className: "crewlet-avatar-stack__member",
138
- name: member.name,
139
- kind: member.kind,
140
- src: member.src,
141
- ring: member.ring,
142
- size,
143
- decorative: true
144
- },
145
- member.id ?? member.name
146
- )),
147
- overflow > 0 ? /* @__PURE__ */ jsxs("span", { className: "crewlet-avatar-stack__member crewlet-avatar-stack__more", "aria-hidden": "true", children: [
148
- "+",
149
- overflow
150
- ] }) : null
151
- ]
152
- }
153
- );
154
- }
155
124
 
156
- export { AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, AvatarStack, avatarCorner, avatarPixels, avatarStackLabel, avatarTint, getInitials };
125
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials };
@@ -0,0 +1,2 @@
1
+ import './Tabs-BWFQSWY3.css';
2
+ import './SegmentedControl-76HODRBT.css';
@@ -1,5 +1,5 @@
1
1
  import { useThemePreference, useDensityPreference } from './chunk-K3OWD7BJ.js';
2
- import { SegmentedControl } from './chunk-N5KCGFWI.js';
2
+ import { SegmentedControl } from './chunk-LPHHDCN3.js';
3
3
  import { SunGlyph, MonitorGlyph, MoonGlyph } from '@crewlethq/icons/glyphs';
4
4
  import { jsx } from 'react/jsx-runtime';
5
5
 
@@ -1,4 +1,4 @@
1
- import { Avatar } from './chunk-IA232OTU.js';
1
+ import { Avatar } from './chunk-UDW3DAP5.js';
2
2
  import { cx } from './chunk-ODEQTPFM.js';
3
3
  import './EntityChip-LUCPZBBG.css';
4
4
  import { Children, isValidElement, cloneElement } from 'react';
@@ -9,6 +9,7 @@ export * from '../CalendarGrid/index.js';
9
9
  export * from '../Callout/index.js';
10
10
  export * from '../Canvas/index.js';
11
11
  export * from '../Card/index.js';
12
+ export * from '../CharacterPicker/index.js';
12
13
  export * from '../Charts/index.js';
13
14
  export * from '../Checkbox/index.js';
14
15
  export * from '../CodeBlock/index.js';
@@ -30,6 +31,7 @@ export * from '../ErrorBoundary/index.js';
30
31
  export * from '../Eyebrow/index.js';
31
32
  export * from '../FilterChip/index.js';
32
33
  export * from '../Fullscreen/index.js';
34
+ export * from '../HuePicker/index.js';
33
35
  export * from '../IconButton/index.js';
34
36
  export * from '../ImageUpload/index.js';
35
37
  export * from '../InlineCode/index.js';