@vanduo-oss/framework 1.6.0 → 1.7.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 +24 -0
- package/README.md +27 -179
- package/SKILL.md +58 -0
- package/css/components/accordion.css +80 -0
- package/css/components/alerts.css +65 -0
- package/css/components/avatar.css +2 -1
- package/css/components/badges.css +2 -1
- package/css/components/buttons.css +62 -9
- package/css/components/cards.css +26 -0
- package/css/components/code-snippet.css +23 -0
- package/css/components/collections.css +21 -1
- package/css/components/flow.css +20 -0
- package/css/components/forms.css +12 -1
- package/css/components/modals.css +69 -0
- package/css/components/preloader.css +31 -0
- package/css/components/progress.css +46 -0
- package/css/components/separator.css +50 -0
- package/css/components/skeleton.css +42 -0
- package/css/components/slider.css +92 -0
- package/css/components/tabs.css +46 -0
- package/css/core/helpers.css +17 -0
- package/css/utilities/table.css +9 -0
- package/css/vanduo.css +3 -0
- package/dist/build-info.json +3 -3
- package/dist/vanduo-core.css +622 -15
- package/dist/vanduo-core.css.map +1 -1
- package/dist/vanduo-core.min.css +2 -2
- package/dist/vanduo-core.min.css.map +1 -1
- package/dist/vanduo.cjs.js +2 -2
- package/dist/vanduo.cjs.min.js +2 -2
- package/dist/vanduo.css +622 -15
- package/dist/vanduo.css.map +1 -1
- package/dist/vanduo.esm.js +2 -2
- package/dist/vanduo.esm.min.js +2 -2
- package/dist/vanduo.js +2 -2
- package/dist/vanduo.min.css +2 -2
- package/dist/vanduo.min.css.map +1 -1
- package/dist/vanduo.min.js +2 -2
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
8
8
|
Full release notes — covering the framework, the documentation site, and
|
|
9
9
|
ecosystem packages side by side — live at <https://vanduo.dev/#changelog>.
|
|
10
10
|
|
|
11
|
+
## [1.7.1] - 2026-07-05
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- **Button danger alias** — `.vd-btn-danger`, `.vd-btn-outline-danger`, and
|
|
15
|
+
`.vd-btn-ghost-danger` now share the same rules as the existing `-error`
|
|
16
|
+
variants, matching badges, alerts, and chips after the unified status vocabulary
|
|
17
|
+
migration.
|
|
18
|
+
|
|
19
|
+
## [1.7.0] - 2026-06-29
|
|
20
|
+
|
|
21
|
+
Additive minor backing the `@vanduo-oss/vue` 0.3.0 release. Adds CSS for new
|
|
22
|
+
components plus alias classes the Vue components render, so the framework
|
|
23
|
+
stylesheet (which `@vanduo-oss/vue` ships as its CSS) styles every class. No
|
|
24
|
+
vanilla class names changed; every rule is additive and container-level rules
|
|
25
|
+
that could collide with legacy base styles are gated with `:has()`.
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- **Separator + Slider components** — new `css/components/separator.css` (`.vd-separator`, `-vertical`, `-labeled`, `-label`) and `css/components/slider.css` (`.vd-slider` range input, `.vd-slider-field`/`-row`/`-value`), wired into `css/vanduo.css`. (`VdSwitch` reuses `.vd-form-switch`; `VdMenu` reuses `.vd-dropdown`.)
|
|
29
|
+
- **Unified status-palette aliases** — `.vd-input-danger` + `.vd-badge-danger` (aliases of the `-error` validation/variant), `.vd-alert-secondary` (new), plus `.vd-form-label` and `.vd-form-radio-icon` form helpers — backing the unified `primary/secondary/success/warning/danger/info` vocabulary in `@vanduo-oss/vue`.
|
|
30
|
+
- **Accordion component** — new `css/components/accordion.css` (`.vd-accordion`, `-item`, `-header`, `-icon`, `-panel`), wired into `css/vanduo.css`. Previously no accordion CSS existed.
|
|
31
|
+
- **Panel-based modal aliases** (`css/components/modals.css`) — `.vd-modal.vd-modal-open` (container open state), `.vd-modal-open .vd-modal-backdrop` (backdrop visibility), `.vd-modal-panel` (merges the legacy `.vd-modal-dialog` + `.vd-modal-content` box), and `.vd-modal-panel-{sm,md,lg}` sizes. Fixes invisible `VdModal` dialogs.
|
|
32
|
+
- **Component sub-element aliases** — `.vd-alert-body` / `.vd-alert-dismiss` (alerts), `.vd-btn-spinner` (a real loading spinner element; legacy `::after` suppressed when present), `.vd-card-interactive` (cards), `.vd-progress-track` / `-fill` / `-label` + `.vd-progress.is-indeterminate` (progress), `.vd-avatar-img` (alias for `.vd-avatar img`), `.vd-tab` / `.vd-tab-panels` (tabs), `.vd-code-snippet-pre` (code snippet), `.vd-collection-list` / `-text-secondary` (collections), `.vd-flow-controls` / `-position` (flow), `.vd-skeleton-lines` / `-text-short` / `-card-header` / `-card-body` / `-card-{sm,md,lg,xl}` (skeleton), `.vd-preloader-spinner` (preloader), and `.vd-table-caption` (tables).
|
|
33
|
+
- **Utilities** — `.vd-muted` and `.vd-visually-hidden` (`css/core/helpers.css`).
|
|
34
|
+
|
|
11
35
|
## [1.6.0] - 2026-06-27
|
|
12
36
|
|
|
13
37
|
Additive release. Adds the Popover and Search primitives and an optional
|
package/README.md
CHANGED
|
@@ -1,201 +1,49 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img src="vanduo-oss-animated.svg" alt="vanduo-oss/framework" width="220"/>
|
|
3
|
+
</div>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
<img src="vanduo-banner.svg" alt="Vanduo Framework Banner" width="100%">
|
|
5
|
-
</p>
|
|
5
|
+
# @vanduo-oss/framework
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<a href="https://github.com/vanduo-oss/framework/blob/main/LICENSE"><img src="https://img.shields.io/github/license/vanduo-oss/framework?style=flat-square&color=64748b" alt="License"></a>
|
|
11
|
-
</p>
|
|
7
|
+
[](https://www.npmjs.com/package/@vanduo-oss/framework)
|
|
8
|
+
[](https://github.com/vanduo-oss/framework/actions/workflows/ci.yml)
|
|
9
|
+
[](./LICENSE)
|
|
12
10
|
|
|
13
|
-
|
|
11
|
+
> The zero-build **Vanilla** engine of the Vanduo design system.
|
|
14
12
|
|
|
15
|
-
[
|
|
13
|
+
Drop-in HTML/CSS/JS — 48+ components driven by `.vd-*` classes and `data-vd-*` attributes, an imperative `window.Vanduo` runtime, and a strict `--vd-*` token API. Zero runtime dependencies; consumes design tokens from [`@vanduo-oss/core`](https://www.npmjs.com/package/@vanduo-oss/core). Need Vue 3 instead? See [`@vanduo-oss/vue`](https://www.npmjs.com/package/@vanduo-oss/vue).
|
|
16
14
|
|
|
17
|
-
##
|
|
15
|
+
## Install
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
- 48+ components across layout, navigation, overlays, search, and effects
|
|
21
|
-
- Scoped runtime APIs for dynamic DOM work
|
|
22
|
-
- Strict design token API under `--vd-*`
|
|
23
|
-
- Built-in dark, light, and system theming
|
|
24
|
-
- Theme customizer with color, font, and radius controls
|
|
25
|
-
- Theme Switcher menu variant for icon-only light/dark/system selection in navbars
|
|
26
|
-
- Playwright-based browser coverage across Chromium, Firefox, and WebKit
|
|
27
|
-
|
|
28
|
-
## What's New in 1.6.0
|
|
29
|
-
|
|
30
|
-
Additive release — two new primitives and an optional palette, plus one HTML-sanitization behavior change to note.
|
|
31
|
-
|
|
32
|
-
- **New — Popover component** (`window.VanduoPopover`) — a general popover primitive with click / hover / focus triggers, external-panel composition via `data-vd-popover-target`, size variants, and auto-placement flip on overflow — alongside the existing `.vd-bubble`.
|
|
33
|
-
- **New — Search helper** (`window.VanduoSearch`) — a small registry letting consumers register their own data sources (`register` / `unregister` / `list` / `query`) behind a single search surface; results merge across sources.
|
|
34
|
-
- **New — Optional Fibonacci palette** — a golden-angle generated palette, opt in at runtime via `data-palette="fibonacci"` on `<html>`. **Open Color remains the default look.**
|
|
35
|
-
- **Behavior change — HTML sanitization denies inline styles by default** — `sanitizeHtml` (used by Bubble / Popover rich content) now strips `style` attributes, closing an attribute-injection vector. Move inline styles to classes; opt back in only where you fully trust the source.
|
|
36
|
-
- **Hardening** — `escapeHtml` is now quote-safe for attribute contexts.
|
|
37
|
-
- **Tooling** — dependencies updated to latest; pnpm config migrated to `pnpm-workspace.yaml`.
|
|
38
|
-
|
|
39
|
-
## Previous: 1.5.1
|
|
40
|
-
|
|
41
|
-
- **Expanding Cards — mobile** — below `768px`, panels stack vertically and expand in place using the same flex-grow redistribution as the desktop strip (replacing progressive hide and non-animatable `order` reorder). Inactive rows render as compact stripes with icon + title; labels and subtitles transition smoothly. `ArrowUp`/`ArrowDown` keyboard navigation added alongside left/right.
|
|
42
|
-
- **Expanding Cards — photo backgrounds** — active panels use `background-size: cover` and `background-repeat: no-repeat` so wide expanded cards no longer show tiled repeats on the sides.
|
|
43
|
-
- **Expanding Cards — polish** — mobile overflow clipping and keyboard focus edge cases resolved.
|
|
44
|
-
|
|
45
|
-
## Previous: 1.5.0
|
|
46
|
-
|
|
47
|
-
- **Layout primitives** — new CSS-only layout containers — `.vd-box`, `.vd-stack`, `.vd-inline`, `.vd-center`, `.vd-frame` (golden-ratio aspect box), `.vd-cover`, and `.vd-switcher` (container-query-free responsive row→column) — with a `data-*` API (`data-pad`, `data-gap`, `data-align`, `data-justify`, `data-round`, `data-ratio`…) that consumes the existing Fibonacci spacing/radius and semantic tokens. They are the composition layer between utilities and components — *utilities style an element; primitives arrange elements*. Zero JS, zero new public tokens.
|
|
48
|
-
- **Hex grid is now a standalone package** — `VdHexGrid` was never part of the bundle; its source has moved out of the framework tree. Install [`@vanduo-oss/hex-grid`](https://www.npmjs.com/package/@vanduo-oss/hex-grid) directly.
|
|
49
|
-
|
|
50
|
-
## Previous: 1.4.6
|
|
51
|
-
|
|
52
|
-
- **Leaner default CSS** — `css/vanduo.css` now bundles the `regular` + `fill` icon weights only (~45% smaller minified CSS). Need all six weights? Import `css/icons/icons-all.css`.
|
|
53
|
-
- **No-icons core build** — new `dist/vanduo-core.min.css` (`@vanduo-oss/framework/css/core`) drops the bundled icons entirely (~123 KB lighter) for consumers who ship their own icon set.
|
|
54
|
-
- **Smaller package** — the build ships only the icon weights the bundle actually uses into `dist/icons/`, instead of all six.
|
|
55
|
-
- **TypeScript types** — a hand-written `dist/vanduo.d.ts` for the `Vanduo` runtime, exposed via the `types` field.
|
|
56
|
-
- **In-repo changelog** — a new [CHANGELOG.md](CHANGELOG.md) (Keep a Changelog), now validated by `check:versions`.
|
|
57
|
-
- **Version-consistency now covers prose** — `pnpm check:versions` validates README, `SECURITY.md`, `llms.txt`, and `CHANGELOG.md`, not just the dist banners.
|
|
58
|
-
- **Lint guard** — raw `innerHTML` assignment is now flagged by ESLint outside the sanitization helpers.
|
|
59
|
-
- **Parallax & print fixes (now tested)** — speed/direction classes and the print stylesheet's hide-list now use the canonical `vd-` prefix, with new Playwright regression specs; removed the unused internal `doc-tabs` styles from the bundle.
|
|
60
|
-
|
|
61
|
-
## Previous: 1.4.5
|
|
62
|
-
|
|
63
|
-
- **Rounded-corner background fixes** — draggable surfaces and input-group addons use `background-clip: padding-box` so opaque fills no longer bleed past border arcs at large `data-radius` presets.
|
|
64
|
-
- **Background-clip audit** — Playwright `@audit` harness at `tests/audit/background-clip-audit.spec.ts` for regression checks.
|
|
65
|
-
- Normative API: [openspec/specs/draggable/spec.md](openspec/specs/draggable/spec.md).
|
|
66
|
-
|
|
67
|
-
## Quick Start
|
|
68
|
-
|
|
69
|
-
### CDN
|
|
70
|
-
|
|
71
|
-
```html
|
|
72
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.6.0/dist/vanduo.min.css">
|
|
73
|
-
<script src="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.6.0/dist/vanduo.min.js"></script>
|
|
74
|
-
<script>
|
|
75
|
-
Vanduo.init();
|
|
76
|
-
</script>
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
> **Production tip:** harden CDN tags with Subresource Integrity — add `integrity="sha384-…" crossorigin="anonymous"`. Copy the hash from [jsdelivr.com](https://www.jsdelivr.com/) (per-file "SRI" button) or generate it with `openssl dgst -sha384 -binary dist/vanduo.min.js | openssl base64 -A`.
|
|
80
|
-
|
|
81
|
-
### Local Dist Files
|
|
82
|
-
|
|
83
|
-
```html
|
|
84
|
-
<link rel="stylesheet" href="dist/vanduo.min.css">
|
|
85
|
-
<script src="dist/vanduo.min.js"></script>
|
|
86
|
-
<script>
|
|
87
|
-
Vanduo.init();
|
|
88
|
-
</script>
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Package Install
|
|
92
|
-
|
|
93
|
-
```bash
|
|
17
|
+
```sh
|
|
94
18
|
pnpm add @vanduo-oss/framework
|
|
95
19
|
```
|
|
96
20
|
|
|
97
21
|
```js
|
|
98
|
-
import
|
|
99
|
-
import { Vanduo } from
|
|
22
|
+
import "@vanduo-oss/framework/css";
|
|
23
|
+
import { Vanduo } from "@vanduo-oss/framework";
|
|
100
24
|
|
|
101
25
|
Vanduo.init();
|
|
102
26
|
```
|
|
103
27
|
|
|
104
|
-
##
|
|
105
|
-
|
|
106
|
-
```js
|
|
107
|
-
Vanduo.init(root);
|
|
108
|
-
Vanduo.initComponents(root);
|
|
109
|
-
Vanduo.reinit('lazyLoad', root);
|
|
110
|
-
Vanduo.destroy(root);
|
|
111
|
-
Vanduo.destroyAll();
|
|
112
|
-
Vanduo.getComponent('docSearch');
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
- Omit `root` to target the full document.
|
|
116
|
-
- Pass an `Element` to initialize or destroy only a subtree.
|
|
117
|
-
- Canonical component registry names use `lowerCamelCase`.
|
|
118
|
-
- `LazyLoad` remains available as a compatibility alias for `lazyLoad` in `1.4.x`.
|
|
119
|
-
|
|
120
|
-
## Token API
|
|
121
|
-
|
|
122
|
-
Vanduo `1.4.1` treats `--vd-*` as the only shipped custom-property namespace:
|
|
123
|
-
|
|
124
|
-
- Palette: `--vd-red-*`, `--vd-primary-*`, `--vd-gray-*`, and related scales. The
|
|
125
|
-
default palette is **Open Color** (`--vd-oc-*`); **Fibonacci** (golden-angle
|
|
126
|
-
generated, `--vd-fib-*`, with a `--vd-golden-1..8` accent track) is opt-in via
|
|
127
|
-
`data-palette="fibonacci"`. See [TOKENS.md](TOKENS.md#palette-system-open-color-default--fibonacci-optional).
|
|
128
|
-
- Colors: `--vd-color-*`
|
|
129
|
-
- Backgrounds: `--vd-bg-*`
|
|
130
|
-
- Text: `--vd-text-*`
|
|
131
|
-
- Borders: `--vd-border-*`
|
|
132
|
-
- Shadows: `--vd-shadow-*`
|
|
133
|
-
- Components/effects: `--vd-btn-*`, `--vd-card-*`, `--vd-morph-*`, and related internals
|
|
134
|
-
|
|
135
|
-
Legacy unprefixed token aliases were removed in `1.4.1`; update custom themes and overrides to use the `--vd-*` equivalents.
|
|
136
|
-
|
|
137
|
-
```css
|
|
138
|
-
.cta {
|
|
139
|
-
color: var(--vd-text-inverse);
|
|
140
|
-
background: var(--vd-color-primary);
|
|
141
|
-
border-color: var(--vd-border-color);
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
More detail lives in [TOKENS.md](TOKENS.md).
|
|
146
|
-
|
|
147
|
-
## CSS Bundle Notes
|
|
148
|
-
|
|
149
|
-
- `css/vanduo.css` remains the main framework entrypoint in `1.4.1`.
|
|
150
|
-
- The main bundle still includes framework-wide form defaults for native inputs and textareas.
|
|
151
|
-
- New component styling should prefer `.vd-*` hooks over new raw element selectors.
|
|
152
|
-
|
|
153
|
-
## Project Structure
|
|
154
|
-
|
|
155
|
-
```text
|
|
156
|
-
framework/
|
|
157
|
-
├── css/ # Foundation, utilities, effects, components
|
|
158
|
-
├── js/ # Runtime, lifecycle, components
|
|
159
|
-
├── dist/ # Built artifacts
|
|
160
|
-
├── tests/ # Playwright fixtures and specs
|
|
161
|
-
├── scripts/ # Build, verification, and inventory scripts
|
|
162
|
-
├── openspec/ # Spec-driven change proposals and component specs
|
|
163
|
-
└── docs/*.md # Release and architecture notes
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Development
|
|
28
|
+
## Quick start (no build)
|
|
167
29
|
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
pnpm test
|
|
175
|
-
pnpm run stats:css
|
|
30
|
+
```html
|
|
31
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.7.1/dist/vanduo.min.css">
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.7.1/dist/vanduo.min.js"></script>
|
|
33
|
+
<script>
|
|
34
|
+
Vanduo.init();
|
|
35
|
+
</script>
|
|
176
36
|
```
|
|
177
37
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
## Release Notes
|
|
181
|
-
|
|
182
|
-
- Changelog: [CHANGELOG.md](CHANGELOG.md)
|
|
183
|
-
- Architecture notes: [ARCHITECTURE.md](ARCHITECTURE.md)
|
|
184
|
-
- Token model: [TOKENS.md](TOKENS.md)
|
|
185
|
-
- Theme Switcher spec: [openspec/specs/theme-switcher/spec.md](openspec/specs/theme-switcher/spec.md)
|
|
186
|
-
- Draggable spec: [openspec/specs/draggable/spec.md](openspec/specs/draggable/spec.md)
|
|
187
|
-
- Changelog policy: [openspec/specs/changelog/spec.md](openspec/specs/changelog/spec.md)
|
|
188
|
-
- QA strategy: [QA-Automation-Strategy.md](QA-Automation-Strategy.md)
|
|
189
|
-
- Contributor workflow: [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
38
|
+
> **Production tip:** pin the version and add Subresource Integrity (`integrity="sha384-…" crossorigin="anonymous"`) to CDN tags. Get the hash from the per-file "SRI" button on [jsdelivr.com](https://www.jsdelivr.com/).
|
|
190
39
|
|
|
191
|
-
##
|
|
40
|
+
## Documentation
|
|
192
41
|
|
|
193
|
-
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
42
|
+
- Docs & live demos — https://vanduo.dev
|
|
43
|
+
- Agent / LLM reference — [SKILL.md](./SKILL.md)
|
|
44
|
+
- Token model — [TOKENS.md](./TOKENS.md) · Architecture — [ARCHITECTURE.md](./ARCHITECTURE.md)
|
|
45
|
+
- Changelog — [CHANGELOG.md](./CHANGELOG.md) · Security — [SECURITY.md](./SECURITY.md)
|
|
197
46
|
|
|
198
47
|
## License
|
|
199
48
|
|
|
200
|
-
MIT -
|
|
201
|
-
Third-party notices are listed in [THIRD-PARTY-LICENSES](THIRD-PARTY-LICENSES).
|
|
49
|
+
[MIT](./LICENSE) © Vanduo — third-party notices in [THIRD-PARTY-LICENSES](./THIRD-PARTY-LICENSES).
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vanduo-framework
|
|
3
|
+
description: Use when building UIs with @vanduo-oss/framework — the zero-build "Vanilla" HTML/CSS/JS engine of the Vanduo design system (data-attribute components + an imperative window.Vanduo runtime). Covers install (CDN/ESM/IIFE), the runtime API, the --vd-* token model, security, and caveats.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# @vanduo-oss/framework
|
|
7
|
+
|
|
8
|
+
The **Vanilla (zero-build) engine** of the Vanduo design system: drop-in HTML/CSS/JS — 48+ components driven by `.vd-*` classes + `data-vd-*` attributes, an imperative `window.Vanduo` runtime, and a strict `--vd-*` token API. Consumes the values from `@vanduo-oss/core`. No build step required.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
pnpm add @vanduo-oss/framework # Node >=18
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<!-- or CDN (pin a version; add SRI in production) -->
|
|
18
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.7.1/dist/vanduo.min.css">
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/gh/vanduo-oss/framework@v1.7.1/dist/vanduo.min.js"></script>
|
|
20
|
+
<script>Vanduo.init()</script>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Build variants in `dist/`: `vanduo.min.css` (or `vanduo-core.min.css`, no bundled icons), `vanduo.esm.js` (bundler), `vanduo.cjs.js` (CJS), `vanduo.min.js` (IIFE → global `window.Vanduo`). Subpaths: `@vanduo-oss/framework/css`, `/css/core`, `/iife`.
|
|
24
|
+
|
|
25
|
+
## Architecture
|
|
26
|
+
|
|
27
|
+
- **Component model** — `.vd-*` classes for styling + `data-vd-*` attributes that the runtime wires up (modal, flow, bubble, stepper, etc.).
|
|
28
|
+
- **Runtime** — `Vanduo.init()` once on load auto-initializes components; `reinit`/`destroy` handle dynamic DOM.
|
|
29
|
+
- **Tokens** — everything themable via `--vd-*` CSS custom properties (Open Color default; opt-in Fibonacci palette via `data-palette="fibonacci"` on `<html>`).
|
|
30
|
+
- **ESM vs IIFE** — ESM bundles into an app; IIFE runs standalone and populates `window.Vanduo`.
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
Runtime (`window.Vanduo`): `init(root?)`, `initComponents(root?)`, `reinit(name, root?)`, `destroy(root?)`, `destroyAll()`, `getComponent(name)`, `register(name, comp, opts?)`. Registry names are `lowerCamelCase`.
|
|
35
|
+
|
|
36
|
+
Component methods via `Vanduo.components.*` — e.g. `toast.show({title,message,type,duration})`, `flow.next/prev/goTo`, `bubble.show/hide`, `stepper.setStep/next/prev`, `rating.get/setValue`, `transfer.getSelected`, `tree.getChecked`, `spotlight.start/next/prev/stop`, `validate.validateForm/addRule`, `waypoint.refresh`.
|
|
37
|
+
|
|
38
|
+
Helpers (global): `sanitizeHtml(html, {allowStyle?, allowSvg?})`, `escapeHtml(str)`, `ready(cb)`, `safeStorageGet/Set`, `debounce`, `throttle`.
|
|
39
|
+
|
|
40
|
+
CSS entrypoints: `/css` (full), `/css/core` (tokens + components, no icons). Token namespaces: `--vd-color/bg/text/border/shadow-*`, `--vd-btn/card/morph-*`, palette scales `--vd-oc-*` / `--vd-fib-*`.
|
|
41
|
+
|
|
42
|
+
## Security
|
|
43
|
+
|
|
44
|
+
- `sanitizeHtml()` — whitelist-based; **denies inline `style` by default** (attribute-injection vector), opt back in only for trusted source. Bubble/Popover restrict links to `http/https/mailto`.
|
|
45
|
+
- `escapeHtml()` is quote-safe for attribute contexts.
|
|
46
|
+
- ESLint flags raw `innerHTML` assignment outside the sanitize helpers (`no-restricted-syntax`).
|
|
47
|
+
- No bundled-style nonce injection — apply your own CSP; harden CDN tags with Subresource Integrity.
|
|
48
|
+
|
|
49
|
+
## Caveats
|
|
50
|
+
|
|
51
|
+
- No-build consumers use CDN or local `/dist`; bare ESM specifiers need a bundler/import map.
|
|
52
|
+
- ES2022, modern browsers (no IE11 shims).
|
|
53
|
+
- Theming persists to `localStorage` (`vanduo-theme-preference`); `data-palette="fibonacci"` is runtime opt-in (Open Color is default).
|
|
54
|
+
- Hex grid and music player are **separate packages** (`@vanduo-oss/hex-grid`, `@vanduo-oss/music-player`).
|
|
55
|
+
|
|
56
|
+
## Docs
|
|
57
|
+
|
|
58
|
+
Full documentation and live demos: https://vanduo.dev
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vanduo Framework - Accordion
|
|
3
|
+
* Added in 1.6.1 to back @vanduo-oss/vue's VdAccordion.
|
|
4
|
+
*
|
|
5
|
+
* VdAccordion renders:
|
|
6
|
+
* ul.vd-accordion
|
|
7
|
+
* li.vd-accordion-item(.is-open)
|
|
8
|
+
* button.vd-accordion-header > span + span.vd-accordion-icon
|
|
9
|
+
* div.vd-accordion-panel (toggled via v-show)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
:root {
|
|
13
|
+
--vd-accordion-border-color: var(--vd-border-color);
|
|
14
|
+
--vd-accordion-header-bg: transparent;
|
|
15
|
+
--vd-accordion-header-bg-hover: var(--vd-bg-secondary);
|
|
16
|
+
--vd-accordion-padding-x: 1.3125rem; /* 21px - fib */
|
|
17
|
+
--vd-accordion-padding-y: 0.8125rem; /* 13px - fib */
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.vd-accordion {
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
list-style: none;
|
|
24
|
+
border: 1px solid var(--vd-accordion-border-color);
|
|
25
|
+
border-radius: var(--vd-btn-border-radius);
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.vd-accordion-item {
|
|
30
|
+
border-top: 1px solid var(--vd-accordion-border-color);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.vd-accordion-item:first-child {
|
|
34
|
+
border-top: none;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.vd-accordion-header {
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: space-between;
|
|
41
|
+
gap: 0.75rem;
|
|
42
|
+
width: 100%;
|
|
43
|
+
padding: var(--vd-accordion-padding-y) var(--vd-accordion-padding-x);
|
|
44
|
+
background: var(--vd-accordion-header-bg);
|
|
45
|
+
border: none;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
font-size: var(--vd-font-size-base);
|
|
48
|
+
font-weight: var(--vd-font-weight-medium);
|
|
49
|
+
color: var(--vd-text-primary);
|
|
50
|
+
text-align: left;
|
|
51
|
+
transition: background-color 0.15s ease;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.vd-accordion-header:hover {
|
|
55
|
+
background: var(--vd-accordion-header-bg-hover);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.vd-accordion-header:focus-visible {
|
|
59
|
+
outline: 2px solid var(--vd-color-primary);
|
|
60
|
+
outline-offset: -2px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.vd-accordion-icon {
|
|
64
|
+
flex-shrink: 0;
|
|
65
|
+
font-size: 1.25rem;
|
|
66
|
+
line-height: 1;
|
|
67
|
+
color: var(--vd-text-secondary);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.vd-accordion-panel {
|
|
71
|
+
padding: var(--vd-accordion-padding-y) var(--vd-accordion-padding-x);
|
|
72
|
+
color: var(--vd-text-primary);
|
|
73
|
+
border-top: 1px solid var(--vd-accordion-border-color);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@media (prefers-reduced-motion: reduce) {
|
|
77
|
+
.vd-accordion-header {
|
|
78
|
+
transition: none;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -94,6 +94,23 @@
|
|
|
94
94
|
color: var(--vd-alert-info-text);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/* Secondary variant (added 1.7.0 for the unified status palette) */
|
|
98
|
+
.vd-alert-secondary {
|
|
99
|
+
background-color: var(--vd-color-secondary-alpha-10);
|
|
100
|
+
border-color: var(--vd-color-secondary);
|
|
101
|
+
color: var(--vd-color-secondary-dark);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
[data-theme="dark"] .vd-alert-secondary {
|
|
105
|
+
color: var(--vd-color-secondary-light);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@media (prefers-color-scheme: dark) {
|
|
109
|
+
:root:not([data-theme]) .vd-alert-secondary {
|
|
110
|
+
color: var(--vd-color-secondary-light);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
97
114
|
/* Alert with Icon */
|
|
98
115
|
.vd-alert-icon {
|
|
99
116
|
display: flex;
|
|
@@ -222,3 +239,51 @@
|
|
|
222
239
|
transition: none;
|
|
223
240
|
}
|
|
224
241
|
}
|
|
242
|
+
|
|
243
|
+
/* ==========================================================================
|
|
244
|
+
@vanduo-oss/vue VdAlert markup (additive; added in 1.6.1)
|
|
245
|
+
VdAlert renders `.vd-alert > .vd-alert-icon + .vd-alert-body + .vd-alert-dismiss`.
|
|
246
|
+
.vd-alert-body wraps the title + content; .vd-alert-dismiss replaces the legacy
|
|
247
|
+
.vd-alert-close. Scoped with :has() so legacy alert markup is untouched.
|
|
248
|
+
========================================================================== */
|
|
249
|
+
.vd-alert:has(.vd-alert-body) {
|
|
250
|
+
display: flex;
|
|
251
|
+
align-items: flex-start;
|
|
252
|
+
gap: 0.75rem;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.vd-alert:has(.vd-alert-body) > .vd-alert-icon {
|
|
256
|
+
flex-shrink: 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.vd-alert-body {
|
|
260
|
+
flex: 1 1 auto;
|
|
261
|
+
min-width: 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.vd-alert-dismiss {
|
|
265
|
+
flex-shrink: 0;
|
|
266
|
+
padding: 0;
|
|
267
|
+
background: transparent;
|
|
268
|
+
border: none;
|
|
269
|
+
cursor: pointer;
|
|
270
|
+
opacity: 0.5;
|
|
271
|
+
color: inherit;
|
|
272
|
+
line-height: 1;
|
|
273
|
+
transition: opacity 0.15s ease;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.vd-alert-dismiss:hover {
|
|
277
|
+
opacity: 1;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.vd-alert-dismiss:focus-visible {
|
|
281
|
+
outline: 2px solid currentColor;
|
|
282
|
+
outline-offset: 2px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@media (prefers-reduced-motion: reduce) {
|
|
286
|
+
.vd-alert-dismiss {
|
|
287
|
+
transition: none;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -165,20 +165,23 @@
|
|
|
165
165
|
transform: translateY(1px);
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
/* Button Variants - Error */
|
|
169
|
-
.vd-btn-error
|
|
168
|
+
/* Button Variants - Danger (unified) / Error (alias) */
|
|
169
|
+
.vd-btn-error,
|
|
170
|
+
.vd-btn-danger {
|
|
170
171
|
background-color: var(--vd-color-error);
|
|
171
172
|
border-color: var(--vd-color-error);
|
|
172
173
|
color: var(--vd-color-white);
|
|
173
174
|
}
|
|
174
175
|
|
|
175
|
-
.vd-btn-error:hover:not(:disabled):not(.disabled):not(.is-disabled)
|
|
176
|
+
.vd-btn-error:hover:not(:disabled):not(.disabled):not(.is-disabled),
|
|
177
|
+
.vd-btn-danger:hover:not(:disabled):not(.disabled):not(.is-disabled) {
|
|
176
178
|
background-color: var(--vd-color-error-dark);
|
|
177
179
|
border-color: var(--vd-color-error-dark);
|
|
178
180
|
color: var(--vd-color-white);
|
|
179
181
|
}
|
|
180
182
|
|
|
181
|
-
.vd-btn-error:active:not(:disabled):not(.disabled):not(.is-disabled)
|
|
183
|
+
.vd-btn-error:active:not(:disabled):not(.disabled):not(.is-disabled),
|
|
184
|
+
.vd-btn-danger:active:not(:disabled):not(.disabled):not(.is-disabled) {
|
|
182
185
|
background-color: var(--vd-color-error-dark);
|
|
183
186
|
border-color: var(--vd-color-error-dark);
|
|
184
187
|
transform: translateY(1px);
|
|
@@ -264,13 +267,15 @@
|
|
|
264
267
|
color: var(--vd-color-black);
|
|
265
268
|
}
|
|
266
269
|
|
|
267
|
-
.vd-btn-outline-error
|
|
270
|
+
.vd-btn-outline-error,
|
|
271
|
+
.vd-btn-outline-danger {
|
|
268
272
|
background-color: transparent;
|
|
269
273
|
border-color: var(--vd-color-error);
|
|
270
274
|
color: var(--vd-color-error);
|
|
271
275
|
}
|
|
272
276
|
|
|
273
|
-
.vd-btn-outline-error:hover:not(:disabled):not(.disabled):not(.is-disabled)
|
|
277
|
+
.vd-btn-outline-error:hover:not(:disabled):not(.disabled):not(.is-disabled),
|
|
278
|
+
.vd-btn-outline-danger:hover:not(:disabled):not(.disabled):not(.is-disabled) {
|
|
274
279
|
background-color: var(--vd-color-error);
|
|
275
280
|
border-color: var(--vd-color-error);
|
|
276
281
|
color: var(--vd-color-white);
|
|
@@ -370,18 +375,21 @@
|
|
|
370
375
|
color: var(--vd-color-warning-active);
|
|
371
376
|
}
|
|
372
377
|
|
|
373
|
-
.vd-btn-ghost-error
|
|
378
|
+
.vd-btn-ghost-error,
|
|
379
|
+
.vd-btn-ghost-danger {
|
|
374
380
|
background-color: transparent;
|
|
375
381
|
border-color: transparent;
|
|
376
382
|
color: var(--vd-color-error);
|
|
377
383
|
}
|
|
378
384
|
|
|
379
|
-
.vd-btn-ghost-error:hover:not(:disabled):not(.disabled):not(.is-disabled)
|
|
385
|
+
.vd-btn-ghost-error:hover:not(:disabled):not(.disabled):not(.is-disabled),
|
|
386
|
+
.vd-btn-ghost-danger:hover:not(:disabled):not(.disabled):not(.is-disabled) {
|
|
380
387
|
background-color: var(--vd-color-error-alpha-10);
|
|
381
388
|
color: var(--vd-color-error-dark);
|
|
382
389
|
}
|
|
383
390
|
|
|
384
|
-
.vd-btn-ghost-error:active:not(:disabled):not(.disabled):not(.is-disabled)
|
|
391
|
+
.vd-btn-ghost-error:active:not(:disabled):not(.disabled):not(.is-disabled),
|
|
392
|
+
.vd-btn-ghost-danger:active:not(:disabled):not(.disabled):not(.is-disabled) {
|
|
385
393
|
background-color: var(--vd-color-error-alpha-20);
|
|
386
394
|
color: var(--vd-color-error-active);
|
|
387
395
|
}
|
|
@@ -513,6 +521,7 @@ a.vd-btn:hover {
|
|
|
513
521
|
.vd-btn-secondary.is-loading::after,
|
|
514
522
|
.vd-btn-success.is-loading::after,
|
|
515
523
|
.vd-btn-error.is-loading::after,
|
|
524
|
+
.vd-btn-danger.is-loading::after,
|
|
516
525
|
.vd-btn-info.is-loading::after {
|
|
517
526
|
border-color: var(--vd-color-white);
|
|
518
527
|
border-right-color: transparent;
|
|
@@ -527,4 +536,48 @@ a.vd-btn:hover {
|
|
|
527
536
|
to {
|
|
528
537
|
transform: rotate(360deg);
|
|
529
538
|
}
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* ==========================================================================
|
|
542
|
+
@vanduo-oss/vue VdButton spinner (additive; added in 1.6.1)
|
|
543
|
+
VdButton renders a real `<span class="vd-btn-spinner">` while loading (the
|
|
544
|
+
button also gets .is-loading). Style the real element and suppress the legacy
|
|
545
|
+
::after so only one spinner is shown.
|
|
546
|
+
========================================================================== */
|
|
547
|
+
.vd-btn.is-loading:has(.vd-btn-spinner)::after {
|
|
548
|
+
content: none;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.vd-btn-spinner {
|
|
552
|
+
position: absolute;
|
|
553
|
+
top: 50%;
|
|
554
|
+
left: 50%;
|
|
555
|
+
width: 1em;
|
|
556
|
+
height: 1em;
|
|
557
|
+
margin: -0.5em 0 0 -0.5em;
|
|
558
|
+
border: 2px solid var(--vd-color-primary);
|
|
559
|
+
border-right-color: transparent;
|
|
560
|
+
border-radius: 50%;
|
|
561
|
+
animation: btn-spinner 0.6s linear infinite;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
.vd-btn-primary .vd-btn-spinner,
|
|
565
|
+
.vd-btn-secondary .vd-btn-spinner,
|
|
566
|
+
.vd-btn-success .vd-btn-spinner,
|
|
567
|
+
.vd-btn-danger .vd-btn-spinner,
|
|
568
|
+
.vd-btn-error .vd-btn-spinner,
|
|
569
|
+
.vd-btn-info .vd-btn-spinner {
|
|
570
|
+
border-color: var(--vd-color-white);
|
|
571
|
+
border-right-color: transparent;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.vd-btn-warning .vd-btn-spinner {
|
|
575
|
+
border-color: var(--vd-color-black);
|
|
576
|
+
border-right-color: transparent;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
@media (prefers-reduced-motion: reduce) {
|
|
580
|
+
.vd-btn-spinner {
|
|
581
|
+
animation-duration: 1.2s;
|
|
582
|
+
}
|
|
530
583
|
}
|
package/css/components/cards.css
CHANGED
|
@@ -323,3 +323,29 @@ a.vd-card:active {
|
|
|
323
323
|
flex: 1 1 0%;
|
|
324
324
|
}
|
|
325
325
|
}
|
|
326
|
+
|
|
327
|
+
/* @vanduo-oss/vue VdCard :interactive (additive; added in 1.6.1) */
|
|
328
|
+
.vd-card-interactive {
|
|
329
|
+
cursor: pointer;
|
|
330
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.vd-card-interactive:hover {
|
|
334
|
+
transform: translateY(-2px) translateZ(0);
|
|
335
|
+
box-shadow: var(--vd-shadow-lg);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.vd-card-interactive:focus-visible {
|
|
339
|
+
outline: 2px solid var(--vd-color-primary);
|
|
340
|
+
outline-offset: 2px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
@media (prefers-reduced-motion: reduce) {
|
|
344
|
+
.vd-card-interactive {
|
|
345
|
+
transition: none;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.vd-card-interactive:hover {
|
|
349
|
+
transform: none;
|
|
350
|
+
}
|
|
351
|
+
}
|