@abuzareal/contour-ui 0.1.1 → 0.2.0

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +86 -11
  2. package/CODE_OF_CONDUCT.md +5 -0
  3. package/CONTRIBUTING.md +15 -0
  4. package/NEXTJS.md +51 -0
  5. package/README.md +176 -76
  6. package/RELEASING.md +14 -28
  7. package/SECURITY.md +1 -1
  8. package/dist/components/hero/SceneBoundary.js +1 -0
  9. package/dist/components/hero/Sculpture.js +6 -4
  10. package/dist/components/three/ObjectStudy.js +7 -3
  11. package/dist/components/ui/Alert.js +1 -0
  12. package/dist/components/ui/BrandMark.js +1 -0
  13. package/dist/components/ui/Checkbox.js +1 -0
  14. package/dist/components/ui/CountUp.js +1 -0
  15. package/dist/components/ui/DataTable.js +1 -0
  16. package/dist/components/ui/Dialog.js +1 -0
  17. package/dist/components/ui/DropdownMenu.d.ts +7 -1
  18. package/dist/components/ui/DropdownMenu.js +62 -14
  19. package/dist/components/ui/FlipCard.js +1 -0
  20. package/dist/components/ui/Magnetic.js +1 -0
  21. package/dist/components/ui/Pagination.js +1 -0
  22. package/dist/components/ui/Popover.d.ts +4 -1
  23. package/dist/components/ui/Popover.js +7 -5
  24. package/dist/components/ui/RadioGroup.js +1 -0
  25. package/dist/components/ui/Reveal.js +1 -0
  26. package/dist/components/ui/ScrollProgress.js +1 -0
  27. package/dist/components/ui/SegmentedControl.js +1 -0
  28. package/dist/components/ui/SelectField.d.ts +11 -1
  29. package/dist/components/ui/SelectField.js +6 -4
  30. package/dist/components/ui/Slider.js +1 -0
  31. package/dist/components/ui/Switch.js +1 -0
  32. package/dist/components/ui/Tabs.d.ts +4 -1
  33. package/dist/components/ui/Tabs.js +12 -5
  34. package/dist/components/ui/Tag.js +1 -0
  35. package/dist/components/ui/TextArea.d.ts +8 -1
  36. package/dist/components/ui/TextArea.js +21 -7
  37. package/dist/components/ui/TextField.d.ts +10 -1
  38. package/dist/components/ui/TextField.js +17 -6
  39. package/dist/components/ui/ThemeToggle.js +1 -0
  40. package/dist/components/ui/TiltCard.js +1 -0
  41. package/dist/components/ui/ToastProvider.js +1 -0
  42. package/dist/components/ui/Tooltip.js +1 -0
  43. package/dist/fonts/dm-mono-LICENSE.txt +93 -0
  44. package/dist/fonts/dm-mono-latin-400-normal.woff2 +0 -0
  45. package/dist/fonts/dm-sans-LICENSE.txt +93 -0
  46. package/dist/fonts/dm-sans-latin-wght-normal.woff2 +0 -0
  47. package/dist/fonts/space-grotesk-LICENSE.txt +93 -0
  48. package/dist/fonts/space-grotesk-latin-wght-normal.woff2 +0 -0
  49. package/dist/fonts-latin.css +35 -0
  50. package/dist/hooks/useClipboardCopy.js +1 -0
  51. package/dist/hooks/useControlRef.d.ts +6 -0
  52. package/dist/hooks/useControlRef.js +13 -0
  53. package/dist/hooks/useDismiss.js +1 -0
  54. package/dist/hooks/useFormReset.d.ts +3 -0
  55. package/dist/hooks/useFormReset.js +31 -0
  56. package/dist/hooks/useHeaderScroll.js +1 -0
  57. package/dist/hooks/useIdleTrigger.js +1 -0
  58. package/dist/hooks/useInitialHashScroll.js +1 -0
  59. package/dist/hooks/useMobileMenu.js +1 -0
  60. package/dist/hooks/useMotionPreference.js +1 -0
  61. package/dist/hooks/useOpenState.d.ts +2 -0
  62. package/dist/hooks/useOpenState.js +15 -0
  63. package/dist/hooks/usePrintPreparation.js +1 -0
  64. package/dist/hooks/useScrollSpy.js +1 -0
  65. package/dist/hooks/useSmoothScroll.js +1 -0
  66. package/dist/hooks/useTheme.js +1 -0
  67. package/dist/hooks/useThreeStage.d.ts +4 -0
  68. package/dist/hooks/useThreeStage.js +165 -128
  69. package/dist/hooks/useToast.js +1 -0
  70. package/package.json +29 -12
package/CHANGELOG.md CHANGED
@@ -1,20 +1,95 @@
1
1
  # Changelog
2
2
 
3
+ Changes to the published `@abuzareal/contour-ui` package. Version headings refer to package versions, not catalogue or application versions. Consumer projects pin their own version and update separately.
4
+
5
+ ## Unreleased
6
+
7
+ No changes recorded.
8
+
9
+ ## 0.2.0
10
+
11
+ - TextField, TextArea and SelectField expose native refs while retaining React 18/19 compatibility. Caller-supplied aria-invalid is preserved when no component error overrides it.
12
+ - Uncontrolled field counters and textarea height follow native form reset, including external form association and canceled resets. A browser task waits for the native reset default action, and native input keeps counters current when an edit repeats the pre-reset value.
13
+ - Tabs adds activeTabId/onTabChange; Popover and DropdownMenu add open/defaultOpen/onOpenChange. Existing uncontrolled defaults remain.
14
+ - DropdownMenu skips disabled items, opens from ArrowUp/ArrowDown, supports label typeahead and accepts stable item ids.
15
+ - Three stages release resources after partial initialization failure; setup can register disposal immediately. ObjectStudy reflows paused scenes on resize instead of arranging every animation frame.
16
+ - Interactive modules retain client boundaries; ESM export targets also provide a default condition for framework dynamic-module resolution. A pinned packed Next.js App Router fixture checks the candidate. Latin font assets use relative packaged URLs with their licenses for webpack compatibility.
17
+ - Contributor setup and issue/PR templates are portable. Release checks reuse one archive across compatibility consumers and publish that verified archive without rerunning source lifecycle gates.
18
+
19
+ These changes are absent from 0.1.2. A separate Next.js fixture mode covers lazy Three.js; Lenis, alternate-bundler and wider framework support remain outside these checks.
20
+
21
+ ## 0.1.2 — 2026-10-07
22
+
23
+ An optional font-loading entry and clearer setup documentation. Component APIs and runtime dependencies are unchanged from 0.1.1.
24
+
25
+ ### Added
26
+
27
+ - `fonts-latin.css`: load Latin WOFF2 files for the three system typefaces. The existing `fonts.css` retains full character coverage.
28
+
29
+ ### Documentation
30
+
31
+ - Clarify installation, CSS import order, public exports, optional dependencies, and upgrade guidance.
32
+ - Pair live examples with their source code on the documentation site. Site navigation, theme transitions, responsive layouts, and the homepage specimen were refined; these site changes do not alter package component APIs.
33
+
34
+ ### Compatibility
35
+
36
+ - React 18 and 19 remain supported. Three.js and Lenis remain optional. Packed optional-entry checks cover strict TypeScript declarations and production builds.
37
+
38
+ ### Upgrading from 0.1.1
39
+
40
+ ```sh
41
+ npm install @abuzareal/contour-ui@0.1.2 --save-exact
42
+ ```
43
+
44
+ No component changes are required. To use the smaller Latin font set, replace your `fonts.css` import with `@abuzareal/contour-ui/fonts-latin.css`. Keep the existing import for additional character coverage. Update your manifest and lockfile and check your application's rendered text.
45
+
3
46
  ## 0.1.1
