@abuzareal/contour-ui 0.5.0 → 0.6.1
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 +16 -0
- package/COMBOBOX.md +87 -0
- package/COMPOSITION.md +4 -0
- package/CONTRACTS.md +27 -27
- package/DOCS.md +86 -0
- package/FORMS.md +4 -0
- package/FOUNDATION.md +35 -0
- package/GETTING-STARTED.md +67 -0
- package/HELPERS.md +33 -0
- package/HOOKS.md +67 -0
- package/MANUAL-QA.md +38 -0
- package/MIGRATION.md +44 -0
- package/MODELS.md +18 -0
- package/NEXTJS.md +3 -1
- package/OVERLAYS.md +4 -0
- package/PROP-REFERENCE.md +37 -0
- package/PUBLIC-API.md +174 -164
- package/README.md +9 -5
- package/RECIPES.md +43 -0
- package/REFERENCE.md +193 -0
- package/RELEASING.md +8 -2
- package/SIZE.md +9 -3
- package/STYLING.md +4 -0
- package/SUPPORT.md +36 -0
- package/THREE.md +40 -0
- package/dist/components/ui/Combobox.d.ts +325 -0
- package/dist/components/ui/Combobox.js +135 -0
- package/dist/components/ui/Combobox.types.d.ts +46 -0
- package/dist/components/ui/Combobox.types.js +1 -0
- package/dist/components/ui/DataTable.js +5 -4
- package/dist/components/ui/Field.js +1 -1
- package/dist/components/ui/FloatingPortal.js +2 -40
- package/dist/components/ui/FloatingScope.d.ts +9 -0
- package/dist/components/ui/FloatingScope.js +43 -0
- package/dist/components/ui/Table.d.ts +20 -0
- package/dist/components/ui/Table.js +9 -0
- package/dist/hooks/useComboboxAnchor.d.ts +17 -0
- package/dist/hooks/useComboboxAnchor.js +61 -0
- package/dist/hooks/useInitialHashScroll.js +5 -1
- package/dist/hooks/usePrintPreparation.js +12 -1
- package/dist/hooks/useScrollSpy.js +6 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/kit/data-display.css +6 -0
- package/dist/kit/forms.css +34 -0
- package/dist/lib/componentClasses.js +1 -1
- package/dist/scoped/kit/data-display.css +6 -0
- package/dist/scoped/kit/forms.css +34 -0
- package/docs/prop-metadata.json +2668 -0
- package/examples/onboarding/SettingsForm.jsx +30 -0
- package/examples/onboarding/SettingsForm.tsx +50 -0
- package/examples/optional/LazyScene.tsx +78 -0
- package/examples/optional/OptionalSmoothScroll.tsx +25 -0
- package/examples/optional/SmoothScrollOwner.tsx +7 -0
- package/examples/optional/optional.css +25 -0
- package/examples/recipes/AsyncProjectPicker.tsx +82 -0
- package/examples/recipes/DeleteProjectConfirmation.tsx +97 -0
- package/examples/recipes/InputCompositions.tsx +49 -0
- package/examples/recipes/RemoteRecordsTable.tsx +256 -0
- package/examples/recipes/useRemoteResource.ts +81 -0
- package/examples/reference/HookExamples.tsx +146 -0
- package/examples/reproduction/README.md +9 -0
- package/examples/reproduction/index.html +14 -0
- package/examples/reproduction/package.json +27 -0
- package/examples/reproduction/src/main.tsx +33 -0
- package/examples/reproduction/src/style.css +19 -0
- package/examples/reproduction/tsconfig.json +18 -0
- package/examples/reproduction/vite.config.ts +19 -0
- package/examples/starters/next/README.md +18 -0
- package/examples/starters/next/app/Demo.tsx +65 -0
- package/examples/starters/next/app/layout.tsx +25 -0
- package/examples/starters/next/app/next-page/page.tsx +9 -0
- package/examples/starters/next/app/page.tsx +11 -0
- package/examples/starters/next/app/style.css +19 -0
- package/examples/starters/next/next-env.d.ts +2 -0
- package/examples/starters/next/next.config.mjs +1 -0
- package/examples/starters/next/package.json +27 -0
- package/examples/starters/next/proxy.ts +16 -0
- package/examples/starters/next/tsconfig.json +30 -0
- package/examples/starters/vite/README.md +16 -0
- package/examples/starters/vite/index.html +14 -0
- package/examples/starters/vite/package.json +27 -0
- package/examples/starters/vite/src/main.tsx +81 -0
- package/examples/starters/vite/src/style.css +19 -0
- package/examples/starters/vite/tsconfig.json +18 -0
- package/examples/starters/vite/vite.config.ts +19 -0
- package/package.json +37 -4
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import Link from "next/link";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Combobox,
|
|
7
|
+
Dialog,
|
|
8
|
+
TextField,
|
|
9
|
+
ThemeToggle,
|
|
10
|
+
buttonClassName,
|
|
11
|
+
} from "@abuzareal/contour-ui";
|
|
12
|
+
const projects = [
|
|
13
|
+
{ value: "atlas", label: "Atlas" },
|
|
14
|
+
{ value: "field", label: "Field notes" },
|
|
15
|
+
];
|
|
16
|
+
export default function Demo() {
|
|
17
|
+
const [open, setOpen] = useState(false),
|
|
18
|
+
[payload, setPayload] = useState("");
|
|
19
|
+
const name = useRef<HTMLInputElement>(null);
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
<p>This form inspects local values. It does not save data.</p>
|
|
23
|
+
<ThemeToggle animate={false} />
|
|
24
|
+
<form
|
|
25
|
+
onSubmit={(event) => {
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
setPayload(
|
|
28
|
+
JSON.stringify(
|
|
29
|
+
Object.fromEntries(new FormData(event.currentTarget)),
|
|
30
|
+
),
|
|
31
|
+
);
|
|
32
|
+
}}
|
|
33
|
+
>
|
|
34
|
+
<TextField
|
|
35
|
+
ref={name}
|
|
36
|
+
label="Name"
|
|
37
|
+
name="name"
|
|
38
|
+
defaultValue="Ada"
|
|
39
|
+
required
|
|
40
|
+
/>
|
|
41
|
+
<Combobox
|
|
42
|
+
label="Project"
|
|
43
|
+
name="project"
|
|
44
|
+
options={projects}
|
|
45
|
+
defaultValue="atlas"
|
|
46
|
+
required
|
|
47
|
+
/>
|
|
48
|
+
<Button type="submit">Inspect values</Button>
|
|
49
|
+
<Button type="reset" variant="secondary">
|
|
50
|
+
Reset form
|
|
51
|
+
</Button>
|
|
52
|
+
</form>
|
|
53
|
+
<output aria-label="Form values">{payload}</output>
|
|
54
|
+
<Button onClick={() => name.current?.focus()}>Focus name</Button>
|
|
55
|
+
<Button onClick={() => setOpen(true)}>Open dialog</Button>
|
|
56
|
+
<Dialog open={open} onClose={() => setOpen(false)} title="Starter dialog">
|
|
57
|
+
<p>Try Tab, Escape and focus return.</p>
|
|
58
|
+
<Button onClick={() => setOpen(false)}>Done</Button>
|
|
59
|
+
</Dialog>
|
|
60
|
+
<Link href="/next-page" className={buttonClassName("secondary")}>
|
|
61
|
+
Next page
|
|
62
|
+
</Link>
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { headers } from "next/headers";
|
|
2
|
+
import { themeBootstrapScript } from "@abuzareal/contour-ui/theme-bootstrap";
|
|
3
|
+
import "@abuzareal/contour-ui/scoped.css";
|
|
4
|
+
import "./style.css";
|
|
5
|
+
export const dynamic = "force-dynamic";
|
|
6
|
+
export const metadata = { title: "Contour Next starter" };
|
|
7
|
+
export default async function Layout({
|
|
8
|
+
children,
|
|
9
|
+
}: {
|
|
10
|
+
children: React.ReactNode;
|
|
11
|
+
}) {
|
|
12
|
+
const nonce = (await headers()).get("x-nonce") ?? undefined;
|
|
13
|
+
return (
|
|
14
|
+
<html lang="en" suppressHydrationWarning>
|
|
15
|
+
<head>
|
|
16
|
+
<meta name="theme-color" content="#f2f3ee" />
|
|
17
|
+
<script
|
|
18
|
+
nonce={nonce}
|
|
19
|
+
dangerouslySetInnerHTML={{ __html: themeBootstrapScript }}
|
|
20
|
+
/>
|
|
21
|
+
</head>
|
|
22
|
+
<body>{children}</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { safeHref } from "@abuzareal/contour-ui";
|
|
2
|
+
import Demo from "./Demo";
|
|
3
|
+
export default function Page() {
|
|
4
|
+
return (
|
|
5
|
+
<main className="contour-root starter">
|
|
6
|
+
<h1>Contour Next starter</h1>
|
|
7
|
+
<p>Server helper result: {safeHref("/next-page")}</p>
|
|
8
|
+
<Demo />
|
|
9
|
+
</main>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
background: var(--contour-bg);
|
|
4
|
+
color: var(--contour-fg);
|
|
5
|
+
}
|
|
6
|
+
.starter {
|
|
7
|
+
max-width: 42rem;
|
|
8
|
+
margin: 0 auto;
|
|
9
|
+
padding: 2rem 1rem;
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: 1.25rem;
|
|
12
|
+
}
|
|
13
|
+
.starter form {
|
|
14
|
+
display: grid;
|
|
15
|
+
gap: 1rem;
|
|
16
|
+
}
|
|
17
|
+
.starter output {
|
|
18
|
+
overflow-wrap: anywhere;
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default { experimental: { cpus: 2 } };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"private": true,
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.12.0"
|
|
7
|
+
},
|
|
8
|
+
"name": "contour-next-starter",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "next dev --webpack",
|
|
11
|
+
"build": "next build --webpack",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"start": "next start"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@abuzareal/contour-ui": "0.6.1",
|
|
17
|
+
"react": "19.3.0",
|
|
18
|
+
"react-dom": "19.3.0",
|
|
19
|
+
"next": "16.4.0"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/react": "19.3.0",
|
|
23
|
+
"@types/react-dom": "19.3.0",
|
|
24
|
+
"@types/node": "26.6.5",
|
|
25
|
+
"typescript": "7.0.2"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NextResponse, type NextRequest } from "next/server";
|
|
2
|
+
export function proxy(request: NextRequest) {
|
|
3
|
+
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
|
|
4
|
+
const development =
|
|
5
|
+
process.env.NODE_ENV === "development" ? " 'unsafe-eval'" : "";
|
|
6
|
+
const policy = `default-src 'self'; script-src 'self' 'nonce-${nonce}' 'strict-dynamic'${development}; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'`;
|
|
7
|
+
const headers = new Headers(request.headers);
|
|
8
|
+
headers.set("x-nonce", nonce);
|
|
9
|
+
headers.set("Content-Security-Policy", policy);
|
|
10
|
+
const response = NextResponse.next({ request: { headers } });
|
|
11
|
+
response.headers.set("Content-Security-Policy", policy);
|
|
12
|
+
return response;
|
|
13
|
+
}
|
|
14
|
+
export const config = {
|
|
15
|
+
matcher: ["/((?!api|_next/static|_next/image|favicon.svg).*)"],
|
|
16
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ES2024"],
|
|
5
|
+
"strict": true,
|
|
6
|
+
"skipLibCheck": false,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"moduleResolution": "Bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"plugins": [
|
|
16
|
+
{
|
|
17
|
+
"name": "next"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"allowJs": true,
|
|
21
|
+
"incremental": true
|
|
22
|
+
},
|
|
23
|
+
"include": [
|
|
24
|
+
"**/*.ts",
|
|
25
|
+
"**/*.tsx",
|
|
26
|
+
".next/types/**/*.ts",
|
|
27
|
+
".next/dev/types/**/*.ts"
|
|
28
|
+
],
|
|
29
|
+
"exclude": ["node_modules"]
|
|
30
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Contour + Vite
|
|
2
|
+
|
|
3
|
+
Copy this folder into a new directory. Node 22.12 or newer is required. Direct dependencies are pinned; `npm install` creates the application's own lockfile. Commit that lockfile and use `npm ci` for later installs.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --strict-peer-deps
|
|
7
|
+
npm run dev
|
|
8
|
+
npm run build
|
|
9
|
+
npm run preview
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Uses Contour 0.6.1, React/React DOM 18.3.1, TypeScript 5.9.3 and Vite 8.3.2. No aliases, workspace links, optional peers, font download, private catalogue or provider are required. Scoped CSS includes tokens and component families without the legacy global reset. The application owns the small body/layout stylesheet. Optional branded fonts: import `@abuzareal/contour-ui/fonts-latin.css` once.
|
|
13
|
+
|
|
14
|
+
The Vite config inserts the exact released theme bootstrap before the application, with a calculated CSP script hash. Keep the placeholder in index.html; recalculate through the build after upgrades. Script execution is restricted; style attributes are allowed because popup positioning and some components use inline styles. Extend connect-src intentionally for your service/development socket. An HTTP CSP header may replace this meta policy if it contains the same hash. See the package GETTING-STARTED.md for embedded themes and optional features.
|
|
15
|
+
|
|
16
|
+
Run against the registry after the release is published. Release candidates are tested with the verified npm archive in a disposable copy; an unpublished candidate version will not install from npm yet.
|
|
@@ -0,0 +1,14 @@
|
|
|
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" />
|
|
6
|
+
<meta name="theme-color" content="#f2f3ee" />
|
|
7
|
+
<!-- theme-bootstrap -->
|
|
8
|
+
<title>Contour starter</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"private": true,
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=22.12.0"
|
|
7
|
+
},
|
|
8
|
+
"name": "contour-vite-starter",
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "vite",
|
|
11
|
+
"typecheck": "tsc --noEmit",
|
|
12
|
+
"build": "tsc --noEmit && vite build",
|
|
13
|
+
"preview": "vite preview"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@abuzareal/contour-ui": "0.6.1",
|
|
17
|
+
"react": "18.3.1",
|
|
18
|
+
"react-dom": "18.3.1"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@types/react": "18.3.31",
|
|
22
|
+
"@types/react-dom": "18.3.7",
|
|
23
|
+
"@types/node": "26.6.5",
|
|
24
|
+
"typescript": "5.9.3",
|
|
25
|
+
"vite": "8.3.2"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { StrictMode, useRef, useState } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
Combobox,
|
|
6
|
+
Dialog,
|
|
7
|
+
TextField,
|
|
8
|
+
ThemeToggle,
|
|
9
|
+
buttonClassName,
|
|
10
|
+
} from "@abuzareal/contour-ui";
|
|
11
|
+
import "@abuzareal/contour-ui/scoped.css";
|
|
12
|
+
import "./style.css";
|
|
13
|
+
const projects = [
|
|
14
|
+
{ value: "atlas", label: "Atlas" },
|
|
15
|
+
{ value: "field", label: "Field notes" },
|
|
16
|
+
];
|
|
17
|
+
function App() {
|
|
18
|
+
const [open, setOpen] = useState(false),
|
|
19
|
+
[payload, setPayload] = useState("");
|
|
20
|
+
const name = useRef<HTMLInputElement>(null);
|
|
21
|
+
return (
|
|
22
|
+
<main className="contour-root starter">
|
|
23
|
+
<h1>Contour starter</h1>
|
|
24
|
+
<p>This form inspects local values. It does not save data.</p>
|
|
25
|
+
<ThemeToggle animate={false} />
|
|
26
|
+
<form
|
|
27
|
+
onSubmit={(event) => {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
setPayload(
|
|
30
|
+
JSON.stringify(
|
|
31
|
+
Object.fromEntries(new FormData(event.currentTarget)),
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<TextField
|
|
37
|
+
ref={name}
|
|
38
|
+
label="Name"
|
|
39
|
+
name="name"
|
|
40
|
+
defaultValue="Ada"
|
|
41
|
+
required
|
|
42
|
+
/>
|
|
43
|
+
<Combobox
|
|
44
|
+
label="Project"
|
|
45
|
+
name="project"
|
|
46
|
+
options={projects}
|
|
47
|
+
defaultValue="atlas"
|
|
48
|
+
required
|
|
49
|
+
/>
|
|
50
|
+
<Button type="submit">Inspect values</Button>
|
|
51
|
+
<Button type="reset" variant="secondary">
|
|
52
|
+
Reset form
|
|
53
|
+
</Button>
|
|
54
|
+
</form>
|
|
55
|
+
<output aria-label="Form values">{payload}</output>
|
|
56
|
+
<Button onClick={() => name.current?.focus()}>Focus name</Button>
|
|
57
|
+
<Button onClick={() => setOpen(true)}>Open dialog</Button>
|
|
58
|
+
<Dialog open={open} onClose={() => setOpen(false)} title="Starter dialog">
|
|
59
|
+
<p>Try Tab, Escape and focus return.</p>
|
|
60
|
+
<Button onClick={() => setOpen(false)}>Done</Button>
|
|
61
|
+
</Dialog>
|
|
62
|
+
<a className={buttonClassName("secondary")} href="#integration">
|
|
63
|
+
Integration notes
|
|
64
|
+
</a>
|
|
65
|
+
<section id="integration">
|
|
66
|
+
<h2>Application ownership</h2>
|
|
67
|
+
<p>
|
|
68
|
+
Add your own router, validation and persistence. No provider is
|
|
69
|
+
required by the controls above.
|
|
70
|
+
</p>
|
|
71
|
+
</section>
|
|
72
|
+
</main>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const root = document.getElementById("root");
|
|
76
|
+
if (!root) throw new Error("Missing root element");
|
|
77
|
+
createRoot(root).render(
|
|
78
|
+
<StrictMode>
|
|
79
|
+
<App />
|
|
80
|
+
</StrictMode>,
|
|
81
|
+
);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
background: var(--contour-bg);
|
|
4
|
+
color: var(--contour-fg);
|
|
5
|
+
}
|
|
6
|
+
.starter {
|
|
7
|
+
max-width: 42rem;
|
|
8
|
+
margin: 0 auto;
|
|
9
|
+
padding: 2rem 1rem;
|
|
10
|
+
display: grid;
|
|
11
|
+
gap: 1.25rem;
|
|
12
|
+
}
|
|
13
|
+
.starter form {
|
|
14
|
+
display: grid;
|
|
15
|
+
gap: 1rem;
|
|
16
|
+
}
|
|
17
|
+
.starter output {
|
|
18
|
+
overflow-wrap: anywhere;
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
5
|
+
"strict": true,
|
|
6
|
+
"skipLibCheck": false,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"module": "ESNext",
|
|
10
|
+
"moduleResolution": "Bundler",
|
|
11
|
+
"allowImportingTsExtensions": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"isolatedModules": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
17
|
+
"exclude": ["node_modules"]
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { defineConfig } from "vite";
|
|
3
|
+
import { themeBootstrapScript } from "@abuzareal/contour-ui/theme-bootstrap";
|
|
4
|
+
const hash = createHash("sha256").update(themeBootstrapScript).digest("base64");
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [
|
|
7
|
+
{
|
|
8
|
+
name: "contour-theme-bootstrap",
|
|
9
|
+
transformIndexHtml(html) {
|
|
10
|
+
// Hash the exact bytes inserted here; no inline handler or unsafe-eval allowance.
|
|
11
|
+
const policy = `default-src 'self'; script-src 'self' 'sha256-${hash}'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'`;
|
|
12
|
+
return html.replace(
|
|
13
|
+
"<!-- theme-bootstrap -->",
|
|
14
|
+
`<meta http-equiv="Content-Security-Policy" content="${policy}"><script>${themeBootstrapScript}</script>`,
|
|
15
|
+
);
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abuzareal/contour-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Editorial React components, themes, restrained motion, and optional Three.js objects.",
|
|
6
6
|
"type": "module",
|
|
@@ -21,7 +21,28 @@
|
|
|
21
21
|
"examples/forms",
|
|
22
22
|
"OVERLAYS.md",
|
|
23
23
|
"STYLING.md",
|
|
24
|
-
"SIZE.md"
|
|
24
|
+
"SIZE.md",
|
|
25
|
+
"FOUNDATION.md",
|
|
26
|
+
"COMBOBOX.md",
|
|
27
|
+
"RECIPES.md",
|
|
28
|
+
"GETTING-STARTED.md",
|
|
29
|
+
"DOCS.md",
|
|
30
|
+
"examples/recipes",
|
|
31
|
+
"examples/starters",
|
|
32
|
+
"examples/reproduction",
|
|
33
|
+
"examples/optional",
|
|
34
|
+
"HOOKS.md",
|
|
35
|
+
"HELPERS.md",
|
|
36
|
+
"THREE.md",
|
|
37
|
+
"REFERENCE.md",
|
|
38
|
+
"PROP-REFERENCE.md",
|
|
39
|
+
"MIGRATION.md",
|
|
40
|
+
"MODELS.md",
|
|
41
|
+
"SUPPORT.md",
|
|
42
|
+
"MANUAL-QA.md",
|
|
43
|
+
"docs/prop-metadata.json",
|
|
44
|
+
"examples/onboarding",
|
|
45
|
+
"examples/reference"
|
|
25
46
|
],
|
|
26
47
|
"sideEffects": [
|
|
27
48
|
"**/*.css"
|
|
@@ -71,7 +92,7 @@
|
|
|
71
92
|
"test": "node --test tests/*.test.mjs",
|
|
72
93
|
"test:browser": "node --test tests/*.browser.mjs",
|
|
73
94
|
"check:package": "node scripts/check-package.mjs",
|
|
74
|
-
"validate": "npm run check:styles && npm run typecheck && npm run lint && npm run build && npm test && npm run test:browser && npm run check:package",
|
|
95
|
+
"validate": "npm run check:styles && npm run typecheck && npm run lint && npm run build && npm run check:docs && npm run check:reference && npm run check:onboarding && npm test && npm run test:browser && npm run check:package",
|
|
75
96
|
"prepublishOnly": "node scripts/verify-release.mjs",
|
|
76
97
|
"test:consumer": "node scripts/test-consumer.mjs",
|
|
77
98
|
"test:compat": "node scripts/test-compat.mjs",
|
|
@@ -83,9 +104,18 @@
|
|
|
83
104
|
"measure:size": "node scripts/measure-size.mjs",
|
|
84
105
|
"check:size": "node scripts/measure-size.mjs --check",
|
|
85
106
|
"check:api-docs": "node scripts/check-api-docs.mjs",
|
|
86
|
-
"check:styles": "node scripts/build-styles.mjs --check"
|
|
107
|
+
"check:styles": "node scripts/build-styles.mjs --check",
|
|
108
|
+
"test:adoption-recipes": "node scripts/test-adoption-recipes.mjs",
|
|
109
|
+
"test:starters": "node scripts/test-starters.mjs",
|
|
110
|
+
"check:docs": "node scripts/check-docs.mjs",
|
|
111
|
+
"test:qa": "playwright test --config playwright.qa.config.mjs",
|
|
112
|
+
"check:reference": "node scripts/check-reference.mjs",
|
|
113
|
+
"check:onboarding": "node scripts/build-onboarding.mjs",
|
|
114
|
+
"qa:preview": "node scripts/qa-preview.mjs",
|
|
115
|
+
"test:diagnostic:upstream": "playwright test --config playwright.upstream.config.mjs"
|
|
87
116
|
},
|
|
88
117
|
"dependencies": {
|
|
118
|
+
"@base-ui/react": "1.9.0",
|
|
89
119
|
"@floating-ui/dom": "1.8.0",
|
|
90
120
|
"@fontsource-variable/dm-sans": "^5.3.0",
|
|
91
121
|
"@fontsource-variable/space-grotesk": "^5.3.0",
|
|
@@ -107,7 +137,10 @@
|
|
|
107
137
|
}
|
|
108
138
|
},
|
|
109
139
|
"devDependencies": {
|
|
140
|
+
"@axe-core/playwright": "4.13.0",
|
|
110
141
|
"@playwright/test": "1.63.0",
|
|
142
|
+
"@tanstack/react-store": "0.11.2",
|
|
143
|
+
"@tanstack/react-table": "9.3.1",
|
|
111
144
|
"@testing-library/react": "^16.3.3",
|
|
112
145
|
"@types/react": "^18.3.5",
|
|
113
146
|
"@types/react-dom": "^18.3.0",
|