@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.
Files changed (61) 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/Charts/index.js +1 -1
  12. package/dist/{Charts-THPA5BWV.css → Charts-JUERFLAR.css} +60 -15
  13. package/dist/CommandPalette/index.js +2 -2
  14. package/dist/DataTable/index.js +3 -3
  15. package/dist/DataView/index.js +10 -10
  16. package/dist/EntityChip/index.js +3 -2
  17. package/dist/HuePicker/HuePicker.d.ts +26 -0
  18. package/dist/HuePicker/index.d.ts +3 -0
  19. package/dist/HuePicker/index.js +8 -0
  20. package/dist/HuePicker-5QIUR6L7.css +18 -0
  21. package/dist/ImageUpload/index.js +3 -2
  22. package/dist/OrgLabel/index.js +3 -2
  23. package/dist/OrgNode/index.js +4 -3
  24. package/dist/OrgTable/index.js +4 -3
  25. package/dist/SegmentedControl/index.js +4 -2
  26. package/dist/Tabs/index.js +2 -1
  27. package/dist/Tabs/roving.d.ts +9 -1
  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-6VL4LGWC.js → chunk-4WNNEDKO.js} +1 -1
  33. package/dist/chunk-AYKXMIOR.js +13 -0
  34. package/dist/chunk-CBOICT64.js +74 -0
  35. package/dist/{chunk-W4GQWFRX.js → chunk-E3HDS4F7.js} +1 -1
  36. package/dist/{chunk-CHG7VT2M.js → chunk-EUT7VBQG.js} +5 -5
  37. package/dist/{chunk-DRHXRGB6.js → chunk-HEOVQZL7.js} +3 -62
  38. package/dist/chunk-IKH3Y4MP.js +73 -0
  39. package/dist/{chunk-B47YUQGM.js → chunk-J3IS2TOA.js} +1 -1
  40. package/dist/{chunk-6SIG5I72.js → chunk-JB6AN4ZC.js} +1 -1
  41. package/dist/{chunk-VCOELPCT.js → chunk-K7OS4O2U.js} +1 -1
  42. package/dist/{chunk-N5KCGFWI.js → chunk-LPHHDCN3.js} +2 -3
  43. package/dist/chunk-OAH4IEQJ.js +68 -0
  44. package/dist/{chunk-IA232OTU.js → chunk-UDW3DAP5.js} +31 -62
  45. package/dist/chunk-UI6HWAWE.js +2 -0
  46. package/dist/{chunk-RHHGLTXJ.js → chunk-X6K6OZ47.js} +1 -1
  47. package/dist/{chunk-WSOFKOLP.js → chunk-Y2V3TSQC.js} +1 -1
  48. package/dist/generated/index.d.ts +2 -0
  49. package/dist/generated/index.js +41 -35
  50. package/dist/index.js +41 -35
  51. package/dist/styles.css +201 -26
  52. package/dist/utils/index.d.ts +2 -0
  53. package/dist/utils/index.js +2 -1
  54. package/dist/utils/nodeHue.d.ts +25 -0
  55. package/dist/utils/tone.d.ts +4 -1
  56. package/package.json +3 -3
  57. package/dist/{chunk-IJ7QXNIJ.js → chunk-AER7UDD4.js} +0 -0
  58. package/dist/{chunk-QJZ3Y6WW.js → chunk-CVB7O3SZ.js} +2 -2
  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-PKIN4IMB.js → chunk-YPTC4TX5.js} +0 -0
package/README.md CHANGED
@@ -42,13 +42,13 @@ import { Button } from '@crewlethq/ui/Button'; // 8 KB of CSS, not 182 KB
42
42
  | ---- | ---------- |
43
43
  | Actions | `Button` and `ButtonLink` (variants `primary`, `secondary`, `outline`, `ghost`, `accent`, `danger`; sizes `small`, `medium`, `large`; shapes `square`, `pill`), `IconButton`, `Menu`, `Link`, `Copyable`, `CopyButton`, `Kbd` |
44
44
  | Content and text | `Text` (the eight registers), `Prose`, `InlineCode`, `List` and `ListItem`, `DescriptionList`, `Timeline`, `RelativeTime` |
45
- | Forms | `Input`, `Textarea`, `Label`, `FormField`, `FormRow`, `Checkbox`, `Select`, `Tag`, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `ImageUpload` |
45
+ | Forms | `Input`, `Textarea`, `Label`, `FormField`, `FormRow`, `Checkbox`, `Select`, `Tag`, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `ImageUpload`, `CharacterPicker`, `HuePicker` |
46
46
  | Data display | `DataTable`, `CopyableCell`, `Table`, `StatCard`, `Meter`, `SegmentedMeter`, `Stepper`, `PricingCard`, `Avatar`, `AvatarStack`, `EntityChip`, `CodeBlock`, `Skeleton`, `Eyebrow` |
