@hemerson/design-system 0.1.0 → 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.
- package/README.md +13 -0
- package/dist/enableGlassRefraction-CgDeg-2E.js +88 -0
- package/dist/enableGlassRefraction-CgDeg-2E.js.map +1 -0
- package/dist/glass/enableGlassRefraction.d.ts +6 -5
- package/dist/glass/index.d.ts +1 -0
- package/dist/glass/lens.d.ts +15 -0
- package/dist/glass.js +1 -0
- package/dist/index.js +211 -257
- package/dist/index.js.map +1 -1
- package/dist/styles.css +76 -28
- package/dist/tokens.css +16 -10
- package/dist/tokens.json +39 -15
- package/package.json +11 -2
package/README.md
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
# Hemerson Design System
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@hemerson/design-system)
|
|
4
|
+
[](https://github.com/hemerson-git/hemerson-design-system/actions/workflows/ci.yml)
|
|
5
|
+
[](https://hemerson-git.github.io/hemerson-design-system/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
3
8
|
A dark-first design system with a sage-teal accent and liquid-glass navigation, built for React. It ships design tokens for a dark and a light theme, a stylesheet, and React components with a Storybook to browse them.
|
|
4
9
|
|
|
10
|
+
**[Browse the components in Storybook →](https://hemerson-git.github.io/hemerson-design-system/)**
|
|
11
|
+
|
|
5
12
|
## Install
|
|
6
13
|
|
|
7
14
|
```bash
|
|
@@ -21,6 +28,7 @@ export function Toolbar() {
|
|
|
21
28
|
|
|
22
29
|
- **Themes:** set `data-theme="dark"` (the default) or `data-theme="light"` on `<html>`.
|
|
23
30
|
- **Reduced transparency:** set `data-transparency="reduced"` on `<html>` to turn every glass surface solid. Offer it as a setting in your app.
|
|
31
|
+
- **Edge lens:** call `enableGlassRefraction()` from `@hemerson/design-system/glass` once at startup to bend the content at the glass edges in Chromium. Other browsers keep frosted glass.
|
|
24
32
|
- **Fonts:** `styles.css` loads Raleway and JetBrains Mono from Google Fonts. To self-host them, import `tokens.css` and your own font files instead.
|
|
25
33
|
|
|
26
34
|
## What's inside
|
|
@@ -28,6 +36,7 @@ export function Toolbar() {
|
|
|
28
36
|
| Export | Contents |
|
|
29
37
|
| --- | --- |
|
|
30
38
|
| `@hemerson/design-system` | React components |
|
|
39
|
+
| `@hemerson/design-system/glass` | `enableGlassRefraction()`, the Chromium edge lens, without React |
|
|
31
40
|
| `@hemerson/design-system/styles.css` | Fonts, tokens and component styles |
|
|
32
41
|
| `@hemerson/design-system/tokens.css` | CSS custom properties for both themes |
|
|
33
42
|
| `@hemerson/design-system/tokens.json` | The tokens as data |
|
|
@@ -46,6 +55,10 @@ npm run build-storybook
|
|
|
46
55
|
|
|
47
56
|
Tokens live in [`tokens/tokens.json`](tokens/tokens.json); `npm run tokens` turns them into `src/styles/tokens.css`. Each component lives in `src/components/<Name>/` with its stories and tests.
|
|
48
57
|
|
|
58
|
+
## Releases
|
|
59
|
+
|
|
60
|
+
Versions follow [semver](https://semver.org) and are managed with [Changesets](https://github.com/changesets/changesets). Every change to the package comes with a changeset (`npx changeset`). Merging to `master` opens a "version packages" pull request that bumps the version and updates the [changelog](CHANGELOG.md); merging that pull request publishes to npm from GitHub Actions. Storybook redeploys on every push to `master`.
|
|
61
|
+
|
|
49
62
|
## Contributing
|
|
50
63
|
|
|
51
64
|
Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for how to set up the project and how contributors are credited.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//#region src/glass/lens.ts
|
|
2
|
+
function e(e, t, n, r) {
|
|
3
|
+
let i = new Uint8ClampedArray(e * t * 4), a = Math.max(0, Math.min(n, e / 2, t / 2));
|
|
4
|
+
for (let n = 0; n < t; n++) for (let o = 0; o < e; o++) {
|
|
5
|
+
let s = o + .5 - e / 2, c = n + .5 - t / 2, l = Math.abs(s) - (e / 2 - a), u = Math.abs(c) - (t / 2 - a), d, f = 0, p = 0;
|
|
6
|
+
if (l > 0 && u > 0) {
|
|
7
|
+
let e = Math.hypot(l, u);
|
|
8
|
+
d = a - e, f = l / e * Math.sign(s), p = u / e * Math.sign(c);
|
|
9
|
+
} else l > u ? (d = e / 2 - Math.abs(s), f = Math.sign(s)) : (d = t / 2 - Math.abs(c), p = Math.sign(c));
|
|
10
|
+
let m = Math.max(0, 1 - d / r), h = m * m, g = (n * e + o) * 4;
|
|
11
|
+
i[g] = 128 - f * h * 127, i[g + 1] = 128 - p * h * 127, i[g + 2] = 128, i[g + 3] = 255;
|
|
12
|
+
}
|
|
13
|
+
return i;
|
|
14
|
+
}
|
|
15
|
+
function t(e) {
|
|
16
|
+
let t = Math.max(4, Math.min(16, e / 3)), n = t * .45;
|
|
17
|
+
return {
|
|
18
|
+
rim: t,
|
|
19
|
+
maxShift: n,
|
|
20
|
+
scale: n / (127 / 255)
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/glass/enableGlassRefraction.ts
|
|
25
|
+
var n = "http://www.w3.org/2000/svg", r = ".hds-glass:not(.hds-glass--thick)", i = null, a = /* @__PURE__ */ new Map();
|
|
26
|
+
function o() {
|
|
27
|
+
return (navigator.userAgentData?.brands ?? []).some(({ brand: e }) => e.includes("Chromium"));
|
|
28
|
+
}
|
|
29
|
+
function s() {
|
|
30
|
+
return i?.isConnected || (i = document.createElementNS(n, "svg"), i.setAttribute("id", "hds-glass-defs"), i.setAttribute("width", "0"), i.setAttribute("height", "0"), i.setAttribute("aria-hidden", "true"), i.style.position = "absolute", document.body.appendChild(i)), i;
|
|
31
|
+
}
|
|
32
|
+
function c(r, i, o) {
|
|
33
|
+
let c = `${r}x${i}r${o}`, l = a.get(c);
|
|
34
|
+
if (l) return l;
|
|
35
|
+
let u = document.createElement("canvas");
|
|
36
|
+
u.width = r, u.height = i;
|
|
37
|
+
let d = u.getContext("2d");
|
|
38
|
+
if (!d) return null;
|
|
39
|
+
let { rim: f, scale: p } = t(i), m = d.createImageData(r, i);
|
|
40
|
+
m.data.set(e(r, i, o, f)), d.putImageData(m, 0, 0);
|
|
41
|
+
let h = `hds-glass-lens-${a.size}`, g = document.createElementNS(n, "filter");
|
|
42
|
+
Object.entries({
|
|
43
|
+
id: h,
|
|
44
|
+
x: "0",
|
|
45
|
+
y: "0",
|
|
46
|
+
width: String(r),
|
|
47
|
+
height: String(i),
|
|
48
|
+
filterUnits: "userSpaceOnUse",
|
|
49
|
+
"color-interpolation-filters": "sRGB"
|
|
50
|
+
}).forEach(([e, t]) => g.setAttribute(e, t));
|
|
51
|
+
let _ = document.createElementNS(n, "feImage");
|
|
52
|
+
_.setAttribute("href", u.toDataURL()), _.setAttribute("x", "0"), _.setAttribute("y", "0"), _.setAttribute("width", String(r)), _.setAttribute("height", String(i)), _.setAttribute("result", "map");
|
|
53
|
+
let v = document.createElementNS(n, "feDisplacementMap");
|
|
54
|
+
return v.setAttribute("in", "SourceGraphic"), v.setAttribute("in2", "map"), v.setAttribute("scale", p.toFixed(2)), v.setAttribute("xChannelSelector", "R"), v.setAttribute("yChannelSelector", "G"), g.append(_, v), s().appendChild(g), a.set(c, h), h;
|
|
55
|
+
}
|
|
56
|
+
function l(e) {
|
|
57
|
+
let t = Math.round(e.offsetWidth), n = Math.round(e.offsetHeight);
|
|
58
|
+
if (t < 8 || n < 8) return;
|
|
59
|
+
let r = parseFloat(getComputedStyle(e).borderTopLeftRadius) || 0, i = c(t, n, Math.min(r, n / 2));
|
|
60
|
+
i && e.style.setProperty("--hds-glass-lens", `url(#${i})`);
|
|
61
|
+
}
|
|
62
|
+
var u = !1;
|
|
63
|
+
function d() {
|
|
64
|
+
if (typeof document > "u") return !1;
|
|
65
|
+
let e = window.matchMedia?.("(prefers-reduced-transparency: reduce)").matches ?? !1;
|
|
66
|
+
if (!o() || e) return !1;
|
|
67
|
+
if (u) return !0;
|
|
68
|
+
u = !0;
|
|
69
|
+
let t = new ResizeObserver((e) => {
|
|
70
|
+
for (let t of e) l(t.target);
|
|
71
|
+
}), n = (e) => {
|
|
72
|
+
e.querySelectorAll(r).forEach((e) => {
|
|
73
|
+
l(e), t.observe(e);
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
return n(document), new MutationObserver((e) => {
|
|
77
|
+
for (let i of e) i.addedNodes.forEach((e) => {
|
|
78
|
+
e instanceof HTMLElement && (e.matches(r) && (l(e), t.observe(e)), n(e));
|
|
79
|
+
});
|
|
80
|
+
}).observe(document.body, {
|
|
81
|
+
childList: !0,
|
|
82
|
+
subtree: !0
|
|
83
|
+
}), document.documentElement.setAttribute("data-glass-refraction", ""), !0;
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { d as t };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=enableGlassRefraction-CgDeg-2E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enableGlassRefraction-CgDeg-2E.js","names":["lensDisplacementMap","data","width","height","r","radius","y","x","px","py","qx","qy","distance","nx","ny","length","t","rim","strength","i","lensSettings","maxShift","SVG","GLASS","defs","filters","isChromium","brand","ensureDefs","filterFor","key","existing","canvas","context","image","id","filter","name","value","map","displace","scale","applyLens","element","active","enableGlassRefraction","reducesTransparency","resizeObserver","entry","entries","watch","mutation","mutations","node"],"sources":["../src/glass/lens.ts","../src/glass/enableGlassRefraction.ts"],"sourcesContent":["/**\n * A displacement map for the edge lens: near the rim the backdrop is sampled from further\n * inside the shape, so content appears to bend towards the edge; the middle is untouched.\n *\n * Red holds the horizontal shift and green the vertical one, with 128 meaning \"no shift\".\n * The shift never exceeds `maxShift`, and `maxShift` stays below the rim width, so content\n * is compressed towards the edge but never flipped.\n */\nexport function lensDisplacementMap(width: number, height: number, radius: number, rim: number): Uint8ClampedArray {\n const data = new Uint8ClampedArray(width * height * 4);\n const r = Math.max(0, Math.min(radius, width / 2, height / 2));\n\n for (let y = 0; y < height; y++) {\n for (let x = 0; x < width; x++) {\n // Distance to the edge of the rounded rectangle and the outward normal there\n const px = x + 0.5 - width / 2;\n const py = y + 0.5 - height / 2;\n const qx = Math.abs(px) - (width / 2 - r);\n const qy = Math.abs(py) - (height / 2 - r);\n let distance: number;\n let nx = 0;\n let ny = 0;\n\n if (qx > 0 && qy > 0) {\n const length = Math.hypot(qx, qy);\n distance = r - length;\n nx = (qx / length) * Math.sign(px);\n ny = (qy / length) * Math.sign(py);\n } else if (qx > qy) {\n distance = width / 2 - Math.abs(px);\n nx = Math.sign(px);\n } else {\n distance = height / 2 - Math.abs(py);\n ny = Math.sign(py);\n }\n\n const t = Math.max(0, 1 - distance / rim);\n const strength = t * t;\n const i = (y * width + x) * 4;\n data[i] = 128 - nx * strength * 127;\n data[i + 1] = 128 - ny * strength * 127;\n data[i + 2] = 128;\n data[i + 3] = 255;\n }\n }\n\n return data;\n}\n\n/** Rim width and the filter scale that keep the largest shift at 45% of the rim. */\nexport function lensSettings(height: number) {\n const rim = Math.max(4, Math.min(16, height / 3));\n const maxShift = rim * 0.45;\n // feDisplacementMap moves by scale × (channel / 255 − 0.5); the map uses at most ±127\n const scale = maxShift / (127 / 255);\n return { rim, maxShift, scale };\n}\n","import { lensDisplacementMap, lensSettings } from \"./lens\";\n\nconst SVG = \"http://www.w3.org/2000/svg\";\nconst GLASS = \".hds-glass:not(.hds-glass--thick)\";\n\nlet defs: SVGSVGElement | null = null;\nconst filters = new Map<string, string>();\n\nfunction isChromium() {\n const brands = (navigator as Navigator & { userAgentData?: { brands: { brand: string }[] } }).userAgentData?.brands ?? [];\n return brands.some(({ brand }) => brand.includes(\"Chromium\"));\n}\n\nfunction ensureDefs() {\n if (defs?.isConnected) return defs;\n defs = document.createElementNS(SVG, \"svg\");\n defs.setAttribute(\"id\", \"hds-glass-defs\");\n defs.setAttribute(\"width\", \"0\");\n defs.setAttribute(\"height\", \"0\");\n defs.setAttribute(\"aria-hidden\", \"true\");\n defs.style.position = \"absolute\";\n document.body.appendChild(defs);\n return defs;\n}\n\n/** One SVG filter per element size and corner radius, shared by elements that match. */\nfunction filterFor(width: number, height: number, radius: number): string | null {\n const key = `${width}x${height}r${radius}`;\n const existing = filters.get(key);\n if (existing) return existing;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n const context = canvas.getContext(\"2d\");\n if (!context) return null;\n\n const { rim, scale } = lensSettings(height);\n const image = context.createImageData(width, height);\n image.data.set(lensDisplacementMap(width, height, radius, rim));\n context.putImageData(image, 0, 0);\n\n const id = `hds-glass-lens-${filters.size}`;\n const filter = document.createElementNS(SVG, \"filter\");\n const attributes: Record<string, string> = {\n id,\n x: \"0\",\n y: \"0\",\n width: String(width),\n height: String(height),\n filterUnits: \"userSpaceOnUse\",\n \"color-interpolation-filters\": \"sRGB\",\n };\n Object.entries(attributes).forEach(([name, value]) => filter.setAttribute(name, value));\n\n const map = document.createElementNS(SVG, \"feImage\");\n map.setAttribute(\"href\", canvas.toDataURL());\n map.setAttribute(\"x\", \"0\");\n map.setAttribute(\"y\", \"0\");\n map.setAttribute(\"width\", String(width));\n map.setAttribute(\"height\", String(height));\n map.setAttribute(\"result\", \"map\");\n\n const displace = document.createElementNS(SVG, \"feDisplacementMap\");\n displace.setAttribute(\"in\", \"SourceGraphic\");\n displace.setAttribute(\"in2\", \"map\");\n displace.setAttribute(\"scale\", scale.toFixed(2));\n displace.setAttribute(\"xChannelSelector\", \"R\");\n displace.setAttribute(\"yChannelSelector\", \"G\");\n\n filter.append(map, displace);\n ensureDefs().appendChild(filter);\n filters.set(key, id);\n return id;\n}\n\nfunction applyLens(element: HTMLElement) {\n const width = Math.round(element.offsetWidth);\n const height = Math.round(element.offsetHeight);\n if (width < 8 || height < 8) return;\n\n const radius = parseFloat(getComputedStyle(element).borderTopLeftRadius) || 0;\n const id = filterFor(width, height, Math.min(radius, height / 2));\n if (id) element.style.setProperty(\"--hds-glass-lens\", `url(#${id})`);\n}\n\nlet active = false;\n\n/**\n * Turns on the edge lens: glass bends the backdrop near its rim, like Apple's Liquid Glass.\n * Every glass element present now or added later gets a lens sized to it.\n *\n * Only Chromium renders SVG filters in backdrop-filter. Firefox accepts them and then\n * drops the whole backdrop-filter, blur included, so other browsers keep plain frosted\n * glass. Nothing happens when the user reduces transparency.\n * Returns whether the lens was turned on.\n */\nexport function enableGlassRefraction(): boolean {\n if (typeof document === \"undefined\") return false;\n\n const reducesTransparency = window.matchMedia?.(\"(prefers-reduced-transparency: reduce)\").matches ?? false;\n if (!isChromium() || reducesTransparency) return false;\n if (active) return true;\n active = true;\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) applyLens(entry.target as HTMLElement);\n });\n const watch = (root: ParentNode) => {\n root.querySelectorAll<HTMLElement>(GLASS).forEach((element) => {\n applyLens(element);\n resizeObserver.observe(element);\n });\n };\n\n watch(document);\n new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n mutation.addedNodes.forEach((node) => {\n if (!(node instanceof HTMLElement)) return;\n if (node.matches(GLASS)) {\n applyLens(node);\n resizeObserver.observe(node);\n }\n watch(node);\n });\n }\n }).observe(document.body, { childList: true, subtree: true });\n\n document.documentElement.setAttribute(\"data-glass-refraction\", \"\");\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Turns on the edge lens: glass bends the backdrop near its rim, like Apple's Liquid Glass.
|
|
3
|
+
* Every glass element present now or added later gets a lens sized to it.
|
|
4
4
|
*
|
|
5
|
-
* Only Chromium renders
|
|
6
|
-
* drops the whole backdrop-filter, blur included, so other browsers
|
|
7
|
-
*
|
|
5
|
+
* Only Chromium renders SVG filters in backdrop-filter. Firefox accepts them and then
|
|
6
|
+
* drops the whole backdrop-filter, blur included, so other browsers keep plain frosted
|
|
7
|
+
* glass. Nothing happens when the user reduces transparency.
|
|
8
|
+
* Returns whether the lens was turned on.
|
|
8
9
|
*/
|
|
9
10
|
export declare function enableGlassRefraction(): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { enableGlassRefraction } from "./enableGlassRefraction";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A displacement map for the edge lens: near the rim the backdrop is sampled from further
|
|
3
|
+
* inside the shape, so content appears to bend towards the edge; the middle is untouched.
|
|
4
|
+
*
|
|
5
|
+
* Red holds the horizontal shift and green the vertical one, with 128 meaning "no shift".
|
|
6
|
+
* The shift never exceeds `maxShift`, and `maxShift` stays below the rim width, so content
|
|
7
|
+
* is compressed towards the edge but never flipped.
|
|
8
|
+
*/
|
|
9
|
+
export declare function lensDisplacementMap(width: number, height: number, radius: number, rim: number): Uint8ClampedArray;
|
|
10
|
+
/** Rim width and the filter scale that keep the largest shift at 45% of the rim. */
|
|
11
|
+
export declare function lensSettings(height: number): {
|
|
12
|
+
rim: number;
|
|
13
|
+
maxShift: number;
|
|
14
|
+
scale: number;
|
|
15
|
+
};
|
package/dist/glass.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { t as enableGlassRefraction } from "./enableGlassRefraction-CgDeg-2E.js";
|