@crewlethq/ui 0.34.1 → 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 (113) hide show
  1. package/README.md +51 -0
  2. package/dist/AppShell/index.js +2 -2
  3. package/dist/ArtifactBar/ArtifactBar.d.ts +7 -1
  4. package/dist/ArtifactBar/index.d.ts +1 -0
  5. package/dist/ArtifactBar/index.js +4 -14
  6. package/dist/{ArtifactBar-C462VD4C.css → ArtifactBar-HV5AT4RG.css} +39 -2
  7. package/dist/ArtifactCard/ArtifactCard.d.ts +1 -10
  8. package/dist/ArtifactCard/index.d.ts +5 -2
  9. package/dist/ArtifactCard/index.js +3 -2
  10. package/dist/{ArtifactCard-XHRLAL7C.css → ArtifactCard-OGTMO2KI.css} +15 -16
  11. package/dist/ArtifactCover/index.js +2 -14
  12. package/dist/ArtifactIcon/ArtifactIcon.d.ts +1 -1
  13. package/dist/ArtifactIcon/index.js +2 -15
  14. package/dist/ArtifactKindGlyph/ArtifactKindGlyph.d.ts +10 -0
  15. package/dist/ArtifactKindGlyph/index.d.ts +2 -0
  16. package/dist/ArtifactKindGlyph/index.js +1 -0
  17. package/dist/ArtifactKindIllustration/ArtifactKindIllustration.d.ts +15 -2
  18. package/dist/ArtifactKindIllustration/index.d.ts +1 -0
  19. package/dist/ArtifactKindIllustration/index.js +1 -1
  20. package/dist/{ArtifactKindIllustration-4NG6IE3C.css → ArtifactKindIllustration-5FPRJQ3P.css} +32 -26
  21. package/dist/ArtifactKinds-CVD3FCYO.css +15 -0
  22. package/dist/AvatarPicker/index.js +3 -3
  23. package/dist/CanvasBoard/CanvasBoard.d.ts +30 -12
  24. package/dist/CanvasBoard/index.js +1 -1
  25. package/dist/ChangeMark/index.js +2 -2
  26. package/dist/ChoiceList/ChoiceList.d.ts +7 -1
  27. package/dist/ChoiceList/index.js +1 -1
  28. package/dist/{ChoiceList-2PQJS4DX.css → ChoiceList-RBL7FNQL.css} +39 -0
  29. package/dist/CommentThread/index.js +2 -2
  30. package/dist/DataTable/index.js +2 -2
  31. package/dist/DataView/index.js +5 -5
  32. package/dist/DateTimePicker/index.js +2 -2
  33. package/dist/DocTabsEditor/index.js +2 -2
  34. package/dist/{Editor-UUZ7XKCU.js → Editor-BVQHBF7L.js} +4 -4
  35. package/dist/FileDrop/FileDrop.d.ts +64 -0
  36. package/dist/FileDrop/index.d.ts +3 -0
  37. package/dist/FileDrop/index.js +4 -0
  38. package/dist/FileDrop-WE7BNZGV.css +80 -0
  39. package/dist/FindingList/FindingList.d.ts +35 -0
  40. package/dist/FindingList/index.d.ts +3 -0
  41. package/dist/FindingList/index.js +3 -0
  42. package/dist/FindingList-PMYA2R6Q.css +71 -0
  43. package/dist/HuePicker/HuePicker.d.ts +9 -0
  44. package/dist/HuePicker/index.d.ts +1 -1
  45. package/dist/HuePicker/index.js +1 -1
  46. package/dist/Markdown/index.js +1 -1
  47. package/dist/Menu/Menu.d.ts +6 -1
  48. package/dist/Menu/index.js +1 -1
  49. package/dist/OrgTable/index.js +1 -1
  50. package/dist/RichEditor/index.js +3 -3
  51. package/dist/RichEditorMarkdown/index.js +3 -3
  52. package/dist/SheetColumnEditor/SheetColumnEditor.d.ts +94 -0
  53. package/dist/SheetColumnEditor/index.d.ts +3 -0
  54. package/dist/SheetColumnEditor/index.js +23 -0
  55. package/dist/SheetColumnEditor-BO2HKFRB.css +73 -0
  56. package/dist/SheetGrid/SheetGrid.d.ts +19 -1
  57. package/dist/SheetGrid/index.js +5 -4
  58. package/dist/{SheetGrid-GDPCCZ4V.css → SheetGrid-YRDXTIIZ.css} +48 -0
  59. package/dist/SheetModel/index.js +1 -1
  60. package/dist/SheetModel/labels.d.ts +6 -0
  61. package/dist/SlideFilmstrip/SlideFilmstrip.d.ts +30 -1
  62. package/dist/SlideFilmstrip/index.js +5 -1
  63. package/dist/{SlideFilmstrip-5U6Z55GS.css → SlideFilmstrip-4ITZLMO4.css} +49 -0
  64. package/dist/SourceEditor/SourceEditor.d.ts +62 -0
  65. package/dist/SourceEditor/index.d.ts +3 -0
  66. package/dist/SourceEditor/index.js +3 -0
  67. package/dist/SourceEditor-G2C3STPX.css +160 -0
  68. package/dist/ThemeGallery/ThemeGallery.d.ts +10 -3
  69. package/dist/ThemeGallery/index.js +1 -1
  70. package/dist/{ThemeGallery-NITASULQ.css → ThemeGallery-HSUKBDWY.css} +9 -0
  71. package/dist/TimeWindowPicker/index.js +2 -2
  72. package/dist/{chunk-UXXJDIYE.js → chunk-22CQQDFW.js} +1 -1
  73. package/dist/{chunk-E4NNGC6X.js → chunk-3VD3G3IL.js} +2 -2
  74. package/dist/{chunk-EWAFN2IU.js → chunk-5VCG26CV.js} +281 -234
  75. package/dist/{chunk-XTOVADJU.js → chunk-7UYONN6K.js} +7 -18
  76. package/dist/{chunk-CFAJP777.js → chunk-AXBRWRGV.js} +1 -1
  77. package/dist/{chunk-KK5OYNAF.js → chunk-BAKPMH3S.js} +8 -4
  78. package/dist/{chunk-3EB2AV3H.js → chunk-BUVCV3WI.js} +1 -1
  79. package/dist/chunk-CE2THTQR.js +19 -0
  80. package/dist/{chunk-4B6LSFDS.js → chunk-CSQTDGTS.js} +1 -1
  81. package/dist/{chunk-WPX6A5BV.js → chunk-E35CMI5D.js} +22 -6
  82. package/dist/{chunk-EBCHVFCS.js → chunk-FJJHD73S.js} +2 -2
  83. package/dist/{chunk-SGHIAGPR.js → chunk-HAKTRTRP.js} +1 -1
  84. package/dist/{chunk-PLDUNXAO.js → chunk-ILDNJHRU.js} +1 -1
  85. package/dist/chunk-MAD6WPER.js +342 -0
  86. package/dist/{chunk-IUD5VA2Z.js → chunk-NKZCJRKO.js} +10 -5
  87. package/dist/chunk-NTB5LRRD.js +52 -0
  88. package/dist/{chunk-VI5FWDZW.js → chunk-OOMXLJ3S.js} +4 -1
  89. package/dist/{chunk-UOR7TOAU.js → chunk-OSFA5ROT.js} +86 -1
  90. package/dist/{chunk-T46NR3WP.js → chunk-PGZ2R3ON.js} +1 -1
  91. package/dist/chunk-PI7HKLIT.js +245 -0
  92. package/dist/{chunk-YZFLH463.js → chunk-QEFHYUCY.js} +1 -1
  93. package/dist/{chunk-7Q7WDXHG.js → chunk-QFNWMWWY.js} +3 -3
  94. package/dist/{chunk-C7DKX453.js → chunk-QH6VYJ3X.js} +1 -1
  95. package/dist/{chunk-XV32RKQZ.js → chunk-QIXMNOBD.js} +67 -6
  96. package/dist/{chunk-GPHWCK7M.js → chunk-SUXP4OBT.js} +6 -3
  97. package/dist/{chunk-TRQCHF2F.js → chunk-SWD4QBL6.js} +1 -1
  98. package/dist/chunk-THDGBD6Y.js +154 -0
  99. package/dist/{chunk-C2FRTWKO.js → chunk-W3UVOZKL.js} +3 -2
  100. package/dist/{chunk-UDQW6UK7.js → chunk-W7QBBKUE.js} +34 -7
  101. package/dist/{chunk-QBXZLGK2.js → chunk-ZU3DUXD2.js} +3 -2
  102. package/dist/generated/index.d.ts +5 -0
  103. package/dist/generated/index.js +73 -68
  104. package/dist/index.js +73 -68
  105. package/dist/styles.css +652 -51
  106. package/dist/utils/csv.d.ts +35 -0
  107. package/dist/utils/index.d.ts +2 -1
  108. package/dist/utils/index.js +1 -1
  109. package/package.json +3 -3
  110. package/dist/{chunk-YCARLYI6.js → chunk-3WCNHYXE.js} +0 -0
  111. package/dist/{chunk-IYO2N5ZH.js → chunk-6JVRY5DQ.js} +1 -1
  112. package/dist/{chunk-BY4N65PM.js → chunk-73A7D5CE.js} +1 -1
  113. package/dist/{chunk-AORVEG5V.js → chunk-F2KY4RLI.js} +1 -1