4
47
 
5
- - Lock background scrolling while a Dialog or drawer is open. Nested dialogs retain the lock until the last closes; closing or unmounting restores existing document styles and scrollbar space.
48
+ A compatibility and interaction update for apps using React 18.3.1 or React 19.
49
+
50
+ ### Compatibility
51
+
52
+ - Extend the React and React DOM peer ranges to React 19. The compatibility script checks packed consumers on 18.3.1, 19.0.0, and 19.3.0 and compiles library source against React 19 types.
53
+ - Preserve inert flip-card faces in both React majors, accept nullable refs in public hooks, and initialize the clipboard timer ref for React 19 types.
54
+
55
+ ### Fixes
56
+
57
+ - **Dialog and drawers:** lock background scrolling while open. Nested dialogs retain the lock until the last closes; closing or unmounting restores the document's previous styles and scrollbar space. Dialog content remains scrollable on short screens.
58
+ - **TextField, TextArea, SelectField:** accept caller IDs and retain caller `aria-describedby` references alongside field hints and errors.
59
+ - **Text counters:** reflect programmatic changes to controlled values.
60
+ - **ThemeToggle:** use a button type that doesn't submit an enclosing form.
61
+ - **CountUp:** show the final value when IntersectionObserver is unavailable.
62
+
63
+ ### Upgrading from 0.1.0
64
+
65
+ ```sh
66
+ npm install @abuzareal/contour-ui@0.1.1 --save-exact
67
+ ```
68
+
69
+ Commit `package.json` and `package-lock.json`, then run your app's checks. Review dialogs and drawers on short screens and with nested overlays. If your app has its own background-scroll workaround, test its interaction with the library lock before removing it. Check caller-supplied field IDs/descriptions and controlled counter updates.
6
70
 
7
- - Support React and React DOM 19 alongside 18.3.1, verified with strict clean-consumer installs, declaration checks, production builds, and runtime tests on 18.3.1, 19.0.0, and 19.3.0.
8
- - Preserve flip-card inert faces in both React majors, accept nullable refs in public hooks, and initialize the clipboard timer ref explicitly for React 19 types.
9
- - Let text fields, text areas, and select fields accept caller IDs and retain caller descriptions; keep controlled text counters synchronized with programmatic values.
10
- - Prevent theme buttons from submitting forms, and show final count-up values when IntersectionObserver is unavailable.
11
- - Document direct package imports and retain a repeatable compatibility check before publication.
71
+ React 18.3.1 remains supported; adopting React 19 isn't required. Three.js and Lenis remain optional peers behind `/three` and `/scroll`. The 3D API remains experimental. The compatibility matrix doesn't establish React Server Component support or universal framework compatibility.
72
+
73
+ ### Developer tooling
74
+
75
+ - Document direct package imports and add a repeatable packed-consumer compatibility check before publication.
12
76
 
13
77
  ## 0.1.0
14
78
 
15
- - Extract reusable React components, theme tokens, styling, and optional 3D/scroll entries from the standalone design-system app.
16
- - Synchronize theme controls, tolerate blocked preference storage, and honor system reduced motion for theme changes.
17
- - Reject executable link schemes, preserve tooltip descriptions, make hidden flip-card faces inert, and handle empty tabs and zero-range sliders.
18
- - Ship typed ESM exports, optional font/reset styles, regression tests, and archive-content validation.
79
+ The first package release, extracted from the portfolio and standalone catalogue.
80
+
81
+ ### Added
82
+
83
+ - Reusable React components, theme tokens, CSS, and separate optional 3D and smooth-scroll entries.
84
+ - Typed ESM exports with font and reset styles available as opt-in imports.
85
+ - Regression tests, archive-content checks, and consumer build validation.
86
+
87
+ ### Interaction behavior
88
+
89
+ - Synchronize theme controls, tolerate blocked preference storage, and respect system reduced motion for theme changes.
90
+ - Reject executable link schemes, preserve tooltip descriptions, and make hidden flip-card faces inert.
91
+ - Handle empty tab lists and zero-range sliders.
92
+
93
+ ### Compatibility at release
19
94
 
