@crewlethq/ui 0.85.0 → 0.86.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 (36) hide show
  1. package/README.md +18 -4
  2. package/dist/DataView/index.js +2 -2
  3. package/dist/KeyValueRows/KeyValueRows.d.ts +125 -0
  4. package/dist/KeyValueRows/index.d.ts +3 -0
  5. package/dist/KeyValueRows/index.js +12 -0
  6. package/dist/KeyValueRows-US5KW7JK.css +44 -0
  7. package/dist/PresenterView/index.js +2 -2
  8. package/dist/RailList/RailList.d.ts +74 -0
  9. package/dist/RailList/index.d.ts +3 -0
  10. package/dist/RailList/index.js +17 -0
  11. package/dist/RailList-N2ZBPRM2.css +97 -0
  12. package/dist/RelatedRow/index.js +2 -2
  13. package/dist/RichEditor/index.js +1 -1
  14. package/dist/SetupWizard/index.js +2 -2
  15. package/dist/ShareDialog/index.js +1 -1
  16. package/dist/TableCells/TableCells.d.ts +60 -0
  17. package/dist/TableCells/index.d.ts +2 -2
  18. package/dist/TableCells/index.js +2 -1
  19. package/dist/{TableCells-TKSNLRK3.css → TableCells-ZALZLLEF.css} +28 -0
  20. package/dist/Text/Text.d.ts +25 -3
  21. package/dist/Text/index.js +1 -1
  22. package/dist/{chunk-AUSFKGKL.js → chunk-3AMWXJQX.js} +1 -1
  23. package/dist/{chunk-AFLS26AC.js → chunk-3CALM534.js} +36 -2
  24. package/dist/{chunk-EAHEJNVJ.js → chunk-CL3FWLDO.js} +1 -1
  25. package/dist/{chunk-QP2P6GDQ.js → chunk-O5CEG7TQ.js} +14 -0
  26. package/dist/chunk-REWKR3S4.js +73 -0
  27. package/dist/chunk-TRZS7DLB.js +159 -0
  28. package/dist/generated/index.d.ts +2 -0
  29. package/dist/generated/index.js +59 -57
  30. package/dist/index.js +59 -57
  31. package/dist/styles.css +176 -1
  32. package/package.json +3 -3
  33. package/dist/{Editor-5D5Z3LBQ.js → Editor-VGNB35NJ.js} +1 -1
  34. package/dist/{chunk-VIX3GZCD.js → chunk-PAGITACP.js} +0 -0
  35. package/dist/{chunk-LMEMH6DO.js → chunk-WCJTOKTY.js} +1 -1
  36. package/dist/{chunk-3BVNNQZY.js → chunk-WRZPO4YL.js} +1 -1
