Skip to content

Commit 5e04275

Browse files
authored
chore: reduce future diff noise (formatting/hooks) + fix TS Node typings and a11y lint (#30)
**Context** This PR is a maintenance pass to make future feature work less noisy and easier to review. It standardizes formatting and pre-commit behavior, and fixes a handful of TypeScript and accessibility lint issues that otherwise keep resurfacing during unrelated changes. **What Changed** - Tooling / formatting - Add Prettier config + lint-staged + Husky pre-commit hook. - Add editor settings to format on save (modifications only) and keep imports organized. - Disable the “no inline styles” hint rule (the codebase intentionally uses inline styles in many places). - TypeScript / module resolution - Add `@types/node` where Node built-ins are imported (SSG + example configs). - Stop excluding SSG files from the root TS project so they are typechecked normally. - Define `ImportMetaEnv` to type `import.meta.env.SSG_MD`, `EXAMPLES`, `SSG_PREVIEWS`. - Fix Shiki dynamic import typing (`import('shiki')` is a Promise; `.then` is not a type member). - Accessibility lint fixes - Use valid, literal `aria-orientation` values on the split pane separator. - Add accessible names (`aria-label`) for `<select>` and related `<input>` controls in the example app. **Why This Helps** - Prevents formatting churn in future PRs (review diffs stay focused on behavior changes). - Avoids repeated TS noise around Node built-ins and `import.meta.env` typing. - Keeps a11y lint from blocking unrelated changes. **Verification** - `pnpm typecheck` (repo root) - `pnpm exec tsc --noEmit` (under `example/`)
1 parent 39e47ff commit 5e04275

30 files changed

+6083
-2057
lines changed

.hintrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": [
3+
"development"
4+
],
5+
"hints": {
6+
"no-inline-styles": "off"
7+
}
8+
}

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
lint-staged

.prettierrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"plugins": ["prettier-plugin-packagejson"],
3+
"singleQuote": true
4+
}

.vscode/settings.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"editor.formatOnSave": true,
3+
"editor.formatOnSaveMode": "modifications",
4+
"editor.codeActionsOnSave": {
5+
"source.fixAll": "explicit",
6+
"source.organizeImports": "explicit"
7+
},
8+
"editor.defaultFormatter": "esbenp.prettier-vscode",
9+
"[javascript]": {
10+
"editor.defaultFormatter": "esbenp.prettier-vscode"
11+
},
12+
"[javascriptreact]": {
13+
"editor.defaultFormatter": "esbenp.prettier-vscode"
14+
},
15+
"[typescript]": {
16+
"editor.defaultFormatter": "esbenp.prettier-vscode"
17+
},
18+
"[typescriptreact]": {
19+
"editor.defaultFormatter": "esbenp.prettier-vscode"
20+
},
21+
"prettier.singleQuote": true,
22+
"prettier.jsxSingleQuote": true,
23+
"javascript.preferences.quoteStyle": "single",
24+
"typescript.preferences.quoteStyle": "single"
25+
}

