mac-human-design 0.1.30-preview.0 → 0.1.30-preview.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/changelog.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  This file tracks changes between published npm versions of `mac-human-design`.
4
4
 
5
+ ## 0.1.30-preview.2
6
+
7
+ ### Added
8
+
9
+ - Added `MacDataTable` arrow, Home, and End keyboard navigation for interactive
10
+ rows.
11
+ - Added a layered `MacDataTable` row hover and selection treatment so row
12
+ feedback animates under cell content without shifting text or layout.
13
+ - Added verifier coverage for data-table keyboard navigation and row state
14
+ layer invariants.
15
+
16
+ ### Changed
17
+
18
+ - Improved Finder-style table interaction polish for object-browser style
19
+ screens while preserving row geometry and selected-row focus rings.
20
+ - Bumped the package to `0.1.30-preview.2` under the `preview` dist-tag.
21
+
22
+ ## 0.1.30-preview.1
23
+
24
+ ### Added
25
+
26
+ - Added shared `MacWindowToolbar` layout guardrails for dense toolbar groups,
27
+ including stable group height, row gaps, fixed child flex sizing, and fixed
28
+ `SymbolIconButton` flex basis inside toolbar groups.
29
+ - Added verifier coverage for toolbar group layout stability.
30
+
31
+ ### Changed
32
+
33
+ - Improved wrapped toolbar behavior so segmented controls and icon buttons keep
34
+ stable alignment as toolbar content density changes.
35
+ - Bumped the package to `0.1.30-preview.1` under the `preview` dist-tag.
36
+
5
37
  ## 0.1.30-preview.0
6
38
 
7
39
  ### Added
@@ -91,8 +91,8 @@ be reimplemented in consuming apps:
91
91
 
92
92
  | App pattern | Export | Contract |
93
93
  | --- | --- | --- |
94
- | Finder-style grid/table primitive | `MacDataTable` | Uses `table` semantics for static rows, upgrades to `grid` semantics for interactive rows, exposes row/column metadata, busy state, keyboard activation, selected row state, and focus-visible row styling. |
95
- | Tauri window toolbar | `MacWindowToolbar` | Provides a labelled `toolbar` landmark, labelled leading/content/trailing control groups, a root drag region, and no-drag regions around interactive controls. |
94
+ | Finder-style grid/table primitive | `MacDataTable` | Uses `table` semantics for static rows, upgrades to `grid` semantics for interactive rows, exposes row/column metadata, busy state, keyboard activation, arrow/Home/End row focus navigation, selected row state, and layered hover/selection styling. |
95
+ | Tauri window toolbar | `MacWindowToolbar` | Provides a labelled `toolbar` landmark, labelled leading/content/trailing control groups, a root drag region, no-drag regions around interactive controls, and stable wrapped-control sizing for dense icon toolbars. |
96
96
  | Segmented control | `MacSegmentedControl` | Wraps the shared macOS segmented toggle styling with accessible labels, stable class names, full-width layout support, and class/style pass-through. |
97
97
  | Centered SF Symbols icon button | `SymbolIconButton` | Renders through `MacIconButton`, defaults to `type="button"`, preserves fixed geometry while allowing style/class pass-through, supports tooltip offsets and per-symbol optical offsets, and exposes loading state with `aria-busy`. |
98
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mac-human-design",
3
- "version": "0.1.30-preview.0",
3
+ "version": "0.1.30-preview.2",
4
4
  "description": "Reusable macOS-oriented UI primitives and SF Symbols bridge for Tauri apps.",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -305,6 +305,12 @@ const missingDataTableRequirements = [
305
305
  ["keyboard row handler", /handleRowKeyDown/],
306
306
  ["enter key activation", /event\.key === "Enter"/],
307
307
  ["space key activation", /event\.key === " "/],
308
+ ["arrow up row navigation", /event\.key === "ArrowUp"/],
309
+ ["arrow down row navigation", /event\.key === "ArrowDown"/],
310
+ ["home row navigation", /event\.key === "Home"/],
311
+ ["end row navigation", /event\.key === "End"/],
312
+ ["data table row focus helper", /function focusDataTableRow/],
313
+ ["interactive row query marker", /data-hd-mac-data-table-row=\{hasInteractiveRows \|\| undefined\}/],
308
314
  ].filter(([, pattern]) => !pattern.test(dataTableSource));
