mac-human-design 0.1.2 → 0.1.5

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
@@ -1,8 +1,9 @@
1
- # human-design
1
+ # mac-human-design
2
2
 
3
3
  A reusable shared library for Tauri macOS apps. It includes:
4
4
 
5
- - `MacSegmentedControl` and macOS-focused BaseUI theme tokens.
5
+ - macOS-styled wrappers for every public `@base-ui/react` component family.
6
+ - `MacSegmentedControl` and macOS design tokens/classes.
6
7
  - A reusable SF Symbols fetch layer with React hooks/components.
7
8
  - A Rust/Tauri plugin crate that exposes a native command:
8
9
  `system_symbol_png_data_url`.
@@ -10,6 +11,7 @@ A reusable shared library for Tauri macOS apps. It includes:
10
11
  ## Structure
11
12
 
12
13
  - `src/` - TypeScript/React library exports
14
+ - `docs/macos-base-ui-coverage.md` - Base UI component coverage and variants
13
15
  - `src-tauri/` - Rust plugin crate (`human-design-tauri-system-symbols`)
14
16
 
15
17
  ## Install
@@ -17,7 +19,17 @@ A reusable shared library for Tauri macOS apps. It includes:
17
19
  From the consumer app:
18
20
 
19
21
  ```bash
20
- npm i human-design
22
+ npm i mac-human-design @base-ui/react react react-dom
23
+ ```
24
+
25
+ `@base-ui/react`, `react`, and `react-dom` are peer dependencies. Install
26
+ `@tauri-apps/api` too when using the SF Symbols helpers or Tauri integration.
27
+
28
+ Consumer apps should also include the macOS Base UI stylesheet once near their
29
+ app root:
30
+
31
+ ```ts
32
+ import "mac-human-design/styles/macos-base-ui.css";
21
33
  ```
22
34
 
23
35
  In the Tauri Rust side, add the local path dependency while developing:
