@crewlethq/ui 0.8.0 → 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.
- package/README.md +12 -2
- package/dist/Avatar/Avatar.d.ts +23 -2
- package/dist/Avatar/AvatarStack.d.ts +6 -0
- package/dist/Avatar/index.d.ts +1 -1
- package/dist/Avatar/index.js +2 -1
- package/dist/{Avatar-XID7Z74C.css → Avatar-JAU77SHZ.css} +73 -9
- package/dist/CharacterPicker/CharacterPicker.d.ts +38 -0
- package/dist/CharacterPicker/index.d.ts +3 -0
- package/dist/CharacterPicker/index.js +4 -0
- package/dist/CharacterPicker-ZEYIKUNQ.css +42 -0
- package/dist/Charts/index.js +1 -1
- package/dist/{Charts-THPA5BWV.css → Charts-JUERFLAR.css} +60 -15
- package/dist/CommandPalette/index.js +2 -2
- package/dist/DataTable/index.js +3 -3
- package/dist/DataView/index.js +10 -10
- package/dist/EntityChip/index.js +3 -2
- package/dist/HuePicker/HuePicker.d.ts +26 -0
- package/dist/HuePicker/index.d.ts +3 -0
- package/dist/HuePicker/index.js +8 -0
- package/dist/HuePicker-5QIUR6L7.css +18 -0
- package/dist/ImageUpload/index.js +3 -2
- package/dist/OrgLabel/index.js +3 -2
- package/dist/OrgNode/index.js +4 -3
- package/dist/OrgTable/index.js +4 -3
- package/dist/SegmentedControl/index.js +4 -2
- package/dist/Tabs/index.js +2 -1
- package/dist/Tabs/roving.d.ts +9 -1
- package/dist/ThemeSwitcher/index.js +5 -3
- package/dist/TimeWindowPicker/index.js +3 -3
- package/dist/TreeCanvas/TreeCanvas.d.ts +5 -13
- package/dist/chunk-26TXVHN2.js +31 -0
- package/dist/{chunk-6VL4LGWC.js → chunk-4WNNEDKO.js} +1 -1
- package/dist/chunk-AYKXMIOR.js +13 -0
- package/dist/chunk-CBOICT64.js +74 -0
- package/dist/{chunk-W4GQWFRX.js → chunk-E3HDS4F7.js} +1 -1
- package/dist/{chunk-CHG7VT2M.js → chunk-EUT7VBQG.js} +5 -5
- package/dist/{chunk-DRHXRGB6.js → chunk-HEOVQZL7.js} +3 -62
- package/dist/chunk-IKH3Y4MP.js +73 -0
- package/dist/{chunk-B47YUQGM.js → chunk-J3IS2TOA.js} +1 -1
- package/dist/{chunk-6SIG5I72.js → chunk-JB6AN4ZC.js} +1 -1
- package/dist/{chunk-VCOELPCT.js → chunk-K7OS4O2U.js} +1 -1
- package/dist/{chunk-N5KCGFWI.js → chunk-LPHHDCN3.js} +2 -3
- package/dist/chunk-OAH4IEQJ.js +68 -0
- package/dist/{chunk-IA232OTU.js → chunk-UDW3DAP5.js} +31 -62
- package/dist/chunk-UI6HWAWE.js +2 -0
- package/dist/{chunk-RHHGLTXJ.js → chunk-X6K6OZ47.js} +1 -1
- package/dist/{chunk-WSOFKOLP.js → chunk-Y2V3TSQC.js} +1 -1
- package/dist/generated/index.d.ts +2 -0
- package/dist/generated/index.js +41 -35
- package/dist/index.js +41 -35
- package/dist/styles.css +201 -26
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -1
- package/dist/utils/nodeHue.d.ts +25 -0
- package/dist/utils/tone.d.ts +4 -1
- package/package.json +3 -3
- package/dist/{chunk-IJ7QXNIJ.js → chunk-AER7UDD4.js} +0 -0
- package/dist/{chunk-QJZ3Y6WW.js → chunk-CVB7O3SZ.js} +2 -2
- package/dist/{chunk-BXPLX7YU.js → chunk-IGWPZZIB.js} +1 -1
- package/dist/{chunk-HVPC2GHY.js → chunk-IZHN5I3H.js} +1 -1
- /package/dist/{chunk-PKIN4IMB.js → chunk-YPTC4TX5.js} +0 -0
package/dist/Tabs/roving.d.ts
CHANGED
|
@@ -36,6 +36,14 @@ export interface RovingOptions {
|
|
|
36
36
|
* a refinement of it.
|
|
37
37
|
*/
|
|
38
38
|
followFocus?: boolean | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* How many options a row of a GRID holds, for options laid out in rows and
|
|
41
|
+
* columns (a picker of tiles): Up and Down then move a whole row, to the
|
|
42
|
+
* option above or below, and stop at the grid's edge rather than wrap into
|
|
43
|
+
* another column. Left and Right still walk the options in reading order.
|
|
44
|
+
* Unset, the options are one line.
|
|
45
|
+
*/
|
|
46
|
+
columns?: number | undefined;
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
49
|
* Roving focus over a row of buttons: ONE TAB STOP for the row, the arrows to
|
|
@@ -59,7 +67,7 @@ export interface RovingOptions {
|
|
|
59
67
|
* focus, so a move that lands on one drops focus on the page body and the
|
|
60
68
|
* next arrow press does nothing at all.
|
|
61
69
|
*/
|
|
62
|
-
export declare function useRoving(count: number, select: ((index: number) => void) | null, { followFocus }?: RovingOptions): {
|
|
70
|
+
export declare function useRoving(count: number, select: ((index: number) => void) | null, { followFocus, columns }?: RovingOptions): {
|
|
63
71
|
buttons: import("react").RefObject<(HTMLButtonElement | null)[]>;
|
|
64
72
|
onKeyDown: (event: KeyboardEvent<HTMLElement>, vertical: boolean) => void;
|
|
65
73
|
onFocusAt: (index: number) => void;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
export { DensitySwitcher, ThemeSwitcher } from '../chunk-
|
|
1
|
+
export { DensitySwitcher, ThemeSwitcher } from '../chunk-X6K6OZ47.js';
|
|
2
2
|
export { applyDensity, applyStoredPreferences, applyTheme, resolveTheme, useDensityPreference, useSystemTheme, useThemePreference } from '../chunk-K3OWD7BJ.js';
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-UI6HWAWE.js';
|
|
4
|
+
import '../chunk-LPHHDCN3.js';
|
|
5
|
+
import '../chunk-HEOVQZL7.js';
|
|
6
|
+
import '../chunk-CBOICT64.js';
|
|
5
7
|
import '../chunk-BHHIIK3M.js';
|
|
6
8
|
import '../chunk-BZFWDIV6.js';
|
|
7
9
|
import '../chunk-ODEQTPFM.js';
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-
|
|
1
|
+
export { DEFAULT_TIME_WINDOW_LABELS, TIME_WINDOW_SPANS, TimeWindowPicker, describeTimeWindow, isTimeWindowSet, parseTimeWindowDuration, resolveTimeWindow, timeWindowMatchesPreset } from '../chunk-IZHN5I3H.js';
|
|
2
2
|
import '../chunk-SEFMO2EV.js';
|
|
3
|
-
import '../chunk-PDUZO35I.js';
|
|
4
|
-
import '../chunk-GXQ3B46I.js';
|
|
5
3
|
import '../chunk-6MU7HNB4.js';
|
|
6
4
|
import '../chunk-ZGX2DP7F.js';
|
|
5
|
+
import '../chunk-PDUZO35I.js';
|
|
6
|
+
import '../chunk-GXQ3B46I.js';
|
|
7
7
|
import '../chunk-PQADV6P6.js';
|
|
8
8
|
import '../chunk-7RPGY3JE.js';
|
|
9
9
|
import '../chunk-R25RGPUB.js';
|
|
@@ -78,26 +78,18 @@
|
|
|
78
78
|
import { type KeyboardEvent, type MouseEvent, type ReactNode, type Ref } from 'react';
|
|
79
79
|
import { type CanvasGround, type CanvasLabels } from '../Canvas/index.js';
|
|
80
80
|
import { type TreeConnectorShape, type TreeInput, type TreeItemAction, type LayoutRanks, type TreeModel, type TreeViewHandle } from '../Tree/index.js';
|
|
81
|
+
import type { NodeHue } from '../utils/nodeHue.js';
|
|
81
82
|
/** A card of the layout: its id and the cards nested under it. */
|
|
82
83
|
export interface TreeCardInput {
|
|
83
84
|
id: string;
|
|
84
85
|
children: TreeCardInput[];
|
|
85
86
|
}
|
|
86
87
|
/**
|
|
87
|
-
* The
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* nothing, so the palette is not measured for separability and the chart owes
|
|
91
|
-
* no legend (`--color-node-*` in the tokens package says the same). It is what
|
|
92
|
-
* an operator picks for one agent so they can find it again, and what a chart
|
|
93
|
-
* with no such choice derives from a stable identity.
|
|
94
|
-
*
|
|
95
|
-
* A NAMED SET RATHER THAN A COLOUR. A caller that could hand in any colour
|
|
96
|
-
* would hand in a literal, and the fill, the border and the ink of a tinted
|
|
97
|
-
* card are measured steps of one hue rather than one value with alphas applied
|
|
98
|
-
* by whoever drew it last.
|
|
88
|
+
* The hue a card is tinted with, and the connector arriving at it: one of the
|
|
89
|
+
* six an operator chooses an entity's hue from ([NodeHue]), so an agent's card
|
|
90
|
+
* wears the same hue as its avatar and its row.
|
|
99
91
|
*/
|
|
100
|
-
export type TreeCardTone =
|
|
92
|
+
export type TreeCardTone = NodeHue;
|
|
101
93
|
/**
|
|
102
94
|
* The props that make an element the pointer-only strip of controls beside a
|
|
103
95
|
* node: see `TreeCardContext.actions`.
|
|
@@ -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 };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { VisuallyHidden } from './chunk-BZFWDIV6.js';
|
|
2
2
|
import { cx } from './chunk-ODEQTPFM.js';
|
|
3
|
-
import './Charts-
|
|
3
|
+
import './Charts-JUERFLAR.css';
|
|
4
4
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
5
5
|
import { useState, useRef, useCallback, useId } from 'react';
|
|
6
6
|
|
|
@@ -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,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';
|
|
4
|
-
import {
|
|
5
|
-
import { Popover } from './chunk-PDUZO35I.js';
|
|
6
|
-
import { DataTable } from './chunk-QJZ3Y6WW.js';
|
|
7
|
-
import { Menu } from './chunk-LSB3EHBW.js';
|
|
3
|
+
import { PageHeader } from './chunk-HOXGBLEY.js';
|
|
8
4
|
import { Kbd } from './chunk-SMBKXWML.js';
|
|
9
5
|
import { useListbox, useOptionKeys } from './chunk-6MU7HNB4.js';
|
|
10
6
|
import { Input } from './chunk-ZGX2DP7F.js';
|
|
7
|
+
import { DataTable } from './chunk-CVB7O3SZ.js';
|
|
8
|
+
import { Menu } from './chunk-LSB3EHBW.js';
|
|
9
|
+
import { DateTimePicker } from './chunk-5I56UXBJ.js';
|
|
10
|
+
import { Popover } from './chunk-PDUZO35I.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,
|
|
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
|
|
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,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-
|
|
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,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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,
|
|
125
|
+
export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useThemePreference, useDensityPreference } from './chunk-K3OWD7BJ.js';
|
|
2
|
-
import { SegmentedControl } from './chunk-
|
|
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
|
|
|
@@ -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';
|