@crewlethq/ui 0.34.2 → 0.35.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 +47 -0
  2. package/dist/AppShell/index.js +2 -2
  3. package/dist/ArtifactBar/ArtifactBar.d.ts +6 -0
  4. package/dist/ArtifactBar/index.d.ts +1 -0
  5. package/dist/ArtifactBar/index.js +2 -2
  6. package/dist/{ArtifactBar-C462VD4C.css → ArtifactBar-HV5AT4RG.css} +39 -2
  7. package/dist/ArtifactCard/index.d.ts +1 -0
  8. package/dist/ArtifactCard/index.js +2 -2
  9. package/dist/{ArtifactCard-XHRLAL7C.css → ArtifactCard-OGTMO2KI.css} +15 -16
  10. package/dist/ArtifactKindIllustration/ArtifactKindIllustration.d.ts +14 -1
  11. package/dist/ArtifactKindIllustration/index.d.ts +1 -0
  12. package/dist/ArtifactKindIllustration/index.js +1 -1
  13. package/dist/{ArtifactKindIllustration-4NG6IE3C.css → ArtifactKindIllustration-5FPRJQ3P.css} +32 -26
  14. package/dist/ArtifactKinds-CVD3FCYO.css +15 -0
  15. package/dist/AvatarPicker/index.js +2 -2
  16. package/dist/CanvasBoard/CanvasBoard.d.ts +30 -12
  17. package/dist/CanvasBoard/index.js +1 -1
  18. package/dist/ChangeMark/index.js +2 -2
  19. package/dist/ChoiceList/ChoiceList.d.ts +7 -1
  20. package/dist/ChoiceList/index.js +1 -1
  21. package/dist/{ChoiceList-2PQJS4DX.css → ChoiceList-RBL7FNQL.css} +39 -0
  22. package/dist/DataTable/index.js +2 -2
  23. package/dist/DataView/index.js +3 -3
  24. package/dist/DocTabsEditor/index.js +2 -2
  25. package/dist/{Editor-JMRD6AZW.js → Editor-BVQHBF7L.js} +4 -4
  26. package/dist/FileDrop/FileDrop.d.ts +64 -0
  27. package/dist/FileDrop/index.d.ts +3 -0
  28. package/dist/FileDrop/index.js +4 -0
  29. package/dist/FileDrop-WE7BNZGV.css +80 -0
  30. package/dist/FindingList/FindingList.d.ts +35 -0
  31. package/dist/FindingList/index.d.ts +3 -0
  32. package/dist/FindingList/index.js +3 -0
  33. package/dist/FindingList-PMYA2R6Q.css +71 -0
  34. package/dist/HuePicker/HuePicker.d.ts +9 -0
  35. package/dist/HuePicker/index.d.ts +1 -1
  36. package/dist/HuePicker/index.js +1 -1
  37. package/dist/Markdown/index.js +1 -1
  38. package/dist/Menu/Menu.d.ts +6 -1
  39. package/dist/Menu/index.js +1 -1
  40. package/dist/RichEditor/index.js +3 -3
  41. package/dist/RichEditorMarkdown/index.js +3 -3
  42. package/dist/SheetColumnEditor/SheetColumnEditor.d.ts +94 -0
  43. package/dist/SheetColumnEditor/index.d.ts +3 -0
  44. package/dist/SheetColumnEditor/index.js +23 -0
  45. package/dist/SheetColumnEditor-BO2HKFRB.css +73 -0
  46. package/dist/SheetGrid/SheetGrid.d.ts +19 -1
  47. package/dist/SheetGrid/index.js +5 -4
  48. package/dist/{SheetGrid-GDPCCZ4V.css → SheetGrid-YRDXTIIZ.css} +48 -0
  49. package/dist/SheetModel/index.js +1 -1
  50. package/dist/SheetModel/labels.d.ts +6 -0
  51. package/dist/SlideFilmstrip/SlideFilmstrip.d.ts +30 -1
  52. package/dist/SlideFilmstrip/index.js +5 -1
  53. package/dist/{SlideFilmstrip-5U6Z55GS.css → SlideFilmstrip-4ITZLMO4.css} +49 -0
  54. package/dist/SourceEditor/SourceEditor.d.ts +62 -0
  55. package/dist/SourceEditor/index.d.ts +3 -0
  56. package/dist/SourceEditor/index.js +3 -0
  57. package/dist/SourceEditor-G2C3STPX.css +160 -0
  58. package/dist/ThemeGallery/ThemeGallery.d.ts +10 -3
  59. package/dist/ThemeGallery/index.js +1 -1
  60. package/dist/{ThemeGallery-NITASULQ.css → ThemeGallery-HSUKBDWY.css} +9 -0
  61. package/dist/{chunk-UXXJDIYE.js → chunk-22CQQDFW.js} +1 -1
  62. package/dist/{chunk-EQ7P7DGN.js → chunk-3VD3G3IL.js} +2 -2
  63. package/dist/{chunk-EWAFN2IU.js → chunk-5VCG26CV.js} +281 -234
  64. package/dist/{chunk-7T5LSYZ2.js → chunk-7UYONN6K.js} +4 -3
  65. package/dist/{chunk-KK5OYNAF.js → chunk-BAKPMH3S.js} +8 -4
  66. package/dist/{chunk-3EB2AV3H.js → chunk-BUVCV3WI.js} +1 -1
  67. package/dist/{chunk-4B6LSFDS.js → chunk-CSQTDGTS.js} +1 -1
  68. package/dist/{chunk-WPX6A5BV.js → chunk-E35CMI5D.js} +22 -6
  69. package/dist/{chunk-OMLACFPP.js → chunk-FJJHD73S.js} +1 -1
  70. package/dist/{chunk-SGHIAGPR.js → chunk-HAKTRTRP.js} +1 -1
  71. package/dist/chunk-MAD6WPER.js +342 -0
  72. package/dist/{chunk-ZADVT7IL.js → chunk-NKZCJRKO.js} +9 -4
  73. package/dist/chunk-NTB5LRRD.js +52 -0
  74. package/dist/{chunk-VI5FWDZW.js → chunk-OOMXLJ3S.js} +4 -1
  75. package/dist/{chunk-UOR7TOAU.js → chunk-OSFA5ROT.js} +86 -1
  76. package/dist/{chunk-T46NR3WP.js → chunk-PGZ2R3ON.js} +1 -1
  77. package/dist/chunk-PI7HKLIT.js +245 -0
  78. package/dist/{chunk-YZFLH463.js → chunk-QEFHYUCY.js} +1 -1
  79. package/dist/{chunk-NPQWKZTB.js → chunk-QFNWMWWY.js} +2 -2
  80. package/dist/{chunk-C7DKX453.js → chunk-QH6VYJ3X.js} +1 -1
  81. package/dist/{chunk-XV32RKQZ.js → chunk-QIXMNOBD.js} +67 -6
  82. package/dist/{chunk-GPHWCK7M.js → chunk-SUXP4OBT.js} +6 -3
  83. package/dist/{chunk-TRQCHF2F.js → chunk-SWD4QBL6.js} +1 -1
  84. package/dist/chunk-THDGBD6Y.js +154 -0
  85. package/dist/{chunk-C2FRTWKO.js → chunk-W3UVOZKL.js} +3 -2
  86. package/dist/{chunk-UDQW6UK7.js → chunk-W7QBBKUE.js} +34 -7
  87. package/dist/{chunk-QBXZLGK2.js → chunk-ZU3DUXD2.js} +3 -2
  88. package/dist/generated/index.d.ts +4 -0
  89. package/dist/generated/index.js +56 -52
  90. package/dist/index.js +56 -52
  91. package/dist/styles.css +652 -51
  92. package/dist/utils/csv.d.ts +35 -0
  93. package/dist/utils/index.d.ts +2 -1
  94. package/dist/utils/index.js +1 -1
  95. package/package.json +3 -3
  96. /package/dist/{chunk-VFRSSP3W.js → chunk-3WCNHYXE.js} +0 -0
