@profpowell/vb-design-system 0.1.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.
- package/LICENSE +21 -0
- package/README.md +122 -0
- package/dist/vb-design-system.css +993 -0
- package/dist/vb-design-system.js +4482 -0
- package/dist/vb-design-system.min.css +1 -0
- package/dist/vb-design-system.min.js +513 -0
- package/package.json +78 -0
- package/src/index.css +21 -0
- package/src/index.js +24 -0
- package/src/lib/bundle-registry.js +156 -0
- package/src/lib/vb-element.js +96 -0
- package/src/patterns/do-dont.css +86 -0
- package/src/patterns/token-table.css +67 -0
- package/src/utils/copy-init.js +287 -0
- package/src/web-components/accessibility-specimen/api.json +51 -0
- package/src/web-components/accessibility-specimen/logic.js +232 -0
- package/src/web-components/accessibility-specimen/static.html +41 -0
- package/src/web-components/accessibility-specimen/styles.css +156 -0
- package/src/web-components/brand-specimen/api.json +37 -0
- package/src/web-components/brand-specimen/logic.js +61 -0
- package/src/web-components/brand-specimen/static.html +77 -0
- package/src/web-components/brand-specimen/styles.css +10 -0
- package/src/web-components/breakpoint-specimen/api.json +44 -0
- package/src/web-components/breakpoint-specimen/logic.js +186 -0
- package/src/web-components/breakpoint-specimen/static.html +38 -0
- package/src/web-components/breakpoint-specimen/styles.css +180 -0
- package/src/web-components/color-palette/api.json +73 -0
- package/src/web-components/color-palette/logic.js +280 -0
- package/src/web-components/color-palette/static.html +54 -0
- package/src/web-components/color-palette/styles.css +113 -0
- package/src/web-components/color-picker/_color-utils.js +210 -0
- package/src/web-components/component-sampler/api.json +15 -0
- package/src/web-components/component-sampler/logic.js +120 -0
- package/src/web-components/component-sampler/static.html +47 -0
- package/src/web-components/component-sampler/styles.css +9 -0
- package/src/web-components/font-pairer/_font-data.js +95 -0
- package/src/web-components/font-pairer/api.json +56 -0
- package/src/web-components/font-pairer/logic.js +401 -0
- package/src/web-components/font-pairer/static.html +9 -0
- package/src/web-components/font-pairer/styles.css +10 -0
- package/src/web-components/gradient-builder/_gradient-utils.js +54 -0
- package/src/web-components/gradient-builder/api.json +63 -0
- package/src/web-components/gradient-builder/logic.js +261 -0
- package/src/web-components/gradient-builder/static.html +9 -0
- package/src/web-components/gradient-builder/styles.css +10 -0
- package/src/web-components/icon-set/api.json +39 -0
- package/src/web-components/icon-set/logic.js +133 -0
- package/src/web-components/icon-set/static.html +36 -0
- package/src/web-components/icon-set/styles.css +82 -0
- package/src/web-components/icon-specimen/api.json +46 -0
- package/src/web-components/icon-specimen/logic.js +67 -0
- package/src/web-components/icon-specimen/static.html +39 -0
- package/src/web-components/icon-specimen/styles.css +38 -0
- package/src/web-components/layout-specimen/api.json +12 -0
- package/src/web-components/layout-specimen/logic.js +219 -0
- package/src/web-components/layout-specimen/static.html +22 -0
- package/src/web-components/layout-specimen/styles.css +95 -0
- package/src/web-components/motion-specimen/api.json +54 -0
- package/src/web-components/motion-specimen/logic.js +146 -0
- package/src/web-components/motion-specimen/static.html +13 -0
- package/src/web-components/motion-specimen/styles.css +29 -0
- package/src/web-components/palette-generator/_palette-utils.js +133 -0
- package/src/web-components/palette-generator/api.json +79 -0
- package/src/web-components/palette-generator/logic.js +288 -0
- package/src/web-components/palette-generator/static.html +47 -0
- package/src/web-components/palette-generator/styles.css +36 -0
- package/src/web-components/semantic-palette/_color-math.js +149 -0
- package/src/web-components/semantic-palette/api.json +41 -0
- package/src/web-components/semantic-palette/logic.js +400 -0
- package/src/web-components/semantic-palette/static.html +42 -0
- package/src/web-components/semantic-palette/styles.css +20 -0
- package/src/web-components/spacing-specimen/api.json +63 -0
- package/src/web-components/spacing-specimen/logic.js +132 -0
- package/src/web-components/spacing-specimen/static.html +71 -0
- package/src/web-components/spacing-specimen/styles.css +58 -0
- package/src/web-components/theme-catalog/api.json +14 -0
- package/src/web-components/theme-catalog/logic.js +228 -0
- package/src/web-components/theme-catalog/static.html +15 -0
- package/src/web-components/theme-export/api.json +18 -0
- package/src/web-components/theme-export/dtcg-serialize.js +417 -0
- package/src/web-components/theme-export/logic.js +201 -0
- package/src/web-components/theme-export/static.html +12 -0
- package/src/web-components/theme-export/theme-css-parse.js +93 -0
- package/src/web-components/theme-import/api.json +14 -0
- package/src/web-components/theme-import/catalog/atlassian.tokens.json +303 -0
- package/src/web-components/theme-import/catalog/bootstrap.tokens.json +304 -0
- package/src/web-components/theme-import/catalog/carbon.tokens.json +301 -0
- package/src/web-components/theme-import/catalog/catppuccin-mocha.tokens.json +301 -0
- package/src/web-components/theme-import/catalog/govuk.tokens.json +301 -0
- package/src/web-components/theme-import/catalog/manifest.json +132 -0
- package/src/web-components/theme-import/catalog/material.tokens.json +289 -0
- package/src/web-components/theme-import/catalog/salesforce.tokens.json +301 -0
- package/src/web-components/theme-import/catalog/tailwind.tokens.json +302 -0
- package/src/web-components/theme-import/dtcg-deserialize.js +322 -0
- package/src/web-components/theme-import/logic.js +263 -0
- package/src/web-components/theme-import/static.html +15 -0
- package/src/web-components/token-specimen/api.json +24 -0
- package/src/web-components/token-specimen/logic.js +256 -0
- package/src/web-components/token-specimen/static.html +47 -0
- package/src/web-components/token-specimen/styles.css +10 -0
- package/src/web-components/type-specimen/api.json +91 -0
- package/src/web-components/type-specimen/logic.js +156 -0
- package/src/web-components/type-specimen/static.html +84 -0
- package/src/web-components/type-specimen/styles.css +131 -0
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@profpowell/vb-design-system",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Design-system documentation components for Vanilla Breeze: color, type, spacing, token and motion specimens, palette generator, semantic palette, component sampler, theme export, accessibility specimen, breakpoint specimen, layout specimen, font pairer, and gradient builder.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Patrick Powell",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"homepage": "https://github.com/ProfPowell/vb-design-system#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/ProfPowell/vb-design-system.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ProfPowell/vb-design-system/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"vanilla-breeze",
|
|
18
|
+
"web-components",
|
|
19
|
+
"design-system",
|
|
20
|
+
"design-tokens",
|
|
21
|
+
"specimen",
|
|
22
|
+
"theme"
|
|
23
|
+
],
|
|
24
|
+
"files": [
|
|
25
|
+
"src",
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"main": "./dist/vb-design-system.js",
|
|
29
|
+
"module": "./src/index.js",
|
|
30
|
+
"style": "./dist/vb-design-system.css",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"import": "./src/index.js",
|
|
34
|
+
"default": "./dist/vb-design-system.js"
|
|
35
|
+
},
|
|
36
|
+
"./css": "./src/index.css",
|
|
37
|
+
"./dist/css": "./dist/vb-design-system.css",
|
|
38
|
+
"./color-palette": "./src/web-components/color-palette/logic.js",
|
|
39
|
+
"./palette-generator": "./src/web-components/palette-generator/logic.js",
|
|
40
|
+
"./type-specimen": "./src/web-components/type-specimen/logic.js",
|
|
41
|
+
"./spacing-specimen": "./src/web-components/spacing-specimen/logic.js",
|
|
42
|
+
"./token-specimen": "./src/web-components/token-specimen/logic.js",
|
|
43
|
+
"./component-sampler": "./src/web-components/component-sampler/logic.js",
|
|
44
|
+
"./semantic-palette": "./src/web-components/semantic-palette/logic.js",
|
|
45
|
+
"./motion-specimen": "./src/web-components/motion-specimen/logic.js",
|
|
46
|
+
"./theme-export": "./src/web-components/theme-export/logic.js",
|
|
47
|
+
"./accessibility-specimen": "./src/web-components/accessibility-specimen/logic.js",
|
|
48
|
+
"./breakpoint-specimen": "./src/web-components/breakpoint-specimen/logic.js",
|
|
49
|
+
"./layout-specimen": "./src/web-components/layout-specimen/logic.js",
|
|
50
|
+
"./font-pairer": "./src/web-components/font-pairer/logic.js",
|
|
51
|
+
"./gradient-builder": "./src/web-components/gradient-builder/logic.js",
|
|
52
|
+
"./theme-import": "./src/web-components/theme-import/logic.js",
|
|
53
|
+
"./theme-catalog": "./src/web-components/theme-catalog/logic.js",
|
|
54
|
+
"./brand-specimen": "./src/web-components/brand-specimen/logic.js",
|
|
55
|
+
"./icon-set": "./src/web-components/icon-set/logic.js",
|
|
56
|
+
"./icon-specimen": "./src/web-components/icon-specimen/logic.js",
|
|
57
|
+
"./package.json": "./package.json"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"build": "npm run build:js && npm run build:css",
|
|
61
|
+
"build:js": "esbuild src/index.js --bundle --format=esm --outfile=dist/vb-design-system.js && esbuild src/index.js --bundle --format=esm --minify --outfile=dist/vb-design-system.min.js",
|
|
62
|
+
"build:css": "esbuild src/index.css --bundle --outfile=dist/vb-design-system.css && esbuild src/index.css --bundle --minify --outfile=dist/vb-design-system.min.css",
|
|
63
|
+
"prepublishOnly": "npm run build",
|
|
64
|
+
"test:components": "playwright test"
|
|
65
|
+
},
|
|
66
|
+
"peerDependencies": {
|
|
67
|
+
"vanilla-breeze": ">=0.1.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"vanilla-breeze": {
|
|
71
|
+
"optional": true
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"devDependencies": {
|
|
75
|
+
"@playwright/test": "^1.61.1",
|
|
76
|
+
"esbuild": "^0.27.0"
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/index.css
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/* @profpowell/vb-design-system — component styles (light DOM). */
|
|
2
|
+
@import "./web-components/color-palette/styles.css";
|
|
3
|
+
@import "./web-components/palette-generator/styles.css";
|
|
4
|
+
@import "./web-components/type-specimen/styles.css";
|
|
5
|
+
@import "./web-components/spacing-specimen/styles.css";
|
|
6
|
+
@import "./web-components/token-specimen/styles.css";
|
|
7
|
+
@import "./web-components/component-sampler/styles.css";
|
|
8
|
+
@import "./web-components/semantic-palette/styles.css";
|
|
9
|
+
@import "./web-components/motion-specimen/styles.css";
|
|
10
|
+
@import "./web-components/accessibility-specimen/styles.css";
|
|
11
|
+
@import "./web-components/breakpoint-specimen/styles.css";
|
|
12
|
+
@import "./web-components/layout-specimen/styles.css";
|
|
13
|
+
@import "./web-components/font-pairer/styles.css";
|
|
14
|
+
@import "./web-components/gradient-builder/styles.css";
|
|
15
|
+
@import "./web-components/brand-specimen/styles.css";
|
|
16
|
+
@import "./web-components/icon-set/styles.css";
|
|
17
|
+
@import "./web-components/icon-specimen/styles.css";
|
|
18
|
+
|
|
19
|
+
/* design-system authoring patterns */
|
|
20
|
+
@import "./patterns/do-dont.css";
|
|
21
|
+
@import "./patterns/token-table.css";
|
package/src/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @profpowell/vb-design-system — barrel.
|
|
3
|
+
* Side-effect imports register every design-system component.
|
|
4
|
+
* Consumes Vanilla Breeze design tokens/themes via CSS custom properties.
|
|
5
|
+
*/
|
|
6
|
+
import './web-components/color-palette/logic.js';
|
|
7
|
+
import './web-components/palette-generator/logic.js';
|
|
8
|
+
import './web-components/type-specimen/logic.js';
|
|
9
|
+
import './web-components/spacing-specimen/logic.js';
|
|
10
|
+
import './web-components/token-specimen/logic.js';
|
|
11
|
+
import './web-components/component-sampler/logic.js';
|
|
12
|
+
import './web-components/semantic-palette/logic.js';
|
|
13
|
+
import './web-components/motion-specimen/logic.js';
|
|
14
|
+
import './web-components/theme-export/logic.js';
|
|
15
|
+
import './web-components/accessibility-specimen/logic.js';
|
|
16
|
+
import './web-components/breakpoint-specimen/logic.js';
|
|
17
|
+
import './web-components/layout-specimen/logic.js';
|
|
18
|
+
import './web-components/font-pairer/logic.js';
|
|
19
|
+
import './web-components/gradient-builder/logic.js';
|
|
20
|
+
import './web-components/theme-import/logic.js';
|
|
21
|
+
import './web-components/theme-catalog/logic.js';
|
|
22
|
+
import './web-components/brand-specimen/logic.js';
|
|
23
|
+
import './web-components/icon-set/logic.js';
|
|
24
|
+
import './web-components/icon-specimen/logic.js';
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bundle Registry — Vanilla Breeze
|
|
3
|
+
*
|
|
4
|
+
* Provides infrastructure for modular bundles to register effects,
|
|
5
|
+
* components, and activate full bundles at runtime.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ─── Effect registry ─────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const effects = new Map()
|
|
11
|
+
let observer = null
|
|
12
|
+
const reducedMotionMq = window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
13
|
+
|
|
14
|
+
function startObserver() {
|
|
15
|
+
if (observer) return
|
|
16
|
+
observer = new MutationObserver(mutations => {
|
|
17
|
+
for (const mutation of mutations) {
|
|
18
|
+
for (const node of mutation.addedNodes) {
|
|
19
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue
|
|
20
|
+
const el = /** @type {Element} */ (node)
|
|
21
|
+
matchEffects(el)
|
|
22
|
+
el.querySelectorAll('*').forEach(matchEffects)
|
|
23
|
+
}
|
|
24
|
+
for (const node of mutation.removedNodes) {
|
|
25
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue
|
|
26
|
+
const el = /** @type {Element} */ (node)
|
|
27
|
+
unmatchEffects(el)
|
|
28
|
+
el.querySelectorAll('*').forEach(unmatchEffects)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
observer.observe(document.body, { childList: true, subtree: true })
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function matchEffects(el) {
|
|
36
|
+
for (const [, def] of effects) {
|
|
37
|
+
if (el.matches?.(def.selector)) {
|
|
38
|
+
if (reducedMotionMq.matches && def.reducedMotionFallback) {
|
|
39
|
+
def.reducedMotionFallback(el)
|
|
40
|
+
} else {
|
|
41
|
+
def.init(el)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function unmatchEffects(el) {
|
|
48
|
+
for (const [, def] of effects) {
|
|
49
|
+
if (el.matches?.(def.selector) && def.destroy) {
|
|
50
|
+
def.destroy(el)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Register a DOM effect that auto-initializes on matching elements.
|
|
57
|
+
*
|
|
58
|
+
* @param {string} name - Unique effect name
|
|
59
|
+
* @param {{ selector: string, init: (el: Element) => void, destroy?: (el: Element) => void, reducedMotionFallback?: (el: Element) => void }} def
|
|
60
|
+
*/
|
|
61
|
+
export function registerEffect(name, def) {
|
|
62
|
+
effects.set(name, def)
|
|
63
|
+
|
|
64
|
+
// Initialize on existing matching elements
|
|
65
|
+
document.querySelectorAll(def.selector).forEach(el => {
|
|
66
|
+
if (reducedMotionMq.matches && def.reducedMotionFallback) {
|
|
67
|
+
def.reducedMotionFallback(el)
|
|
68
|
+
} else {
|
|
69
|
+
def.init(el)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// Start shared observer lazily
|
|
74
|
+
if (document.body) {
|
|
75
|
+
startObserver()
|
|
76
|
+
} else {
|
|
77
|
+
document.addEventListener('DOMContentLoaded', startObserver, { once: true })
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─── Component registry ──────────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
const components = new Map()
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Register a custom element with priority-based conflict resolution.
|
|
87
|
+
* First-wins at equal priority. Higher priority wins over lower.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} tag - Custom element tag name
|
|
90
|
+
* @param {typeof HTMLElement} impl - The element class
|
|
91
|
+
* @param {{ bundle?: string, contract?: string, priority?: number }} [opts]
|
|
92
|
+
*/
|
|
93
|
+
export function registerComponent(tag, impl, opts = {}) {
|
|
94
|
+
const priority = opts.priority ?? 10
|
|
95
|
+
const meta = { impl, bundle: opts.bundle, contract: opts.contract, priority }
|
|
96
|
+
|
|
97
|
+
const existing = components.get(tag)
|
|
98
|
+
|
|
99
|
+
if (customElements.get(tag)) {
|
|
100
|
+
// Already defined in the browser — cannot redefine
|
|
101
|
+
if (!existing || existing.priority >= priority) {
|
|
102
|
+
if (existing && existing.priority === priority && existing.impl !== impl) {
|
|
103
|
+
console.warn(
|
|
104
|
+
`[VB Bundle] Tag <${tag}> already registered by "${existing.bundle}" (priority ${existing.priority}). Skipping "${opts.bundle}".`
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
// Higher priority but can't redefine — warn
|
|
110
|
+
console.warn(
|
|
111
|
+
`[VB Bundle] Tag <${tag}> defined by "${existing.bundle}" cannot be replaced (customElements.define is permanent). "${opts.bundle}" has higher priority but arrived late.`
|
|
112
|
+
)
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (existing && existing.priority >= priority) {
|
|
117
|
+
if (existing.priority === priority) {
|
|
118
|
+
console.warn(
|
|
119
|
+
`[VB Bundle] Tag <${tag}> already registered by "${existing.bundle}". Skipping "${opts.bundle}" (first wins at equal priority).`
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
components.set(tag, meta)
|
|
126
|
+
customElements.define(tag, impl)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Activate a full pack by loading its CSS and JS from the CDN path.
|
|
131
|
+
* Convention: cdn/packs/{name}.full.css and cdn/packs/{name}.full.js
|
|
132
|
+
*
|
|
133
|
+
* @param {string} bundleName
|
|
134
|
+
* @param {{ basePath?: string }} [opts]
|
|
135
|
+
* @returns {Promise<void>}
|
|
136
|
+
*/
|
|
137
|
+
export async function activateBundle(bundleName, opts = {}) {
|
|
138
|
+
const base = opts.basePath ?? '/cdn/packs'
|
|
139
|
+
|
|
140
|
+
// Load CSS
|
|
141
|
+
const cssHref = `${base}/${bundleName}.full.css`
|
|
142
|
+
if (!document.querySelector(`link[href="${cssHref}"]`)) {
|
|
143
|
+
const link = document.createElement('link')
|
|
144
|
+
link.rel = 'stylesheet'
|
|
145
|
+
link.href = cssHref
|
|
146
|
+
await new Promise((resolve, reject) => {
|
|
147
|
+
link.onload = resolve
|
|
148
|
+
link.onerror = () => reject(new Error(`Failed to load bundle CSS: ${cssHref}`))
|
|
149
|
+
document.head.appendChild(link)
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Load JS
|
|
154
|
+
const jsSrc = `${base}/${bundleName}.full.js`
|
|
155
|
+
await import(jsSrc)
|
|
156
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VBElement — Minimal base class for Vanilla Breeze web components
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - data-upgraded guard (prevents double initialization on reconnect)
|
|
6
|
+
* - listen() method with automatic cleanup on disconnect
|
|
7
|
+
* - setup()/teardown() lifecycle hooks
|
|
8
|
+
*
|
|
9
|
+
* Does NOT provide: props reflection, template rendering, reactivity.
|
|
10
|
+
* Components that need observedAttributes/attributeChangedCallback
|
|
11
|
+
* declare them normally alongside setup()/teardown().
|
|
12
|
+
*/
|
|
13
|
+
class VBElement extends HTMLElement {
|
|
14
|
+
#cleanups = [];
|
|
15
|
+
/** @type {ElementInternals | undefined} */
|
|
16
|
+
#internals;
|
|
17
|
+
|
|
18
|
+
connectedCallback() {
|
|
19
|
+
if (this.hasAttribute('data-upgraded')) return;
|
|
20
|
+
if (this.setup() === false) return;
|
|
21
|
+
this.setAttribute('data-upgraded', '');
|
|
22
|
+
// Dispatch :upgraded in a microtask so any sibling component definitions
|
|
23
|
+
// queued in the same synchronous script (e.g. a pack's registerComponent
|
|
24
|
+
// calls) complete before consumers react. Without this, listeners that
|
|
25
|
+
// immediately assign .items can hit a race where downstream components
|
|
26
|
+
// (work-item, etc.) aren't defined yet and the default renderer falls
|
|
27
|
+
// back to a plain element.
|
|
28
|
+
queueMicrotask(() => {
|
|
29
|
+
this.dispatchEvent(new CustomEvent(`${this.localName}:upgraded`, { bubbles: true }));
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
disconnectedCallback() {
|
|
34
|
+
for (const fn of this.#cleanups) fn();
|
|
35
|
+
this.#cleanups = [];
|
|
36
|
+
this.removeAttribute('data-upgraded');
|
|
37
|
+
this.teardown();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Track an event listener for automatic cleanup on disconnect.
|
|
42
|
+
* @param {EventTarget} target
|
|
43
|
+
* @param {string} event
|
|
44
|
+
* @param {EventListenerOrEventListenerObject} handler
|
|
45
|
+
* @param {AddEventListenerOptions} [opts]
|
|
46
|
+
*/
|
|
47
|
+
listen(target, event, handler, opts) {
|
|
48
|
+
target.addEventListener(event, handler, opts);
|
|
49
|
+
this.#cleanups.push(() => target.removeEventListener(event, handler, opts));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Override in subclass. Return false to abort upgrade.
|
|
54
|
+
* @returns {boolean | void}
|
|
55
|
+
*/
|
|
56
|
+
setup() {}
|
|
57
|
+
|
|
58
|
+
/** Override in subclass for cleanup beyond event listeners. */
|
|
59
|
+
teardown() {}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Toggle a CustomStateSet entry targetable via the `:state(name)` CSS selector.
|
|
63
|
+
* Use for component-private flags. For author-facing state, keep using
|
|
64
|
+
* data-* / aria-* attributes — see admin/specs/custom-state-set-research.md.
|
|
65
|
+
*
|
|
66
|
+
* Lazily attaches ElementInternals on first call; subclasses that already
|
|
67
|
+
* attached internals (form-associated components) must hand them over via
|
|
68
|
+
* `_adoptInternals(this.attachInternals())` in their constructor to avoid
|
|
69
|
+
* the double-attach throw.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} name
|
|
72
|
+
* @param {boolean} on
|
|
73
|
+
*/
|
|
74
|
+
setState(name, on) {
|
|
75
|
+
if (!this.#internals) this.#internals = this.attachInternals();
|
|
76
|
+
const states = this.#internals.states;
|
|
77
|
+
try {
|
|
78
|
+
if (on) states.add(name); else states.delete(name);
|
|
79
|
+
} catch {
|
|
80
|
+
// Legacy --name syntax for older Chromium/WebKit releases
|
|
81
|
+
const legacy = `--${name}`;
|
|
82
|
+
if (on) states.add(legacy); else states.delete(legacy);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Hand pre-attached ElementInternals to the base class. Form-associated
|
|
88
|
+
* subclasses call this in their constructor right after attachInternals().
|
|
89
|
+
* @param {ElementInternals} internals
|
|
90
|
+
*/
|
|
91
|
+
_adoptInternals(internals) {
|
|
92
|
+
if (!this.#internals) this.#internals = internals;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { VBElement };
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do/Don't and Pro/Con list patterns
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* <ul data-list="do-dont">
|
|
6
|
+
* <li data-do>Use the full logo on light backgrounds.</li>
|
|
7
|
+
* <li data-dont>Don't stretch or rotate the logo.</li>
|
|
8
|
+
* </ul>
|
|
9
|
+
*
|
|
10
|
+
* <ul data-list="pro-con">
|
|
11
|
+
* <li data-pro>Fast initial load time.</li>
|
|
12
|
+
* <li data-con>Requires JavaScript for interactivity.</li>
|
|
13
|
+
* </ul>
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
[data-list="do-dont"],
|
|
17
|
+
[data-list="pro-con"] {
|
|
18
|
+
list-style: none;
|
|
19
|
+
padding-inline-start: 0;
|
|
20
|
+
display: grid;
|
|
21
|
+
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
|
|
22
|
+
gap: var(--size-s, 0.5rem);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Do / Pro items */
|
|
26
|
+
[data-list] > [data-do],
|
|
27
|
+
[data-list] > [data-pro] {
|
|
28
|
+
padding: var(--size-s, 0.5rem) var(--size-m, 1rem);
|
|
29
|
+
border-inline-start: 4px solid var(--color-success, oklch(55% 0.2 145));
|
|
30
|
+
background: var(--color-success-subtle, oklch(95% 0.03 145));
|
|
31
|
+
border-radius: var(--radius-s, 0.25rem);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Don't / Con items */
|
|
35
|
+
[data-list] > [data-dont],
|
|
36
|
+
[data-list] > [data-con] {
|
|
37
|
+
padding: var(--size-s, 0.5rem) var(--size-m, 1rem);
|
|
38
|
+
border-inline-start: 4px solid var(--color-error, oklch(55% 0.22 25));
|
|
39
|
+
background: var(--color-error-subtle, oklch(95% 0.03 25));
|
|
40
|
+
border-radius: var(--radius-s, 0.25rem);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Labels via ::before */
|
|
44
|
+
[data-list="do-dont"] > [data-do]::before {
|
|
45
|
+
content: "Do";
|
|
46
|
+
display: block;
|
|
47
|
+
font-weight: 700;
|
|
48
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
49
|
+
color: var(--color-success, oklch(45% 0.2 145));
|
|
50
|
+
margin-block-end: var(--size-2xs, 0.25rem);
|
|
51
|
+
text-transform: uppercase;
|
|
52
|
+
letter-spacing: 0.05em;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
[data-list="do-dont"] > [data-dont]::before {
|
|
56
|
+
content: "Don\2019t";
|
|
57
|
+
display: block;
|
|
58
|
+
font-weight: 700;
|
|
59
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
60
|
+
color: var(--color-error, oklch(45% 0.22 25));
|
|
61
|
+
margin-block-end: var(--size-2xs, 0.25rem);
|
|
62
|
+
text-transform: uppercase;
|
|
63
|
+
letter-spacing: 0.05em;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
[data-list="pro-con"] > [data-pro]::before {
|
|
67
|
+
content: "Pro";
|
|
68
|
+
display: block;
|
|
69
|
+
font-weight: 700;
|
|
70
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
71
|
+
color: var(--color-success, oklch(45% 0.2 145));
|
|
72
|
+
margin-block-end: var(--size-2xs, 0.25rem);
|
|
73
|
+
text-transform: uppercase;
|
|
74
|
+
letter-spacing: 0.05em;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
[data-list="pro-con"] > [data-con]::before {
|
|
78
|
+
content: "Con";
|
|
79
|
+
display: block;
|
|
80
|
+
font-weight: 700;
|
|
81
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
82
|
+
color: var(--color-error, oklch(45% 0.22 25));
|
|
83
|
+
margin-block-end: var(--size-2xs, 0.25rem);
|
|
84
|
+
text-transform: uppercase;
|
|
85
|
+
letter-spacing: 0.05em;
|
|
86
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design System Token Table
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* <table class="ds-token-table">
|
|
6
|
+
* <thead><tr><th>Token</th><th>Preview</th><th>Value</th></tr></thead>
|
|
7
|
+
* <tbody>
|
|
8
|
+
* <tr>
|
|
9
|
+
* <td><code>--color-primary</code></td>
|
|
10
|
+
* <td><token-swatch data-preview="var(--color-primary)"></token-swatch></td>
|
|
11
|
+
* <td>oklch(50% 0.2 260)</td>
|
|
12
|
+
* </tr>
|
|
13
|
+
* </tbody>
|
|
14
|
+
* </table>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
.ds-token-table {
|
|
18
|
+
width: 100%;
|
|
19
|
+
border-collapse: collapse;
|
|
20
|
+
font-size: var(--font-size-s, 0.875rem);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.ds-token-table thead {
|
|
24
|
+
border-block-end: 2px solid var(--color-border, #ddd);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.ds-token-table th {
|
|
28
|
+
text-align: start;
|
|
29
|
+
padding: var(--size-xs, 0.25rem) var(--size-s, 0.5rem);
|
|
30
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
31
|
+
font-weight: 700;
|
|
32
|
+
text-transform: uppercase;
|
|
33
|
+
letter-spacing: 0.05em;
|
|
34
|
+
color: var(--color-text-muted, #666);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.ds-token-table td {
|
|
38
|
+
padding: var(--size-xs, 0.25rem) var(--size-s, 0.5rem);
|
|
39
|
+
border-block-end: 1px solid var(--color-border, #eee);
|
|
40
|
+
vertical-align: middle;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ds-token-table code {
|
|
44
|
+
font-family: var(--font-mono, monospace);
|
|
45
|
+
font-size: var(--font-size-xs, 0.75rem);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Inline swatch preview in table cells */
|
|
49
|
+
.ds-token-table .ds-swatch {
|
|
50
|
+
display: inline-block;
|
|
51
|
+
width: 2.5rem;
|
|
52
|
+
height: 1.5rem;
|
|
53
|
+
border-radius: var(--radius-s, 0.25rem);
|
|
54
|
+
border: 1px solid var(--color-border, #ddd);
|
|
55
|
+
vertical-align: middle;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Also support token-swatch with proper child markup */
|
|
59
|
+
.ds-token-table token-swatch {
|
|
60
|
+
display: inline-flex;
|
|
61
|
+
}
|
|
62
|
+
.ds-token-table token-swatch > [data-preview] {
|
|
63
|
+
width: 2.5rem;
|
|
64
|
+
height: 1.5rem;
|
|
65
|
+
border-radius: var(--radius-s, 0.25rem);
|
|
66
|
+
border: 1px solid var(--color-border, #ddd);
|
|
67
|
+
}
|