@crisp-ui-kit/crisp 0.23.3 → 0.23.5

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.
@@ -114,5 +114,5 @@ function FileUpload({ className, labels, "aria-label": ariaLabel, accept, disabl
114
114
  // instead means attaching them here; without inputRef, `openFilePicker`
115
115
  // finds no input and returns silently, so the dropzone opens nothing.
116
116
  inputRef, dropzoneRef, } = api;
117
- return ((0, jsx_runtime_1.jsxs)("div", { ...rest, className: (0, fileupload_recipe_1.fileuploadRecipe)({ className }), children: [(0, jsx_runtime_1.jsxs)("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-title", children: t.title }), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-hint", children: t.hint })] }), (0, jsx_runtime_1.jsx)("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => ((0, jsx_runtime_1.jsxs)("li", { className: "fileupload-item", "data-status": entry.status, children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && ((0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: (0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), rejections.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => ((0, jsx_runtime_1.jsx)("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) }))] }));
117
+ return ((0, jsx_runtime_1.jsxs)("div", { ...rest, className: (0, fileupload_recipe_1.fileuploadRecipe)({ className }), children: [(0, jsx_runtime_1.jsxs)("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-title", children: t.title }), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-hint", children: t.hint })] }), (0, jsx_runtime_1.jsx)("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && ((0, jsx_runtime_1.jsx)("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => ((0, jsx_runtime_1.jsxs)("li", { className: "fileupload-item", "data-status": entry.status, children: [(0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && ((0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: (0, jsx_runtime_1.jsx)("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), (0, jsx_runtime_1.jsx)("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), (0, jsx_runtime_1.jsx)("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => ((0, jsx_runtime_1.jsx)("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) })] }));
118
118
  }
@@ -92,6 +92,10 @@ const config = (0, core_1.defineRecipe)({
92
92
  & .fileupload-remove:focus-visible { outline-color: ${tokens_1.contract.strokeFocusRing}; }
93
93
 
94
94
  & .fileupload-errors { display: flex; flex-direction: column; gap: ${tokens_1.contract.space["0.5"]}; margin: 0; padding: 0; list-style: none; }
95
+ /* out of flow while empty, so the always-mounted live region costs no
96
+ layout: display:none would take it out of the accessibility tree, which
97
+ is the one thing it exists to be in */
98
+ & .fileupload-errors:empty { position: absolute; }
95
99
  & .fileupload-error { color: ${tokens_1.contract.bgDanger}; font-size: ${tokens_1.contract.text.md}; line-height: 18px; }
96
100
  `,
97
101
  variants: {},
@@ -48,7 +48,7 @@ const ICONS = {
48
48
  };
49
49
  function ToastCard({ item, onClose, dismissLabel, }) {
50
50
  const Icon = ICONS[item.tone ?? "info"];
51
- return ((0, jsx_runtime_1.jsxs)("div", { className: "toast", role: "status", "data-tone": item.tone ?? "info", children: [(0, jsx_runtime_1.jsx)("span", { className: "toast-icon", children: (0, jsx_runtime_1.jsx)(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "toast-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "toast-title", children: item.title }), item.description != null && ((0, jsx_runtime_1.jsx)("div", { className: "toast-desc", children: item.description })), item.action && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "toast-action", onClick: () => {
51
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "toast", "data-tone": item.tone ?? "info", children: [(0, jsx_runtime_1.jsx)("span", { className: "toast-icon", children: (0, jsx_runtime_1.jsx)(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), (0, jsx_runtime_1.jsxs)("div", { className: "toast-body", children: [(0, jsx_runtime_1.jsx)("div", { className: "toast-title", children: item.title }), item.description != null && ((0, jsx_runtime_1.jsx)("div", { className: "toast-desc", children: item.description })), item.action && ((0, jsx_runtime_1.jsx)("button", { type: "button", className: "toast-action", onClick: () => {
52
52
  item.action?.onClick();
53
53
  onClose();
54
54
  }, children: item.action.label }))] }), (0, jsx_runtime_1.jsx)("button", { type: "button", className: "toast-close", "aria-label": dismissLabel, onClick: onClose, children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 15, strokeWidth: 2, "aria-hidden": "true" }) })] }));
@@ -84,7 +84,7 @@ function ToastProvider({ children, duration = 4000, dismissLabel = "Dismiss", re
84
84
  return () => map.forEach(clearTimeout);
85
85
  }, []);
86
86
  const api = React.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
87
- return ((0, jsx_runtime_1.jsxs)(ToastContext.Provider, { value: api, children: [children, (0, jsx_runtime_1.jsx)("div", { className: (0, toast_recipe_1.toastRecipe)(), children: (0, jsx_runtime_1.jsx)("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, children: items.map((t) => ((0, jsx_runtime_1.jsx)(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
87
+ return ((0, jsx_runtime_1.jsxs)(ToastContext.Provider, { value: api, children: [children, (0, jsx_runtime_1.jsx)("div", { className: (0, toast_recipe_1.toastRecipe)(), children: (0, jsx_runtime_1.jsx)("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, "aria-live": "polite", "aria-atomic": "false", children: items.map((t) => ((0, jsx_runtime_1.jsx)(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
88
88
  }
89
89
  ToastProvider.displayName = "ToastProvider";
90
90
  function useToast() {
@@ -1045,7 +1045,13 @@ function RecordsTable({ labels, columns: columnsProp = exports.defaultColumns, r
1045
1045
  const canEdit = canEditCol(col);
1046
1046
  const isPicker = isPickerCol(col);
1047
1047
  const isEditing = editing?.id === row.id && editing?.key === col.key;
1048
- 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
1049
1055
  ? ""
1050
1056
  : undefined, onClick: () => {
1051
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; }
@@ -77,5 +77,5 @@ export function FileUpload({ className, labels, "aria-label": ariaLabel, accept,
77
77
  // instead means attaching them here; without inputRef, `openFilePicker`
78
78
  // finds no input and returns silently, so the dropzone opens nothing.
79
79
  inputRef, dropzoneRef, } = api;
80
- return (_jsxs("div", { ...rest, className: fileuploadRecipe({ className }), children: [_jsxs("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [_jsx("span", { className: "fileupload-title", children: t.title }), _jsx("span", { className: "fileupload-hint", children: t.hint })] }), _jsx("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && (_jsx("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => (_jsxs("li", { className: "fileupload-item", "data-status": entry.status, children: [_jsx("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && (_jsx("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: _jsx("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), _jsx("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), _jsx("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: _jsx(X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), rejections.length > 0 && (_jsx("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => (_jsx("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) }))] }));
80
+ return (_jsxs("div", { ...rest, className: fileuploadRecipe({ className }), children: [_jsxs("button", { ...dropzoneProps, ref: dropzoneRef, type: "button", className: "fileupload-zone", tabIndex: disabled ? -1 : 0, "aria-label": ariaLabel ?? t.hint, disabled: disabled, "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, "data-invalid": invalid ? "" : undefined, onClick: () => openFilePicker(), children: [_jsx("span", { className: "fileupload-title", children: t.title }), _jsx("span", { className: "fileupload-hint", children: t.hint })] }), _jsx("input", { ...hiddenInputProps, ref: inputRef, className: "fileupload-input" }), acceptedFileEntries.length > 0 && (_jsx("ul", { className: "fileupload-list", children: acceptedFileEntries.map((entry) => (_jsxs("li", { className: "fileupload-item", "data-status": entry.status, children: [_jsx("span", { className: "fileupload-item-name", children: entry.file.name }), entry.status === "uploading" && entry.progress != null && (_jsx("span", { className: "fileupload-progress", role: "progressbar", "aria-valuenow": Math.round(entry.progress), "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": entry.file.name, children: _jsx("span", { className: "fileupload-progress-fill", style: { width: `${entry.progress}%` } }) })), _jsx("span", { className: "fileupload-item-size", children: formatSize(entry.file.size) }), _jsx("button", { type: "button", className: "fileupload-remove", "aria-label": `${t.remove}: ${entry.file.name}`, onClick: () => removeFileEntry(entry.id), children: _jsx(X, { size: 13, strokeWidth: 2 }) })] }, entry.id))) })), _jsx("ul", { className: "fileupload-errors", "aria-live": "polite", children: rejections.map((r) => (_jsx("li", { className: "fileupload-error", children: `${r.file.name}: ${r.errors.map((e) => t.errors[e] ?? e).join(" ")}` }, r.file.name))) })] }));
81
81
  }
@@ -89,6 +89,10 @@ const config = defineRecipe({
89
89
  & .fileupload-remove:focus-visible { outline-color: ${c.strokeFocusRing}; }
90
90
 
91
91
  & .fileupload-errors { display: flex; flex-direction: column; gap: ${c.space["0.5"]}; margin: 0; padding: 0; list-style: none; }
92
+ /* out of flow while empty, so the always-mounted live region costs no
93
+ layout: display:none would take it out of the accessibility tree, which
94
+ is the one thing it exists to be in */
95
+ & .fileupload-errors:empty { position: absolute; }
92
96
  & .fileupload-error { color: ${c.bgDanger}; font-size: ${c.text.md}; line-height: 18px; }
93
97
  `,
94
98
  variants: {},
@@ -11,7 +11,7 @@ const ICONS = {
11
11
  };
12
12
  function ToastCard({ item, onClose, dismissLabel, }) {
13
13
  const Icon = ICONS[item.tone ?? "info"];
14
- return (_jsxs("div", { className: "toast", role: "status", "data-tone": item.tone ?? "info", children: [_jsx("span", { className: "toast-icon", children: _jsx(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), _jsxs("div", { className: "toast-body", children: [_jsx("div", { className: "toast-title", children: item.title }), item.description != null && (_jsx("div", { className: "toast-desc", children: item.description })), item.action && (_jsx("button", { type: "button", className: "toast-action", onClick: () => {
14
+ return (_jsxs("div", { className: "toast", "data-tone": item.tone ?? "info", children: [_jsx("span", { className: "toast-icon", children: _jsx(Icon, { size: 16, strokeWidth: 1.75, "aria-hidden": "true" }) }), _jsxs("div", { className: "toast-body", children: [_jsx("div", { className: "toast-title", children: item.title }), item.description != null && (_jsx("div", { className: "toast-desc", children: item.description })), item.action && (_jsx("button", { type: "button", className: "toast-action", onClick: () => {
15
15
  item.action?.onClick();
16
16
  onClose();
17
17
  }, children: item.action.label }))] }), _jsx("button", { type: "button", className: "toast-close", "aria-label": dismissLabel, onClick: onClose, children: _jsx(X, { size: 15, strokeWidth: 2, "aria-hidden": "true" }) })] }));
@@ -47,7 +47,7 @@ export function ToastProvider({ children, duration = 4000, dismissLabel = "Dismi
47
47
  return () => map.forEach(clearTimeout);
48
48
  }, []);
49
49
  const api = React.useMemo(() => ({ toast, dismiss }), [toast, dismiss]);
50
- return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx("div", { className: toastRecipe(), children: _jsx("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, children: items.map((t) => (_jsx(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
50
+ return (_jsxs(ToastContext.Provider, { value: api, children: [children, _jsx("div", { className: toastRecipe(), children: _jsx("div", { className: "toast-viewport", role: "region", "aria-label": regionLabel, "aria-live": "polite", "aria-atomic": "false", children: items.map((t) => (_jsx(ToastCard, { item: t, onClose: () => dismiss(t.id), dismissLabel: dismissLabel }, t.id))) }) })] }));
51
51
  }
52
52
  ToastProvider.displayName = "ToastProvider";
53
53
  export function useToast() {
@@ -1005,7 +1005,13 @@ export function RecordsTable({ labels, columns: columnsProp = defaultColumns, ro
1005
1005
  const canEdit = canEditCol(col);
1006
1006
  const isPicker = isPickerCol(col);
1007
1007
  const isEditing = editing?.id === row.id && editing?.key === col.key;
1008
- 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
1009
1015
  ? ""
1010
1016
  : undefined, onClick: () => {
1011
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; }
@@ -72,6 +72,10 @@
72
72
  & .fileupload-remove:focus-visible { outline-color: var(--stroke-focus-ring); }
73
73
 
74
74
  & .fileupload-errors { display: flex; flex-direction: column; gap: var(--space-0-5); margin: 0; padding: 0; list-style: none; }
75
+ /* out of flow while empty, so the always-mounted live region costs no
76
+ layout: display:none would take it out of the accessibility tree, which
77
+ is the one thing it exists to be in */
78
+ & .fileupload-errors:empty { position: absolute; }
75
79
  & .fileupload-error { color: var(--bg-danger); font-size: var(--text-md); line-height: 18px; }
76
80
 
77
81
  }
@@ -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
@@ -950,6 +950,10 @@
950
950
  & .fileupload-remove:focus-visible { outline-color: var(--stroke-focus-ring); }
951
951
 
952
952
  & .fileupload-errors { display: flex; flex-direction: column; gap: var(--space-0-5); margin: 0; padding: 0; list-style: none; }
953
+ /* out of flow while empty, so the always-mounted live region costs no
954
+ layout: display:none would take it out of the accessibility tree, which
955
+ is the one thing it exists to be in */
956
+ & .fileupload-errors:empty { position: absolute; }
953
957
  & .fileupload-error { color: var(--bg-danger); font-size: var(--text-md); line-height: 18px; }
954
958
 
955
959
  }
@@ -2499,7 +2503,10 @@
2499
2503
  & .recordstable-addcol button:hover { background: var(--bg-raised); color: var(--fg-primary); }
2500
2504
 
2501
2505
  /* cells */
2502
- & .recordstable-td { font-size: var(--text-lg); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
2506
+ /* font-weight is explicit because the first cell of each row is a
2507
+ th[scope=row] — the record's name is what the row IS — and a th
2508
+ defaults to bold. Measured before the change and unchanged after: 400. */
2509
+ & .recordstable-td { font-size: var(--text-lg); font-weight: var(--weight-regular); color: var(--fg-primary); background: var(--bg-surface); cursor: default; }
2503
2510
  & .recordstable-td--editable { cursor: text; }
2504
2511
  /* keyboard/click cell selection (spreadsheet-style) */
2505
2512
  & .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.3",
3
+ "version": "0.23.5",
4
4
  "description": "A lean React design system, measured pixel-for-pixel from Attio.",
5
5
  "license": "MIT",
6
6
  "type": "module",