@@ -426,6 +426,54 @@
426
426
  font-size: var(--font-size-xs);
427
427
  }
428
428
 
429
+ /* A HEADER THAT OPENS ITS COLUMN'S SETTINGS reads as pressable: the pointer,
430
+ and the hover tint the open header keeps while its popover is up. */
431
+ .crewlet-sheet-grid__header--settings {
432
+ cursor: pointer;
433
+ }
434
+
435
+ .crewlet-sheet-grid__header--settings:hover,
436
+ .crewlet-sheet-grid__header--open {
437
+ background: var(--color-surface-hover);
438
+ color: var(--color-text-primary);
439
+ }
440
+
441
+ /* A COLUMN'S SETTINGS: the popover holds a short form, so it is padded as a
442
+ panel and given the room a list of choices needs before it scrolls. */
443
+ .crewlet-popover.crewlet-sheet-grid__column-settings {
444
+ width: 300px;
445
+ max-height: min(560px, 80vh);
446
+ padding: var(--spacing-3);
447
+ }
448
+
449
+ /* ADD COLUMN stands beside the header row, outside the grid's roles: the
450
+ scroller lays the grid and the control side by side, the grid's last track
451
+ still takes the slack up to the control, and the control sticks to the top
452
+ with the header while the rows scroll under it. */
453
+ .crewlet-sheet-grid__scroller--add-column {
454
+ --crewlet-sheet-add-column-width: var(--size-target-min);
455
+ display: flex;
456
+ align-items: flex-start;
457
+ }
458
+
459
+ .crewlet-sheet-grid__scroller--add-column > .crewlet-sheet-grid__grid {
460
+ flex: 0 0 auto;
461
+ min-width: calc(100% - var(--crewlet-sheet-add-column-width));
462
+ }
463
+
464
+ .crewlet-sheet-grid__add-column {
465
+ position: sticky;
466
+ top: 0;
467
+ z-index: var(--z-index-sticky);
468
+ display: flex;
469
+ flex: 0 0 var(--crewlet-sheet-add-column-width);
470
+ align-items: center;
471
+ justify-content: center;
472
+ box-sizing: border-box;
473
+ border-bottom: 1px solid var(--color-border-default);
474
+ background: var(--color-surface-subtle);
475
+ }
476
+
429
477
  .crewlet-sheet-grid__sync {
430
478
  display: inline-flex;
431
479
  align-items: center;
@@ -1,3 +1,3 @@
1
- export { LONGTEXT_MAX_DEFAULT, RATING_MAX_CEILING, RATING_MAX_DEFAULT, SHEET_COLUMN_BOUNDS, SHEET_COLUMN_TYPES, SHEET_COLUMN_WIDTHS, SHEET_FIT_SAMPLES, SHEET_LABELS, SHEET_ROW_HEIGHT, SHEET_ROW_NUMBER_WIDTH, SheetPendingEdits, TEXT_MAX_DEFAULT, URL_MAX, cellDescription, cellKey, cellSpeech, changeText, changeTime, checkValue, columnOffsets, columnWidth, compareValues, displayText, drawnColumns, editText, editorSide, findOption, findPerson, fitSamples, fittedWidth, flagText, hasPrevious, inRange, isEmptyValue, isMod, isMultiCell, isSheetColumnType, isTypingKey, liveOptions, moveFrom, nextSort, normalizeValue, optionHue, parseOptionList, parseTSV, parseText, planClear, planPaste, presenceByCell, presenceByColumn, presenceByRow, rangeOf, ratingMax, refusalText, rowName, sameValue, scrollToRow, sheetLabels, sortRows, spokenText, statusTone, textMax, toTSV, visibleRows } from '../chunk-VI5FWDZW.js';
1
+ export { LONGTEXT_MAX_DEFAULT, RATING_MAX_CEILING, RATING_MAX_DEFAULT, SHEET_COLUMN_BOUNDS, SHEET_COLUMN_TYPES, SHEET_COLUMN_WIDTHS, SHEET_FIT_SAMPLES, SHEET_LABELS, SHEET_ROW_HEIGHT, SHEET_ROW_NUMBER_WIDTH, SheetPendingEdits, TEXT_MAX_DEFAULT, URL_MAX, cellDescription, cellKey, cellSpeech, changeText, changeTime, checkValue, columnOffsets, columnWidth, compareValues, displayText, drawnColumns, editText, editorSide, findOption, findPerson, fitSamples, fittedWidth, flagText, hasPrevious, inRange, isEmptyValue, isMod, isMultiCell, isSheetColumnType, isTypingKey, liveOptions, moveFrom, nextSort, normalizeValue, optionHue, parseOptionList, parseTSV, parseText, planClear, planPaste, presenceByCell, presenceByColumn, presenceByRow, rangeOf, ratingMax, refusalText, rowName, sameValue, scrollToRow, sheetLabels, sortRows, spokenText, statusTone, textMax, toTSV, visibleRows } from '../chunk-OOMXLJ3S.js';
2
2
  import '../chunk-Z7JYG5TF.js';
3
3
  import '../chunk-AYKXMIOR.js';
@@ -74,6 +74,12 @@ export interface SheetLabels {
74
74
  keyboardHelp: string;
75
75
  /** A sort, for the header's control. */
76
76
  sortBy: (column: string) => string;
77
+ /** A column's settings popover, its name and its header's tip. */
78
+ columnSettings: (column: string) => string;
79
+ /** Appended to the keyboard help when headers open their column's settings. */
80
+ columnSettingsHelp: string;
81
+ /** The control after the last header that adds a column. */
82
+ addColumn: string;
77
83
  }
78
84
  export declare const SHEET_LABELS: SheetLabels;
79
85
  /** Labels with a caller's overrides applied, the one way both renderers merge them. */
@@ -1,4 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type MenuEntry } from '../Menu/index.js';
2
3
  /** One slide as the filmstrip lists it. */
