mac-human-design 0.1.30-preview.1 → 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,23 @@
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
+
5
22
  ## 0.1.30-preview.1
6
23
 
7
24
  ### Added
@@ -91,7 +91,7 @@ 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. |
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
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`. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mac-human-design",
3
- "version": "0.1.30-preview.1",
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\}/],
@@ -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}
@@ -1566,6 +1566,9 @@
1566
1566
  }
1567
1567
 
1568
1568
  .hd-mac-data-table-row {
1569
+ position: relative;
1570
+ isolation: isolate;
1571
+ overflow: hidden;
1569
1572
  border-bottom: 1px solid var(--hd-mac-border);
1570
1573
  padding: 8px 10px;
1571
1574
  transform-origin: center;
@@ -1576,6 +1579,19 @@
1576
1579
  filter var(--hd-mac-motion-fast);
1577
1580
  }
1578
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
+
1579
1595
  .hd-mac-data-table-row:last-child {
1580
1596
  border-bottom: 0;
1581
1597
  }
@@ -1592,7 +1608,11 @@
1592
1608
  }
1593
1609
 
1594
1610
  .hd-mac-data-table-row-interactive:hover {
1595
- background: var(--hd-mac-fill-hover);
1611
+ background: transparent;
1612
+ }
1613
+
1614
+ .hd-mac-data-table-row-interactive:hover::before {
1615
+ opacity: 1;
1596
1616
  }
1597
1617
 
1598
1618
  .hd-mac-data-table-row-interactive:active {
@@ -1600,10 +1620,15 @@
1600
1620
  }
1601
1621
 
1602
1622
  .hd-mac-data-table-row[data-selected] {
1603
- background: color-mix(in srgb, var(--hd-mac-blue) 18%, transparent);
1623
+ background: transparent;
1604
1624
  box-shadow: inset 3px 0 0 var(--hd-mac-blue);
1605
1625
  }
1606
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
+
1607
1632
  .hd-mac-data-table-row[data-selected]:focus-visible {
1608
1633
  box-shadow:
1609
1634
  var(--hd-mac-focus-ring),
@@ -1611,17 +1636,28 @@
1611
1636
  }
1612
1637
 
1613
1638
  .hd-mac-data-table-row[data-selected]:hover {
1639
+ background: transparent;
1640
+ }
1641
+
1642
+ .hd-mac-data-table-row[data-selected]:hover::before {
1614
1643
  background: color-mix(in srgb, var(--hd-mac-blue) 24%, transparent);
1644
+ opacity: 1;
1615
1645
  }
1616
1646
 
1617
1647
  .hd-mac-data-table-header-cell,
1618
1648
  .hd-mac-data-table-cell {
1649
+ position: relative;
1650
+ z-index: 1;
1619
1651
  min-width: 0;
1620
1652
  overflow: hidden;
1621
1653
  text-overflow: ellipsis;
1622
1654
  white-space: nowrap;
1623
1655
  }
1624
1656
 
1657
+ .hd-mac-data-table-cell {
1658
+ z-index: 1;
1659
+ }
1660
+
1625
1661
  .hd-mac-data-table-cell {
1626
1662
  color: var(--hd-mac-secondary-text);
1627
1663
  font: 400 12px/18px var(--hd-mac-font);