@crewlethq/ui 0.48.3 → 0.49.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 (144) hide show
  1. package/README.md +56 -0
  2. package/dist/AgentHandoffPanel/index.js +3 -3
  3. package/dist/ArrangeList/index.js +2 -2
  4. package/dist/ArtifactBar/index.js +4 -4
  5. package/dist/{ArtifactBar-6PGWGKN2.css → ArtifactBar-UMZCTARR.css} +9 -0
  6. package/dist/ArtifactCard/ArtifactCard.d.ts +30 -1
  7. package/dist/ArtifactCard/index.js +10 -3
  8. package/dist/{ArtifactCard-OGTMO2KI.css → ArtifactCard-SOB63NV5.css} +72 -1
  9. package/dist/ArtifactCover/index.js +2 -2
  10. package/dist/ArtifactIcon/index.js +2 -2
  11. package/dist/ArtifactKindGlyph/ArtifactKindGlyph.d.ts +7 -3
  12. package/dist/ArtifactKindGlyph/index.js +1 -1
  13. package/dist/ArtifactKindIllustration/ArtifactKindIllustration.d.ts +4 -3
  14. package/dist/ArtifactKindIllustration/index.js +1 -1
  15. package/dist/{ArtifactKinds-CVD3FCYO.css → ArtifactKinds-O3CALPVX.css} +1 -0
  16. package/dist/ArtifactMakeRow/index.js +2 -2
  17. package/dist/ArtifactNameCell/ArtifactNameCell.d.ts +14 -1
  18. package/dist/ArtifactNameCell/index.d.ts +1 -1
  19. package/dist/ArtifactNameCell/index.js +2 -2
  20. package/dist/{ArtifactNameCell-RTVP4LO4.css → ArtifactNameCell-3AHLUSE5.css} +12 -0
  21. package/dist/BrandChip/BrandChip.d.ts +26 -0
  22. package/dist/BrandChip/index.d.ts +3 -0
  23. package/dist/BrandChip/index.js +2 -0
  24. package/dist/BrandChip-SQWBC2WU.css +81 -0
  25. package/dist/BrandSample/BrandSample.d.ts +75 -0
  26. package/dist/BrandSample/index.d.ts +3 -0
  27. package/dist/BrandSample/index.js +5 -0
  28. package/dist/BrandSample-G5V7GKR2.css +185 -0
  29. package/dist/BrandScope/BrandScope.d.ts +61 -0
  30. package/dist/BrandScope/index.d.ts +4 -0
  31. package/dist/BrandScope/index.js +4 -0
  32. package/dist/BrandScope-H2KZHGT7.css +29 -0
  33. package/dist/Checkbox/Checkbox.d.ts +8 -0
  34. package/dist/Checkbox/index.js +1 -1
  35. package/dist/{Checkbox-ALWG3WV2.css → Checkbox-MB22OW6P.css} +18 -0
  36. package/dist/ColorField/ColorField.d.ts +63 -0
  37. package/dist/ColorField/index.d.ts +3 -0
  38. package/dist/ColorField/index.js +11 -0
  39. package/dist/ColorField-2OIOWT3Z.css +68 -0
  40. package/dist/ColorSwatch/ColorSwatch.d.ts +43 -0
  41. package/dist/ColorSwatch/index.d.ts +3 -0
  42. package/dist/ColorSwatch/index.js +9 -0
  43. package/dist/ColorSwatch-DNMUFHNS.css +83 -0
  44. package/dist/Combobox/Combobox.d.ts +45 -4
  45. package/dist/Combobox/index.d.ts +1 -1
  46. package/dist/Combobox/index.js +1 -1
  47. package/dist/Combobox-GBCWXWEB.css +163 -0
  48. package/dist/CommandPalette/index.js +3 -3
  49. package/dist/CommentThread/index.js +3 -3
  50. package/dist/Composer/index.js +2 -2
  51. package/dist/ContrastBadge/ContrastBadge.d.ts +63 -0
  52. package/dist/ContrastBadge/index.d.ts +3 -0
  53. package/dist/ContrastBadge/index.js +6 -0
  54. package/dist/ContrastBadge-CBZPGG3G.css +47 -0
  55. package/dist/DataGrid/DataGrid.d.ts +28 -1
  56. package/dist/DataGrid/index.js +8 -1
  57. package/dist/{DataGrid-AQKPJD7W.css → DataGrid-VNGQESJA.css} +15 -0
  58. package/dist/DataTable/index.js +3 -3
  59. package/dist/DataView/index.js +8 -8
  60. package/dist/DateTimePicker/index.js +2 -2
  61. package/dist/FolderTile/FolderTile.d.ts +91 -0
  62. package/dist/FolderTile/index.d.ts +3 -0
  63. package/dist/FolderTile/index.js +7 -0
  64. package/dist/FolderTile-FDT5Y63Z.css +231 -0
  65. package/dist/LinkInterstitial/index.js +2 -2
  66. package/dist/ListInput/index.js +2 -2
  67. package/dist/LogoSlot/LogoSlot.d.ts +84 -0
  68. package/dist/LogoSlot/index.d.ts +3 -0
  69. package/dist/LogoSlot/index.js +9 -0
  70. package/dist/LogoSlot-T2UFOJXU.css +159 -0
  71. package/dist/Modal/Modal.d.ts +13 -0
  72. package/dist/Modal/index.js +1 -1
  73. package/dist/{Modal-TOEWHDCQ.css → Modal-3HMP7WAZ.css} +30 -0
  74. package/dist/PresenterView/index.js +2 -2
  75. package/dist/PrincipalPicker/index.js +2 -2
  76. package/dist/SelectionBar/SelectionBar.d.ts +50 -0
  77. package/dist/SelectionBar/index.d.ts +3 -0
  78. package/dist/SelectionBar/index.js +9 -0
  79. package/dist/SelectionBar-XPWKUOSC.css +61 -0
  80. package/dist/ShareDialog/index.js +3 -3
  81. package/dist/SheetColumnEditor/index.js +3 -3
  82. package/dist/SheetGrid/index.js +2 -2
  83. package/dist/Switcher/index.js +2 -2
  84. package/dist/ThemeGallery/ThemeGallery.d.ts +13 -2
  85. package/dist/ThemeGallery/index.js +3 -1
  86. package/dist/{ThemeGallery-X35Y25EX.css → ThemeGallery-UEFZRT6W.css} +21 -0
  87. package/dist/TimeWindowPicker/index.js +2 -2
  88. package/dist/TypeSpecimen/TypeSpecimen.d.ts +49 -0
  89. package/dist/TypeSpecimen/index.d.ts +3 -0
  90. package/dist/TypeSpecimen/index.js +3 -0
  91. package/dist/TypeSpecimen-WK6YNHL7.css +96 -0
  92. package/dist/chunk-5SGHW42B.js +23 -0
  93. package/dist/{chunk-ILDNJHRU.js → chunk-AVL52EME.js} +1 -1
  94. package/dist/chunk-B235ANDO.js +66 -0
  95. package/dist/{chunk-2MYSESZF.js → chunk-FB5CFQTG.js} +82 -12
  96. package/dist/{chunk-DY4DQ7EB.js → chunk-GP4YWZFO.js} +1 -1
  97. package/dist/{chunk-LIJQT74Y.js → chunk-H55D66IK.js} +1 -1
  98. package/dist/{chunk-6EBGPCAW.js → chunk-H7NMJ5AI.js} +1 -1
  99. package/dist/chunk-ITI2Z44C.js +139 -0
  100. package/dist/{chunk-P5VGSVWG.js → chunk-J24Q4HTD.js} +17 -8
  101. package/dist/{chunk-5EBDOE3C.js → chunk-JFDIMO3A.js} +1 -1
  102. package/dist/chunk-JKAFEFFC.js +44 -0
  103. package/dist/{chunk-32TGEMQQ.js → chunk-KHZYAEGZ.js} +1 -1
  104. package/dist/chunk-M4QM477B.js +80 -0
  105. package/dist/{chunk-TWZEWXNW.js → chunk-MIEBOO7Y.js} +2 -2
  106. package/dist/{chunk-SMOFYZJ5.js → chunk-NAWUXCBC.js} +3 -3
  107. package/dist/{chunk-F57N6ZJG.js → chunk-NCHKKYPQ.js} +5 -2
  108. package/dist/chunk-OCRVY42T.js +50 -0
  109. package/dist/chunk-OEEYL2CM.js +73 -0
  110. package/dist/chunk-P3OIM6OC.js +38 -0
  111. package/dist/{chunk-FWBKMPNR.js → chunk-P3QWT5VR.js} +1 -1
  112. package/dist/chunk-P5JBDHWC.js +206 -0
  113. package/dist/{chunk-OKE5YSLD.js → chunk-Q44X36QC.js} +79 -35
  114. package/dist/{chunk-R2IBCEU6.js → chunk-R3BA3C4Y.js} +2 -2
  115. package/dist/{chunk-CE2THTQR.js → chunk-RSKW25Y5.js} +4 -3
  116. package/dist/{chunk-UBZDYOCA.js → chunk-RV6XB5UV.js} +12 -1
  117. package/dist/{chunk-E4BOVKNJ.js → chunk-UTESMBPL.js} +5 -3
  118. package/dist/chunk-UZMNR366.js +9 -0
  119. package/dist/{chunk-CWKWMIIJ.js → chunk-V7GOOXPK.js} +1 -1
  120. package/dist/{chunk-7JED2NYP.js → chunk-VBIM6HFC.js} +1 -1
  121. package/dist/{chunk-U4HOKU6P.js → chunk-VN47PYUF.js} +5 -5
  122. package/dist/{chunk-MUQJCH2Y.js → chunk-VTSJMDGP.js} +2 -2
  123. package/dist/chunk-W6FOEBIL.js +119 -0
  124. package/dist/chunk-WLSEAIVC.js +48 -0
  125. package/dist/{chunk-AS2BMY3E.js → chunk-WQ7S7CKZ.js} +2 -2
  126. package/dist/{chunk-6AKG2VLR.js → chunk-YCC2S7DF.js} +4 -1
  127. package/dist/chunk-ZH77BXMA.js +14 -0
  128. package/dist/generated/index.d.ts +10 -0
  129. package/dist/generated/index.js +80 -68
  130. package/dist/index.js +80 -68
  131. package/dist/styles.css +1414 -85
  132. package/dist/utils/fontFamily.d.ts +29 -0
  133. package/dist/utils/hexColour.d.ts +12 -0
  134. package/package.json +3 -3
  135. package/scripts/check-css-variables.mjs +18 -2
  136. package/dist/Combobox-YDONYDTM.css +0 -81
  137. package/dist/chunk-OOJTPR7N.js +0 -137
  138. package/dist/{chunk-245IXG5P.js → chunk-3WMOEGEL.js} +0 -0
  139. package/dist/{chunk-ISDEXIXH.js → chunk-E6HXFFWO.js} +1 -1
  140. package/dist/{chunk-6R5BSA36.js → chunk-GHY63X4C.js} +1 -1
  141. package/dist/{chunk-ICVS3U4S.js → chunk-PGR2PKH6.js} +1 -1
  142. package/dist/{chunk-VKFG4FLE.js → chunk-R6R2UHVG.js} +1 -1
  143. package/dist/{chunk-OO7QJCJQ.js → chunk-WXOYHVWG.js} +1 -1
  144. package/dist/{chunk-UFXLNC2N.js → chunk-ZFM5L7M4.js} +1 -1
