@sfinterface/numbers 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.
@@ -0,0 +1,333 @@
1
+ @layer arc, theme, base, components, utilities;
2
+ @layer arc {
3
+ .sfi-numbers,
4
+ .sfi-numbers-row,
5
+ .sfi-numbers-slot,
6
+ .sfi-numbers-window,
7
+ .sfi-numbers-strip,
8
+ .sfi-numbers-cell,
9
+ .sfi-numbers-face,
10
+ .sfi-numbers-mark {
11
+ font: inherit;
12
+ color: inherit;
13
+ letter-spacing: inherit;
14
+ }
15
+
16
+ @property --sfi-numbers-veil {
17
+ syntax: "<length>";
18
+ inherits: true;
19
+ initial-value: 0px;
20
+ }
21
+
22
+ @keyframes sfi-numbers-veil {
23
+ 0% {
24
+ --sfi-numbers-veil: calc(var(--sfi-numbers-bleed) * var(--sfi-numbers-fade));
25
+ }
26
+ 32% {
27
+ --sfi-numbers-veil: var(--sfi-numbers-veil-deep);
28
+ }
29
+ 100% {
30
+ --sfi-numbers-veil: calc(var(--sfi-numbers-bleed) * var(--sfi-numbers-fade));
31
+ }
32
+ }
33
+
34
+ .sfi-numbers-slot[data-turning] {
35
+ animation: sfi-numbers-veil var(--sfi-numbers-roll) var(--sfi-numbers-ease);
36
+ }
37
+
38
+ .sfi-numbers {
39
+ display: inline-flex;
40
+ align-items: baseline;
41
+ position: relative;
42
+ white-space: nowrap;
43
+
44
+ font-variant-numeric: tabular-nums;
45
+ font-feature-settings: "tnum" 1;
46
+
47
+ --sfi-numbers-roll: var(--sfi-resolve, 520ms);
48
+
49
+ --sfi-numbers-ease: var(--sfi-ease, cubic-bezier(0.32, 0.72, 0, 1));
50
+ --sfi-numbers-ease-exit: var(--sfi-ease-exit, cubic-bezier(0.4, 0, 1, 1));
51
+
52
+ --sfi-numbers-blur: 0.09em;
53
+
54
+ --sfi-numbers-cell: 1.4em;
55
+
56
+ --sfi-numbers-bleed: calc((var(--sfi-numbers-cell) - 0.86em) / 2);
57
+
58
+ --sfi-numbers-fade: 1;
59
+ --sfi-numbers-fade-roll: 1.9;
60
+ --sfi-numbers-veil: calc(var(--sfi-numbers-bleed) * var(--sfi-numbers-fade));
61
+ --sfi-numbers-veil-deep: calc(var(--sfi-numbers-bleed) * var(--sfi-numbers-fade) * var(--sfi-numbers-fade-roll));
62
+
63
+ --sfi-numbers-exit: var(--sfi-settle, 240ms);
64
+ }
65
+
66
+ .sfi-numbers-row {
67
+ display: inline-flex;
68
+ align-items: baseline;
69
+
70
+ position: relative;
71
+
72
+ flex: none;
73
+ }
74
+
75
+ .sfi-numbers-said {
76
+ position: absolute;
77
+ width: 1px;
78
+ height: 1px;
79
+ padding: 0;
80
+ border: 0;
81
+ overflow: hidden;
82
+ white-space: nowrap;
83
+ clip-path: inset(50%);
84
+ }
85
+
86
+ .sfi-numbers-slot {
87
+ position: relative;
88
+ display: inline-block;
89
+ }
90
+ .sfi-numbers-slot::before {
91
+ content: "0";
92
+ visibility: hidden;
93
+ display: block;
94
+ height: var(--sfi-numbers-cell);
95
+ line-height: var(--sfi-numbers-cell);
96
+ }
97
+
98
+ .sfi-numbers-window {
99
+ position: absolute;
100
+ left: 0;
101
+ right: 0;
102
+ top: calc(var(--sfi-numbers-bleed) * -1);
103
+ bottom: calc(var(--sfi-numbers-bleed) * -1);
104
+ overflow: hidden;
105
+
106
+ mask-image: linear-gradient(
107
+ to bottom,
108
+ rgb(0 0 0 / 0) 0,
109
+ rgb(0 0 0 / 0.06) calc(var(--sfi-numbers-veil) * 0.35),
110
+ rgb(0 0 0 / 0.4) calc(var(--sfi-numbers-veil) * 0.68),
111
+ rgb(0 0 0 / 0.86) calc(var(--sfi-numbers-veil) * 0.9),
112
+ rgb(0 0 0 / 1) var(--sfi-numbers-veil),
113
+ rgb(0 0 0 / 1) calc(100% - var(--sfi-numbers-veil)),
114
+ rgb(0 0 0 / 0.86) calc(100% - var(--sfi-numbers-veil) * 0.9),
115
+ rgb(0 0 0 / 0.4) calc(100% - var(--sfi-numbers-veil) * 0.68),
116
+ rgb(0 0 0 / 0.06) calc(100% - var(--sfi-numbers-veil) * 0.35),
117
+ rgb(0 0 0 / 0) 100%
118
+ );
119
+ }
120
+
121
+ .sfi-numbers-strip {
122
+ position: absolute;
123
+ left: 0;
124
+
125
+ top: var(--sfi-numbers-bleed);
126
+
127
+ transform: translateY(calc(var(--sfi-numbers-at, 10) * var(--sfi-numbers-cell) * -1));
128
+ }
129
+
130
+ .sfi-numbers-cell {
131
+ display: block;
132
+ height: var(--sfi-numbers-cell);
133
+ line-height: var(--sfi-numbers-cell);
134
+ text-align: center;
135
+ }
136
+
137
+ .sfi-numbers-face {
138
+ position: absolute;
139
+ top: var(--sfi-numbers-bleed);
140
+ left: 0;
141
+ right: 0;
142
+ height: var(--sfi-numbers-cell);
143
+ line-height: var(--sfi-numbers-cell);
144
+ text-align: center;
145
+ }
146
+
147
+ .sfi-numbers[data-transition="blur"] .sfi-numbers-window,
148
+ .sfi-numbers[data-transition="flip"] .sfi-numbers-window,
149
+ .sfi-numbers[data-transition="scale"] .sfi-numbers-window {
150
+ overflow: visible;
151
+ mask-image: none;
152
+ }
153
+
154
+ .sfi-numbers[data-transition="tick"] .sfi-numbers-face[data-in] {
155
+ animation: sfi-numbers-tick-in var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
156
+ }
157
+ .sfi-numbers[data-transition="tick"] .sfi-numbers-face[data-out] {
158
+ animation: sfi-numbers-tick-out var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
159
+ }
160
+ @keyframes sfi-numbers-tick-in {
161
+ from {
162
+ transform: translateY(calc(var(--sfi-numbers-dir, 1) * var(--sfi-numbers-cell)));
163
+ opacity: 0;
164
+ filter: blur(var(--sfi-numbers-blur));
165
+ }
166
+ to {
167
+ transform: translateY(0);
168
+ opacity: 1;
169
+ filter: blur(0);
170
+ }
171
+ }
172
+ @keyframes sfi-numbers-tick-out {
173
+ from {
174
+ transform: translateY(0);
175
+ opacity: 1;
176
+ filter: blur(0);
177
+ }
178
+ to {
179
+ transform: translateY(calc(var(--sfi-numbers-dir, 1) * var(--sfi-numbers-cell) * -1));
180
+ opacity: 0;
181
+ filter: blur(var(--sfi-numbers-blur));
182
+ }
183
+ }
184
+
185
+ .sfi-numbers[data-transition="blur"] .sfi-numbers-face[data-in] {
186
+ animation: sfi-numbers-dissolve-in var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
187
+ }
188
+ .sfi-numbers[data-transition="blur"] .sfi-numbers-face[data-out] {
189
+ animation: sfi-numbers-dissolve-out var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
190
+ }
191
+ @keyframes sfi-numbers-dissolve-in {
192
+ from {
193
+ opacity: 0;
194
+ filter: blur(calc(var(--sfi-numbers-blur) * 2.2));
195
+ }
196
+ to {
197
+ opacity: 1;
198
+ filter: blur(0);
199
+ }
200
+ }
201
+ @keyframes sfi-numbers-dissolve-out {
202
+ from {
203
+ opacity: 1;
204
+ filter: blur(0);
205
+ }
206
+ to {
207
+ opacity: 0;
208
+ filter: blur(calc(var(--sfi-numbers-blur) * 1.6));
209
+ }
210
+ }
211
+
212
+ .sfi-numbers[data-transition="flip"] .sfi-numbers-window {
213
+ perspective: 7em;
214
+ }
215
+ .sfi-numbers[data-transition="flip"] .sfi-numbers-face {
216
+ backface-visibility: hidden;
217
+ }
218
+ .sfi-numbers[data-transition="flip"] .sfi-numbers-face[data-in] {
219
+ animation: sfi-numbers-flip-in var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
220
+ }
221
+ .sfi-numbers[data-transition="flip"] .sfi-numbers-face[data-out] {
222
+ animation: sfi-numbers-flip-out var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
223
+ }
224
+ @keyframes sfi-numbers-flip-in {
225
+ from {
226
+ transform: rotateX(calc(var(--sfi-numbers-dir, 1) * -88deg));
227
+ opacity: 0;
228
+ }
229
+ to {
230
+ transform: rotateX(0deg);
231
+ opacity: 1;
232
+ }
233
+ }
234
+ @keyframes sfi-numbers-flip-out {
235
+ from {
236
+ transform: rotateX(0deg);
237
+ opacity: 1;
238
+ }
239
+ to {
240
+ transform: rotateX(calc(var(--sfi-numbers-dir, 1) * 88deg));
241
+ opacity: 0;
242
+ }
243
+ }
244
+
245
+ .sfi-numbers[data-transition="scale"] .sfi-numbers-face[data-in] {
246
+ animation: sfi-numbers-depth-in var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
247
+ }
248
+ .sfi-numbers[data-transition="scale"] .sfi-numbers-face[data-out] {
249
+ animation: sfi-numbers-depth-out var(--sfi-numbers-roll) var(--sfi-numbers-ease) both;
250
+ }
251
+ @keyframes sfi-numbers-depth-in {
252
+ from {
253
+ transform: scale(0.58);
254
+ opacity: 0;
255
+ filter: blur(var(--sfi-numbers-blur));
256
+ }
257
+ to {
258
+ transform: scale(1);
259
+ opacity: 1;
260
+ filter: blur(0);
261
+ }
262
+ }
263
+ @keyframes sfi-numbers-depth-out {
264
+ from {
265
+ transform: scale(1);
266
+ opacity: 1;
267
+ filter: blur(0);
268
+ }
269
+ to {
270
+ transform: scale(1.34);
271
+ opacity: 0;
272
+ filter: blur(calc(var(--sfi-numbers-blur) * 1.4));
273
+ }
274
+ }
275
+
276
+ .sfi-numbers-mark {
277
+ display: inline-block;
278
+ white-space: pre;
279
+ }
280
+
281
+ .sfi-numbers-slot[data-arriving],
282
+ .sfi-numbers-mark[data-arriving] {
283
+ animation: sfi-numbers-in var(--sfi-settle, 240ms) var(--sfi-numbers-ease) both;
284
+ }
285
+
286
+ @keyframes sfi-numbers-in {
287
+ from {
288
+ opacity: 0;
289
+ filter: blur(var(--sfi-numbers-blur));
290
+ transform: translateY(calc(var(--sfi-numbers-bleed) * -0.5));
291
+ }
292
+ to {
293
+ opacity: 1;
294
+ filter: blur(0);
295
+ transform: translateY(0);
296
+ }
297
+ }
298
+
299
+ .sfi-numbers-slot[data-leaving],
300
+ .sfi-numbers-mark[data-leaving] {
301
+ position: absolute;
302
+ top: 0;
303
+ pointer-events: none;
304
+ animation: sfi-numbers-out var(--sfi-numbers-exit) var(--sfi-numbers-ease-exit) forwards;
305
+ }
306
+
307
+ @keyframes sfi-numbers-out {
308
+ to {
309
+ opacity: 0;
310
+ filter: blur(var(--sfi-numbers-blur));
311
+ }
312
+ }
313
+
314
+ @media (prefers-reduced-motion: reduce) {
315
+ .sfi-numbers-slot,
316
+ .sfi-numbers-mark,
317
+ .sfi-numbers-face {
318
+ filter: none !important;
319
+ }
320
+
321
+ .sfi-numbers-face[data-out] {
322
+ display: none;
323
+ }
324
+ .sfi-numbers-face[data-in] {
325
+ animation: none !important;
326
+ transform: none !important;
327
+ opacity: 1 !important;
328
+ }
329
+ .sfi-numbers-window {
330
+ mask-image: none;
331
+ }
332
+ }
333
+ }
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@sfinterface/numbers",
3
+ "author": "cz",
4
+ "version": "0.1.0",
5
+ "description": "Numbers that move the way they should. A React component from The San Francisco Interface.",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "sideEffects": [
9
+ "*.css"
10
+ ],
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "main": "./dist/index.cjs",
15
+ "module": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "types": "./dist/index.d.ts",
20
+ "import": "./dist/index.js",
21
+ "require": "./dist/index.cjs"
22
+ },
23
+ "./styles.css": "./dist/numbers.css",
24
+ "./package.json": "./package.json"
25
+ },
26
+ "scripts": {
27
+ "dev": "node scripts/build-css.mjs && concurrently -r \"tsup --watch\" \"node scripts/build-css.mjs --watch\"",
28
+ "build": "tsup && node scripts/build-css.mjs",
29
+ "typecheck": "tsc --noEmit",
30
+ "prepare": "npm run build"
31
+ },
32
+ "peerDependencies": {
33
+ "react": ">=18",
34
+ "react-dom": ">=18"
35
+ },
36
+ "devDependencies": {
37
+ "@types/react": "^19.0.0",
38
+ "@types/react-dom": "^19.0.0",
39
+ "concurrently": "^9.1.2",
40
+ "tsup": "^8.3.5",
41
+ "typescript": "^5.7.2"
42
+ },
43
+ "keywords": [
44
+ "animation",
45
+ "counter",
46
+ "number",
47
+ "odometer",
48
+ "react",
49
+ "rolling-number",
50
+ "ticker"
51
+ ],
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "git+https://github.com/wherescz/sfi-numbers.git"
58
+ },
59
+ "homepage": "https://github.com/wherescz/sfi-numbers",
60
+ "bugs": {
61
+ "url": "https://github.com/wherescz/sfi-numbers/issues"
62
+ }
63
+ }