3
4
  export interface FilmstripSlide {
4
5
  id: string;
@@ -14,6 +15,10 @@ export interface SlideFilmstripLabels {
14
15
  slide: (position: number, title: string) => string;
15
16
  hidden: string;
16
17
  untitled: string;
18
+ /** A slide's actions menu: "Actions for slide 4, The plan". */
19
+ actions: (position: number, title: string) => string;
20
+ duplicate: string;
21
+ delete: string;
17
22
  }
18
23
  /**
19
24
  * Which way the strip runs: a column beside the stage, or a row under it
@@ -33,6 +38,23 @@ export interface SlideFilmstripProps {
33
38
  */
34
39
  onReorder?: ((ids: string[]) => void) | undefined;
35
40
  orientation?: SlideFilmstripOrientation | undefined;
41
+ /**
42
+ * Copy a slide in place, after itself: Command+D (Control+D elsewhere) on
43
+ * its thumbnail, or its actions menu. Left out, nothing duplicates.
44
+ */
45
+ onDuplicate?: ((id: string) => void) | undefined;
46
+ /**
47
+ * Remove a slide: Delete or Backspace on its thumbnail, or its actions
48
+ * menu. Left out, nothing deletes. The caller moves the selection.
49
+ */
50
+ onDelete?: ((id: string) => void) | undefined;
51
+ /** Further entries of a slide's actions menu, after Duplicate and Delete. */
52
+ actions?: ((id: string) => readonly MenuEntry[]) | undefined;
53
+ /**
54
+ * What follows the last slide inside the strip, such as a New slide
55
+ * control, so it scrolls with the slides it adds to.
56
+ */
57
+ footer?: ReactNode;
36
58
  className?: string | undefined;
37
59
  labels?: Partial<SlideFilmstripLabels> | undefined;
38
60
  }