@@ -0,0 +1,83 @@
1
+ /*
2
+ * One colour of a brand: a chip of it over its role and its value. The chip's
3
+ * fill is the one value that is not a token, and it arrives through
4
+ * `--crewlet-color-swatch-value` only after it has passed `#rrggbb`. Every
5
+ * other colour here is a token.
6
+ */
7
+ .crewlet-color-swatch {
8
+ /* The hatch of no colour, as one value: the same lines an arranged page's
9
+ ground draws, so "nothing here" reads one way across the package. */
10
+ --crewlet-color-swatch-hatch: repeating-linear-gradient(
11
+ -45deg,
12
+ var(--color-border-hatch) 0 1px,
13
+ transparent 1px var(--spacing-2)
14
+ );
15
+
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: var(--spacing-2);
19
+ min-width: 0;
20
+ }
21
+
22
+ /* THE CHIP HAS AN EDGE OF ITS OWN, so a colour that matches the page is
23
+ still a chip rather than a gap. */
24
+ .crewlet-color-swatch__chip {
25
+ display: block;
26
+ width: 100%;
27
+ height: var(--size-row-lg);
28
+ box-sizing: border-box;
29
+ border-radius: var(--radius-md);
30
+ background: var(--crewlet-color-swatch-value, var(--color-surface-inset));
31
+ box-shadow: inset 0 0 0 1px var(--color-border-hover);
32
+ }
33
+
34
+ .crewlet-color-swatch__chip.is-empty {
35
+ background: var(--crewlet-color-swatch-hatch);
36
+ }
37
+
38
+ .crewlet-color-swatch__words {
39
+ display: flex;
40
+ flex-direction: column;
41
+ gap: 2px;
42
+ min-width: 0;
43
+ }
44
+
45
+ .crewlet-color-swatch__name {
46
+ overflow: hidden;
47
+ color: var(--color-text-primary);
48
+ font-size: var(--font-size-sm);
49
+ font-weight: var(--font-weight-medium);
50
+ text-overflow: ellipsis;
51
+ white-space: nowrap;
52
+ }
53
+
54
+ .crewlet-color-swatch__description {
55
+ color: var(--color-text-tertiary);
56
+ font-size: var(--font-size-xs);
57
+ }
58
+
59
+ .crewlet-color-swatch__value--plain {
60
+ color: var(--color-text-secondary);
61
+ font-family: var(--font-family-mono);
62
+ font-size: var(--font-size-xs);
63
+ }
64
+
65
+ .crewlet-color-swatch__empty {
66
+ color: var(--color-text-tertiary);
67
+ font-size: var(--font-size-xs);
68
+ }
69
+
70
+ /* ---- sm: a chip beside the words, for a dense list ---- */
71
+
72
+ .crewlet-color-swatch--sm {
73
+ flex-direction: row;
74
+ align-items: center;
75
+ gap: var(--spacing-2);
76
+ }
77
+
78
+ .crewlet-color-swatch--sm .crewlet-color-swatch__chip {
79
+ flex: none;
80
+ width: var(--size-control-sm);
81
+ height: var(--size-control-sm);
82
+ border-radius: var(--radius-sm);
83
+ }
@@ -20,7 +20,8 @@ export interface ComboboxListRender {
20
20
  /** Mouse wiring for the row at `index`. */
21
21
  optionHandlers: (index: number) => Record<string, unknown>;
22
22
  }
