@ponchia/ui 0.2.2 → 0.3.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.
Files changed (48) hide show
  1. package/README.md +108 -79
  2. package/behaviors/index.d.ts +53 -0
  3. package/behaviors/index.js +745 -34
  4. package/classes/index.d.ts +216 -3
  5. package/classes/index.js +85 -10
  6. package/classes/vscode.css-custom-data.json +407 -0
  7. package/css/app.css +53 -44
  8. package/css/base.css +14 -23
  9. package/css/content.css +37 -2
  10. package/css/core.css +5 -5
  11. package/css/disclosure.css +17 -5
  12. package/css/dots.css +1 -1
  13. package/css/feedback.css +87 -2
  14. package/css/forms.css +128 -2
  15. package/css/navigation.css +16 -85
  16. package/css/overlay.css +73 -2
  17. package/css/primitives.css +100 -3
  18. package/css/site.css +295 -0
  19. package/css/table.css +59 -0
  20. package/css/tokens.css +79 -24
  21. package/dist/bronto.css +1 -1
  22. package/dist/css/app.css +1 -0
  23. package/dist/css/base.css +1 -0
  24. package/dist/css/content.css +1 -0
  25. package/dist/css/disclosure.css +1 -0
  26. package/dist/css/dots.css +1 -0
  27. package/dist/css/feedback.css +1 -0
  28. package/dist/css/fonts.css +1 -0
  29. package/dist/css/forms.css +1 -0
  30. package/dist/css/motion.css +1 -0
  31. package/dist/css/navigation.css +1 -0
  32. package/dist/css/overlay.css +1 -0
  33. package/dist/css/primitives.css +1 -0
  34. package/dist/css/site.css +1 -0
  35. package/dist/css/table.css +1 -0
  36. package/dist/css/tokens.css +1 -0
  37. package/package.json +60 -30
  38. package/shiki/nothing.json +83 -0
  39. package/tokens/index.d.ts +18 -10
  40. package/tokens/index.js +49 -16
  41. package/tokens/index.json +98 -32
  42. package/tokens/tokens.dtcg.json +241 -22
  43. package/css/cards.css +0 -336
  44. package/css/index.css +0 -5
  45. package/css/layout.css +0 -219
  46. package/css/responsive.css +0 -157
  47. package/css/typography.css +0 -139
  48. package/dist/bronto-core.css +0 -1