47
47
  | List screens | `DataView`, and its parts on their own: `DataViewToolbar`, `FilterAxisBar`, `FilterAxisChip`, plus the filter model (`filterDefsFromColumns`, `applyColumnFilters`, `filterPredicate`, `blankFilterValue`) |
48
48
  | Feedback and overlays | `Callout`, `Toaster`, `Modal` (with `variant="sheet"`), `ConfirmModal`, `CommandPalette`, `Tooltip`, `Popover`, `Announcer` |
49
49
  | Charts | `Legend`, `BarList`, `StackedBar`, `StackedColumns`, `ActivityStrip`, `TimeSeries`, `Sparkline`, the reading layer they share (`ChartTooltip`, `useChartHover`), and the ramp (`DATA_COLORS`, `DATA_COLOR_OTHER`, `dataColor`) |
50
50
  | Marks | `Count`, `StatusDot`, `EmptyValue`, `VisuallyHidden` |
51
- | Hooks and seams | `useModalLayer`, `usePopupLayer`, `LayerHost`, `useListbox`, `useOptionKeys`, `useClipboard`, `useAnnouncer`, `useNow`, `formatRelative`, `HeadingLevelProvider`, `cx` |
51
+ | Hooks and seams | `useModalLayer`, `usePopupLayer`, `LayerHost`, `useListbox`, `useOptionKeys`, `useClipboard`, `useAnnouncer`, `useNow`, `formatRelative`, `HeadingLevelProvider`, `cx`, the node hues (`NODE_HUES`, `NODE_HUE_NAMES`, `isNodeHue`) |
52
52
  | Layout | `Container`, `Section`, `Card`, `Tabs`, `Accordion`, `Disclosure` |
53
53
  | Application shell | `AppShell` with `AppShell.Rail`, `AppShell.Topbar` and `useAppShell`, `SidebarNav` and `NavItem`, `BrandLockup`, `SearchTrigger`, `PageHeader`, `Toolbar`, `Stack`, `Inline`, `Spacer`, `AutoGrid`, `ErrorBoundary`, `useShortcut`, `useFullscreen` |
54
54
  | Preferences | `ThemeToggle`, `ThemeSwitcher`, `DensitySwitcher`, `useThemePreference`, `useDensityPreference`, `useSystemTheme`, `resolveTheme`, `applyStoredPreferences` |
@@ -191,6 +191,16 @@ places:
191
191
  - A surface that pans or zooms dispatches `LAYER_REPOSITION_EVENT` on its host
192
192
  when the content beneath it moves, and every panel anchored inside follows.
193
193
 
194
+ ## Changes in 0.9.0
195
+
196
+ 0.9.0 gives an agent a face of its own: one of the thirty Crewlet characters in `@crewlethq/icons/characters`, drawn in one of the six node hues an operator chooses for it.
197
+
198
+ **An agent's badge can be its character.** `Avatar` takes `character` and `hue`. An agent badge with a `character` draws that character, centred, on a plate of its hue (the hue's `-fill`, its `-line` round the badge and the hue itself as the ink), in place of its initials and of any image. A badge of `AVATAR_CHARACTER_FULL_DETAIL` (56px) and up draws the character's keyline and visor gap; a smaller one draws it compact, where a hairline would be a blur. A `human` badge ignores both and keeps its circle and initials, and what any badge says to a screen reader is unchanged. An `AvatarStack` member takes the same two fields, for a stack of agents drawn as themselves. What to change: nothing; a badge with neither prop draws as it did.
199
+
200
+ **The node hues are one exported set.** `NODE_HUES`, `NODE_HUE_NAMES`, `isNodeHue` and the `NodeHue` type name the six hues an entity is told apart by, where somebody chose one. `TreeCardTone` (and so `OrgTableTone`) is now `NodeHue`, so an agent's card, row and badge are drawn from one list. What to change: nothing; the six names are the same.
201
+
202
+ **Two pickers choose them.** `CharacterPicker` is a radio group of every character, laid out in rows of six (`CHARACTER_PICKER_COLUMNS`), each drawn as the badge it would make in the agent's hue; Left and Right walk the characters, Up and Down move a whole row, and the chosen badge carries the kit's selected ring. `HuePicker` is a `SegmentedControl` radio row of the six hues, each a swatch and the hue's name. Both take `disabled`, which keeps the choice shown and lets nothing in the group take focus or a press. Wrap either in `FormField as="fieldset"` for a labelled field.
203
+
194
204
  ## Changes in 0.7.0
195
205
 