@@ -42,8 +54,9 @@ fn main() {
42
54
 
43
55
  ```ts
44
56
  import { useState } from "react";
45
- import { MacSegmentedControl } from "human-design";
46
- import { SystemSymbolImage } from "human-design/symbols";
57
+ import { MacButton, MacSegmentedControl, MacSelect } from "mac-human-design";
58
+ import { SystemSymbolImage } from "mac-human-design/symbols";
59
+ import "mac-human-design/styles/macos-base-ui.css";
47
60
 
48
61
  export function Demo() {
49
62
  const [tab, setTab] = useState<"files" | "settings">("files");
@@ -59,18 +72,50 @@ export function Demo() {
59
72
  value={tab}
60
73
  onChange={setTab}
61
74
  />
75
+ <MacButton data-variant="primary">Continue</MacButton>
76
+ <MacSelect.Root items={[{ label: "Files", value: "files" }]}>
77
+ <MacSelect.Trigger>
78
+ <MacSelect.Value placeholder="Choose" />
79
+ </MacSelect.Trigger>
80
+ </MacSelect.Root>
62
81
  </div>
63
82
  );
64
83
  }
65
84
  ```
66
85
 
86
+ ## Verify
87
+
88
+ ```bash
89
+ npm run check
90
+ npm run dev:gallery -- --port 5177
91
+ ```
92
+
67
93
  ## Why it works cross-platform
68
94
 
95
+ The React components stay browser-safe. The optional Tauri plugin is the only
96
+ native layer:
97
+
98
+ - On macOS, Rust command renders the symbol to PNG via `NSImage`.
99
+ - On non-macOS, command returns `None` so invocations stay safe and predictable.
100
+
69
101
  ## Shared UI components moved in
70
102
 
71
103
  The following components are now in the shared library and can be imported by any app:
72
104
 
73
105
  - `AppWindowShell`
106
+ - `MacAccordion`, `MacAlertDialog`, `MacAutocomplete`, `MacAvatar`,
107
+ `MacButton`, `MacPrimaryButton`, `MacSecondaryButton`,
108
+ `MacDestructiveButton`, `MacPlainButton`, `MacIconButton`,
109
+ `MacHelpButton`, `MacCheckbox`, `MacCheckboxGroup`, `MacCollapsible`,
110
+ `MacCombobox`, `MacContextMenu`, `MacDialog`, `MacDrawer`, `MacField`,
111
+ `MacFieldset`, `MacForm`, `MacInput`, `MacTextField`, `MacSearchField`,
112
+ `MacMenu`, `MacMenubar`, `MacMeter`, `MacNavigationMenu`,
113
+ `MacNumberField`, `MacOTPField`, `MacPopover`,
114
+ `MacPreviewCard`, `MacProgress`, `MacRadio`, `MacRadioGroup`,
115
+ `MacScrollArea`, `MacSelect`, `MacSeparator`, `MacSlider`, `MacSwitch`,
116
+ `MacTabs`, `MacToast`, `MacToggle`, `MacToolbarToggle`,
117
+ `MacToggleGroup`, `MacSegmentedToggleGroup`,
118
+ `MacSeparatedSegmentedToggleGroup`, `MacToolbar`, `MacTooltip`
74
119
  - `StatusMessage`
75
120
  - `SymbolIconButton`
76
121
  - `ViewDragRegion`
@@ -85,8 +130,5 @@ import {
85
130
  SymbolIconButton,
86
131
  ViewDragRegion,
87
132
  isDraggableAreaTarget,
88
- } from "human-design";
133
+ } from "mac-human-design";
89
134
  ```
90
-
91
- - On macOS, Rust command renders the symbol to PNG via `NSImage`.
92
- - On non-macOS, command returns `None` so invocations stay safe and predictable.
package/changelog.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ This file tracks changes between published npm versions of `mac-human-design`.
4
+
5
+ ## 0.1.5
6
+
7
+ ### Changed
8
+
9
+ - Replaced the previous Base Web `baseui` foundation with `@base-ui/react`.
10
+ - Updated the package peer dependencies so consumers install `@base-ui/react`,
11
+ `react`, and `react-dom` alongside `mac-human-design`.
12
+ - Updated README and coverage documentation to use the published package name
13
+ `mac-human-design` in install and import examples.
14
+
15
+ ### Added
16
+
17
+ - Added macOS-styled wrappers for every public renderable `@base-ui/react`
18
+ component family in version 1.5.0:
19
+ `Accordion`, `AlertDialog`, `Autocomplete`, `Avatar`, `Button`,
20
+ `Checkbox`, `CheckboxGroup`, `Collapsible`, `Combobox`, `ContextMenu`,
21
+ `CSPProvider`, `Dialog`, `DirectionProvider`, `Drawer`, `Field`,
22
+ `Fieldset`, `Form`, `Input`, `Menu`, `Menubar`, `Meter`,
23
+ `NavigationMenu`, `NumberField`, `OTPField`, `Popover`, `PreviewCard`,
24
+ `Progress`, `Radio`, `RadioGroup`, `ScrollArea`, `Select`, `Separator`,
25
+ `Slider`, `Switch`, `Tabs`, `Toast`, `Toggle`, `ToggleGroup`, `Toolbar`,
26
+ and `Tooltip`.
27
+ - Added macOS-native variants for common platform control styles, including
28
+ primary, secondary, destructive, plain, icon, and help buttons; text and
29
+ search fields; pop-up and pull-down select triggers; segmented controls;
30
+ toolbar buttons; sheet dialogs; and sidebar drawers.
31
+ - Added `src/styles/macosBaseUi.css`, which defines the macOS control styling,
32
+ system font stack, light/dark tokens, focus rings, reduced-motion behavior,
33
+ popup/menu/dialog surfaces, and state styling used by the wrappers.
34
+ - Added `MacBaseUIGallery` and a Vite example app at
35
+ `examples/macos-base-ui-gallery` to visually exercise the wrapped component
36
+ families and variants.
37
+ - Added `docs/macos-base-ui-coverage.md` to document Base UI family coverage,
38
+ intentional utility exclusions, native variants, and verification commands.
39
+ - Added verification scripts for Base UI coverage, macOS design constraints,
40
+ gallery buildability, CSS selector coverage, stale Base Web references, and
41
+ npm package contents.
42
+
43
+ ### Removed
44
+
45
+ - Removed the old `baseui` dependency path from package metadata, source,
46
+ docs, examples, and the lockfile.
47
+ - Removed any dependency on Base Web or Styletron as the shared UI foundation.
48
+
49
+ ### Verification
50
+
51
+ - `npm run check` typechecks the package, verifies all public Base UI component
52
+ wrappers and namespace parts, validates macOS design constraints, and builds
53
+ the gallery.
54
+ - `npm pack --dry-run --json` confirms the npm package includes source, styles,
55
+ docs, examples, scripts, README, license, and this changelog.
@@ -0,0 +1,114 @@
1
+ # macOS Base UI Coverage
2
+
3
+ `mac-human-design` wraps every public component family exported by `@base-ui/react`
4
+ 1.5.0 with macOS-oriented class names. Import the CSS once:
5
+
6
+ ```ts
7
+ import "mac-human-design/styles/macos-base-ui.css";
8
+ ```
9
+
10
+ Consumer apps install `@base-ui/react`, `react`, and `react-dom` as peer
11
+ dependencies alongside this package.
12
+
13
+ ## Component Families
14
+
15
+ | Base UI family | macOS export |
16
+ | --- | --- |
17
+ | `accordion` | `MacAccordion` |
18
+ | `alert-dialog` | `MacAlertDialog` |
19
+ | `autocomplete` | `MacAutocomplete` |
20
+ | `avatar` | `MacAvatar` |
21
+ | `button` | `MacButton` |
22
+ | `checkbox` | `MacCheckbox` |
23
+ | `checkbox-group` | `MacCheckboxGroup` |
24
+ | `collapsible` | `MacCollapsible` |
25
+ | `combobox` | `MacCombobox` |
26
+ | `context-menu` | `MacContextMenu` |
27
+ | `csp-provider` | `MacCSPProvider` |
28
+ | `dialog` | `MacDialog` |
29
+ | `direction-provider` | `MacDirectionProvider` |
30
+ | `drawer` | `MacDrawer` |
31
+ | `field` | `MacField` |
32
+ | `fieldset` | `MacFieldset` |
33
+ | `form` | `MacForm` |
34
+ | `input` | `MacInput` |
35
+ | `menu` | `MacMenu` |
36
+ | `menubar` | `MacMenubar` |
37
+ | `meter` | `MacMeter` |
38
+ | `navigation-menu` | `MacNavigationMenu` |
39
+ | `number-field` | `MacNumberField` |
40
+ | `otp-field` | `MacOTPField` |
41
+ | `popover` | `MacPopover` |
42
+ | `preview-card` | `MacPreviewCard` |
43
+ | `progress` | `MacProgress` |
44
+ | `radio` | `MacRadio` |
45
+ | `radio-group` | `MacRadioGroup` |
46
+ | `scroll-area` | `MacScrollArea` |
47
+ | `select` | `MacSelect` |
48
+ | `separator` | `MacSeparator` |
49
+ | `slider` | `MacSlider` |
50
+ | `switch` | `MacSwitch` |
51
+ | `tabs` | `MacTabs` |
52
+ | `toast` | `MacToast` |
53
+ | `toggle` | `MacToggle` |
54
+ | `toggle-group` | `MacToggleGroup` |
55
+ | `toolbar` | `MacToolbar` |
56
+ | `tooltip` | `MacTooltip` |
57
+
58
+ Support exports such as `merge-props`, `use-render`, and
59
+ `unstable-use-media-query` are intentionally not wrapped because they do not
60
+ render UI.
61
+
62
+ ## Native Variants
63
+
64
+ | Native role | Export |
65
+ | --- | --- |
66
+ | Default push button | `MacButton` |
67
+ | Blue default button | `MacPrimaryButton` |
68
+ | Secondary push button | `MacSecondaryButton` |
69
+ | Destructive button | `MacDestructiveButton` |
70
+ | Borderless button | `MacPlainButton` |
71
+ | Icon button | `MacIconButton` |
72
+ | Help button | `MacHelpButton` |
73
+ | Text field | `MacTextField` / `MacInput` |
74
+ | Search field | `MacSearchField` |
75
+ | Pop-up button | `MacSelect.PopUpButtonTrigger` |
76
+ | Pull-down button | `MacSelect.PullDownButtonTrigger` |
77
+ | Segmented control | `MacSegmentedToggleGroup` |
78
+ | Separated segmented control | `MacSeparatedSegmentedToggleGroup` |
79
+ | Toolbar toggle | `MacToolbarToggle` |
80
+ | Toolbar icon button | `MacToolbar.IconButton` |
81
+ | Window sheet | `MacDialog.SheetPopup` |
82
+ | Sidebar drawer | `MacDrawer.SidebarPopup` |
83
+
84
+ The gallery at `examples/macos-base-ui-gallery` renders these wrappers across
85
+ normal, selected, disabled, mixed, popup, dialog, and narrow-width states.
86
+
87
+ ## Verification
88
+
89
+ Run the full local gate before publishing wrapper changes:
90
+
91
+ ```bash
92
+ npm run check
93
+ ```
94
+
95
+ The gate typechecks the library and verifies:
96
+
97
+ - every public `@base-ui/react` component family has a `Mac...` wrapper export,
98
+ - every renderable namespace part in each wrapped family has a matching macOS part,
99
+ - every component family is listed in this coverage document,
100
+ - required native variants are exported,
101
+ - nested native variant parts such as pop-up buttons, sheets, and sidebar drawers are exported,
102
+ - every class assigned by the wrapper module has a matching CSS selector,
103
+ - every public wrapper export is represented in the visual gallery source,
104
+ - macOS design features are present: system font stack, dark mode, reduced motion,
105
+ keyboard focus rings, accent tokens, styled `hd-mac` classes, and typography
106
+ constraints,
107
+ - the visual gallery can be bundled for production from the shipped source,
108
+ - old UI-foundation references have not returned.
109
+
110
+ Run the visual gallery with:
111
+
112
+ ```bash
113
+ npm run dev:gallery -- --port 5177
114
+ ```
@@ -0,0 +1,12 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>human-design macOS Base UI gallery</title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="/src/main.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,13 @@
1
+ import { StrictMode } from "react";
2
+ import { createRoot } from "react-dom/client";
3
+ import { AppWindowShell, MacBaseUIGallery } from "../../../src";
4
+ import "../../../src/styles/macosBaseUi.css";
5
+ import "../../../src/styles/macosTauri.css";
6
+
7
+ createRoot(document.getElementById("root") as HTMLElement).render(
8
+ <StrictMode>
9
+ <AppWindowShell>
10
+ <MacBaseUIGallery />
11
+ </AppWindowShell>
12
+ </StrictMode>,
13
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mac-human-design",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
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",
@@ -11,10 +11,17 @@
11
11
  "./theme": "./src/theme/index.ts",
12
12
  "./symbols": "./src/symbols/index.ts",
13
13
  "./tauri": "./src/tauri/index.ts",
14
+ "./tauri/macos-window-config": "./src/tauri/macosWindowConfig.ts",
15
+ "./styles/macos-base-ui.css": "./src/styles/macosBaseUi.css",
14
16
  "./utils": "./src/utils/index.ts",
17
+ "./styles/macos-tauri.css": "./src/styles/macosTauri.css",
15
18
  "./rust": "./src-tauri"
16
19
  },
17
20
  "files": [
21
+ "changelog.md",
22
+ "docs/**/*",
23
+ "examples/**/*",
24
+ "scripts/**/*",
18
25
  "src/**/*",
19
26
  "src-tauri/**/*",
20
27
  "README.md",
@@ -29,31 +36,36 @@
29
36
  "components"
30
37
  ],
31
38
  "scripts": {
32
- "publish": "npm publish --access public --ignore-scripts"
39
+ "check": "npm run typecheck && npm run verify:base-ui && npm run verify:design && npm run verify:gallery",
40
+ "dev:gallery": "vite --host 127.0.0.1 examples/macos-base-ui-gallery",
41
+ "publish": "npm publish --access public --ignore-scripts",
42
+ "typecheck": "tsc --noEmit",
43
+ "verify:base-ui": "node scripts/verify-base-ui-coverage.mjs",
44
+ "verify:design": "node scripts/verify-macos-design.mjs",
45
+ "verify:gallery": "rm -rf .verify/macos-base-ui-gallery && vite build examples/macos-base-ui-gallery --outDir ../../.verify/macos-base-ui-gallery --emptyOutDir && rm -rf .verify/macos-base-ui-gallery"
33
46
  },
34
47
  "author": "human-design",
35
48
  "license": "MIT",
36
49
  "peerDependencies": {
50
+ "@base-ui/react": "^1.5.0",
37
51
  "@tauri-apps/api": "^2",
38
- "baseui": ">=18",
39
52
  "react": ">=18",
40
- "react-dom": ">=18",
41
- "styletron-react": "^6.1.1",
42
- "styletron-standard": "^3.1.0"
53
+ "react-dom": ">=18"
43
54
  },
44
55
  "peerDependenciesMeta": {
45
56
  "@tauri-apps/api": {
46
57
  "optional": true
47
- },
48
- "baseui": {
49
- "optional": true
50
- },
51
- "styletron-react": {
52
- "optional": true
53
- },
54
- "styletron-standard": {
55
- "optional": true
56
58
  }
57
59
  },
58
- "dependencies": {}
60
+ "devDependencies": {
61
+ "@base-ui/react": "^1.5.0",
62
+ "@tauri-apps/api": "^2.11.0",
63
+ "@types/react": "^19.2.17",
64
+ "@types/react-dom": "^19.2.3",
65
+ "@vitejs/plugin-react": "^6.0.2",
66
+ "react": "^19.2.7",
67
+ "react-dom": "^19.2.7",
68
+ "typescript": "^6.0.3",
69
+ "vite": "^8.0.16"
70
+ }
59
71
  }
@@ -0,0 +1,273 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
6
+ const packageJsonPath = path.join(repoRoot, "node_modules", "@base-ui", "react", "package.json");
7
+ const wrapperPath = path.join(repoRoot, "src", "components", "MacBaseUI.tsx");
8
+ const galleryPath = path.join(repoRoot, "src", "components", "MacBaseUIGallery.tsx");
9
+ const stylesPath = path.join(repoRoot, "src", "styles", "macosBaseUi.css");
10
+ const docsPath = path.join(repoRoot, "docs", "macos-base-ui-coverage.md");
11
+
12
+ const nonComponentExports = new Set([
13
+ ".",
14
+ "esm",
15
+ "merge-props",
16
+ "types",
17
+ "unstable-use-media-query",
18
+ "use-render",
19
+ ]);
20
+
21
+ const acronymParts = new Map([
22
+ ["csp", "CSP"],
23
+ ["otp", "OTP"],
24
+ ]);
25
+
26
+ function readText(filePath) {
27
+ return fs.readFileSync(filePath, "utf8");
28
+ }
29
+
30
+ function toMacExportName(family) {
31
+ return `Mac${family
32
+ .split("-")
33
+ .map((part) => acronymParts.get(part) ?? `${part[0].toUpperCase()}${part.slice(1)}`)
34
+ .join("")}`;
35
+ }
36
+
37
+ function getBaseUiFamilies() {
38
+ const packageJson = JSON.parse(readText(packageJsonPath));
39
+ return Object.keys(packageJson.exports)
40
+ .filter((exportKey) => exportKey.startsWith("./"))
41
+ .map((exportKey) => exportKey.slice(2))
42
+ .filter((exportName) => !exportName.startsWith("internals/"))
43
+ .filter((exportName) => exportName !== "package.json")
44
+ .filter((exportName) => !nonComponentExports.has(exportName))
45
+ .sort();
46
+ }
47
+
48
+ function getMacExports(source) {
49
+ return new Set(
50
+ Array.from(source.matchAll(/^export const (Mac[A-Za-z0-9]+)\b/gm), (match) => match[1]),
51
+ );
52
+ }
53
+
54
+ function getBaseUiParts(family) {
55
+ const partsPath = path.join(repoRoot, "node_modules", "@base-ui", "react", family, "index.parts.d.ts");
56
+ if (!fs.existsSync(partsPath)) {
57
+ return [];
58
+ }
59
+
60
+ const partsSource = readText(partsPath);
61
+ const parts = new Set();
62
+
63
+ for (const match of partsSource.matchAll(/export\s+\{\s*[A-Za-z0-9_$]+\s+as\s+([A-Z][A-Za-z0-9_$]*)\s*\}/g)) {
64
+ parts.add(match[1]);
65
+ }
66
+
67
+ for (const match of partsSource.matchAll(/export\s+\{\s*([A-Z][A-Za-z0-9_$]*)\s*\}/g)) {
68
+ parts.add(match[1]);
69
+ }
70
+
71
+ return Array.from(parts).sort();
72
+ }
73
+
74
+ function getMacObjectPartKeys(source, macExport) {
75
+ const objectStart = source.match(new RegExp(`export const ${macExport} = \\\\{`));
76
+ if (!objectStart) {
77
+ return null;
78
+ }
79
+
80
+ const startIndex = objectStart.index + objectStart[0].length;
81
+ let depth = 1;
82
+ let index = startIndex;
83
+
84
+ while (index < source.length && depth > 0) {
85
+ const char = source[index];
86
+ if (char === "{") {
87
+ depth += 1;
88
+ } else if (char === "}") {
89
+ depth -= 1;
90
+ }
91
+ index += 1;
92
+ }
93
+
94
+ const objectBody = source.slice(startIndex, index - 1);
95
+ return new Set(
96
+ Array.from(objectBody.matchAll(/^\s*([A-Z][A-Za-z0-9_$]*):/gm), (match) => match[1]),
97
+ );
98
+ }
99
+
100
+ function fail(message, details = []) {
101
+ console.error(message);
102
+ for (const detail of details) {
103
+ console.error(`- ${detail}`);
104
+ }
105
+ process.exitCode = 1;
106
+ }
107
+
108
+ const families = getBaseUiFamilies();
109
+ const wrapperSource = readText(wrapperPath);
110
+ const gallerySource = readText(galleryPath);
111
+ const stylesSource = readText(stylesPath);
112
+ const docsSource = readText(docsPath);
113
+ const macExports = getMacExports(wrapperSource);
114
+
115
+ const missingWrappers = families
116
+ .map((family) => [family, toMacExportName(family)])
117
+ .filter(([, macExport]) => !macExports.has(macExport))
118
+ .map(([family, macExport]) => `${family} -> ${macExport}`);
119
+
120
+ if (missingWrappers.length > 0) {
121
+ fail("Missing macOS wrappers for public @base-ui/react component families.", missingWrappers);
122
+ }
123
+
124
+ const missingPartWrappers = [];
125
+ for (const family of families) {
126
+ const macExport = toMacExportName(family);
127
+ const baseParts = getBaseUiParts(family);
128
+ if (baseParts.length === 0) {
129
+ continue;
130
+ }
131
+
132
+ const macParts = getMacObjectPartKeys(wrapperSource, macExport);
133
+ if (!macParts) {
134
+ continue;
135
+ }
136
+
137
+ for (const part of baseParts) {
138
+ if (!macParts.has(part)) {
139
+ missingPartWrappers.push(`${family}.${part} -> ${macExport}.${part}`);
140
+ }
141
+ }
142
+ }
143
+
144
+ if (missingPartWrappers.length > 0) {
145
+ fail("Missing macOS wrappers for public @base-ui/react namespace parts.", missingPartWrappers);
146
+ }
147
+
148
+ const missingDocsRows = families
149
+ .map((family) => [family, toMacExportName(family)])
150
+ .filter(([family, macExport]) => {
151
+ return !docsSource.includes(`| \`${family}\` | \`${macExport}\` |`);
152
+ })
153
+ .map(([family, macExport]) => `${family} -> ${macExport}`);
154
+
155
+ if (missingDocsRows.length > 0) {
156
+ fail("Missing coverage documentation rows.", missingDocsRows);
157
+ }
158
+
159
+ const requiredVariants = [
160
+ "MacPrimaryButton",
161
+ "MacSecondaryButton",
162
+ "MacDestructiveButton",
163
+ "MacPlainButton",
164
+ "MacIconButton",
165
+ "MacHelpButton",
166
+ "MacTextField",
167
+ "MacSearchField",
168
+ "MacToolbarToggle",
169
+ "MacSegmentedToggleGroup",
170
+ "MacSeparatedSegmentedToggleGroup",
171
+ ];
172
+
173
+ const missingVariants = requiredVariants.filter((variant) => !macExports.has(variant));
174
+ if (missingVariants.length > 0) {
175
+ fail("Missing expected native macOS variant exports.", missingVariants);
176
+ }
177
+
178
+ const requiredNestedVariants = [
179
+ "MacSelect.PopUpButtonTrigger",
180
+ "MacSelect.PullDownButtonTrigger",
181
+ "MacDialog.SheetPopup",
182
+ "MacDrawer.SidebarPopup",
183
+ "MacToolbar.IconButton",
184
+ ];
185
+
186
+ const missingNestedVariants = requiredNestedVariants.filter((variantPath) => {
187
+ const [exportName, partName] = variantPath.split(".");
188
+ return !new RegExp(`export const ${exportName} = [\\s\\S]*?^\\s*${partName}:`, "m").test(
189
+ wrapperSource,
190
+ );
191
+ });
192
+
193
+ if (missingNestedVariants.length > 0) {
194
+ fail("Missing expected native macOS nested variant exports.", missingNestedVariants);
195
+ }
196
+
197
+ const missingGalleryCoverage = Array.from(macExports)
198
+ .sort()
199
+ .filter((macExport) => !gallerySource.includes(macExport));
200
+
201
+ if (missingGalleryCoverage.length > 0) {
202
+ fail("Missing gallery coverage for public macOS wrapper exports.", missingGalleryCoverage);
203
+ }
204
+
205
+ const wrapperClasses = new Set(
206
+ Array.from(wrapperSource.matchAll(/"([^"]*hd-mac[^"]*)"/g))
207
+ .flatMap((match) => match[1].split(/\s+/))
208
+ .filter(Boolean),
209
+ );
210
+
211
+ const missingClassStyles = Array.from(wrapperClasses)
212
+ .sort()
213
+ .filter((className) => {
214
+ const escapedClassName = className.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
215
+ return !new RegExp(`\\.${escapedClassName}(?![a-zA-Z0-9_-])`).test(stylesSource);
216
+ });
217
+
218
+ if (missingClassStyles.length > 0) {
219
+ fail("Missing CSS selectors for macOS wrapper classes.", missingClassStyles);
220
+ }
221
+
222
+ const forbiddenPatterns = [
223
+ /\bfrom\s+["']baseui(?:\/[^"']*)?["']/,
224
+ /\bbaseui\b/,
225
+ /\bstyletron\b/i,
226
+ /Base Web/,
227
+ ];
228
+
229
+ function listFiles(directory, relativePrefix = "") {
230
+ const files = [];
231
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
232
+ const relativePath = path.join(relativePrefix, entry.name);
233
+ const absolutePath = path.join(directory, entry.name);
234
+ if (entry.isDirectory()) {
235
+ files.push(...listFiles(absolutePath, relativePath));
236
+ } else if (entry.isFile()) {
237
+ files.push(relativePath);
238
+ }
239
+ }
240
+ return files;
241
+ }
242
+
243
+ const sourceFiles = [
244
+ "package.json",
245
+ "package-lock.json",
246
+ "README.md",
247
+ "docs/macos-base-ui-coverage.md",
248
+ ...listFiles(path.join(repoRoot, "src")).map((filePath) => path.join("src", filePath)),
249
+ ...listFiles(path.join(repoRoot, "examples")).map((filePath) => path.join("examples", filePath)),
250
+ ];
251
+
252
+ const forbiddenHits = [];
253
+ for (const relativeFile of sourceFiles) {
254
+ const absoluteFile = path.join(repoRoot, relativeFile);
255
+ const text = readText(absoluteFile);
256
+ for (const pattern of forbiddenPatterns) {
257
+ if (pattern.test(text)) {
258
+ forbiddenHits.push(`${relativeFile}: ${pattern}`);
259
+ }
260
+ }
261
+ }
262
+
263
+ if (forbiddenHits.length > 0) {
264
+ fail("Forbidden Base Web or Styletron references found.", forbiddenHits);
265
+ }
266
+
267
+ if (process.exitCode) {
268
+ process.exit();
269
+ }
270
+
271
+ console.log(
272
+ `Verified ${families.length} @base-ui/react component families, namespace parts, ${requiredVariants.length} native variants, ${requiredNestedVariants.length} nested variants, ${wrapperClasses.size} wrapper classes, gallery coverage, and no Base Web references.`,
273
+ );