20
- This is the first release. The 3D interface is experimental; React 19 compatibility has not been verified.
95
+ React 18.3.1 was the verified baseline for 0.1.0; React 19 compatibility was added in 0.1.1. The 3D API was introduced as experimental.
@@ -0,0 +1,5 @@
1
+ # Code of conduct
2
+
3
+ Treat contributors and users with respect. Focus criticism on behavior and code. Harassment, discrimination, threats, sharing private information without permission and repeated personal attacks are unacceptable.
4
+
5
+ Maintainers may remove disruptive material or restrict participation to keep the project usable. Send conduct concerns privately to abuzart1999@gmail.com, including links or evidence you are comfortable sharing. Reports are handled privately where possible; do not publish other people's personal details in issues.
@@ -0,0 +1,15 @@
1
+ # Contributing to Contour UI
2
+
3
+ Contour is a styled React library. The catalogue is a separate application at [contour.abuzr.in](https://contour.abuzr.in/). Domain workflows and product scenes belong in applications; reusable controls, semantic tokens and shared browser lifecycles belong here.
4
+
5
+ Start with an issue describing the user task, current behavior and a small reproduction. For a new component, describe its stable props, native semantics, keyboard behavior, failure/empty states and why existing exports cannot compose the result. Do not include secrets or private application data. Report security concerns through [SECURITY.md](SECURITY.md).
6
+
7
+ Use Node 22.12+ or 24+, then `npm ci --ignore-scripts`. Install Chromium once with `npx playwright install chromium`. Run `npm run validate` for types, lint, build, component and browser regressions, and archive checks. Run `npm run test:compat` for packed React 18/19 consumers and source declarations; run `npm run test:next` for the pinned App Router fixture. Compatibility installs need network access. The core fixture must work without Three.js or Lenis. Optional entries have separate consumers.
8
+
9
+ Keep strict types and validate untrusted data before use. Components own presentation and nearby state; hooks own subscriptions and browser lifecycles; helpers own pure calculations. Use native controls, linked labels/errors, visible focus and explicit button types. Respect reduced motion. Release every listener, timer, observer and GPU resource on unmount and partial initialization failure. Use `onDispose` immediately for resources allocated in a custom stage setup.
10
+
11
+ For a fix, add a regression that fails for the previous behavior. Use component tests for interaction contracts and real browsers for native dialogs, event timing, layout and GPU integration. Check narrow layouts, long content and both themes. Do not replace browser evidence with jsdom when a browser owns the behavior. Avoid duplicate tests that only restate implementation.
12
+
13
+ Update the README and Unreleased changelog when public behavior changes. Keep documented APIs consistent with the archive. New APIs need a migration/usage example. Generic CSS class names and the legacy `aa-theme` storage key are existing compatibility constraints; do not rename them silently.
14
+
15
+ A pull request should name the concrete behavior change, why it helps, which checks passed and any remaining limitation. Review public exports, packed files and dependency changes. No publish, deploy or merge is implied by opening a pull request. Consumers adopt an exact published release with a lockfile update; local source edits do not update them.
package/NEXTJS.md ADDED
@@ -0,0 +1,51 @@
1
+ # Next.js App Router integration
2
+
3
+ This guide describes **Contour 0.2.0**. npm 0.1.2 does not include the client directives, native refs or relative Latin font files described here. Check npm for release availability before installing. The fixture pins Next 16.4.0 with React/React DOM 19.3.0, uses the webpack production build, and consumes an npm archive. It does not establish every Next version, Turbopack, Pages Router, scroll entries or hosting platform. A separate optional mode checks a lazy Three.js scene with SSR disabled and disposal on navigation.
4
+
5
+ In `app/layout.tsx`, load CSS once:
6
+
7
+ ```tsx
8
+ import "@abuzareal/contour-ui/styles.css";
9
+ import "@abuzareal/contour-ui/fonts-latin.css"; // Optional; use your own fonts if preferred.
10
+ import { themeBootstrapScript } from "@abuzareal/contour-ui/theme-bootstrap";
11
+
12
+ export default function Layout({ children }: { children: React.ReactNode }) {
13
+ return (
14
+ <html lang="en" suppressHydrationWarning>
15
+ <head>
16
+ <script dangerouslySetInnerHTML={{ __html: themeBootstrapScript }} />
17
+ </head>
18
+ <body>{children}</body>
19
+ </html>
20
+ );
21
+ }
22
+ ```
23
+
24
+ The narrowly scoped hydration suppression handles the root theme attribute changed before hydration; do not use it to hide arbitrary mismatch errors. A restrictive CSP requires a nonce or hash for the bootstrap script. `reset.css` is optional and global; decide whether your host reset already supplies equivalent defaults, visible focus and a `[hidden]` rule.
25
+
26
+ A client component owns event handlers, state and providers:
27
+
28
+ ```tsx
29
+ "use client";
30
+ import { useState } from "react";
31
+ import { TextField, Button } from "@abuzareal/contour-ui";
32
+
33
+ export default function SearchForm() {
34
+ const [query, setQuery] = useState("");
35
+ return (
36
+ <form>
37
+ <TextField
38
+ label="Search"
39
+ name="query"
40
+ value={query}
41
+ onChange={(event) => setQuery(event.target.value)}
42
+ />
43
+ <Button type="submit">Search</Button>
44
+ </form>
45
+ );
46
+ }
47
+ ```
48
+
49
+ Provide real submission behavior in the application. Toast consumers need ToastProvider; dialogs need application-owned open/onClose. Keep function props inside client boundaries. A server component can pass serializable props to a package client component or import pure `safeHref`; a client directive does not remove normal server prerendering.
50
+
51
+ Run `npm run test:next` to rebuild and consume the candidate archive. The fixture checks server imports/prerendering, hydration, CSS/fonts, refs, native resets, dialog dismissal/focus, toast, tabs, theme persistence and client navigation without Three.js/Lenis installed. Run `CONTOUR_NEXT_OPTIONAL=1 node scripts/test-next.mjs` for the separate lazy `/three` route; ordinary consumers still require neither optional peer. Compatibility evidence applies to the fixture's exact pair and local runtime, not deployment.
package/README.md CHANGED
@@ -1,139 +1,239 @@
1
1
  # Contour UI
2
2
 
3
- An independent React component library for editorial interfaces: paper and ink surfaces, an acid accent, readable typography, restrained motion, and optional Three.js objects.
3
+ React components and CSS tokens for interfaces with paper and ink surfaces, a lime accent, and light and dark themes. Contour started as the shared UI in a personal portfolio; it now supplies components to the portfolio, its catalogue, Atmos, and Orbit.
4
4
 
5
- The npm package is public under MIT; the development repository is private. Public consumers can inspect the distributed JavaScript, declarations, and CSS, but the repository and its issue tracker are accessible only to invited collaborators.
5
+ Use it when you want this visual style with typed controls, feedback, navigation, and motion. Applications own their layouts, data, validation, and workflows. Three.js scenes and smooth scrolling are separate, optional entries.
6
6
 
7
- **Status:** `0.1.1` compatibility update. React 18.3.1 and React 19 are supported; the packed-package matrix checks React 18.3.1, 19.0.0, and 19.3.0. React Server Component execution is not advertised as tested. Interactive components belong in a client boundary in frameworks such as Next.js. The root module can be imported on the server, and basic components can render there.
7
+ [Live catalogue](https://contour.abuzr.in/) · [npm package](https://www.npmjs.com/package/@abuzareal/contour-ui) · [Maintainer](https://github.com/abuzareal)
8
+
9
+ This source checkout targets **0.2.0**. Package publication and application upgrades are separate; check the npm registry for release availability and each application's manifest for its installed version. Catalogue examples include application patterns as well as package components. Check the exports below before treating an example as an importable component.
8
10
 
9
11
  ## Install
10
12
 
13
+ Use an existing React application with a bundler that resolves package CSS imports. Contour ships ESM and TypeScript declarations. The package declares Node.js 22 or newer; repository tooling uses Vite 8, which needs Node.js 22.12+ or 24+.
14
+
11
15
  ```sh
12
- npm install @abuzareal/contour-ui
13
- # Your application must supply matching React and React DOM versions:
14
- # React 18.3.1 or React 19.
16
+ npm install @abuzareal/contour-ui@0.2.0 --save-exact
15
17
  ```
16
18
 
19
+ Your app must provide matching `react` and `react-dom` versions: **18.3.1 or React 19**. The compatibility script covers 18.3.1, 19.0.0, and 19.3.0; it doesn't establish support for every framework or React Server Component setup. Put interactive components inside a client boundary when your framework requires one.
20
+
21
+ ## First component
22
+
23
+ Import the styles once in your application entry. Import components directly from the package; no generated files or local re-exports are needed.
24
+
17
25
  ```tsx
18
- import "@abuzareal/contour-ui/reset.css"; // optional, global reset; omit with an existing reset
19
- import "@abuzareal/contour-ui/fonts.css"; // optional, self-hosted font assets bundled by your app
26
+ import { useState } from "react";
27
+ import "@abuzareal/contour-ui/reset.css";
28
+ import "@abuzareal/contour-ui/fonts.css";
20
29
  import "@abuzareal/contour-ui/styles.css";
21
- import {
22
- Button,
23
- TextField,
24
- ToastProvider,
25
- ThemeToggle,
26
- } from "@abuzareal/contour-ui";
27
-
28
- export function App() {
30
+ import { Button, TextField, ThemeToggle } from "@abuzareal/contour-ui";
31
+
32
+ export default function App() {
33
+ const [name, setName] = useState("");
34
+ const [savedName, setSavedName] = useState("");
35
+
29
36
  return (
30
- <ToastProvider>
31
- <main data-motion="off">
32
- <ThemeToggle animate={false} />
33
- <TextField label="City" placeholder="Pune" />
34
- <Button variant="accent">Show forecast</Button>
35
- </main>
36
- </ToastProvider>
37
+ <main data-motion="off">
38
+ <ThemeToggle animate={false} />
39
+ <TextField
40
+ label="Name"
41
+ value={name}
42
+ onChange={(event) => setName(event.target.value)}
43
+ />
44
+ <Button variant="accent" onClick={() => setSavedName(name)}>
45
+ Save locally
46
+ </Button>
47
+ <p role="status">{savedName && `Saved for this session: ${savedName}`}</p>
48
+ </main>
37
49
  );
38
50
  }
39
51
  ```
40
52
 
41
- For an app with its own reset, include equivalent native button/input defaults, border-box sizing, focus outlines, and the `[hidden]` rule. Styles use globally named component classes and `:root` theme tokens; they are not Shadow DOM isolated. Avoid redefining generic classes such as `.card` or `.button` elsewhere.
53
+ This example keeps the value in React state until the component unmounts. To persist it or send it to a server, add that behavior in your app.
42
54
 
43
- ## Direct imports: no local component files required
55
+ `Button` and ordinary controls need no provider. Toasts require `ToastProvider` around components that call `useToast()`.
44
56
 
45
- Use named imports directly in any component file:
57
+ ### Optional Latin fonts
58
+
59
+ `fonts-latin.css`, added in 0.1.2, keeps DM Sans, Space Grotesk, and DM Mono while loading only Latin WOFF2 files. Use it instead of `fonts.css` for Latin text; keep `fonts.css` when the additional character sets are needed. Existing font imports continue to work.
46
60
 
47
61
  ```tsx
48
- import { Button } from "@abuzareal/contour-ui";
62
+ import "@abuzareal/contour-ui/fonts-latin.css";
63
+ ```
49
64
 
50
- export function SaveAction() {
51
- return (
52
- <Button variant="accent" onClick={() => console.log("Saved")}>
53
- Save
54
- </Button>
55
- );
65
+ ## Styles and customization
66
+
67
+ | Import | Purpose |
68
+ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
69
+ | `styles.css` | Required for the supplied appearance: tokens, component styles, and utilities. |
70
+ | `reset.css` | Optional global reset. Omit it if your app already has equivalent native-control defaults, border-box sizing, focus styles, and a `[hidden]` rule. |
71
+ | `fonts-latin.css` | Optional Latin-only WOFF2 fonts, available since 0.1.2. Use instead of `fonts.css`, not alongside it. |
72
+ | `fonts.css` | Optional self-hosted Space Grotesk, DM Sans, and DM Mono via Fontsource. Your bundler emits the font assets. |
73
+ | `tokens.css` | Tokens alone, for an app that supplies its own component styles. Already included by `styles.css`. |
74
+
75
+ Override semantic tokens after importing the styles:
76
+
77
+ ```css
78
+ :root {
79
+ --font-sans: system-ui, sans-serif;
80
+ --font-display: system-ui, sans-serif;
81
+ }
82
+
83
+ :root[data-theme="dark"] {
84
+ --bg: #111411;
85
+ --fg: #edf0e8;
56
86
  }
57
87
  ```
58
88
 
59
- Import `styles.css` once at the application entry. `reset.css` and `fonts.css` are optional. No provider is needed for `Button` or ordinary controls; only toast consumers require `ToastProvider`.
89
+ Styles use global component classes and document-level theme tokens. Scope your application's classes to avoid collisions with names such as `.card` and `.button`. Contour's CSS isn't isolated with Shadow DOM or CSS Modules.
90
+
91
+ The three Fontsource packages and `lucide-react` are direct dependencies. Omitting `fonts.css` keeps its font assets out of your application's bundle; the font packages still install. React and React DOM are peers. Three.js and Lenis are optional peers. Development tools aren't installed as Contour's consumer dependencies; tests and tooling are excluded from the npm archive.
92
+
93
+ ## Theme and motion
94
+
95
+ Set `data-theme="light"` or `"dark"` on `<html>`. `ThemeToggle` and `useTheme(animate)` read the same document state. The hook returns `{ theme, toggle }`; call `toggle(buttonElement)` from a user action. Preferences use the `aa-theme` local-storage key and are local to the site's origin.
96
+
97
+ For theme selection before first paint, inject `themeBootstrapScript` from `@abuzareal/contour-ui/theme-bootstrap` into the HTML head at build time. The exported string has no user interpolation. With a strict Content Security Policy, authorize that script with a nonce or hash.
60
98
 
61
- The original Portfolio and Design-System applications retained thin compatibility re-exports to preserve their pre-package imports. Those files are an application migration choice, not a requirement of this library. Create a wrapper only when it represents your own reusable application behavior.
99
+ `useMotionPreference()` returns whether the user prefers reduced motion. Combine it with your app's pause state, set `data-motion="off"` on the app wrapper when needed, and pass `motionEnabled` to scenes and `animate` to theme controls. System reduced motion also disables the theme reveal.
62
100
 
63
- Text fields accept explicit `id` values and preserve your `aria-describedby` references alongside their own hint or error. Native props follow the documented component types; not every component currently accepts `className`, DOM refs, or arbitrary native attributes. Do not assume router `asChild` composition or form-library ref integration is available in this release.
101
+ ## Components
64
102
 
65
- ## Theme and motion setup
103
+ | Area | Public exports |
104
+ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105
+ | Actions | `Button`, `IconButton`, `ExternalLink`, `SegmentedControl`, `ThemeToggle` |
106
+ | Forms | `Field`, `TextField`, `TextArea`, `SelectField`, `Checkbox`, `RadioGroup`, `Switch`, `Slider` |
107
+ | Navigation | `Tabs`, `Breadcrumbs`, `Pagination`, `Stepper`, `DropdownMenu` |
108
+ | Data and layout | `Avatar`, `Badge`, `Card`, `DataTable`, `Disclosure`, `Divider`, `EmptyState`, `Kbd`, `SectionLabel`, `Stat`, `Tag`, `Timeline` |
109
+ | Feedback | `Alert`, `ProgressBar`, `Skeleton`, `Spinner`, `ToastProvider`, `useToast` |
110
+ | Motion and identity | `BrandMark`, `CountUp`, `DepthButton`, `FlipCard`, `Magnetic`, `Marquee`, `Reveal`, `RevealHeading`, `ScrollProgress`, `TiltCard`, `GitHubIcon`, `LinkedInIcon` |
111
+ | Overlays and scene fallback | `Dialog`, `Popover`, `Tooltip`, `SceneBoundary` |
66
112
 
67
- All theme toggles read the same document state. Set `data-theme="light"` or `"dark"` on `<html>`. `useTheme(animate)` returns `{ theme, toggle }`; call `toggle(buttonElement)` for a user action. The existing `aa-theme` local-storage key is preserved for compatibility with the original portfolio. Preference storage is origin-local, not shared across different website domains.
113
+ The root entry also exports theme, motion, clipboard, dismissal, navigation, and browser-lifecycle hooks plus utility functions. Check `src/index.ts` in a source checkout or `dist/index.d.ts` in the installed package for the complete API. Component declarations describe their props.
68
114
 
69
- To avoid a first-paint theme flash, inject the exported static `themeBootstrapScript` from `@abuzareal/contour-ui/theme-bootstrap` into the HTML head at build time. It has no user-supplied interpolation. A strict Content Security Policy needs the appropriate script hash or nonce; do not enable unsafe inline scripts generally.
115
+ Use visible field labels, accessible names for icon buttons, and text alongside status colors. `DataTable` sorts scalar string/number values; `Pagination` expects a positive integer page count and a page within that range. Flip cards use a button and make the hidden face inert.
70
116
 
71
- Set `data-motion="off"` on your application wrapper when animation is disabled. `useMotionPreference()` tracks the system setting; combine it with your app's pause state. Pass the resulting `motionEnabled` to Three.js scenes and `animate` to theme controls. Reduced motion overrides theme reveal animations even if `animate` is true. No animation is required to operate the UI.
117
+ Props support varies between components. Don't assume every export forwards DOM refs, accepts arbitrary native attributes, supports router `asChild` composition, or integrates with form libraries through refs. Verify the relevant type before adopting it.
72
118
 
73
- `useToast()` must run below `ToastProvider`. The library does not send messages, collect analytics, fetch application data, or require a service account. Links reject executable URL schemes; application authentication, validation, authorization, and data handling remain the application's responsibility.
119
+ ## Optional scenes and scrolling
74
120
 
75
- ## Optional entries
121
+ Core imports don't load Three.js or Lenis. Install either only if you use its entry:
76
122
 
77
123
  ```sh
78
- npm install three@^0.186.1 # only for the /three entry
79
- npm install lenis@^1.3.26 # only for the /scroll entry
124
+ npm install three@^0.186.1 # @abuzareal/contour-ui/three
125
+ npm install lenis@^1.3.26 # @abuzareal/contour-ui/scroll
126
+ # TypeScript consumers of /three also need the matching declarations:
127
+ npm install -D @types/three@^0.186.0
80
128
  ```
81
129
 
130
+ `/scroll` exports `useSmoothScroll`. `/three` exports `Sculpture`, `ObjectStudy`, `useThreeStage`, geometry/material helpers, and associated types. CSS depth controls such as `TiltCard` and `FlipCard` are core exports and don't require Three.js.
131
+
82
132
  ```tsx
83
133
  import { lazy, Suspense } from "react";
134
+ import { SceneBoundary } from "@abuzareal/contour-ui";
135
+
84
136
  const Sculpture = lazy(() =>
85
137
  import("@abuzareal/contour-ui/three").then((module) => ({
86
138
  default: module.Sculpture,
87
139
  })),
88
140
  );
89
141
 
90
- // Provide a sized container and an application-owned static fallback.
91
- <Suspense fallback={<p>Loading preview…</p>}>
92
- <Sculpture motionEnabled={false} />
93
- </Suspense>;
142
+ export function Preview() {
143
+ return (
144
+ <div>
145
+ <p>Three interlocking links, shown in a WebGL preview when available.</p>
146
+ <SceneBoundary>
147
+ <Suspense fallback={<p>Loading preview…</p>}>
148
+ <Sculpture motionEnabled={false} />
149
+ </Suspense>
150
+ </SceneBoundary>
151
+ </div>
152
+ );
153
+ }
94
154
  ```
95
155
 
96
- `/three` also exports `ObjectStudy`, `useThreeStage`, geometry/material helpers, and their types. Treat the 3D API as experimental in this initial release. Scene setup functions are captured on mount; remount the scene when its setup configuration changes. Scenes require WebGL and should always have a visible fallback. No Three.js or Lenis imports occur in the core runtime graph.
97
-
98
- ## Components and typed APIs
156
+ Give scenes a sized container and a usable static fallback. `SceneBoundary` hides a scene on failure; it doesn't supply fallback content, so keep that content outside the boundary. The 3D API is experimental. Stage setup functions are captured on mount; remount a scene when its setup configuration changes. WebGL availability is a runtime requirement for scenes.
99
157
 
100
- The package exports named components and props types. TypeScript declarations are shipped with every entry; editors provide the complete props API.
158
+ ## Release notes and upgrades
101
159
 
102
- - Actions: `Button`, `IconButton`, `ExternalLink`, `SegmentedControl`, `ThemeToggle`.
103
- - Forms: `Field`, `TextField`, `TextArea`, `SelectField`, `Checkbox`, `RadioGroup`, `Switch`, `Slider`.
104
- - Navigation: `Tabs`, `Breadcrumbs`, `Pagination`, `Stepper`, `DropdownMenu`.
105
- - Data and layout: `Avatar`, `Badge`, `Card`, `DataTable`, `Disclosure`, `Divider`, `EmptyState`, `Kbd`, `SectionLabel`, `Stat`, `Tag`, `Timeline`.
106
- - Feedback: `Alert`, `ProgressBar`, `Skeleton`, `Spinner`, `ToastProvider`, `useToast`.
107
- - Motion and signature: `BrandMark`, `CountUp`, `DepthButton`, `FlipCard`, `Magnetic`, `Marquee`, `Reveal`, `RevealHeading`, `ScrollProgress`, `TiltCard`, `GitHubIcon`, `LinkedInIcon`.
108
- - Overlays: `Dialog`, `Popover`, `Tooltip`, `SceneBoundary`.
109
-
110
- `Dialog` locks document scrolling while open, including drawer placements. Its content remains scrollable on short screens. Nested dialogs share the lock; closing or unmounting the last restores the document's previous styles. This behavior is included in version 0.1.1.
111
-
112
- Use visible labels for fields, concise action labels for buttons, accessible labels for icon-only controls, and text alongside status colors. Sortable tables expect scalar string/number row values. Pagination expects a positive integer page count and a page in that range. Flip cards switch through their button; the hidden side is inert.
113
-
114
- Global colors, fonts, radii, duration, and spacing variables are in `tokens.css`. Override semantic tokens rather than copying components into your app. `styles.css` includes tokens and component styles; `fonts.css` and `reset.css` are separately opt-in. Do not import catalogue or portfolio CSS into other apps.
115
-
116
- ## Independent repositories and updates
117
-
118
- This repository contains only the library. The catalogue and portfolio remain separate repositories and consume the same published npm version. During first-release validation, a packed archive can be installed locally; replace the archive dependency with the registry version before committing consumer manifests.
160
+ **0.2.0** adds native field refs, controlled tabs and disclosure state, menu keyboard improvements, native reset synchronization, Three.js lifecycle fixes and a tested Next.js App Router integration. Existing uncontrolled defaults and React 18/19 support remain. `fonts-latin.css`, introduced in 0.1.2, now uses packaged relative font URLs for webpack resolution. `CHANGELOG.md` is included in the package archive and [npm's Code view](https://www.npmjs.com/package/@abuzareal/contour-ui?activeTab=code); it contains the upgrade details for each version.
119
161
 
120
162
  ```sh
121
- npm install @abuzareal/contour-ui@0.1.1 --save-exact
163
+ npm install @abuzareal/contour-ui@0.2.0 --save-exact
122
164
  ```
123
165
 
124
- Commit both `package.json` and `package-lock.json`. Dependabot proposes version updates in each consumer repository. Updates reach production after that project's checks, merge, rebuild, and deployment. A registry release does not change deployed applications automatically.
166
+ Commit your manifest and lockfile, run your application's checks, and review both themes, dialogs, forms, and motion before deploying. Version 0.1.1 includes a document scroll lock for dialogs and drawers. Review any app-level lock before removing it, including nested dialogs and short screens. Package publication doesn't update deployed consumers automatically.
167
+
168
+ The package and [source repository](https://github.com/abuzareal/contour-ui) are public under MIT. Report reproducible defects in the [issue tracker](https://github.com/abuzareal/contour-ui/issues); use [SECURITY.md](SECURITY.md) for private vulnerability reporting. Public users can inspect code, CSS, declarations and release documents through GitHub or npm.
169
+
170
+ ## Develop this library
125
171
 
126
- ## Development and release
172
+ From a source checkout:
127
173
 
128
174
  ```sh
129
175
  npm ci --ignore-scripts
130
- npx playwright install chromium # first browser-test run
176
+ npx playwright install chromium
131
177
  npm run validate
132
- npm run test:compat # packed consumers in both React majors and source compilation with React 19 types
178
+ npm run test:compat
133
179
  npm audit
134
180
  npm pack --dry-run
135
181
  ```
136
182
 
137
- See `RELEASING.md` for the release checklist, authentication, and trusted-publishing setup. The package ships only built code/styles and release documents, with no consumer installation scripts. The complete-source Git repository contains tests and tooling; those are excluded from the npm archive.
183
+ `validate` checks types, lint, builds, Node/component tests, dialog and Three.js browser behavior, and archive contents. `test:compat` builds packed React 18/19 consumers and compiles the source with React 19 types. `test:consumer` checks one packed consumer, with optional peers absent. `test:optional` verifies strict `/three` and `/scroll` declarations and builds their imports with explicit peers and Three.js types. The compatibility gate runs both checks and verifies the Latin font assets. Compatibility runs need registry access for clean installs.
184
+
185
+ `src/` owns components, hooks, helpers, and public entries. `styles/` owns CSS. `tests/` owns regressions and browser checks; `scripts/` owns builds and package/consumer checks. `dist/` is generated. `RELEASING.md` in the source checkout and package archive covers validation and publication.
186
+
187
+ MIT licensed. Fontsource fonts and dependencies retain their own licenses.
188
+
189
+ ## APIs added in 0.2.0
190
+
191
+ Version 0.2.0 adds native refs to TextField, TextArea and SelectField; synchronizes uncontrolled counters and auto-resize after native form reset; adds controlled Tabs (`activeTabId`, `onTabChange`) and disclosures (`open`, `defaultOpen`, `onOpenChange`); and adds disabled menu items, stable item ids and typeahead. These additions are absent from 0.1.2. Switching a field/disclosure between controlled and uncontrolled ownership during its lifetime is unsupported.
192
+
193
+ Existing uncontrolled calls remain valid. Use a native ref to focus a field or integrate a form controller; controlled tabs and disclosures require the caller to update the selected id or open state:
194
+
195
+ ```tsx
196
+ import { useRef, useState } from "react";
197
+ import { Button, Popover, Tabs, TextField } from "@abuzareal/contour-ui";
198
+
199
+ export function AccountControls() {
200
+ const input = useRef<HTMLInputElement>(null);
201
+ const [activeTabId, setActiveTabId] = useState("details");
202
+ const [open, setOpen] = useState(false);
203
+
204
+ return (
205
+ <>
206
+ <TextField ref={input} label="Name" name="name" />
207
+ <Button onClick={() => input.current?.focus()}>Focus name</Button>
208
+ <Tabs
209
+ label="Account"
210
+ activeTabId={activeTabId}
211
+ onTabChange={setActiveTabId}
212
+ tabs={[
213
+ { id: "details", label: "Details", content: <p>Account details</p> },
214
+ {
215
+ id: "settings",
216
+ label: "Settings",
217
+ content: <p>Account settings</p>,
218
+ },
219
+ ]}
220
+ />
221
+ <Popover trigger="Help" title="Help" open={open} onOpenChange={setOpen}>
222
+ <p>Account help</p>
223
+ </Popover>
224
+ </>
225
+ );
226
+ }
227
+ ```
228
+
229
+ Interactive module boundaries retain `use client` in the built package. The pinned Next.js App Router consumer checks the packed 0.2.0 archive. Follow [Next.js setup](NEXTJS.md) for the pinned Next.js 16.4.0 / React 19.3.0 pair. Pure URL/theme-bootstrap helpers remain usable from the server. A separate fixture mode checks lazy optional Three.js loading and navigation cleanup. Lenis integration, other Next versions and alternate bundlers remain separate compatibility questions.
230
+
231
+ Custom `useThreeStage` setup can register disposal through `context.onDispose?.(cleanup)` immediately after acquiring each resource, including resources allocated before setup returns. Registered resources are released on failed initialization and unmount; avoid also disposing the same resource in `StageScene.dispose`. A stage may implement `resize()` to reflow after aspect changes while motion is paused.
232
+
233
+ ## Compatibility boundaries
234
+
235
+ Styles are global, not a scoped CSS engine. Existing class names such as `.field` and `.menu` can collide with host CSS. Import Contour styles before deliberate application overrides; keep application selectors area-prefixed. The optional reset and fonts affect the document. Tokens use root `data-theme`; `useTheme` retains the legacy `aa-theme` local-storage key for compatibility. A multi-library page must decide which system owns its root theme.
236
+
237
+ Menus and popovers remain local panels without portals or collision detection; use them where the container can accommodate their content. No submenu or arbitrary trigger-composition contract is claimed. BrandMark and page/editorial helpers preserve existing identity and layout assumptions; they are optional exports rather than universal primitives. Do not copy private internals or deep-import them.
138
238
 
139
- MIT licensed. Font dependencies retain their own font licenses; Lucide, React, Three.js, and Lenis retain their respective licenses.
239
+ For contribution setup and review expectations, see [CONTRIBUTING.md](CONTRIBUTING.md). Contour currently provides React components; no Vue, Svelte or Angular adapter is included.
package/RELEASING.md CHANGED
@@ -1,37 +1,23 @@
1
1
  # Releasing Contour UI
2
2
 
3
- ## Initial release
3
+ Source is public at [github.com/abuzareal/contour-ui](https://github.com/abuzareal/contour-ui); the package is public under MIT. Query npm for the latest published version; the source manifest does not prove publication. Source changes are not delivered to consumers until publication and an exact dependency/lockfile update. The npm README changes only when a new version is published; do not overwrite or unpublish an existing version to edit it.
4
4
 
5
- 1. Verify `npm whoami` is `abuzareal`; the package is `@abuzareal/contour-ui` and public under MIT.
6
- 2. Run `npm ci --ignore-scripts`, install Chromium with `npx playwright install chromium` on a new machine, then run `npm run validate`, `npm run test:compat`, and `npm audit`. Review every advisory; do not release with unexplained audit findings.
7
- 3. Test the actual packed archive in clean React 18 and React 19 consumers without optional Three.js or Lenis, and in the catalogue and portfolio with their full browser suites.
8
- 4. Check `npm pack --dry-run --json` and licenses. No private data, credentials, unrelated assets, maps, or app content may enter the archive.
9
- 5. Push the reviewed source and release commit to the independent GitHub repository. The owner currently keeps this repository private; the npm distribution remains public under MIT.
10
- 6. Set `private` to `false` only for an approved, validated release. Publish from the verified owner account: `npm publish --access public`. Complete npm's required authentication/2FA personally.
11
- 7. Verify registry metadata, install the exact registry version in both consumers, rerun checks, and commit the manifest/lockfile changes. Do not commit temporary filesystem/archive dependencies.
12
- 8. Tag the matching package version and record the release. Every future release requires a new version; npm versions cannot be overwritten.
5
+ Before selecting a release version, review public API and visual changes, types, dependencies, licenses, changelog and compatibility limits. Use patch for compatible fixes, minor for additions, and document every incompatible 0.x change explicitly. README examples must match the archive. Record publication dates only after verifying the registry. A local check is not deployment evidence.
13
6
 
14
- ## Future trusted releases
7
+ ## Verify and publish one archive
15
8
 
16
- After the first package exists, configure npm's GitHub trusted publisher for owner `abuzareal`, repository `contour-ui`, workflow `release.yml`. Authenticate interactively to set this relationship; do not paste credentials into code or chat. Enable two-factor authentication on the owner account and prefer disabling ordinary token publishing after trusted publishing has been successfully verified.
9
+ 1. Obtain maintainer authorization to publish; validation alone is not authorization.
10
+ 2. Select an unused registry version and update package.json, its lockfile and release notes. Never reuse an existing registry version; a locally verified archive does not make it publishable under an already released version. Use a reviewed release commit on main and a matching `vVERSION` tag. The hosted workflow checks the tag version and that its source is an ancestor of origin/main. It cannot publish from a pull request.
11
+ 3. Run `npm ci --ignore-scripts`; install Chromium once with `npx playwright install chromium`. Use Node 22.12+ or 24+.
12
+ 4. Set `CONTOUR_RELEASE_DIR` to an existing temporary directory and run `npm run verify:release`. It runs validate once, packs one archive, tests that archive in clean React 18/19 core and optional consumers plus the pinned Next App Router fixture, audits dependencies, and writes `verified-archive.json` with its SHA-256. Core consumers must have no Three.js or Lenis installed. Review failures and advisories instead of bypassing gates.
13
+ 5. Inspect the archive contents, verify its checksum against `verified-archive.json`, and publish that exact path using `npm publish /absolute/path/to/archive.tgz --ignore-scripts --access public`. `--ignore-scripts` is appropriate here because that exact archive has already passed the release gates; it is not permission to publish an unchecked package. Source `npm publish` retains a prepublishOnly guard. The hosted workflow verifies the checksum again and publishes the archive with provenance, avoiding duplicate source gates.
14
+ 6. The owner completes npm authentication/2FA personally. Never put tokens, OTPs or credentials in this repository or logs. Prefer configured trusted publishing and short-lived identity over persistent tokens.
15
+ 7. Verify registry version, tarball/integrity and publication date; install that exact registry version in each affected consumer, commit its manifest/lockfile, and run its required checks before deployment. Do not substitute a local link or source copy for release validation.
17
16
 
18
- With account 2FA enabled, configure and verify the relationship using npm 11.15 or later:
17
+ The tag workflow is configured for a public repository on main. Configuration does not prove that its npm trusted-publisher relationship is active; check npm/GitHub settings before relying on it. Publication requires authorization even when CI passes.
19
18
 
20
- ```sh
21
- npm trust github @abuzareal/contour-ui --file release.yml --repo abuzareal/contour-ui --allow-publish
22
- npm trust list @abuzareal/contour-ui
23
- ```
19
+ ## Validation cost
24
20
 
25
- The release workflow accepts a manually dispatched version already present in package.json and requires the matching `vVERSION` tag to identify its source. It reruns validation, dependency audit, and clean-consumer tests before publishing with provenance. Push the reviewed release commit to main before tagging. Never publish from a pull-request event or add a persistent npm token to the workflow.
21
+ Browser checks remain for native dialog, reset timing and graphics lifecycle behavior. jsdom does not reproduce all browser default actions. Compatibility checks reuse one archive and avoid another library build when `CONTOUR_ARCHIVE` is provided. Documentation-only diffs retain types, lint, build, archive checks and audit; runtime diffs keep component, browser and complete compatibility checks. Changes to components, hooks, entries, styles, build/package configuration or the Next fixture also run the pinned Next check. Unknown history falls back to complete gates. No measured CI speedup is claimed until the updated workflow has run.
26
22
 
27
- The repository is currently private, so the configured workflow deliberately skips publishing. Release locally after running the checklist. Trusted publishing can be configured for a private repository, but npm does not support provenance attestations from private source repositories. If hosted releases are enabled later, review private-runner spending settings and remove the explicit provenance requirement for private source. The current workflow is ready for a future public repository and must not be presented as active automation while the repository stays private.
28
-
29
- Increment PATCH for compatible fixes, MINOR for compatible additions, and MAJOR for incompatible APIs or substantial incompatible default behavior. While the package is at 0.x, document every change carefully and keep consumers pinned to exact versions. Review visual changes in consuming apps even when the API is compatible.
30
-
31
- ## Dependency updates and cost
32
-
33
- Dependabot is selected because it is integrated with GitHub and requires no extra hosted service or bot account. It proposes weekly npm and action updates; the library is not auto-merged. npm distribution is public. Standard-hosted Actions run only if the repository is public; checks run locally while it stays private. Do not enable paid runners, private npm distribution, or paid security subscriptions as part of this setup.
34
-
35
- The validation workflows deliberately skip private repositories. If a consumer stays private, run its checks locally before merging dependency updates. Enabling private-repository Actions later requires reviewing that account's included usage and spending settings first.
36
-
37
- Consumers install with `npm install @abuzareal/contour-ui@VERSION --save-exact`, commit their lockfile, run their checks, and redeploy. Keep the three Git repositories independent.
23
+ Dependabot proposes dependency/action changes for review; changes are not auto-merged. Actions use pinned revisions and minimal permissions. Do not enable paid runners or private distribution as part of a release. Contributor and application checks remain separate from registry/deployment verification.
package/SECURITY.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Security
2
2
 
3
- Report suspected vulnerabilities privately using GitHub's private vulnerability reporting for this repository once enabled. If that option is unavailable, contact the maintainer privately through their GitHub profile; do not post exploit details or credentials in a public issue.
3
+ Report suspected vulnerabilities privately to abuzart1999@gmail.com. Include the affected version and a minimal reproduction without credentials or unrelated personal data. If GitHub private vulnerability reporting is available on this repository, it is another private channel. Do not post exploit details or credentials in a public issue.
4
4
 
5
5
  The latest published release is the supported version. Dependency audits identify known reported vulnerabilities, not all possible defects. No claim of complete security or formal accessibility certification is made.
6
6
 
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  /** Error boundary that hides the 3D scene if its lazy module or renderer throws. */
2
3
  import { Component } from "react";
3
4
  export default class SceneBoundary extends Component {