@crewlethq/ui 0.9.0 → 0.11.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 (96) hide show
  1. package/README.md +32 -1
  2. package/dist/Accordion/index.js +3 -3
  3. package/dist/AppShell/index.js +2 -2
  4. package/dist/Avatar/Avatar.d.ts +45 -14
  5. package/dist/Avatar/AvatarStack.d.ts +1 -3
  6. package/dist/Avatar/index.d.ts +2 -2
  7. package/dist/Avatar/index.js +2 -2
  8. package/dist/{Avatar-JAU77SHZ.css → Avatar-QHYOFID3.css} +83 -25
  9. package/dist/AvatarPicker/AvatarPicker.d.ts +32 -0
  10. package/dist/AvatarPicker/index.d.ts +3 -0
  11. package/dist/AvatarPicker/index.js +14 -0
  12. package/dist/AvatarPicker-PREY36MG.css +54 -0
  13. package/dist/Canvas/index.js +3 -3
  14. package/dist/Card/index.js +2 -2
  15. package/dist/CharacterPicker/index.js +3 -2
  16. package/dist/CodeBlock/index.js +3 -3
  17. package/dist/Combobox/index.js +3 -3
  18. package/dist/CommandPalette/index.js +6 -6
  19. package/dist/Copyable/index.js +2 -2
  20. package/dist/DataTable/index.js +6 -6
  21. package/dist/DataView/index.js +11 -11
  22. package/dist/DateTimePicker/index.js +4 -4
  23. package/dist/Disclosure/index.js +3 -3
  24. package/dist/EntityChip/index.js +3 -3
  25. package/dist/FactList/FactList.d.ts +33 -0
  26. package/dist/FactList/index.d.ts +3 -0
  27. package/dist/FactList/index.js +6 -0
  28. package/dist/FactList-G2H73NFR.css +57 -0
  29. package/dist/HuePicker/index.js +4 -3
  30. package/dist/ImageUpload/index.js +3 -3
  31. package/dist/Input/FormField.d.ts +8 -1
  32. package/dist/Input/index.js +1 -1
  33. package/dist/{Input-DRFNI26F.css → Input-RAKNQJCV.css} +7 -0
  34. package/dist/ListInput/ListInput.d.ts +3 -1
  35. package/dist/ListInput/index.js +3 -3
  36. package/dist/Menu/index.js +3 -3
  37. package/dist/Modal/index.js +3 -3
  38. package/dist/OrgLabel/index.js +3 -3
  39. package/dist/OrgNode/index.js +4 -4
  40. package/dist/OrgTable/index.js +6 -6
  41. package/dist/SegmentedControl/index.js +3 -3
  42. package/dist/Tabs/Tabs.d.ts +18 -0
  43. package/dist/Tabs/index.d.ts +1 -1
  44. package/dist/Tabs/index.js +1 -1
  45. package/dist/{Tabs-BWFQSWY3.css → Tabs-5I5Q5KKM.css} +33 -0
  46. package/dist/TagsInput/index.js +2 -2
  47. package/dist/ThemeSwitcher/index.js +4 -4
  48. package/dist/TimeWindowPicker/index.js +5 -5
  49. package/dist/TreeCanvas/index.js +4 -4
  50. package/dist/TreeGrid/index.js +2 -2
  51. package/dist/chunk-3L5NHASN.js +1 -0
  52. package/dist/{chunk-OAH4IEQJ.js → chunk-3UK4VFSK.js} +2 -3
  53. package/dist/{chunk-L7THQMFB.js → chunk-5WEVLIB6.js} +1 -1
  54. package/dist/{chunk-J3IS2TOA.js → chunk-6OF2DBKY.js} +1 -1
  55. package/dist/{chunk-IGWPZZIB.js → chunk-6SDGRKQ7.js} +2 -2
  56. package/dist/{chunk-EUT7VBQG.js → chunk-CIOKUMVC.js} +6 -6
  57. package/dist/{chunk-Y2V3TSQC.js → chunk-DDTDN5L2.js} +1 -1
  58. package/dist/{chunk-LPHHDCN3.js → chunk-EBBAAQDY.js} +1 -1
  59. package/dist/{chunk-UYK72NOS.js → chunk-ELZKOVEC.js} +1 -1
  60. package/dist/chunk-EXHQ2QVW.js +1 -0
  61. package/dist/{chunk-ZGX2DP7F.js → chunk-FTEJPHBI.js} +8 -2
  62. package/dist/{chunk-RIAZM6L3.js → chunk-G2AVKPSL.js} +1 -1
  63. package/dist/chunk-HI6Q2UXQ.js +169 -0
  64. package/dist/{chunk-IZHN5I3H.js → chunk-HLBRPES3.js} +4 -4
  65. package/dist/chunk-HV6IZFBK.js +64 -0
  66. package/dist/{chunk-K7OS4O2U.js → chunk-IHGKPEEV.js} +1 -1
  67. package/dist/{chunk-HEOVQZL7.js → chunk-JHQUT4WJ.js} +6 -2
  68. package/dist/{chunk-26TXVHN2.js → chunk-K5Q2DK3P.js} +1 -2
  69. package/dist/{chunk-MORLKUGM.js → chunk-KGTQ5CVD.js} +1 -1
  70. package/dist/{chunk-E3HDS4F7.js → chunk-LAQK4V3Z.js} +1 -1
  71. package/dist/{chunk-6HXH57BL.js → chunk-LZP7FGT7.js} +4 -2
  72. package/dist/{chunk-CVB7O3SZ.js → chunk-R4ZJB5YX.js} +4 -4
  73. package/dist/{chunk-MICH6QSJ.js → chunk-S4RCG44T.js} +1 -1
  74. package/dist/{chunk-UI6HWAWE.js → chunk-UAQIUSSK.js} +1 -1
  75. package/dist/chunk-URYDN2KA.js +25 -0
  76. package/dist/{chunk-X6K6OZ47.js → chunk-WEIINZPA.js} +1 -1
  77. package/dist/{chunk-IKH3Y4MP.js → chunk-YXMCUKFI.js} +1 -2
  78. package/dist/{chunk-JB6AN4ZC.js → chunk-ZMJHK7DR.js} +2 -2
  79. package/dist/generated/index.d.ts +2 -0
  80. package/dist/generated/index.js +58 -54
  81. package/dist/index.js +58 -54
  82. package/dist/styles.css +245 -30
  83. package/dist/utils/index.js +1 -1
  84. package/package.json +3 -3
  85. package/dist/chunk-UDW3DAP5.js +0 -125
  86. package/dist/{chunk-VE6LD3KM.js → chunk-2PZBIHRV.js} +2 -2
  87. package/dist/{chunk-MPXI6FM6.js → chunk-7JGWSOLM.js} +1 -1
  88. package/dist/{chunk-OVLJEVQS.js → chunk-7LD6P32I.js} +1 -1
  89. package/dist/{chunk-CEOXFO3E.js → chunk-EG6NYWVK.js} +1 -1
  90. package/dist/{chunk-FZVJDJFN.js → chunk-ENJUPIND.js} +1 -1
  91. package/dist/{chunk-5I56UXBJ.js → chunk-JCNUQ3US.js} +2 -2
  92. package/dist/{chunk-SX2DFTQV.js → chunk-MCPKHYMC.js} +1 -1
  93. package/dist/{chunk-YPTC4TX5.js → chunk-PQLMLG5K.js} +0 -0
  94. package/dist/{chunk-BTHX2FS3.js → chunk-TEEJSTFG.js} +2 -2
  95. package/dist/{chunk-LSB3EHBW.js → chunk-TFH6SYWB.js} +2 -2
  96. package/dist/{chunk-26SCUACK.js → chunk-YACKC3K2.js} +1 -1