23
- export interface ComboboxProps extends Omit<InputProps, 'value' | 'onChange' | 'role' | 'onKeyDown' | 'list'> {
23
+ /** What every combobox takes, whether its list is a popup or always on screen. */
24
+ export interface ComboboxBaseProps extends Omit<InputProps, 'value' | 'onChange' | 'role' | 'onKeyDown' | 'list'> {
24
25
  /** What the field holds. The caller owns it: a completion is an edit to it. */
25
26
  value: string;
26
27
  onValueChange: (next: string) => void;
@@ -45,9 +46,6 @@ export interface ComboboxProps extends Omit<InputProps, 'value' | 'onChange' | '
45
46
  * `${NAME}` inside a longer value) does it itself.
46
47
  */
47
48
  onCommit?: ((option: ComboboxOption, index: number) => void) | undefined;
48
- /** Whether the list is on screen. Controlled: only the caller knows when it has something to offer. */
49
- open: boolean;
50
- onOpenChange: (open: boolean) => void;
51
49
  /** Names the list. A listbox with no name is announced as "list box" and nothing else. */
52
50
  label: string;
53
51
  /**
@@ -67,6 +65,35 @@ export interface ComboboxProps extends Omit<InputProps, 'value' | 'onChange' | '
67
65
  /** The line shown while the list is open with nothing to offer. Nothing is drawn without one. */
68
66
  emptyMessage?: ReactNode;
69
67
  }