309
315
 
310
316
  if (missingDataTableRequirements.length > 0) {
@@ -319,6 +325,33 @@ requireCssDeclarations(".hd-mac-data-table-row-interactive:focus-visible", [
319
325
  ["focus ring", /var\(--hd-mac-focus-ring\)/],
320
326
  ]);
321
327
 
328
+ requireCssDeclarations(".hd-mac-data-table-row", [
329
+ ["row state layer positioning", /position\s*:\s*relative\s*;/],
330
+ ["row state layer isolation", /isolation\s*:\s*isolate\s*;/],
331
+ ["row state layer clipping", /overflow\s*:\s*hidden\s*;/],
332
+ ]);
333
+
334
+ requireCssDeclarations(".hd-mac-data-table-row::before", [
335
+ ["row state layer content", /content\s*:\s*""\s*;/],
336
+ ["row state layer fills row", /inset\s*:\s*0\s*;/],
337
+ ["row state layer behind cells", /z-index\s*:\s*0\s*;/],
338
+ ["row state layer hidden by default", /opacity\s*:\s*0\s*;/],
339
+ ["row state layer opacity transition", /opacity\s+var\(--hd-mac-motion-row\)/],
340
+ ]);
341
+
342
+ requireCssDeclarations(".hd-mac-data-table-row-interactive:hover::before", [
343
+ ["row hover state layer visible", /opacity\s*:\s*1\s*;/],
344
+ ]);
345
+
346
+ requireCssDeclarations(".hd-mac-data-table-row[data-selected]::before", [
347
+ ["selected row state layer uses accent fill", /color-mix\(in srgb,\s*var\(--hd-mac-blue\)\s*18%,\s*transparent\)/],
348
+ ["selected row state layer visible", /opacity\s*:\s*1\s*;/],
349
+ ]);
350
+
351
+ requireCssDeclarations(".hd-mac-data-table-cell", [
352
+ ["cell above row state layer", /z-index\s*:\s*1\s*;/],
353
+ ]);
354
+
322
355
  const missingToolbarRequirements = [
323
356
  ["toolbar role", /role=["']toolbar["']/],
324
357
  ["optional aria label", /aria-label=\{ariaLabel\}/],
@@ -338,6 +371,20 @@ if (missingToolbarRequirements.length > 0) {
338
371
  );
339
372
  }
340
373
 
374
+ requireCssDeclarations(".hd-mac-window-toolbar-group", [
375
+ ["toolbar group stable min height", /min-height\s*:\s*30px\s*;/],
376
+ ["toolbar group row gap", /row-gap\s*:\s*6px\s*;/],
377
+ ["toolbar group center transform origin", /transform-origin\s*:\s*center\s*;/],
378
+ ]);
379
+
380
+ requireCssDeclarations(".hd-mac-window-toolbar-group > *", [
381
+ ["toolbar controls fixed auto flex", /flex\s*:\s*0\s+0\s+auto\s*;/],
382
+ ]);
383
+
384
+ requireCssDeclarations(".hd-mac-window-toolbar-group > .hd-mac-symbol-icon-button", [
385
+ ["toolbar icon button fixed flex basis", /flex-basis\s*:\s*30px\s*;/],
386
+ ]);
387
+
341
388
  const missingPublicDocs = [
342
389
  ["README documents MacDataTable", /`MacDataTable`[\s\S]*Finder-style grid\/table primitive/],
343
390
  ["README documents MacWindowToolbar", /`MacWindowToolbar`[\s\S]*Tauri window toolbar/],
@@ -46,6 +46,32 @@ function alignmentClassName(align: MacDataTableColumn<unknown>["align"]) {
46
46
  return undefined;
47
47
  }
48
48
 
49
+ function focusDataTableRow(currentRow: HTMLElement, direction: "previous" | "next" | "first" | "last") {
50
+ const parent = currentRow.parentElement;
51
+ if (!parent) {
52
+ return;
53
+ }
54
+
55
+ const rows = Array.from(
56
+ parent.querySelectorAll<HTMLElement>('[data-hd-mac-data-table-row="true"]'),
57
+ );
58
+ const currentIndex = rows.indexOf(currentRow);
59
+ if (currentIndex === -1) {
60
+ return;
61
+ }
62
+
63
+ const nextIndex =
64
+ direction === "first"
65
+ ? 0
66
+ : direction === "last"
67
+ ? rows.length - 1
68
+ : direction === "previous"
69
+ ? Math.max(0, currentIndex - 1)
70
+ : Math.min(rows.length - 1, currentIndex + 1);
71
+
72
+ rows[nextIndex]?.focus();
73
+ }
74
+
49
75
  const tableTransition: Transition = {
50
76
  default: { type: "spring", stiffness: 520, damping: 44, mass: 0.78 },
51
77
  opacity: { duration: 0.12, ease: "easeOut" },
@@ -78,6 +104,7 @@ export function MacDataTable<Row>({
78
104
  if (!hasInteractiveRows) {
79
105
  return;
80
106
  }
107
+ const currentRow = event.currentTarget as HTMLElement;
81
108
 
82
109
  if (event.key === "Enter") {
83
110
  event.preventDefault();
@@ -92,6 +119,26 @@ export function MacDataTable<Row>({
92
119
  event.preventDefault();
93
120
  onRowClick?.(row, index);
94
121
  }
122
+
123
+ if (event.key === "ArrowUp") {
124
+ event.preventDefault();
125
+ focusDataTableRow(currentRow, "previous");
126
+ }
127
+
128
+ if (event.key === "ArrowDown") {
129
+ event.preventDefault();
130
+ focusDataTableRow(currentRow, "next");
131
+ }
132
+
133
+ if (event.key === "Home") {
134
+ event.preventDefault();
135
+ focusDataTableRow(currentRow, "first");
136
+ }
137
+
138
+ if (event.key === "End") {
139
+ event.preventDefault();
140
+ focusDataTableRow(currentRow, "last");
141
+ }
95
142
  },
96
143
  [hasInteractiveRows, onRowClick, onRowDoubleClick],
97
144
  );
@@ -172,6 +219,7 @@ export function MacDataTable<Row>({
172
219
  hasInteractiveRows && "hd-mac-data-table-row-interactive",
173
220
  rowClassName?.(row, index),
174
221
  )}
222
+ data-hd-mac-data-table-row={hasInteractiveRows || undefined}
175
223
  data-selected={selected || undefined}
176
224
  onClick={onRowClick ? () => onRowClick(row, index) : undefined}
177
225
  onDoubleClick={onRowDoubleClick ? () => onRowDoubleClick(row, index) : undefined}
@@ -1483,12 +1483,52 @@
1483
1483
  .hd-mac-window-toolbar-content {
1484
1484
  display: inline-flex;
1485
1485
  min-width: 0;
1486
+ min-height: 30px;
1486
1487
  align-items: center;
1487
1488
  gap: 8px;
1489
+ row-gap: 6px;
1488
1490
  flex-wrap: wrap;
1489
1491
  transform-origin: center;
1490
1492
  }
1491
1493
 
1494
+ .hd-mac-window-toolbar-group {
1495
+ min-height: 30px;
1496
+ row-gap: 6px;
1497
+ transform-origin: center;
1498
+ }
1499
+
1500
+ .hd-mac-window-toolbar-content {
1501
+ min-height: 30px;
1502
+ row-gap: 6px;
1503
+ transform-origin: center;
1504
+ }
1505
+
1506
+ .hd-mac-window-toolbar-group > *,
1507
+ .hd-mac-window-toolbar-content > * {
1508
+ flex: 0 0 auto;
1509
+ }
1510
+
1511
+ .hd-mac-window-toolbar-group > * {
1512
+ flex: 0 0 auto;
1513
+ }
1514
+
1515
+ .hd-mac-window-toolbar-content > * {
1516
+ flex: 0 0 auto;
1517
+ }
1518
+
1519
+ .hd-mac-window-toolbar-group > .hd-mac-symbol-icon-button,
1520
+ .hd-mac-window-toolbar-content > .hd-mac-symbol-icon-button {
1521
+ flex-basis: 30px;
1522
+ }
1523
+
1524
+ .hd-mac-window-toolbar-group > .hd-mac-symbol-icon-button {
1525
+ flex-basis: 30px;
1526
+ }
1527
+
1528
+ .hd-mac-window-toolbar-content > .hd-mac-symbol-icon-button {
1529
+ flex-basis: 30px;
1530
+ }
1531
+
1492
1532
  .hd-mac-window-toolbar-title {
1493
1533
  min-width: 0;
1494
1534
  flex: 1;
@@ -1526,6 +1566,9 @@
1526
1566
  }
1527
1567
 
1528
1568
  .hd-mac-data-table-row {
1569
+ position: relative;
1570
+ isolation: isolate;
1571
+ overflow: hidden;
1529
1572
  border-bottom: 1px solid var(--hd-mac-border);
1530
1573
  padding: 8px 10px;
1531
1574
  transform-origin: center;
@@ -1536,6 +1579,19 @@
1536
1579
  filter var(--hd-mac-motion-fast);
1537
1580
  }
1538
1581
 
1582
+ .hd-mac-data-table-row::before {
1583
+ content: "";
1584
+ position: absolute;
1585
+ inset: 0;
1586
+ z-index: 0;
1587
+ background: var(--hd-mac-fill-hover);
1588
+ opacity: 0;
1589
+ pointer-events: none;
1590
+ transition:
1591
+ opacity var(--hd-mac-motion-row),
1592
+ background-color var(--hd-mac-motion-row);
1593
+ }
1594
+
1539
1595
  .hd-mac-data-table-row:last-child {
1540
1596
  border-bottom: 0;
1541
1597
  }
@@ -1552,7 +1608,11 @@
1552
1608
  }
1553
1609
 
1554
1610
  .hd-mac-data-table-row-interactive:hover {
1555
- background: var(--hd-mac-fill-hover);
1611
+ background: transparent;
1612
+ }
1613
+
1614
+ .hd-mac-data-table-row-interactive:hover::before {
1615
+ opacity: 1;
1556
1616
  }
1557
1617
 
1558
1618
  .hd-mac-data-table-row-interactive:active {
@@ -1560,10 +1620,15 @@
1560
1620
  }
1561
1621
 
1562
1622
  .hd-mac-data-table-row[data-selected] {
1563
- background: color-mix(in srgb, var(--hd-mac-blue) 18%, transparent);
1623
+ background: transparent;
1564
1624
  box-shadow: inset 3px 0 0 var(--hd-mac-blue);
1565
1625
  }
1566
1626
 
1627
+ .hd-mac-data-table-row[data-selected]::before {
1628
+ background: color-mix(in srgb, var(--hd-mac-blue) 18%, transparent);
1629
+ opacity: 1;
1630
+ }
1631
+
1567
1632
  .hd-mac-data-table-row[data-selected]:focus-visible {
1568
1633
  box-shadow:
1569
1634
  var(--hd-mac-focus-ring),
@@ -1571,17 +1636,28 @@
1571
1636
  }
1572
1637
 
1573
1638
  .hd-mac-data-table-row[data-selected]:hover {
1639
+ background: transparent;
1640
+ }
1641
+
1642
+ .hd-mac-data-table-row[data-selected]:hover::before {
1574
1643
  background: color-mix(in srgb, var(--hd-mac-blue) 24%, transparent);
1644
+ opacity: 1;
1575
1645
  }
1576
1646
 
1577
1647
  .hd-mac-data-table-header-cell,
1578
1648
  .hd-mac-data-table-cell {
1649
+ position: relative;
1650
+ z-index: 1;
1579
1651
  min-width: 0;
1580
1652
  overflow: hidden;
1581
1653
  text-overflow: ellipsis;
1582
1654
  white-space: nowrap;
1583
1655
  }
1584
1656
 
1657
+ .hd-mac-data-table-cell {
1658
+ z-index: 1;
1659
+ }
1660
+
1585
1661
  .hd-mac-data-table-cell {
1586
1662
  color: var(--hd-mac-secondary-text);
1587
1663
  font: 400 12px/18px var(--hd-mac-font);