@webority/theme 0.3.0 → 0.4.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 +18 -29
- package/dist/webority-theme.css +1 -1
- package/package.json +2 -2
- package/scss/_components.scss +42 -0
- package/scss/_variables.scss +17 -0
- package/scss/_wui-components.scss +19 -3723
- package/scss/wui/_card.scss +37 -0
- package/scss/wui/_choice.scss +746 -0
- package/scss/wui/_controls.scss +808 -0
- package/scss/wui/_data.scss +614 -0
- package/scss/wui/_disclosure.scss +113 -0
- package/scss/wui/_display.scss +508 -0
- package/scss/wui/_flow.scss +410 -0
- package/scss/wui/_media.scss +569 -0
- package/scss/wui/_navigation.scss +284 -0
- package/scss/wui/_overlays.scss +350 -0
- package/scss/wui/_shell.scss +474 -0
- package/scss/wui/_typography.scss +275 -0
- package/scss/wui/_utilities.scss +340 -0
|
@@ -0,0 +1,746 @@
|
|
|
1
|
+
// Structure card, search select, date picker, phone input.
|
|
2
|
+
//
|
|
3
|
+
// Part of the wui-components layer — see _wui-components.scss for the whole
|
|
4
|
+
// picture and the load order. Order within the layer is LOAD-BEARING: these
|
|
5
|
+
// partials are a split of one stylesheet, not independent modules, so a rule
|
|
6
|
+
// here may be overridden by a later partial. Never reorder the imports.
|
|
7
|
+
|
|
8
|
+
// ── Structure card (struct-card*) ──
|
|
9
|
+
// Single-select radio-card control (e.g. "type of structure" picker).
|
|
10
|
+
.struct-card {
|
|
11
|
+
position: relative;
|
|
12
|
+
display: flex;
|
|
13
|
+
align-items: center;
|
|
14
|
+
gap: 11px;
|
|
15
|
+
padding: 20px;
|
|
16
|
+
border: 1.5px solid var(--color-border);
|
|
17
|
+
border-radius: var(--radius);
|
|
18
|
+
background: var(--color-surface);
|
|
19
|
+
cursor: pointer;
|
|
20
|
+
transition:
|
|
21
|
+
border-color 0.12s ease,
|
|
22
|
+
background 0.12s ease;
|
|
23
|
+
}
|
|
24
|
+
.struct-card:hover {
|
|
25
|
+
border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
|
|
26
|
+
}
|
|
27
|
+
.struct-card.checked {
|
|
28
|
+
border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
|
|
29
|
+
background: color-mix(in srgb, var(--color-primary) 5%, transparent);
|
|
30
|
+
}
|
|
31
|
+
.struct-card.checked .struct-card-title {
|
|
32
|
+
color: var(--color-primary);
|
|
33
|
+
}
|
|
34
|
+
.struct-card-input {
|
|
35
|
+
position: absolute;
|
|
36
|
+
opacity: 0;
|
|
37
|
+
pointer-events: none;
|
|
38
|
+
}
|
|
39
|
+
.struct-card-ic {
|
|
40
|
+
width: 44px;
|
|
41
|
+
height: 44px;
|
|
42
|
+
border-radius: 99px;
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
display: inline-flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
justify-content: center;
|
|
47
|
+
background: var(--color-bg-muted);
|
|
48
|
+
color: var(--color-text-subtle);
|
|
49
|
+
transition:
|
|
50
|
+
background 0.12s,
|
|
51
|
+
color 0.12s;
|
|
52
|
+
}
|
|
53
|
+
.struct-card.checked .struct-card-ic {
|
|
54
|
+
background: var(--color-surface);
|
|
55
|
+
color: var(--color-primary);
|
|
56
|
+
}
|
|
57
|
+
// Icon illustrations are coloured PNGs: greyscale them until the card is
|
|
58
|
+
// selected, then show the full-colour (blue) art.
|
|
59
|
+
.struct-card-ic img {
|
|
60
|
+
filter: grayscale(1);
|
|
61
|
+
opacity: 0.6;
|
|
62
|
+
transition:
|
|
63
|
+
filter 0.12s,
|
|
64
|
+
opacity 0.12s;
|
|
65
|
+
}
|
|
66
|
+
.struct-card.checked .struct-card-ic img {
|
|
67
|
+
filter: none;
|
|
68
|
+
opacity: 1;
|
|
69
|
+
}
|
|
70
|
+
.struct-card-body {
|
|
71
|
+
display: flex;
|
|
72
|
+
flex-direction: column;
|
|
73
|
+
min-width: 0;
|
|
74
|
+
}
|
|
75
|
+
.struct-card-title {
|
|
76
|
+
font-weight: 600;
|
|
77
|
+
font-size: 16px;
|
|
78
|
+
color: var(--color-text);
|
|
79
|
+
}
|
|
80
|
+
.struct-card-desc {
|
|
81
|
+
font-size: 14px;
|
|
82
|
+
font-weight: 400;
|
|
83
|
+
color: var(--color-text-muted);
|
|
84
|
+
line-height: 1.35;
|
|
85
|
+
margin-top: 2px;
|
|
86
|
+
}
|
|
87
|
+
.struct-card-check {
|
|
88
|
+
position: absolute;
|
|
89
|
+
top: 10px;
|
|
90
|
+
right: 10px;
|
|
91
|
+
display: inline-flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
background: transparent;
|
|
95
|
+
color: var(--color-primary);
|
|
96
|
+
opacity: 0;
|
|
97
|
+
transform: scale(0.5);
|
|
98
|
+
transition:
|
|
99
|
+
opacity 0.12s ease,
|
|
100
|
+
transform 0.12s ease;
|
|
101
|
+
}
|
|
102
|
+
.struct-card.checked .struct-card-check {
|
|
103
|
+
opacity: 1;
|
|
104
|
+
transform: scale(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Tile variant: big centered illustration + label. Opt in with
|
|
108
|
+
// className="struct-card-tile".
|
|
109
|
+
.struct-card-tile {
|
|
110
|
+
flex-direction: column;
|
|
111
|
+
align-items: center;
|
|
112
|
+
text-align: center;
|
|
113
|
+
gap: 16px;
|
|
114
|
+
padding: 26px 18px 20px;
|
|
115
|
+
}
|
|
116
|
+
// Drop the icon disc — the illustration stands on its own, sized large.
|
|
117
|
+
.struct-card-tile .struct-card-ic,
|
|
118
|
+
.struct-card-tile.checked .struct-card-ic {
|
|
119
|
+
width: auto;
|
|
120
|
+
height: auto;
|
|
121
|
+
border-radius: 0;
|
|
122
|
+
background: transparent;
|
|
123
|
+
}
|
|
124
|
+
// Full-colour at all times (override the greyscale-until-selected treatment).
|
|
125
|
+
.struct-card-tile .struct-card-ic img,
|
|
126
|
+
.struct-card-tile.checked .struct-card-ic img {
|
|
127
|
+
width: 100px;
|
|
128
|
+
height: 100px;
|
|
129
|
+
filter: none;
|
|
130
|
+
opacity: 1;
|
|
131
|
+
}
|
|
132
|
+
.struct-card-tile .struct-card-body {
|
|
133
|
+
align-items: center;
|
|
134
|
+
}
|
|
135
|
+
.struct-card-tile .struct-card-title {
|
|
136
|
+
font-size: 17px;
|
|
137
|
+
}
|
|
138
|
+
.struct-card-tile .struct-card-desc {
|
|
139
|
+
margin-top: 4px;
|
|
140
|
+
}
|
|
141
|
+
.struct-card-tile .struct-card-check {
|
|
142
|
+
display: none;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── Search select ──
|
|
146
|
+
.search-select {
|
|
147
|
+
position: relative;
|
|
148
|
+
min-width: 0;
|
|
149
|
+
}
|
|
150
|
+
.search-select-control {
|
|
151
|
+
display: flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
gap: 8px;
|
|
155
|
+
text-align: left;
|
|
156
|
+
cursor: pointer;
|
|
157
|
+
width: 100%;
|
|
158
|
+
min-width: 0;
|
|
159
|
+
}
|
|
160
|
+
.search-select-control > span {
|
|
161
|
+
min-width: 0;
|
|
162
|
+
overflow: hidden;
|
|
163
|
+
text-overflow: ellipsis;
|
|
164
|
+
white-space: nowrap;
|
|
165
|
+
}
|
|
166
|
+
.search-select-control:disabled {
|
|
167
|
+
cursor: not-allowed;
|
|
168
|
+
opacity: 0.6;
|
|
169
|
+
}
|
|
170
|
+
.search-select-control:hover:not(:disabled) {
|
|
171
|
+
border-color: var(--color-border-strong);
|
|
172
|
+
}
|
|
173
|
+
.search-select-control.open {
|
|
174
|
+
background: var(--color-bg-muted);
|
|
175
|
+
border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
|
|
176
|
+
}
|
|
177
|
+
.search-select-caret {
|
|
178
|
+
flex-shrink: 0;
|
|
179
|
+
color: var(--color-text-muted);
|
|
180
|
+
transition: transform 0.15s ease;
|
|
181
|
+
}
|
|
182
|
+
.search-select-caret path {
|
|
183
|
+
stroke-width: 2px;
|
|
184
|
+
}
|
|
185
|
+
.search-select-control.open .search-select-caret {
|
|
186
|
+
transform: rotate(180deg);
|
|
187
|
+
}
|
|
188
|
+
.search-select-placeholder {
|
|
189
|
+
color: var(--color-text-subtle);
|
|
190
|
+
}
|
|
191
|
+
// Menu matches the themed-select dropdown: 16px squircle, 4px padding, soft
|
|
192
|
+
// shadow.
|
|
193
|
+
.search-select-menu {
|
|
194
|
+
position: absolute;
|
|
195
|
+
z-index: 40;
|
|
196
|
+
top: calc(100% + 6px);
|
|
197
|
+
left: 0;
|
|
198
|
+
right: 0;
|
|
199
|
+
background: var(--color-surface);
|
|
200
|
+
border: 1px solid var(--color-border);
|
|
201
|
+
border-radius: var(--radius-lg);
|
|
202
|
+
corner-shape: squircle;
|
|
203
|
+
box-shadow: var(--shadow-overlay);
|
|
204
|
+
padding: 4px;
|
|
205
|
+
overflow: hidden;
|
|
206
|
+
}
|
|
207
|
+
// Portalled to <body>: fixed-positioned (top/left set inline from the
|
|
208
|
+
// trigger rect) so the menu overlays instead of being clipped by a
|
|
209
|
+
// scrollable modal / table card. Sits above the modal layer.
|
|
210
|
+
.search-select-menu-fixed {
|
|
211
|
+
position: fixed;
|
|
212
|
+
z-index: 1600;
|
|
213
|
+
right: auto;
|
|
214
|
+
top: auto;
|
|
215
|
+
left: auto;
|
|
216
|
+
}
|
|
217
|
+
// Search box matches the search bar: rounded field, leading icon turns
|
|
218
|
+
// primary.
|
|
219
|
+
.search-select-search {
|
|
220
|
+
display: flex;
|
|
221
|
+
align-items: center;
|
|
222
|
+
gap: 8px;
|
|
223
|
+
margin: 4px;
|
|
224
|
+
padding: 0 12px;
|
|
225
|
+
height: 40px;
|
|
226
|
+
border: 1px solid var(--color-border);
|
|
227
|
+
border-radius: var(--radius);
|
|
228
|
+
corner-shape: squircle;
|
|
229
|
+
background: var(--color-surface);
|
|
230
|
+
color: var(--color-text-subtle);
|
|
231
|
+
}
|
|
232
|
+
.search-select-search {
|
|
233
|
+
position: relative;
|
|
234
|
+
}
|
|
235
|
+
.search-select-search:focus-within {
|
|
236
|
+
background: var(--color-bg-muted);
|
|
237
|
+
}
|
|
238
|
+
.search-select-search:focus-within svg {
|
|
239
|
+
color: var(--color-primary);
|
|
240
|
+
}
|
|
241
|
+
.search-select-clear {
|
|
242
|
+
display: grid;
|
|
243
|
+
place-items: center;
|
|
244
|
+
width: 24px;
|
|
245
|
+
height: 24px;
|
|
246
|
+
border: none;
|
|
247
|
+
background: transparent;
|
|
248
|
+
padding: 0;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
color: var(--color-text-subtle);
|
|
251
|
+
}
|
|
252
|
+
.search-select-clear:hover {
|
|
253
|
+
color: var(--color-text);
|
|
254
|
+
}
|
|
255
|
+
.search-select-input {
|
|
256
|
+
flex: 1;
|
|
257
|
+
border: none;
|
|
258
|
+
outline: none;
|
|
259
|
+
font-size: 14px;
|
|
260
|
+
font-family: inherit;
|
|
261
|
+
color: var(--color-text);
|
|
262
|
+
background: transparent;
|
|
263
|
+
}
|
|
264
|
+
.search-select-options {
|
|
265
|
+
max-height: 300px;
|
|
266
|
+
overflow-y: auto;
|
|
267
|
+
padding: 4px 4px 4px;
|
|
268
|
+
display: flex;
|
|
269
|
+
flex-direction: column;
|
|
270
|
+
gap: 4px;
|
|
271
|
+
scrollbar-gutter: stable;
|
|
272
|
+
}
|
|
273
|
+
.search-select-option {
|
|
274
|
+
display: flex;
|
|
275
|
+
align-items: center;
|
|
276
|
+
justify-content: space-between;
|
|
277
|
+
gap: 8px;
|
|
278
|
+
width: 100%;
|
|
279
|
+
text-align: left;
|
|
280
|
+
padding: 9px 14px;
|
|
281
|
+
line-height: 1.4;
|
|
282
|
+
border: none;
|
|
283
|
+
border-radius: var(--radius);
|
|
284
|
+
corner-shape: squircle;
|
|
285
|
+
background: transparent;
|
|
286
|
+
font-size: 14px;
|
|
287
|
+
color: var(--color-text);
|
|
288
|
+
cursor: pointer;
|
|
289
|
+
transition:
|
|
290
|
+
background 0.12s ease,
|
|
291
|
+
color 0.12s ease;
|
|
292
|
+
}
|
|
293
|
+
.search-select-option:hover,
|
|
294
|
+
.search-select-option.is-active {
|
|
295
|
+
background: var(--color-primary-soft);
|
|
296
|
+
color: var(--color-primary);
|
|
297
|
+
}
|
|
298
|
+
.search-select-option.selected {
|
|
299
|
+
background: var(--color-primary-soft);
|
|
300
|
+
color: var(--color-primary);
|
|
301
|
+
font-weight: 500;
|
|
302
|
+
}
|
|
303
|
+
.search-select-empty {
|
|
304
|
+
padding: 12px 10px;
|
|
305
|
+
font-size: 13px;
|
|
306
|
+
color: var(--color-text-subtle);
|
|
307
|
+
text-align: center;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ── Date picker ──
|
|
311
|
+
// Custom DatePicker — themed popover calendar (the native popup can't be
|
|
312
|
+
// styled).
|
|
313
|
+
.datepicker {
|
|
314
|
+
position: relative;
|
|
315
|
+
}
|
|
316
|
+
.datepicker-trigger {
|
|
317
|
+
text-align: left;
|
|
318
|
+
cursor: pointer;
|
|
319
|
+
}
|
|
320
|
+
.datepicker-trigger:not(.has-value) {
|
|
321
|
+
color: var(--color-text-subtle);
|
|
322
|
+
}
|
|
323
|
+
.datepicker.open .datepicker-trigger {
|
|
324
|
+
background-color: var(--color-bg-muted);
|
|
325
|
+
border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
|
|
326
|
+
box-shadow: none;
|
|
327
|
+
}
|
|
328
|
+
// Portalled to <body> and fixed-positioned from JS so a modal's
|
|
329
|
+
// overflow:hidden can't clip it; top/left come from inline styles. z-index
|
|
330
|
+
// sits above the modal layer.
|
|
331
|
+
.datepicker-pop {
|
|
332
|
+
position: fixed;
|
|
333
|
+
z-index: 1600;
|
|
334
|
+
width: 312px;
|
|
335
|
+
max-width: calc(100vw - 16px);
|
|
336
|
+
padding: 18px;
|
|
337
|
+
background: var(--color-surface);
|
|
338
|
+
border: 1px solid var(--color-border);
|
|
339
|
+
border-radius: var(--radius-xl);
|
|
340
|
+
corner-shape: squircle;
|
|
341
|
+
box-shadow: var(--shadow-overlay);
|
|
342
|
+
animation: datepicker-in 0.14s ease;
|
|
343
|
+
}
|
|
344
|
+
.datepicker-pop.drop-up {
|
|
345
|
+
animation: datepicker-in-up 0.14s ease;
|
|
346
|
+
}
|
|
347
|
+
@keyframes datepicker-in {
|
|
348
|
+
from {
|
|
349
|
+
opacity: 0;
|
|
350
|
+
transform: translateY(-4px);
|
|
351
|
+
}
|
|
352
|
+
to {
|
|
353
|
+
opacity: 1;
|
|
354
|
+
transform: translateY(0);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
@keyframes datepicker-in-up {
|
|
358
|
+
from {
|
|
359
|
+
opacity: 0;
|
|
360
|
+
transform: translateY(4px);
|
|
361
|
+
}
|
|
362
|
+
to {
|
|
363
|
+
opacity: 1;
|
|
364
|
+
transform: translateY(0);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
.datepicker-head {
|
|
368
|
+
display: flex;
|
|
369
|
+
align-items: center;
|
|
370
|
+
justify-content: space-between;
|
|
371
|
+
margin-bottom: 14px;
|
|
372
|
+
}
|
|
373
|
+
.datepicker-month {
|
|
374
|
+
font-size: 15px;
|
|
375
|
+
font-weight: 600;
|
|
376
|
+
color: var(--color-text);
|
|
377
|
+
letter-spacing: -0.01em;
|
|
378
|
+
}
|
|
379
|
+
.datepicker-nav {
|
|
380
|
+
display: inline-flex;
|
|
381
|
+
gap: 6px;
|
|
382
|
+
}
|
|
383
|
+
.datepicker-nav-btn {
|
|
384
|
+
display: inline-flex;
|
|
385
|
+
align-items: center;
|
|
386
|
+
justify-content: center;
|
|
387
|
+
width: 30px;
|
|
388
|
+
height: 30px;
|
|
389
|
+
border: 1px solid var(--color-border);
|
|
390
|
+
border-radius: 999px;
|
|
391
|
+
background: transparent;
|
|
392
|
+
color: var(--color-text-muted);
|
|
393
|
+
cursor: pointer;
|
|
394
|
+
transition:
|
|
395
|
+
background 0.12s,
|
|
396
|
+
color 0.12s,
|
|
397
|
+
border-color 0.12s;
|
|
398
|
+
}
|
|
399
|
+
.datepicker-nav-btn:hover {
|
|
400
|
+
background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary) 8%, transparent));
|
|
401
|
+
border-color: var(--color-primary);
|
|
402
|
+
color: var(--color-primary);
|
|
403
|
+
}
|
|
404
|
+
.datepicker-weekdays {
|
|
405
|
+
display: grid;
|
|
406
|
+
grid-template-columns: repeat(7, 1fr);
|
|
407
|
+
gap: 4px;
|
|
408
|
+
margin-bottom: 6px;
|
|
409
|
+
}
|
|
410
|
+
.datepicker-grid {
|
|
411
|
+
display: flex;
|
|
412
|
+
flex-direction: column;
|
|
413
|
+
gap: 4px;
|
|
414
|
+
}
|
|
415
|
+
.datepicker-row {
|
|
416
|
+
display: grid;
|
|
417
|
+
grid-template-columns: repeat(7, 1fr);
|
|
418
|
+
gap: 4px;
|
|
419
|
+
}
|
|
420
|
+
.datepicker-weekdays span {
|
|
421
|
+
text-align: center;
|
|
422
|
+
font-size: 11px;
|
|
423
|
+
font-weight: 600;
|
|
424
|
+
text-transform: uppercase;
|
|
425
|
+
letter-spacing: 0.04em;
|
|
426
|
+
color: var(--color-text-subtle);
|
|
427
|
+
padding: 4px 0;
|
|
428
|
+
}
|
|
429
|
+
.datepicker-day {
|
|
430
|
+
display: inline-flex;
|
|
431
|
+
align-items: center;
|
|
432
|
+
justify-content: center;
|
|
433
|
+
aspect-ratio: 1;
|
|
434
|
+
width: 100%;
|
|
435
|
+
border: none;
|
|
436
|
+
border-radius: 50%;
|
|
437
|
+
background: transparent;
|
|
438
|
+
font-size: 13px;
|
|
439
|
+
font-weight: 500;
|
|
440
|
+
color: var(--color-text);
|
|
441
|
+
cursor: pointer;
|
|
442
|
+
transition:
|
|
443
|
+
background 0.12s,
|
|
444
|
+
color 0.12s,
|
|
445
|
+
box-shadow 0.12s;
|
|
446
|
+
}
|
|
447
|
+
.datepicker-day:hover:not(:disabled):not(.is-selected) {
|
|
448
|
+
background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary) 8%, transparent));
|
|
449
|
+
color: var(--color-primary);
|
|
450
|
+
}
|
|
451
|
+
.datepicker-day.is-outside {
|
|
452
|
+
color: var(--color-text-subtle);
|
|
453
|
+
font-weight: 400;
|
|
454
|
+
}
|
|
455
|
+
.datepicker-day.is-today {
|
|
456
|
+
font-weight: 700;
|
|
457
|
+
color: var(--color-primary);
|
|
458
|
+
box-shadow: inset 0 0 0 1.5px var(--color-primary);
|
|
459
|
+
}
|
|
460
|
+
.datepicker-day.is-selected {
|
|
461
|
+
background: var(--color-primary);
|
|
462
|
+
color: #fff;
|
|
463
|
+
font-weight: 600;
|
|
464
|
+
}
|
|
465
|
+
.datepicker-day:disabled {
|
|
466
|
+
color: var(--color-border-strong);
|
|
467
|
+
cursor: not-allowed;
|
|
468
|
+
}
|
|
469
|
+
.datepicker-foot {
|
|
470
|
+
display: flex;
|
|
471
|
+
align-items: center;
|
|
472
|
+
justify-content: space-between;
|
|
473
|
+
margin-top: 14px;
|
|
474
|
+
padding-top: 14px;
|
|
475
|
+
border-top: 1px solid var(--color-border);
|
|
476
|
+
}
|
|
477
|
+
.datepicker-link {
|
|
478
|
+
border: none;
|
|
479
|
+
background: transparent;
|
|
480
|
+
padding: 6px 12px;
|
|
481
|
+
border-radius: var(--radius);
|
|
482
|
+
font-size: 13px;
|
|
483
|
+
font-weight: 600;
|
|
484
|
+
color: var(--color-primary);
|
|
485
|
+
cursor: pointer;
|
|
486
|
+
transition: background 0.12s;
|
|
487
|
+
}
|
|
488
|
+
.datepicker-link:hover:not(:disabled) {
|
|
489
|
+
background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary) 8%, transparent));
|
|
490
|
+
}
|
|
491
|
+
.datepicker-link:disabled {
|
|
492
|
+
color: var(--color-text-subtle);
|
|
493
|
+
cursor: not-allowed;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// ── Phone input ──
|
|
497
|
+
.app-phone-number-input {
|
|
498
|
+
width: 100%;
|
|
499
|
+
}
|
|
500
|
+
// One field, one border: the WRAPPER owns the chrome (same pattern as
|
|
501
|
+
// .input-with-unit) so the dial-code picker and the number light up together.
|
|
502
|
+
// The adornment used to be absolutely positioned over the input, which let the
|
|
503
|
+
// placeholder run underneath it — masked only by the UA button's grey fill.
|
|
504
|
+
.app-phone-number-input .phone-input-wrap {
|
|
505
|
+
display: flex;
|
|
506
|
+
align-items: center;
|
|
507
|
+
width: 100%;
|
|
508
|
+
height: var(--wui-control-height);
|
|
509
|
+
border: 1px solid var(--color-border);
|
|
510
|
+
border-radius: var(--radius);
|
|
511
|
+
corner-shape: squircle;
|
|
512
|
+
background: var(--color-surface);
|
|
513
|
+
transition:
|
|
514
|
+
border-color 0.12s,
|
|
515
|
+
background-color 0.12s;
|
|
516
|
+
}
|
|
517
|
+
.app-phone-number-input .phone-input-wrap:hover:not(:focus-within) {
|
|
518
|
+
background: var(--color-bg-muted);
|
|
519
|
+
border-color: var(--color-border-strong);
|
|
520
|
+
}
|
|
521
|
+
.app-phone-number-input .phone-input-wrap:focus-within {
|
|
522
|
+
background: var(--color-bg-muted);
|
|
523
|
+
border-color: var(--color-primary);
|
|
524
|
+
}
|
|
525
|
+
.app-phone-number-input .phone-input-wrap:has(> .input:disabled) {
|
|
526
|
+
background: var(--color-bg-muted);
|
|
527
|
+
cursor: not-allowed;
|
|
528
|
+
}
|
|
529
|
+
.app-phone-number-input .phone-input-wrap:has(.input.error),
|
|
530
|
+
.app-phone-number-input .phone-input-wrap:has(.input.is-invalid) {
|
|
531
|
+
border-color: color-mix(in srgb, var(--color-danger) 45%, var(--color-surface));
|
|
532
|
+
}
|
|
533
|
+
// The inner control drops its own chrome — the shell carries it.
|
|
534
|
+
.app-phone-number-input .phone-input-wrap > .input,
|
|
535
|
+
.app-phone-number-input .phone-input-wrap > .input:hover,
|
|
536
|
+
.app-phone-number-input .phone-input-wrap > .input:focus {
|
|
537
|
+
flex: 1 1 auto;
|
|
538
|
+
min-width: 0;
|
|
539
|
+
width: auto;
|
|
540
|
+
height: 100%;
|
|
541
|
+
border: 0;
|
|
542
|
+
background: transparent;
|
|
543
|
+
box-shadow: none;
|
|
544
|
+
}
|
|
545
|
+
// `relative` so the menu anchors here (it is NOT positioned by JS — it used to
|
|
546
|
+
// rely on the adornment being absolute, which is why it appeared to float).
|
|
547
|
+
.app-phone-number-input .phone-country-adornment {
|
|
548
|
+
position: relative;
|
|
549
|
+
flex: none;
|
|
550
|
+
display: flex;
|
|
551
|
+
align-items: center;
|
|
552
|
+
padding-left: 12px;
|
|
553
|
+
z-index: 5;
|
|
554
|
+
}
|
|
555
|
+
// NOT scoped under `.country-dropdown` — <wui-phone> renders the toggle inside
|
|
556
|
+
// `.phone-country-adornment`, with no such wrapper. Scoping it there left the
|
|
557
|
+
// button on raw UA styling (2px outset border + grey fill) inside the field.
|
|
558
|
+
.country-toggle {
|
|
559
|
+
display: flex;
|
|
560
|
+
align-items: center;
|
|
561
|
+
gap: 6px;
|
|
562
|
+
padding: 0;
|
|
563
|
+
border: 0;
|
|
564
|
+
background: transparent;
|
|
565
|
+
box-shadow: none;
|
|
566
|
+
color: var(--color-text);
|
|
567
|
+
cursor: pointer;
|
|
568
|
+
font: inherit;
|
|
569
|
+
line-height: 1;
|
|
570
|
+
}
|
|
571
|
+
.country-toggle::after {
|
|
572
|
+
display: none;
|
|
573
|
+
}
|
|
574
|
+
.country-toggle:hover,
|
|
575
|
+
.country-toggle:focus,
|
|
576
|
+
.country-toggle:active {
|
|
577
|
+
background: transparent;
|
|
578
|
+
box-shadow: none;
|
|
579
|
+
color: var(--color-text);
|
|
580
|
+
}
|
|
581
|
+
.country-toggle:hover .phone-chevron {
|
|
582
|
+
color: var(--color-text);
|
|
583
|
+
}
|
|
584
|
+
.country-toggle:focus {
|
|
585
|
+
outline: none;
|
|
586
|
+
}
|
|
587
|
+
.country-toggle:focus-visible {
|
|
588
|
+
outline: 2px solid var(--color-primary);
|
|
589
|
+
outline-offset: 2px;
|
|
590
|
+
border-radius: var(--radius-sm);
|
|
591
|
+
}
|
|
592
|
+
.country-toggle:disabled {
|
|
593
|
+
cursor: not-allowed;
|
|
594
|
+
opacity: 0.6;
|
|
595
|
+
}
|
|
596
|
+
// Flag glyphs come from the generated .wui-flag-* classes (_flags.scss).
|
|
597
|
+
.app-phone-number-input .phone-chevron {
|
|
598
|
+
color: var(--color-text-muted);
|
|
599
|
+
transition: transform 0.2s ease;
|
|
600
|
+
}
|
|
601
|
+
// Keyed off the element's own ARIA state — <wui-phone> toggles aria-expanded,
|
|
602
|
+
// it never adds react-bootstrap's `.show`.
|
|
603
|
+
.country-toggle[aria-expanded="true"] .phone-chevron {
|
|
604
|
+
transform: rotate(180deg);
|
|
605
|
+
}
|
|
606
|
+
.app-phone-number-input .phone-dial {
|
|
607
|
+
font-size: 13px;
|
|
608
|
+
font-weight: 500;
|
|
609
|
+
color: var(--color-text);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Menu, search field and rows all share the .search-select language so the
|
|
613
|
+
// country picker reads as the same component family as every other picker.
|
|
614
|
+
// Fixed, with top/left set from the trigger rect by <wui-phone>, so an
|
|
615
|
+
// overflow-hidden card/modal/table wrapper can't clip the list. Sits above the
|
|
616
|
+
// modal layer, matching .search-select-menu-fixed and .datepicker-pop.
|
|
617
|
+
.country-dropdown-menu {
|
|
618
|
+
position: fixed;
|
|
619
|
+
z-index: 1600;
|
|
620
|
+
width: 320px;
|
|
621
|
+
max-width: calc(100vw - 16px);
|
|
622
|
+
padding: 4px;
|
|
623
|
+
border: 1px solid var(--color-border);
|
|
624
|
+
border-radius: var(--radius-lg);
|
|
625
|
+
corner-shape: squircle;
|
|
626
|
+
background: var(--color-surface);
|
|
627
|
+
box-shadow: var(--shadow-overlay);
|
|
628
|
+
overflow: hidden;
|
|
629
|
+
}
|
|
630
|
+
.dropdown-search-wrapper {
|
|
631
|
+
position: relative;
|
|
632
|
+
margin: 4px;
|
|
633
|
+
}
|
|
634
|
+
.dropdown-search-icon {
|
|
635
|
+
position: absolute;
|
|
636
|
+
left: 12px;
|
|
637
|
+
top: 50%;
|
|
638
|
+
transform: translateY(-50%);
|
|
639
|
+
display: flex;
|
|
640
|
+
color: var(--color-text-subtle);
|
|
641
|
+
pointer-events: none;
|
|
642
|
+
transition: color 0.12s ease;
|
|
643
|
+
}
|
|
644
|
+
.dropdown-search-wrapper:focus-within .dropdown-search-icon {
|
|
645
|
+
color: var(--color-primary);
|
|
646
|
+
}
|
|
647
|
+
.dropdown-search-input {
|
|
648
|
+
width: 100%;
|
|
649
|
+
height: 40px;
|
|
650
|
+
padding: 0 12px 0 36px;
|
|
651
|
+
border: 1px solid var(--color-border);
|
|
652
|
+
border-radius: var(--radius);
|
|
653
|
+
corner-shape: squircle;
|
|
654
|
+
font-size: 14px;
|
|
655
|
+
color: var(--color-text);
|
|
656
|
+
background: var(--color-surface);
|
|
657
|
+
outline: none;
|
|
658
|
+
}
|
|
659
|
+
.dropdown-search-input:hover:not(:focus) {
|
|
660
|
+
background: var(--color-bg-muted);
|
|
661
|
+
border-color: var(--color-border-strong);
|
|
662
|
+
}
|
|
663
|
+
// Border is the focus cue everywhere else in the system — no glow ring here.
|
|
664
|
+
.dropdown-search-input:focus {
|
|
665
|
+
background: var(--color-bg-muted);
|
|
666
|
+
border-color: var(--color-primary);
|
|
667
|
+
}
|
|
668
|
+
.country-list-scroll {
|
|
669
|
+
max-height: 250px;
|
|
670
|
+
overflow-y: auto;
|
|
671
|
+
overflow-x: hidden;
|
|
672
|
+
padding: 4px;
|
|
673
|
+
display: flex;
|
|
674
|
+
flex-direction: column;
|
|
675
|
+
gap: 4px;
|
|
676
|
+
scrollbar-width: thin;
|
|
677
|
+
scrollbar-gutter: stable;
|
|
678
|
+
}
|
|
679
|
+
.country-list-scroll::-webkit-scrollbar {
|
|
680
|
+
width: 6px;
|
|
681
|
+
}
|
|
682
|
+
.country-list-scroll::-webkit-scrollbar-thumb {
|
|
683
|
+
background: var(--color-border);
|
|
684
|
+
border-radius: 999px;
|
|
685
|
+
}
|
|
686
|
+
// Rounded, inset rows with a primary-tinted hover — identical to
|
|
687
|
+
// .search-select-option. (!important is required: react-bootstrap's
|
|
688
|
+
// .dropdown-item ships its own colour/padding at equal specificity.)
|
|
689
|
+
.country-dropdown-item {
|
|
690
|
+
display: flex !important;
|
|
691
|
+
align-items: center;
|
|
692
|
+
gap: 10px;
|
|
693
|
+
padding: 9px 14px !important;
|
|
694
|
+
border-radius: var(--radius) !important;
|
|
695
|
+
corner-shape: squircle;
|
|
696
|
+
cursor: pointer;
|
|
697
|
+
color: var(--color-text) !important;
|
|
698
|
+
background: transparent !important;
|
|
699
|
+
border: 0 !important;
|
|
700
|
+
transition:
|
|
701
|
+
background 0.12s ease,
|
|
702
|
+
color 0.12s ease;
|
|
703
|
+
}
|
|
704
|
+
.country-dropdown-item:hover,
|
|
705
|
+
.country-dropdown-item:focus {
|
|
706
|
+
background: var(--color-primary-soft) !important;
|
|
707
|
+
color: var(--color-primary) !important;
|
|
708
|
+
}
|
|
709
|
+
.country-dropdown-item.selected {
|
|
710
|
+
background: var(--color-primary-soft) !important;
|
|
711
|
+
color: var(--color-primary) !important;
|
|
712
|
+
font-weight: 500;
|
|
713
|
+
}
|
|
714
|
+
.country-dropdown-menu .wui-flag {
|
|
715
|
+
flex-shrink: 0;
|
|
716
|
+
}
|
|
717
|
+
.country-name-text {
|
|
718
|
+
font-size: 14px;
|
|
719
|
+
font-weight: 500;
|
|
720
|
+
color: var(--color-text);
|
|
721
|
+
}
|
|
722
|
+
.country-code-text {
|
|
723
|
+
margin-left: 6px;
|
|
724
|
+
font-weight: 400;
|
|
725
|
+
color: var(--color-text-muted);
|
|
726
|
+
}
|
|
727
|
+
// On a tinted row the label must ride the row colour, not stay grey.
|
|
728
|
+
.country-dropdown-item:hover .country-name-text,
|
|
729
|
+
.country-dropdown-item:focus .country-name-text,
|
|
730
|
+
.country-dropdown-item.selected .country-name-text,
|
|
731
|
+
.country-dropdown-item:hover .country-code-text,
|
|
732
|
+
.country-dropdown-item:focus .country-code-text,
|
|
733
|
+
.country-dropdown-item.selected .country-code-text {
|
|
734
|
+
color: currentColor;
|
|
735
|
+
}
|
|
736
|
+
.selected-check-icon {
|
|
737
|
+
margin-left: auto;
|
|
738
|
+
display: flex;
|
|
739
|
+
color: var(--color-primary);
|
|
740
|
+
}
|
|
741
|
+
.country-empty {
|
|
742
|
+
padding: 10px 16px;
|
|
743
|
+
text-align: center;
|
|
744
|
+
color: var(--color-text-subtle);
|
|
745
|
+
font-size: 14px;
|
|
746
|
+
}
|