68
+ /** A field that offers completions in a list that opens under it. */
69
+ export interface ComboboxPopupProps extends ComboboxBaseProps {
70
+ inline?: false | undefined;
71
+ /** Whether the list is on screen. Controlled: only the caller knows when it has something to offer. */
72
+ open: boolean;
73
+ onOpenChange: (open: boolean) => void;
74
+ }
75
+ /**
76
+ * A field over a list that is always on screen: a picker whose list IS the
77
+ * surface's body (a folder picker in a dialog), filtered by the field.
78
+ */
79
+ export interface ComboboxInlineProps extends ComboboxBaseProps {
80
+ /**
81
+ * The list is part of the surface rather than a popup: always on screen,
82
+ * in the flow under the field, at a stable height, filtered by what the
83
+ * field holds. See the component's notes.
84
+ */
85
+ inline: true;
86
+ /** How many rows the list shows before it scrolls, and so how tall it stands. Six by default. */
87
+ rows?: number | undefined;
88
+ /**
89
+ * The value of the option chosen so far: drawn chosen, announced as
90
+ * selected, and where the highlight starts.
91
+ */
92
+ chosen?: string | undefined;
93
+ open?: undefined;
94
+ onOpenChange?: undefined;
95
+ }
96
+ export type ComboboxProps = ComboboxPopupProps | ComboboxInlineProps;
70
97
  /**
71
98
  * A text field that offers completions.
72
99
  *
@@ -81,6 +108,20 @@ export interface ComboboxProps extends Omit<InputProps, 'value' | 'onChange' | '
81
108
  * field stays open; a second Escape reaches it. Without that, somebody
82
109
  * dismissing a completion they did not want lost the whole editor with it.
83
110
  *
111
+ * INLINE (`inline`), THE LIST IS THE SURFACE'S BODY. For a picker whose list
112
+ * is the point of the dialog it sits in (Move to…), the list is always on
113
+ * screen, in the flow under the field, filtered by it: no popup, no portal,
114
+ * nothing that opens or closes. A list that closed when the field lost focus
115
+ * made the dialog shrink under the pointer between the press on Cancel and
116
+ * its release, so the click landed on the veil. Its box keeps one height
117
+ * (`rows`) whatever the filter leaves in it, so nothing under it moves as
118
+ * somebody types, and says so in its own row when nothing matches. The keys
119
+ * are the popup's (the arrows step over a disabled row, Enter takes the
120
+ * highlighted one, the letters filter), Home and End reach the first and the
121
+ * last row while the field is empty and are the caret's once it holds text,
122
+ * and Escape is never its own: there is nothing to dismiss, so it reaches the
123
+ * dialog. `chosen` marks the option picked so far as selected.
124
+ *
84
125
  * WHAT IT DOES NOT DECIDE is what matches. The caller filters and hands over
85
126
  * what is offered, because a completion's question belongs to the value: the
86
127
  * engine's secret references complete on the name under the caret, not on the
@@ -1,4 +1,4 @@
1
1
  import '../HitArea/HitArea.css';
2
2
  import './Combobox.css';
3
3
  export { Combobox } from './Combobox.js';
4
- export type { ComboboxListRender, ComboboxOption, ComboboxProps } from './Combobox.js';
4
+ export type { ComboboxBaseProps, ComboboxInlineProps, ComboboxListRender, ComboboxOption, ComboboxPopupProps, ComboboxProps, } from './Combobox.js';
@@ -1,4 +1,4 @@
1
- export { Combobox } from '../chunk-OOJTPR7N.js';
1
+ export { Combobox } from '../chunk-P5JBDHWC.js';
2
2
  import '../chunk-7KHM2FZH.js';
3
3
  import '../chunk-EXRRTKWT.js';
4
4
  import '../chunk-XCUUI7E7.js';
@@ -0,0 +1,163 @@
1
+ /*
2
+ * Combobox: a field that offers completions.
3
+ *
4
+ * The panel is anchored inside the field's own box rather than portalled or
5
+ * laid out in the flow. In the flow it pushed every field under it down the
6
+ * form as somebody typed; portalled, it would have to be placed, followed and
7
+ * given a layer of its own for a list that never leaves its field's side.
8
+ */
9
+
10
+ .crewlet-combobox {
11
+ position: relative;
12
+ width: 100%;
13
+ }
14
+
15
+ .crewlet-combobox__panel {
16
+ /* Six rows and a scroll, as every list this package offers from a field. */
17
+ --crewlet-combobox-panel-max-height: 12rem;
18
+
19
+ position: absolute;
20
+ top: calc(100% + var(--spacing-1));
21
+ left: 0;
22
+ right: 0;
23
+ max-height: var(--crewlet-combobox-panel-max-height);
24
+ overflow-y: auto;
25
+ overscroll-behavior: contain;
26
+ padding: var(--spacing-1);
27
+ --crewlet-listbox-gap: 1px;
28
+ display: flex;
29
+ flex-direction: column;
30
+ gap: var(--crewlet-listbox-gap);
31
+ /*
32
+ * OPAQUE, and the product's own panel surface: a translucent list over a
33
+ * form puts two sets of words in the same place, and the words underneath
34
+ * are a label and a value somebody is in the middle of typing.
35
+ */
36
+ background: var(--color-surface-subtle);
37
+ border: 1px solid var(--color-border-default);
38
+ border-radius: var(--radius-md);
39
+ box-shadow: var(--shadow-md);
40
+ /* Above the fields below it, and nothing more: it never leaves its form. */
41
+ z-index: var(--z-index-dropdown);
42
+ }
43
+
44
+ /* Names read exactly rather than for sense: a secret reference, a path, a key. */
45
+ .crewlet-combobox__panel.is-mono .crewlet-combobox__label {
46
+ font-family: var(--font-family-mono);
47
+ font-size: var(--font-size-compact);
48
+ }
49
+
50
+ .crewlet-combobox__label {
51
+ overflow: hidden;
52
+ text-overflow: ellipsis;
53
+ white-space: nowrap;
54
+ }
55
+
56
+ /*
57
+ * The row the arrows or the pointer are on, in the hover tint. The accent is
58
+ * what "here, this is the current one" means elsewhere in the product; a
59
+ * completion list has no current one, only the row about to be taken.
60
+ *
61
+ * Scoped to the panel rather than written on the row class, because the
62
+ * shared listbox register paints [aria-selected] itself and the stylesheets
63
+ * are bundled in hash order: a rule of equal weight would win or lose by the
64
+ * name of a build artefact.
65
+ */
66
+ .crewlet-combobox__panel .crewlet-listbox__option {
67
+ border-radius: var(--radius-xs);
68
+ }
69
+
70
+ .crewlet-combobox__panel .crewlet-listbox__option[aria-selected='true'],
71
+ .crewlet-combobox__panel .crewlet-listbox__option.is-highlight,
72
+ .crewlet-combobox__panel .crewlet-listbox__option:hover {
73
+ background: var(--color-surface-hover);
74
+ color: var(--color-text-primary);
75
+ }
76
+
77
+ .crewlet-combobox__panel .crewlet-listbox__option.is-disabled {
78
+ background: transparent;
79
+ color: var(--color-text-tertiary);
80
+ cursor: not-allowed;
81
+ }
82
+
83
+ /* ---- inline (`inline`): the list is the surface's body ------------------
84
+ Always on screen, in the flow under the field, at ONE HEIGHT: the box is
85
+ `rows` one-line rows tall (`--crewlet-combobox-rows`, set by the component)
86
+ whatever the filter leaves in it, so nothing under it moves as somebody
87
+ types, and it scrolls past that. It sits on the surface's own ground inside
88
+ a hairline, because it is part of the surface rather than a panel over it. */
89
+ .crewlet-combobox--inline {
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: var(--spacing-2);
93
+ }
94
+
95
+ .crewlet-combobox__list {
96
+ /* ONE ROW IS ONE ROW STEP, exactly: a row's own height is held to it
97
+ below, so a label that draws a glyph beside its words is no taller than
98
+ one that does not, and `rows` rows fill the box to the pixel. */
99
+ --crewlet-combobox-row: var(--size-row-md);
100
+ --crewlet-listbox-gap: 1px;
101
+
102
+ height: calc(
103
+ var(--crewlet-combobox-rows) * var(--crewlet-combobox-row) + (var(--crewlet-combobox-rows) - 1) * var(--crewlet-listbox-gap) +
104
+ var(--spacing-1) * 2 + 2px
105
+ );
106
+ box-sizing: border-box;
107
+ overflow: hidden;
108
+ border: 1px solid var(--color-border-default);
109
+ border-radius: var(--radius-md);
110
+ }
111
+
112
+ .crewlet-combobox__options {
113
+ display: flex;
114
+ flex-direction: column;
115
+ gap: var(--crewlet-listbox-gap);
116
+ height: 100%;
117
+ box-sizing: border-box;
118
+ padding: var(--spacing-1);
119
+ overflow-y: auto;
120
+ overscroll-behavior: contain;
121
+ }
122
+
123
+ .crewlet-combobox__list.is-mono .crewlet-combobox__label {
124
+ font-family: var(--font-family-mono);
125
+ font-size: var(--font-size-compact);
126
+ }
127
+
128
+ .crewlet-combobox__options .crewlet-listbox__option {
129
+ height: var(--crewlet-combobox-row);
130
+ min-height: 0;
131
+ padding-block: 0;
132
+ border-radius: var(--radius-xs);
133
+ }
134
+
135
+ /* The row the arrows or the pointer are on, in the hover tint, as the popup
136
+ draws it. Scoped to the list for the same reason as the panel's. */
137
+ .crewlet-combobox__options .crewlet-listbox__option.is-highlight,
138
+ .crewlet-combobox__options .crewlet-listbox__option:hover {
139
+ background: var(--color-surface-hover);
140
+ color: var(--color-text-primary);
141
+ }
142
+
143
+ /*
144
+ * THE CHOSEN ROW (`chosen`), as every chosen option in the package is drawn:
145
+ * the selected fill, never the accent, with a tick in the accent's ink so the
146
+ * choice never rests on the tint. It keeps its fill under the arrows too.
147
+ */
148
+ .crewlet-combobox__options .crewlet-listbox__option[aria-selected='true'] {
149
+ background: var(--color-surface-selected);
150
+ color: var(--color-text-primary);
151
+ }
152
+
153
+ .crewlet-combobox__check {
154
+ display: inline-flex;
155
+ flex: none;
156
+ color: var(--color-brand-accent-ink);
157
+ }
158
+
159
+ .crewlet-combobox__options .crewlet-listbox__option.is-disabled {
160
+ background: transparent;
161
+ color: var(--color-text-tertiary);
162
+ cursor: not-allowed;
163
+ }
@@ -1,9 +1,9 @@
1
- export { CommandPalette } from '../chunk-TWZEWXNW.js';
2
- import '../chunk-6AKG2VLR.js';
1
+ export { CommandPalette } from '../chunk-MIEBOO7Y.js';
2
+ import '../chunk-YCC2S7DF.js';
3
3
  import '../chunk-7KHM2FZH.js';
