@echodial/deck 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 +1327 -0
- package/bin/deck.mjs +219 -0
- package/build.mjs +338 -0
- package/dist/api-buckets.json +10486 -0
- package/dist/api.json +57896 -0
- package/dist/brand/deck-apple-touch-icon.png +0 -0
- package/dist/brand/deck-logo-dark.svg +1 -0
- package/dist/brand/deck-logo-light.svg +1 -0
- package/dist/brand/deck-logo-stacked.svg +1 -0
- package/dist/brand/deck-logo.svg +1 -0
- package/dist/brand/deck-mark.svg +7 -0
- package/dist/brand/deck-og.png +0 -0
- package/dist/collisions.json +223 -0
- package/dist/deck-adapters.js +482 -0
- package/dist/deck-adapters.min.js +23 -0
- package/dist/deck-extras.js +823 -0
- package/dist/deck-extras.min.js +5 -0
- package/dist/deck-icons.svg +184 -0
- package/dist/deck.bundle.js +2638 -0
- package/dist/deck.bundle.min.js +86 -0
- package/dist/deck.css +7904 -0
- package/dist/deck.esm.js +2644 -0
- package/dist/deck.js +1331 -0
- package/dist/deck.min.css +32 -0
- package/dist/deck.min.js +60 -0
- package/dist/layers/anchor.css +192 -0
- package/dist/layers/buttons.css +210 -0
- package/dist/layers/charts.css +337 -0
- package/dist/layers/combobox.css +248 -0
- package/dist/layers/components.css +868 -0
- package/dist/layers/container.css +199 -0
- package/dist/layers/datagrid.css +335 -0
- package/dist/layers/datepicker.css +305 -0
- package/dist/layers/forms.css +401 -0
- package/dist/layers/gradients.css +302 -0
- package/dist/layers/inputs.css +522 -0
- package/dist/layers/layers.css +87 -0
- package/dist/layers/layout.css +235 -0
- package/dist/layers/logical.css +226 -0
- package/dist/layers/media.css +400 -0
- package/dist/layers/mobile.css +245 -0
- package/dist/layers/motion.css +379 -0
- package/dist/layers/nav.css +771 -0
- package/dist/layers/perf.css +234 -0
- package/dist/layers/print.css +198 -0
- package/dist/layers/reset.css +103 -0
- package/dist/layers/space3d.css +280 -0
- package/dist/layers/toasts.css +201 -0
- package/dist/layers/tokens.css +229 -0
- package/dist/layers/type.css +114 -0
- package/dist/layers/utilities.css +241 -0
- package/dist/sizes.json +52 -0
- package/dist/usage.json +6340 -0
- package/package.json +94 -0
- package/src/00-layers.css +87 -0
- package/src/01-tokens.css +229 -0
- package/src/02-reset.css +103 -0
- package/src/03-type.css +114 -0
- package/src/04-layout.css +235 -0
- package/src/05-buttons.css +210 -0
- package/src/06-forms.css +401 -0
- package/src/07-components.css +868 -0
- package/src/08-mobile.css +245 -0
- package/src/09-utilities.css +241 -0
- package/src/10-datepicker.css +305 -0
- package/src/11-combobox.css +248 -0
- package/src/12-datagrid.css +335 -0
- package/src/13-toasts.css +201 -0
- package/src/14-charts.css +337 -0
- package/src/16-motion.css +379 -0
- package/src/18-container.css +199 -0
- package/src/19-logical.css +226 -0
- package/src/20-gradients.css +302 -0
- package/src/21-space3d.css +280 -0
- package/src/22-nav.css +771 -0
- package/src/23-inputs.css +522 -0
- package/src/24-media.css +400 -0
- package/src/25-anchor.css +192 -0
- package/src/26-perf.css +234 -0
- package/src/99-print.css +198 -0
- package/src/brand/deck-apple-touch-icon.png +0 -0
- package/src/brand/deck-logo-dark.svg +1 -0
- package/src/brand/deck-logo-light.svg +1 -0
- package/src/brand/deck-logo-stacked.svg +1 -0
- package/src/brand/deck-logo.svg +1 -0
- package/src/brand/deck-mark.svg +7 -0
- package/src/brand/deck-og.png +0 -0
- package/src/brand/sources.json +7 -0
- package/src/deck-icons.svg +184 -0
- package/src/js/deck-adapters.js +482 -0
- package/src/js/deck-extras.js +823 -0
- package/src/js/deck.js +1331 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Deck — 21 Space (3D transforms)
|
|
3
|
+
3D earns its place when depth carries meaning: a card that has two sides, a
|
|
4
|
+
stack you are working down through, a control that physically depresses.
|
|
5
|
+
It does not earn its place as decoration on a landing page.
|
|
6
|
+
|
|
7
|
+
Every transform here uses translate / rotate / scale as individual
|
|
8
|
+
properties rather than the transform shorthand, so two effects on the same
|
|
9
|
+
element compose instead of overwriting each other.
|
|
10
|
+
========================================================================== */
|
|
11
|
+
|
|
12
|
+
@layer deck.effects {
|
|
13
|
+
|
|
14
|
+
/* --- Scene ---------------------------------------------------------------
|
|
15
|
+
A scene establishes the vanishing point. Children need preserve-3d to
|
|
16
|
+
stay in the same space instead of being flattened.
|
|
17
|
+
---------------------------------------------------------------------- */
|
|
18
|
+
.scene {
|
|
19
|
+
perspective: var(--perspective, 1000px);
|
|
20
|
+
perspective-origin: var(--vanish, 50% 50%);
|
|
21
|
+
}
|
|
22
|
+
.scene-near { --perspective: 560px; }
|
|
23
|
+
.scene-far { --perspective: 2000px; }
|
|
24
|
+
.space { transform-style: preserve-3d; }
|
|
25
|
+
.flat { transform-style: flat; }
|
|
26
|
+
.backface-hidden { backface-visibility: hidden; }
|
|
27
|
+
|
|
28
|
+
/* --- Flip card -----------------------------------------------------------
|
|
29
|
+
Two faces, one footprint. Front and back are stacked in the same grid
|
|
30
|
+
cell so the card is exactly as tall as its taller side.
|
|
31
|
+
---------------------------------------------------------------------- */
|
|
32
|
+
.flip {
|
|
33
|
+
display: grid;
|
|
34
|
+
transform-style: preserve-3d;
|
|
35
|
+
transition: rotate var(--dur-4) var(--ease-spring);
|
|
36
|
+
}
|
|
37
|
+
.flip > .flip-front, .flip > .flip-back {
|
|
38
|
+
grid-area: 1 / 1;
|
|
39
|
+
backface-visibility: hidden;
|
|
40
|
+
-webkit-backface-visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
.flip > .flip-back { rotate: y 180deg; }
|
|
43
|
+
.flip.is-flipped { rotate: y 180deg; }
|
|
44
|
+
.flip-x { transition: rotate var(--dur-4) var(--ease-spring); }
|
|
45
|
+
.flip-x > .flip-back { rotate: x 180deg; }
|
|
46
|
+
.flip-x.is-flipped { rotate: x 180deg; }
|
|
47
|
+
|
|
48
|
+
/* Hover flip for pointer devices only — on touch it needs a real tap */
|
|
49
|
+
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
|
50
|
+
.flip-hover:hover { rotate: y 180deg; }
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* --- Tilt ----------------------------------------------------------------
|
|
54
|
+
deck.js writes --tilt-x and --tilt-y from the pointer position. Both are
|
|
55
|
+
registered angles, so they interpolate smoothly back to rest.
|
|
56
|
+
---------------------------------------------------------------------- */
|
|
57
|
+
.tilt {
|
|
58
|
+
transform-style: preserve-3d;
|
|
59
|
+
rotate: var(--tilt-axis, 1 1 0) var(--tilt-amount, 0deg);
|
|
60
|
+
transition: rotate var(--dur-3) var(--ease-out), scale var(--dur-2) var(--ease-out);
|
|
61
|
+
will-change: auto;
|
|
62
|
+
}
|
|
63
|
+
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
|
64
|
+
.tilt.is-tilting { transition: rotate 80ms linear; }
|
|
65
|
+
.tilt:hover { scale: 1.015; }
|
|
66
|
+
/* Content that should float above the card face while it tilts */
|
|
67
|
+
.tilt .tilt-lift { transform: translateZ(var(--depth, 28px)); }
|
|
68
|
+
.tilt .tilt-lift-sm { transform: translateZ(12px); }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* --- Depth stack ---------------------------------------------------------
|
|
72
|
+
A pile of records you are working through. The one on top is live, the
|
|
73
|
+
ones behind are context. --i is the child's own position, 0 for the top
|
|
74
|
+
card; deck.js parks a dismissed card at the end so the rest close up.
|
|
75
|
+
---------------------------------------------------------------------- */
|
|
76
|
+
@supports (animation-delay: calc(sibling-index() * 1ms)) {
|
|
77
|
+
.pile > * { --i: calc(sibling-index() - 1); }
|
|
78
|
+
}
|
|
79
|
+
@supports not (animation-delay: calc(sibling-index() * 1ms)) {
|
|
80
|
+
.pile > :nth-child(1) { --i: 0; }
|
|
81
|
+
.pile > :nth-child(2) { --i: 1; }
|
|
82
|
+
.pile > :nth-child(3) { --i: 2; }
|
|
83
|
+
.pile > :nth-child(4) { --i: 3; }
|
|
84
|
+
.pile > :nth-child(5) { --i: 4; }
|
|
85
|
+
.pile > :nth-child(6) { --i: 5; }
|
|
86
|
+
.pile > :nth-child(7) { --i: 6; }
|
|
87
|
+
.pile > :nth-child(8) { --i: 7; }
|
|
88
|
+
}
|
|
89
|
+
.pile {
|
|
90
|
+
display: grid;
|
|
91
|
+
transform-style: preserve-3d;
|
|
92
|
+
perspective: 1200px;
|
|
93
|
+
}
|
|
94
|
+
.pile > * {
|
|
95
|
+
grid-area: 1 / 1;
|
|
96
|
+
translate: 0 calc(var(--i, 0) * 10px);
|
|
97
|
+
scale: calc(1 - var(--i, 0) * .045);
|
|
98
|
+
z-index: calc(10 - var(--i, 0));
|
|
99
|
+
filter: brightness(calc(1 - var(--i, 0) * .04));
|
|
100
|
+
transition: translate var(--dur-3) var(--ease-out),
|
|
101
|
+
scale var(--dur-3) var(--ease-out),
|
|
102
|
+
rotate var(--dur-3) var(--ease-out),
|
|
103
|
+
opacity var(--dur-2) var(--ease-out);
|
|
104
|
+
}
|
|
105
|
+
.pile > :nth-child(n+4) { opacity: 0; pointer-events: none; }
|
|
106
|
+
|
|
107
|
+
/* Fan the pile out to see what is in it */
|
|
108
|
+
.pile.is-fanned > * {
|
|
109
|
+
translate: calc(var(--i, 0) * 14px) calc(var(--i, 0) * 22px);
|
|
110
|
+
rotate: calc(var(--i, 0) * 2.5deg);
|
|
111
|
+
scale: 1;
|
|
112
|
+
filter: none;
|
|
113
|
+
}
|
|
114
|
+
.pile.is-fanned > :nth-child(n+4):not(.is-dismissed) { opacity: 1; pointer-events: auto; }
|
|
115
|
+
|
|
116
|
+
/* Dismiss the top card away from the pile */
|
|
117
|
+
.pile > .is-dismissed {
|
|
118
|
+
translate: 120% -20px;
|
|
119
|
+
rotate: 14deg;
|
|
120
|
+
opacity: 0;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* --- Coverflow -----------------------------------------------------------
|
|
124
|
+
A horizontal scroller where the off-center items rotate away. Uses scroll
|
|
125
|
+
snap for the mechanics and 3D only for the read.
|
|
126
|
+
---------------------------------------------------------------------- */
|
|
127
|
+
.coverflow {
|
|
128
|
+
display: flex;
|
|
129
|
+
gap: var(--space-4);
|
|
130
|
+
overflow-x: auto;
|
|
131
|
+
scroll-snap-type: x mandatory;
|
|
132
|
+
perspective: 1200px;
|
|
133
|
+
padding-block: var(--space-6);
|
|
134
|
+
padding-inline: max(var(--space-gutter), 20%);
|
|
135
|
+
scrollbar-width: none;
|
|
136
|
+
overscroll-behavior-inline: contain;
|
|
137
|
+
}
|
|
138
|
+
.coverflow::-webkit-scrollbar { display: none; }
|
|
139
|
+
.coverflow > * {
|
|
140
|
+
flex: 0 0 auto;
|
|
141
|
+
scroll-snap-align: center;
|
|
142
|
+
transform-style: preserve-3d;
|
|
143
|
+
transition: rotate var(--dur-3) var(--ease-out), scale var(--dur-3) var(--ease-out);
|
|
144
|
+
}
|
|
145
|
+
/* deck.js marks the centered item; without JS everything simply sits flat */
|
|
146
|
+
.coverflow > .is-behind-start { rotate: y 32deg; scale: .88; }
|
|
147
|
+
.coverflow > .is-behind-end { rotate: y -32deg; scale: .88; }
|
|
148
|
+
.coverflow > .is-front { rotate: y 0deg; scale: 1; }
|
|
149
|
+
|
|
150
|
+
/* --- Cube ----------------------------------------------------------------
|
|
151
|
+
Six faces for a rotating status block or an empty-state illustration.
|
|
152
|
+
---------------------------------------------------------------------- */
|
|
153
|
+
.cube {
|
|
154
|
+
--size: 120px;
|
|
155
|
+
position: relative;
|
|
156
|
+
inline-size: var(--size);
|
|
157
|
+
block-size: var(--size);
|
|
158
|
+
transform-style: preserve-3d;
|
|
159
|
+
transition: rotate var(--dur-5) var(--ease-spring);
|
|
160
|
+
}
|
|
161
|
+
.cube > * {
|
|
162
|
+
position: absolute;
|
|
163
|
+
inset: 0;
|
|
164
|
+
display: grid;
|
|
165
|
+
place-items: center;
|
|
166
|
+
border: 1px solid var(--line);
|
|
167
|
+
background: color-mix(in oklab, var(--surface) 88%, transparent);
|
|
168
|
+
backface-visibility: visible;
|
|
169
|
+
}
|
|
170
|
+
.cube > .face-front { transform: translateZ(calc(var(--size) / 2)); }
|
|
171
|
+
.cube > .face-back { transform: rotateY(180deg) translateZ(calc(var(--size) / 2)); }
|
|
172
|
+
.cube > .face-end { transform: rotateY(90deg) translateZ(calc(var(--size) / 2)); }
|
|
173
|
+
.cube > .face-start { transform: rotateY(-90deg) translateZ(calc(var(--size) / 2)); }
|
|
174
|
+
.cube > .face-top { transform: rotateX(90deg) translateZ(calc(var(--size) / 2)); }
|
|
175
|
+
.cube > .face-bottom { transform: rotateX(-90deg) translateZ(calc(var(--size) / 2)); }
|
|
176
|
+
|
|
177
|
+
.cube[data-face="front"] { rotate: 0deg; }
|
|
178
|
+
.cube[data-face="end"] { rotate: y -90deg; }
|
|
179
|
+
.cube[data-face="back"] { rotate: y 180deg; }
|
|
180
|
+
.cube[data-face="start"] { rotate: y 90deg; }
|
|
181
|
+
.cube[data-face="top"] { rotate: x -90deg; }
|
|
182
|
+
.cube[data-face="bottom"] { rotate: x 90deg; }
|
|
183
|
+
|
|
184
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
185
|
+
.cube-spin { animation: dk-cube 14s linear infinite; }
|
|
186
|
+
@keyframes dk-cube {
|
|
187
|
+
from { transform: rotateX(-18deg) rotateY(0deg); }
|
|
188
|
+
to { transform: rotateX(-18deg) rotateY(360deg); }
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/* --- Depressible controls ------------------------------------------------
|
|
193
|
+
A button with real thickness. The face moves down into the shadow instead
|
|
194
|
+
of just changing color.
|
|
195
|
+
---------------------------------------------------------------------- */
|
|
196
|
+
.btn-3d {
|
|
197
|
+
--lift: 3px;
|
|
198
|
+
position: relative;
|
|
199
|
+
border: 0;
|
|
200
|
+
box-shadow:
|
|
201
|
+
0 var(--lift) 0 0 color-mix(in oklab, var(--brand-600) 62%, var(--ink-900)),
|
|
202
|
+
0 calc(var(--lift) + 3px) 8px oklch(20% .03 var(--hue-neutral) / .22);
|
|
203
|
+
translate: 0 0;
|
|
204
|
+
transition: translate 70ms var(--ease-out), box-shadow 70ms var(--ease-out);
|
|
205
|
+
}
|
|
206
|
+
.btn-3d:active {
|
|
207
|
+
translate: 0 var(--lift);
|
|
208
|
+
box-shadow: 0 0 0 0 color-mix(in oklab, var(--brand-600) 62%, var(--ink-900));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* --- Parallax layers -----------------------------------------------------
|
|
212
|
+
True 3D parallax: layers sit at different Z depths inside a perspective
|
|
213
|
+
container, so the browser does the math on the compositor. No scroll
|
|
214
|
+
handler, no jank.
|
|
215
|
+
---------------------------------------------------------------------- */
|
|
216
|
+
.parallax {
|
|
217
|
+
block-size: 100%;
|
|
218
|
+
overflow-y: auto;
|
|
219
|
+
overflow-x: hidden;
|
|
220
|
+
perspective: 8px;
|
|
221
|
+
perspective-origin: 0 0;
|
|
222
|
+
}
|
|
223
|
+
.parallax-layer {
|
|
224
|
+
position: absolute;
|
|
225
|
+
inset: 0;
|
|
226
|
+
transform-origin: 0 0;
|
|
227
|
+
}
|
|
228
|
+
.parallax-back { transform: translateZ(-6px) scale(1.75); }
|
|
229
|
+
.parallax-mid { transform: translateZ(-3px) scale(1.375); }
|
|
230
|
+
.parallax-front { transform: translateZ(0); }
|
|
231
|
+
|
|
232
|
+
@media (prefers-reduced-motion: reduce) {
|
|
233
|
+
.parallax { perspective: none; }
|
|
234
|
+
.parallax-layer { transform: none; position: relative; }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* --- Page turn -----------------------------------------------------------
|
|
238
|
+
For stepping through a multi-page form or a wizard. Pairs with
|
|
239
|
+
Deck.transition() so the DOM swap and the motion happen together.
|
|
240
|
+
---------------------------------------------------------------------- */
|
|
241
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
242
|
+
.turn-out { animation: dk-turn-out var(--dur-3) var(--ease-in) both; transform-origin: left center; }
|
|
243
|
+
.turn-in { animation: dk-turn-in var(--dur-4) var(--ease-out) both; transform-origin: left center; }
|
|
244
|
+
@keyframes dk-turn-out {
|
|
245
|
+
to { transform: perspective(1400px) rotateY(-22deg); opacity: 0; }
|
|
246
|
+
}
|
|
247
|
+
@keyframes dk-turn-in {
|
|
248
|
+
from { transform: perspective(1400px) rotateY(24deg); opacity: 0; }
|
|
249
|
+
}
|
|
250
|
+
[dir="rtl"] :is(.turn-out, .turn-in) { transform-origin: right center; }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* --- Layered elevation ---------------------------------------------------
|
|
254
|
+
Lift an element toward the viewer inside a scene, rather than faking it
|
|
255
|
+
with a bigger shadow.
|
|
256
|
+
---------------------------------------------------------------------- */
|
|
257
|
+
.z-lift-1 { transform: translateZ(8px); }
|
|
258
|
+
.z-lift-2 { transform: translateZ(20px); }
|
|
259
|
+
.z-lift-3 { transform: translateZ(40px); }
|
|
260
|
+
.z-sink { transform: translateZ(-16px); }
|
|
261
|
+
|
|
262
|
+
/* --- Performance guard ---------------------------------------------------
|
|
263
|
+
3D forces layers onto the GPU. Promote only while something is actually
|
|
264
|
+
moving, and hand the memory back when it stops.
|
|
265
|
+
---------------------------------------------------------------------- */
|
|
266
|
+
.tilt.is-tilting, .flip.is-flipped, .pile.is-fanned > *,
|
|
267
|
+
.coverflow > *, .cube {
|
|
268
|
+
will-change: transform, rotate, scale;
|
|
269
|
+
}
|
|
270
|
+
.tilt:not(.is-tilting), .flip:not(.is-flipped) { will-change: auto; }
|
|
271
|
+
|
|
272
|
+
@media (prefers-reduced-motion: reduce) {
|
|
273
|
+
.flip, .flip-x, .tilt, .cube, .pile > *, .coverflow > * {
|
|
274
|
+
transition-duration: 1ms;
|
|
275
|
+
rotate: none;
|
|
276
|
+
}
|
|
277
|
+
.flip.is-flipped, .flip-x.is-flipped { rotate: y 180deg; }
|
|
278
|
+
.coverflow > * { rotate: none; scale: 1; }
|
|
279
|
+
}
|
|
280
|
+
}
|