@hanzo/ui 8.17.0 → 8.17.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/dist/gallery.html +114 -1
- package/dist/glass.cjs +47 -1
- package/dist/glass.css +67 -0
- package/dist/glass.d.ts +71 -0
- package/dist/glass.d.ts.map +1 -1
- package/dist/glass.js +43 -0
- package/dist/glass.js.map +1 -1
- package/dist/styles/motion.css +46 -0
- package/dist/styles.css +113 -0
- package/dist/theme.css +67 -0
- package/package.json +1 -1
package/dist/gallery.html
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!doctype html><html lang="en" class="t_dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>@hanzo/ui 8.17.
|
|
1
|
+
<!doctype html><html lang="en" class="t_dark"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>@hanzo/ui 8.17.1</title><style>/* @hanzo/ui — generated by scripts/gen-css.mjs. Do not edit. */
|
|
2
2
|
:root { --hanzo-ui-styles: 1; }
|
|
3
3
|
/* Hanzo Design System — the entry point. Import THIS one file.
|
|
4
4
|
*
|
|
@@ -1725,6 +1725,73 @@
|
|
|
1725
1725
|
border-bottom-right-radius: 0 !important;
|
|
1726
1726
|
}
|
|
1727
1727
|
|
|
1728
|
+
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
1729
|
+
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
1730
|
+
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
1731
|
+
offset. That is right, and it means the ladder has nothing to say about a
|
|
1732
|
+
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
1733
|
+
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
1734
|
+
abutting rectangles with lines ruled between them, because the only mark at
|
|
1735
|
+
the seam is the hairline.
|
|
1736
|
+
|
|
1737
|
+
What a real sheet lays on the one beneath it, side by side under a light from
|
|
1738
|
+
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
1739
|
+
has no direction of its own, which is both why it is honest here and why it is
|
|
1740
|
+
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
1741
|
+
not one.
|
|
1742
|
+
|
|
1743
|
+
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
1744
|
+
paints above the sheet's own fill and below every child. That ordering is the
|
|
1745
|
+
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
1746
|
+
this same element, !important, so the two would silently fight) and not an
|
|
1747
|
+
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
1748
|
+
|
|
1749
|
+
No side named -> both edges, which is what a pane with a neighbour on each
|
|
1750
|
+
hand needs. Name one and the other stops being drawn. */
|
|
1751
|
+
:root {
|
|
1752
|
+
--crease-ink: rgb(0 0 0 / .28);
|
|
1753
|
+
--crease-depth: 20px;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
.light, :root.t_light, .t_light {
|
|
1757
|
+
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
1758
|
+
drops make, and for the same reason. */
|
|
1759
|
+
--crease-ink: rgb(0 0 0 / .05);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.hz-crease {
|
|
1763
|
+
position: relative;
|
|
1764
|
+
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
1765
|
+
indistinguishable from the crease not being there at all. */
|
|
1766
|
+
isolation: isolate;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
.hz-crease::before,
|
|
1770
|
+
.hz-crease::after {
|
|
1771
|
+
content: "";
|
|
1772
|
+
position: absolute;
|
|
1773
|
+
top: 0;
|
|
1774
|
+
bottom: 0;
|
|
1775
|
+
width: var(--crease-depth);
|
|
1776
|
+
z-index: -1;
|
|
1777
|
+
pointer-events: none;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
.hz-crease::before {
|
|
1781
|
+
left: 0;
|
|
1782
|
+
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
.hz-crease::after {
|
|
1786
|
+
right: 0;
|
|
1787
|
+
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
.hz-crease[data-crease="left"]::after,
|
|
1791
|
+
.hz-crease[data-crease="right"]::before {
|
|
1792
|
+
content: none;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1728
1795
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
1729
1796
|
The dim that makes a floating panel read as floating rather than as more
|
|
1730
1797
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
|
@@ -2370,6 +2437,52 @@ body {
|
|
|
2370
2437
|
}
|
|
2371
2438
|
}
|
|
2372
2439
|
|
|
2440
|
+
/* ── Unfold — how a sheet arrives ─────────────────────────────────────────────
|
|
2441
|
+
A panel that appears by fading is a rectangle switching on. A sheet of paper
|
|
2442
|
+
arrives by TURNING OPEN about the edge it is hinged on, so its near edge swings
|
|
2443
|
+
toward the reader and its far edge stays put — which is the one motion that
|
|
2444
|
+
says "this was already here, folded" rather than "this was drawn just now".
|
|
2445
|
+
|
|
2446
|
+
The hinge is the ONLY thing that varies, so it is the only knob: a drawer
|
|
2447
|
+
coming off the left wall turns about its left edge, a pane folding in from the
|
|
2448
|
+
right about its right. The angle follows the hinge — a sheet swings toward you
|
|
2449
|
+
from whichever side it is held — so naming the hinge sets both, and there is no
|
|
2450
|
+
way to ask for a turn that opens the wrong way.
|
|
2451
|
+
|
|
2452
|
+
`perspective()` inside the transform rather than on a parent: the vanishing
|
|
2453
|
+
point is then the sheet's own centre, so the turn reads at any size and the
|
|
2454
|
+
caller does not have to own a 3D context it did not ask for.
|
|
2455
|
+
|
|
2456
|
+
Seven degrees over 220ms. Enough to see the plane; short of the swinging-door
|
|
2457
|
+
effect that makes a workspace feel like a slideshow. */
|
|
2458
|
+
@keyframes hz-unfold {
|
|
2459
|
+
from {
|
|
2460
|
+
opacity: 0;
|
|
2461
|
+
transform: perspective(1600px) rotateY(var(--hz-turn, -7deg));
|
|
2462
|
+
}
|
|
2463
|
+
to {
|
|
2464
|
+
opacity: 1;
|
|
2465
|
+
transform: perspective(1600px) rotateY(0deg);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
.hz-unfold {
|
|
2470
|
+
animation: hz-unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
2471
|
+
transform-origin: left center;
|
|
2472
|
+
will-change: transform, opacity;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
.hz-unfold[data-hinge="right"] {
|
|
2476
|
+
transform-origin: right center;
|
|
2477
|
+
--hz-turn: 7deg;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2481
|
+
.hz-unfold {
|
|
2482
|
+
animation: none;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2373
2486
|
/* ── Layout guarantees ─────────────────────────────────────────────────────────
|
|
2374
2487
|
Two rules, both structural. They are attached to `data-slot` rather than to a
|
|
2375
2488
|
class because they are not styling a caller can opt out of — they are the
|
package/dist/glass.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.screen = exports.accent = exports.selected = exports.row = exports.rows = exports.panel = exports.scrim = exports.fold = exports.sheet = exports.glass = void 0;
|
|
3
|
+
exports.screen = exports.accent = exports.selected = exports.row = exports.rows = exports.panel = exports.scrim = exports.fold = exports.unfold = exports.crease = exports.sheet = exports.glass = void 0;
|
|
4
|
+
exports.paper = paper;
|
|
4
5
|
/**
|
|
5
6
|
* The chrome, as values — `@hanzo/ui/glass`.
|
|
6
7
|
*
|
|
@@ -107,6 +108,51 @@ const SHEET_FILL = {
|
|
|
107
108
|
1: 'var(--sheet-1, rgb(38 38 38 / .5))',
|
|
108
109
|
2: 'var(--sheet-2, rgb(38 38 38 / .75))',
|
|
109
110
|
};
|
|
111
|
+
/**
|
|
112
|
+
* The crease — the valley where a neighbouring sheet lies over this one.
|
|
113
|
+
*
|
|
114
|
+
* <YStack {...paper(sheet(0), crease('right'))}>
|
|
115
|
+
*
|
|
116
|
+
* The ladder's drops fall straight down (design's rule is one light, above), so
|
|
117
|
+
* it has nothing to say about a VERTICAL seam — and an app shell is nothing but
|
|
118
|
+
* vertical seams. Three sheets a rung apart, side by side, still read as three
|
|
119
|
+
* abutting rectangles. This is the mark that makes them read as paper: the
|
|
120
|
+
* ground going dark in the valley, which is what a sheet actually lays on the
|
|
121
|
+
* one beside it.
|
|
122
|
+
*
|
|
123
|
+
* It goes on the sheet that is COVERED, on the edge the neighbour lies over —
|
|
124
|
+
* a rail with a sidebar to its right takes `crease('right')`. Nothing can paint
|
|
125
|
+
* outside its own box, so the receiver draws it; the caster only has to be
|
|
126
|
+
* higher up the ladder.
|
|
127
|
+
*
|
|
128
|
+
* Spend it at a seam and nowhere else. A crease down the side of a card with
|
|
129
|
+
* nothing beside it is a gradient somebody liked.
|
|
130
|
+
*/
|
|
131
|
+
const crease = (edge) => ({ className: 'hz-crease', ...(edge ? { 'data-crease': edge } : {}) });
|
|
132
|
+
exports.crease = crease;
|
|
133
|
+
/**
|
|
134
|
+
* Unfold — how a sheet ARRIVES: turning open about the edge it is hinged on,
|
|
135
|
+
* rather than fading up as a rectangle.
|
|
136
|
+
*
|
|
137
|
+
* <YStack {...paper(sheet(2), unfold('right'))}>
|
|
138
|
+
*
|
|
139
|
+
* The hinge is the only knob, and it sets the direction of the turn with it, so
|
|
140
|
+
* a sheet cannot be asked to swing the wrong way. A drawer off the left wall is
|
|
141
|
+
* `unfold()`; a pane folding in from the right edge is `unfold('right')`.
|
|
142
|
+
*
|
|
143
|
+
* Motion only — it says nothing about what the surface is made of, so it
|
|
144
|
+
* composes with `sheet`, `glass` or neither. Off under reduced motion, in
|
|
145
|
+
* `styles/motion.css` beside every other keyframe this package ships.
|
|
146
|
+
*/
|
|
147
|
+
const unfold = (hinge = 'left') => ({ className: 'hz-unfold', ...(hinge === 'right' ? { 'data-hinge': 'right' } : {}) });
|
|
148
|
+
exports.unfold = unfold;
|
|
149
|
+
function paper(...marks) {
|
|
150
|
+
const className = marks
|
|
151
|
+
.map((mark) => mark.className)
|
|
152
|
+
.filter(Boolean)
|
|
153
|
+
.join(' ');
|
|
154
|
+
return { ...Object.assign({}, ...marks), ...(className ? { className } : {}) };
|
|
155
|
+
}
|
|
110
156
|
/**
|
|
111
157
|
* The fold — a corner turned back, and the ONE mark that says an item opens.
|
|
112
158
|
*
|
package/dist/glass.css
CHANGED
|
@@ -244,6 +244,73 @@
|
|
|
244
244
|
border-bottom-right-radius: 0 !important;
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
+
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
248
|
+
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
249
|
+
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
250
|
+
offset. That is right, and it means the ladder has nothing to say about a
|
|
251
|
+
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
252
|
+
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
253
|
+
abutting rectangles with lines ruled between them, because the only mark at
|
|
254
|
+
the seam is the hairline.
|
|
255
|
+
|
|
256
|
+
What a real sheet lays on the one beneath it, side by side under a light from
|
|
257
|
+
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
258
|
+
has no direction of its own, which is both why it is honest here and why it is
|
|
259
|
+
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
260
|
+
not one.
|
|
261
|
+
|
|
262
|
+
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
263
|
+
paints above the sheet's own fill and below every child. That ordering is the
|
|
264
|
+
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
265
|
+
this same element, !important, so the two would silently fight) and not an
|
|
266
|
+
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
267
|
+
|
|
268
|
+
No side named -> both edges, which is what a pane with a neighbour on each
|
|
269
|
+
hand needs. Name one and the other stops being drawn. */
|
|
270
|
+
:root {
|
|
271
|
+
--crease-ink: rgb(0 0 0 / .28);
|
|
272
|
+
--crease-depth: 20px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.light, :root.t_light, .t_light {
|
|
276
|
+
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
277
|
+
drops make, and for the same reason. */
|
|
278
|
+
--crease-ink: rgb(0 0 0 / .05);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.hz-crease {
|
|
282
|
+
position: relative;
|
|
283
|
+
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
284
|
+
indistinguishable from the crease not being there at all. */
|
|
285
|
+
isolation: isolate;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.hz-crease::before,
|
|
289
|
+
.hz-crease::after {
|
|
290
|
+
content: "";
|
|
291
|
+
position: absolute;
|
|
292
|
+
top: 0;
|
|
293
|
+
bottom: 0;
|
|
294
|
+
width: var(--crease-depth);
|
|
295
|
+
z-index: -1;
|
|
296
|
+
pointer-events: none;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.hz-crease::before {
|
|
300
|
+
left: 0;
|
|
301
|
+
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.hz-crease::after {
|
|
305
|
+
right: 0;
|
|
306
|
+
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.hz-crease[data-crease="left"]::after,
|
|
310
|
+
.hz-crease[data-crease="right"]::before {
|
|
311
|
+
content: none;
|
|
312
|
+
}
|
|
313
|
+
|
|
247
314
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
248
315
|
The dim that makes a floating panel read as floating rather than as more
|
|
249
316
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
package/dist/glass.d.ts
CHANGED
|
@@ -75,6 +75,76 @@ export declare const sheet: (level?: 0 | 1 | 2) => {
|
|
|
75
75
|
readonly backgroundColor: "var(--sheet-0, #0a0a0a)" | "var(--sheet-1, rgb(38 38 38 / .5))" | "var(--sheet-2, rgb(38 38 38 / .75))";
|
|
76
76
|
readonly className?: "elevation-1" | "elevation-2" | undefined;
|
|
77
77
|
};
|
|
78
|
+
/**
|
|
79
|
+
* Which of a surface's edges lies UNDER a neighbour. Omit for both, which is
|
|
80
|
+
* what a pane between two other panes needs.
|
|
81
|
+
*/
|
|
82
|
+
export type Edge = 'left' | 'right';
|
|
83
|
+
/**
|
|
84
|
+
* The crease — the valley where a neighbouring sheet lies over this one.
|
|
85
|
+
*
|
|
86
|
+
* <YStack {...paper(sheet(0), crease('right'))}>
|
|
87
|
+
*
|
|
88
|
+
* The ladder's drops fall straight down (design's rule is one light, above), so
|
|
89
|
+
* it has nothing to say about a VERTICAL seam — and an app shell is nothing but
|
|
90
|
+
* vertical seams. Three sheets a rung apart, side by side, still read as three
|
|
91
|
+
* abutting rectangles. This is the mark that makes them read as paper: the
|
|
92
|
+
* ground going dark in the valley, which is what a sheet actually lays on the
|
|
93
|
+
* one beside it.
|
|
94
|
+
*
|
|
95
|
+
* It goes on the sheet that is COVERED, on the edge the neighbour lies over —
|
|
96
|
+
* a rail with a sidebar to its right takes `crease('right')`. Nothing can paint
|
|
97
|
+
* outside its own box, so the receiver draws it; the caster only has to be
|
|
98
|
+
* higher up the ladder.
|
|
99
|
+
*
|
|
100
|
+
* Spend it at a seam and nowhere else. A crease down the side of a card with
|
|
101
|
+
* nothing beside it is a gradient somebody liked.
|
|
102
|
+
*/
|
|
103
|
+
export declare const crease: (edge?: Edge) => {
|
|
104
|
+
readonly className: 'hz-crease';
|
|
105
|
+
readonly 'data-crease'?: Edge | undefined;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Unfold — how a sheet ARRIVES: turning open about the edge it is hinged on,
|
|
109
|
+
* rather than fading up as a rectangle.
|
|
110
|
+
*
|
|
111
|
+
* <YStack {...paper(sheet(2), unfold('right'))}>
|
|
112
|
+
*
|
|
113
|
+
* The hinge is the only knob, and it sets the direction of the turn with it, so
|
|
114
|
+
* a sheet cannot be asked to swing the wrong way. A drawer off the left wall is
|
|
115
|
+
* `unfold()`; a pane folding in from the right edge is `unfold('right')`.
|
|
116
|
+
*
|
|
117
|
+
* Motion only — it says nothing about what the surface is made of, so it
|
|
118
|
+
* composes with `sheet`, `glass` or neither. Off under reduced motion, in
|
|
119
|
+
* `styles/motion.css` beside every other keyframe this package ships.
|
|
120
|
+
*/
|
|
121
|
+
export declare const unfold: (hinge?: Edge) => {
|
|
122
|
+
readonly className: 'hz-unfold';
|
|
123
|
+
readonly 'data-hinge'?: string | undefined;
|
|
124
|
+
};
|
|
125
|
+
interface Mark {
|
|
126
|
+
className?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Compose marks onto one surface, without losing a class.
|
|
130
|
+
*
|
|
131
|
+
* <YStack {...paper(sheet(1), crease('left'), fold)}>
|
|
132
|
+
*
|
|
133
|
+
* SPREADING TWO RECIPES SILENTLY DROPS ONE. `{...sheet(1)} {...fold}` — the
|
|
134
|
+
* composition `fold`'s own documentation shows — keeps only the last
|
|
135
|
+
* `className`, so the sheet arrives with its fill and its fold and WITHOUT
|
|
136
|
+
* `elevation-1`: the surface is a shade lighter than the page and flat, which
|
|
137
|
+
* looks like a design decision rather than a lost property. JSX assigns whole
|
|
138
|
+
* keys, and `className` is one key; this repo already records the same shape
|
|
139
|
+
* costing a breakpoint object.
|
|
140
|
+
*
|
|
141
|
+
* So marks are composed through here rather than beside each other. Every other
|
|
142
|
+
* key still takes the last writer, which is what a caller means by ordering
|
|
143
|
+
* them; only the class list accumulates.
|
|
144
|
+
*/
|
|
145
|
+
export declare function paper<A extends Mark>(a: A): A;
|
|
146
|
+
export declare function paper<A extends Mark, B extends Mark>(a: A, b: B): A & B;
|
|
147
|
+
export declare function paper<A extends Mark, B extends Mark, C extends Mark>(a: A, b: B, c: C): A & B & C;
|
|
78
148
|
/**
|
|
79
149
|
* The fold — a corner turned back, and the ONE mark that says an item opens.
|
|
80
150
|
*
|
|
@@ -289,4 +359,5 @@ export declare const screen: {
|
|
|
289
359
|
readonly alignItems: 'center';
|
|
290
360
|
readonly justifyContent: 'center';
|
|
291
361
|
};
|
|
362
|
+
export {};
|
|
292
363
|
//# sourceMappingURL=glass.d.ts.map
|
package/dist/glass.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glass.d.ts","sourceRoot":"","sources":["../src/glass.ts"],"names":[],"mappings":"AA8BA;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,KAAK,WAAW,IAAI;aAE7B,SAAS;aACT,eAAe,EAAE,aAAa;aAC9B,WAAW,EAAE,cAAc;CAClB,CAAA;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,KAAK,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;;;CAIzB,CAAA;AAQb;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,IAAI;aAAK,SAAS,EAAE,MAAM;CAAW,CAAA;AAElD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK;aAAK,eAAe,EAAE,uCAAuC;CAAW,CAAA;AAE1F;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,KAAK;aAChB,eAAe,EAAE,SAAS;aAC1B,WAAW,EAAE,CAAC;aACd,WAAW,EAAE,cAAc;aAC3B,YAAY,EAAE,IAAI;aAClB,SAAS,EAAE,aAAa;CAChB,CAAA;AAEV;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,IAAI;8BAxBE,SAAS;0BACb,CAAC;0BACD,cAAc;2BACb,IAAI;wBACP,aAAa;uBAuBd,QAAQ;CACV,CAAA;AAEV;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,GAAG;aACd,aAAa,EAAE,KAAK;aACpB,UAAU,EAAE,QAAQ;aACpB,cAAc,EAAE,eAAe;aAC/B,GAAG,EAAE,IAAI;aACT,iBAAiB,EAAE,IAAI;aACvB,eAAe,EAAE,IAAI;CACb,CAAA;AAEV;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,QAAQ,OAAQ,OAAO;8BAEV,SAAS;oBAAS,UAAU;;8BAC5B,aAAa;oBAAS,UAAU;CAAY,CAAA;AAEtE;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,MAAM;aACjB,eAAe,EAAE,SAAS;aAC1B,WAAW,EAAE,CAAC;aACd,WAAW,EAAE,SAAS;IACtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;aACH,KAAK,EAAE,UAAU;aACjB,UAAU;iBAAI,eAAe,EAAE,SAAS;iBAAE,KAAK,EAAE,UAAU;;CACnD,CAAA;AAEV;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,MAAM;aACjB,SAAS,EAAE,QAAQ;aACnB,UAAU,EAAE,QAAQ;aACpB,cAAc,EAAE,QAAQ;CAChB,CAAA"}
|
|
1
|
+
{"version":3,"file":"glass.d.ts","sourceRoot":"","sources":["../src/glass.ts"],"names":[],"mappings":"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"}
|
package/dist/glass.js
CHANGED
|
@@ -102,6 +102,49 @@ const SHEET_FILL = {
|
|
|
102
102
|
1: 'var(--sheet-1, rgb(38 38 38 / .5))',
|
|
103
103
|
2: 'var(--sheet-2, rgb(38 38 38 / .75))',
|
|
104
104
|
};
|
|
105
|
+
/**
|
|
106
|
+
* The crease — the valley where a neighbouring sheet lies over this one.
|
|
107
|
+
*
|
|
108
|
+
* <YStack {...paper(sheet(0), crease('right'))}>
|
|
109
|
+
*
|
|
110
|
+
* The ladder's drops fall straight down (design's rule is one light, above), so
|
|
111
|
+
* it has nothing to say about a VERTICAL seam — and an app shell is nothing but
|
|
112
|
+
* vertical seams. Three sheets a rung apart, side by side, still read as three
|
|
113
|
+
* abutting rectangles. This is the mark that makes them read as paper: the
|
|
114
|
+
* ground going dark in the valley, which is what a sheet actually lays on the
|
|
115
|
+
* one beside it.
|
|
116
|
+
*
|
|
117
|
+
* It goes on the sheet that is COVERED, on the edge the neighbour lies over —
|
|
118
|
+
* a rail with a sidebar to its right takes `crease('right')`. Nothing can paint
|
|
119
|
+
* outside its own box, so the receiver draws it; the caster only has to be
|
|
120
|
+
* higher up the ladder.
|
|
121
|
+
*
|
|
122
|
+
* Spend it at a seam and nowhere else. A crease down the side of a card with
|
|
123
|
+
* nothing beside it is a gradient somebody liked.
|
|
124
|
+
*/
|
|
125
|
+
export const crease = (edge) => ({ className: 'hz-crease', ...(edge ? { 'data-crease': edge } : {}) });
|
|
126
|
+
/**
|
|
127
|
+
* Unfold — how a sheet ARRIVES: turning open about the edge it is hinged on,
|
|
128
|
+
* rather than fading up as a rectangle.
|
|
129
|
+
*
|
|
130
|
+
* <YStack {...paper(sheet(2), unfold('right'))}>
|
|
131
|
+
*
|
|
132
|
+
* The hinge is the only knob, and it sets the direction of the turn with it, so
|
|
133
|
+
* a sheet cannot be asked to swing the wrong way. A drawer off the left wall is
|
|
134
|
+
* `unfold()`; a pane folding in from the right edge is `unfold('right')`.
|
|
135
|
+
*
|
|
136
|
+
* Motion only — it says nothing about what the surface is made of, so it
|
|
137
|
+
* composes with `sheet`, `glass` or neither. Off under reduced motion, in
|
|
138
|
+
* `styles/motion.css` beside every other keyframe this package ships.
|
|
139
|
+
*/
|
|
140
|
+
export const unfold = (hinge = 'left') => ({ className: 'hz-unfold', ...(hinge === 'right' ? { 'data-hinge': 'right' } : {}) });
|
|
141
|
+
export function paper(...marks) {
|
|
142
|
+
const className = marks
|
|
143
|
+
.map((mark) => mark.className)
|
|
144
|
+
.filter(Boolean)
|
|
145
|
+
.join(' ');
|
|
146
|
+
return { ...Object.assign({}, ...marks), ...(className ? { className } : {}) };
|
|
147
|
+
}
|
|
105
148
|
/**
|
|
106
149
|
* The fold — a corner turned back, and the ONE mark that says an item opens.
|
|
107
150
|
*
|
package/dist/glass.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glass.js","sourceRoot":"","sources":["../src/glass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAU1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,GAAS,CAAC,EAAE,EAAE,CACvC,CAAC;IACC,SAAS,EAAE,mBAAmB,KAAK,EAAE;IACrC,eAAe,EAAE,aAAa;IAC9B,WAAW,EAAE,cAAc;CAC5B,CAAU,CAAA;AAEb;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAK,GAAc,CAAC,EAAE,EAAE,CAC5C,CAAC;IACC,eAAe,EAAE,UAAU,CAAC,KAAK,CAAC;IAClC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,aAAa,KAAK,EAAW,EAAE,CAAC;CACrE,CAAU,CAAA;AAEb,MAAM,UAAU,GAAG;IACjB,CAAC,EAAE,yBAAyB;IAC5B,CAAC,EAAE,oCAAoC;IACvC,CAAC,EAAE,qCAAqC;CAChC,CAAA;
|
|
1
|
+
{"version":3,"file":"glass.js","sourceRoot":"","sources":["../src/glass.ts"],"names":[],"mappings":"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"}
|
package/dist/styles/motion.css
CHANGED
|
@@ -217,6 +217,52 @@
|
|
|
217
217
|
}
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
+
/* ── Unfold — how a sheet arrives ─────────────────────────────────────────────
|
|
221
|
+
A panel that appears by fading is a rectangle switching on. A sheet of paper
|
|
222
|
+
arrives by TURNING OPEN about the edge it is hinged on, so its near edge swings
|
|
223
|
+
toward the reader and its far edge stays put — which is the one motion that
|
|
224
|
+
says "this was already here, folded" rather than "this was drawn just now".
|
|
225
|
+
|
|
226
|
+
The hinge is the ONLY thing that varies, so it is the only knob: a drawer
|
|
227
|
+
coming off the left wall turns about its left edge, a pane folding in from the
|
|
228
|
+
right about its right. The angle follows the hinge — a sheet swings toward you
|
|
229
|
+
from whichever side it is held — so naming the hinge sets both, and there is no
|
|
230
|
+
way to ask for a turn that opens the wrong way.
|
|
231
|
+
|
|
232
|
+
`perspective()` inside the transform rather than on a parent: the vanishing
|
|
233
|
+
point is then the sheet's own centre, so the turn reads at any size and the
|
|
234
|
+
caller does not have to own a 3D context it did not ask for.
|
|
235
|
+
|
|
236
|
+
Seven degrees over 220ms. Enough to see the plane; short of the swinging-door
|
|
237
|
+
effect that makes a workspace feel like a slideshow. */
|
|
238
|
+
@keyframes hz-unfold {
|
|
239
|
+
from {
|
|
240
|
+
opacity: 0;
|
|
241
|
+
transform: perspective(1600px) rotateY(var(--hz-turn, -7deg));
|
|
242
|
+
}
|
|
243
|
+
to {
|
|
244
|
+
opacity: 1;
|
|
245
|
+
transform: perspective(1600px) rotateY(0deg);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.hz-unfold {
|
|
250
|
+
animation: hz-unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
251
|
+
transform-origin: left center;
|
|
252
|
+
will-change: transform, opacity;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.hz-unfold[data-hinge="right"] {
|
|
256
|
+
transform-origin: right center;
|
|
257
|
+
--hz-turn: 7deg;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
@media (prefers-reduced-motion: reduce) {
|
|
261
|
+
.hz-unfold {
|
|
262
|
+
animation: none;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
220
266
|
/* ── Layout guarantees ─────────────────────────────────────────────────────────
|
|
221
267
|
Two rules, both structural. They are attached to `data-slot` rather than to a
|
|
222
268
|
class because they are not styling a caller can opt out of — they are the
|
package/dist/styles.css
CHANGED
|
@@ -1725,6 +1725,73 @@
|
|
|
1725
1725
|
border-bottom-right-radius: 0 !important;
|
|
1726
1726
|
}
|
|
1727
1727
|
|
|
1728
|
+
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
1729
|
+
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
1730
|
+
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
1731
|
+
offset. That is right, and it means the ladder has nothing to say about a
|
|
1732
|
+
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
1733
|
+
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
1734
|
+
abutting rectangles with lines ruled between them, because the only mark at
|
|
1735
|
+
the seam is the hairline.
|
|
1736
|
+
|
|
1737
|
+
What a real sheet lays on the one beneath it, side by side under a light from
|
|
1738
|
+
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
1739
|
+
has no direction of its own, which is both why it is honest here and why it is
|
|
1740
|
+
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
1741
|
+
not one.
|
|
1742
|
+
|
|
1743
|
+
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
1744
|
+
paints above the sheet's own fill and below every child. That ordering is the
|
|
1745
|
+
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
1746
|
+
this same element, !important, so the two would silently fight) and not an
|
|
1747
|
+
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
1748
|
+
|
|
1749
|
+
No side named -> both edges, which is what a pane with a neighbour on each
|
|
1750
|
+
hand needs. Name one and the other stops being drawn. */
|
|
1751
|
+
:root {
|
|
1752
|
+
--crease-ink: rgb(0 0 0 / .28);
|
|
1753
|
+
--crease-depth: 20px;
|
|
1754
|
+
}
|
|
1755
|
+
|
|
1756
|
+
.light, :root.t_light, .t_light {
|
|
1757
|
+
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
1758
|
+
drops make, and for the same reason. */
|
|
1759
|
+
--crease-ink: rgb(0 0 0 / .05);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.hz-crease {
|
|
1763
|
+
position: relative;
|
|
1764
|
+
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
1765
|
+
indistinguishable from the crease not being there at all. */
|
|
1766
|
+
isolation: isolate;
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
.hz-crease::before,
|
|
1770
|
+
.hz-crease::after {
|
|
1771
|
+
content: "";
|
|
1772
|
+
position: absolute;
|
|
1773
|
+
top: 0;
|
|
1774
|
+
bottom: 0;
|
|
1775
|
+
width: var(--crease-depth);
|
|
1776
|
+
z-index: -1;
|
|
1777
|
+
pointer-events: none;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
.hz-crease::before {
|
|
1781
|
+
left: 0;
|
|
1782
|
+
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
.hz-crease::after {
|
|
1786
|
+
right: 0;
|
|
1787
|
+
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
1788
|
+
}
|
|
1789
|
+
|
|
1790
|
+
.hz-crease[data-crease="left"]::after,
|
|
1791
|
+
.hz-crease[data-crease="right"]::before {
|
|
1792
|
+
content: none;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1728
1795
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
1729
1796
|
The dim that makes a floating panel read as floating rather than as more
|
|
1730
1797
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
|
@@ -2370,6 +2437,52 @@ body {
|
|
|
2370
2437
|
}
|
|
2371
2438
|
}
|
|
2372
2439
|
|
|
2440
|
+
/* ── Unfold — how a sheet arrives ─────────────────────────────────────────────
|
|
2441
|
+
A panel that appears by fading is a rectangle switching on. A sheet of paper
|
|
2442
|
+
arrives by TURNING OPEN about the edge it is hinged on, so its near edge swings
|
|
2443
|
+
toward the reader and its far edge stays put — which is the one motion that
|
|
2444
|
+
says "this was already here, folded" rather than "this was drawn just now".
|
|
2445
|
+
|
|
2446
|
+
The hinge is the ONLY thing that varies, so it is the only knob: a drawer
|
|
2447
|
+
coming off the left wall turns about its left edge, a pane folding in from the
|
|
2448
|
+
right about its right. The angle follows the hinge — a sheet swings toward you
|
|
2449
|
+
from whichever side it is held — so naming the hinge sets both, and there is no
|
|
2450
|
+
way to ask for a turn that opens the wrong way.
|
|
2451
|
+
|
|
2452
|
+
`perspective()` inside the transform rather than on a parent: the vanishing
|
|
2453
|
+
point is then the sheet's own centre, so the turn reads at any size and the
|
|
2454
|
+
caller does not have to own a 3D context it did not ask for.
|
|
2455
|
+
|
|
2456
|
+
Seven degrees over 220ms. Enough to see the plane; short of the swinging-door
|
|
2457
|
+
effect that makes a workspace feel like a slideshow. */
|
|
2458
|
+
@keyframes hz-unfold {
|
|
2459
|
+
from {
|
|
2460
|
+
opacity: 0;
|
|
2461
|
+
transform: perspective(1600px) rotateY(var(--hz-turn, -7deg));
|
|
2462
|
+
}
|
|
2463
|
+
to {
|
|
2464
|
+
opacity: 1;
|
|
2465
|
+
transform: perspective(1600px) rotateY(0deg);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
|
|
2469
|
+
.hz-unfold {
|
|
2470
|
+
animation: hz-unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
2471
|
+
transform-origin: left center;
|
|
2472
|
+
will-change: transform, opacity;
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
.hz-unfold[data-hinge="right"] {
|
|
2476
|
+
transform-origin: right center;
|
|
2477
|
+
--hz-turn: 7deg;
|
|
2478
|
+
}
|
|
2479
|
+
|
|
2480
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2481
|
+
.hz-unfold {
|
|
2482
|
+
animation: none;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2373
2486
|
/* ── Layout guarantees ─────────────────────────────────────────────────────────
|
|
2374
2487
|
Two rules, both structural. They are attached to `data-slot` rather than to a
|
|
2375
2488
|
class because they are not styling a caller can opt out of — they are the
|
package/dist/theme.css
CHANGED
|
@@ -1723,6 +1723,73 @@
|
|
|
1723
1723
|
border-bottom-right-radius: 0 !important;
|
|
1724
1724
|
}
|
|
1725
1725
|
|
|
1726
|
+
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
1727
|
+
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
1728
|
+
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
1729
|
+
offset. That is right, and it means the ladder has nothing to say about a
|
|
1730
|
+
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
1731
|
+
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
1732
|
+
abutting rectangles with lines ruled between them, because the only mark at
|
|
1733
|
+
the seam is the hairline.
|
|
1734
|
+
|
|
1735
|
+
What a real sheet lays on the one beneath it, side by side under a light from
|
|
1736
|
+
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
1737
|
+
has no direction of its own, which is both why it is honest here and why it is
|
|
1738
|
+
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
1739
|
+
not one.
|
|
1740
|
+
|
|
1741
|
+
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
1742
|
+
paints above the sheet's own fill and below every child. That ordering is the
|
|
1743
|
+
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
1744
|
+
this same element, !important, so the two would silently fight) and not an
|
|
1745
|
+
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
1746
|
+
|
|
1747
|
+
No side named -> both edges, which is what a pane with a neighbour on each
|
|
1748
|
+
hand needs. Name one and the other stops being drawn. */
|
|
1749
|
+
:root {
|
|
1750
|
+
--crease-ink: rgb(0 0 0 / .28);
|
|
1751
|
+
--crease-depth: 20px;
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
.light, :root.t_light, .t_light {
|
|
1755
|
+
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
1756
|
+
drops make, and for the same reason. */
|
|
1757
|
+
--crease-ink: rgb(0 0 0 / .05);
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
.hz-crease {
|
|
1761
|
+
position: relative;
|
|
1762
|
+
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
1763
|
+
indistinguishable from the crease not being there at all. */
|
|
1764
|
+
isolation: isolate;
|
|
1765
|
+
}
|
|
1766
|
+
|
|
1767
|
+
.hz-crease::before,
|
|
1768
|
+
.hz-crease::after {
|
|
1769
|
+
content: "";
|
|
1770
|
+
position: absolute;
|
|
1771
|
+
top: 0;
|
|
1772
|
+
bottom: 0;
|
|
1773
|
+
width: var(--crease-depth);
|
|
1774
|
+
z-index: -1;
|
|
1775
|
+
pointer-events: none;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.hz-crease::before {
|
|
1779
|
+
left: 0;
|
|
1780
|
+
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
.hz-crease::after {
|
|
1784
|
+
right: 0;
|
|
1785
|
+
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
.hz-crease[data-crease="left"]::after,
|
|
1789
|
+
.hz-crease[data-crease="right"]::before {
|
|
1790
|
+
content: none;
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1726
1793
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
1727
1794
|
The dim that makes a floating panel read as floating rather than as more
|
|
1728
1795
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/ui",
|
|
3
|
-
"version": "8.17.
|
|
3
|
+
"version": "8.17.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Hanzo UI — the one canonical Hanzo component library, on @hanzo/gui + @hanzo/design. ONE substrate: every component renders through @hanzo/gui primitives, so the same import works on web, native (expo) and desktop (Tauri). Self-contained (theme.css), presentational, host-agnostic, clean-room.",
|
|
6
6
|
"exports": {
|