4
+ import '../chunk-SMBKXWML.js';
4
5
  import '../chunk-EXRRTKWT.js';
5
6
  import '../chunk-XCUUI7E7.js';
6
- import '../chunk-SMBKXWML.js';
7
7
  import '../chunk-BHHIIK3M.js';
8
8
  import '../chunk-PQADV6P6.js';
9
9
  import '../chunk-RSAQOKH3.js';
@@ -1,14 +1,14 @@
1
- export { COMMENT_THREAD_LABELS, CommentThread } from '../chunk-6EBGPCAW.js';
1
+ export { COMMENT_THREAD_LABELS, CommentThread } from '../chunk-H7NMJ5AI.js';
2
2
  import '../chunk-CI3VPIJN.js';
3
3
  import '../chunk-3CZ7XAVY.js';
4
4
  import '../chunk-EUCC37WY.js';
5
5
  import '../chunk-5AQBPHZD.js';
6
6
  import '../chunk-PZKHBB7D.js';
7
7
  import '../chunk-PWG3VHRQ.js';
8
- import '../chunk-6R5BSA36.js';
8
+ import '../chunk-GHY63X4C.js';
9
+ import '../chunk-SMBKXWML.js';
9
10
  import '../chunk-EXRRTKWT.js';
10
11
  import '../chunk-XCUUI7E7.js';