196
206
  0.7.0 draws the org surfaces (`TreeCanvas`'s `node` appearance, `OrgTable`,
@@ -1,4 +1,6 @@
1
1
  import type { HTMLAttributes } from 'react';
2
+ import { type CrewletCharacterId } from '@crewlethq/icons/characters';
3
+ import type { NodeHue } from '../utils/nodeHue.js';
2
4
  import type { Tone } from '../utils/tone.js';
3
5
  /**
4
6
  * WHAT THE BADGE STANDS FOR, drawn as its outline.
@@ -91,7 +93,26 @@ export interface AvatarProps extends HTMLAttributes<HTMLElement> {
91
93
  * outlives a rename, so the colour does too. Only read with `tone="seeded"`.
92
94
  */
93
95
  colorSeed?: string | undefined;
96
+ /**
97
+ * The Crewlet character an AGENT is drawn as, in place of its initials and
98
+ * of any image. A person is never drawn as one: on a `human` badge this is
99
+ * ignored, and the circle and the initials stay.
100
+ */
101
+ character?: CrewletCharacterId | undefined;
102
+ /**
103
+ * The hue the agent's character is drawn in, on a plate of the same hue.
104
+ * Read only with `character`; a character with no hue is drawn in the
105
+ * neutral badge's ink, on its plate.
106
+ */
107
+ hue?: NodeHue | undefined;
94
108
  }
109
+ /**
110
+ * The smallest badge, in px, a character is drawn at full detail: its keyline
111
+ * and its visor gap. Under it both are hairlines finer than a pixel, which a
112
+ * screen draws as a blur round the body, so the character is drawn compact
113
+ * (see `CrewletCharacterDetail`).
114
+ */
115
+ export declare const AVATAR_CHARACTER_FULL_DETAIL = 56;
95
116
  /**
96
117
  * Two uppercase initials, or one where the name has only one letter to give.
97
118
  *
@@ -139,11 +160,11 @@ export declare function avatarPixels(size: AvatarSize): number;
139
160
  */
140
161
  export declare function avatarCorner(pixels: number): number;
141
162
  /**
142
- * An identity badge: an image, or the initials behind it.
163
+ * An identity badge: an agent's character, an image, or the initials behind it.
143
164
  *
144
165
  * If the image fails to load (a stale CDN URL, an expired signature) it
145
166
  * degrades to the initials rather than to a broken-image glyph. Either way it
146
167
  * keeps its kind's outline and its ring: whether somebody has uploaded a photo
147
168
  * says nothing about what they are or what they are doing.
148
169
  */
149
- export declare const Avatar: ({ src, name, size, kind, tone, ring, decorative, colorSeed, className, style, ...rest }: AvatarProps) => import("react").JSX.Element;
170
+ export declare const Avatar: ({ src, name, size, kind, tone, ring, decorative, colorSeed, character, hue, className, style, ...rest }: AvatarProps) => import("react").JSX.Element;
@@ -1,4 +1,6 @@
1
1
  import type { HTMLAttributes } from 'react';
2
+ import type { CrewletCharacterId } from '@crewlethq/icons/characters';
3
+ import type { NodeHue } from '../utils/nodeHue.js';
2
4
  import { type AvatarKind, type AvatarRing, type AvatarSizeStep } from './Avatar.js';
3
5
  /** One badge in a stack. */