package/README.md CHANGED
@@ -42,7 +42,7 @@ 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`, `CharacterPicker`, `HuePicker` |
45
+ | Forms | `Input`, `Textarea`, `Label`, `FormField`, `FormRow`, `Checkbox`, `Select`, `Tag`, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `ImageUpload`, `CharacterPicker`, `HuePicker`, `AvatarPicker`, `FactList` |
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` |
@@ -191,6 +191,37 @@ 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.11.0
195
+
196
+ 0.11.0 adds the parts a dense editing form is built from.
197
+
198
+ **`FactList`** draws facts a form shows and does not edit as 32px rows in one bordered box: the label on the left, the value on the right. A row with a `reason` carries a lock and says why in a tooltip on hover and to a screen reader after its value, in place of a caption under every value.
199
+
200
+ **`AvatarPicker`** is an agent's badge that opens its own picker. Pressing it opens the characters and the hues in a popover, and each choice applies as it is made; a `disabled` one is the badge alone. It replaces a `CharacterPicker` and a `HuePicker` drawn open in a form.
201
+
202
+ **`Tabs` take a `marker`** per item: `{ tone: 'danger', count, label }` for problems, or `{ tone: 'warning' | 'changed', label }` for a 6px dot. One per tab, the most urgent, and it stands in for the item's `count` while set; `label` is what a screen reader hears. `TabsMarker` is its type.
203
+
204
+ **`FormField` takes `helperOnFocus`**: the helper is still in `aria-describedby`, and is drawn only while the field has focus, so a form whose every field carries a sentence reads as labels and values at rest. `ListInput` passes the same prop to its field.
205
+
206
+ `@crewlethq/icons` adds `LockGlyph` (Lucide's `lock`), which `FactList` draws.
207
+
208
+ What to change: nothing. Every addition is new.
209
+
210
+ ## Breaking changes in 0.10.0
211
+
212
+ 0.10.0 moves an agent's state off the ring round its badge and onto a small badge on its corner.
213
+
214
+ **A state is a status, never a ring.** `Avatar` takes `status`: `working`, `needs` (waiting on a person) or `stopped`, and none for idle. It draws a round badge on the lower-right corner, the state's fill carrying a glyph whose shape says it (play, a question mark, a square) in `--color-text-inverse`, which the tokens' palette suite now holds at 3:1 on each fill (`MARK_ON_FILL`). The badge sits in a notch cut out of the face with a mask, so it reads on any ground without knowing its colour. A badge with a status is drawn inside a `.crewlet-avatar-frame` of the face's own size, which takes your `className` and `style`; a badge that names itself appends the state to its accessible name (`Software Engineer avatar, stopped`), and a decorative one says nothing, so say the state in words beside it. `AVATAR_STATUSES` and `AVATAR_STATUS_LABELS` list the statuses and their words. A ring of a state's hue round a plate in the agent's own hue put two colours on one small mark, and framed what the agent was doing louder than who it is.
215
+
216
+ | Was | Is |
217
+ |---|---|
218
+ | `<Avatar ring="info">`, `ring="warning"`, `ring="danger"` for what a seat is doing | `status="working"`, `status="needs"`, `status="stopped"` |
219
+ | `<Avatar ring="success">` | no status; say a finished state in words beside the badge |
220
+ | `AvatarRing` naming `info`, `warning`, `danger` or `success` | `AvatarRing` is `'brand'` alone, the selected ring; a state is an `AvatarStatus` |
221
+ | an `AvatarStack` member's `ring` | nothing: each member overlaps the one before it, so a corner badge would be hidden; say what the members are doing beside the stack |
222
+ | a stylesheet of your own reading `.crewlet-avatar--ring-info`, `-warning`, `-danger` or `-success` | `.crewlet-avatar__status--working`, `--needs` or `--stopped` |
223
+ | a `ring="brand"` and a `status` on one badge | the status alone; the notch is cut from the outline the ring would follow, so a badge with a status draws no ring |
224
+
194
225
  ## Changes in 0.9.0
195
226
 
196
227
  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.
@@ -1,6 +1,6 @@
1
- export { Accordion, AccordionItem } from '../chunk-RIAZM6L3.js';
2
- import '../chunk-FZVJDJFN.js';
3
- import '../chunk-BHHIIK3M.js';
1
+ export { Accordion, AccordionItem } from '../chunk-G2AVKPSL.js';
2
+ import '../chunk-ENJUPIND.js';
4
3
  import '../chunk-PQADV6P6.js';
4
+ import '../chunk-BHHIIK3M.js';
5
5
  import '../chunk-BZFWDIV6.js';
6
6
  import '../chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
- export { AppShell, AppShellRail, AppShellRailRow, AppShellToggle, AppShellTopbar, useAppShell } from '../chunk-OVLJEVQS.js';
1
+ export { AppShell, AppShellRail, AppShellRailRow, AppShellToggle, AppShellTopbar, useAppShell } from '../chunk-7LD6P32I.js';
2
+ import '../chunk-4FQT6ZAY.js';
2
3
  import '../chunk-7RPGY3JE.js';
3
4
  import '../chunk-R25RGPUB.js';
4
- import '../chunk-4FQT6ZAY.js';
5
5
  import '../chunk-BZFWDIV6.js';
6
6
  import '../chunk-ODEQTPFM.js';
@@ -1,7 +1,6 @@
1
1
  import type { HTMLAttributes } from 'react';
2
2
  import { type CrewletCharacterId } from '@crewlethq/icons/characters';
3
3
  import type { NodeHue } from '../utils/nodeHue.js';
4
- import type { Tone } from '../utils/tone.js';
5
4
  /**
6
5
  * WHAT THE BADGE STANDS FOR, drawn as its outline.
7
6
  *
@@ -37,16 +36,37 @@ export type AvatarKind = 'agent' | 'human';
37
36
  */
38
37
  export type AvatarTone = 'neutral' | 'seeded';
39
38
  /**
40
- * The STATE ring: a 1.5px line 2px outside the badge, in one of the state
41
- * fills or the accent.
42
- *
43
- * `info`, `warning`, `danger` and `success` are what the thing is DOING, and
44
- * `brand` is SELECTED. Which state each one means is the consumer's to decide,
45
- * and to SAY in words beside the badge: the ring is never the only carrier of
46
- * a state, because in forced-colors mode every ring is the same system colour.
47
- * No ring at all is the resting state.
39
+ * The SELECTED ring: a 1.5px line 2px outside the badge, in the accent.
40
+ *
41
+ * It is the one ring there is. A ring used to carry a state too (`info`,
42
+ * `warning`, `danger`, `success`), and on a character plate that already
43
+ * wears its own hue it put a second colour round a 32px mark, framing what
44
+ * the agent was doing louder than who it is. A state is a [AvatarStatus]
45
+ * now, a small badge on the corner whose SHAPE says it.
46
+ */
47
+ export type AvatarRing = 'brand';
48
+ /**
49
+ * WHAT AN AGENT IS DOING, drawn as a small round badge on the lower-right
50
+ * corner: `working`, `needs` (it is waiting on a person) or `stopped`. An idle
51
+ * badge carries none, because a mark that means "nothing is happening" is one
52
+ * a reader learns to skip.
53
+ *
54
+ * SHAPE FIRST, colour second. Each badge is a state's fill step carrying a
55
+ * glyph, play for working, a question for needs and a square for stopped, so
56
+ * it reads to somebody who cannot separate the hues and in forced-colors mode,
57
+ * where every fill is one system colour. The glyph is in the inverse ink,
58
+ * which the tokens' palette suite holds at 3:1 on each fill (`MARK_ON_FILL`).
59
+ *
60
+ * THE BADGE IS NOT THE ONLY CARRIER. A row that draws a badge with a status
61
+ * says the state in words as well; a badge drawn alone (a breadcrumb, a stack)
62
+ * is the case the glyph exists for. A badge that names itself appends the
63
+ * state to its accessible name.
48
64
  */
49
- export type AvatarRing = Exclude<Tone, 'neutral'>;
65
+ export type AvatarStatus = 'working' | 'needs' | 'stopped';
66
+ /** Every status, in the order a legend lists them. */
67
+ export declare const AVATAR_STATUSES: readonly ["working", "needs", "stopped"];
68
+ /** What each status is called in a sentence: the accessible name's last words. */
69
+ export declare const AVATAR_STATUS_LABELS: Readonly<Record<AvatarStatus, string>>;
50
70
  /** The four steps, in px. A number is accepted for anything outside them. */
51
71
  export declare const AVATAR_SIZES: {
52
72
  readonly xs: 20;
@@ -81,8 +101,13 @@ export interface AvatarProps extends HTMLAttributes<HTMLElement> {
81
101
  /** An agent (the default) is a squircle; a human is a circle. */
82
102
  kind?: AvatarKind | undefined;
83
103
  tone?: AvatarTone | undefined;
84
- /** A state ring, or none. `brand` is selected. */
104
+ /**
105
+ * The selected ring, or none. Not drawn on a badge with a `status`: the
106
+ * corner badge is cut out of the outline the ring would follow.
107
+ */
85
108
  ring?: AvatarRing | undefined;
109
+ /** What the agent is doing, as a corner badge; none is idle. */
110
+ status?: AvatarStatus | undefined;
86
111
  /**
87
112
  * The name is already printed beside this badge, so the badge itself says
88
113
  * nothing. Without it a row reads "Carlos Diaz avatar, Carlos Diaz".
@@ -164,7 +189,13 @@ export declare function avatarCorner(pixels: number): number;
164
189
  *
165
190
  * If the image fails to load (a stale CDN URL, an expired signature) it
166
191
  * degrades to the initials rather than to a broken-image glyph. Either way it
167
- * keeps its kind's outline and its ring: whether somebody has uploaded a photo
168
- * says nothing about what they are or what they are doing.
192
+ * keeps its kind's outline, its ring and its status: whether somebody has
193
+ * uploaded a photo says nothing about what they are or what they are doing.
194
+ *
195
+ * A BADGE WITH A STATUS IS FRAMED: the face (character, image or initials)
196
+ * stands in a box of its own size beside the corner badge, and the face has a
197
+ * notch cut where the badge sits, so the badge reads on any ground without
198
+ * knowing what colour that ground is. The frame takes the caller's class and
199
+ * style, which is where a layout reaches for the badge.
169
200
  */
170
- export declare const Avatar: ({ src, name, size, kind, tone, ring, decorative, colorSeed, character, hue, className, style, ...rest }: AvatarProps) => import("react").JSX.Element;
201
+ export declare const Avatar: ({ src, name, size, kind, tone, ring, status, decorative, colorSeed, character, hue, className, style, ...rest }: AvatarProps) => import("react").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  import type { HTMLAttributes } from 'react';
2
2
  import type { CrewletCharacterId } from '@crewlethq/icons/characters';
3
3
  import type { NodeHue } from '../utils/nodeHue.js';
4
- import { type AvatarKind, type AvatarRing, type AvatarSizeStep } from './Avatar.js';
4
+ import { type AvatarKind, type AvatarSizeStep } from './Avatar.js';
5
5
  /** One badge in a stack. */
6
6
  export interface AvatarStackMember {
7
7
  /** Who: the initials, and a word of the stack's accessible name. */
@@ -9,8 +9,6 @@ export interface AvatarStackMember {
9
9
  /** An agent (the default) is a squircle; a human is a circle. */
10
10
  kind?: AvatarKind | undefined;
11
11
  src?: string | undefined;
12
- /** A state ring on this badge, as `Avatar` draws it. */
13
- ring?: AvatarRing | undefined;
14
12
  /** The Crewlet character an agent member is drawn as, as `Avatar` draws it. */
15
13
  character?: CrewletCharacterId | undefined;
16
14
  /** The hue an agent member's character is drawn in, as `Avatar` draws it. */
@@ -1,6 +1,6 @@
1
1
  import './Avatar.css';
2
2
  import './AvatarStack.css';
3
- export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials, } from './Avatar.js';
4
- export type { AvatarKind, AvatarProps, AvatarRing, AvatarSize, AvatarSizeStep, AvatarTone } from './Avatar.js';
3
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, AVATAR_STATUS_LABELS, AVATAR_STATUSES, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials, } from './Avatar.js';
4
+ export type { AvatarKind, AvatarProps, AvatarRing, AvatarSize, AvatarSizeStep, AvatarStatus, AvatarTone, } from './Avatar.js';
5
5
  export { AvatarStack, avatarStackLabel } from './AvatarStack.js';
6
6
  export type { AvatarStackMember, AvatarStackProps } from './AvatarStack.js';
@@ -1,3 +1,3 @@
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';
1
+ export { AvatarStack, avatarStackLabel } from '../chunk-3UK4VFSK.js';
2
+ export { AVATAR_CHARACTER_FULL_DETAIL, AVATAR_CORNER_RATIO, AVATAR_SIZES, AVATAR_STATUSES, AVATAR_STATUS_LABELS, Avatar, avatarCorner, avatarPixels, avatarTint, getInitials } from '../chunk-HI6Q2UXQ.js';
3
3
  import '../chunk-ODEQTPFM.js';
@@ -10,8 +10,10 @@
10
10
  * OUTLINE (a squircle for an agent, a circle for a person), the monogram and
11
11
  * the name, and for an agent an operator gave one, its character and its hue.
12
12
  *
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.
13
+ * A STATE IS A CORNER BADGE, NEVER A LINE ROUND THE PLATE. A ring in a state's
14
+ * hue round a plate in the agent's own hue put two colours on a 32px mark and
15
+ * framed what the agent was doing louder than who it is. The one ring left is
16
+ * SELECTED, in the accent.
15
17
  *
16
18
  * The seeded tints stay for the one case that earns them, a roster somebody
17
19
  * scans, and their grounds are TOKENS: measured under white initials and held
@@ -211,11 +213,12 @@
211
213
  color: var(--color-node-blue);
212
214
  }
213
215
 
214
- /* ── the state ring ────────────────────────────────────────────────────── */
216
+ /* ── the selected ring ────────────────────────────────────────────────── */
215
217
 
216
218
  /*
217
219
  * A 1.5px LINE 2px OUTSIDE THE BADGE, which is the design's ring: it draws a
218
220
  * 3.5px shadow over a 2px one in the card's colour, and 3.5 less 2 is 1.5.
221
+ * Longhands, so nothing else that sets an outline resets the ring's geometry.
219
222
  *
220
223
  * AN OUTLINE RATHER THAN THAT SHADOW PAIR, for three reasons. The gap is
221
224
  * TRANSPARENT, so the ring reads on whatever the badge stands on, where the
@@ -223,42 +226,97 @@
223
226
  * other ground. An outline follows the corner, the squircle's included, in
224
227
  * every engine this package supports. And forced-colors mode keeps an outline
225
228
  * and drops every shadow, so the ring is still drawn for the readers who most
226
- * need a boundary; it is drawn in the system colour there, which is why the
227
- * state is always said in words beside the badge as well.
229
+ * need a boundary.
228
230
  *
229
- * LONGHANDS, so the tone rules below set the colour alone and cannot reset the
230
- * geometry, whichever order they are read in. Each fill is measured at 3:1 as
231
- * a mark on every opaque surface by @crewlethq/tokens, which is the floor a
232
- * boundary a reader has to see is held to.
231
+ * SELECTED, in the accent, which is what the accent means: where the reader
232
+ * is. It is the only place a badge spends the accent, and the accent is
233
+ * measured at 3:1 as a mark on every opaque surface by @crewlethq/tokens.
233
234
  */
234
- .crewlet-avatar--ring-info,
235
- .crewlet-avatar--ring-warning,
236
- .crewlet-avatar--ring-danger,
237
- .crewlet-avatar--ring-success,
238
235
  .crewlet-avatar--ring-brand {
239
236
  outline-style: solid;
240
237
  outline-width: 1.5px;
241
238
  outline-offset: 2px;
239
+ outline-color: var(--color-brand-accent);
240
+ }
241
+
242
+ /* ── the status badge ─────────────────────────────────────────────────── */
243
+
244
+ /*
245
+ * THE FRAME is the face's own box, so a badge with a status takes exactly the
246
+ * room one without takes: the corner badge hangs past it rather than growing
247
+ * it, and a row lays out the same either way. The badge is 0.42 of the box,
248
+ * never under 10px, which is the size its glyph stays a shape at.
249
+ */
250
+ .crewlet-avatar-frame {
251
+ --crewlet-avatar-status-size: max(10px, calc(var(--crewlet-avatar-size) * 0.42));
252
+ --crewlet-avatar-status-overhang: 2px;
253
+ --crewlet-avatar-status-gap: 1.5px;
254
+ position: relative;
255
+ display: inline-flex;
256
+ flex: none;
257
+ width: var(--crewlet-avatar-size);
258
+ height: var(--crewlet-avatar-size);
259
+ vertical-align: middle;
242
260
  }
243
261
 
244
- .crewlet-avatar--ring-info {
245
- outline-color: var(--color-feedback-info);
262
+ /*
263
+ * THE NOTCH: the face is masked by a circle a gap wider than the badge, centred
264
+ * where the badge sits, so the gap shows whatever the badge stands on. A ring
265
+ * of the ground's colour would need to know that ground, and a badge on a card,
266
+ * a hovered row and the page would each need a different one. A mask reads only
267
+ * alpha, so its black is opacity rather than a colour.
268
+ */
269
+ .crewlet-avatar--notched {
270
+ --crewlet-avatar-status-centre: calc(
271
+ 100% + var(--crewlet-avatar-status-overhang) - var(--crewlet-avatar-status-size) / 2
272
+ );
273
+ --crewlet-avatar-status-cut: calc(var(--crewlet-avatar-status-size) / 2 + var(--crewlet-avatar-status-gap));
274
+ -webkit-mask-image: radial-gradient(
275
+ circle at var(--crewlet-avatar-status-centre) var(--crewlet-avatar-status-centre),
276
+ transparent var(--crewlet-avatar-status-cut),
277
+ #000 calc(var(--crewlet-avatar-status-cut) + 0.5px)
278
+ );
279
+ mask-image: radial-gradient(
280
+ circle at var(--crewlet-avatar-status-centre) var(--crewlet-avatar-status-centre),
281
+ transparent var(--crewlet-avatar-status-cut),
282
+ #000 calc(var(--crewlet-avatar-status-cut) + 0.5px)
283
+ );
284
+ }
285
+
286
+ /*
287
+ * THE BADGE: a state's fill step carrying its glyph in the inverse ink, which
288
+ * the tokens' palette suite holds at 3:1 on each fill (`MARK_ON_FILL`). The
289
+ * transparent outline is drawn only in forced-colors mode, where the fill
290
+ * becomes the page's own colour and the outline is what keeps a boundary.
291
+ */
292
+ .crewlet-avatar__status {
293
+ position: absolute;
294
+ right: calc(var(--crewlet-avatar-status-overhang) * -1);
295
+ bottom: calc(var(--crewlet-avatar-status-overhang) * -1);
296
+ display: grid;
297
+ place-items: center;
298
+ width: var(--crewlet-avatar-status-size);
299
+ height: var(--crewlet-avatar-status-size);
300
+ border-radius: var(--radius-circle);
301
+ outline: 1px solid transparent;
302
+ color: var(--color-text-inverse);
303
+ pointer-events: none;
246
304
  }
247
305
 
248
- .crewlet-avatar--ring-warning {
249
- outline-color: var(--color-feedback-warning);
306
+ .crewlet-avatar__status > svg {
307
+ display: block;
308
+ width: 100%;
309
+ height: 100%;
250
310
  }
251
311
 
252
- .crewlet-avatar--ring-danger {
253
- outline-color: var(--color-feedback-danger);
312
+ .crewlet-avatar__status--working {
313
+ background: var(--color-feedback-info);
254
314
  }
255
315
 
256
- .crewlet-avatar--ring-success {
257
- outline-color: var(--color-feedback-success);
316
+ .crewlet-avatar__status--needs {
317
+ background: var(--color-feedback-warning);
258
318
  }
259
319
 
260
- /* SELECTED, in the accent, which is what the accent means: where the reader
261
- is. It is the only place a badge spends the accent. */
262
- .crewlet-avatar--ring-brand {
263
- outline-color: var(--color-brand-accent);
320
+ .crewlet-avatar__status--stopped {
321
+ background: var(--color-feedback-danger);
264
322
  }
@@ -0,0 +1,32 @@
1
+ import { type CrewletCharacterId } from '@crewlethq/icons/characters';
2
+ import { type AvatarSize } from '../Avatar/Avatar.js';
3
+ import { type NodeHue } from '../utils/nodeHue.js';
4
+ /** An agent's look: its character and the hue it is drawn in. */
5
+ export interface AvatarPickerValue {
6
+ character: CrewletCharacterId;
7
+ hue: NodeHue;
8
+ }
9
+ export interface AvatarPickerProps {
10
+ value: AvatarPickerValue;
11
+ onChange: (next: AvatarPickerValue) => void;
12
+ /** The agent's name, for the button's accessible name. */
13
+ name: string;
14
+ /** The badge's size. 40px, the size a form's header draws an identity at. */
15
+ size?: AvatarSize | undefined;
16
+ /** The characters offered, in order. Every character, by default. */
17
+ characters?: readonly CrewletCharacterId[] | undefined;
18
+ /** The badge is drawn, and nothing opens. */
19
+ disabled?: boolean | undefined;
20
+ className?: string | undefined;
21
+ }
22
+ /**
23
+ * An agent's badge that opens its own picker: press it and the characters and
24
+ * the hues open in a popover beside it.
25
+ *
26
+ * THE BADGE IS THE CONTROL. The two pickers drawn open in a form took about
27
+ * 330px for a choice made once, so the form keeps one badge, marked with a
28
+ * pencil pip as the thing that changes it, and the grid opens on demand. A
29
+ * choice applies as it is made, as the pickers' own radios do; Escape or a
30
+ * press outside closes the popover.
31
+ */
32
+ export declare function AvatarPicker({ value, onChange, name, size, characters, disabled, className, }: AvatarPickerProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './AvatarPicker.css';
2
+ export { AvatarPicker } from './AvatarPicker.js';
3
+ export type { AvatarPickerProps, AvatarPickerValue } from './AvatarPicker.js';
@@ -0,0 +1,14 @@
1
+ export { AvatarPicker } from '../chunk-HV6IZFBK.js';
2
+ import '../chunk-K5Q2DK3P.js';
3
+ import '../chunk-AYKXMIOR.js';
4
+ import '../chunk-EBBAAQDY.js';
5
+ import '../chunk-JHQUT4WJ.js';
6
+ import '../chunk-PDUZO35I.js';
7
+ import '../chunk-YXMCUKFI.js';
8
+ import '../chunk-CBOICT64.js';
9
+ import '../chunk-BHHIIK3M.js';
10
+ import '../chunk-7RPGY3JE.js';
11
+ import '../chunk-R25RGPUB.js';
12
+ import '../chunk-BZFWDIV6.js';
13
+ import '../chunk-HI6Q2UXQ.js';
14
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,54 @@
1
+ /*
2
+ * The badge as a button, with a pencil pip on its corner saying it changes
3
+ * the badge. No chrome of its own beyond the focus ring: the badge is the
4
+ * control's face.
5
+ */
6
+ .crewlet-avatar-picker {
7
+ position: relative;
8
+ display: inline-flex;
9
+ flex: none;
10
+ padding: 0;
11
+ border: 0;
12
+ border-radius: var(--radius-lg);
13
+ background: none;
14
+ cursor: pointer;
15
+ }
16
+
17
+ button.crewlet-avatar-picker:focus-visible {
18
+ outline: 2px solid var(--color-focus);
19
+ outline-offset: 2px;
20
+ }
21
+
22
+ .crewlet-avatar-picker__pip {
23
+ position: absolute;
24
+ right: calc(var(--spacing-1) * -1);
25
+ bottom: calc(var(--spacing-1) * -1);
26
+ display: grid;
27
+ place-items: center;
28
+ width: 16px;
29
+ height: 16px;
30
+ border: 1px solid var(--color-border-strong);
31
+ border-radius: var(--radius-circle);
32
+ background: var(--color-surface-elevated);
33
+ color: var(--color-text-secondary);
34
+ }
35
+
36
+ button.crewlet-avatar-picker:hover .crewlet-avatar-picker__pip {
37
+ color: var(--color-text-primary);
38
+ }
39
+
40
+ .crewlet-avatar-picker__body {
41
+ display: grid;
42
+ gap: var(--spacing-2);
43
+ width: max-content;
44
+ max-width: 100%;
45
+ padding: var(--spacing-3);
46
+ }
47
+
48
+ .crewlet-avatar-picker__label {
49
+ font-size: var(--font-size-2xs);
50
+ font-weight: var(--font-weight-medium);
51
+ letter-spacing: var(--font-letter-spacing-wide);
52
+ text-transform: uppercase;
53
+ color: var(--color-text-tertiary);
54
+ }
@@ -1,8 +1,8 @@
1
- export { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, CANVAS_FIT_PADDING, CANVAS_FOCUS_CONTEXT, CANVAS_MAX_ZOOM, CANVAS_MIN_ZOOM, CANVAS_PAN_MARGIN, CANVAS_PAN_STEP, CANVAS_REVEAL_PADDING, CANVAS_TAP_SLOP, CANVAS_WHEEL_LINE_PX, CANVAS_WHEEL_ZOOM_PER_PIXEL, CANVAS_ZOOM_CEILING, CANVAS_ZOOM_LIMITS, CANVAS_ZOOM_STEP, Canvas, IDENTITY_VIEW, anchorView, beyondSlop, clampPan, clampZoom, fitView, panBy, pinchView, regionView, revealView, screenRect, toScreen, toWorld, wheelPixels, wheelZoomFactor, zoomAt, zoomLimits } from '../chunk-VE6LD3KM.js';
1
+ export { CANVAS_COMPOSE_CONTEXT, CANVAS_FIT_MAX_ZOOM, CANVAS_FIT_PADDING, CANVAS_FOCUS_CONTEXT, CANVAS_MAX_ZOOM, CANVAS_MIN_ZOOM, CANVAS_PAN_MARGIN, CANVAS_PAN_STEP, CANVAS_REVEAL_PADDING, CANVAS_TAP_SLOP, CANVAS_WHEEL_LINE_PX, CANVAS_WHEEL_ZOOM_PER_PIXEL, CANVAS_ZOOM_CEILING, CANVAS_ZOOM_LIMITS, CANVAS_ZOOM_STEP, Canvas, IDENTITY_VIEW, anchorView, beyondSlop, clampPan, clampZoom, fitView, panBy, pinchView, regionView, revealView, screenRect, toScreen, toWorld, wheelPixels, wheelZoomFactor, zoomAt, zoomLimits } from '../chunk-2PZBIHRV.js';
2
2
  import '../chunk-53DVJCVW.js';
3
+ import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-4FQT6ZAY.js';
3
5
  import '../chunk-7RPGY3JE.js';
4
6
  import '../chunk-R25RGPUB.js';
5
- import '../chunk-4FQT6ZAY.js';
6
- import '../chunk-OG6CL3EB.js';
7
7
  import '../chunk-BZFWDIV6.js';
8
8
  import '../chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
- export { Card } from '../chunk-CEOXFO3E.js';
1
+ export { Card } from '../chunk-EG6NYWVK.js';
2
2
  export { useCardHeaderSlot } from '../chunk-AV2DXAEL.js';
3
- import '../chunk-BHHIIK3M.js';
4
3
  import '../chunk-PQADV6P6.js';
4
+ import '../chunk-BHHIIK3M.js';
5
5
  import '../chunk-BZFWDIV6.js';
6
6
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,5 @@
1
- export { CHARACTER_PICKER_COLUMNS, CharacterPicker } from '../chunk-IKH3Y4MP.js';
1
+ import '../chunk-3L5NHASN.js';
2
+ export { CHARACTER_PICKER_COLUMNS, CharacterPicker } from '../chunk-YXMCUKFI.js';
2
3
  import '../chunk-CBOICT64.js';
3
- import '../chunk-UDW3DAP5.js';
4
+ import '../chunk-HI6Q2UXQ.js';
4
5
  import '../chunk-ODEQTPFM.js';
@@ -1,7 +1,7 @@
1
- export { CodeBlock } from '../chunk-MORLKUGM.js';
2
- import '../chunk-26SCUACK.js';
1
+ export { CodeBlock } from '../chunk-KGTQ5CVD.js';
2
+ import '../chunk-YACKC3K2.js';
3
3
  import '../chunk-5VNUYO76.js';
4
- import '../chunk-4FQT6ZAY.js';
5
4
  import '../chunk-OG6CL3EB.js';
5
+ import '../chunk-4FQT6ZAY.js';
6
6
  import '../chunk-BZFWDIV6.js';
7
7
  import '../chunk-ODEQTPFM.js';
@@ -1,8 +1,8 @@
1
- export { Combobox } from '../chunk-UYK72NOS.js';
1
+ export { Combobox } from '../chunk-ELZKOVEC.js';
2
+ import '../chunk-FTEJPHBI.js';
2
3
  import '../chunk-6MU7HNB4.js';
3
- import '../chunk-ZGX2DP7F.js';
4
4
  import '../chunk-PQADV6P6.js';
5
- import '../chunk-R25RGPUB.js';
6
5
  import '../chunk-4FQT6ZAY.js';
6
+ import '../chunk-R25RGPUB.js';
7
7
  import '../chunk-BZFWDIV6.js';
8
8
  import '../chunk-ODEQTPFM.js';
@@ -1,13 +1,13 @@
1
- export { CommandPalette } from '../chunk-IGWPZZIB.js';
1
+ export { CommandPalette } from '../chunk-6SDGRKQ7.js';
2
2
  import '../chunk-SMBKXWML.js';
3
+ import '../chunk-FTEJPHBI.js';
3
4
  import '../chunk-6MU7HNB4.js';
4
- import '../chunk-ZGX2DP7F.js';
5
- import '../chunk-BTHX2FS3.js';
6
- import '../chunk-BHHIIK3M.js';
5
+ import '../chunk-TEEJSTFG.js';
6
+ import '../chunk-OG6CL3EB.js';
7
7
  import '../chunk-PQADV6P6.js';
8
+ import '../chunk-4FQT6ZAY.js';
9
+ import '../chunk-BHHIIK3M.js';
8
10
  import '../chunk-7RPGY3JE.js';
9
11
  import '../chunk-R25RGPUB.js';
10
- import '../chunk-4FQT6ZAY.js';
11
- import '../chunk-OG6CL3EB.js';
12
12
  import '../chunk-BZFWDIV6.js';
13
13
  import '../chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
- export { CopyButton, Copyable } from '../chunk-26SCUACK.js';
1
+ export { CopyButton, Copyable } from '../chunk-YACKC3K2.js';
2
2
  import '../chunk-5VNUYO76.js';
3
- import '../chunk-4FQT6ZAY.js';
4
3
  import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-4FQT6ZAY.js';
5
5
  import '../chunk-BZFWDIV6.js';
6
6
  import '../chunk-ODEQTPFM.js';
@@ -1,14 +1,14 @@
1
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-CVB7O3SZ.js';
2
- import '../chunk-LSB3EHBW.js';
1
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-R4ZJB5YX.js';
2
+ import '../chunk-TFH6SYWB.js';
3
3
  import '../chunk-EUCC37WY.js';
4
- import '../chunk-BTHX2FS3.js';
4
+ import '../chunk-TEEJSTFG.js';
5
+ import '../chunk-5VNUYO76.js';
6
+ import '../chunk-OG6CL3EB.js';
5
7
  import '../chunk-AV2DXAEL.js';
6
8
  import '../chunk-YCTMKKRA.js';
7
- import '../chunk-5VNUYO76.js';
8
9
  import '../chunk-PQADV6P6.js';
10
+ import '../chunk-4FQT6ZAY.js';
9
11
  import '../chunk-7RPGY3JE.js';
10
12
  import '../chunk-R25RGPUB.js';
11
- import '../chunk-4FQT6ZAY.js';
12
- import '../chunk-OG6CL3EB.js';
13
13
  import '../chunk-BZFWDIV6.js';
14
14
  import '../chunk-ODEQTPFM.js';
@@ -1,25 +1,25 @@
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';
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-CIOKUMVC.js';
2
2
  import '../chunk-PGRPNDWM.js';
3
3
  import '../chunk-3CZ7XAVY.js';
4
4
  import '../chunk-HOXGBLEY.js';
5
+ import '../chunk-JCNUQ3US.js';
5
6
  import '../chunk-SMBKXWML.js';
7
+ import '../chunk-FTEJPHBI.js';
6
8
  import '../chunk-6MU7HNB4.js';
7
- import '../chunk-ZGX2DP7F.js';
8
- import '../chunk-CVB7O3SZ.js';
9
- import '../chunk-LSB3EHBW.js';
9
+ import '../chunk-R4ZJB5YX.js';
10
+ import '../chunk-TFH6SYWB.js';
10
11
  import '../chunk-EUCC37WY.js';
11
- import '../chunk-BTHX2FS3.js';
12
- import '../chunk-5I56UXBJ.js';
13
- import '../chunk-PDUZO35I.js';
12
+ import '../chunk-TEEJSTFG.js';
13
+ import '../chunk-5VNUYO76.js';
14
14
  import '../chunk-GXQ3B46I.js';
15
+ import '../chunk-OG6CL3EB.js';
15
16
  import '../chunk-AV2DXAEL.js';
16
17
  import '../chunk-YCTMKKRA.js';
17
- import '../chunk-5VNUYO76.js';
18
- import '../chunk-BHHIIK3M.js';
19
18
  import '../chunk-PQADV6P6.js';
19
+ import '../chunk-4FQT6ZAY.js';
20
+ import '../chunk-PDUZO35I.js';
21
+ import '../chunk-BHHIIK3M.js';
20
22
  import '../chunk-7RPGY3JE.js';
21
23
  import '../chunk-R25RGPUB.js';
22
- import '../chunk-4FQT6ZAY.js';
23
- import '../chunk-OG6CL3EB.js';
24
24
  import '../chunk-BZFWDIV6.js';
25
25
  import '../chunk-ODEQTPFM.js';
@@ -1,9 +1,9 @@
1
- export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-5I56UXBJ.js';
2
- import '../chunk-PDUZO35I.js';
1
+ export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-JCNUQ3US.js';
3
2
  import '../chunk-GXQ3B46I.js';
3
+ import '../chunk-OG6CL3EB.js';
4
+ import '../chunk-4FQT6ZAY.js';
5
+ import '../chunk-PDUZO35I.js';
4
6
  import '../chunk-7RPGY3JE.js';
5
7
  import '../chunk-R25RGPUB.js';
6
- import '../chunk-4FQT6ZAY.js';
7
- import '../chunk-OG6CL3EB.js';
8
8
  import '../chunk-BZFWDIV6.js';
9
9
  import '../chunk-ODEQTPFM.js';
@@ -1,6 +1,6 @@
1
- export { Disclosure } from '../chunk-MICH6QSJ.js';
2
- export { DisclosureAnatomy } from '../chunk-FZVJDJFN.js';
3
- import '../chunk-BHHIIK3M.js';
1
+ export { Disclosure } from '../chunk-S4RCG44T.js';
2
+ export { DisclosureAnatomy } from '../chunk-ENJUPIND.js';
4
3
  import '../chunk-PQADV6P6.js';
4
+ import '../chunk-BHHIIK3M.js';
5
5
  import '../chunk-BZFWDIV6.js';
6
6
  import '../chunk-ODEQTPFM.js';
@@ -1,4 +1,4 @@
1
- export { EntityChip } from '../chunk-Y2V3TSQC.js';
2
- import '../chunk-OAH4IEQJ.js';
3
- import '../chunk-UDW3DAP5.js';
1
+ export { EntityChip } from '../chunk-DDTDN5L2.js';
2
+ import '../chunk-3UK4VFSK.js';
3
+ import '../chunk-HI6Q2UXQ.js';
4
4
  import '../chunk-ODEQTPFM.js';