package/README.md CHANGED
@@ -1,9 +1,33 @@
1
1
  # @ponchia/ui
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/@ponchia/ui?logo=npm)](https://www.npmjs.com/package/@ponchia/ui)
4
+ [![npm provenance](https://img.shields.io/badge/npm-provenance-blue?logo=npm)](https://www.npmjs.com/package/@ponchia/ui#provenance)
5
+ [![runtime deps](https://img.shields.io/badge/runtime%20deps-0-brightgreen)](package.json)
6
+ [![bundle](https://img.shields.io/badge/dist-~54kB%20%2F%20~10kB%20gzip-informational)](scripts/check-dist.mjs)
7
+ [![CI](https://github.com/Ponchia/bronto-ui/actions/workflows/ci.yml/badge.svg)](https://github.com/Ponchia/bronto-ui/actions/workflows/ci.yml)
8
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
9
+
3
10
  Shared UI framework for Bronto personal projects. Nothing-inspired:
4
11
  monochrome surfaces, a single red accent, dot-matrix display type (Doto),
5
12
  flat hairline borders, restrained motion. CSS-first and framework-agnostic.
6
13
 
14
+ **New here?** → [Getting started](#getting-started) ·
15
+ [Reference](docs/reference.md) · [Theming](docs/theming.md) ·
16
+ [Roadmap](ROADMAP.md) · [Contributing](CONTRIBUTING.md)
17
+
18
+ > **Editor IntelliSense.** The package ships a VS Code CSS Custom Data
19
+ > file so every design token autocompletes inside `var(--…)`. Add to
20
+ > your `.vscode/settings.json`:
21
+ >
22
+ > ```json
23
+ > {
24
+ > "css.customData": ["node_modules/@ponchia/ui/classes/vscode.css-custom-data.json"]
25
+ > }
26
+ > ```
27
+
28
+ **[Live demo →](https://ponchia.github.io/bronto-ui/)** — the kitchen
29
+ sink (every component, light/dark, RTL, theming) deployed from `demo/`.
30
+
7
31
  ## Use
8
32
 
9
33
  Install from npm (public, no registry config):
@@ -18,30 +42,33 @@ npm i @ponchia/ui
18
42
  > deliberately distinct from the package name. See
19
43
  > [`docs/architecture.md`](docs/architecture.md).
20
44
 
21
- Import the full theme (includes responsive breakpoints):
22
-
23
- ```css
24
- @import '@ponchia/ui/css';
25
- ```
26
-
27
- Or the core bundle if the app manages its own responsive layer:
45
+ Import the theme (one bundle — `ui-*` components carry their own
46
+ breakpoints, so there is no separate core/full split as of 0.3.0):
28
47
 
29
48
  ```css
30
- @import '@ponchia/ui/css/core.css';
49
+ @import '@ponchia/ui/css'; /* === @ponchia/ui/css/core.css */
31
50
  ```
32
51
 
33
52
  **Prebuilt single file (recommended for apps without a CSS bundler).**
34
- `@ponchia/ui/css` is a 17-deep `@import` graph fine through a bundler,
35
- a load waterfall over plain HTTP. The package also ships flattened,
36
- minified bundles with no `@import` chain:
53
+ `@ponchia/ui/css` is a wide `@import` fan-out (~14 leaves, one level
54
+ deep) — fine through a bundler, a load waterfall over plain HTTP. The
55
+ package also ships one flattened, minified bundle with no `@import`
56
+ chain:
37
57
 
38
58
  ```css
39
- @import '@ponchia/ui'; /* → dist/bronto.css, full */
40
- @import '@ponchia/ui/dist/bronto-core.css'; /* core, no responsive */
59
+ @import '@ponchia/ui'; /* → dist/bronto.css, the whole framework */
41
60
  ```
42
61
 
43
- ~62 kB raw / ~11 kB gzip, one request, same `@layer bronto`. Source CSS,
44
- tokens/classes/behaviors entrypoints are unchanged use whichever fits.
62
+ ~54 kB raw / ~10 kB gzip, one request, same `@layer bronto`. (The
63
+ enforced ceiling lives in `scripts/check-dist.mjs`, not this prose —
64
+ treat these figures as indicative.) Source CSS, tokens/classes/behaviors
65
+ entrypoints are unchanged — use whichever fits.
66
+
67
+ > **The package root is CSS-only.** `@ponchia/ui` (the `.` export)
68
+ > resolves to a stylesheet — `@import '@ponchia/ui'` in CSS, never
69
+ > `import '@ponchia/ui'` in JS. There is no JS module at the root; the
70
+ > JS entrypoints are the explicit subpaths `@ponchia/ui/tokens`,
71
+ > `/classes`, and `/behaviors` (see [Entrypoints](#entrypoints)).
45
72
 
46
73
  ### Browser support
47
74
 
@@ -59,10 +86,14 @@ font instead, import everything except `fonts.css` and override `--display` /
59
86
 
60
87
  Everything ships inside a single `@layer bronto`, so any un-layered CSS in
61
88
  your app overrides the framework without a specificity fight or `!important`.
62
- The layer is applied by the `css` and `css/core.css` bundles only —
63
- importing an individual leaf such as `@ponchia/ui/css/primitives.css`
64
- directly is **unlayered** (full specificity), which is an intentional
65
- escape hatch, not the default path.
89
+
90
+ > **Leaf imports are layer-safe by default.** Every per-leaf export
91
+ > `@ponchia/ui/css/primitives.css`, etc. is self-wrapped in
92
+ > `@layer bronto`, so mixing the bundle with individual leaves (e.g.
93
+ > per-route CSS splitting in SvelteKit/Astro) is safe: no silent
94
+ > cascade inversion. The deliberate full-specificity escape hatch is
95
+ > the explicit `@ponchia/ui/css/unlayered/<leaf>.css` path — use it
96
+ > only when you *want* an unlayered override, never by accident.
66
97
 
67
98
  Set `data-theme="light"` or `data-theme="dark"` on `<html>`; defaults follow
68
99
  `prefers-color-scheme`.
@@ -90,7 +121,9 @@ themeColor('dark').accent; // → "#ff3b41"
90
121
  ```
91
122
 
92
123
  `behaviors` wires `[data-bronto-theme-toggle]`, `[data-bronto-dismiss]` /
93
- `[data-bronto-dismissible]`, `[data-bronto-disclosure]`, and native
124
+ `[data-bronto-dismissible]`, `[data-bronto-disclosure]`,
125
+ `[data-bronto-menu]` (`initMenu`: Escape / outside-click /
126
+ close-on-activate for a `<details>` `.ui-menu` dropdown), and native
94
127
  `<dialog>` glue (`initDialog`: `[data-bronto-open]` / `[data-bronto-close]`
95
128
  / `[data-bronto-dialog-light]`). `toast(message, { tone, title, duration })`
96
129
  pushes into a shared, body-anchored stack. Each initializer is SSR-safe and
@@ -112,74 +145,70 @@ modules, so it is also a live integration test.
112
145
  | `overlay.css` | modal + drawer (native `<dialog>`), dropdown menu |
113
146
  | `disclosure.css` | tabs, accordion (`<details>`), segmented, breadcrumb, pagination, avatar |
114
147
  | `table.css` | `ui-table` dense / comfortable |
115
- | `app.css` | admin shell: rail, topbar, toolbar, panel, metrics |
116
- | `navigation.css` | site nav, menu, theme toggle (dot indicator) |
117
- | `typography.css` | display headings, eyebrows, legacy `.button` |
118
- | `content.css` | `.ui-prose` Markdown/raw-HTML long-form, zero per-element classes |
119
- | `cards.css` | semantic content cards (token-driven) |
120
- | `layout.css` | site shell, hero, grids |
121
- | `responsive.css` | breakpoint overrides |
148
+ | `app.css` | admin shell: `ui-app-shell`/`-rail`/`-topbar`/`-toolbar`/`-panel`/`-nav`/`-metrics` |
149
+ | `navigation.css` | `ui-themetoggle` (dot-thumb switch) |
150
+ | `site.css` | content-site shell: `ui-container`, `ui-siteheader`/`ui-sitenav` (aria-current), `ui-sitemenu`, `ui-sitefooter`, `ui-skiplink`, `ui-tags`, `ui-meta` |
151
+ | `content.css` | `.ui-prose` Markdown/raw-HTML long-form (zero classes) + `ui-quote` pull-quote |
122
152
 
123
- ## Demo
153
+ ## Getting started
124
154
 
125
- `demo/index.html` is a kitchen sink covering every primitive in both themes.
126
- Serve the package root and open `/demo/`:
155
+ | Consumer | Guide |
156
+ | ----------------------- | ------------------------------------------------------------------ |
157
+ | Astro | [`docs/getting-started/astro.md`](docs/getting-started/astro.md) |
158
+ | SvelteKit | [`docs/getting-started/sveltekit.md`](docs/getting-started/sveltekit.md) |
159
+ | Vanilla / Vite / plain | [`docs/getting-started/vanilla.md`](docs/getting-started/vanilla.md) |
160
+ | React / Solid (snippet) | [`docs/getting-started/react-solid.md`](docs/getting-started/react-solid.md) |
161
+ | Tailwind / cascade-layer interop | [`docs/interop/tailwind.md`](docs/interop/tailwind.md) |
127
162
 
128
- ```bash
129
- python3 -m http.server -d . 8080 # then open http://localhost:8080/demo/
130
- ```
163
+ Each covers the CSS import location, the **no-flash** `applyStoredTheme`
164
+ head-script pattern, behavior init/cleanup in that framework's lifecycle,
165
+ and SSR caveats. Index: [`docs/integration.md`](docs/integration.md).
131
166
 
132
- ## Develop
133
-
134
- ```bash
135
- npm install # stylelint + jsdom (test only)
136
- npm run check # lint + 5 integrity checks (exports, tokens, classes, dist, pack)
137
- npm test # node:test — pure modules + jsdom behavior tests
138
- npm run lint:fix # auto-fix the safe stylistic rules + logical properties
139
- npm run tokens:build # regenerate tokens/index.json from tokens/index.js
140
- npm run dist:build # rebuild the flattened dist/ bundles
141
- ```
142
-
143
- `npm run check` enforces that the data mirrors cannot drift from the CSS:
144
- exports/import-graph integrity, `tokens.css` ⇄ `tokens/index.{js,json}`, the
145
- `classes` registry ⇄ the `.ui-*` selectors, `dist/` ⇄ `css/` (fresh + in
146
- budget), and that the published tarball ships only the intended files.
147
-
148
- Visual + a11y regression is a separate suite (real browser, so not in the
149
- zero-dep core check):
150
-
151
- ```bash
152
- npx playwright test # demo screenshots (light/dark/RTL) + axe-core WCAG
153
- ```
154
-
155
- It is pinned to a Playwright container so baselines are byte-stable; the
156
- committed baselines under `test/e2e/__screenshots__` were authored in that
157
- same image. CI (`.github/workflows/ci.yml`) runs both the `check` job and a
158
- containerised `visual` job on every branch push and PR. It never publishes —
159
- a push to `main` ships nothing.
160
-
161
- ## Release
167
+ ## Demo
162
168
 
163
- Releases publish to npm and are tag-driven:
169
+ `demo/index.html` is a kitchen sink covering every primitive in both
170
+ themes — it drives itself with the real behavior modules, so it is also a
171
+ live integration test. Serve the package root and open `/demo/`:
164
172
 
165
173
  ```bash
166
- # 1. bump "version" in package.json, land on main, let CI go green
167
- git tag vX.Y.Z && git push origin vX.Y.Z
174
+ python3 -m http.server -d . 8080 # then open http://localhost:8080/demo/
168
175
  ```
169
176
 
170
- The tag triggers `.github/workflows/release.yml`: `validate` (read-only
171
- checks + tag↔version match) → `publish-npm` (only if validate passes) +
172
- `release-notes`. **The npm publish is the gate** a failing check means
173
- the version never reaches npm, so consumers never resolve it. GitHub also
174
- serves the raw tag tarball ungated, but that is a legacy/fallback path, not
175
- the documented install. See [`docs/architecture.md`](docs/architecture.md).
176
-
177
- Published: `@ponchia/ui` is live on npm (latest `0.2.1`), released by CI
178
- with provenance. The `@ponchia` scope and the `NPM_TOKEN` repo secret are
179
- in place, so a pushed `vX.Y.Z` tag is all a release needs.
177
+ ## Develop & release
178
+
179
+ Contributor setup, the 14 `check` gates, the e2e suite, the visual-
180
+ baseline workflow, the deprecation policy and the tag-driven release
181
+ flow all live in **[CONTRIBUTING.md](CONTRIBUTING.md)**. Direction and
182
+ scope: **[ROADMAP.md](ROADMAP.md)**.
183
+
184
+ ## Versioning
185
+
186
+ Pre-1.0 and deliberately so. **Until `1.0.0`, breaking changes ship in
187
+ the _minor_** (`0.x.0`); patches (`0.x.y`) are non-breaking. This is the
188
+ standard 0.x reading of SemVer, stated explicitly because this framework
189
+ dresses several apps:
190
+
191
+ - Because breaking changes bump the **minor**, the protective range is
192
+ the patch range. At `0.x` npm resolves **both** `^0.3.0` and `~0.3.0`
193
+ to `>=0.3.0 <0.4.0` — they are equivalent here, and either gives you
194
+ only non-breaking `0.3.x` patches while holding back the next
195
+ (breaking) `0.4.0`. Pin either; pin an **exact** version if you want
196
+ zero surprise and to adopt each minor deliberately.
197
+ - Every breaking change is called out in [`CHANGELOG.md`](CHANGELOG.md)
198
+ under a **BREAKING** heading with a migration note.
199
+
200
+ **What is contractual** (changes are breaking): the `--accent`
201
+ derivation and token **names** (incl. `--accent-text`, `--focus-ring`);
202
+ the `.ui-*` class names and `cls`/recipe names; the `data-bronto-*`
203
+ behavior attributes; each behavior's return-cleanup contract. **What is
204
+ not** (may change in any release): token _values_ (visual tuning), the
205
+ internal leaf-file boundaries and `@layer` internals, and anything
206
+ explicitly marked legacy/deprecated. Full token contract:
207
+ [`docs/theming.md`](docs/theming.md).
180
208
 
181
209
  ## Consumers
182
210
 
183
- Built for two shapes of app: a content/marketing site (imports
184
- `@ponchia/ui/css/core.css`) and an admin dashboard (imports the full
185
- `@ponchia/ui/css`). Consuming apps depend on it via `@ponchia/ui`.
211
+ Built for two shapes of app: a content/marketing site (`ui-site*`,
212
+ `ui-prose`) and an admin dashboard (`ui-app-*` shell). Both import the
213
+ one bundle `@ponchia/ui` (or `@ponchia/ui/css`); consuming apps depend
214
+ on it via `@ponchia/ui`.
@@ -39,6 +39,59 @@ export declare function dismissible(opts?: DelegateOpts): Cleanup;
39
39
  /** Wire `[data-bronto-disclosure]` triggers. Returns a cleanup function. */
40
40
  export declare function initDisclosure(opts?: DelegateOpts): Cleanup;
41
41
 
42
+ /**
43
+ * Close affordances (Escape, outside-click, close-on-activate) for a
44
+ * native `<details data-bronto-menu>` dropdown holding a `.ui-menu`.
45
+ * Not a full ARIA menu by design. Returns a cleanup function.
46
+ */
47
+ export declare function initMenu(opts?: DelegateOpts): Cleanup;
48
+
49
+ /**
50
+ * Accessible validation glue for `<form data-bronto-validate>`:
51
+ * progressive enhancement over the Constraint Validation API. Sets
52
+ * `aria-invalid`, writes `validationMessage` into the field's
53
+ * `[data-bronto-error]` / `.ui-hint` slot (linked via
54
+ * `aria-describedby`), and on invalid submit fills the form's
55
+ * `[data-bronto-error-summary]` with focusable links and blocks submit.
56
+ * Works without JS (native validation). Returns a cleanup function.
57
+ */
58
+ export declare function initFormValidation(opts?: DelegateOpts): Cleanup;
59
+
60
+ /**
61
+ * Editable combobox with a filtered listbox popup (WAI-ARIA APG
62
+ * pattern), dependency-free and CSS-anchored. Wires
63
+ * `[data-bronto-combobox]` (input `role=combobox` +
64
+ * `.ui-combobox__list` of `role=option`): ids, `aria-expanded` /
65
+ * `aria-controls` / `aria-activedescendant`, type-to-filter, full
66
+ * keyboard, pointer select, outside-click close. Emits `bronto:change`
67
+ * ({ detail: { value } }) on selection. SSR-safe, idempotent per
68
+ * instance. Returns a cleanup function.
69
+ */
70
+ export declare function initCombobox(opts?: DelegateOpts): Cleanup;
71
+
72
+ /**
73
+ * Collision-aware popover, dependency-free. A `[data-bronto-popover]`
74
+ * trigger toggles the `.ui-popover` panel it names; the panel flips
75
+ * above when it would overflow the viewport and its inline edge is
76
+ * clamped on-screen. Uses the native top layer when the panel has
77
+ * `popover` and the Popover API exists, else an `.is-open` class.
78
+ * Manages `aria-expanded`/`aria-controls`, Escape + outside-click
79
+ * close, scroll/resize reposition. Returns a cleanup function.
80
+ */
81
+ export declare function initPopover(opts?: DelegateOpts): Cleanup;
82
+
83
+ /**
84
+ * Client-side sortable + selectable data table for
85
+ * `[data-bronto-sortable]`. Header `.ui-table__sort` / `th[data-sort]`
86
+ * cycles `aria-sort` and reorders the tbody (numeric- or
87
+ * locale-string-aware); `[data-bronto-select-all]` toggles
88
+ * `[data-bronto-select]` rows + `aria-selected` with synced
89
+ * checked/indeterminate state. Emits `bronto:selectionchange`
90
+ * ({ detail: { count } }). SSR-safe, idempotent per table. Returns a
91
+ * cleanup function.
92
+ */
93
+ export declare function initTableSort(opts?: DelegateOpts): Cleanup;
94
+
42
95
  /**
43
96
  * Wire `[data-bronto-tabs]` groups with the WAI-ARIA Tabs keyboard
44
97
  * pattern (roving tabindex, Arrow/Home/End, aria-selected, panel sync).