package/README.md CHANGED
@@ -41,9 +41,9 @@ import { Button } from '@crewlethq/ui/Button'; // 8 KB of CSS, not 182 KB
41
41
  | Area | Components |
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`, `DownloadButton`, `Kbd` |
44
- | Content and text | `Text` (the eight registers and `inherit`), `Prose`, `Statement`, `Document`, `DocumentTitle` and `DocumentTitleField`, the Markdown grammar (`parseMarkdown`, `parseMarkdownSpans`, `markdownInline`, `safeHref` and the line readers, with no React in it), `Highlight`, `InlineCode`, `List` and `ListItem`, `DescriptionList`, `Timeline`, `RelativeTime`, `Note`, `Divider` |
45
- | Forms | `Input`, `Textarea`, `Label`, `FormField`, `FormRow`, `Checkbox`, `CheckboxGroup`, `ConfirmField`, `Select`, `Tag`, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `TimeRangePicker`, `ImageUpload`, `CharacterPicker`, `HuePicker`, `AvatarPicker`, `FactList`, `ChoiceList`, `ChoiceCards`, `MemberPicker` (groups granted whole, with members left out or chosen on their own, and `chosenMembers`), `ChipField` (chosen items as chips inside the field), `PersonRow` (a person or an agent as one row of a list), `Composer`, `MarkdownEditor`, `RichEditor` (with `preloadRichEditor`, and the round trip `roundTripMarkdown` and `canonicalMarkdown` from `@crewlethq/ui/RichEditorMarkdown`) |
46
- | Data display | `DataGrid` (with `useDataGridDriving`, `useAnyDataGridDriving` and `countDataGridRows`), `DataTable`, `CopyableCell`, `Table`, the read-only table cells (`TableKeyCell`, `TableNumberCell`, `TableDateCell`, `TableEntityCell`, `TableStatusCell`, `TableTagsCell`, `TableTextCell`), `StatCard`, `Meter`, `SegmentedMeter`, `Stepper`, `PricingCard`, `Avatar`, `AvatarStack`, `EntityChip`, `CodeBlock`, `QrCode`, `ObjectHeader`, `FactLine`, `SetByLine`, `Skeleton`, `Eyebrow`, `StatGroup`, `PinTile`, `IconTile`, `SettingsTable` (with `SettingsTable.Row`), `CatalogTile` |
44
+ | Content and text | `Text` (the eight registers and `inherit`; a line cut by `truncate` or `clamp` shows its whole words on hover), `Prose`, `Statement`, `Document`, `DocumentTitle` and `DocumentTitleField`, the Markdown grammar (`parseMarkdown`, `parseMarkdownSpans`, `markdownInline`, `safeHref` and the line readers, with no React in it), `Highlight`, `InlineCode`, `List` and `ListItem`, `DescriptionList`, `Timeline`, `RelativeTime`, `Note`, `Divider` |
45
+ | Forms | `Input`, `Textarea`, `Label`, `FormField`, `FormRow`, `Checkbox`, `CheckboxGroup`, `ConfirmField`, `Select`, `Tag`, `TagsInput`, `DateTimePicker`, `TimeWindowPicker`, `TimeRangePicker`, `ImageUpload`, `CharacterPicker`, `HuePicker`, `AvatarPicker`, `FactList`, `ChoiceList`, `ChoiceCards`, `MemberPicker` (groups granted whole, with members left out or chosen on their own, and `chosenMembers`), `KeyValueRows` (keys and their values as rows under one column head, with `keyValueRowsLabels`), `ChipField` (chosen items as chips inside the field), `PersonRow` (a person or an agent as one row of a list), `Composer`, `MarkdownEditor`, `RichEditor` (with `preloadRichEditor`, and the round trip `roundTripMarkdown` and `canonicalMarkdown` from `@crewlethq/ui/RichEditorMarkdown`) |
46
+ | Data display | `DataGrid` (with `useDataGridDriving`, `useAnyDataGridDriving` and `countDataGridRows`), `DataTable`, `CopyableCell`, `Table`, the read-only table cells (`TableKeyCell`, `TableNumberCell`, `TableDateCell`, `TableEntityCell`, `TableStatusCell`, `TableTagsCell`, `TableTextCell`, `TableTwoLineCell`), `StatCard`, `Meter`, `SegmentedMeter`, `Stepper`, `PricingCard`, `Avatar`, `AvatarStack`, `EntityChip`, `CodeBlock`, `QrCode`, `ObjectHeader`, `FactLine`, `SetByLine`, `Skeleton`, `Eyebrow`, `StatGroup`, `PinTile`, `IconTile`, `SettingsTable` (with `SettingsTable.Row`), `CatalogTile` |
47
47
  | List screens | `DataView`, and its parts on their own: `DataViewToolbar`, `FilterAxisBar`, `FilterAxisChip`, `FilterPill`, plus the filter model (`filterDefsFromColumns`, `applyColumnFilters`, `filterPredicate`, `blankFilterValue`) |
48
48
  | Feedback and overlays | `Callout`, `AttentionList` (what needs a person, as rows in one card), `ConflictNote`, `EditingStatus`, `Toaster`, `Modal` (with `variant="sheet"`), `ConfirmModal`, `CommandPalette`, `Tooltip`, `Popover`, `Announcer` |
49
49
  | Documents and review | `DiffView` and `DiffSummary` with the line diff they draw (`diffLines`, `diffStat`, `collapseDiff`, `firstChangedLines`, `splitLines`, `MAX_DIFF_LINES`, with no React in it), `DiffList`, `VersionCompare`, `CommentThread` |
@@ -51,7 +51,7 @@ import { Button } from '@crewlethq/ui/Button'; // 8 KB of CSS, not 182 KB
51
51
  | Charts | `Legend`, `BarList`, `StackedBar`, `StackedColumns`, `ActivityStrip`, `TimeSeries`, `Sparkline`, the reading layer they share (`ChartTooltip`, `useChartHover`), and the ramp (`DATA_COLORS`, `DATA_COLOR_OTHER`, `dataColor`) |
52
52
  | Marks | `Count` (with `tone="attention"`), `StatusDot`, `Spinner`, `EmptyValue`, `VisuallyHidden` |
53
53
  | Hooks and seams | `useModalLayer`, `usePopupLayer`, `LayerHost`, `useListbox`, `useOptionKeys`, `useHighlightRest` and `HIGHLIGHT_REST_MS`, `useClipboard`, `useDownload`, `downloadText`, `downloadBlob`, `safeFilename`, `toCsv`, `elementToPng` and `ElementToPngError`, `useOutcome`, `useAnnouncer`, `useNow`, `formatRelative`, `HeadingLevelProvider`, `cx`, the node hues (`NODE_HUES`, `NODE_HUE_NAMES`, `isNodeHue`) |
54
- | Layout | `Container`, `Section`, `Card`, `TileGrid`, `ListDetail`, `AsideLayout`, `Tabs`, `Accordion`, `Disclosure`, `Outline` (with `useActiveHeading` and `scrollToHeading`), `TreeGrid` |
54
+ | Layout | `Container`, `Section`, `Card`, `TileGrid`, `ListDetail`, `RailList` (a directory's groups as a rail beside its list, folding into a picker), `AsideLayout`, `Tabs`, `Accordion`, `Disclosure`, `Outline` (with `useActiveHeading` and `scrollToHeading`), `TreeGrid` |
55
55
  | Arranging a page | `ArrangeBoard`, `ArrangeGrid`, `ArrangeFrame` (with `useGridResize`), `ArrangeGroup`, `ArrangeList`, and the reorder hooks under them (`useReorder`, `useReorderLists`, `moveKey`) |
56
56
  | Application shell | `AppShell` with `AppShell.Rail`, the compact rail (`rail="compact"`, the one fold control from `onRailChange`, and `useAppShell().rail` to pick the shape) and `fill="flush"`, the `aside` track and the `peek` slot (`useAppShellAside`, `useAppShellPeek`), `AppShell.ResizeHandle` (also `ResizeHandle`) and `useStoredWidth`, `SidePanel` and `SidePanelFrame`, `PeekRail` and `PeekHost` (with `PeekNeighbours`, `usePeekNeighbours`, `usePeekStep`, `peekClickHandler`, `peekRowActivation`), `SectionFrame` (with `SectionFrame.Nav` and `SectionFrame.Body`), `DockColumn` and `usePresence`, `LockedLabel`, `AppShell.Topbar`, `AppShell.AccountRow` and `useAppShell`, `AuthLayout`, `SidebarNav` and `NavItem` (with `dense` lists, `unread` and `muted` rows and `collapsible` groups), `CompactNav` with `CompactNavItem`, `CompactNavGroup` and `CompactNavSeparator` (the rail folded to its marks, fed from the same places), `DirectoryList`, `BrandLockup`, `SearchTrigger`, `PageHeader`, `Toolbar`, `Stack`, `Inline`, `Spacer`, `AutoGrid`, `ErrorBoundary`, `useShortcut`, `useFullscreen`, `useIdle`, `useMediaMatch` |
57
57
  | Preferences | `ThemeToggle`, `ThemeSwitcher`, `DensitySwitcher`, `ThemeGallery`, `ThemeSwatch`, `useThemePreference`, `useDensityPreference`, `useSystemTheme`, `resolveTheme`, `applyStoredPreferences`, and the framework-free `applyTheme`, `applyPalette`, `applyDensity` with `THEME_PREFERENCES`, `DENSITY_PREFERENCES` and their guards |
@@ -205,6 +205,20 @@ places:
205
205
  - A surface that pans or zooms dispatches `LAYER_REPOSITION_EVENT` on its host
206
206
  when the content beneath it moves, and every panel anchored inside follows.
207
207
 
208
+ ## Changes in 0.86.0
209
+
210
+ ### Forms, tables and directories
211
+
212
+ **`KeyValueRows` is new**: keys and their values edited as rows under one column head, for request headers, environment variables and any list of names and what each is set to. The key and value columns are named once (`keyLabel`, `valueLabel`), and each field is named on its own for a screen reader ("Header 2", "Value for Authorization"), so every row is the same row. Every row stands on its fields' top edge, so a refused key or value (`keyError`, `valueError`) is said under its own field, linked to it, and the controls beside it stay level. The remove button is a square the fields' height, and Add is a flush quiet action under the rows. Add puts the focus in the new row's key; Remove moves it to the row that took that row's place, else the one before, else Add, and says what went. Keys take the `reference` appearance and are never spell-checked; `secret` hides each value and marks it `new-password`, so no browser offers a saved password into it. `keyReadOnly` holds a row's key, and `valuePlaceholder` may differ per row. Controlled: every edit hands back a new list with each untouched row as it was. Rows may carry fields of their own (`KeyValueRows<T extends KeyValueRow>`), and then `createRow` makes a blank one, which the type requires. The group is a fieldset named by `label` (`hideLabel` keeps it for assistive technology only); `empty` is what an empty list says; `helper`, `error` and `disabled` are as on a field. Every word is the caller's (`labels`), with English defaults made from the column names by `keyValueRowsLabels(keyLabel, valueLabel)`. Types: `KeyValueRow`, `KeyValueRowsLabels`, `KeyValueRowsProps`. Stories: `KeyValueRows`.
213
+
214
+ **`TableTwoLineCell` is new**: a value over a quieter line, each cut on one line, among the read-only table cells. The `value` is set in the cell's own register and the `detail` under it is a caption in the secondary ink, so a row of these is exactly two lines tall whatever they hold. `mono` (`TableTwoLineCellMono`: `value`, `detail` or `both`) sets a literal in the mono face. A mark stands centred against both lines, as a column's hidden `icon` or a row's read `mark`, and in a grid's stacked rows the lines give the row its baseline. A cut line shows its whole words on hover; `title` speaks for the whole cell instead, and `titleWhenCut={false}` leaves the words to a `Tooltip` around the cell. Types: `TableTwoLineCellProps`, `TableTwoLineCellMono`. Stories: `TableCells` Two Line Cells, and its right to left, stacked and both themes variants.
215
+
216
+ **`RailList` is new**: a directory in a card, the groups its items are filed in as a rail beside the chosen group's list, so a long catalogue reads as a few short lists. The rail is a dense `SidebarNav`, each group (`RailListItem`) a row with its `count`, read as part of its name with `labels.counted` ("Chat, 6 apps"), the chosen one (`value`) raised and `aria-current`, with an optional quiet `note` under the rows. A group with an `href` is a link a reader can open in a new tab, and a plain click chooses it in place (`onChange`); without one it is a button. The chosen group's `description` stands over the list on a hairline, and a grid at the top of the list draws no second rule. Under 44rem of the card's own width the rail goes and a `Select` of the same groups, named by the same `label`, joins the bar across the top, so the same directory in a page and in a sheet needs nothing set. `toolbar` is the bar's content: given as a function, it is handed the picker to place among its own controls; given as content, the picker leads it. `renderLink` draws each row's link for a router. Every word is the caller's (`labels`, with `RAIL_LIST_LABELS` as the defaults). Types: `RailListItem`, `RailListLabels`, `RailListProps`. Stories: `RailList`.
217
+
218
+ ### Text
219
+
220
+ **A `Text` cut by `truncate` or `clamp` shows its whole words on hover.** While the words are cut, the element's title carries them whole, read from the element as it is shown; while they fit, it carries none. The cut is measured when the pointer arrives, so the title never goes stale after a resize or a new value, and nothing is measured until then. A `title` the caller passes always wins, and `titleWhenCut={false}` leaves the title to whatever already shows the words, such as a `Tooltip`. Story: `Text` Whole Words When Cut.
221
+
208
222
  ## Changes in 0.85.0
209
223
 
210
224
  ### What needs a person, and who gets something
@@ -4,11 +4,11 @@ import '../chunk-K4LZXSKZ.js';
4
4
  import '../chunk-7K6LVM5I.js';
5
5
  import '../chunk-WANKINXG.js';
6
6
  import '../chunk-ZXXZESCD.js';
7
+ import '../chunk-YGRTX67J.js';
7
8
  import '../chunk-STJ7QBC3.js';
8
9
  import '../chunk-DTIW4CHZ.js';
9
- import '../chunk-YGRTX67J.js';
10
- import '../chunk-EE3DJMSQ.js';
11
10
  import '../chunk-NXFTCPF6.js';
11
+ import '../chunk-EE3DJMSQ.js';
12
12
  import '../chunk-EC6EUIAD.js';
13
13
  import '../chunk-EJNJMHQG.js';
14
14
  import '../chunk-RE3FBGQQ.js';
@@ -0,0 +1,125 @@
1
+ import { type ReactNode } from 'react';
2
+ /** One key and its value: a header and what it carries, a variable and what it is set to. */
3
+ export interface KeyValueRow {
4
+ /**
5
+ * Stable across edits, and unique in the list: the row's identity while its
6
+ * key is typed, emptied or repeated. Two rows may share a key; never an id.
7
+ */
8
+ id: string;
9
+ key: string;
10
+ value: string;
11
+ }
12
+ /** Every word the rows say, beyond the names of their two columns. */
13
+ export interface KeyValueRowsLabels {
14
+ /** Names a row's key field: "Header 2". */
15
+ key: (position: number) => string;
16
+ /** Names a row's value field by its key: "Value for Authorization", or "Value for header 2" before one is typed. */
17
+ value: (key: string, position: number) => string;
18
+ /** Names a row's remove button: "Remove Authorization". */
19
+ remove: (key: string, position: number) => string;
20
+ /** The add action's words: "Add header". */
21
+ add: string;
22
+ /** Said once a row is removed, since the row's going is otherwise silent: "Removed Authorization". */
23
+ removed: (key: string, position: number) => string;
24
+ }
25
+ /**
26
+ * The rows' words in English, made from the two column names: `Header` and
27
+ * `Value` give "Header 2", "Value for Authorization", "Remove Authorization"
28
+ * and "Add header". A caller whose key column is an acronym (`URL`) or not in
29
+ * English passes its own `labels`.
30
+ */
31
+ export declare function keyValueRowsLabels(keyLabel: string, valueLabel?: string): KeyValueRowsLabels;
32
+ interface KeyValueRowsBaseProps<T extends KeyValueRow> {
33
+ /**
34
+ * What the list is: "Headers", "Environment variables". The group's legend,
35
+ * read on entering it.
36
+ */
37
+ label: string;
38
+ /**
39
+ * The legend is kept for assistive technology and drawn for nobody, where
40
+ * the column head or a heading right above already names the list.
41
+ */
42
+ hideLabel?: boolean | undefined;
43
+ /** The key column's head, and the name each key field is called by: "Header", "Variable". */
44
+ keyLabel: string;
45
+ /** The value column's head. "Value" by default. */
46
+ valueLabel?: string | undefined;
47
+ value: readonly T[];
48
+ onChange: (next: T[]) => void;
49
+ keyPlaceholder?: string | undefined;
50
+ /** The value field's placeholder, the same for every row or per row (a stored secret says so). */
51
+ valuePlaceholder?: string | ((row: T) => string | undefined) | undefined;
52
+ /**
53
+ * The values are secrets (a token, a password): each value field hides what
54
+ * is typed, and no browser offers a saved password for it.
55
+ */
56
+ secret?: boolean | undefined;
57
+ /**
58
+ * A row whose key may not change, such as one already saved: its key field
59
+ * is read only, and its value and its remove button still work.
60
+ */
61
+ keyReadOnly?: ((row: T) => boolean) | undefined;
62
+ /** Why a row's key was refused, said under that key and linked to it. */
63
+ keyError?: ((row: T, index: number) => ReactNode) | undefined;
64
+ /** Why a row's value was refused, said under that value and linked to it. */
65
+ valueError?: ((row: T, index: number) => ReactNode) | undefined;
66
+ /**
67
+ * What the list says while it holds no row, in place of the rows. Left out,
68
+ * an empty list is its legend and its add action.
69
+ */
70
+ empty?: ReactNode;
71
+ /** Where the keys come from, or what shape they take, under the add action. */
72
+ helper?: ReactNode;
73
+ /** Why the list as a whole was refused. */
74
+ error?: ReactNode;
75
+ disabled?: boolean | undefined;
76
+ /** Words in place of the ones `keyValueRowsLabels` makes from `keyLabel` and `valueLabel`. */
77
+ labels?: Partial<KeyValueRowsLabels> | undefined;
78
+ className?: string | undefined;
79
+ }
80
+ /**
81
+ * A blank row for the add action. Optional while a row is nothing but its id,
82
+ * key and value, when the list makes `{ id, key: '', value: '' }` itself;
83
+ * required once the caller's rows carry a field of their own that a blank row
84
+ * must set.
85
+ *
86
+ * AN EMPTY LIST NAMES NO ROW TYPE. `value={[]}` infers `never`, which no row
87
+ * is assignable to, so a test of assignability alone asked an empty list for
88
+ * a `createRow` it has no use for. A list whose row type was never inferred
89
+ * makes its own blank rows too.
90
+ */
91
+ type RowMaker<T extends KeyValueRow> = [T] extends [never] ? {
92
+ createRow?: (() => T) | undefined;
93
+ } : KeyValueRow extends T ? {
94
+ createRow?: (() => T) | undefined;
95
+ } : {
96
+ createRow: () => T;
97
+ };
98
+ export type KeyValueRowsProps<T extends KeyValueRow = KeyValueRow> = KeyValueRowsBaseProps<T> & RowMaker<T>;
99
+ /**
100
+ * Keys and their values, edited as rows under one column head: request
101
+ * headers, environment variables, any list of names and what each is set to.
102
+ *
103
+ * ONE HEAD OVER THE COLUMNS, SO EVERY ROW IS THE SAME ROW. The key and value
104
+ * columns are named once, above the first row, and each field's own name is
105
+ * read rather than drawn ("Header 2", "Value for Authorization"). A label
106
+ * drawn on the first row only stood that row taller than the rest, and the
107
+ * value and the remove button beside it lost the line they shared.
108
+ *
109
+ * AN ERROR MOVES NOTHING BESIDE IT. Every row stands on its fields' top edge,
110
+ * so a refused key grows its own cell downward and the value and the remove
111
+ * button stay level with the key's field.
112
+ *
113
+ * THE REMOVE BUTTON IS THE FIELDS' HEIGHT, a square at the control step, so a
114
+ * row is one line of three controls. Add is a flush quiet action under the
115
+ * rows, its words on the fields' own edge.
116
+ *
117
+ * FOCUS NEVER FALLS TO THE PAGE. Add puts it in the new row's key; Remove
118
+ * moves it to the row that took that row's place, else the one before, else
119
+ * Add, and says what went.
120
+ *
121
+ * Controlled: the rows are the caller's, and every edit hands back a new
122
+ * list with each untouched row as it was.
123
+ */
124
+ export declare function KeyValueRows<T extends KeyValueRow = KeyValueRow>(props: KeyValueRowsProps<T>): import("react").JSX.Element;
125
+ export {};
@@ -0,0 +1,3 @@
1
+ import './KeyValueRows.css';
2
+ export { KeyValueRows, keyValueRowsLabels } from './KeyValueRows.js';
3
+ export type { KeyValueRow, KeyValueRowsLabels, KeyValueRowsProps } from './KeyValueRows.js';
@@ -0,0 +1,12 @@
1
+ export { KeyValueRows, keyValueRowsLabels } from '../chunk-TRZS7DLB.js';
2
+ import '../chunk-O7N6W52M.js';
3
+ import '../chunk-PGCLHYVP.js';
4
+ import '../chunk-DGXZ635L.js';
5
+ import '../chunk-XSPCITPN.js';
6
+ import '../chunk-TUEM2XIW.js';
7
+ import '../chunk-4ITETIGZ.js';
8
+ import '../chunk-UAUP6XGK.js';
9
+ import '../chunk-PQADV6P6.js';
10
+ import '../chunk-2G355KDJ.js';
11
+ import '../chunk-UT6CW3C7.js';
12
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,44 @@
1
+ /*
2
+ * KeyValueRows: keys and their values as rows under one column head
3
+ * (KeyValueRows.tsx).
4
+ */
5
+
6
+ /* The rows, then Add under them, a row's gap apart. */
7
+ .crewlet-key-value-rows__body,
8
+ .crewlet-key-value-rows__table {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--spacing-2);
12
+ min-width: 0;
13
+ }
14
+
15
+ /*
16
+ * EVERY ROW STANDS ON ITS FIELDS' TOP EDGE, so a key's error grows its own
17
+ * cell downward and nothing beside it moves. The last track is the remove
18
+ * button's, a square the fields' height, and the head keeps it empty so the
19
+ * value's name stands over the value column.
20
+ */
21
+ .crewlet-key-value-rows__head,
22
+ .crewlet-key-value-rows__row {
23
+ display: grid;
24
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) var(--size-control-md);
25
+ align-items: start;
26
+ gap: var(--spacing-2);
27
+ }
28
+
29
+ /* The head stands over the first row at a field label's distance from its field. */
30
+ .crewlet-key-value-rows__head {
31
+ margin-block-end: calc(var(--spacing-1) - var(--spacing-2));
32
+ }
33
+
34
+ .crewlet-key-value-rows__empty {
35
+ margin: 0;
36
+ font-size: var(--font-size-compact);
37
+ line-height: var(--font-line-height-normal);
38
+ color: var(--color-text-secondary);
39
+ }
40
+
41
+ /* Add hugs its words, on the fields' start edge, rather than spanning the list. */
42
+ .crewlet-key-value-rows__add {
43
+ display: flex;
44
+ }
@@ -1,6 +1,6 @@
1
- export { PresenterView, formatStopwatch } from '../chunk-LMEMH6DO.js';
2
- import '../chunk-5AJR6X75.js';
1
+ export { PresenterView, formatStopwatch } from '../chunk-WCJTOKTY.js';
3
2
  import '../chunk-O6EV6GKI.js';
3
+ import '../chunk-5AJR6X75.js';
4
4
  import '../chunk-RK4XPHVG.js';
5
5
  import '../chunk-DGXZ635L.js';
6
6
  import '../chunk-XSPCITPN.js';
@@ -0,0 +1,74 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type NavItemProps } from '../SidebarNav/index.js';
3
+ /** One of the groups a directory files its items in, and the rail's row for it. */
4
+ export interface RailListItem {
5
+ /** Unique among the items, and what `value` names. An empty key is a fine "All". */
6
+ key: string;
7
+ label: string;
8
+ /** How many items the group holds: a quiet figure at the row's end, and after the label in the folded picker. */
9
+ count?: number | undefined;
10
+ /**
11
+ * The group's own address, where the chosen group is kept in the page's
12
+ * address: the row is then a link a reader can open in a new tab, and a
13
+ * plain click still chooses it in place.
14
+ */
15
+ href?: string | undefined;
16
+ /** One quiet line about the group, said over the list while it is chosen: what the group holds. */
17
+ description?: ReactNode;
18
+ }
19
+ /** Every word the rail and its picker say, beyond the items' own labels. */
20
+ export interface RailListLabels {
21
+ /** What a count counts, read after the figure as part of the row's name: "apps" makes "Chat, 6 apps". */
22
+ counted: string;
23
+ /** A group as the folded picker names it: "Chat (6)". */
24
+ option: (label: string, count: number | undefined) => string;
25
+ }
26
+ export declare const RAIL_LIST_LABELS: RailListLabels;
27
+ export interface RailListProps {
28
+ /** Names the rail's navigation and the picker it folds into: "Categories", "Template kinds". */
29
+ label: string;
30
+ /** The groups, in the order the rail lists them; an "All" group is one of them, usually the first. */
31
+ items: readonly RailListItem[];
32
+ /** The chosen group's key. */
33
+ value: string;
34
+ onChange: (key: string) => void;
35
+ /**
36
+ * The bar across the top of the card, over the rail and the list: a search
37
+ * and filter chips. Where the card is too narrow for the rail, the picker
38
+ * it folds into joins this bar. Given as a function, it is handed the
39
+ * picker to place among its own controls; given as content, the picker
40
+ * leads the bar. Left out, the bar is drawn only to hold the picker.
41
+ */
42
+ toolbar?: ReactNode | ((picker: ReactNode) => ReactNode);
43
+ /** One quiet fact about the whole directory, under the rail's rows: what every item in it has in common. */
44
+ note?: ReactNode;
45
+ /** The list the chosen group shows: a grid, a list of tiles. */
46
+ children: ReactNode;
47
+ /** Draws each rail row's link, for a router that owns navigation (`SidebarNav`'s `renderLink`). */
48
+ renderLink?: NavItemProps['renderLink'];
49
+ labels?: Partial<RailListLabels> | undefined;
50
+ className?: string | undefined;
51
+ }
52
+ /**
53
+ * A directory in a card: a rail of the groups its items are filed in, beside
54
+ * the list of the chosen group, so a long catalogue reads as a few short
55
+ * lists: apps in what they are for, templates in their kinds, reports in
56
+ * the teams that read them.
57
+ *
58
+ * THE RAIL IS THE APPLICATION'S RAIL, DENSER (`SidebarNav` `dense`), each
59
+ * group a row with its count, the chosen one raised and `aria-current`, on a
60
+ * hairline of its own beside the list, with an optional quiet note under its
61
+ * rows. The chosen group's description, where it has one, stands over the
62
+ * list on a hairline, so a reader knows what the short list is.
63
+ *
64
+ * IT FOLDS BY ITS OWN WIDTH, NOT THE WINDOW'S. Under 44rem of the card's
65
+ * width the rail does not leave the list a readable column, so the rail goes
66
+ * and a `Select` of the same groups, named the same, joins the bar across the
67
+ * top. The same directory in a page and in a 560px sheet is one component
68
+ * with nothing to set: the sheet is simply narrow.
69
+ *
70
+ * Controlled: the chosen group is the caller's, often kept in the page's
71
+ * address (`href` on each group), so a group opened in a new tab and Back
72
+ * both keep it.
73
+ */
74
+ export declare function RailList({ label, items, value, onChange, toolbar, note, children, renderLink, labels: overrides, className, }: RailListProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './RailList.css';
2
+ export { RAIL_LIST_LABELS, RailList } from './RailList.js';
3
+ export type { RailListItem, RailListLabels, RailListProps } from './RailList.js';
@@ -0,0 +1,17 @@
1
+ export { RAIL_LIST_LABELS, RailList } from '../chunk-REWKR3S4.js';
2
+ import '../chunk-BRK3HXGZ.js';
3
+ import '../chunk-3IWZVEXA.js';
4
+ import '../chunk-O5CEG7TQ.js';
5
+ import '../chunk-YGRTX67J.js';
6
+ import '../chunk-TEV5REGB.js';
7
+ import '../chunk-HBDA76EZ.js';
8
+ import '../chunk-U2IQNDDR.js';
9
+ import '../chunk-AV2DXAEL.js';
10
+ import '../chunk-OMV5W53A.js';
11
+ import '../chunk-2YTOOH3A.js';
12
+ import '../chunk-TUEM2XIW.js';
13
+ import '../chunk-4ITETIGZ.js';
14
+ import '../chunk-D2GT3CR4.js';
15
+ import '../chunk-PQADV6P6.js';
16
+ import '../chunk-UT6CW3C7.js';
17
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,97 @@
1
+ /*
2
+ * RailList: a directory in a card, a rail of groups beside the chosen
3
+ * group's list, folding into a picker where the card is narrow
4
+ * (RailList.tsx).
5
+ *
6
+ * SIZED BY ITS OWN WIDTH, NOT THE WINDOW'S, because the same directory stands
7
+ * in a page and in a sheet: the root is an inline-size container, and under
8
+ * the rail's room (44rem) the rail goes and the picker shows. Both are always
9
+ * rendered and the stylesheet decides, so the fold costs no measurement and
10
+ * never draws the wrong one first.
11
+ */
12
+ .crewlet-rail-list {
13
+ container: crewlet-rail-list / inline-size;
14
+ min-width: 0;
15
+ }
16
+
17
+ /* The bar across the card's top: the caller's search and chips, and the folded picker. */
18
+ .crewlet-rail-list__bar {
19
+ display: flex;
20
+ flex-wrap: wrap;
21
+ align-items: center;
22
+ gap: var(--spacing-2);
23
+ padding: var(--spacing-3);
24
+ border-block-end: 1px solid var(--color-border-default);
25
+ }
26
+
27
+ /* Wide, the rail is the choice: the picker and a bar that holds nothing else are not drawn. */
28
+ .crewlet-rail-list__picker,
29
+ .crewlet-rail-list__bar--picker-only {
30
+ display: none;
31
+ }
32
+
33
+ /* The rail at a fixed width (13rem by default), the list taking the rest. */
34
+ .crewlet-rail-list__body {
35
+ display: grid;
36
+ grid-template-columns: var(--crewlet-rail-list-rail, 13rem) minmax(0, 1fr);
37
+ min-width: 0;
38
+ }
39
+
40
+ /* The rail on a hairline of its own, its note a step under its rows. */
41
+ .crewlet-rail-list__rail {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--spacing-3);
45
+ min-width: 0;
46
+ padding: var(--spacing-2);
47
+ border-inline-end: 1px solid var(--color-border-default);
48
+ }
49
+
50
+ /* The note starts on the rows' words, inside the dense rail's own inset. */
51
+ .crewlet-rail-list__note {
52
+ margin: 0;
53
+ padding-inline: var(--spacing-2);
54
+ }
55
+
56
+ .crewlet-rail-list__list {
57
+ display: flex;
58
+ flex-direction: column;
59
+ min-width: 0;
60
+ }
61
+
62
+ /* What the chosen group holds, over its list on a hairline, at the list's own inset. */
63
+ .crewlet-rail-list__about {
64
+ margin: 0;
65
+ padding: var(--spacing-2) var(--spacing-4);
66
+ border-block-end: 1px solid var(--color-border-default);
67
+ }
68
+
69
+ /*
70
+ * A GRID AT THE LIST'S TOP TAKES NO RULE OF ITS OWN. A grid in a card draws
71
+ * one rule above its head to part it from the card's head (DataGrid.css);
72
+ * here the bar's hairline, the description's or the card's own edge is
73
+ * already that rule, and the grid's drew a second line under it.
74
+ */
75
+ .crewlet-rail-list__list > .crewlet-data-grid:first-child,
76
+ .crewlet-rail-list__about + .crewlet-data-grid {
77
+ border-top: 0;
78
+ }
79
+
80
+ /* Under the rail's room the list takes the card, and the picker takes the rail's place in the bar. */
81
+ @container crewlet-rail-list (width < 44rem) {
82
+ .crewlet-rail-list__body {
83
+ grid-template-columns: minmax(0, 1fr);
84
+ }
85
+
86
+ .crewlet-rail-list__rail {
87
+ display: none;
88
+ }
89
+
90
+ .crewlet-rail-list__picker {
91
+ display: inline-flex;
92
+ }
93
+
94
+ .crewlet-rail-list__bar--picker-only {
95
+ display: flex;
96
+ }
97
+ }
@@ -1,5 +1,5 @@
1
- export { RelatedRow } from '../chunk-EAHEJNVJ.js';
2
- import '../chunk-QP2P6GDQ.js';
1
+ export { RelatedRow } from '../chunk-CL3FWLDO.js';
2
+ import '../chunk-O5CEG7TQ.js';
3
3
  import '../chunk-ZAC7SKUN.js';
4
4
  import '../chunk-U2IQNDDR.js';
5
5
  import '../chunk-AV2DXAEL.js';
@@ -1,4 +1,4 @@
1
- export { RichEditor, preloadRichEditor } from '../chunk-AUSFKGKL.js';
1
+ export { RichEditor, preloadRichEditor } from '../chunk-3AMWXJQX.js';
2
2
  export { RICH_EDITOR_LABELS, richEditorLabels } from '../chunk-2DMTW2Y3.js';
3
3
  import '../chunk-KOJPDCGQ.js';
4
4
  import '../chunk-KBZO4B33.js';
@@ -1,6 +1,6 @@
1
- export { SetupWizard } from '../chunk-3BVNNQZY.js';
2
- import '../chunk-FPDIHEM4.js';
1
+ export { SetupWizard } from '../chunk-WRZPO4YL.js';
3
2
  import '../chunk-TMML7BHT.js';
3
+ import '../chunk-FPDIHEM4.js';
4
4
  import '../chunk-YJQXESOJ.js';
5
5
  import '../chunk-CYQBDZ6M.js';
6
6
  import '../chunk-NAHA62WD.js';
@@ -1,10 +1,10 @@
1
1
  export { ARTIFACT_ROLES, SHAREABLE_ROLES, ShareDialog, roleAtLeast } from '../chunk-Y7PPKQFQ.js';
2
2
  import '../chunk-3IWZVEXA.js';
3
3
  import '../chunk-ZXXZESCD.js';
4
+ import '../chunk-YGRTX67J.js';
4
5
  import '../chunk-ETNQYT5O.js';
5
6
  import '../chunk-STJ7QBC3.js';
6
7
  import '../chunk-DTIW4CHZ.js';
7
- import '../chunk-YGRTX67J.js';
8
8
  import '../chunk-BPCY7ZID.js';
9
9
  import '../chunk-HF5L56YQ.js';
10
10
  import '../chunk-YTLWOHOY.js';
@@ -151,3 +151,63 @@ export type TableTextCellProps = {
151
151
  * would draw the column's answer over the row's.
152
152
  */
153
153
  export declare function TableTextCell({ children, icon, mark }: TableTextCellProps): import("react").JSX.Element;
154
+ /** Which of a two-line cell's lines is a literal, set in the mono face. */
155
+ export type TableTwoLineCellMono = 'value' | 'detail' | 'both';
156
+ export type TableTwoLineCellProps = {
157
+ /** The value, in the cell's own register: a name, a key, a short state. */
158
+ value: ReactNode;
159
+ /**
160
+ * The quieter line under it, a caption in the secondary ink: where it runs,
161
+ * the id it resolves to, when it last answered. Left out, the cell is the
162
+ * value's one line, at the same place a row of two-line cells puts it.
163
+ */
164
+ detail?: ReactNode;
165
+ /**
166
+ * Which line is a literal (a command, an id, a key), set in the mono face:
167
+ * in the sans face `--` and `=` read as prose.
168
+ */
169
+ mono?: TableTwoLineCellMono | undefined;
170
+ /**
171
+ * The whole cell's hover text, where the two lines are not the whole story
172
+ * (a model's CLI, key and id in one line). Given, neither line adds its own.
173
+ */
174
+ title?: string | undefined;
175
+ /**
176
+ * Whether a cut line carries its whole words as its title (`Text`'s
177
+ * `titleWhenCut`). On by default. Off where something else already shows
178
+ * them, a `Tooltip` around the cell.
179
+ */
180
+ titleWhenCut?: boolean | undefined;
181
+ } & ({
182
+ /**
183
+ * A mark every row of the column wears, centred against the two lines.
184
+ * The header carries the meaning, so it is drawn as decoration.
185
+ */
186
+ icon?: ReactNode;
187
+ mark?: never;
188
+ } | {
189
+ icon?: never;
190
+ /**
191
+ * A mark that varies per row and states a fact of its own (a vendor, the
192
+ * CLI a model runs on), centred against the two lines. It brings its own
193
+ * accessible name and is read.
194
+ */
195
+ mark: ReactNode;
196
+ });
197
+ /**
198
+ * A value over a quieter line, each cut on one line: a name over where it
199
+ * runs, a key over the id it resolves to, a short state over when it began.
200
+ *
201
+ * TWO LINES IN TWO REGISTERS, ALWAYS THE SAME TWO, so every two-line cell in a
202
+ * table reads alike: the value in the cell's own register (it inherits the
203
+ * grid's size and ink), the line under it a caption in the secondary ink. A
204
+ * row of them is as tall as two lines whatever they hold, because each line
205
+ * is cut with an ellipsis rather than wrapped, and its whole words are on its
206
+ * title while it is cut (`Text`'s `truncate`).
207
+ *
208
+ * A MARK STANDS CENTRED AGAINST BOTH LINES, the way a vendor's mark stands
209
+ * beside a service's name and host. In a grid's stacked rows the lines, not
210
+ * the mark, give the row its baseline, so a column's label stands on the
211
+ * value's line (DataGrid.css).
212
+ */
213
+ export declare function TableTwoLineCell({ value, detail, mono, title, titleWhenCut, icon, mark, }: TableTwoLineCellProps): import("react").JSX.Element;
@@ -1,3 +1,3 @@
1
1
  import './TableCells.css';
2
- export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell, } from './TableCells.js';
3
- export type { TableDateCellProps, TableEntityCellProps, TableKeyCellProps, TableNumberCellProps, TableStatusCellProps, TableTagsCellLabels, TableTagsCellProps, TableTextCellProps, } from './TableCells.js';
2
+ export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell, TableTwoLineCell, } from './TableCells.js';
3
+ export type { TableDateCellProps, TableEntityCellProps, TableKeyCellProps, TableNumberCellProps, TableStatusCellProps, TableTagsCellLabels, TableTagsCellProps, TableTextCellProps, TableTwoLineCellMono, TableTwoLineCellProps, } from './TableCells.js';
@@ -1,4 +1,5 @@
1
- export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell } from '../chunk-AFLS26AC.js';
1
+ export { TABLE_TAGS_CELL_LABELS, TableDateCell, TableEntityCell, TableKeyCell, TableNumberCell, TableStatusCell, TableTagsCell, TableTextCell, TableTwoLineCell } from '../chunk-3CALM534.js';
2
+ import '../chunk-O5CEG7TQ.js';
2
3
  import '../chunk-QF5UNP4T.js';
3
4
  import '../chunk-LBGKLYBY.js';
4
5
  import '../chunk-EJNJMHQG.js';
@@ -112,3 +112,31 @@
112
112
  font-size: var(--font-size-xs);
113
113
  font-variant-numeric: tabular-nums;
114
114
  }
115
+
116
+ /*
117
+ * A VALUE OVER A QUIETER LINE (TableTwoLineCell), each line its own block cut
118
+ * on one line. A column of boxes rather than two runs of text, so neither
119
+ * line takes the line box of the words around it, and the cell is exactly
120
+ * the two lines tall. `min-width: 0` lets the column shrink inside a grid's
121
+ * cell, which is what cuts the lines rather than pushing the column wider.
122
+ */
123
+ .crewlet-table-cell__lines {
124
+ display: flex;
125
+ flex-direction: column;
126
+ min-width: 0;
127
+ max-width: 100%;
128
+ }
129
+
130
+ /* The mark is centred against both lines, as an entity's badge is against its name. */
131
+ .crewlet-table-cell__two-line {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: var(--spacing-2);
135
+ min-width: 0;
136
+ max-width: 100%;
137
+ }
138
+
139
+ /* The mark keeps its size: the lines give way to the column, never the mark. */
140
+ .crewlet-table-cell__two-line > :first-child {
141
+ flex: none;
142
+ }