@@ -57,5 +79,12 @@ export interface SlideFilmstripProps {
57
79
  *
58
80
  * THUMBNAILS ARE THE SLIDES THEMSELVES, drawn by the caller at the slide's own
59
81
  * size and scaled by `SlideStage`, so what the strip shows is what presents.
82
+ *
83
+ * A SLIDE'S ACTIONS ARE KEYS ON ITS THUMBNAIL AND A MENU BESIDE IT, as a
84
+ * presentation editor's filmstrip has them: Command+D (Control+D) duplicates,
85
+ * Delete or Backspace deletes, and the menu names both with their keys, so the
86
+ * pointer and the keyboard reach the same acts and the menu teaches the keys.
87
+ * The menu's trigger is out of the tab order, since the thumbnail's keys reach
88
+ * every act it holds and the Menu key (or Shift+F10) opens it from there.
60
89
  */
61
- export declare function SlideFilmstrip({ slides, selected, onSelect, renderSlide, onReorder, orientation, className, labels, }: SlideFilmstripProps): import("react").JSX.Element;
90
+ export declare function SlideFilmstrip({ slides, selected, onSelect, renderSlide, onReorder, orientation, onDuplicate, onDelete, actions, footer, className, labels, }: SlideFilmstripProps): import("react").JSX.Element;
@@ -1,8 +1,12 @@
1
- export { SlideFilmstrip } from '../chunk-XV32RKQZ.js';
1
+ export { SlideFilmstrip } from '../chunk-QIXMNOBD.js';
2
2
  import '../chunk-LV4APO72.js';
3
3
  import '../chunk-XJ2QEBMM.js';
4
+ import '../chunk-SMBKXWML.js';
5
+ import '../chunk-BUVCV3WI.js';
4
6
  import '../chunk-OMV5W53A.js';
5
7
  import '../chunk-R25RGPUB.js';
8
+ import '../chunk-OG6CL3EB.js';
6
9
  import '../chunk-RSAQOKH3.js';
10
+ import '../chunk-4FQT6ZAY.js';
7
11
  import '../chunk-BZFWDIV6.js';
8
12
  import '../chunk-ODEQTPFM.js';
@@ -167,3 +167,52 @@
167
167
  .crewlet-slide-filmstrip--horizontal .crewlet-slide-filmstrip__item[data-reorder-target='after'] .crewlet-slide-filmstrip__thumb {
168
168
  box-shadow: var(--spacing-1) 0 0 var(--color-brand-accent);
169
169
  }
170
+
171
+ /* A SLIDE'S CONTROLS, beside its thumbnail: the handle over the actions menu,
172
+ one column, so a thumbnail keeps the strip's full width beside them. The
173
+ menu's trigger shows on the selected slide and under the pointer or focus,
174
+ so a strip of twelve slides is not twelve rows of ellipses. */
175
+ .crewlet-slide-filmstrip__controls {
176
+ display: flex;
177
+ flex-direction: column;
178
+ align-items: center;
179
+ gap: var(--spacing-0);
180
+ }
181
+
182
+ .crewlet-slide-filmstrip__controls .crewlet-menu-anchor {
183
+ opacity: 0;
184
+ }
185
+
186
+ .crewlet-slide-filmstrip__item[data-selected='true'] .crewlet-menu-anchor,
187
+ .crewlet-slide-filmstrip__item:hover .crewlet-menu-anchor,
188
+ .crewlet-slide-filmstrip__controls .crewlet-menu-anchor:focus-within,
189
+ .crewlet-slide-filmstrip__controls .crewlet-menu-anchor:has([aria-expanded='true']) {
190
+ opacity: 1;
191
+ }
192
+
193
+ @media (hover: none) {
194
+ .crewlet-slide-filmstrip__controls .crewlet-menu-anchor {
195
+ opacity: 1;
196
+ }
197
+ }
198
+
199
+ /* What follows the slides (a New slide control), aligned with the thumbnails
200
+ rather than with the numbers beside them. */
201
+ .crewlet-slide-filmstrip__footer {
202
+ padding: var(--spacing-1) var(--spacing-1) var(--spacing-2) calc(var(--spacing-5) + var(--spacing-2));
203
+ }
204
+
205
+ .crewlet-slide-filmstrip--horizontal {
206
+ display: flex;
207
+ align-items: flex-start;
208
+ }
209
+
210
+ .crewlet-slide-filmstrip--horizontal .crewlet-slide-filmstrip__controls {
211
+ grid-area: handle;
212
+ flex-direction: row;
213
+ }
214
+
215
+ .crewlet-slide-filmstrip--horizontal .crewlet-slide-filmstrip__footer {
216
+ flex: none;
217
+ padding: var(--spacing-1) var(--spacing-2);
218
+ }
@@ -0,0 +1,62 @@
1
+ import { type TextareaHTMLAttributes } from "react";
2
+ /** How a marked line reads: a refusal, or advice. */
3
+ export type SourceMarkTone = "danger" | "warning";
4
+ /** One line called out in the source, as a checker found it. */
5
+ export interface SourceMark {
6
+ /** The line, counted from 1. A line past the end is ignored. */
7
+ line: number;
8
+ tone: SourceMarkTone;
9
+ /** What is wrong on the line, shown as the gutter number's tooltip. */
10
+ message?: string;
11
+ }
12
+ export interface SourceEditorProps extends Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, "value" | "onChange" | "onSubmit" | "children" | "wrap" | "spellCheck"> {
13
+ value: string;
14
+ onChange: (value: string) => void;
15
+ /** Names the field for a screen reader when no visible label points at it. */
16
+ label?: string;
17
+ /** Lines to call out in the gutter and behind the text. */
18
+ marks?: readonly SourceMark[];
19
+ /** Called on Command+Enter (Control+Enter elsewhere). */
20
+ onSubmit?: (() => void) | undefined;
21
+ /** Spaces one Tab indents by. */
22
+ indent?: number;
23
+ /** Fill the parent's height rather than size to `rows`. */
24
+ fill?: boolean;
25
+ className?: string | undefined;
26
+ /** The field's own class, for a consumer that sets its height. */
27
+ fieldClassName?: string | undefined;
28
+ }
29
+ /** What a parent can ask of the editor. */
30
+ export interface SourceEditorHandle {
31
+ /** Focus the field with the caret at the start of `line` (from 1), scrolled into view. */
32
+ revealLine: (line: number) => void;
33
+ focus: () => void;
34
+ /** The field itself. */
35
+ readonly element: HTMLTextAreaElement | null;
36
+ }
37
+ /** The keyboard instructions every editor carries for a screen reader. */
38
+ export declare const SOURCE_EDITOR_KEYS = "Tab indents and Shift+Tab outdents. Press Escape, then Tab, to move to the next control.";
39
+ /** The offset of the start of `line` (from 1) in `text`, clamped to the text. */
40
+ export declare function lineStart(text: string, line: number): number;
41
+ /**
42
+ * Source text written in place: a monospaced field with a line gutter, and
43
+ * lines a checker called out marked in the gutter and behind the text.
44
+ *
45
+ * A REAL TEXTAREA, so everything a browser gives a field (selection, undo,
46
+ * spelling off, a screen reader's editing commands, autofill off) is there
47
+ * without being rebuilt. The gutter and the marks are drawn behind and beside
48
+ * it and scroll with it; they are hidden from assistive technology, which
49
+ * reads the findings where the consumer lists them.
50
+ *
51
+ * LINES NEVER WRAP, so a line number and a mark always sit on the line they
52
+ * name: a long line scrolls sideways.
53
+ *
54
+ * TAB INDENTS, AND ESCAPE GIVES TAB BACK. Tab and Shift+Tab indent and outdent
55
+ * the lines under the selection, as every code editor does. A keyboard user
56
+ * leaves by pressing Escape first: the next Tab then moves focus as usual. The
57
+ * instructions are the field's description.
58
+ *
59
+ * ENTER KEEPS THE INDENT of the line it breaks, and Command+Enter (Control+Enter)
60
+ * calls `onSubmit`.
61
+ */
62
+ export declare const SourceEditor: import("react").ForwardRefExoticComponent<SourceEditorProps & import("react").RefAttributes<SourceEditorHandle>>;
@@ -0,0 +1,3 @@
1
+ import "./SourceEditor.css";
2
+ export { SOURCE_EDITOR_KEYS, SourceEditor, lineStart } from "./SourceEditor.js";
3
+ export type { SourceEditorHandle, SourceEditorProps, SourceMark, SourceMarkTone, } from "./SourceEditor.js";
@@ -0,0 +1,3 @@
1
+ export { SOURCE_EDITOR_KEYS, SourceEditor, lineStart } from '../chunk-PI7HKLIT.js';
2
+ import '../chunk-BZFWDIV6.js';
3
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,160 @@
1
+ /*
2
+ * Source text written in place: a gutter of line numbers beside a real
3
+ * textarea, and the marks a checker placed drawn behind the text. The gutter,
4
+ * the marks and the field share one font, one line height and one top inset,
5
+ * so a number and a mark always sit on the line they name; the layers follow
6
+ * the field's scroll by a transform.
7
+ *
8
+ * The BOX takes the focus ring, as the Composer's does.
9
+ */
10
+ .crewlet-source-editor {
11
+ --crewlet-source-inset: var(--spacing-2);
12
+
13
+ position: relative;
14
+ display: grid;
15
+ grid-template-columns: auto minmax(0, 1fr);
16
+ min-width: 0;
17
+ overflow: hidden;
18
+ border: 1px solid var(--color-border-strong);
19
+ border-radius: var(--radius-md);
20
+ background: var(--color-surface-background);
21
+ font-family: var(--font-family-mono);
22
+ font-size: var(--font-size-xs);
23
+ line-height: var(--font-line-height-normal);
24
+ transition:
25
+ border-color var(--motion-duration-fast) var(--motion-easing-default),
26
+ box-shadow var(--motion-duration-fast) var(--motion-easing-default);
27
+ }
28
+
29
+ .crewlet-source-editor:hover {
30
+ border-color: var(--color-border-strong-hover);
31
+ }
32
+
33
+ .crewlet-source-editor:focus-within {
34
+ border-color: var(--color-brand-accent);
35
+ box-shadow: 0 0 0 2px var(--color-brand-accent-soft);
36
+ }
37
+
38
+ .crewlet-source-editor.is-fill {
39
+ height: 100%;
40
+ }
41
+
42
+ .crewlet-source-editor__gutter {
43
+ position: relative;
44
+ overflow: hidden;
45
+ border-right: 1px solid var(--color-border-default);
46
+ background: var(--color-surface-subtle);
47
+ user-select: none;
48
+ }
49
+
50
+ .crewlet-source-editor__numbers {
51
+ display: grid;
52
+ padding: var(--crewlet-source-inset) 0;
53
+ will-change: transform;
54
+ }
55
+
56
+ .crewlet-source-editor__number {
57
+ /* Wide enough for the longest number, so the text never shifts as lines are added. */
58
+ min-width: calc(var(--crewlet-source-digits, 2) * 1ch + var(--spacing-2) * 2);
59
+ padding: 0 var(--spacing-2);
60
+ text-align: right;
61
+ font-variant-numeric: tabular-nums;
62
+ color: var(--color-text-tertiary);
63
+ }
64
+
65
+ .crewlet-source-editor__number.is-danger {
66
+ color: var(--color-feedback-danger-ink);
67
+ font-weight: var(--font-weight-semibold);
68
+ box-shadow: inset 2px 0 0 var(--color-feedback-danger-ink);
69
+ }
70
+
71
+ .crewlet-source-editor__number.is-warning {
72
+ color: var(--color-feedback-warning-ink);
73
+ font-weight: var(--font-weight-semibold);
74
+ box-shadow: inset 2px 0 0 var(--color-feedback-warning-ink);
75
+ }
76
+
77
+ .crewlet-source-editor__body {
78
+ position: relative;
79
+ display: grid;
80
+ min-width: 0;
81
+ }
82
+
83
+ .crewlet-source-editor__marks {
84
+ position: absolute;
85
+ inset: 0;
86
+ overflow: hidden;
87
+ pointer-events: none;
88
+ }
89
+
90
+ .crewlet-source-editor__marks > div {
91
+ position: relative;
92
+ will-change: transform;
93
+ }
94
+
95
+ .crewlet-source-editor__mark {
96
+ position: absolute;
97
+ top: calc(var(--crewlet-source-inset) + var(--crewlet-source-line) * 1lh);
98
+ left: 0;
99
+ right: 0;
100
+ height: 1lh;
101
+ }
102
+
103
+ .crewlet-source-editor__mark.is-danger {
104
+ background: var(--color-feedback-danger-soft);
105
+ }
106
+
107
+ .crewlet-source-editor__mark.is-warning {
108
+ background: var(--color-feedback-warning-soft);
109
+ }
110
+
111
+ .crewlet-source-editor .crewlet-source-editor__field {
112
+ position: relative;
113
+ display: block;
114
+ width: 100%;
115
+ min-height: 0;
116
+ margin: 0;
117
+ padding: var(--crewlet-source-inset) var(--spacing-3);
118
+ border: 0;
119
+ border-radius: 0;
120
+ background: transparent;
121
+ color: var(--color-text-primary);
122
+ font: inherit;
123
+ white-space: pre;
124
+ overflow: auto;
125
+ resize: none;
126
+ tab-size: 2;
127
+ caret-color: var(--color-brand-accent);
128
+ }
129
+
130
+ .crewlet-source-editor.is-fill .crewlet-source-editor__field {
131
+ height: 100%;
132
+ }
133
+
134
+ .crewlet-source-editor .crewlet-source-editor__field::placeholder {
135
+ color: var(--color-text-tertiary);
136
+ }
137
+
138
+ /* The ring is the box's, above. A transparent outline stays, because forced
139
+ colors drops the box's shadow and paints an outline in its place. */
140
+ .crewlet-source-editor .crewlet-source-editor__field:focus-visible {
141
+ outline: 2px solid transparent;
142
+ outline-offset: -2px;
143
+ }
144
+
145
+ .crewlet-source-editor .crewlet-source-editor__field[readonly] {
146
+ color: var(--color-text-secondary);
147
+ }
148
+
149
+ @media (forced-colors: active) {
150
+ .crewlet-source-editor__mark {
151
+ background: Highlight;
152
+ opacity: 0.25;
153
+ }
154
+ }
155
+
156
+ @media (prefers-reduced-motion: reduce) {
157
+ .crewlet-source-editor {
158
+ transition: none;
159
+ }
160
+ }
@@ -1,4 +1,4 @@
1
- import { type HTMLAttributes } from 'react';
1
+ import { type HTMLAttributes, type ReactNode } from 'react';
2
2
  import { type ThemeId } from '@crewlethq/tokens';
3
3
  import { type ThemeSwatchPair } from '../ThemeSwatch/index.js';
4
4
  /** A theme as the gallery offers it: the fields of a `themeRegistry` entry it reads. */
@@ -9,7 +9,8 @@ export interface ThemeGalleryTheme<T extends string = string> {
9
9
  tag: string;
10
10
  /** The id of the group it is listed under. */
11
11
  group: string;
12
- swatch: ThemeSwatchPair;
12
+ /** Its two palettes, drawn as the card's thumbnail unless `renderPreview` draws one. */
13
+ swatch?: ThemeSwatchPair | undefined;
13
14
  }
14
15
  /** A heading the themes are listed under, as `themeGroups` carries it. */
15
16
  export interface ThemeGalleryGroup {
@@ -38,6 +39,12 @@ export interface ThemeGalleryProps<T extends string = ThemeId> extends Omit<HTML
38
39
  columns?: number | undefined;
39
40
  /** Nothing can be chosen, and the gallery says so. */
40
41
  disabled?: boolean | undefined;
42
+ /**
43
+ * Draws a card's thumbnail in place of its swatch: a theme of something
44
+ * other than the product's chrome, such as a slide deck's, shown as what it
45
+ * themes. Decoration, as the swatch is: the card is named by its theme.
46
+ */
47
+ renderPreview?: ((theme: ThemeGalleryTheme<T>) => ReactNode) | undefined;
41
48
  }
42
49
  /**
43
50
  * The choice of a theme: every theme, each drawn as its two palettes, listed
@@ -62,4 +69,4 @@ export interface ThemeGalleryProps<T extends string = ThemeId> extends Omit<HTML
62
69
  * and described by its group's heading; the drawing is decoration, because
63
70
  * the name is printed under it.
64
71
  */
65
- export declare function ThemeGallery<T extends string = ThemeId>({ label, value, onValueChange, onPreview, themes, groups, columns, disabled, className, style, ...rest }: ThemeGalleryProps<T>): import("react").JSX.Element;
72
+ export declare function ThemeGallery<T extends string = ThemeId>({ label, value, onValueChange, onPreview, themes, groups, columns, disabled, renderPreview, className, style, ...rest }: ThemeGalleryProps<T>): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- export { ThemeGallery } from '../chunk-C2FRTWKO.js';
1
+ export { ThemeGallery } from '../chunk-W3UVOZKL.js';
2
2
  import '../chunk-MNFU2RNT.js';
3
3
  import '../chunk-F73MC7EZ.js';
4
4
  import '../chunk-RKKO7QHH.js';
@@ -91,3 +91,12 @@
91
91
  border-width: 2px;
92
92
  }
