@crispy-seed/data-table 0.12.1 → 0.14.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.
package/dist/index.js CHANGED
@@ -1168,7 +1168,7 @@ function isStringArray(value) {
1168
1168
  // per-row measurement, no ResizeObserver per row.
1169
1169
  /** The recipe's own row height (`--seed-dimension-x9` = 36px, `row.height`). */ const DEFAULT_VIRTUAL_ROW_HEIGHT = 36;
1170
1170
  /** Rows rendered beyond each edge of the viewport, so a fast scroll never outruns the
1171
- * render and flashes an empty gap. */ const DEFAULT_VIRTUAL_OVERSCAN = 8;
1171
+ * render and flashes an empty gap. */ const DEFAULT_VIRTUAL_OVERSCAN = 16;
1172
1172
  /** Distance from the bottom (px) at which `onLoadMore` fires in virtualized mode --
1173
1173
  * the same 160px look-ahead the IntersectionObserver's rootMargin gives a non-
1174
1174
  * virtualized table. */ const LOAD_MORE_THRESHOLD = 160;
@@ -3232,19 +3232,20 @@ function StatusCell({ value }) {
3232
3232
  * same "literal color as a computed prop" call `RatingCell`'s star fill already
3233
3233
  * makes. Shared by `ChipCell` (Feature A, single value) and `ChipListCell`/
3234
3234
  * editors.tsx's `ChipListEditor` (Feature B, multi value) so all three chip
3235
- * renderings stay byte-identical. */ function SwatchChip({ value, className, children }) {
3235
+ * renderings stay byte-identical. */ function SwatchChip({ value, label, color, className, children }) {
3236
3236
  return /*#__PURE__*/ jsxs("span", {
3237
3237
  className: className,
3238
3238
  style: {
3239
- backgroundColor: swatchColorFor(value),
3240
- color: swatchInkFor(value)
3239
+ backgroundColor: color ?? swatchColorFor(value),
3240
+ color: color ? CHIP_CUSTOM_COLOR_INK : swatchInkFor(value)
3241
3241
  },
3242
3242
  children: [
3243
- value,
3243
+ label ?? value,
3244
3244
  children
3245
3245
  ]
3246
3246
  });
3247
3247
  }
3248
+ const CHIP_CUSTOM_COLOR_INK = "#1f2937";
3248
3249
  /** `type: "chip"` (Feature A, #9) -- a single value rendered as one colored chip,
3249
3250
  * the color derived deterministically from the value string (`swatchColorFor`):
3250
3251
  * same value, same color, every render, every column. For a column like provider/
@@ -3257,6 +3258,14 @@ function StatusCell({ value }) {
3257
3258
  className: className
3258
3259
  });
3259
3260
  }
3261
+ /** The `label`/`color` a `chipOptions` entry gives `tag`, spread onto its chip so a
3262
+ * tag looks identical in the closed cell and in the editor's option list. */ function optionProps(chipOptions, tag) {
3263
+ const option = chipOptions?.find((entry)=>entry.value === tag);
3264
+ return option ? {
3265
+ label: option.label,
3266
+ color: option.color
3267
+ } : {};
3268
+ }
3260
3269
  // Feature B rework (#8) -- the chip-list DISPLAY row's own gap, mirrored from the
3261
3270
  // qvism recipe's `chipList` slot (`packages/qvism-preset/src/recipes/data-table.ts`'s
3262
3271
  // `CHIP_GAP`, measured live off Attio at 3px between chips). Kept as a literal here
@@ -3289,7 +3298,7 @@ const CHIP_LIST_GAP_PX = 3;
3289
3298
  * times, not just while a `ResizeObserver` fires, because widening the column back
3290
3299
  * out needs to know the width of chips currently hidden behind "+N" to decide
3291
3300
  * whether they now fit again.
3292
- */ function ChipListCell({ value, className, chipClassName, overflowClassName }) {
3301
+ */ function ChipListCell({ value, className, chipClassName, overflowClassName, chipOptions }) {
3293
3302
  const tags = Array.isArray(value) ? value.filter((tag)=>!!tag) : [];
3294
3303
  const containerRef = React.useRef(null);
3295
3304
  const measureRef = React.useRef(null);
@@ -3338,6 +3347,7 @@ const CHIP_LIST_GAP_PX = 3;
3338
3347
  children: [
3339
3348
  tags.slice(0, clampedVisible).map((tag)=>/*#__PURE__*/ jsx(SwatchChip, {
3340
3349
  value: tag,
3350
+ ...optionProps(chipOptions, tag),
3341
3351
  className: chipClassName
3342
3352
  }, tag)),
3343
3353
  overflowCount > 0 && /*#__PURE__*/ jsxs("span", {
@@ -3358,6 +3368,7 @@ const CHIP_LIST_GAP_PX = 3;
3358
3368
  },
3359
3369
  children: tags.map((tag)=>/*#__PURE__*/ jsx(SwatchChip, {
3360
3370
  value: tag,
3371
+ ...optionProps(chipOptions, tag),
3361
3372
  className: chipClassName
3362
3373
  }, tag))
3363
3374
  }),
@@ -4120,7 +4131,45 @@ const TextFieldTextarea = /*#__PURE__*/ forwardRef(({ className, autoresize = tr
4120
4131
  });
4121
4132
  TextFieldTextarea.displayName = "TextFieldTextarea";
4122
4133
 
4123
- __insertCSS(".seed-data-table__root{box-sizing:border-box;position:relative;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:not([data-editable]){user-select:none}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-overlay-open]{overflow:visible;z-index:20}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entityName[data-clickable]{cursor:pointer;border:none;background:0 0;padding:0;margin:0;font-family:inherit;font-size:inherit;line-height:inherit;color:inherit;text-align:start}.seed-data-table__entityName[data-clickable]:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__entityActions{display:flex;align-items:center;gap:6px;margin-inline-start:auto;flex-shrink:0;opacity:0;transition:opacity .15s}tr:hover .seed-data-table__entityActions{opacity:1}.seed-data-table__entityActions:focus-within{opacity:1}.seed-data-table__entityAction{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:2px;border:none;border-radius:6px;background:0 0;font-family:inherit;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer;flex-shrink:0;transition:background-color .2s,color .2s,box-shadow .2s}.seed-data-table__entityAction:hover{background:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__chip{box-sizing:border-box;display:inline-flex;align-items:center;flex-shrink:0;max-width:100%;height:22px;padding:0 4px;border-radius:7px;font-size:13px;font-weight:var(--seed-font-weight-medium);line-height:15px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__chipList{position:relative;display:flex;align-items:center;flex-wrap:nowrap;gap:3px;overflow:hidden;min-width:0;width:100%}.seed-data-table__chipOverflow{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;padding:0 4px;border-radius:6px;background-color:#f6f7f7;color:#000;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;white-space:nowrap}.seed-data-table__chipListEditor{display:flex;align-items:center;flex-wrap:wrap;gap:3px;min-width:0;width:100%}.seed-data-table__chipRemove{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:12px;height:12px;margin:0;margin-inline-start:2px;padding:0;border:none;border-radius:999px;background:0 0;color:inherit;opacity:.6;cursor:pointer;transition:opacity .12s,background-color .12s}.seed-data-table__chipRemove:hover{opacity:1;background-color:rgba(0,0,0,.08)}.seed-data-table__chipInput{flex:1 1 auto;min-width:40px;height:22px;margin:0;padding:0;border:none;outline:0;background:0 0;font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);letter-spacing:-.14px}.seed-data-table__expandOverlay{box-sizing:border-box;position:absolute;top:-1px;inset-inline-start:-1px;inset-inline-end:-1px;z-index:10;min-height:calc(100% + 2px);display:flex;align-items:flex-start;padding-inline:var(--seed-dimension-x3);padding-block:var(--seed-dimension-x3);background-color:var(--seed-color-bg-layer-floating);border-radius:4px;box-shadow:none;border:1px solid #266df0;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);letter-spacing:-.14px;cursor:default}.seed-data-table__expandOverlayText{width:100%;min-width:0;white-space:normal;word-break:break-word}.seed-data-table__cellSuffixRow{display:flex;align-items:center;gap:4px;min-width:0;width:100%}.seed-data-table__cellSuffixText{flex:1 1 0%;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cellSuffixIcon{flex-shrink:0;display:inline-flex;align-items:center;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent)}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__bulkBar{box-sizing:border-box;position:absolute;inset-inline-start:50%;transform:translateX(-50%);bottom:var(--seed-dimension-x4);z-index:30;display:flex;align-items:center;gap:var(--seed-dimension-x3);min-height:36px;padding-inline:var(--seed-dimension-x3_5);padding-block:var(--seed-dimension-x2);border-radius:var(--seed-radius-full);box-shadow:var(--seed-shadow-s3);background-color:var(--seed-color-bg-layer-floating);color:var(--seed-color-fg-neutral);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap}.seed-data-table__bulkBarCount{flex-shrink:0;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums}.seed-data-table__bulkBarClear{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px;margin:0;padding:2px;border:none;border-radius:6px;background:0 0;font-family:inherit;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer;transition:background-color .2s,color .2s}.seed-data-table__bulkBarClear:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 8%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__bulkBarActions{display:flex;align-items:center;flex-shrink:0;gap:var(--seed-dimension-x3);padding-inline-start:var(--seed-dimension-x3);border-inline-start:1px solid color-mix(in srgb,var(--seed-color-fg-neutral) 16%,transparent)}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
4134
+ // Row-narrowing for the toolbar's search box -- split out of DataTable.tsx the way
4135
+ // cells.tsx splits out cell-type rendering: a self-contained, independently testable
4136
+ // concern DataTable.tsx just calls, rather than inline `.filter()` calls piling up in
4137
+ // the same component that also owns markup. The toolbar's typed Filter CONDITIONS
4138
+ // (field/operator/value chips, DATATABLE-ATTIO-SPEC.md's Attio/crisp model) live in
4139
+ // `toolbar-conditions.tsx` instead, alongside the Sort/Filter chrome that manages
4140
+ // them -- this file is search only now; the old per-column "is/is not" picker
4141
+ // (`matchesFilter`/`DataTableFilterState`) is gone, replaced by that toolbar model.
4142
+ /**
4143
+ * A column's `value(row)` if it supplies one, else the raw field at `column.key` --
4144
+ * the single accessor sort/search/filter/export all read through
4145
+ * (DATATABLE-ATTIO-SPEC.md's Column API), so a consumer only teaches the table how to
4146
+ * read a value ONCE rather than once per feature.
4147
+ */ function getColumnValue(column, row) {
4148
+ return column.value ? column.value(row) : row[column.key];
4149
+ }
4150
+ /**
4151
+ * Case-insensitive substring match against a row's stringified value -- crisp's own
4152
+ * `applyFilters` "contains" semantics (`tabletoolbar.tsx`), reused here for the
4153
+ * toolbar's single free-text query. `null`/`undefined` never match a non-empty query --
4154
+ * there is no text to search.
4155
+ */ function matchesSearch(value, query) {
4156
+ if (!query) return true;
4157
+ if (value == null) return false;
4158
+ return String(value).toLowerCase().includes(query.toLowerCase());
4159
+ }
4160
+ /**
4161
+ * The toolbar's search query -- an OR across `searchable` columns, matching GRC's own
4162
+ * `useFilteredRows`. The toolbar's own typed Filter conditions apply SEPARATELY, as a
4163
+ * second pass over this function's result (`toolbar-conditions.tsx`'s
4164
+ * `applyToolbarFilters`, called by `DataTable.tsx` right after this) -- narrowing what
4165
+ * the search box already found, not the other way round.
4166
+ */ function getVisibleRows(data, columns, query) {
4167
+ const searchableColumns = columns.filter((column)=>column.searchable);
4168
+ if (!query) return data;
4169
+ return data.filter((row)=>searchableColumns.some((column)=>matchesSearch(getColumnValue(column, row), query)));
4170
+ }
4171
+
4172
+ __insertCSS(".seed-data-table__root{box-sizing:border-box;position:relative;display:flex;flex-direction:column;width:100%;border-width:1px;border-style:solid;font-family:Inter,-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif}.seed-data-table__table{width:100%;border-collapse:separate;border-spacing:0;table-layout:fixed}.seed-data-table__headerCell{box-sizing:border-box;position:sticky;top:0;z-index:2;vertical-align:middle;text-align:start;padding:0;height:var(--seed-dimension-x10);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium);letter-spacing:-.14px}.seed-data-table__headerCell:last-child{border-inline-end:none}.seed-data-table__headerCell[data-sortable]{cursor:pointer;user-select:none}.seed-data-table__headerCell [data-chevron]{opacity:0;transition:opacity .12s}.seed-data-table__headerCell[data-sortable]:hover [data-chevron]{opacity:.6}.seed-data-table__headerCell[data-sorted] [data-chevron]{opacity:1;color:var(--seed-color-fg-neutral)}.seed-data-table__headerCell:hover [data-column-menu]{opacity:1}.seed-data-table__headerCell [data-column-menu]:focus-visible,.seed-data-table__headerCell [data-column-menu][data-open]{opacity:1}.seed-data-table__headerCell[data-dragging]{opacity:.5}.seed-data-table__headerCell[data-sticky]{position:sticky;z-index:3;background-color:var(--seed-color-bg-layer-default)}.seed-data-table__headerCell{outline:var(--seed-dimension-x0_5) solid transparent;outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell:is(:focus-visible,[data-focus-visible]){outline:var(--seed-dimension-x0_5) solid var(--seed-color-stroke-focus-ring);outline-offset:calc(var(--seed-dimension-x0_5) * -1)}.seed-data-table__headerCell .seed-data-table-resize-handle{position:absolute;top:0;inset-inline-end:calc(7px / -2);width:7px;height:100%;z-index:4;display:flex;align-items:center;justify-content:center;cursor:col-resize;touch-action:none}.seed-data-table__headerCell .seed-data-table-resize-handle-inner{width:3px;height:100%;border-radius:3px;background-color:#0298d9;opacity:0;transition:opacity .1s}.seed-data-table__headerCell .seed-data-table-resize-handle:hover .seed-data-table-resize-handle-inner,.seed-data-table__headerCell .seed-data-table-resize-handle[data-resizing] .seed-data-table-resize-handle-inner{opacity:1}.seed-data-table__headerCellInner{box-sizing:border-box;display:flex;align-items:center;width:100%;height:100%;min-width:0;gap:var(--seed-dimension-x1_5);padding-inline:var(--seed-dimension-x3)}.seed-data-table__headerCellLabel{min-width:0;flex:1 1 0%;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__headerCellIcon{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;justify-content:center;width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-subtle);border:none;background:0 0;padding:0;font:inherit;cursor:pointer}.seed-data-table__headerCellIcon[data-active]{color:var(--seed-color-fg-neutral)}.seed-data-table__headerCellIcon[data-column-menu]{opacity:0;transition:opacity .12s}.seed-data-table__row{position:relative;background-color:var(--seed-color-bg-layer-default);--seed-data-table-row-bg:var(--seed-color-bg-layer-default)}.seed-data-table__row[data-clickable]{cursor:pointer}.seed-data-table__row:is([aria-selected=true],[data-selected]){background-color:color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default));--seed-data-table-row-bg:color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default))}.seed-data-table__row:is([aria-selected=true],[data-selected]):is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,color-mix(in srgb,#0298d9 10%,var(--seed-color-bg-layer-default)));--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, color-mix(in srgb, #0298d9 10%, var(--seed-color-bg-layer-default)))}.seed-data-table__cell{box-sizing:border-box;position:relative;vertical-align:middle;text-align:start;height:var(--seed-dimension-x9);border-bottom:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-top:none;border-inline-start:none;padding-block:0;padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-regular);letter-spacing:-.14px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cell:not([data-editable]){user-select:none}.seed-data-table__cell:last-child{border-inline-end:none}tbody tr:last-child .seed-data-table__cell{border-bottom:none}.seed-data-table__cell[data-numeric]{text-align:end;font-variant-numeric:tabular-nums}.seed-data-table__cell[data-sticky]{position:sticky;z-index:1;background-color:var(--seed-data-table-row-bg)}.seed-data-table__cell[data-overlay-open]{overflow:visible;z-index:20}.seed-data-table__cell[data-editable]{cursor:default}.seed-data-table__cell .seed-data-table-edit-picker{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);min-width:0}.seed-data-table__cell .seed-data-table-edit-pending{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);animation:rotate .6s linear infinite}.seed-data-table__cell .seed-data-table-edit-error{position:absolute;top:100%;inset-inline-start:var(--seed-dimension-x3);inset-inline-end:var(--seed-dimension-x3);z-index:2;padding-top:2px;font-size:12px;line-height:1.3;color:var(--seed-color-fg-critical);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entity{display:flex;align-items:center;min-width:0;gap:var(--seed-dimension-x1_5)}.seed-data-table__entityName{min-width:0;font-weight:var(--seed-font-weight-medium);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__entityName[data-clickable]{cursor:pointer;border:none;background:0 0;padding:0;margin:0;font-family:inherit;font-size:inherit;line-height:inherit;color:inherit;text-align:start}.seed-data-table__entityName[data-clickable]:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__tagList{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);overflow:hidden;min-width:0}.seed-data-table__entityActions{display:flex;align-items:center;gap:6px;margin-inline-start:auto;flex-shrink:0;opacity:0;transition:opacity .15s}tr:hover .seed-data-table__entityActions{opacity:1}.seed-data-table__entityActions:focus-within{opacity:1}.seed-data-table__entityAction{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;margin:0;padding:2px;border:none;border-radius:6px;background:0 0;font-family:inherit;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer;flex-shrink:0;transition:background-color .2s,color .2s,box-shadow .2s}.seed-data-table__entityAction:hover{background:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__link{color:var(--seed-color-fg-neutral);text-decoration:none;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__link:is(:hover,[data-hover]){text-decoration:underline}.seed-data-table__chip{box-sizing:border-box;display:inline-flex;align-items:center;flex-shrink:0;max-width:100%;height:22px;padding:0 4px;border-radius:7px;font-size:13px;font-weight:var(--seed-font-weight-medium);line-height:15px;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__chipList{position:relative;display:flex;align-items:center;flex-wrap:nowrap;gap:3px;overflow:hidden;min-width:0;width:100%}.seed-data-table__chipOverflow{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;height:20px;padding:0 4px;border-radius:6px;background-color:#f6f7f7;color:#000;font-size:10px;font-weight:var(--seed-font-weight-regular);line-height:15px;white-space:nowrap}.seed-data-table__chipPicker{display:flex;flex-direction:column;width:100%;min-width:0}.seed-data-table__chipPickerList{display:flex;flex-direction:column;max-height:240px;overflow-y:auto;padding:0 4px 4px}.seed-data-table__chipPickerRow{box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;min-height:32px;margin:0;padding:4px 8px;border:none;border-radius:6px;background:0 0;font:inherit;color:inherit;text-align:start;cursor:pointer}.seed-data-table__chipPickerRow:hover{background-color:#f6f7f7}.seed-data-table__chipPickerRow:disabled{cursor:default;opacity:.6}.seed-data-table__chipPickerBox{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:16px;height:16px;border-radius:4px;border:1px solid rgba(0,0,0,.25);background-color:#fff;color:#fff}.seed-data-table__chipPickerBox[data-checked]{border-color:#266df0;background-color:#266df0}.seed-data-table__chipPickerBox svg{width:12px;height:12px}.seed-data-table__chipPickerCreate{box-sizing:border-box;display:flex;align-items:center;gap:6px;width:100%;min-height:32px;margin:0;padding:4px 8px;border:none;border-radius:6px;background:0 0;font:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);text-align:start;cursor:pointer}.seed-data-table__chipPickerCreate:hover{background-color:#f6f7f7}.seed-data-table__expandOverlay{box-sizing:border-box;position:absolute;top:-1px;inset-inline-start:-1px;inset-inline-end:-1px;z-index:10;min-height:calc(100% + 2px);display:flex;align-items:flex-start;padding-inline:var(--seed-dimension-x3);padding-block:var(--seed-dimension-x3);background-color:var(--seed-color-bg-layer-floating);border-radius:4px;box-shadow:none;border:1px solid #266df0;color:var(--seed-color-fg-neutral);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);letter-spacing:-.14px;cursor:default}.seed-data-table__expandOverlayText{width:100%;min-width:0;white-space:normal;word-break:break-word}.seed-data-table__cellSuffixRow{display:flex;align-items:center;gap:4px;min-width:0;width:100%}.seed-data-table__cellSuffixText{flex:1 1 0%;min-width:0;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__cellSuffixIcon{flex-shrink:0;display:inline-flex;align-items:center;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent)}.seed-data-table__toolbar{box-sizing:border-box;display:flex;align-items:center;width:100%;flex-shrink:0;min-height:49px;gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x3);border-top:1px solid var(--seed-color-stroke-neutral-muted)}.seed-data-table__search{position:relative;display:inline-flex;align-items:center;flex:1 1 0%;max-width:280px}.seed-data-table__search svg{position:absolute;inset-inline-start:var(--seed-dimension-x2);width:var(--seed-dimension-x4);height:var(--seed-dimension-x4);color:var(--seed-color-fg-neutral-muted);pointer-events:none}.seed-data-table__search input{width:100%;height:var(--seed-dimension-x8);padding-inline-start:var(--seed-dimension-x7);padding-inline-end:var(--seed-dimension-x2);border:none;border-radius:var(--seed-radius-r2);background-color:var(--seed-color-bg-layer-default);box-shadow:inset 0 0 0 1px var(--seed-color-stroke-neutral-weak);font-family:inherit;font-size:var(--seed-font-size-t4);color:var(--seed-color-fg-neutral);outline:0;transition:box-shadow .1s var(--seed-timing-function-easing)}.seed-data-table__search input::placeholder{color:var(--seed-color-fg-neutral-subtle)}.seed-data-table__search input:focus{box-shadow:inset 0 0 0 2px var(--seed-color-stroke-neutral-contrast)}.seed-data-table__count{flex-shrink:0;color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t3);font-variant-numeric:tabular-nums}.seed-data-table__toolbarEnd{flex-shrink:0;margin-inline-start:auto;display:inline-flex;align-items:center;gap:var(--seed-dimension-x2)}.seed-data-table__scrollArea{position:relative;display:flex;flex-direction:column;width:100%;min-width:0;flex:1 1 auto;min-height:0;overflow-x:auto;overflow-y:auto}.seed-data-table__scrollArea[data-scrolled-start] [data-sticky-edge]{clip-path:inset(0 -38px 0 0);box-shadow:6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__scrollArea[data-scrolled-end] [data-sticky-edge-end]{clip-path:inset(0 0 0 -38px);box-shadow:-6px 0 16px 4px rgba(0,0,0,.12)}.seed-data-table__footerCell{box-sizing:border-box;position:sticky;bottom:0;z-index:2;vertical-align:middle;padding:0;height:var(--seed-dimension-x9);background-color:var(--seed-color-bg-layer-default);border-top:1px solid var(--seed-color-stroke-neutral-muted);border-inline-end:1px solid var(--seed-color-stroke-neutral-muted);border-inline-start:none}.seed-data-table__footerCell:last-child{border-inline-end:none}.seed-data-table__footerCell[data-sticky]{z-index:3}.seed-data-table__footerCell .seed-data-table-column-calc-trigger{display:flex;align-items:center;gap:var(--seed-dimension-x1_5);width:100%;height:100%;min-width:0;margin:0;padding:0 var(--seed-dimension-x3);border:none;background:0 0;color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap;overflow:clip;cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__footerCell .seed-data-table-column-calc-trigger:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__footerCell .seed-data-table-column-calc-trigger[data-align=right]{justify-content:flex-end}.seed-data-table__footerCell .seed-data-table-column-calc-trigger svg{flex-shrink:0;opacity:.7}.seed-data-table__footerCell .seed-data-table-column-calc-placeholder{overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-value{min-width:0;flex-shrink:1;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums;overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__footerCell .seed-data-table-column-calc-op{min-width:0;flex-shrink:1;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);overflow:clip;text-overflow:ellipsis;white-space:nowrap}.seed-data-table__emptyState{box-sizing:border-box;text-align:center;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:var(--seed-color-fg-neutral-subtle);font-size:var(--seed-font-size-t4)}.seed-data-table__loadingState{box-sizing:border-box;display:flex;align-items:center;justify-content:center;gap:10px;padding-block:var(--seed-dimension-x8);padding-inline:var(--seed-dimension-x3);color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);font-size:var(--seed-font-size-t4);line-height:var(--seed-line-height-t4);font-weight:var(--seed-font-weight-medium)}.seed-data-table__loadingState[data-inline]{padding-block:0;padding-inline:0;height:var(--seed-dimension-x9)}.seed-data-table__loadingState .seed-data-table-loading-spinner{flex-shrink:0;color:color-mix(in srgb,var(--seed-color-fg-neutral) 63%,transparent);animation:rotate .6s linear infinite}.seed-data-table__addRowCell{box-sizing:border-box;padding:0;border-top:none}.seed-data-table__addRow{box-sizing:border-box;display:flex;align-items:center;width:100%;margin:0;border:none;border-top:1px solid var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);height:var(--seed-dimension-x9);gap:var(--seed-dimension-x2);padding-inline:var(--seed-dimension-x2);color:var(--seed-color-fg-neutral-subtle);font-family:inherit;font-size:var(--seed-font-size-t4);cursor:pointer;transition:background-color .12s,color .12s}.seed-data-table__addRow:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 4%,var(--seed-color-bg-layer-default));color:var(--seed-color-fg-neutral)}.seed-data-table__addRow svg{flex-shrink:0}.seed-data-table__selectionCell{text-align:center;padding:0}.seed-data-table__bulkBar{box-sizing:border-box;position:absolute;inset-inline-start:50%;transform:translateX(-50%);bottom:var(--seed-dimension-x4);z-index:30;display:flex;align-items:center;gap:var(--seed-dimension-x3);min-height:36px;padding-inline:var(--seed-dimension-x3_5);padding-block:var(--seed-dimension-x2);border-radius:var(--seed-radius-full);box-shadow:var(--seed-shadow-s3);background-color:var(--seed-color-bg-layer-floating);color:var(--seed-color-fg-neutral);font-family:inherit;font-size:var(--seed-font-size-t4);font-weight:var(--seed-font-weight-medium);white-space:nowrap}.seed-data-table__bulkBar[data-above-footer]{bottom:calc(var(--seed-dimension-x4) + var(--seed-dimension-x9))}.seed-data-table__bulkBarCount{flex-shrink:0;color:var(--seed-color-fg-neutral);font-variant-numeric:tabular-nums}.seed-data-table__bulkBarClear{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:20px;height:20px;margin:0;padding:2px;border:none;border-radius:6px;background:0 0;font-family:inherit;color:color-mix(in srgb,var(--seed-color-fg-neutral) 55%,transparent);cursor:pointer;transition:background-color .2s,color .2s}.seed-data-table__bulkBarClear:hover{background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 8%,transparent);color:var(--seed-color-fg-neutral)}.seed-data-table__bulkBarActions{display:flex;align-items:center;flex-shrink:0;gap:var(--seed-dimension-x3);padding-inline-start:var(--seed-dimension-x3);border-inline-start:1px solid color-mix(in srgb,var(--seed-color-fg-neutral) 16%,transparent)}.seed-data-table__root--surface_card{border-color:var(--seed-color-stroke-neutral-muted);background-color:var(--seed-color-bg-layer-default);border-radius:var(--seed-radius-r3)}.seed-data-table__root--surface_bleed{border-color:var(--seed-color-bg-transparent);background-color:var(--seed-color-bg-transparent)}.seed-data-table__row--interactive_true{transition:background-color .12s}.seed-data-table__row--interactive_true:is(:hover,[data-hover]){background-color:color-mix(in srgb,var(--seed-color-fg-neutral) 3%,transparent);--seed-data-table-row-bg:color-mix(in srgb, var(--seed-color-fg-neutral) 3%, var(--seed-color-bg-layer-default))}");
4124
4173
 
4125
4174
  const createClassName = (className, variants, compoundVariants = [])=>{
4126
4175
  const variantKeys = Object.keys(variants);
@@ -4228,16 +4277,24 @@ const dataTableSlotNames = [
4228
4277
  "seed-data-table__chipOverflow"
4229
4278
  ],
4230
4279
  [
4231
- "chipListEditor",
4232
- "seed-data-table__chipListEditor"
4280
+ "chipPicker",
4281
+ "seed-data-table__chipPicker"
4233
4282
  ],
4234
4283
  [
4235
- "chipRemove",
4236
- "seed-data-table__chipRemove"
4284
+ "chipPickerList",
4285
+ "seed-data-table__chipPickerList"
4237
4286
  ],
4238
4287
  [
4239
- "chipInput",
4240
- "seed-data-table__chipInput"
4288
+ "chipPickerRow",
4289
+ "seed-data-table__chipPickerRow"
4290
+ ],
4291
+ [
4292
+ "chipPickerBox",
4293
+ "seed-data-table__chipPickerBox"
4294
+ ],
4295
+ [
4296
+ "chipPickerCreate",
4297
+ "seed-data-table__chipPickerCreate"
4241
4298
  ],
4242
4299
  [
4243
4300
  "expandOverlay",
@@ -4856,94 +4913,154 @@ function RatingEditor({ column, value, pending, onCommit }) {
4856
4913
  });
4857
4914
  }
4858
4915
  ////////////////////////////////////////////////////////////////////////////////////
4859
- // -- editable: "chip-list" (Feature B rework, #8) -- click-to-edit, Attio's own model
4860
- // rather than the always-live widget this replaced (crispy-seed#1094: every row
4861
- // rendering a live add-tag editor at once overflowed the cell and collided with
4862
- // sticky columns). `body-cells.tsx`'s `DataTableBodyCell` opens this INSIDE the
4863
- // same anchored `CellExpandOverlay` Feature C already built for a gated editor's
4864
- // expanded state, on a plain single click (no truncation gate, unlike every other
4865
- // read-only cell's peek) -- clicking a short 2-tag cell must open the editor just
4866
- // as readily as a 10-tag one. It stays open across MULTIPLE add/remove commits
4867
- // (closes only on blur/outside-click/Escape, `DataTableBodyCell`'s own effect) by
4868
- // NOT going through `useDataTableEdit`'s `isEditing` gate the way `SelectEditor`/
4869
- // `TextEditor` do -- `commitEdit` closes `editingCell` the instant a SYNC commit
4870
- // resolves (its own doc comment), which would have closed a gated chip editor
4871
- // after the very first tag. `DataTableBodyCell` instead tracks THIS editor's own
4872
- // open/closed state in its local `overlayOpen`, independent of `editingCell`.
4873
- // Every add/remove still commits the FULL next array through the same one-string
4874
- // contract every other editor already uses (`useDataTableEdit`'s own doc
4875
- // comment): `JSON.stringify(nextTags)`, which the consumer's `onEdit` parses back
4876
- // -- crisp/GRC's contract stays "one string in, no typed union", not a second
4877
- // commit shape invented for just this column.
4916
+ // -- editable: "chip-list" -- Attio's multi-select popover (0.14.0; replaces the
4917
+ // 0.10.0-0.13.0 free-text "Add..." tag adder, which stacked an empty input over the
4918
+ // chips and read as broken on an empty cell). Measured off Attio's Company
4919
+ // "Categories" cell: a search field pinned on top, below it a scrolling list of the
4920
+ // column's OPTIONS, each drawn as its own colored chip with a checkbox on the RIGHT
4921
+ // edge (filled blue when the tag is on this row); clicking a row toggles that tag
4922
+ // and the popover STAYS OPEN across toggles; typing filters the list; text matching
4923
+ // no option offers a "Create '<text>'" row (freeform tag columns, e.g. tether's
4924
+ // Labels). `body-cells.tsx`'s `DataTableBodyCell` opens this inside a portaled
4925
+ // `expandOverlay` on a plain click and closes it on blur/outside-click/Escape; it
4926
+ // tracks its own `overlayOpen` rather than `useDataTableEdit`'s `isEditing` gate,
4927
+ // since a sync commit closes `editingCell` on the first toggle.
4928
+ //
4929
+ // Commit contract is unchanged: every toggle/create commits the FULL next array as
4930
+ // `JSON.stringify(nextTags)` through the one-string `onCommit`, which the consumer's
4931
+ // `onEdit` parses back.
4878
4932
  //
4879
- // Renders through `classNames.chipListEditor`, NOT the read-only `chipList` slot
4880
- // (cells.tsx's `ChipListCell`) -- the display row clips to one line with a "+N"
4881
- // badge; this editor instead WRAPS onto as many lines as it needs inside the
4882
- // overlay's own grow-in-height box, since every tag (plus the add-input) has to
4883
- // stay visible and editable at once.
4884
- function ChipListEditor({ column, value, pending, onCommit, classNames }) {
4933
+ // Option source: `column.chipOptions` (value/label?/color?); tags already on the row
4934
+ // but absent from it are still listed (so they can be unchecked); with no
4935
+ // `chipOptions` at all, the distinct tags across the table's rows.
4936
+ /** Adds `tag` when absent, removes it when present -- the picker's one toggle. */ function toggleTag(tags, tag) {
4937
+ return tags.includes(tag) ? tags.filter((existing)=>existing !== tag) : [
4938
+ ...tags,
4939
+ tag
4940
+ ];
4941
+ }
4942
+ /** The option list a `chip-list` popover shows: declared `chipOptions` first, then any
4943
+ * selected tag not declared, then (only when nothing was declared) the distinct tags
4944
+ * across `rows`. */ function buildChipPickerOptions(column, tags, rows) {
4945
+ const seen = new Set();
4946
+ const out = [];
4947
+ function push(option) {
4948
+ if (!option.value || seen.has(option.value)) return;
4949
+ seen.add(option.value);
4950
+ out.push(option);
4951
+ }
4952
+ for (const option of column.chipOptions ?? [])push(option);
4953
+ for (const tag of tags)push({
4954
+ value: tag
4955
+ });
4956
+ if (!column.chipOptions) {
4957
+ const distinct = new Set();
4958
+ for (const row of rows){
4959
+ const raw = getColumnValue(column, row);
4960
+ if (Array.isArray(raw)) {
4961
+ for (const tag of raw)if (typeof tag === "string") distinct.add(tag);
4962
+ }
4963
+ }
4964
+ for (const tag of [
4965
+ ...distinct
4966
+ ].sort((x, y)=>x.localeCompare(y)))push({
4967
+ value: tag
4968
+ });
4969
+ }
4970
+ return out;
4971
+ }
4972
+ function ChipListEditor({ column, value, pending, onCommit, classNames, allRows = [] }) {
4885
4973
  const tags = Array.isArray(value) ? value.filter((tag)=>!!tag) : [];
4886
- const [draft, setDraft] = React.useState("");
4974
+ const built = buildChipPickerOptions(column, tags, allRows);
4975
+ // Options only ever GROW while the popover is open: with the row-derived fallback,
4976
+ // unchecking a tag that no other row carries would otherwise drop it from the list
4977
+ // and leave no way to re-check it.
4978
+ const knownRef = React.useRef([]);
4979
+ const known = knownRef.current;
4980
+ for (const option of built){
4981
+ const at = known.findIndex((entry)=>entry.value === option.value);
4982
+ if (at === -1) known.push(option);
4983
+ else known[at] = option;
4984
+ }
4985
+ const options = [
4986
+ ...known
4987
+ ];
4988
+ const optionText = React.useCallback((option)=>option.label ?? option.value, []);
4989
+ const { query, setQuery, filtered } = useSelectSearch(options, optionText);
4990
+ const trimmed = query.trim();
4991
+ const canCreate = column.chipCreatable !== false && trimmed !== "" && !options.some((option)=>option.value.toLowerCase() === trimmed.toLowerCase() || optionText(option).toLowerCase() === trimmed.toLowerCase());
4887
4992
  function commitTags(next) {
4888
4993
  onCommit(JSON.stringify(next));
4889
4994
  }
4890
- function addTag() {
4891
- const tag = draft.trim();
4892
- setDraft("");
4893
- if (!tag || tags.includes(tag)) return;
4894
- commitTags([
4895
- ...tags,
4896
- tag
4897
- ]);
4898
- }
4899
- function removeTag(tag) {
4900
- commitTags(tags.filter((existing)=>existing !== tag));
4995
+ function create() {
4996
+ setQuery("");
4997
+ commitTags(toggleTag(tags, trimmed));
4901
4998
  }
4902
- return(// biome-ignore lint/a11y/noStaticElementInteractions: not a widget -- this span never responds to interaction on ITSELF, only stops propagation of events that already occurred on a real interactive descendant (the remove buttons, the add-tag input). No role fits it because it isn't a control.
4903
- /*#__PURE__*/ jsxs("span", {
4904
- className: classNames.chipListEditor,
4999
+ return(// biome-ignore lint/a11y/noStaticElementInteractions: not a widget -- this wrapper never responds to interaction on ITSELF, only stops propagation of events that already occurred on a real interactive descendant (the search input, the option rows). No role fits it because it isn't a control.
5000
+ /*#__PURE__*/ jsxs("div", {
5001
+ className: classNames.chipPicker,
4905
5002
  onClick: (event)=>event.stopPropagation(),
4906
5003
  children: [
4907
- tags.map((tag)=>/*#__PURE__*/ jsx(SwatchChip, {
4908
- value: tag,
4909
- className: classNames.chip,
4910
- children: /*#__PURE__*/ jsx("button", {
4911
- type: "button",
4912
- disabled: pending,
4913
- "aria-label": `Remove ${tag}`,
4914
- className: classNames.chipRemove,
4915
- onClick: ()=>removeTag(tag),
4916
- children: /*#__PURE__*/ jsx(IconXmarkLine_default, {
4917
- size: 10
4918
- })
4919
- })
4920
- }, tag)),
4921
- /*#__PURE__*/ jsx("input", {
4922
- // biome-ignore lint/a11y/noAutofocus: this editor only ever mounts in response to an explicit click that just opened it (never on page load), matching `SelectEditor`'s own `open` (controlled, always-open-on-mount) -- the same UX every gated editor in this file already gives via a component the linter can't see through (`TextFieldInput`/`SelectSearchField`), just on a bare `<input>` here since `chipInput` has no such wrapper.
5004
+ /*#__PURE__*/ jsx(SelectSearchField, {
4923
5005
  autoFocus: true,
4924
- className: classNames.chipInput,
4925
- value: draft,
4926
- disabled: pending,
4927
- placeholder: tags.length ? "" : "Add…",
4928
- "aria-label": `Add tag to ${column.key}`,
4929
- onChange: (event)=>setDraft(event.target.value),
5006
+ value: query,
5007
+ onChange: setQuery,
5008
+ placeholder: column.editorSearchPlaceholder ?? "Search…",
5009
+ "aria-label": `Search ${column.key}`,
4930
5010
  onKeyDown: (event)=>{
4931
- // Escape is the ONE key this input must NOT stop propagation for: there is
4932
- // no in-progress draft state worth clearing locally (every add/remove
4933
- // already commits immediately), so it needs to bubble all the way to
4934
- // `document` -- `DataTableBodyCell`'s own Escape listener is what actually
4935
- // closes this popover. Every other key stops here, same as before, so it
4936
- // never reaches the row's own click/keyboard handling.
4937
- if (event.key === "Escape") return;
4938
- event.stopPropagation();
4939
- if (event.key === "Enter") {
4940
- event.preventDefault();
4941
- addTag();
4942
- } else if (event.key === "Backspace" && draft === "" && tags.length > 0) {
4943
- removeTag(tags[tags.length - 1]);
4944
- }
5011
+ if (event.key !== "Enter") return;
5012
+ event.preventDefault();
5013
+ if (pending) return;
5014
+ if (canCreate) create();
5015
+ else if (trimmed && filtered.length > 0) commitTags(toggleTag(tags, filtered[0].value));
4945
5016
  }
4946
5017
  }),
5018
+ /*#__PURE__*/ jsxs("div", {
5019
+ className: classNames.chipPickerList,
5020
+ role: "group",
5021
+ "aria-label": `${column.key} options`,
5022
+ children: [
5023
+ filtered.map((option)=>{
5024
+ const checked = tags.includes(option.value);
5025
+ return /*#__PURE__*/ jsxs("button", {
5026
+ type: "button",
5027
+ role: "checkbox",
5028
+ "aria-checked": checked,
5029
+ disabled: pending,
5030
+ className: classNames.chipPickerRow,
5031
+ // Keep focus in the search field so typing keeps filtering after a toggle.
5032
+ onMouseDown: (event)=>event.preventDefault(),
5033
+ onClick: ()=>commitTags(toggleTag(tags, option.value)),
5034
+ children: [
5035
+ /*#__PURE__*/ jsx(SwatchChip, {
5036
+ value: option.value,
5037
+ label: option.label,
5038
+ color: option.color,
5039
+ className: classNames.chip
5040
+ }),
5041
+ /*#__PURE__*/ jsx("span", {
5042
+ className: classNames.chipPickerBox,
5043
+ "data-checked": checked ? "" : undefined,
5044
+ children: checked && /*#__PURE__*/ jsx(IconCheckmarkFatFill_default, {
5045
+ "aria-hidden": "true"
5046
+ })
5047
+ })
5048
+ ]
5049
+ }, option.value);
5050
+ }),
5051
+ canCreate && /*#__PURE__*/ jsx("button", {
5052
+ type: "button",
5053
+ disabled: pending,
5054
+ className: classNames.chipPickerCreate,
5055
+ onMouseDown: (event)=>event.preventDefault(),
5056
+ onClick: create,
5057
+ children: `Create '${trimmed}'`
5058
+ }),
5059
+ !canCreate && filtered.length === 0 && /*#__PURE__*/ jsx(SelectSearchEmpty, {
5060
+ children: column.editorEmptyLabel ?? "No results"
5061
+ })
5062
+ ]
5063
+ }),
4947
5064
  pending && /*#__PURE__*/ jsx(EditPendingIndicator, {})
4948
5065
  ]
4949
5066
  }));
@@ -5032,44 +5149,6 @@ function CellExpandOverlay({ className, anchorRef, contentRef, children }) {
5032
5149
  }), document.body);
5033
5150
  }
5034
5151
 
5035
- // Row-narrowing for the toolbar's search box -- split out of DataTable.tsx the way
5036
- // cells.tsx splits out cell-type rendering: a self-contained, independently testable
5037
- // concern DataTable.tsx just calls, rather than inline `.filter()` calls piling up in
5038
- // the same component that also owns markup. The toolbar's typed Filter CONDITIONS
5039
- // (field/operator/value chips, DATATABLE-ATTIO-SPEC.md's Attio/crisp model) live in
5040
- // `toolbar-conditions.tsx` instead, alongside the Sort/Filter chrome that manages
5041
- // them -- this file is search only now; the old per-column "is/is not" picker
5042
- // (`matchesFilter`/`DataTableFilterState`) is gone, replaced by that toolbar model.
5043
- /**
5044
- * A column's `value(row)` if it supplies one, else the raw field at `column.key` --
5045
- * the single accessor sort/search/filter/export all read through
5046
- * (DATATABLE-ATTIO-SPEC.md's Column API), so a consumer only teaches the table how to
5047
- * read a value ONCE rather than once per feature.
5048
- */ function getColumnValue(column, row) {
5049
- return column.value ? column.value(row) : row[column.key];
5050
- }
5051
- /**
5052
- * Case-insensitive substring match against a row's stringified value -- crisp's own
5053
- * `applyFilters` "contains" semantics (`tabletoolbar.tsx`), reused here for the
5054
- * toolbar's single free-text query. `null`/`undefined` never match a non-empty query --
5055
- * there is no text to search.
5056
- */ function matchesSearch(value, query) {
5057
- if (!query) return true;
5058
- if (value == null) return false;
5059
- return String(value).toLowerCase().includes(query.toLowerCase());
5060
- }
5061
- /**
5062
- * The toolbar's search query -- an OR across `searchable` columns, matching GRC's own
5063
- * `useFilteredRows`. The toolbar's own typed Filter conditions apply SEPARATELY, as a
5064
- * second pass over this function's result (`toolbar-conditions.tsx`'s
5065
- * `applyToolbarFilters`, called by `DataTable.tsx` right after this) -- narrowing what
5066
- * the search box already found, not the other way round.
5067
- */ function getVisibleRows(data, columns, query) {
5068
- const searchableColumns = columns.filter((column)=>column.searchable);
5069
- if (!query) return data;
5070
- return data.filter((row)=>searchableColumns.some((column)=>matchesSearch(getColumnValue(column, row), query)));
5071
- }
5072
-
5073
5152
  // Feature C (#12) -- the click-to-expand gate: measures whether a cell's rendered
5074
5153
  // content is ACTUALLY truncated right now, so a single click only opens the
5075
5154
  // anchored overlay (editors.tsx's `CellExpandOverlay`) when there's real hidden
@@ -5135,7 +5214,10 @@ function isCellTruncated(cell) {
5135
5214
  * `overflow: visible` on every element in between and regardless of how high its
5136
5215
  * `z-index` is raised -- neither of which is a stacking-context or overflow bug
5137
5216
  * fixable from the INSIDE. A portal sidesteps it entirely by not being a
5138
- * descendant of the sticky `<td>` at all once mounted. */ function isChipListEditable(column) {
5217
+ * descendant of the sticky `<td>` at all once mounted. */ /** The table's full `data`, so an editable chip-list column with no `chipOptions` can
5218
+ * fall back to the distinct tags already present across rows. */ const DataTableRowsContext = /*#__PURE__*/ React.createContext([]);
5219
+ /** Attio's multi-select popover is wider than a narrow tags column. */ const CHIP_PICKER_MIN_WIDTH = 240;
5220
+ function isChipListEditable(column) {
5139
5221
  return !!column.editable && column.type === "chip-list";
5140
5222
  }
5141
5223
  function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyFirst, stickyLast, cellContextMenu, onViewEditHistory, cellContextMenuItems }) {
@@ -5195,6 +5277,7 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
5195
5277
  const [contextMenuOpen, setContextMenuOpen] = React.useState(false);
5196
5278
  const alwaysLive = isAlwaysLiveEditable(column);
5197
5279
  const chipListEditable = isChipListEditable(column);
5280
+ const allRows = React.useContext(DataTableRowsContext);
5198
5281
  // A gated `editable` column (everything except the always-live widgets AND the
5199
5282
  // click-to-edit chip-list) opens on double-click -- Attio's own measured gesture
5200
5283
  // (crisp's #411), matched here rather than a single click, which stays "select
@@ -5224,7 +5307,10 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
5224
5307
  top: rect.bottom,
5225
5308
  insetInlineStart: rect.left,
5226
5309
  insetInlineEnd: "auto",
5227
- minWidth: rect.width,
5310
+ minWidth: Math.max(rect.width, CHIP_PICKER_MIN_WIDTH),
5311
+ // The multi-select popover owns its own inner padding (search field + option
5312
+ // rows inset themselves); the overlay's cell-editor padding would double it.
5313
+ padding: 0,
5228
5314
  // Both override the SAME `expandOverlay` class properties this box also
5229
5315
  // carries (`className={classNames.expandOverlay}`, below) -- that class's
5230
5316
  // `minHeight: calc(100% + 2px)` resolves against an ANCHORED box's own
@@ -5371,7 +5457,10 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
5371
5457
  chipListEditorOpen,
5372
5458
  measurePopoverPosition
5373
5459
  ]);
5374
- const overlayActive = overlayOpen && (alwaysLive || isEditing(row.id, column.key) || isPeeking(row.id, column.key));
5460
+ // Never for a chip-list cell: its picker is its own portaled popover, and the
5461
+ // in-cell overlay box would show for the first frame only (a sync commit closes
5462
+ // `isEditing` on the first toggle) and overlap the popover's top edge.
5463
+ const overlayActive = overlayOpen && !chipListEditable && (alwaysLive || isEditing(row.id, column.key) || isPeeking(row.id, column.key));
5375
5464
  const rawValue = getColumnValue(column, row);
5376
5465
  const pending = isPending(row.id, column.key);
5377
5466
  return /*#__PURE__*/ jsxs(Fragment, {
@@ -5429,7 +5518,8 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
5429
5518
  value: resolveEditValue(column, row, rawValue),
5430
5519
  pending: pending,
5431
5520
  onCommit: (value)=>commitEdit(row.id, column.key, value),
5432
- classNames: classNames
5521
+ classNames: classNames,
5522
+ allRows: allRows
5433
5523
  })
5434
5524
  }), document.body)
5435
5525
  ]
@@ -5483,7 +5573,8 @@ function ColumnBodyCells({ columns, row, classNames, locale, selectable, stickyF
5483
5573
  value: rawValue,
5484
5574
  className: classNames.chipList,
5485
5575
  chipClassName: classNames.chip,
5486
- overflowClassName: classNames.chipOverflow
5576
+ overflowClassName: classNames.chipOverflow,
5577
+ chipOptions: column.chipOptions
5487
5578
  });
5488
5579
  } else if (column.editable && isEditing(rowId, column.key)) {
5489
5580
  if (column.editor === "select") {
@@ -5600,7 +5691,8 @@ function DisplayCellContent({ column, row, value, classNames, locale }) {
5600
5691
  value: value,
5601
5692
  className: classNames.chipList,
5602
5693
  chipClassName: classNames.chip,
5603
- overflowClassName: classNames.chipOverflow
5694
+ overflowClassName: classNames.chipOverflow,
5695
+ chipOptions: column.chipOptions
5604
5696
  });
5605
5697
  case "number":
5606
5698
  return /*#__PURE__*/ jsx(Fragment, {
@@ -5664,13 +5756,14 @@ const DataTableBulkBarClear = withContext$1(Primitive.button, "bulkBarClear");
5664
5756
  * exactly this reason -- see `data-table.ts`'s own `bulkBar` slot comment for why its
5665
5757
  * geometry borrows `contextual-floating-button`'s already-measured vars rather than a
5666
5758
  * guessed literal.
5667
- */ function DataTableBulkBar({ clearLabel = "Clear selection", children }) {
5759
+ */ function DataTableBulkBar({ clearLabel = "Clear selection", aboveFooter, children }) {
5668
5760
  const { selectedIds, clearSelection } = useDataTableContext();
5669
5761
  if (selectedIds.length === 0) return null;
5670
5762
  return /*#__PURE__*/ jsxs(DataTableBulkBarRoot, {
5671
5763
  role: "toolbar",
5672
5764
  "aria-label": "Bulk actions",
5673
5765
  "aria-orientation": "horizontal",
5766
+ "data-above-footer": aboveFooter ? "" : undefined,
5674
5767
  children: [
5675
5768
  /*#__PURE__*/ jsxs(DataTableBulkBarCount, {
5676
5769
  "aria-live": "polite",
@@ -5930,7 +6023,11 @@ const DEFAULT_SORT_ICON = {
5930
6023
  * component (not inlined in `DataTableInner`'s render) so it alone re-renders when
5931
6024
  * `visibleColumnOrder`/labels/widths change, without also re-deriving `sortedData`'s
5932
6025
  * render above it. */ function ColumnHeaderCells({ columns, columnMenu, reorderable, resizable, sortIcon, selectable, stickyFirst, stickyLast }) {
5933
- const { draggingColumnKey, beginColumnDrag, dragOverColumn, endColumnDrag } = useDataTableContext();
6026
+ const { draggingColumnKey, beginColumnDrag, dragOverColumn, endColumnDrag, visibleColumnOrder } = useDataTableContext();
6027
+ // Move left/right operate on the visible order, but never across the `actions`
6028
+ // column (the raw order re-pins it last, so a move onto/past it is a silent no-op).
6029
+ const actionsKey = columns.find((column)=>column.actions)?.key;
6030
+ const movableKeys = visibleColumnOrder.filter((key)=>key !== actionsKey);
5934
6031
  const effective = useEffectiveColumns(columns, {
5935
6032
  selectable,
5936
6033
  stickyFirst
@@ -5978,6 +6075,8 @@ const DEFAULT_SORT_ICON = {
5978
6075
  columnMenu && /*#__PURE__*/ jsx(ColumnMenu, {
5979
6076
  column: column,
5980
6077
  label: label,
6078
+ canMoveLeft: movableKeys.indexOf(column.key) > 0,
6079
+ canMoveRight: movableKeys.indexOf(column.key) !== -1 && movableKeys.indexOf(column.key) < movableKeys.length - 1,
5981
6080
  onRename: ()=>setRenamingKey(column.key)
5982
6081
  })
5983
6082
  ]
@@ -6069,8 +6168,8 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
6069
6168
  * `data-table.ts`) -- crisp's own header shows the trigger only on hover, not
6070
6169
  * permanently, so this one carries its own marker attribute distinct from that
6071
6170
  * slot's OTHER occupants (the sort chevron, the filter trigger), which stay visible
6072
- * under their own separate rules regardless of hover. */ function ColumnMenu({ column, label, onRename }) {
6073
- const { moveColumn, hideColumn, isColumnPinned, togglePinColumn, sort, clearSort } = useDataTableContext();
6171
+ * under their own separate rules regardless of hover. */ function ColumnMenu({ column, label, canMoveLeft, canMoveRight, onRename }) {
6172
+ const { moveColumn, hideColumn, isColumnPinned, togglePinColumn, sort, setSort, clearSort } = useDataTableContext();
6074
6173
  const columnLabel = typeof label === "string" ? label : column.key;
6075
6174
  const pinned = isColumnPinned(column.key);
6076
6175
  // Attio/GRC's "Remove sort" (live-review fix D) -- the header's own click-to-sort
@@ -6121,40 +6220,68 @@ function ColumnRenameInput({ column, initialLabel, onDone }) {
6121
6220
  },
6122
6221
  children: /*#__PURE__*/ jsxs(MenuScrollArea, {
6123
6222
  children: [
6124
- /*#__PURE__*/ jsx(MenuItem, {
6125
- onClick: onRename,
6126
- children: /*#__PURE__*/ jsx(MenuItemLabel, {
6127
- children: "Rename"
6128
- })
6223
+ column.sortable && /*#__PURE__*/ jsxs(Fragment, {
6224
+ children: [
6225
+ /*#__PURE__*/ jsx(MenuItem, {
6226
+ role: "menuitemradio",
6227
+ "aria-checked": isSorted && sort?.dir === "asc",
6228
+ onClick: ()=>setSort({
6229
+ key: column.key,
6230
+ dir: "asc"
6231
+ }),
6232
+ children: /*#__PURE__*/ jsx(MenuItemLabel, {
6233
+ children: "Sort ascending"
6234
+ })
6235
+ }),
6236
+ /*#__PURE__*/ jsx(MenuItem, {
6237
+ role: "menuitemradio",
6238
+ "aria-checked": isSorted && sort?.dir === "desc",
6239
+ onClick: ()=>setSort({
6240
+ key: column.key,
6241
+ dir: "desc"
6242
+ }),
6243
+ children: /*#__PURE__*/ jsx(MenuItemLabel, {
6244
+ children: "Sort descending"
6245
+ })
6246
+ }),
6247
+ isSorted && /*#__PURE__*/ jsx(MenuItem, {
6248
+ onClick: clearSort,
6249
+ children: /*#__PURE__*/ jsx(MenuItemLabel, {
6250
+ children: "Clear sort"
6251
+ })
6252
+ })
6253
+ ]
6129
6254
  }),
6130
6255
  /*#__PURE__*/ jsx(MenuItem, {
6256
+ disabled: !canMoveLeft,
6131
6257
  onClick: ()=>moveColumn(column.key, "left"),
6132
6258
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
6133
6259
  children: "Move left"
6134
6260
  })
6135
6261
  }),
6136
6262
  /*#__PURE__*/ jsx(MenuItem, {
6263
+ disabled: !canMoveRight,
6137
6264
  onClick: ()=>moveColumn(column.key, "right"),
6138
6265
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
6139
6266
  children: "Move right"
6140
6267
  })
6141
6268
  }),
6142
- isSorted && /*#__PURE__*/ jsx(MenuItem, {
6143
- onClick: clearSort,
6269
+ /*#__PURE__*/ jsx(MenuItem, {
6270
+ onClick: ()=>togglePinColumn(column.key),
6144
6271
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
6145
- children: "Clear sort"
6272
+ children: pinned ? "Unpin column" : "Pin column"
6146
6273
  })
6147
6274
  }),
6148
6275
  /*#__PURE__*/ jsx(MenuItem, {
6149
- onClick: ()=>togglePinColumn(column.key),
6276
+ onClick: onRename,
6150
6277
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
6151
- children: pinned ? "Unpin column" : "Pin column"
6278
+ children: "Edit column label"
6152
6279
  })
6153
6280
  }),
6154
6281
  /*#__PURE__*/ jsx(MenuItem, {
6155
6282
  onClick: ()=>hideColumn(column.key),
6156
6283
  children: /*#__PURE__*/ jsx(MenuItemLabel, {
6157
- children: "Hide column"
6284
+ children: "Hide from view"
6158
6285
  })
6159
6286
  })
6160
6287
  ]
@@ -11985,222 +12112,226 @@ function DataTableInner(props, ref) {
11985
12112
  const totalCols = columns.length + (selectable ? 1 : 0);
11986
12113
  return /*#__PURE__*/ jsx(ClassNamesProvider, {
11987
12114
  value: classNames,
11988
- children: /*#__PURE__*/ jsxs(DataTableRoot, {
11989
- ref: ref,
11990
- className: clsx(classNames.root, className),
11991
- rowIds: rowIds,
11992
- selectable: selectable,
11993
- selectedIds: selectedIds,
11994
- defaultSelectedIds: defaultSelectedIds,
11995
- onSelectionChange: onSelectionChange,
11996
- sort: sort,
11997
- defaultSort: defaultSort,
11998
- onSortChange: handleSortChange,
11999
- query: resolvedQuery,
12000
- onQueryChange: handleQueryChange,
12001
- toolbarSorts: resolvedToolbarSorts,
12002
- onToolbarSortsChange: handleToolbarSortsChange,
12003
- toolbarFilters: resolvedToolbarFilters,
12004
- onToolbarFiltersChange: handleToolbarFiltersChange,
12005
- columnKeys: columnKeys,
12006
- actionsColumnKey: actionsColumnKey,
12007
- columnOrder: columnOrder,
12008
- defaultColumnOrder: defaultColumnOrder,
12009
- onColumnOrderChange: onColumnOrderChange,
12010
- hiddenColumnKeys: hiddenColumnKeys,
12011
- defaultHiddenColumnKeys: defaultHiddenColumnKeys,
12012
- onHiddenColumnKeysChange: onHiddenColumnKeysChange,
12013
- columnWidths: columnWidths,
12014
- defaultColumnWidths: defaultColumnWidths,
12015
- onColumnWidthsChange: onColumnWidthsChange,
12016
- columnLabels: columnLabels,
12017
- defaultColumnLabels: defaultColumnLabels,
12018
- onColumnLabelsChange: onColumnLabelsChange,
12019
- pinnedColumnKeys: pinnedColumnKeys,
12020
- defaultPinnedColumnKeys: defaultPinnedColumnKeys,
12021
- onPinnedColumnKeysChange: onPinnedColumnKeysChange,
12022
- columnCalcOps: columnCalcOps,
12023
- defaultColumnCalcOps: defaultColumnCalcOps,
12024
- onColumnCalcOpsChange: onColumnCalcOpsChange,
12025
- onEdit: onEdit,
12026
- onLoadMore: onLoadMore,
12027
- hasMore: hasMore,
12028
- loadingMore: loadingMore,
12029
- virtualized: virtualized,
12030
- rowHeight: rowHeight,
12031
- overscan: overscan,
12032
- ...restProps,
12033
- children: [
12034
- onColumnsChange && /*#__PURE__*/ jsx(ColumnsChangeEffect, {
12035
- columns: columns,
12036
- onColumnsChange: onColumnsChange
12037
- }),
12038
- showToolbar && /*#__PURE__*/ jsxs(DataTableToolbar, {
12039
- children: [
12040
- searchable && /*#__PURE__*/ jsx(SearchBox, {
12041
- placeholder: searchPlaceholder,
12042
- label: searchLabel
12043
- }),
12044
- /*#__PURE__*/ jsx(SortControl, {
12045
- columns: columns
12046
- }),
12047
- /*#__PURE__*/ jsx(FilterControl, {
12048
- columns: columns
12049
- }),
12050
- (showCount || toolbarActions) && /*#__PURE__*/ jsxs(DataTableToolbarEnd, {
12051
- children: [
12052
- toolbarActions,
12053
- showCount && /*#__PURE__*/ jsx(RowCount, {
12054
- shown: sortedData.length,
12055
- total: data.length,
12056
- countLabel: countLabel
12057
- })
12058
- ]
12059
- })
12060
- ]
12061
- }),
12062
- /*#__PURE__*/ jsx(DataTableScrollBody, {
12063
- scrollProps: scrollProps,
12064
- virtualized: virtualized,
12065
- children: /*#__PURE__*/ jsxs(DataTableTable, {
12066
- "aria-rowcount": virtualized ? sortedData.length + 1 : undefined,
12115
+ children: /*#__PURE__*/ jsx(DataTableRowsContext.Provider, {
12116
+ value: data,
12117
+ children: /*#__PURE__*/ jsxs(DataTableRoot, {
12118
+ ref: ref,
12119
+ className: clsx(classNames.root, className),
12120
+ rowIds: rowIds,
12121
+ selectable: selectable,
12122
+ selectedIds: selectedIds,
12123
+ defaultSelectedIds: defaultSelectedIds,
12124
+ onSelectionChange: onSelectionChange,
12125
+ sort: sort,
12126
+ defaultSort: defaultSort,
12127
+ onSortChange: handleSortChange,
12128
+ query: resolvedQuery,
12129
+ onQueryChange: handleQueryChange,
12130
+ toolbarSorts: resolvedToolbarSorts,
12131
+ onToolbarSortsChange: handleToolbarSortsChange,
12132
+ toolbarFilters: resolvedToolbarFilters,
12133
+ onToolbarFiltersChange: handleToolbarFiltersChange,
12134
+ columnKeys: columnKeys,
12135
+ actionsColumnKey: actionsColumnKey,
12136
+ columnOrder: columnOrder,
12137
+ defaultColumnOrder: defaultColumnOrder,
12138
+ onColumnOrderChange: onColumnOrderChange,
12139
+ hiddenColumnKeys: hiddenColumnKeys,
12140
+ defaultHiddenColumnKeys: defaultHiddenColumnKeys,
12141
+ onHiddenColumnKeysChange: onHiddenColumnKeysChange,
12142
+ columnWidths: columnWidths,
12143
+ defaultColumnWidths: defaultColumnWidths,
12144
+ onColumnWidthsChange: onColumnWidthsChange,
12145
+ columnLabels: columnLabels,
12146
+ defaultColumnLabels: defaultColumnLabels,
12147
+ onColumnLabelsChange: onColumnLabelsChange,
12148
+ pinnedColumnKeys: pinnedColumnKeys,
12149
+ defaultPinnedColumnKeys: defaultPinnedColumnKeys,
12150
+ onPinnedColumnKeysChange: onPinnedColumnKeysChange,
12151
+ columnCalcOps: columnCalcOps,
12152
+ defaultColumnCalcOps: defaultColumnCalcOps,
12153
+ onColumnCalcOpsChange: onColumnCalcOpsChange,
12154
+ onEdit: onEdit,
12155
+ onLoadMore: onLoadMore,
12156
+ hasMore: hasMore,
12157
+ loadingMore: loadingMore,
12158
+ virtualized: virtualized,
12159
+ rowHeight: rowHeight,
12160
+ overscan: overscan,
12161
+ ...restProps,
12162
+ children: [
12163
+ onColumnsChange && /*#__PURE__*/ jsx(ColumnsChangeEffect, {
12164
+ columns: columns,
12165
+ onColumnsChange: onColumnsChange
12166
+ }),
12167
+ showToolbar && /*#__PURE__*/ jsxs(DataTableToolbar, {
12067
12168
  children: [
12068
- /*#__PURE__*/ jsx(DataTableColGroup, {
12069
- columns: columns,
12070
- selectable: !!selectable,
12071
- stickyFirst: stickyFirst
12169
+ searchable && /*#__PURE__*/ jsx(SearchBox, {
12170
+ placeholder: searchPlaceholder,
12171
+ label: searchLabel
12172
+ }),
12173
+ /*#__PURE__*/ jsx(SortControl, {
12174
+ columns: columns
12072
12175
  }),
12073
- /*#__PURE__*/ jsxs(DataTableHeader, {
12176
+ /*#__PURE__*/ jsx(FilterControl, {
12177
+ columns: columns
12178
+ }),
12179
+ (showCount || toolbarActions) && /*#__PURE__*/ jsxs(DataTableToolbarEnd, {
12074
12180
  children: [
12075
- selectable && /*#__PURE__*/ jsx(SelectionHeaderCell, {
12076
- stickyFirst: stickyFirst,
12077
- children: /*#__PURE__*/ jsx(SelectAllCheckbox, {
12078
- label: selectAllLabel,
12079
- checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON,
12080
- indeterminateIcon: selectionIndeterminateIcon ?? DEFAULT_INDETERMINATE_ICON
12081
- })
12082
- }),
12083
- /*#__PURE__*/ jsx(ColumnHeaderCells, {
12084
- columns: columns,
12085
- columnMenu: columnMenu,
12086
- reorderable: reorderable,
12087
- resizable: resizable,
12088
- sortIcon: sortIcon,
12089
- selectable: !!selectable,
12090
- stickyFirst: stickyFirst,
12091
- stickyLast: resolvedStickyLast
12181
+ toolbarActions,
12182
+ showCount && /*#__PURE__*/ jsx(RowCount, {
12183
+ shown: sortedData.length,
12184
+ total: data.length,
12185
+ countLabel: countLabel
12092
12186
  })
12093
12187
  ]
12094
- }),
12095
- /*#__PURE__*/ jsx(DataTableBody, {
12096
- children: loading ? /*#__PURE__*/ jsx("tr", {
12097
- children: /*#__PURE__*/ jsx(DataTableCell, {
12098
- colSpan: totalCols,
12099
- children: /*#__PURE__*/ jsx(LoadingStateContent, {
12100
- label: loadingLabel,
12101
- classNames: classNames
12188
+ })
12189
+ ]
12190
+ }),
12191
+ /*#__PURE__*/ jsx(DataTableScrollBody, {
12192
+ scrollProps: scrollProps,
12193
+ virtualized: virtualized,
12194
+ children: /*#__PURE__*/ jsxs(DataTableTable, {
12195
+ "aria-rowcount": virtualized ? sortedData.length + 1 : undefined,
12196
+ children: [
12197
+ /*#__PURE__*/ jsx(DataTableColGroup, {
12198
+ columns: columns,
12199
+ selectable: !!selectable,
12200
+ stickyFirst: stickyFirst
12201
+ }),
12202
+ /*#__PURE__*/ jsxs(DataTableHeader, {
12203
+ children: [
12204
+ selectable && /*#__PURE__*/ jsx(SelectionHeaderCell, {
12205
+ stickyFirst: stickyFirst,
12206
+ children: /*#__PURE__*/ jsx(SelectAllCheckbox, {
12207
+ label: selectAllLabel,
12208
+ checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON,
12209
+ indeterminateIcon: selectionIndeterminateIcon ?? DEFAULT_INDETERMINATE_ICON
12210
+ })
12211
+ }),
12212
+ /*#__PURE__*/ jsx(ColumnHeaderCells, {
12213
+ columns: columns,
12214
+ columnMenu: columnMenu,
12215
+ reorderable: reorderable,
12216
+ resizable: resizable,
12217
+ sortIcon: sortIcon,
12218
+ selectable: !!selectable,
12219
+ stickyFirst: stickyFirst,
12220
+ stickyLast: resolvedStickyLast
12102
12221
  })
12103
- })
12104
- }) : error ? /*#__PURE__*/ jsx("tr", {
12105
- children: /*#__PURE__*/ jsx(DataTableCell, {
12106
- colSpan: totalCols,
12107
- children: /*#__PURE__*/ jsx(EmptyStateContent, {
12108
- classNames: classNames,
12109
- children: error
12222
+ ]
12223
+ }),
12224
+ /*#__PURE__*/ jsx(DataTableBody, {
12225
+ children: loading ? /*#__PURE__*/ jsx("tr", {
12226
+ children: /*#__PURE__*/ jsx(DataTableCell, {
12227
+ colSpan: totalCols,
12228
+ children: /*#__PURE__*/ jsx(LoadingStateContent, {
12229
+ label: loadingLabel,
12230
+ classNames: classNames
12231
+ })
12110
12232
  })
12111
- })
12112
- }) : sortedData.length === 0 ? /*#__PURE__*/ jsx("tr", {
12113
- children: /*#__PURE__*/ jsx(DataTableCell, {
12114
- colSpan: totalCols,
12115
- children: /*#__PURE__*/ jsx(EmptyStateContent, {
12116
- classNames: classNames,
12117
- children: empty
12233
+ }) : error ? /*#__PURE__*/ jsx("tr", {
12234
+ children: /*#__PURE__*/ jsx(DataTableCell, {
12235
+ colSpan: totalCols,
12236
+ children: /*#__PURE__*/ jsx(EmptyStateContent, {
12237
+ classNames: classNames,
12238
+ children: error
12239
+ })
12118
12240
  })
12119
- })
12120
- }) : /*#__PURE__*/ jsxs(Fragment, {
12121
- children: [
12122
- /*#__PURE__*/ jsx(WindowedRows, {
12123
- rows: sortedData,
12124
- virtualized: virtualized,
12241
+ }) : sortedData.length === 0 ? /*#__PURE__*/ jsx("tr", {
12242
+ children: /*#__PURE__*/ jsx(DataTableCell, {
12125
12243
  colSpan: totalCols,
12126
- children: (windowRows, firstIndex)=>/*#__PURE__*/ jsx(Fragment, {
12127
- children: windowRows.map((row, offset)=>/*#__PURE__*/ jsxs(DataTableRow, {
12128
- rowId: row.id,
12129
- "aria-rowindex": virtualized ? firstIndex + offset + 2 : undefined,
12130
- "data-clickable": onRowClick ? "" : undefined,
12131
- onClick: onRowClick ? ()=>onRowClick(row) : undefined,
12132
- children: [
12133
- selectable && /*#__PURE__*/ jsx(SelectionCell, {
12134
- // The row itself carries `onClick={onRowClick}` above, and a
12135
- // native click on this cell's checkbox bubbles up through it
12136
- // (React attaches DataTableRow's handler on the <tr>, which
12137
- // sits between the checkbox and anything a consumer could stop
12138
- // it from at -- so this has to live here, not in the consumer).
12139
- // Without this, checking a row's box also fires `onRowClick`.
12140
- onClick: (event)=>event.stopPropagation(),
12141
- stickyFirst: stickyFirst,
12142
- children: /*#__PURE__*/ jsx(RowCheckbox, {
12143
- label: getRowSelectionLabel(row),
12144
- checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON
12244
+ children: /*#__PURE__*/ jsx(EmptyStateContent, {
12245
+ classNames: classNames,
12246
+ children: empty
12247
+ })
12248
+ })
12249
+ }) : /*#__PURE__*/ jsxs(Fragment, {
12250
+ children: [
12251
+ /*#__PURE__*/ jsx(WindowedRows, {
12252
+ rows: sortedData,
12253
+ virtualized: virtualized,
12254
+ colSpan: totalCols,
12255
+ children: (windowRows, firstIndex)=>/*#__PURE__*/ jsx(Fragment, {
12256
+ children: windowRows.map((row, offset)=>/*#__PURE__*/ jsxs(DataTableRow, {
12257
+ rowId: row.id,
12258
+ "aria-rowindex": virtualized ? firstIndex + offset + 2 : undefined,
12259
+ "data-clickable": onRowClick ? "" : undefined,
12260
+ onClick: onRowClick ? ()=>onRowClick(row) : undefined,
12261
+ children: [
12262
+ selectable && /*#__PURE__*/ jsx(SelectionCell, {
12263
+ // The row itself carries `onClick={onRowClick}` above, and a
12264
+ // native click on this cell's checkbox bubbles up through it
12265
+ // (React attaches DataTableRow's handler on the <tr>, which
12266
+ // sits between the checkbox and anything a consumer could stop
12267
+ // it from at -- so this has to live here, not in the consumer).
12268
+ // Without this, checking a row's box also fires `onRowClick`.
12269
+ onClick: (event)=>event.stopPropagation(),
12270
+ stickyFirst: stickyFirst,
12271
+ children: /*#__PURE__*/ jsx(RowCheckbox, {
12272
+ label: getRowSelectionLabel(row),
12273
+ checkedIcon: selectionCheckedIcon ?? DEFAULT_CHECKED_ICON
12274
+ })
12275
+ }),
12276
+ /*#__PURE__*/ jsx(ColumnBodyCells, {
12277
+ columns: columns,
12278
+ row: row,
12279
+ classNames: classNames,
12280
+ locale: locale,
12281
+ selectable: !!selectable,
12282
+ stickyFirst: stickyFirst,
12283
+ stickyLast: resolvedStickyLast,
12284
+ cellContextMenu: cellContextMenu,
12285
+ onViewEditHistory: onViewEditHistory,
12286
+ cellContextMenuItems: cellContextMenuItems
12145
12287
  })
12146
- }),
12147
- /*#__PURE__*/ jsx(ColumnBodyCells, {
12148
- columns: columns,
12149
- row: row,
12150
- classNames: classNames,
12151
- locale: locale,
12152
- selectable: !!selectable,
12153
- stickyFirst: stickyFirst,
12154
- stickyLast: resolvedStickyLast,
12155
- cellContextMenu: cellContextMenu,
12156
- onViewEditHistory: onViewEditHistory,
12157
- cellContextMenuItems: cellContextMenuItems
12158
- })
12159
- ]
12160
- }, row.id))
12161
- })
12288
+ ]
12289
+ }, row.id))
12290
+ })
12291
+ }),
12292
+ onLoadMore && /*#__PURE__*/ jsx(InfiniteScrollRow, {
12293
+ colSpan: totalCols,
12294
+ classNames: classNames,
12295
+ loadingLabel: loadingLabel
12296
+ })
12297
+ ]
12298
+ })
12299
+ }),
12300
+ showFooter && /*#__PURE__*/ jsxs(DataTableFooter, {
12301
+ children: [
12302
+ selectable && // The 40px-wide selection SPACER cell is now a plain `DataTableFooterCell`
12303
+ // (not the `selectionCell` slot) -- the `<colgroup>`'s own 40px `<col>`
12304
+ // is what makes every row's selection column line up now, not a matching
12305
+ // per-slot width formula, so there is no more reason for this cell to
12306
+ // borrow a different slot than its footer siblings.
12307
+ /*#__PURE__*/ jsx(SelectionFooterCell, {
12308
+ stickyFirst: stickyFirst
12162
12309
  }),
12163
- onLoadMore && /*#__PURE__*/ jsx(InfiniteScrollRow, {
12164
- colSpan: totalCols,
12165
- classNames: classNames,
12166
- loadingLabel: loadingLabel
12310
+ /*#__PURE__*/ jsx(ColumnCalcCells, {
12311
+ columns: columns,
12312
+ rows: sortedData,
12313
+ selectable: !!selectable,
12314
+ stickyFirst: stickyFirst,
12315
+ stickyLast: resolvedStickyLast
12167
12316
  })
12168
12317
  ]
12318
+ }),
12319
+ onAddRow && /*#__PURE__*/ jsx(AddRowFooter, {
12320
+ onAddRow: onAddRow,
12321
+ addRowLabel: addRowLabel,
12322
+ colSpan: totalCols,
12323
+ classNames: classNames
12169
12324
  })
12170
- }),
12171
- showFooter && /*#__PURE__*/ jsxs(DataTableFooter, {
12172
- children: [
12173
- selectable && // The 40px-wide selection SPACER cell is now a plain `DataTableFooterCell`
12174
- // (not the `selectionCell` slot) -- the `<colgroup>`'s own 40px `<col>`
12175
- // is what makes every row's selection column line up now, not a matching
12176
- // per-slot width formula, so there is no more reason for this cell to
12177
- // borrow a different slot than its footer siblings.
12178
- /*#__PURE__*/ jsx(SelectionFooterCell, {
12179
- stickyFirst: stickyFirst
12180
- }),
12181
- /*#__PURE__*/ jsx(ColumnCalcCells, {
12182
- columns: columns,
12183
- rows: sortedData,
12184
- selectable: !!selectable,
12185
- stickyFirst: stickyFirst,
12186
- stickyLast: resolvedStickyLast
12187
- })
12188
- ]
12189
- }),
12190
- onAddRow && /*#__PURE__*/ jsx(AddRowFooter, {
12191
- onAddRow: onAddRow,
12192
- addRowLabel: addRowLabel,
12193
- colSpan: totalCols,
12194
- classNames: classNames
12195
- })
12196
- ]
12325
+ ]
12326
+ })
12327
+ }),
12328
+ selectable && /*#__PURE__*/ jsx(DataTableBulkBar, {
12329
+ clearLabel: clearSelectionLabel,
12330
+ aboveFooter: showFooter || !!onAddRow,
12331
+ children: bulkActions
12197
12332
  })
12198
- }),
12199
- selectable && /*#__PURE__*/ jsx(DataTableBulkBar, {
12200
- clearLabel: clearSelectionLabel,
12201
- children: bulkActions
12202
- })
12203
- ]
12333
+ ]
12334
+ })
12204
12335
  })
12205
12336
  });
12206
12337
  }