11
- import '../chunk-SMBKXWML.js';
12
12
  import '../chunk-BHHIIK3M.js';
13
13
  import '../chunk-PQADV6P6.js';
14
14
  import '../chunk-RSAQOKH3.js';
@@ -1,7 +1,7 @@
1
- export { COMPOSER_COUNTER_AT, Composer } from '../chunk-6R5BSA36.js';
1
+ export { COMPOSER_COUNTER_AT, Composer } from '../chunk-GHY63X4C.js';
2
+ import '../chunk-SMBKXWML.js';
2
3
  import '../chunk-EXRRTKWT.js';
3
4
  import '../chunk-XCUUI7E7.js';
4
- import '../chunk-SMBKXWML.js';
5
5
  import '../chunk-PQADV6P6.js';
6
6
  import '../chunk-RSAQOKH3.js';
7
7
  import '../chunk-H5XTJ7GJ.js';
@@ -0,0 +1,63 @@
1
+ /**
2
+ * What a pair is read as. `body` is text at the body's size, held to 4.5:1
3
+ * for AA and 7:1 for AAA. `large` is large text and every graphical mark (a
4
+ * logo, an accent on a ground), held to 3:1 for AA and 4.5:1 for AAA.
5
+ */
6
+ export type ContrastScale = 'body' | 'large';
7
+ /**
8
+ * Where a pair stands: AAA, AA, AA for large text only (body text that clears
9
+ * 3:1 but not 4.5:1), or under every floor its scale has.
10
+ */
11
+ export type ContrastLevel = 'aaa' | 'aa' | 'aa-large' | 'fail';
12
+ /**
13
+ * The level a measured ratio reaches, on the floors `@crewlethq/tokens`
14
+ * exports. The ratio is compared UNROUNDED: a pair that passes only once
15
+ * rounded does not pass.
16
+ */
17
+ export declare function contrastLevel(ratio: number, scale?: ContrastScale): ContrastLevel;
18
+ /**
19
+ * The ratio between two `#rrggbb` colours, or null when either is not one.
20
+ * The one measurement every brand part takes, from `@crewlethq/tokens`.
21
+ */
22
+ export declare function contrastRatio(foreground: string, background: string): number | null;
23
+ /**
24
+ * A ratio as printed, cut DOWN to two places and never rounded up, so the
25
+ * number shown never claims a floor the pair misses: 4.497 is "4.49", not
26
+ * "4.5".
27
+ */
28
+ export declare function formatContrastRatio(ratio: number): string;
29
+ export interface ContrastBadgeLabels {
30
+ levels: Record<ContrastLevel, string>;
31
+ /** Said for a pair that cannot be measured (a colour not set yet). */
32
+ unmeasured: string;
33
+ /** The ratio, said in words: "4.49 to 1". */
34
+ ratio: (ratio: string) => string;
35
+ /** The letters the sample draws the pair with. */
36
+ sample: string;
37
+ }
38
+ export interface ContrastBadgeProps {
39
+ /** The colour read: text, a logo, an accent. `#rrggbb`. */
40
+ foreground: string;
41
+ /** The colour it is read on. `#rrggbb`. */
42
+ background: string;
43
+ /** What the pair is: "Text on light ground". */
44
+ label?: string | undefined;
45
+ /** What it is read as: body text (the default), or large text and marks. */
46
+ scale?: ContrastScale | undefined;
47
+ className?: string | undefined;
48
+ labels?: Partial<ContrastBadgeLabels> | undefined;
49
+ }
50
+ /**
51
+ * Whether one colour reads on another: a sample of the pair, the measured
52
+ * ratio, and the level it reaches.
53
+ *
54
+ * THE MEASUREMENT IS THE TOKENS PACKAGE'S. The ratio comes from
55
+ * `@crewlethq/tokens`' `contrast()`, the same maths the palette suite holds
56
+ * every theme to, and the floors from its `WCAG_CONTRAST`, so the badge an
57
+ * administrator reads and the gate a theme passes never disagree.
58
+ *
59
+ * THE LEVEL IS A WORD AND A GLYPH, never the tint alone, and the ratio is
60
+ * said as "4.49 to 1" rather than read out as punctuation. The sample is
61
+ * decoration: it shows the pair, and the words say how it measures.
62
+ */
63
+ export declare function ContrastBadge({ foreground, background, label, scale, className, labels }: ContrastBadgeProps): import("react").JSX.Element;
@@ -0,0 +1,3 @@
1
+ import './ContrastBadge.css';
2
+ export { ContrastBadge, contrastLevel, contrastRatio, formatContrastRatio } from './ContrastBadge.js';
3
+ export type { ContrastBadgeLabels, ContrastBadgeProps, ContrastLevel, ContrastScale } from './ContrastBadge.js';
@@ -0,0 +1,6 @@
1
+ export { ContrastBadge, contrastLevel, contrastRatio, formatContrastRatio } from '../chunk-B235ANDO.js';
2
+ import '../chunk-KYIAFNU7.js';
3
+ import '../chunk-UZMNR366.js';
4
+ import '../chunk-WIATRXEJ.js';
5
+ import '../chunk-BZFWDIV6.js';
6
+ import '../chunk-ODEQTPFM.js';
@@ -0,0 +1,47 @@
1
+ /*
2
+ * Whether one colour reads on another: a sample of the pair, the ratio and
3
+ * the level. The sample's two colours are the only values here that are not
4
+ * tokens, and they arrive through `--crewlet-contrast-badge-ink` and
5
+ * `--crewlet-contrast-badge-ground` only once both have passed `#rrggbb`.
6
+ */
7
+ .crewlet-contrast-badge {
8
+ display: inline-flex;
9
+ flex-wrap: wrap;
10
+ align-items: center;
11
+ gap: var(--spacing-2);
12
+ min-width: 0;
13
+ font-size: var(--font-size-xs);
14
+ }
15
+
16
+ /* THE SAMPLE HAS AN EDGE OF ITS OWN, so a ground that matches the page is
17
+ still a sample. */
18
+ .crewlet-contrast-badge__sample {
19
+ display: inline-flex;
20
+ flex: none;
21
+ align-items: center;
22
+ justify-content: center;
23
+ width: var(--size-control-sm);
24
+ height: var(--size-control-sm);
25
+ box-sizing: border-box;
26
+ border-radius: var(--radius-sm);
27
+ background: var(--crewlet-contrast-badge-ground, var(--color-surface-inset));
28
+ box-shadow: inset 0 0 0 1px var(--color-border-hover);
29
+ color: var(--crewlet-contrast-badge-ink, var(--color-text-tertiary));
30
+ font-size: var(--font-size-xs);
31
+ font-weight: var(--font-weight-semibold);
32
+ line-height: 1;
33
+ }
34
+
35
+ .crewlet-contrast-badge__label {
36
+ color: var(--color-text-secondary);
37
+ }
38
+
39
+ .crewlet-contrast-badge__ratio {
40
+ color: var(--color-text-primary);
41
+ font-family: var(--font-family-mono);
42
+ font-variant-numeric: tabular-nums;
43
+ }
44
+
45
+ .crewlet-contrast-badge__unmeasured {
46
+ color: var(--color-text-tertiary);
47
+ }
@@ -123,6 +123,20 @@ export interface DataGridBand<T> {
123
123
  /** A per-band aggregate line, or the way to what the band did not fit. */
124
124
  footer?: ReactNode;
125
125
  }