93
93
  }
94
+
95
+ /* A THUMBNAIL THE CALLER DRAWS (`renderPreview`) fills the card's width, as
96
+ the swatch does, and is clipped to the card's inner corner. */
97
+ .crewlet-theme-gallery__preview {
98
+ display: block;
99
+ overflow: hidden;
100
+ border-radius: var(--radius-sm);
101
+ pointer-events: none;
102
+ }
@@ -3,7 +3,7 @@ import { Modal } from './chunk-XEGZHHRH.js';
3
3
  import { Checkbox } from './chunk-CPEPST4S.js';
4
4
  import { EmptyValue } from './chunk-EUCC37WY.js';
5
5
  import { useCardHeaderSlot } from './chunk-AV2DXAEL.js';
6
- import { Menu } from './chunk-3EB2AV3H.js';
6
+ import { Menu } from './chunk-BUVCV3WI.js';
7
7
  import { Button } from './chunk-OG6CL3EB.js';
8
8
  import { IconButton } from './chunk-4FQT6ZAY.js';
9
9
  import { VisuallyHidden } from './chunk-BZFWDIV6.js';
@@ -1,4 +1,4 @@
1
- import { richEditorLabels } from './chunk-4B6LSFDS.js';
1
+ import { richEditorLabels } from './chunk-CSQTDGTS.js';
2
2
  import { Callout } from './chunk-SZZRIHGT.js';
3
3
  import { Skeleton } from './chunk-TEUQWOWZ.js';
4
4
  import { Button } from './chunk-OG6CL3EB.js';
@@ -9,7 +9,7 @@ import { jsx } from 'react/jsx-runtime';
9
9
  var engine = null;
10
10
  var loading = null;
11
11
  function loadEngine() {
12
- loading ??= import('./Editor-JMRD6AZW.js').then(
12
+ loading ??= import('./Editor-BVQHBF7L.js').then(
13
13
  (module) => {
14
14
  engine = module.Editor;
15
15
  return engine;