@atelic-action/artifact 5.1.0 → 5.1.2

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/README.md CHANGED
@@ -26,7 +26,7 @@ Every export of the package, all from the one entry, `@atelic-action/artifact`.
26
26
  | `ReadAccess`, `ReadTier`, `ReadSection`, `ReadChange`, `ReadRecommendation`, `ReadMarkets`, `ReadMarketRow`, `ReadRented`, `ReadStep`, `ReadPlan`, `ReadClose`, `ReadPrint`, `ReadLink`, `ReadParagraph` | The shapes a read's content is written in. `ReadSection` is a `ReadTopic` plus `gist`, `before`, `changes`, and `recommend`; its `why`, a finding's `body`, a market row's `read`, and the rented `text` take a paragraph (a string, or runs of text and links) as well as a node, so a routine can write a read as JSON | none |
27
27
  | `Topic` | The section card on its own: the trade name linked to its definition, the one liner, the grade, the why line, the blocks, and the sources, with an `extra` slot after the blocks. The read renders every section through it | `/the-read` |
28
28
  | `ratingCell` | A star rating table cell for a `table` block, sorted by its figure | `/the-read` |
29
- | `ReadTopic`, `ReadBlock`, `ReadInnerBlock`, `ReadChecks`, `ReadTable`, `ReadBar`, `ReadScale`, `ReadStats`, `ReadColumns`, `ReadFindings`, `ReadShots`, `ReadMore`, `ReadBullet`, `ReadSource`, `ReadMark`, `ReadCell`, `ReadSorted`, `ReadTone` | The shapes a section card and its blocks are written in | none |
29
+ | `ReadTopic`, `ReadBlock`, `ReadInnerBlock`, `ReadChecks`, `ReadTable`, `ReadBar`, `ReadScale`, `ReadStats`, `ReadColumns`, `ReadFindings`, `ReadShots`, `ReadMore`, `ReadBullet`, `ReadSource`, `ReadMark`, `ReadCell`, `ReadSorted`, `ReadTone` | The shapes a section card and its blocks are written in. In a `table` block, a cell past the first given as `null` is empty: it reaches ui's `DataTable` untouched, draws its short gray rule, reads the column's `emptyLabel` (or "None") to a screen reader, and sorts last either way, while a typed dash stays content, since it can mean unchanged. A `none` mark draws the same rule with its own `text` but sorts as a mark, lowest of the four, and the markets table's unread grade draws it too | none |
30
30
  | `WriteupGrade`, `WriteupPerson`, `WriteupShot` | The grade letter, the sign off person, and the owner's screen, shared by every document, all three re exported from ui under ui's names | none |
31
31
  | `Report`, `ReportProps` | The monthly page: the four questions, the seven grades now and before, the sign off, on one letter sheet | `/report` |
32
32
  | `ReportLead`, `ReportLeads`, `ReportGradeRow` | The shapes a monthly page's content is written in | none |
@@ -48,7 +48,7 @@ What a document is built from stays in `@atelic-action/ui`, and this package imp
48
48
  bun add @atelic-action/artifact @atelic-action/ui
49
49
  ```
50
50
 
51
- Peer dependencies: `@atelic-action/ui` at `^3.4.0`, `react` at `^19.0.0`, and `lucide-react` at `^1.23.0`. The package ships TSX and CSS as source, compiled inside the site's own Vite like ui's; a site whose `vite.config.ts` is one `artifactConfig` call from `@atelic-action/ui/vite` needs nothing more, for the build, the prerender, and the dev server alike. The default labels a document sets live in the document: the read's `readLabels` and the sealed document's gate copy are overridden through props, and the monthly page's four questions are fixed on purpose, since they are its contract with the Statement of Work.
51
+ Peer dependencies: `@atelic-action/ui` at `^3.9.1`, `react` at `^19.0.0`, and `lucide-react` at `^1.23.0`. The package ships TSX and CSS as source, compiled inside the site's own Vite like ui's; a site whose `vite.config.ts` is one `artifactConfig` call from `@atelic-action/ui/vite` needs nothing more, for the build, the prerender, and the dev server alike. The default labels a document sets live in the document: the read's `readLabels` and the sealed document's gate copy are overridden through props, and the monthly page's four questions are fixed on purpose, since they are its contract with the Statement of Work.
52
52
 
53
53
  ```tsx
