@crisp-ui-kit/crisp 0.23.2 → 0.23.4

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.
@@ -452,8 +452,22 @@ function DataTable({ columns: columnsProp, data, selectable = false, selectedIds
452
452
  ...(scrolledX ? { "data-scrolled-x": "" } : {}),
453
453
  }, children: [(0, jsx_runtime_1.jsxs)("colgroup", { children: [showGrip && (0, jsx_runtime_1.jsx)("col", { style: { width: GRIP_W } }), selectable && (0, jsx_runtime_1.jsx)("col", { style: { width: CHECK_W } }), columns.map((col) => ((0, jsx_runtime_1.jsx)("col", { style: { width: colWidth(col) } }, col.key)))] }), (0, jsx_runtime_1.jsx)(table_1.TableHeader, { children: (0, jsx_runtime_1.jsxs)(table_1.TableRow, { children: [showGrip && ((0, jsx_runtime_1.jsx)(table_1.TableHead, { className: "datatable-col-grip", ...stickyCol(-2) })), selectable && ((0, jsx_runtime_1.jsx)(table_1.TableHead, { className: "datatable-col-check", ...stickyCol(-1), children: (0, jsx_runtime_1.jsx)("span", { className: "datatable-check", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { "aria-label": selectAllLabel, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
454
454
  const Icon = col.icon;
455
+ // The sort direction was painted (`data-sorted`) and never
456
+ // announced: a screen reader heard the same header before and
457
+ // after sorting (#229). Only the PRIMARY sort is exposed —
458
+ // aria-sort is specified as one header per table, and with the
459
+ // multi-sort the `sort` prop allows, a second "ascending" says
460
+ // nothing about which column came first.
461
+ const sortable = col.sortable || !!columnMenu;
462
+ const ariaSort = !sortable
463
+ ? undefined
464
+ : sorts[0]?.key === col.key
465
+ ? sorts[0].dir === "asc"
466
+ ? "ascending"
467
+ : "descending"
468
+ : "none";
455
469
  const inner = ((0, jsx_runtime_1.jsxs)("span", { className: "datatable-th-inner", children: [Icon ? (0, jsx_runtime_1.jsx)(Icon, { size: 14, strokeWidth: 1.75 }) : null, (0, jsx_runtime_1.jsx)("span", { className: "datatable-th-label", children: col.header }), col.sortable ? (0, jsx_runtime_1.jsx)(ChevronFor, { colKey: col.key }) : null] }));
456
- return ((0, jsx_runtime_1.jsxs)(table_1.TableHead, { align: alignFor(col), ...stickyCol(i), children: [renaming === col.key ? ((0, jsx_runtime_1.jsx)("input", {
470
+ return ((0, jsx_runtime_1.jsxs)(table_1.TableHead, { align: alignFor(col), "aria-sort": ariaSort, ...stickyCol(i), children: [renaming === col.key ? ((0, jsx_runtime_1.jsx)("input", {
457
471
  // biome-ignore lint/a11y/noAutofocus: the rename item opens this field
458
472
  autoFocus: true, className: "datatable-th-rename", defaultValue: typeof col.header === "string" ? col.header : "", "aria-label": `Rename column`, onBlur: (e) => {
459
473
  renameColumn(col.key, e.currentTarget.value);
@@ -1002,7 +1002,11 @@ function RecordsTable({ labels, columns: columnsProp = exports.defaultColumns, r
1002
1002
  }, children: [(0, jsx_runtime_1.jsxs)("colgroup", { children: [(0, jsx_runtime_1.jsx)("col", { style: { width: CHECK_W } }), cols.map((col) => ((0, jsx_runtime_1.jsx)("col", { style: { width: colWidth(col) } }, col.key))), (0, jsx_runtime_1.jsx)("col", {})] }), (0, jsx_runtime_1.jsx)("thead", { children: (0, jsx_runtime_1.jsxs)("tr", { children: [(0, jsx_runtime_1.jsx)("th", { className: "recordstable-th recordstable-col-check", children: (0, jsx_runtime_1.jsx)("span", { className: "recordstable-check-inner", children: (0, jsx_runtime_1.jsx)(checkbox_1.Checkbox, { "aria-label": t.selectAll, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) }), cols.map((col, i) => {
1003
1003
  const Icon = col.icon;
1004
1004
  const sc = sorts.find((s) => s.key === col.key);
1005
- return ((0, jsx_runtime_1.jsxs)("th", { className: `recordstable-th${i === 0 ? " recordstable-col-entity" : ""}`, "data-sorted": sc?.dir, "data-drop": dragCol && dragCol !== col.key && i >= 1 ? "" : undefined, onDragOver: dragCol && i >= 1 ? (e) => e.preventDefault() : undefined, onDrop: dragCol && i >= 1
1005
+ return ((0, jsx_runtime_1.jsxs)("th", { className: `recordstable-th${i === 0 ? " recordstable-col-entity" : ""}`, "data-sorted": sc?.dir, "aria-sort": sorts[0]?.key === col.key
1006
+ ? sorts[0].dir === "asc"
1007
+ ? "ascending"
1008
+ : "descending"
1009
+ : "none", "data-drop": dragCol && dragCol !== col.key && i >= 1 ? "" : undefined, onDragOver: dragCol && i >= 1 ? (e) => e.preventDefault() : undefined, onDrop: dragCol && i >= 1
1006
1010
  ? (e) => {
1007
1011
  e.preventDefault();
1008
1012
  reorderColumn(dragCol, col.key);
@@ -1041,7 +1045,13 @@ function RecordsTable({ labels, columns: columnsProp = exports.defaultColumns, r
1041
1045
  const canEdit = canEditCol(col);
1042
1046
  const isPicker = isPickerCol(col);
1043
1047
  const isEditing = editing?.id === row.id && editing?.key === col.key;
1044
- return ((0, jsx_runtime_1.jsxs)("td", { className: `recordstable-td${i === 0 ? " recordstable-col-entity" : ""}${canEdit ? " recordstable-td--editable" : ""}${isPicker ? " recordstable-td--picker" : ""}`, "data-enriched": col.enriched ? "" : undefined, "data-selected": selCell?.id === row.id && selCell?.key === col.key
1048
+ // The first column is the record's NAME — it is what the row
1049
+ // is, not a value the row has. As a `<th scope="row">` a
1050
+ // screen reader reads "Google, Employees, 182,000" across the
1051
+ // row instead of a bare "182,000", and the same header is
1052
+ // repeated in every cell's context (#231).
1053
+ const Cell = (i === 0 ? "th" : "td");
1054
+ return ((0, jsx_runtime_1.jsxs)(Cell, { scope: i === 0 ? "row" : undefined, className: `recordstable-td${i === 0 ? " recordstable-col-entity" : ""}${canEdit ? " recordstable-td--editable" : ""}${isPicker ? " recordstable-td--picker" : ""}`, "data-enriched": col.enriched ? "" : undefined, "data-selected": selCell?.id === row.id && selCell?.key === col.key
1045
1055
  ? ""
1046
1056
  : undefined, onClick: () => {
1047
1057
  if (isPicker)
@@ -56,7 +56,10 @@ ${(0, tabletoolbar_chrome_1.toolbarChromeBody)("recordstable")}
56
56
  & .recordstable-addcol button:hover { background: ${tokens_1.contract.bgRaised}; color: ${tokens_1.contract.fgPrimary}; }
57
57
 
58
58
  /* cells */
59
- & .recordstable-td { font-size: ${tokens_1.contract.text.lg}; color: ${tokens_1.contract.fgPrimary}; background: ${tokens_1.contract.bgSurface}; cursor: default; }
59
+ /* font-weight is explicit because the first cell of each row is a
60
+ th[scope=row] — the record's name is what the row IS — and a th
61
+ defaults to bold. Measured before the change and unchanged after: 400. */
62
+ & .recordstable-td { font-size: ${tokens_1.contract.text.lg}; font-weight: ${tokens_1.contract.weight.regular}; color: ${tokens_1.contract.fgPrimary}; background: ${tokens_1.contract.bgSurface}; cursor: default; }
60
63
  & .recordstable-td--editable { cursor: text; }
61
64
  /* keyboard/click cell selection (spreadsheet-style) */
62
65
  & .recordstable-td[data-selected] { outline: 2px solid ${tokens_1.contract.bgBrandSolid}; outline-offset: -2px; border-radius: ${tokens_1.contract.radius.sm}; z-index: 3; }
@@ -416,8 +416,22 @@ export function DataTable({ columns: columnsProp, data, selectable = false, sele
416
416
  ...(scrolledX ? { "data-scrolled-x": "" } : {}),
417
417
  }, children: [_jsxs("colgroup", { children: [showGrip && _jsx("col", { style: { width: GRIP_W } }), selectable && _jsx("col", { style: { width: CHECK_W } }), columns.map((col) => (_jsx("col", { style: { width: colWidth(col) } }, col.key)))] }), _jsx(TableHeader, { children: _jsxs(TableRow, { children: [showGrip && (_jsx(TableHead, { className: "datatable-col-grip", ...stickyCol(-2) })), selectable && (_jsx(TableHead, { className: "datatable-col-check", ...stickyCol(-1), children: _jsx("span", { className: "datatable-check", children: _jsx(Checkbox, { "aria-label": selectAllLabel, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) })), columns.map((col, i) => {
418
418
  const Icon = col.icon;
419
+ // The sort direction was painted (`data-sorted`) and never
420
+ // announced: a screen reader heard the same header before and
421
+ // after sorting (#229). Only the PRIMARY sort is exposed —
422
+ // aria-sort is specified as one header per table, and with the
423
+ // multi-sort the `sort` prop allows, a second "ascending" says
424
+ // nothing about which column came first.
425
+ const sortable = col.sortable || !!columnMenu;
426
+ const ariaSort = !sortable
427
+ ? undefined
428
+ : sorts[0]?.key === col.key
429
+ ? sorts[0].dir === "asc"
430
+ ? "ascending"
431
+ : "descending"
432
+ : "none";
419
433
  const inner = (_jsxs("span", { className: "datatable-th-inner", children: [Icon ? _jsx(Icon, { size: 14, strokeWidth: 1.75 }) : null, _jsx("span", { className: "datatable-th-label", children: col.header }), col.sortable ? _jsx(ChevronFor, { colKey: col.key }) : null] }));
420
- return (_jsxs(TableHead, { align: alignFor(col), ...stickyCol(i), children: [renaming === col.key ? (_jsx("input", {
434
+ return (_jsxs(TableHead, { align: alignFor(col), "aria-sort": ariaSort, ...stickyCol(i), children: [renaming === col.key ? (_jsx("input", {
421
435
  // biome-ignore lint/a11y/noAutofocus: the rename item opens this field
422
436
  autoFocus: true, className: "datatable-th-rename", defaultValue: typeof col.header === "string" ? col.header : "", "aria-label": `Rename column`, onBlur: (e) => {
423
437
  renameColumn(col.key, e.currentTarget.value);
@@ -962,7 +962,11 @@ export function RecordsTable({ labels, columns: columnsProp = defaultColumns, ro
962
962
  }, children: [_jsxs("colgroup", { children: [_jsx("col", { style: { width: CHECK_W } }), cols.map((col) => (_jsx("col", { style: { width: colWidth(col) } }, col.key))), _jsx("col", {})] }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: "recordstable-th recordstable-col-check", children: _jsx("span", { className: "recordstable-check-inner", children: _jsx(Checkbox, { "aria-label": t.selectAll, checked: allSelected, indeterminate: someSelected, onChange: toggleAll }) }) }), cols.map((col, i) => {
963
963
  const Icon = col.icon;
964
964
  const sc = sorts.find((s) => s.key === col.key);
965
- return (_jsxs("th", { className: `recordstable-th${i === 0 ? " recordstable-col-entity" : ""}`, "data-sorted": sc?.dir, "data-drop": dragCol && dragCol !== col.key && i >= 1 ? "" : undefined, onDragOver: dragCol && i >= 1 ? (e) => e.preventDefault() : undefined, onDrop: dragCol && i >= 1
965
+ return (_jsxs("th", { className: `recordstable-th${i === 0 ? " recordstable-col-entity" : ""}`, "data-sorted": sc?.dir, "aria-sort": sorts[0]?.key === col.key
966
+ ? sorts[0].dir === "asc"
967
+ ? "ascending"
968
+ : "descending"
969
+ : "none", "data-drop": dragCol && dragCol !== col.key && i >= 1 ? "" : undefined, onDragOver: dragCol && i >= 1 ? (e) => e.preventDefault() : undefined, onDrop: dragCol && i >= 1
966
970
  ? (e) => {
967
971
  e.preventDefault();
968
972
  reorderColumn(dragCol, col.key);
@@ -1001,7 +1005,13 @@ export function RecordsTable({ labels, columns: columnsProp = defaultColumns, ro
1001
1005
  const canEdit = canEditCol(col);
1002
1006
  const isPicker = isPickerCol(col);
1003
1007
  const isEditing = editing?.id === row.id && editing?.key === col.key;
1004
- return (_jsxs("td", { className: `recordstable-td${i === 0 ? " recordstable-col-entity" : ""}${canEdit ? " recordstable-td--editable" : ""}${isPicker ? " recordstable-td--picker" : ""}`, "data-enriched": col.enriched ? "" : undefined, "data-selected": selCell?.id === row.id && selCell?.key === col.key
1008
+ // The first column is the record's NAME — it is what the row
1009
+ // is, not a value the row has. As a `<th scope="row">` a
1010
+ // screen reader reads "Google, Employees, 182,000" across the
1011
+ // row instead of a bare "182,000", and the same header is
1012
+ // repeated in every cell's context (#231).
1013
+ const Cell = (i === 0 ? "th" : "td");
1014
+ return (_jsxs(Cell, { scope: i === 0 ? "row" : undefined, className: `recordstable-td${i === 0 ? " recordstable-col-entity" : ""}${canEdit ? " recordstable-td--editable" : ""}${isPicker ? " recordstable-td--picker" : ""}`, "data-enriched": col.enriched ? "" : undefined, "data-selected": selCell?.id === row.id && selCell?.key === col.key
1005
1015
  ? ""
1006
1016
  : undefined, onClick: () => {
1007
1017
  if (isPicker)
@@ -53,7 +53,10 @@ ${toolbarChromeBody("recordstable")}
53
53
  & .recordstable-addcol button:hover { background: ${c.bgRaised}; color: ${c.fgPrimary}; }
54
54
 
55
55
  /* cells */
56
- & .recordstable-td { font-size: ${c.text.lg}; color: ${c.fgPrimary}; background: ${c.bgSurface}; cursor: default; }
56
+ /* font-weight is explicit because the first cell of each row is a
57
+ th[scope=row] — the record's name is what the row IS — and a th
58
+ defaults to bold. Measured before the change and unchanged after: 400. */
59
+ & .recordstable-td { font-size: ${c.text.lg}; font-weight: ${c.weight.regular}; color: ${c.fgPrimary}; background: ${c.bgSurface}; cursor: default; }
57
60
  & .recordstable-td--editable { cursor: text; }
58
61
  /* keyboard/click cell selection (spreadsheet-style) */
59
62
  & .recordstable-td[data-selected] { outline: 2px solid ${c.bgBrandSolid}; outline-offset: -2px; border-radius: ${c.radius.sm}; z-index: 3; }
@@ -101,7 +101,10 @@
101
101
  & .recordstable-addcol button:hover { background: var(--bg-raised); color: var(--fg-primary); }
102
102
 
103
103
  /* cells */
104
- & .recordstable-td { font-size: var(--text-lg); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
104
+ /* font-weight is explicit because the first cell of each row is a
105
+ th[scope=row] — the record's name is what the row IS — and a th
106
+ defaults to bold. Measured before the change and unchanged after: 400. */
107
+ & .recordstable-td { font-size: var(--text-lg); font-weight: var(--weight-regular); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
105
108
  & .recordstable-td--editable { cursor: text; }
106
109
  /* keyboard/click cell selection (spreadsheet-style) */
107
110
  & .recordstable-td[data-selected] { outline: 2px solid var(--bg-brand-solid); outline-offset: -2px; border-radius: var(--radius-sm); z-index: 3; }
package/dist/styles.css CHANGED
@@ -2499,7 +2499,10 @@
2499
2499
  & .recordstable-addcol button:hover { background: var(--bg-raised); color: var(--fg-primary); }
2500
2500
 
2501
2501
  /* cells */
2502
- & .recordstable-td { font-size: var(--text-lg); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
2502
+ /* font-weight is explicit because the first cell of each row is a
2503
+ th[scope=row] — the record's name is what the row IS — and a th
2504
+ defaults to bold. Measured before the change and unchanged after: 400. */
2505
+ & .recordstable-td { font-size: var(--text-lg); font-weight: var(--weight-regular); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
2503
2506
  & .recordstable-td--editable { cursor: text; }
2504
2507
  /* keyboard/click cell selection (spreadsheet-style) */
2505
2508
  & .recordstable-td[data-selected] { outline: 2px solid var(--bg-brand-solid); outline-offset: -2px; border-radius: var(--radius-sm); z-index: 3; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crisp-ui-kit/crisp",
3
- "version": "0.23.2",
3
+ "version": "0.23.4",
4
4
  "description": "A lean React design system, measured pixel-for-pixel from Attio.",
5
5
  "license": "MIT",
6
6
  "type": "module",