mac-human-design 0.1.7 → 0.1.8

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,21 @@
2
2
 
3
3
  This file tracks changes between published npm versions of `mac-human-design`.
4
4
 
5
+ ## 0.1.8
6
+
7
+ ### Added
8
+
9
+ - Added `MacDataTable`, a reusable macOS Finder-style table/list primitive with
10
+ column definitions, header rows, selectable rows, loading and empty states,
11
+ bordered surfaces, and compact macOS typography.
12
+ - Added `MacWindowToolbar`, a Tauri-aware macOS window toolbar that owns
13
+ draggable-region markup while wrapping interactive leading, content, and
14
+ trailing controls in no-drag zones.
15
+
16
+ ### Changed
17
+
18
+ - Bumped the package to `0.1.8`.
19
+
5
20
  ## 0.1.7
6
21
 
7
22
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mac-human-design",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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",
@@ -53,7 +53,9 @@ import {
53
53
  MacToolbarToggle,
54
54
  MacTooltip,
55
55
  } from "./MacBaseUI";
56
+ import { MacDataTable } from "./MacDataTable";
56
57
  import { MacSegmentedControl } from "./MacSegmentedControl";
58
+ import { MacWindowToolbar } from "./MacWindowToolbar";
57
59
 
58
60
  const choices = [
59
61
  { label: "General", value: "general" },
@@ -61,6 +63,11 @@ const choices = [
61
63
  { label: "Advanced", value: "advanced" },
62
64
  ];
63
65
 
66
+ const tableRows = [
67
+ { name: "Documents", modified: "Today", size: "-", kind: "Folder" },
68
+ { name: "report.pdf", modified: "Yesterday", size: "2.4 MB", kind: "PDF" },
69
+ ];
70
+
64
71
  function GallerySection({ title, children }: { title: string; children: React.ReactNode }) {
65
72
  return (
66
73
  <section className="hd-mac-gallery-section">
@@ -395,6 +402,23 @@ export function MacBaseUIGallery() {
395
402
  <MacAvatar.Root>
396
403
  <MacAvatar.Fallback>HD</MacAvatar.Fallback>
397
404
  </MacAvatar.Root>
405
+ <MacWindowToolbar
406
+ leading={<MacSegmentedControl options={choices} value={segment} onChange={setSegment} />}
407
+ title="Library"
408
+ trailing={<MacIconButton aria-label="Refresh">↻</MacIconButton>}
409
+ />
410
+ <MacDataTable
411
+ bordered
412
+ columns={[
413
+ { id: "name", header: "Name", width: "minmax(140px, 1fr)", render: (row) => row.name },
414
+ { id: "modified", header: "Modified", width: "90px", render: (row) => row.modified },
415
+ { id: "size", header: "Size", width: "70px", render: (row) => row.size },
416
+ { id: "kind", header: "Kind", width: "80px", render: (row) => row.kind },
417
+ ]}
418
+ rows={tableRows}
419
+ getRowKey={(row) => row.name}
420
+ isRowSelected={(row) => row.name === "Documents"}
421
+ />
398
422
  <MacNavigationMenu.Root>
399
423
  <MacNavigationMenu.List>
400
424
  <MacNavigationMenu.Item>
@@ -0,0 +1,132 @@
1
+ import * as React from "react";
2
+
3
+ export type MacDataTableColumn<Row> = {
4
+ id: string;
5
+ header: React.ReactNode;
6
+ width: string;
7
+ render: (row: Row, index: number) => React.ReactNode;
8
+ align?: "start" | "center" | "end";
9
+ className?: string;
10
+ headerClassName?: string;
11
+ style?: React.CSSProperties;
12
+ headerStyle?: React.CSSProperties;
13
+ };
14
+
15
+ export type MacDataTableProps<Row> = {
16
+ columns: readonly MacDataTableColumn<Row>[];
17
+ rows: readonly Row[];
18
+ getRowKey: (row: Row, index: number) => React.Key;
19
+ isRowSelected?: (row: Row, index: number) => boolean;
20
+ onRowClick?: (row: Row, index: number) => void;
21
+ onRowDoubleClick?: (row: Row, index: number) => void;
22
+ loading?: boolean;
23
+ loadingContent?: React.ReactNode;
24
+ emptyContent?: React.ReactNode;
25
+ bordered?: boolean;
26
+ className?: string;
27
+ style?: React.CSSProperties;
28
+ rowClassName?: (row: Row, index: number) => string | undefined;
29
+ rowStyle?: (row: Row, index: number) => React.CSSProperties | undefined;
30
+ };
31
+
32
+ function joinClasses(...classes: Array<string | undefined | false>) {
33
+ return classes.filter(Boolean).join(" ");
34
+ }
35
+
36
+ function alignmentClassName(align: MacDataTableColumn<unknown>["align"]) {
37
+ if (align === "center") {
38
+ return "hd-mac-data-table-cell-center";
39
+ }
40
+ if (align === "end") {
41
+ return "hd-mac-data-table-cell-end";
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ export function MacDataTable<Row>({
47
+ columns,
48
+ rows,
49
+ getRowKey,
50
+ isRowSelected,
51
+ onRowClick,
52
+ onRowDoubleClick,
53
+ loading = false,
54
+ loadingContent = "Loading...",
55
+ emptyContent = "No rows.",
56
+ bordered = false,
57
+ className,
58
+ style,
59
+ rowClassName,
60
+ rowStyle,
61
+ }: MacDataTableProps<Row>) {
62
+ const gridTemplateColumns = columns.map((column) => column.width).join(" ");
63
+ const hasInteractiveRows = Boolean(onRowClick || onRowDoubleClick);
64
+
65
+ return (
66
+ <div
67
+ className={joinClasses("hd-mac-data-table", bordered && "hd-mac-data-table-bordered", className)}
68
+ style={style}
69
+ >
70
+ <div
71
+ className="hd-mac-data-table-header"
72
+ role="row"
73
+ style={{ gridTemplateColumns }}
74
+ >
75
+ {columns.map((column) => (
76
+ <div
77
+ key={column.id}
78
+ className={joinClasses(
79
+ "hd-mac-data-table-header-cell",
80
+ alignmentClassName(column.align),
81
+ column.headerClassName,
82
+ )}
83
+ role="columnheader"
84
+ style={column.headerStyle}
85
+ >
86
+ {column.header}
87
+ </div>
88
+ ))}
89
+ </div>
90
+
91
+ {loading ? (
92
+ <div className="hd-mac-data-table-message">{loadingContent}</div>
93
+ ) : rows.length === 0 ? (
94
+ <div className="hd-mac-data-table-message">{emptyContent}</div>
95
+ ) : (
96
+ rows.map((row, index) => {
97
+ const selected = isRowSelected?.(row, index) ?? false;
98
+ return (
99
+ <div
100
+ key={getRowKey(row, index)}
101
+ className={joinClasses(
102
+ "hd-mac-data-table-row",
103
+ hasInteractiveRows && "hd-mac-data-table-row-interactive",
104
+ rowClassName?.(row, index),
105
+ )}
106
+ data-selected={selected || undefined}
107
+ onClick={onRowClick ? () => onRowClick(row, index) : undefined}
108
+ onDoubleClick={onRowDoubleClick ? () => onRowDoubleClick(row, index) : undefined}
109
+ role="row"
110
+ style={{ gridTemplateColumns, ...rowStyle?.(row, index) }}
111
+ >
112
+ {columns.map((column) => (
113
+ <div
114
+ key={column.id}
115
+ className={joinClasses(
116
+ "hd-mac-data-table-cell",
117
+ alignmentClassName(column.align),
118
+ column.className,
119
+ )}
120
+ role="cell"
121
+ style={column.style}
122
+ >
123
+ {column.render(row, index)}
124
+ </div>
125
+ ))}
126
+ </div>
127
+ );
128
+ })
129
+ )}
130
+ </div>
131
+ );
132
+ }
@@ -0,0 +1,52 @@
1
+ import * as React from "react";
2
+
3
+ export type MacWindowToolbarProps = {
4
+ leading?: React.ReactNode;
5
+ title?: React.ReactNode;
6
+ trailing?: React.ReactNode;
7
+ children?: React.ReactNode;
8
+ className?: string;
9
+ style?: React.CSSProperties;
10
+ };
11
+
12
+ function joinClasses(...classes: Array<string | undefined | false>) {
13
+ return classes.filter(Boolean).join(" ");
14
+ }
15
+
16
+ export function MacWindowToolbar({
17
+ leading,
18
+ title,
19
+ trailing,
20
+ children,
21
+ className,
22
+ style,
23
+ }: MacWindowToolbarProps) {
24
+ return (
25
+ <div
26
+ className={joinClasses("hd-mac-window-toolbar", className)}
27
+ data-tauri-drag-region
28
+ style={style}
29
+ >
30
+ {leading ? (
31
+ <div className="hd-mac-window-toolbar-group" data-tauri-no-drag-region>
32
+ {leading}
33
+ </div>
34
+ ) : null}
35
+ {title ? (
36
+ <div className="hd-mac-window-toolbar-title" data-tauri-drag-region>
37
+ {title}
38
+ </div>
39
+ ) : null}
40
+ {children ? (
41
+ <div className="hd-mac-window-toolbar-content" data-tauri-no-drag-region>
42
+ {children}
43
+ </div>
44
+ ) : null}
45
+ {trailing ? (
46
+ <div className="hd-mac-window-toolbar-group" data-tauri-no-drag-region>
47
+ {trailing}
48
+ </div>
49
+ ) : null}
50
+ </div>
51
+ );
52
+ }
@@ -1,6 +1,8 @@
1
1
  export * from "./MacBaseUI";
2
2
  export { MacBaseUIGallery } from "./MacBaseUIGallery";
3
+ export { MacDataTable, type MacDataTableColumn, type MacDataTableProps } from "./MacDataTable";
3
4
  export { MacSegmentedControl, type MacSegmentedControlOption } from "./MacSegmentedControl";
5
+ export { MacWindowToolbar, type MacWindowToolbarProps } from "./MacWindowToolbar";
4
6
  export { StatusMessage } from "./StatusMessage";
5
7
  export { SymbolIconButton } from "./SymbolIconButton";
6
8
  export { AppWindowShell } from "./AppWindowShell";
package/src/index.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from "./components/MacBaseUI";
2
2
  export { MacBaseUIGallery } from "./components/MacBaseUIGallery";
3
3
  export { AppWindowShell } from "./components/AppWindowShell";
4
+ export { MacDataTable, type MacDataTableColumn, type MacDataTableProps } from "./components/MacDataTable";
4
5
  export { MacSegmentedControl, type MacSegmentedControlOption } from "./components/MacSegmentedControl";
6
+ export { MacWindowToolbar, type MacWindowToolbarProps } from "./components/MacWindowToolbar";
5
7
  export { SymbolIconButton } from "./components/SymbolIconButton";
6
8
  export { StatusMessage } from "./components/StatusMessage";
7
9
  export { ViewDragRegion } from "./components/ViewDragRegion";
@@ -1107,6 +1107,119 @@
1107
1107
  background: var(--hd-mac-border);
1108
1108
  }
1109
1109
 
1110
+ .hd-mac-window-toolbar {
1111
+ display: flex;
1112
+ min-height: 48px;
1113
+ align-items: center;
1114
+ justify-content: space-between;
1115
+ gap: 12px;
1116
+ border-bottom: 1px solid var(--hd-mac-border);
1117
+ padding: 10px 16px;
1118
+ background: var(--hd-mac-surface);
1119
+ box-sizing: border-box;
1120
+ }
1121
+
1122
+ .hd-mac-window-toolbar-group,
1123
+ .hd-mac-window-toolbar-content {
1124
+ display: inline-flex;
1125
+ min-width: 0;
1126
+ align-items: center;
1127
+ gap: 8px;
1128
+ flex-wrap: wrap;
1129
+ }
1130
+
1131
+ .hd-mac-window-toolbar-title {
1132
+ min-width: 0;
1133
+ flex: 1;
1134
+ overflow: hidden;
1135
+ text-overflow: ellipsis;
1136
+ white-space: nowrap;
1137
+ color: var(--hd-mac-text);
1138
+ font: 600 15px/20px var(--hd-mac-font);
1139
+ }
1140
+
1141
+ .hd-mac-data-table {
1142
+ min-width: 0;
1143
+ color: var(--hd-mac-text);
1144
+ font-family: var(--hd-mac-font);
1145
+ }
1146
+
1147
+ .hd-mac-data-table-bordered {
1148
+ overflow: hidden;
1149
+ border: 1px solid var(--hd-mac-border);
1150
+ border-radius: 10px;
1151
+ }
1152
+
1153
+ .hd-mac-data-table-header,
1154
+ .hd-mac-data-table-row {
1155
+ display: grid;
1156
+ min-width: 0;
1157
+ }
1158
+
1159
+ .hd-mac-data-table-header {
1160
+ border-bottom: 1px solid var(--hd-mac-border);
1161
+ padding: 8px 10px;
1162
+ color: var(--hd-mac-muted-text);
1163
+ font: 600 12px/16px var(--hd-mac-font);
1164
+ }
1165
+
1166
+ .hd-mac-data-table-row {
1167
+ border-bottom: 1px solid var(--hd-mac-border);
1168
+ padding: 8px 10px;
1169
+ }
1170
+
1171
+ .hd-mac-data-table-row:last-child {
1172
+ border-bottom: 0;
1173
+ }
1174
+
1175
+ .hd-mac-data-table-row-interactive {
1176
+ cursor: default;
1177
+ }
1178
+
1179
+ .hd-mac-data-table-row-interactive:hover {
1180
+ background: var(--hd-mac-fill-hover);
1181
+ }
1182
+
1183
+ .hd-mac-data-table-row[data-selected] {
1184
+ background: color-mix(in srgb, var(--hd-mac-blue) 18%, transparent);
1185
+ }
1186
+
1187
+ .hd-mac-data-table-row[data-selected]:hover {
1188
+ background: color-mix(in srgb, var(--hd-mac-blue) 24%, transparent);
1189
+ }
1190
+
1191
+ .hd-mac-data-table-header-cell,
1192
+ .hd-mac-data-table-cell {
1193
+ min-width: 0;
1194
+ overflow: hidden;
1195
+ text-overflow: ellipsis;
1196
+ white-space: nowrap;
1197
+ }
1198
+
1199
+ .hd-mac-data-table-cell {
1200
+ color: var(--hd-mac-secondary-text);
1201
+ font: 400 12px/18px var(--hd-mac-font);
1202
+ }
1203
+
1204
+ .hd-mac-data-table-cell:first-child {
1205
+ color: var(--hd-mac-text);
1206
+ font-size: 13px;
1207
+ }
1208
+
1209
+ .hd-mac-data-table-cell-center {
1210
+ text-align: center;
1211
+ }
1212
+
1213
+ .hd-mac-data-table-cell-end {
1214
+ text-align: end;
1215
+ }
1216
+
1217
+ .hd-mac-data-table-message {
1218
+ padding: 12px 10px;
1219
+ color: var(--hd-mac-secondary-text);
1220
+ font: 400 13px/18px var(--hd-mac-font);
1221
+ }
1222
+
1110
1223
  .hd-mac-gallery {
1111
1224
  display: grid;
1112
1225
  gap: 14px;