@celestia-island/hikari 0.55.23 → 0.55.24
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/package.json
CHANGED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
@use "../tokens";
|
|
2
|
+
|
|
3
|
+
/* ── HkOtpInput — one cell per character ─────────────────────────────
|
|
4
|
+
* A thin row of `.hk-otp-cell` inputs, styled from the same shell
|
|
5
|
+
* vocabulary as HkInput (55%-surface fill, 14% text border, focus ring
|
|
6
|
+
* on the focused cell) so a code field and a text field sit together
|
|
7
|
+
* without looking like two design systems.
|
|
8
|
+
*
|
|
9
|
+
* L3 hooks carry every geometric knob, so a host can resize the row
|
|
10
|
+
* without touching the library:
|
|
11
|
+
* --hk-otp-cell-size cell width AND height
|
|
12
|
+
* --hk-otp-font-size pin the character's size outright
|
|
13
|
+
* --hk-otp-font-max cap the fitted glyph (set by the size ramps)
|
|
14
|
+
* --hk-otp-gap gap between cells
|
|
15
|
+
* --hk-otp-gap-group gap at the `separated` split
|
|
16
|
+
* The two font knobs are deliberately separate: `-font-size` wins the
|
|
17
|
+
* cascade outright (the cell's font chain reads it first), while
|
|
18
|
+
* `-font-max` is the ramp's ceiling the measured fit clamps under — the
|
|
19
|
+
* fit keeps publishing either way, so releasing a pin needs no event.
|
|
20
|
+
* The size classes are written as complete rule sets (not as deltas over
|
|
21
|
+
* a shared base) on purpose: a `var()` chain whose fallback resolves
|
|
22
|
+
* through an UNSET custom property is invalid at computed-value time, so
|
|
23
|
+
* a ramp declares its cell size, its gap and its font fallback together.
|
|
24
|
+
*
|
|
25
|
+
* Which declarations carry a literal fallback today: the CELL box (width,
|
|
26
|
+
* min-height, radius, durations, easings, the font family and the font
|
|
27
|
+
* size chain), the label and the two messages. The RAMPS' own font values
|
|
28
|
+
* deliberately consume the scale tokens without a literal — they are the
|
|
29
|
+
* design's intended sizes, and a host that loaded this sheet alone still
|
|
30
|
+
* gets a correctly sized row through the fitted-font chain in the cell.
|
|
31
|
+
*
|
|
32
|
+
* Token note: the scale family consumed here (--space-*, --text-*,
|
|
33
|
+
* --radius-*, --duration-*, --ease-*) lives in the canonical scale root,
|
|
34
|
+
* which ships through the `@celestia-island/hikari/styles` aggregate —
|
|
35
|
+
* this sheet `@use`s only ../tokens (the color channels), like every
|
|
36
|
+
* other component sheet. A host that loads ONE component sheet in
|
|
37
|
+
* isolation therefore gets the color tokens but not the scale ones.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
.hk-otp-wrapper {
|
|
41
|
+
display: block;
|
|
42
|
+
width: 100%;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.hk-otp-label {
|
|
46
|
+
display: block;
|
|
47
|
+
font-size: var(--text-xs, 0.75rem);
|
|
48
|
+
font-weight: 600;
|
|
49
|
+
letter-spacing: 0.02em;
|
|
50
|
+
margin-bottom: var(--space-4, 0.25rem);
|
|
51
|
+
color: rgb(var(--color-text) / var(--hk-field-label-alpha, 72%));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.hk-otp {
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
width: 100%;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* The `separated` split (123 456): a slot that only widens the gap, so
|
|
62
|
+
* the two groups keep the row's own centering. */
|
|
63
|
+
.hk-otp-gap {
|
|
64
|
+
flex: none;
|
|
65
|
+
width: calc(var(--hk-otp-gap-group, 1rem) - var(--hk-otp-gap, 0.5rem));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.hk-otp-cell {
|
|
69
|
+
/* Self-declared box model — the cells' centering must not depend on a
|
|
70
|
+
* host reset (same precedent as HkInput's element). */
|
|
71
|
+
box-sizing: border-box;
|
|
72
|
+
/* The ramp size is a CEILING, not a fixed width: with shrink enabled
|
|
73
|
+
* and a 0 floor the row always fits the box it is given, so a card
|
|
74
|
+
* narrower than N x ramp (eight cells in a 290px column, six cells in a
|
|
75
|
+
* phone card) shrinks the cells instead of overflowing the card and
|
|
76
|
+
* hiding the hint beside them. `aspect-ratio` keeps them square as they
|
|
77
|
+
* shrink; `max-width` keeps them from growing past the ramp when the
|
|
78
|
+
* row is wider than it needs. */
|
|
79
|
+
flex: 0 1 auto;
|
|
80
|
+
width: var(--hk-otp-cell-size, 3rem);
|
|
81
|
+
max-width: var(--hk-otp-cell-size, 3rem);
|
|
82
|
+
min-width: 0;
|
|
83
|
+
/* Without this the cells keep an automatic minimum HEIGHT and the square
|
|
84
|
+
* breaks once the width shrinks past the content height (12 cells in a
|
|
85
|
+
* 340px card render 17.67 x 26 without it). */
|
|
86
|
+
min-height: 0;
|
|
87
|
+
aspect-ratio: 1;
|
|
88
|
+
margin: 0;
|
|
89
|
+
padding: 0;
|
|
90
|
+
background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
|
|
91
|
+
border: 1px solid color-mix(in srgb, rgb(var(--color-text)) 14%, transparent);
|
|
92
|
+
border-radius: var(--radius-sm, 4px);
|
|
93
|
+
outline: none;
|
|
94
|
+
appearance: none;
|
|
95
|
+
-webkit-appearance: none;
|
|
96
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
97
|
+
/* Three levels, most specific first:
|
|
98
|
+
* 1. --hk-otp-font-size — a host pinning the glyph outright.
|
|
99
|
+
* 2. --hk-otp-fitted-font — published PER ROW by the component from a
|
|
100
|
+
* measurement of one cell (see the glyph-fit block in the tsx):
|
|
101
|
+
* CSS cannot size the glyph from the cell's own width, because a
|
|
102
|
+
* container cannot query itself and an input has no children.
|
|
103
|
+
* 3. the literal — for a host that loaded this sheet without the
|
|
104
|
+
* canonical scale root (see the header note).
|
|
105
|
+
* The ramps feed the fit through --hk-otp-font-max instead of writing
|
|
106
|
+
* here, so this property stays free of the fit's own output. */
|
|
107
|
+
font-size: var(--hk-otp-font-size, var(--hk-otp-fitted-font, 1.25rem));
|
|
108
|
+
font-weight: 600;
|
|
109
|
+
line-height: 1;
|
|
110
|
+
font-variant-numeric: tabular-nums;
|
|
111
|
+
text-align: center;
|
|
112
|
+
color: rgb(var(--color-text));
|
|
113
|
+
caret-color: rgb(var(--color-primary));
|
|
114
|
+
transition-property: background-color, border-color, color, box-shadow, opacity;
|
|
115
|
+
transition-duration: var(--duration-normal, 0.3s);
|
|
116
|
+
transition-timing-function: var(--ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
|
|
117
|
+
|
|
118
|
+
/* `text` (not `none`): a drag inside a cell still selects its glyph for
|
|
119
|
+
* the keyboard-replace path, while a stray triple-click selection never
|
|
120
|
+
* bleeds across the visual gaps the cells do not actually have. */
|
|
121
|
+
user-select: text;
|
|
122
|
+
|
|
123
|
+
/* `:not(:focus)` is load-bearing, not decoration: the hover selector
|
|
124
|
+
* weighs (0,4,0) against `:focus`'s (0,2,0), so without the exclusion a
|
|
125
|
+
* focused cell under the pointer painted the HOVER border over the
|
|
126
|
+
* focus border (the focus box-shadow survived, which is exactly why it
|
|
127
|
+
* read as a near-miss rather than an obvious bug). */
|
|
128
|
+
&:hover:not(:focus):not(:disabled):not(:read-only) {
|
|
129
|
+
border-color: var(--c-primary-strong);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&:focus {
|
|
133
|
+
border-color: rgb(var(--color-focused-border));
|
|
134
|
+
box-shadow: var(--shadow-focus);
|
|
135
|
+
background: rgb(var(--color-surface));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
&:disabled {
|
|
139
|
+
opacity: 0.5;
|
|
140
|
+
cursor: not-allowed;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
&:read-only {
|
|
144
|
+
cursor: default;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Chromium's autofill paint would otherwise flood the cell with the
|
|
148
|
+
* UA's own yellow/blue and hide the theme surface. */
|
|
149
|
+
&:-webkit-autofill {
|
|
150
|
+
-webkit-text-fill-color: rgb(var(--color-text));
|
|
151
|
+
-webkit-box-shadow: 0 0 0 1000px rgb(var(--color-surface)) inset;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Size ramps: the cell box and its type scale move together. */
|
|
156
|
+
.hk-otp-sm {
|
|
157
|
+
--hk-otp-cell-size: 2.25rem;
|
|
158
|
+
--hk-otp-font-max: var(--text-base);
|
|
159
|
+
gap: var(--hk-otp-gap, 0.375rem);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.hk-otp-md {
|
|
163
|
+
--hk-otp-cell-size: 3rem;
|
|
164
|
+
--hk-otp-font-max: var(--text-xl);
|
|
165
|
+
gap: var(--hk-otp-gap, 0.5rem);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.hk-otp-lg {
|
|
169
|
+
--hk-otp-cell-size: 3.5rem;
|
|
170
|
+
--hk-otp-font-max: var(--text-2xl);
|
|
171
|
+
gap: var(--hk-otp-gap, 0.625rem);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.hk-otp-disabled {
|
|
175
|
+
opacity: 0.6;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
.hk-otp-error .hk-otp-cell {
|
|
179
|
+
border-color: var(--c-error-strong);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.hk-otp-error .hk-otp-cell:focus {
|
|
183
|
+
border-color: rgb(var(--color-error));
|
|
184
|
+
box-shadow: var(--shadow-focus-error);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.hk-otp-error-msg {
|
|
188
|
+
margin: var(--space-6, 0.375rem) 0 0;
|
|
189
|
+
font-size: var(--text-xs, 0.75rem);
|
|
190
|
+
color: rgb(var(--color-error));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.hk-otp-hint {
|
|
194
|
+
margin: var(--space-6, 0.375rem) 0 0;
|
|
195
|
+
font-size: var(--text-xs, 0.75rem);
|
|
196
|
+
color: rgb(var(--color-muted));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* Narrow viewports: shrink the ramps a step so a phone card shows the row
|
|
200
|
+
* at its intended pitch rather than at whatever the shrink-to-fit
|
|
201
|
+
* arithmetic lands on. (The cells would fit either way — this is about
|
|
202
|
+
* proportion, not overflow: a six-cell row in a 340px card measures ~40px
|
|
203
|
+
* per cell at this ramp and ~41px from the flexible shrink.) */
|
|
204
|
+
@media (max-width: 480px) {
|
|
205
|
+
.hk-otp-sm {
|
|
206
|
+
--hk-otp-cell-size: 2rem;
|
|
207
|
+
gap: var(--hk-otp-gap, 0.3125rem);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.hk-otp-md {
|
|
211
|
+
--hk-otp-cell-size: 2.5rem;
|
|
212
|
+
--hk-otp-font-max: var(--text-lg);
|
|
213
|
+
gap: var(--hk-otp-gap, 0.375rem);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.hk-otp-lg {
|
|
217
|
+
--hk-otp-cell-size: 2.75rem;
|
|
218
|
+
--hk-otp-font-max: var(--text-xl);
|
|
219
|
+
gap: var(--hk-otp-gap, 0.5rem);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.hk-otp-gap {
|
|
223
|
+
width: calc(var(--hk-otp-gap-group, 0.75rem) - var(--hk-otp-gap, 0.375rem));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
@media (prefers-reduced-motion: reduce) {
|
|
228
|
+
.hk-otp-cell {
|
|
229
|
+
transition: none;
|
|
230
|
+
}
|
|
231
|
+
}
|