54
54
  import { TheRead } from "@atelic-action/artifact";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atelic-action/artifact",
3
- "version": "5.1.0",
3
+ "version": "5.1.2",
4
4
  "description": "The composed documents the Atelic practice hands or sends a business (the read, the monthly page, the note, the first call sheet, and the sealed document), built from the pieces in @atelic-action/ui",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,12 +37,12 @@
37
37
  "format": "biome format . --write"
38
38
  },
39
39
  "peerDependencies": {
40
- "@atelic-action/ui": "^3.5.0",
40
+ "@atelic-action/ui": "^3.9.1",
41
41
  "lucide-react": "^1.23.0",
42
42
  "react": "^19.0.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@atelic-action/ui": "^3.5.0",
45
+ "@atelic-action/ui": "^3.9.1",
46
46
  "@biomejs/biome": "^2.0.0",
47
47
  "@playwright/test": "^1.60.0",
48
48
  "@sentry/react": "^10.0.0",
@@ -454,8 +454,8 @@ function Markets({ markets }: { markets: ReadMarkets }) {
454
454
  </>
455
455
  ) : (
456
456
  <>
457
- <span className="op-sr-only">{`${column}, not read`}</span>
458
- <span className="op-dash" aria-hidden="true" />
457
+ <span className="data-table-empty" aria-hidden="true" />
458
+ <span className="data-table-empty-label">{`${column}, not read`}</span>
459
459
  </>
460
460
  )}
461
461
  </td>
@@ -82,7 +82,15 @@ export interface ReadSorted {
82
82
  sort: number | string;
83
83
  }
84
84
 
85
- export type ReadCell = ReactNode | ReadMark | ReadSorted;
85
+ /**
86
+ * A table cell: a node, a mark, or a sorted pair. `null` past the first
87
+ * column (which names the row, so is never empty) is an empty cell,
88
+ * passed to the shared table untouched: it draws the table's short gray rule,
89
+ * reads its column's `emptyLabel` to a screen reader, and sorts last either
90
+ * way. A typed dash is a string and stays content, since a dash can mean
91
+ * "unchanged".
92
+ */
93
+ export type ReadCell = ReactNode | ReadMark | ReadSorted | null;
86
94
 
87
95
  function isMark(cell: ReadCell): cell is ReadMark {
88
96
  return typeof cell === "object" && cell !== null && "mark" in cell;
@@ -112,6 +120,8 @@ export interface ReadTable extends BlockBase {
112
120
  firstSort?: "asc" | "desc";
113
121
  /** The column hugs its content, for a swatch or a mark. */
114
122
  fit?: boolean;
123
+ /** What a screen reader hears for an empty cell in this column; defaults to "None". */
124
+ emptyLabel?: string;
115
125
  }>;
116
126
  rows: Array<{ cells: ReadCell[]; tone?: ReadTone }>;
117
127
  /** The sort the table opens in. */
@@ -298,12 +308,15 @@ const toneIcon = {
298
308
  } as const;
299
309
 
300
310
  function Mark({ cell }: { cell: ReadMark }) {
311
+ // The none mark is ui's empty cell dash and nothing around it: the same
312
+ // markup DataTable draws for a null cell, so the two sit on one line. A
313
+ // flex wrapper would center the dash in the icon's box instead.
301
314
  if (cell.mark === "none") {
302
315
  return (
303
- <span className="op-mark-cell" data-tone="muted">
304
- <span className="op-dash" aria-hidden="true" />
305
- <span className="op-sr-only">{cell.text}</span>
306
- </span>
316
+ <>
317
+ <span className="data-table-empty" aria-hidden="true" />
318
+ <span className="data-table-empty-label">{cell.text}</span>
319
+ </>
307
320
  );
308
321
  }
309
322
  const Icon = toneIcon[cell.mark];
@@ -1069,13 +1069,6 @@
1069
1069
  color: var(--op-ink);
1070
1070
  font-weight: 600;
1071
1071
  }
1072
- .atelic-ui .op-dash {
1073
- display: inline-block;
1074
- width: 14px;
1075
- height: 1.5px;
1076
- vertical-align: 0.3em;
1077
- background: var(--neutral-300);
1078
- }
1079
1072
 
1080
1073
  /* The blocks are the shared package's components. These are the read's
1081
1074
  sizes for them. */