126
+ /**
127
+ * Rows a reader picks for a bulk action, by their `rowKey`: a column of boxes
128
+ * before the first, with a box over them in the head.
129
+ */
130
+ export interface DataGridSelection<T> {
131
+ /** The keys of the rows picked. Controlled, and kept across pages and sorts by the host. */
132
+ selected: ReadonlySet<string>;
133
+ /** The keys as they should be now. */
134
+ onChange: (selected: ReadonlySet<string>) => void;
135
+ /** A row's box, said: "Select Q3 plan". The row's own words are its name, so this says what ticking it does. */
136
+ rowLabel: (row: T) => string;
137
+ /** A row that cannot be picked (the reader may not act on it): its box is drawn and disabled. */
138
+ isSelectable?: ((row: T) => boolean) | undefined;
139
+ }
126
140
  /** The words a grid says, for an application that says them otherwise. */
127
141
  export interface DataGridLabels {
128
142
  /** "Hidden to fit: Due and Updated". */
@@ -131,6 +145,8 @@ export interface DataGridLabels {
131
145
  showEveryColumn: string;
132
146
  /** Joins the last two names of a list: "Due and Updated". */
133
147
  and: string;
148
+ /** The head's box, over every row the grid draws. */
149
+ selectAll: string;
134
150
  }
135
151
  /**
136
152
  * What an application drives a grid's cursor with. The grid binds no keys of
@@ -156,6 +172,17 @@ export interface DataGridProps<T> {
156
172
  rowHref?: ((row: T) => string) | undefined;
157
173
  /** The row the reader is on (the object a page or a side panel shows): tinted and announced as current. */
158
174
  isSelected?: ((row: T) => boolean) | undefined;
175
+ /**
176
+ * Rows picked for a bulk action: a box on every row before the first
177
+ * column, and one in the head over every row drawn (ticked, clear, or mixed
178
+ * when some are). Shift with a box picks or clears every row between it and
179
+ * the box pressed before it, in the order the grid draws them.
180
+ *
181
+ * NOT `isSelected`, which is the one row the reader is ON. A picked row is
182
+ * tinted in the selected fill and its box says it; the current row keeps
183
+ * its own mark.
184
+ */
185
+ selection?: DataGridSelection<T> | undefined;
159
186
  isFailed?: ((row: T) => boolean) | undefined;
160
187
  /**
161
188
  * The sort as `key` or `-key` (descending), empty for the rows' own order.
@@ -264,4 +291,4 @@ export declare function fitGridColumns({ fit, width, overflows, visible, }: {
264
291
  * lets its head stick against the page's scroller; an application whose
265
292
  * scroller carries a sticky bar sets `--crewlet-data-grid-sticky-top`.
266
293
  */
267
- export declare function DataGrid<T>({ rows, bands, columns, rowKey, onRowActivate, rowHref, isSelected, isFailed, sort: sortRaw, onSortChange, serverSorted, cols: colsRaw, onColsChange, empty, footer, onLoadMore, loadedNote, phoneRows, flush, handleRef, onPointerDown, labels, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, className, }: DataGridProps<T>): import("react").JSX.Element;
294
+ export declare function DataGrid<T>({ rows, bands, columns, rowKey, onRowActivate, rowHref, isSelected, selection, isFailed, sort: sortRaw, onSortChange, serverSorted, cols: colsRaw, onColsChange, empty, footer, onLoadMore, loadedNote, phoneRows, flush, handleRef, onPointerDown, labels, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledby, className, }: DataGridProps<T>): import("react").JSX.Element;
@@ -1,7 +1,14 @@
1
- export { ChooserList, ColumnChooser, DataGrid, columnChoicesOf, fitGridColumns, parseGridSort } from '../chunk-2MYSESZF.js';
1
+ export { ChooserList, ColumnChooser, DataGrid, columnChoicesOf, fitGridColumns, parseGridSort } from '../chunk-FB5CFQTG.js';
2
+ import '../chunk-NCHKKYPQ.js';
2
3
  import '../chunk-PPUR46MK.js';
4
+ import '../chunk-EXRRTKWT.js';
5
+ import '../chunk-XCUUI7E7.js';
3
6
  import '../chunk-PQADV6P6.js';
7
+ import '../chunk-RSAQOKH3.js';
4
8
  import '../chunk-RTPQDNW3.js';
5
9
  import '../chunk-OG6CL3EB.js';
10
+ import '../chunk-H5XTJ7GJ.js';
11
+ import '../chunk-LACA4JGC.js';
12
+ import '../chunk-NUZHC6MM.js';
6
13
  import '../chunk-BZFWDIV6.js';
7
14
  import '../chunk-ODEQTPFM.js';
@@ -195,6 +195,21 @@ button.crewlet-data-grid__row-link {
195
195
  background: var(--color-brand-accent-soft);
196
196
  }
197
197
 
198
+ /*
199
+ * PICKED FOR A BULK ACTION (`selection`), as every chosen option is drawn:
200
+ * the selected fill, never the accent. One fill, so the hover overlay does not
201
+ * stack on it, and its box says it as well.
202
+ */
203
+ .crewlet-data-grid__row--picked,
204
+ .crewlet-data-grid__row--picked:hover {
205
+ background: var(--color-surface-selected);
206
+ }
207
+
208
+ /* The selection box, centred in its track and standing above the row's link. */
209
+ .crewlet-data-grid__select {
210
+ display: inline-flex;
211
+ }
212
+
198
213
  .crewlet-data-grid__row--cursor {
199
214
  box-shadow: inset 2px 0 0 var(--color-brand-accent);
200
215
  }
@@ -1,10 +1,10 @@
1
- export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-AS2BMY3E.js';
1
+ export { ALL_ITEMS, CopyableCell, DATA_TABLE_LABELS, DataTable, RowActionsMenu } from '../chunk-WQ7S7CKZ.js';
2
+ import '../chunk-YCC2S7DF.js';
2
3
  import '../chunk-STJ7QBC3.js';
3
4
  import '../chunk-DTIW4CHZ.js';
4
- import '../chunk-6AKG2VLR.js';
5
- import '../chunk-F57N6ZJG.js';
6
5
  import '../chunk-EUCC37WY.js';
7
6
  import '../chunk-AV2DXAEL.js';
7
+ import '../chunk-NCHKKYPQ.js';
8
8
  import '../chunk-EXRRTKWT.js';
9
9
  import '../chunk-XCUUI7E7.js';
10
10
  import '../chunk-PQADV6P6.js';
@@ -1,21 +1,21 @@
1
- export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-SMOFYZJ5.js';
1
+ export { DATA_VIEW_TOOLBAR_LABELS, DataView, DataViewToolbar, FILTER_AXIS_LABELS, FilterAxisBar, FilterAxisChip, applyColumnFilters, applyFilters, blankFilterValue, defaultOperator, filterDefsFromColumns, filterHasValue, filterPredicate, formatFilterValue, operatorOf, tableColumns } from '../chunk-NAWUXCBC.js';
2
2
  import '../chunk-DKB73KZI.js';
3
- import '../chunk-AS2BMY3E.js';
4
- import '../chunk-UFXLNC2N.js';
3
+ import '../chunk-ZFM5L7M4.js';
4
+ import '../chunk-WQ7S7CKZ.js';
5
+ import '../chunk-YCC2S7DF.js';
6
+ import '../chunk-7KHM2FZH.js';
5
7
  import '../chunk-STJ7QBC3.js';
6
8
  import '../chunk-DTIW4CHZ.js';
7
- import '../chunk-6AKG2VLR.js';
8
- import '../chunk-7KHM2FZH.js';
9
+ import '../chunk-GXQ3B46I.js';
9
10
  import '../chunk-NR4CPM4T.js';
10
11
  import '../chunk-KHJIEPZV.js';
11
- import '../chunk-GXQ3B46I.js';
12
- import '../chunk-F57N6ZJG.js';
13
12
  import '../chunk-3CZ7XAVY.js';
14
13
  import '../chunk-EUCC37WY.js';
15
14
  import '../chunk-AV2DXAEL.js';
15
+ import '../chunk-NCHKKYPQ.js';
16
+ import '../chunk-SMBKXWML.js';
16
17
  import '../chunk-EXRRTKWT.js';
17
18
  import '../chunk-XCUUI7E7.js';
18
- import '../chunk-SMBKXWML.js';
19
19
  import '../chunk-BHHIIK3M.js';
20
20
  import '../chunk-PQADV6P6.js';
21
21
  import '../chunk-RSAQOKH3.js';
@@ -1,6 +1,6 @@
1
- export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-UFXLNC2N.js';
2
- import '../chunk-KHJIEPZV.js';
1
+ export { DEFAULT_DATE_TIME_PICKER_LABELS, DateTimePicker } from '../chunk-ZFM5L7M4.js';
3
2
  import '../chunk-GXQ3B46I.js';
3
+ import '../chunk-KHJIEPZV.js';
4
4
  import '../chunk-OMV5W53A.js';
5
5
  import '../chunk-OG6CL3EB.js';
6
6
  import '../chunk-H5XTJ7GJ.js';