@@ -0,0 +1,94 @@
1
+ /**
2
+ * A sheet column's settings, as a compact panel: its name, its type, the
3
+ * choices a select, multi-select or status column offers (each with its
4
+ * colour, or its category for a status), whether a value is required, and
5
+ * moving or deleting the column. What a SheetGrid header's popover holds
6
+ * (`renderColumnEditor`), and what any schema surface that edits one column
7
+ * at a time draws.
8
+ *
9
+ * LIVE, NOT A FORM TO SUBMIT. Every change is handed to the host at once as
10
+ * the next `SheetColumn`, so the grid beside it redraws as the reader types
11
+ * and picks; Done only closes. A name cleared to nothing is held here and
12
+ * not handed on, since a column with no name is one nobody can find, and the
13
+ * name it had comes back if the reader leaves it empty.
14
+ *
15
+ * A CHOICE'S ID IS MADE ONCE, from its label when it is added, and never
16
+ * changes after, so renaming a choice never rewrites a value that chose it.
17
+ * A host whose store has its own id rule passes `optionId`.
18
+ */
19
+ import { type SheetColumn, type SheetColumnType, type SheetStatusCategory } from '../SheetModel/index.js';
20
+ /** The glyph each column type is drawn with, in a type menu and beside a column's name. */
21
+ export declare function SheetColumnTypeGlyph({ type, size }: {
22
+ type: SheetColumnType;
23
+ size?: 'xs' | 'sm' | 'md' | undefined;
24
+ }): import("react").JSX.Element;
25
+ export interface SheetColumnEditorLabels {
26
+ name: string;
27
+ /** Said when the name field is left empty. */
28
+ nameMissing: string;
29
+ type: string;
30
+ /** Each type's name. */
31
+ types: Record<SheetColumnType, string>;
32
+ /** What each type holds, under its name in the type list. */
33
+ typeDetails: Record<SheetColumnType, string>;
34
+ /** The suggestion beside the type: "Looks like dates". */
35
+ suggestion: (type: string) => string;
36
+ /** The button that takes the suggestion: "Use Date". */
37
+ useType: (type: string) => string;
38
+ choices: string;
39
+ addChoice: string;
40
+ choiceName: (index: number) => string;
41
+ choiceColor: (choice: string) => string;
42
+ noColor: string;
43
+ choiceCategory: (choice: string) => string;
44
+ categories: Record<SheetStatusCategory, string>;
45
+ removeChoice: (choice: string) => string;
46
+ noChoices: string;
47
+ duplicateChoice: (choice: string) => string;
48
+ /** The choices a new status column starts with, one per category it names. */
49
+ statusStarters: readonly {
50
+ label: string;
51
+ category: SheetStatusCategory;
52
+ }[];
53
+ required: string;
54
+ requiredDetail: string;
55
+ stars: string;
56
+ moveBefore: string;
57
+ moveAfter: string;
58
+ deleteColumn: string;
59
+ done: string;
60
+ }
61
+ export declare const SHEET_COLUMN_EDITOR_LABELS: SheetColumnEditorLabels;
62
+ export interface SheetColumnEditorProps {
63
+ column: SheetColumn;
64
+ /** Every change, at once, as the next column. */
65
+ onChange: (next: SheetColumn) => void;
66
+ /** Done: the host closes the panel. Enter in the name field does the same. */
67
+ onDone?: (() => void) | undefined;
68
+ /** Shows Delete column. */
69
+ onDelete?: (() => void) | undefined;
70
+ /** Why Delete column cannot be pressed, said on it: the one column a sheet needs, say. */
71
+ deleteDisabledReason?: string | undefined;
72
+ /** Shows Move left and Move right. */
73
+ onMove?: ((step: -1 | 1) => void) | undefined;
74
+ canMoveBefore?: boolean | undefined;
75
+ canMoveAfter?: boolean | undefined;
76
+ /** The types offered, in their order. Every type by default. */
77
+ types?: readonly SheetColumnType[] | undefined;
78
+ /** Why the type cannot change, said under it: the column every row is named by, say. */
79
+ typeLockedReason?: string | undefined;
80
+ /** A type the host proposes from the column's name or its values, offered as one press. */
81
+ suggestedType?: SheetColumnType | undefined;
82
+ /** Why the host refuses the name (another column has it, say). */
83
+ nameError?: string | undefined;
84
+ /** Makes a new choice's id from its label, unique among `taken`. */
85
+ optionId?: ((label: string, taken: readonly string[]) => string) | undefined;
86
+ /**
87
+ * Starts on the name, selected, so typing replaces it: a panel opened on a
88
+ * header, or on a column just added with a placeholder name.
89
+ */
90
+ selectName?: boolean | undefined;
91
+ labels?: Partial<SheetColumnEditorLabels> | undefined;
92
+ className?: string | undefined;
93
+ }
94
+ export declare function SheetColumnEditor({ column, onChange, onDone, onDelete, deleteDisabledReason, onMove, canMoveBefore, canMoveAfter, types, typeLockedReason, suggestedType, nameError, optionId, selectName, labels: overrides, className, }: SheetColumnEditorProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './SheetColumnEditor.css';
2
+ export { SHEET_COLUMN_EDITOR_LABELS, SheetColumnEditor, SheetColumnTypeGlyph } from './SheetColumnEditor.js';
3
+ export type { SheetColumnEditorLabels, SheetColumnEditorProps } from './SheetColumnEditor.js';
@@ -0,0 +1,23 @@
1
+ export { SHEET_COLUMN_EDITOR_LABELS, SheetColumnEditor, SheetColumnTypeGlyph } from '../chunk-MAD6WPER.js';
2
+ import '../chunk-BQ7AKL2N.js';
3
+ import '../chunk-FFMCMSJB.js';
4
+ import '../chunk-F73MC7EZ.js';
5
+ import '../chunk-OOMXLJ3S.js';
6
+ import '../chunk-Z7JYG5TF.js';
7
+ import '../chunk-SUXP4OBT.js';
8
+ import '../chunk-AYKXMIOR.js';
9
+ import '../chunk-CPEPST4S.js';
10
+ import '../chunk-6QFAK2WV.js';
11
+ import '../chunk-SMBKXWML.js';
12
+ import '../chunk-CCAXYHQS.js';
13
+ import '../chunk-VL6CUNSX.js';
14
+ import '../chunk-RKKO7QHH.js';
15
+ import '../chunk-BHHIIK3M.js';
16
+ import '../chunk-PQADV6P6.js';
17
+ import '../chunk-BUVCV3WI.js';
18
+ import '../chunk-OMV5W53A.js';
19
+ import '../chunk-R25RGPUB.js';
20
+ import '../chunk-OG6CL3EB.js';
21
+ import '../chunk-4FQT6ZAY.js';
22
+ import '../chunk-BZFWDIV6.js';
23
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,73 @@
1
+ /*
2
+ * A sheet column's settings (SheetColumnEditor.tsx): a column of fields at
3
+ * the compact step, the choices as rows of a swatch, a name and a remove
4
+ * control, and a foot with the column's own actions at the start and Done at
5
+ * the end. It sits in a popover, so it sets no surface of its own.
6
+ */
7
+
8
+ .crewlet-sheet-column-editor {
9
+ display: flex;
10
+ flex-direction: column;
11
+ gap: var(--spacing-3);
12
+ width: 100%;
13
+ min-width: 0;
14
+ }
15
+
16
+ /* The suggestion: a quiet line naming the type, and the press that takes it. */
17
+ .crewlet-sheet-column-editor__suggestion {
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: space-between;
21
+ gap: var(--spacing-2);
22
+ margin-top: calc(var(--spacing-2) * -1);
23
+ color: var(--color-text-secondary);
24
+ font-size: var(--font-size-xs);
25
+ }
26
+
27
+ .crewlet-sheet-column-editor__suggestion-text {
28
+ display: inline-flex;
29
+ align-items: center;
30
+ gap: var(--spacing-1);
31
+ min-width: 0;
32
+ }
33
+
34
+ .crewlet-sheet-column-editor__choices {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: var(--spacing-1);
38
+ margin: 0 0 var(--spacing-1);
39
+ padding: 0;
40
+ list-style: none;
41
+ }
42
+
43
+ .crewlet-sheet-column-editor__choices:empty {
44
+ display: none;
45
+ }
46
+
47
+ .crewlet-sheet-column-editor__choice {
48
+ display: flex;
49
+ align-items: center;
50
+ gap: var(--spacing-1);
51
+ min-width: 0;
52
+ }
53
+
54
+ .crewlet-sheet-column-editor__choice > .crewlet-input {
55
+ flex: 1 1 auto;
56
+ min-width: 0;
57
+ }
58
+
59
+ /* The foot: a hairline above it, the column's own actions, then Done. */
60
+ .crewlet-sheet-column-editor__foot {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: space-between;
64
+ gap: var(--spacing-2);
65
+ padding-top: var(--spacing-3);
66
+ border-top: 1px solid var(--color-border-default);
67
+ }
68
+
69
+ .crewlet-sheet-column-editor__foot-start {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: var(--spacing-1);
73
+ }
@@ -28,6 +28,7 @@
28
28
  * row's `aria-rowindex` tell assistive technology how many there are and
29
29
  * where it is.
30
30
  */
31
+ import { type ReactNode } from 'react';
31
32
  import { type PresenceLabels } from '../PresenceModel/index.js';
32
33
  import { type SheetCellPresence, type SheetColumn, type SheetEdit, type SheetLabels, type SheetPerson, type SheetRow, type SheetSort, type SheetSyncState } from '../SheetModel/index.js';
33
34
  /** `edit` takes edits; `read` draws the same grid with every cell read only. */
@@ -95,10 +96,27 @@ export interface SheetGridProps {
95
96
  * (`sync.refused`), so the reader clears them once they have read why.
96
97
  */
97
98
  onDismissRefused?: (() => void) | undefined;
99
+ /**
100
+ * Makes each column header open the host's column settings in a popover
101
+ * anchored to it: a click, Enter or Space on a header opens it, and Escape
102
+ * closes it and returns to the header. The grid owns the popover and its
103
+ * placement; the host draws what is inside and changes its own `columns`.
104
+ * A header that opens settings does not sort on a click: a host that offers
105
+ * both puts its sort in the settings, as a spreadsheet's column menu does.
106
+ */
107
+ renderColumnEditor?: ((column: SheetColumn, close: () => void) => ReactNode) | undefined;
108
+ /**
109
+ * The field whose settings are open, for a host that opens them itself (a
110
+ * column it has just added, say). Leave it out and the grid keeps its own.
111
+ */
112
+ settingsColumn?: string | null | undefined;
113
+ onSettingsColumnChange?: ((field: string | null) => void) | undefined;
114
+ /** Shows the Add column control after the last header. The host appends the column. */
115
+ onAddColumn?: (() => void) | undefined;
98
116
  /** A BCP 47 tag for numbers and dates; the reader's own locale when absent. */
99
117
  locale?: string | undefined;
100
118
  className?: string | undefined;
101
119
  labels?: Partial<SheetLabels> | undefined;
102
120
  presenceLabels?: Partial<PresenceLabels> | undefined;
103
121
  }
104
- export declare function SheetGrid({ label, columns: declared, rows: given, people, mode, onEdit, onAddRow, onShowHistory, onActiveCellChange, onEditingChange, onUndo, onRedo, onOpenLink, presence, sort, onSortChange, sync, onRetry, height, fit, onDeleteRow, onDismissRefused, locale, className, labels: labelOverrides, presenceLabels: presenceOverrides, }: SheetGridProps): import("react").JSX.Element;
122
+ export declare function SheetGrid({ label, columns: declared, rows: given, people, mode, onEdit, onAddRow, onShowHistory, onActiveCellChange, onEditingChange, onUndo, onRedo, onOpenLink, presence, sort, onSortChange, sync, onRetry, height, fit, onDeleteRow, onDismissRefused, renderColumnEditor, settingsColumn, onSettingsColumnChange, onAddColumn, locale, className, labels: labelOverrides, presenceLabels: presenceOverrides, }: SheetGridProps): import("react").JSX.Element;
@@ -1,18 +1,19 @@
1
- export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-EWAFN2IU.js';
1
+ export { CellDisplay, CellEditor, CheckboxCell, DateCell, LongTextCell, MultiSelectCell, NumberCell, PersonCell, RatingCell, SelectCell, SheetCell, SheetGrid, StatusCell, TextCell, UrlCell } from '../chunk-5VCG26CV.js';
2
2
  import '../chunk-O2EGEONV.js';
3
3
  import '../chunk-CENOOTAV.js';
4
4
  import '../chunk-GFV4LJHH.js';
5
5
  import '../chunk-WIATRXEJ.js';
6
6
  import '../chunk-3BYIWOTV.js';
7
7
  import '../chunk-I6POAB4V.js';
8
- import '../chunk-SGHIAGPR.js';
9
- import '../chunk-VI5FWDZW.js';
8
+ import '../chunk-HAKTRTRP.js';
9
+ import '../chunk-OOMXLJ3S.js';
10
10
  import '../chunk-Z7JYG5TF.js';
11
+ import '../chunk-K3IJQNB7.js';
11
12
  import '../chunk-AYKXMIOR.js';
12
13
  import '../chunk-6ZJ3N7QI.js';
13
14
  import '../chunk-5AQBPHZD.js';
14
15
  import '../chunk-PZKHBB7D.js';
15
- import '../chunk-3EB2AV3H.js';
16
+ import '../chunk-BUVCV3WI.js';
16
17
  import '../chunk-OMV5W53A.js';
17
18
  import '../chunk-R25RGPUB.js';
18
19
  import '../chunk-OG6CL3EB.js';
@@ -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';