4
6
  export interface AvatarStackMember {
@@ -9,6 +11,10 @@ export interface AvatarStackMember {
9
11
  src?: string | undefined;
10
12
  /** A state ring on this badge, as `Avatar` draws it. */
11
13
  ring?: AvatarRing | undefined;
14
+ /** The Crewlet character an agent member is drawn as, as `Avatar` draws it. */
15
+ character?: CrewletCharacterId | undefined;
16
+ /** The hue an agent member's character is drawn in, as `Avatar` draws it. */
17
+ hue?: NodeHue | undefined;
12
18
  /**
13
19
  * What tells two members apart when their names do not (a seat's handle, a
14
20
  * person's id), unique within the stack. The name is used when it is absent.
@@ -1,6 +1,6 @@
1
1
  import './Avatar.css';
2
2
  import './AvatarStack.css';
3
- export { AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials, } from './Avatar.js';
3
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials, } from './Avatar.js';
4
4
  export type { AvatarKind, AvatarProps, AvatarRing, AvatarSize, AvatarSizeStep, AvatarTone } from './Avatar.js';
5
5
  export { AvatarStack, avatarStackLabel } from './AvatarStack.js';
6
6
  export type { AvatarStackMember, AvatarStackProps } from './AvatarStack.js';
@@ -1,2 +1,3 @@
1
- export { AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, AvatarStack, avatarCorner, avatarPixels, avatarStackLabel, avatarTint, getInitials } from '../chunk-IA232OTU.js';
1
+ export { AvatarStack, avatarStackLabel } from '../chunk-OAH4IEQJ.js';
2
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials } from '../chunk-UDW3DAP5.js';
2
3
  import '../chunk-ODEQTPFM.js';
@@ -1,21 +1,28 @@
1
1
  /*
2
2
  * The identity badge.
3
3
  *
4
- * IT IS NEUTRAL, and that is the whole rule. The system this replaces coloured
5
- * a seat by `PALETTE[hash(name) % 8]`, over the same eight families it also
6
- * spent on phases and event categories, so one amber meant "the execute
7
- * phase", "the decision category" and "the Analyst" at once. A hash of a name
8
- * carries no information: rename the seat and its colour changes, which is the
9
- * proof it never meant anything. Identity is the OUTLINE (a squircle for an
10
- * agent, a circle for a person), the monogram and the name.
4
+ * IT IS NEUTRAL UNLESS SOMEBODY CHOSE OTHERWISE, and a hash never chooses. The
5
+ * system this replaces coloured a seat by `PALETTE[hash(name) % 8]`, over the
6
+ * same eight families it also spent on phases and event categories, so one
7
+ * amber meant "the execute phase", "the decision category" and "the Analyst"
8
+ * at once. A hash of a name carries no information: rename the seat and its
9
+ * colour changes, which is the proof it never meant anything. Identity is the
10
+ * OUTLINE (a squircle for an agent, a circle for a person), the monogram and
11
+ * the name, and for an agent an operator gave one, its character and its hue.
11
12
  *
12
- * THE ONE HUE A BADGE CARRIES IS A STATE, as a ring round it, and the ring is
13
- * the component's only coloured line.
13
+ * THE ONE HUE A BADGE CARRIES AS A LINE IS A STATE, as a ring round it, and the
14
+ * ring is the component's only coloured line outside its own plate.
14
15
  *
15
16
  * The seeded tints stay for the one case that earns them, a roster somebody
16
17
  * scans, and their grounds are TOKENS: measured under white initials and held
17
18
  * at 4.5:1 by the palette suite. Spelled as literals, five of the ten sat
18
19
  * under that floor while the suite measured ten values nothing painted with.
20
+ *
21
+ * AN AGENT'S OWN HUE IS NOT A HASH. An agent an operator gave a Crewlet
22
+ * character and a hue is drawn as that character, in that hue, on a plate of
23
+ * it: the hue was chosen for the seat and survives a rename, which a hash of
24
+ * the name never did. It is one of the six node hues (`NodeHue`), each a
25
+ * measured set of steps rather than a colour with alphas applied here.
19
26
  */
20
27
 
21
28
  .crewlet-avatar {
@@ -147,6 +154,63 @@
147
154
  .crewlet-avatar--tint-8 { background: var(--color-avatar-tint-8); }
148
155
  .crewlet-avatar--tint-9 { background: var(--color-avatar-tint-9); }
149
156
 
157
+ /* ── an agent's character ─────────────────────────────────────────────── */
158
+
159
+ /*
160
+ * THE CHARACTER FILLS MOST OF THE PLATE, centred by its own frame (it frames
161
+ * every silhouette square on what it draws), with the plate's corner clear of
162
+ * it: a wide character such as the original Crewlet reaches the plate's
163
+ * sides, a tall one its top and its foot, and none touches the curve.
164
+ */
165
+ .crewlet-avatar--character {
166
+ border: 1px solid transparent;
167
+ }
168
+
169
+ .crewlet-avatar__character {
170
+ display: block;
171
+ flex: none;
172
+ width: 74%;
173
+ height: 74%;
174
+ }
175
+
176
+ /* The plate an agent's hue is drawn on: the hue's fill, its line round the
177
+ badge and the hue itself as the character's ink. */
178
+ .crewlet-avatar--hue-purple {
179
+ background: var(--color-node-purple-fill);
180
+ border-color: var(--color-node-purple-line);
181
+ color: var(--color-node-purple);
182
+ }
183
+
184
+ .crewlet-avatar--hue-cyan {
185
+ background: var(--color-node-cyan-fill);
186
+ border-color: var(--color-node-cyan-line);
187
+ color: var(--color-node-cyan);
188
+ }
189
+
190
+ .crewlet-avatar--hue-green {
191
+ background: var(--color-node-green-fill);
192
+ border-color: var(--color-node-green-line);
193
+ color: var(--color-node-green);
194
+ }
195
+
196
+ .crewlet-avatar--hue-amber {
197
+ background: var(--color-node-amber-fill);
198
+ border-color: var(--color-node-amber-line);
199
+ color: var(--color-node-amber);
200
+ }
201
+
202
+ .crewlet-avatar--hue-rose {
203
+ background: var(--color-node-rose-fill);
204
+ border-color: var(--color-node-rose-line);
205
+ color: var(--color-node-rose);
206
+ }
207
+
208
+ .crewlet-avatar--hue-blue {
209
+ background: var(--color-node-blue-fill);
210
+ border-color: var(--color-node-blue-line);
211
+ color: var(--color-node-blue);
212
+ }
213
+
150
214
  /* ── the state ring ────────────────────────────────────────────────────── */
151
215
 
152
216
  /*
@@ -0,0 +1,38 @@
1
+ import type { HTMLAttributes } from 'react';
2
+ import { type CrewletCharacterId } from '@crewlethq/icons/characters';
3
+ import type { NodeHue } from '../utils/nodeHue.js';
4
+ /**
5
+ * How many characters a row of the grid holds. Thirty characters make five
6
+ * full rows, and a grid that wraps by width would leave the arrow keys
7
+ * guessing which option sits above which.
8
+ */
9
+ export declare const CHARACTER_PICKER_COLUMNS = 6;
10
+ export interface CharacterPickerProps extends Omit<HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
11
+ /** The group's name, said on entering it: "Character". */
12
+ label: string;
13
+ /** The chosen character. */
14
+ value: CrewletCharacterId;
15
+ onValueChange: (character: CrewletCharacterId) => void;
16
+ /** The hue every option is shown in, so the grid previews the agent it will be. */
17
+ hue?: NodeHue | undefined;
18
+ /** The characters offered, in order. Every character, by default. */
19
+ characters?: readonly CrewletCharacterId[] | undefined;
20
+ /** Nothing can be chosen, and the grid says so. */
21
+ disabled?: boolean | undefined;
22
+ }
23
+ /**
24
+ * The choice of an agent's Crewlet character: a grid of the characters, each
25
+ * drawn as the badge it would make, in the agent's own hue.
26
+ *
27
+ * A RADIO GROUP, because a character is a setting and exactly one is chosen:
28
+ * the grid is one tab stop, the arrows move through it and choose as they
29
+ * move, as the platform's own radio group does. Left and Right walk the
30
+ * options in reading order and Up and Down move a whole row, because the
31
+ * options are laid out in rows and an arrow that ignored that would move
32
+ * somewhere the reader is not looking.
33
+ *
34
+ * THE CHOSEN OPTION IS SAID THE WAY THE KIT SAYS SELECTED, with the badge's
35
+ * own `brand` ring, rather than a frame the grid draws round a tile: one
36
+ * badge, one line round it, and the line means "this one".
37
+ */
38
+ export declare function CharacterPicker({ label, value, onValueChange, hue, characters, disabled, className, ...rest }: CharacterPickerProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './CharacterPicker.css';
2
+ export { CHARACTER_PICKER_COLUMNS, CharacterPicker } from './CharacterPicker.js';
3
+ export type { CharacterPickerProps } from './CharacterPicker.js';
@@ -0,0 +1,4 @@
1
+ export { CHARACTER_PICKER_COLUMNS, CharacterPicker } from '../chunk-IKH3Y4MP.js';
2
+ import '../chunk-CBOICT64.js';
3
+ import '../chunk-UDW3DAP5.js';
4
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,42 @@
1
+ /*
2
+ * The grid of characters.
3
+ *
4
+ * SIX COLUMNS, ALWAYS, and the tiles share the width: the arrow keys move a
5
+ * whole row on Up and Down, so a row has to hold the same options at every
6
+ * width (`CHARACTER_PICKER_COLUMNS`). A tile is a target the size of the
7
+ * badge it holds and the gap round it, never smaller than the kit's control
8
+ * floor.
9
+ */
10
+
11
+ .crewlet-character-picker {
12
+ display: grid;
13
+ grid-template-columns: repeat(6, minmax(0, 1fr));
14
+ gap: var(--spacing-1);
15
+ justify-items: center;
16
+ }
17
+
18
+ .crewlet-character-picker__option {
19
+ display: grid;
20
+ place-items: center;
21
+ min-width: var(--size-control-lg);
22
+ min-height: var(--size-control-lg);
23
+ padding: var(--spacing-1);
24
+ border: 0;
25
+ border-radius: var(--radius-md);
26
+ background: transparent;
27
+ cursor: pointer;
28
+ }
29
+
30
+ .crewlet-character-picker__option:hover:not(:disabled) {
31
+ background: var(--color-surface-hover);
32
+ }
33
+
34
+ .crewlet-character-picker__option:focus-visible {
35
+ outline: 2px solid var(--color-focus);
36
+ outline-offset: 2px;
37
+ }
38
+
39
+ .crewlet-character-picker__option:disabled {
40
+ cursor: not-allowed;
41
+ opacity: 0.5;
42
+ }
@@ -1,3 +1,3 @@
1
- export { ActivityStrip, BarList, ChartTooltip, DATA_COLORS, DATA_COLOR_OTHER, Legend, Sparkline, StackedBar, StackedColumns, TimeSeries, dataColor, niceScale, useChartHover } from '../chunk-6VL4LGWC.js';
1
+ export { ActivityStrip, BarList, ChartTooltip, DATA_COLORS, DATA_COLOR_OTHER, Legend, Sparkline, StackedBar, StackedColumns, TimeSeries, dataColor, niceScale, useChartHover } from '../chunk-4WNNEDKO.js';
2
2
  import '../chunk-BZFWDIV6.js';
3
3
  import '../chunk-ODEQTPFM.js';
@@ -213,24 +213,67 @@
213
213
  gap: calc(var(--spacing-1) * 1.5);
214
214
  }
215
215
 
216
+ /*
217
+ * THE BAR STANDS ON THE NAME'S LINE, AND A SPLIT BAR'S KEY ON THE SUB'S. An
218
+ * item is a grid of two columns, the words' and the plot, and two lines. The
219
+ * row spans it and lends its parts to it (`subgrid`), and the words' wrapper
220
+ * lends its own two lines in turn (`display: contents`), so the name and the
221
+ * plot share the first line and are centred on each other, and the sub and a
222
+ * split bar's key share the second, the key starting where the bar starts.
223
+ * Centred on the words' whole column instead, a row with a sub drew its bar,
224
+ * and the value at its end, between the name and the sub, a few pixels below
225
+ * the name it belongs to; and the key stood on a third line of its own, under
226
+ * the sub, where it read as one more bar. A row with neither is one line,
227
+ * centred in the item's height.
228
+ *
229
+ * THE KEY LETS THE POINTER THROUGH. It is outside the row in the markup,
230
+ * because a row that leads somewhere is a link or a button and holds no list,
231
+ * so it is drawn over the row's second line rather than inside it, and a
232
+ * press on it is a press on the row.
233
+ */
234
+ .crewlet-bar-list--beside .crewlet-bar-list__item {
235
+ display: grid;
236
+ grid-template-columns: var(--crewlet-bar-list-label-width) minmax(0, 1fr);
237
+ grid-template-rows: auto auto;
238
+ align-content: center;
239
+ column-gap: var(--spacing-3);
240
+ min-height: var(--size-control-md);
241
+ }
242
+
243
+ /* `gap: normal` is what hands a subgrid its parent's gaps: the stacked
244
+ register's own gap on every row would otherwise move the plot off the
245
+ column the key stands in. */
216
246
  .crewlet-bar-list--beside .crewlet-bar-list__row {
217
- flex-direction: row;
247
+ display: grid;
248
+ grid-column: 1 / -1;
249
+ grid-row: 1 / -1;
250
+ grid-template-columns: subgrid;
251
+ grid-template-rows: subgrid;
218
252
  align-items: center;
219
- gap: var(--spacing-3);
220
- min-height: var(--size-control-md);
253
+ gap: normal;
221
254
  }
222
255
 
223
256
  .crewlet-bar-list__names {
224
- display: flex;
225
- flex: none;
226
- flex-direction: column;
227
- width: var(--crewlet-bar-list-label-width);
228
- min-width: 0;
257
+ display: contents;
229
258
  line-height: var(--font-line-height-tight);
230
259
  }
231
260
 
261
+ .crewlet-bar-list--beside .crewlet-bar-list__names > .crewlet-bar-list__label {
262
+ grid-row: 1;
263
+ grid-column: 1;
264
+ }
265
+
266
+ .crewlet-bar-list--beside .crewlet-bar-list__plot {
267
+ grid-row: 1;
268
+ grid-column: 2;
269
+ }
270
+
271
+ .crewlet-bar-list--beside .crewlet-bar-list__names > .crewlet-bar-list__sub {
272
+ grid-row: 2;
273
+ grid-column: 1;
274
+ }
275
+
232
276
  .crewlet-bar-list--beside .crewlet-bar-list__label {
233
- flex: none;
234
277
  color: var(--color-text-secondary);
235
278
  }
236
279
 
@@ -240,7 +283,6 @@
240
283
 
241
284
  .crewlet-bar-list__plot {
242
285
  display: block;
243
- flex: 1 1 auto;
244
286
  min-width: 0;
245
287
  }
246
288
 
@@ -296,10 +338,10 @@
296
338
  }
297
339
 
298
340
  /*
299
- * THE KEY UNDER A SPLIT BAR, at the caption step, starting where the bar
300
- * starts: under the plot in the BESIDE register, past the words' column and
301
- * the gap after it, so each name stands under the bar it keys rather than
302
- * under the row's own name.
341
+ * THE KEY UNDER A SPLIT BAR, at the caption step. In the BESIDE register it
342
+ * stands on the row's second line, under the bar it keys (see the item's
343
+ * grid above), so each name stands under its part rather than under the
344
+ * row's own name.
303
345
  */
304
346
  .crewlet-bar-list__key {
305
347
  margin-top: var(--spacing-1);
@@ -307,8 +349,11 @@
307
349
  }
308
350
 
309
351
  .crewlet-bar-list--beside .crewlet-bar-list__key {
352
+ grid-row: 2;
353
+ grid-column: 2;
354
+ align-self: center;
310
355
  margin-top: 0;
311
- padding-inline-start: calc(var(--crewlet-bar-list-label-width) + var(--spacing-3));
356
+ pointer-events: none;
312
357
  }
313
358
 
314
359
  /* ─── Stacked bar ─────────────────────────────────────────────── */
@@ -1,8 +1,8 @@
1
- export { CommandPalette } from '../chunk-BXPLX7YU.js';
1
+ export { CommandPalette } from '../chunk-IGWPZZIB.js';
2
2
  import '../chunk-SMBKXWML.js';
3
- import '../chunk-BTHX2FS3.js';
4
3
  import '../chunk-6MU7HNB4.js';
5
4
  import '../chunk-ZGX2DP7F.js';
5
+ import '../chunk-BTHX2FS3.js';
6
6
  import '../chunk-BHHIIK3M.js';
7
7
  import '../chunk-PQADV6P6.js';
8
8
  import '../chunk-7RPGY3JE.js';
@@ -1,10 +1,10 @@
1
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-QJZ3Y6WW.js';
1
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-CVB7O3SZ.js';
2
2
  import '../chunk-LSB3EHBW.js';
3
3
  import '../chunk-EUCC37WY.js';
4
- import '../chunk-YCTMKKRA.js';
4
+ import '../chunk-BTHX2FS3.js';
5
5
  import '../chunk-AV2DXAEL.js';
6
+ import '../chunk-YCTMKKRA.js';
6
7
  import '../chunk-5VNUYO76.js';
7
- import '../chunk-BTHX2FS3.js';
8
8
  import '../chunk-PQADV6P6.js';
9
9
  import '../chunk-7RPGY3JE.js';
10
10
  import '../chunk-R25RGPUB.js';
@@ -1,20 +1,20 @@
1
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-CHG7VT2M.js';
1
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-EUT7VBQG.js';
2
2
  import '../chunk-PGRPNDWM.js';
3
- import '../chunk-HOXGBLEY.js';
4
3
  import '../chunk-3CZ7XAVY.js';
5
- import '../chunk-5I56UXBJ.js';
6
- import '../chunk-PDUZO35I.js';
7
- import '../chunk-QJZ3Y6WW.js';
4
+ import '../chunk-HOXGBLEY.js';
5
+ import '../chunk-SMBKXWML.js';
6
+ import '../chunk-6MU7HNB4.js';
7
+ import '../chunk-ZGX2DP7F.js';
8
+ import '../chunk-CVB7O3SZ.js';
8
9
  import '../chunk-LSB3EHBW.js';
9
10
  import '../chunk-EUCC37WY.js';
10
- import '../chunk-YCTMKKRA.js';
11
+ import '../chunk-BTHX2FS3.js';
12
+ import '../chunk-5I56UXBJ.js';
13
+ import '../chunk-PDUZO35I.js';
11
14
  import '../chunk-GXQ3B46I.js';
12
15
  import '../chunk-AV2DXAEL.js';
16
+ import '../chunk-YCTMKKRA.js';
13
17
  import '../chunk-5VNUYO76.js';
14
- import '../chunk-SMBKXWML.js';
15
- import '../chunk-BTHX2FS3.js';
16
- import '../chunk-6MU7HNB4.js';
17
- import '../chunk-ZGX2DP7F.js';
18
18
  import '../chunk-BHHIIK3M.js';
19
19
  import '../chunk-PQADV6P6.js';
20
20
  import '../chunk-7RPGY3JE.js';
@@ -1,3 +1,4 @@
1
- export { EntityChip } from '../chunk-WSOFKOLP.js';
2
- import '../chunk-IA232OTU.js';
1
+ export { EntityChip } from '../chunk-Y2V3TSQC.js';
2
+ import '../chunk-OAH4IEQJ.js';
3
+ import '../chunk-UDW3DAP5.js';
3
4
  import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,26 @@
1
+ import { type SegmentedSize } from '../SegmentedControl/SegmentedControl.js';
2
+ import { type NodeHue } from '../utils/nodeHue.js';
3
+ export interface HuePickerProps {
4
+ /** The group's name, said on entering it: "Color". */
5
+ label: string;
6
+ value: NodeHue;
7
+ onValueChange: (hue: NodeHue) => void;
8
+ size?: SegmentedSize | undefined;
9
+ /** Nothing can be chosen, and the row says so. */
10
+ disabled?: boolean | undefined;
11
+ className?: string | undefined;
12
+ }
13
+ /**
14
+ * The choice of an entity's hue: the six node hues as a row of chips, each a
15
+ * swatch and the hue's name.
16
+ *
17
+ * THE NAME IS PRINTED, not left to the swatch, because a swatch alone asks the
18
+ * reader to tell six hues apart, which some readers cannot, and says nothing
19
+ * to a screen reader. It is a `SegmentedControl` radio row, so it keeps the
20
+ * kit's one tab stop and the arrows that choose as they move.
21
+ *
22
+ * DISABLED IS EVERY CHIP DISABLED, as `CharacterPicker` is every tile: the
23
+ * row is still read and the chosen hue still shown, and nothing in it takes
24
+ * focus or a press.
25
+ */
26
+ export declare function HuePicker({ label, value, onValueChange, size, disabled, className }: HuePickerProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './HuePicker.css';
2
+ export { HuePicker } from './HuePicker.js';
3
+ export type { HuePickerProps } from './HuePicker.js';
@@ -0,0 +1,8 @@
1
+ export { HuePicker } from '../chunk-26TXVHN2.js';
2
+ import '../chunk-AYKXMIOR.js';
3
+ import '../chunk-LPHHDCN3.js';
4
+ import '../chunk-HEOVQZL7.js';
5
+ import '../chunk-CBOICT64.js';
6
+ import '../chunk-BHHIIK3M.js';
7
+ import '../chunk-BZFWDIV6.js';
8
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,18 @@
1
+ /*
2
+ * A hue's swatch: the hue itself, as a dot beside its name. The name carries
3
+ * the choice; the dot is there so the row can be scanned for a colour.
4
+ */
5
+
6
+ .crewlet-hue-picker__swatch {
7
+ display: block;
8
+ width: var(--spacing-3);
9
+ height: var(--spacing-3);
10
+ border-radius: var(--radius-circle);
11
+ }
12
+
13
+ .crewlet-hue-picker__swatch--purple { background: var(--color-node-purple); }
14
+ .crewlet-hue-picker__swatch--cyan { background: var(--color-node-cyan); }
15
+ .crewlet-hue-picker__swatch--green { background: var(--color-node-green); }
16
+ .crewlet-hue-picker__swatch--amber { background: var(--color-node-amber); }
17
+ .crewlet-hue-picker__swatch--rose { background: var(--color-node-rose); }
18
+ .crewlet-hue-picker__swatch--blue { background: var(--color-node-blue); }
@@ -1,3 +1,4 @@
1
- export { ImageUpload } from '../chunk-W4GQWFRX.js';
2
- import '../chunk-IA232OTU.js';
1
+ export { ImageUpload } from '../chunk-E3HDS4F7.js';
2
+ import '../chunk-OAH4IEQJ.js';
3
+ import '../chunk-UDW3DAP5.js';
3
4
  import '../chunk-ODEQTPFM.js';
@@ -1,3 +1,4 @@
1
- export { OrgLabel } from '../chunk-B47YUQGM.js';
2
- import '../chunk-IA232OTU.js';
1
+ export { OrgLabel } from '../chunk-J3IS2TOA.js';
2
+ import '../chunk-OAH4IEQJ.js';
3
+ import '../chunk-UDW3DAP5.js';
3
4
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,5 @@
1
- export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from '../chunk-VCOELPCT.js';
2
- import '../chunk-B47YUQGM.js';
3
- import '../chunk-IA232OTU.js';
1
+ export { OrgNodeDisclosure, OrgNodeLabel, OrgNodeLead } from '../chunk-K7OS4O2U.js';
2
+ import '../chunk-J3IS2TOA.js';
3
+ import '../chunk-OAH4IEQJ.js';
4
+ import '../chunk-UDW3DAP5.js';
4
5
  import '../chunk-ODEQTPFM.js';
@@ -1,12 +1,13 @@
1
- export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from '../chunk-6SIG5I72.js';
1
+ export { OrgTable, OrgTableActions, OrgTableAdd, OrgTableName } from '../chunk-JB6AN4ZC.js';
2
2
  import '../chunk-SX2DFTQV.js';
3
3
  import '../chunk-S3BCVWTU.js';
4
- import '../chunk-B47YUQGM.js';
4
+ import '../chunk-J3IS2TOA.js';
5
5
  import '../chunk-53DVJCVW.js';
6
6
  import '../chunk-74WGARJE.js';
7
7
  import '../chunk-7RPGY3JE.js';
8
8
  import '../chunk-R25RGPUB.js';
9
9
  import '../chunk-4FQT6ZAY.js';
10
- import '../chunk-IA232OTU.js';
10
+ import '../chunk-OAH4IEQJ.js';
11
+ import '../chunk-UDW3DAP5.js';
11
12
  import '../chunk-BZFWDIV6.js';
12
13
  import '../chunk-ODEQTPFM.js';
@@ -1,5 +1,7 @@
1
- export { SegmentedControl } from '../chunk-N5KCGFWI.js';
2
- import '../chunk-DRHXRGB6.js';
1
+ import '../chunk-UI6HWAWE.js';
2
+ export { SegmentedControl } from '../chunk-LPHHDCN3.js';
3
+ import '../chunk-HEOVQZL7.js';
4
+ import '../chunk-CBOICT64.js';
3
5
  import '../chunk-BHHIIK3M.js';
4
6
  import '../chunk-BZFWDIV6.js';
5
7
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,5 @@
1
- export { TabPanel, Tabs, tabId } from '../chunk-DRHXRGB6.js';
1
+ export { TabPanel, Tabs, tabId } from '../chunk-HEOVQZL7.js';
2
+ import '../chunk-CBOICT64.js';
2
3
  import '../chunk-BHHIIK3M.js';
3
4
  import '../chunk-BZFWDIV6.js';
4
5
  import '../chunk-ODEQTPFM.js';