README.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const config = {
1515

1616
<GoConfigProvider config={config}>
1717
<Go example="hello-world" defaultFile="src/App.tsx" />
18-
</GoConfigProvider>
18+
</GoConfigProvider>;
1919
```
2020

2121
### With rspress
@@ -31,7 +31,7 @@ const config = {
3131

3232
<GoConfigProvider config={config}>
3333
<Go example="hello-world" />
34-
</GoConfigProvider>
34+
</GoConfigProvider>;
3535
```
3636

3737
### SSG (Static Site Generation)
@@ -57,7 +57,7 @@ const config = {
5757

5858
<GoConfigProvider config={config}>
5959
<Go example="hello-world" defaultFile="src/App.tsx" />
60-
</GoConfigProvider>
60+
</GoConfigProvider>;
6161
```
6262

6363
#### Option B: Pure function (build-time injection)
@@ -102,16 +102,16 @@ For non-React sites (Hugo, Jekyll, plain HTML, etc.), use the iframe embed API.
102102

103103
Options:
104104

105-
| Option | Type | Description |
106-
|--------|------|-------------|
107-
| `example` | `string` | **Required.** Example folder name |
108-
| `defaultFile` | `string` | Initial file to display (default: `'src/App.tsx'`) |
109-
| `defaultTab` | `'preview' \| 'web' \| 'qrcode'` | Default preview tab |
110-
| `exampleBasePath` | `string` | Base path or full URL for example data |
111-
| `img` | `string` | Static preview image URL |
112-
| `defaultEntryFile` | `string` | Default entry file for web preview |
113-
| `highlight` | `string` | Line highlight spec, e.g. `'{1,3-5}'` |
114-
| `entry` | `string \| string[]` | Filter entry files in tree |
105+
| Option | Type | Description |
106+
| ------------------ | -------------------------------- | -------------------------------------------------- |
107+
| `example` | `string` | **Required.** Example folder name |
108+
| `defaultFile` | `string` | Initial file to display (default: `'src/App.tsx'`) |
109+
| `defaultTab` | `'preview' \| 'web' \| 'qrcode'` | Default preview tab |
110+
| `exampleBasePath` | `string` | Base path or full URL for example data |
111+
| `img` | `string` | Static preview image URL |
112+
| `defaultEntryFile` | `string` | Default entry file for web preview |
113+
| `highlight` | `string` | Line highlight spec, e.g. `'{1,3-5}'` |
114+
| `entry` | `string \| string[]` | Filter entry files in tree |
115115

116116
## Development
117117

example-iframe-embed/index.html

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html lang="en">
33
<head>
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>Go Web — Iframe Embed Test</title>
77
<style>
8-
* { box-sizing: border-box; margin: 0; padding: 0; }
8+
* {
9+
box-sizing: border-box;
10+
margin: 0;
11+
padding: 0;
12+
}
913

1014
body {
11-
font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif;
15+
font-family:
16+
-apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', sans-serif;
1217
background: #f0f0f0;
1318
color: #333;
1419
padding: 40px;
@@ -29,7 +34,7 @@
2934
height: 500px;
3035
border-radius: 12px;
3136
overflow: hidden;
32-
box-shadow: 0 4px 24px rgba(0,0,0,0.12);
37+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
3338
margin-bottom: 32px;
3439
}
3540

@@ -49,8 +54,14 @@
4954
font-size: 14px;
5055
}
5156

52-
button:hover { background: #f5f5f5; }
53-
button.active { background: #0071e3; color: #fff; border-color: #0071e3; }
57+
button:hover {
58+
background: #f5f5f5;
59+
}
60+
button.active {
61+
background: #0071e3;
62+
color: #fff;
63+
border-color: #0071e3;
64+
}
5465

5566
code {
5667
background: #e8e8e8;
@@ -86,34 +97,34 @@
8697
font-size: 14px;
8798
line-height: 1.5;
8899
}
89-
90100
</style>
91101
</head>
92102
<body>
93103
<h1>Iframe Embed API Test</h1>
94104
<p>
95105
This page demonstrates the <code>@lynx-js/go-web</code> iframe embed API.
96-
It loads the Go component inside an iframe via a pure JS <code>mount()</code> call —
97-
no React dependency needed on the host page.
106+
It loads the Go component inside an iframe via a pure JS
107+
<code>mount()</code> call — no React dependency needed on the host page.
98108
</p>
99109

100110
<div class="info">
101-
<strong>How to test:</strong><br/>
102-
1. Start dev server: <code>cd example && pnpm dev</code> (serves on <strong>localhost:5969</strong>)<br/>
103-
2. Open this file in a browser (or <code>npx serve example-iframe-embed</code>)<br/>
104-
Example data is proxied from <strong>go.lynxjs.org</strong> via <code>/proxy-lynx-examples</code>.
111+
<strong>How to test:</strong><br />
112+
1. Start dev server: <code>cd example && pnpm dev</code> (serves on
113+
<strong>localhost:5969</strong>)<br />
114+
2. Open this file in a browser (or
115+
<code>npx serve example-iframe-embed</code>)<br />
116+
Example data is proxied from <strong>go.lynxjs.org</strong> via
117+
<code>/proxy-lynx-examples</code>.
105118
</div>
106119

107120
<h2>Usage</h2>
108-
<div class="code-block">&lt;div id="demo" style="height: 500px"&gt;&lt;/div&gt;
109-
&lt;script type="module"&gt;
110-
import { mount } from 'https://go.lynxjs.org/embed.js';
111-
mount('#demo', {
112-
example: 'hello-world',
113-
defaultFile: 'src/App.tsx',
114-
exampleBasePath: 'https://go.lynxjs.org/lynx-examples',
115-
});
116-
&lt;/script&gt;</div>
121+
<div class="code-block">
122+
&lt;div id="demo" style="height: 500px"&gt;&lt;/div&gt; &lt;script
123+
type="module"&gt; import { mount } from 'https://go.lynxjs.org/embed.js';
124+
mount('#demo', { example: 'hello-world', defaultFile: 'src/App.tsx',
125+
exampleBasePath: 'https://go.lynxjs.org/lynx-examples', });
126+
&lt;/script&gt;
127+
</div>
117128

118129
<h2>Live Demo</h2>
119130

@@ -138,9 +149,10 @@ <h2>Live Demo</h2>
138149
// ---------------------------------------------------------------------------
139150

140151
function mount(container, options) {
141-
const el = typeof container === 'string'
142-
? document.querySelector(container)
143-
: container;
152+
const el =
153+
typeof container === 'string'
154+
? document.querySelector(container)
155+
: container;
144156

145157
if (!el) throw new Error('Container not found: ' + container);
146158

@@ -155,10 +167,13 @@ <h2>Live Demo</h2>
155167
function handleMessage(event) {
156168
if (event.source !== iframe.contentWindow) return;
157169
if (event.data?.type === 'go-embed:ready') {
158-
iframe.contentWindow.postMessage({
159-
type: 'go-embed:init',
160-
options: currentOptions,
161-
}, '*');
170+
iframe.contentWindow.postMessage(
171+
{
172+
type: 'go-embed:init',
173+
options: currentOptions,
174+
},
175+
'*',
176+
);
162177
}
163178
}
164179

@@ -170,10 +185,13 @@ <h2>Live Demo</h2>
170185
iframe,
171186
update(newOptions) {
172187
currentOptions = { ...currentOptions, ...newOptions };
173-
iframe.contentWindow.postMessage({
174-
type: 'go-embed:update',
175-
options: newOptions,
176-
}, '*');
188+
iframe.contentWindow.postMessage(
189+
{
190+
type: 'go-embed:update',
191+
options: newOptions,
192+
},
193+
'*',
194+
);
177195
},
178196
destroy() {
179197
window.removeEventListener('message', handleMessage);
@@ -190,17 +208,28 @@ <h2>Live Demo</h2>
190208
// Try a few known examples; the production site doesn't expose a directory listing.
191209
// Requests go through the dev server proxy to avoid CORS.
192210
const knownExamples = [
193-
'hello-world', 'text', 'view', 'image', 'css',
194-
'scroll-view', 'list', 'navigator',
211+
'hello-world',
212+
'text',
213+
'view',
214+
'image',
215+
'css',
216+
'scroll-view',
217+
'list',
218+
'navigator',
195219
];
196220

197221
const available = [];
198222
await Promise.all(
199223
knownExamples.map(async (name) => {
200224
try {
201-
const res = await fetch(`${EMBED_BASE}${EXAMPLE_BASE_PATH}/${name}/example-metadata.json`, { method: 'HEAD' });
225+
const res = await fetch(
226+
`${EMBED_BASE}${EXAMPLE_BASE_PATH}/${name}/example-metadata.json`,
227+
{ method: 'HEAD' },
228+
);
202229
if (res.ok) available.push(name);
203-
} catch { /* skip */ }
230+
} catch {
231+
/* skip */
232+
}
204233
}),
205234
);
206235

@@ -237,7 +266,9 @@ <h2>Live Demo</h2>
237266
btn.textContent = ex.name;
238267
if (i === 0) btn.classList.add('active');
239268
btn.addEventListener('click', () => {
240-
controls.querySelectorAll('button').forEach(b => b.classList.remove('active'));
269+
controls
270+
.querySelectorAll('button')
271+
.forEach((b) => b.classList.remove('active'));
241272
btn.classList.add('active');
242273
embed.destroy();
243274
embed = mount('#demo', {
@@ -249,7 +280,6 @@ <h2>Live Demo</h2>
249280
});
250281
controls.appendChild(btn);
251282
});
252-
253283
</script>
254284
</body>
255285
</html>

example-rspress/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
"private": true,
44
"type": "module",
55
"scripts": {
6-
"prepare": "node scripts/prepare-examples.js",
7-
"prepare:clean": "node scripts/prepare-examples.js --clean",
6+
"build": "rspress build",
87
"dev": "rspress dev",
9-
"build": "rspress build"
8+
"prepare": "node scripts/prepare-examples.js",
9+
"prepare:clean": "node scripts/prepare-examples.js --clean"
1010
},
1111
"dependencies": {
12-
"@lynx-js/go-web": "file:..",
13-
"@rspress/core": "^2.0.3",
1412
"@douyinfe/semi-icons": "^2.74.0",
1513
"@douyinfe/semi-ui": "^2.75.0",
14+
"@lynx-js/go-web": "file:..",
1615
"@lynx-js/web-core": "npm:@lynx-js/web-core-canary@0.19.7-canary-20260126-5e7e43c5",
1716
"@lynx-js/web-elements": "^0.11.0",
17+
"@rspress/core": "^2.0.3",
1818
"@shikijs/transformers": "^3.4.2",
1919
"qrcode.react": "^4.2.0",
2020
"react": "^18.2.0",
@@ -25,9 +25,10 @@
2525
},
2626
"devDependencies": {
2727
"@rsbuild/plugin-sass": "^1.3.0",
28+
"@types/node": "^22.15.3",
2829
"@types/react": "^18.2.0",
29-
"@types/react-dom": "^18.2.0",
3030
"@types/react-copy-to-clipboard": "^5.0.7",
31+
"@types/react-dom": "^18.2.0",
3132
"typescript": "^5.7.0"
3233
}
3334
}

0 commit comments

Comments
 (0)