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 +15 -0
- package/package.json +1 -1
- package/src/components/MacBaseUIGallery.tsx +24 -0
- package/src/components/MacDataTable.tsx +132 -0
- package/src/components/MacWindowToolbar.tsx +52 -0
- package/src/components/index.ts +2 -0
- package/src/index.ts +2 -0
- package/src/styles/macosBaseUi.css +113 -0
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
|
@@ -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
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -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;
|