non-spooky-react-cookie 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,624 @@
1
+ /*
2
+ * non-spooky-react-cookie — the one stylesheet.
3
+ *
4
+ * Import it once in your app:
5
+ * import "non-spooky-react-cookie/styles.css";
6
+ *
7
+ * Every color, radius and z-index is a `--nsr-*` custom property. Override
8
+ * them globally (on `:root`), per theme (`.dark` or `[data-theme="dark"]`),
9
+ * or per provider via the `theme` / `darkTheme` props, which write the same
10
+ * properties into a scoped `<style>` rule for the banner, dialog and settings
11
+ * link. No Tailwind required; every component also accepts `className` props
12
+ * if you want to add your own.
13
+ *
14
+ * Five colors are the real inputs: primary, primary-text, accent, surface and
15
+ * text. Everything else (muted text, borders, secondary buttons, hover
16
+ * backgrounds, switch track/thumb, focus ring) is derived from those with
17
+ * `color-mix()` on the component roots, so a custom surface or text color
18
+ * never leaves stale defaults behind. Set the derived variable yourself to
19
+ * opt out of the derivation for that one color.
20
+ *
21
+ * On phones (under 640px) the settings dialog is a bottom sheet, the banner
22
+ * and dialog respect `env(safe-area-inset-*)`, and every control has a tap
23
+ * target of at least 44px.
24
+ */
25
+
26
+ :root {
27
+ --nsr-primary: #155e75;
28
+ --nsr-primary-text: #ffffff;
29
+ --nsr-accent: #0e7490;
30
+ --nsr-surface: #ffffff;
31
+ --nsr-text: #09090b;
32
+ --nsr-backdrop: rgb(9 9 11 / 0.6);
33
+ --nsr-radius: 1rem;
34
+ --nsr-font: inherit;
35
+ --nsr-z-banner: 90;
36
+ --nsr-z-dialog: 100;
37
+ }
38
+
39
+ .dark,
40
+ [data-theme="dark"] {
41
+ --nsr-primary: #22d3ee;
42
+ --nsr-primary-text: #083344;
43
+ --nsr-accent: #22d3ee;
44
+ --nsr-surface: #09090b;
45
+ --nsr-text: #fafafa;
46
+ }
47
+
48
+ /*
49
+ * Derived colors, resolved on the component roots so they see the values
50
+ * the `theme` prop / a `.dark` ancestor set for *this* banner or dialog.
51
+ * `--nsr-<name>` (public, unset by default) wins over the derivation.
52
+ */
53
+ .nsr-banner,
54
+ .nsr-settings-dialog,
55
+ .nsr-settings-link {
56
+ --_nsr-muted: var(
57
+ --nsr-muted,
58
+ color-mix(in srgb, var(--nsr-text) 65%, var(--nsr-surface))
59
+ );
60
+ --_nsr-border: var(
61
+ --nsr-border,
62
+ color-mix(in srgb, var(--nsr-text) 12%, var(--nsr-surface))
63
+ );
64
+ --_nsr-surface-muted: var(
65
+ --nsr-surface-muted,
66
+ color-mix(in srgb, var(--nsr-text) 4%, var(--nsr-surface))
67
+ );
68
+ --_nsr-secondary: var(--nsr-secondary, var(--nsr-surface));
69
+ --_nsr-secondary-text: var(--nsr-secondary-text, var(--nsr-text));
70
+ --_nsr-primary-hover: var(
71
+ --nsr-primary-hover,
72
+ color-mix(in srgb, var(--nsr-primary) 85%, var(--nsr-primary-text))
73
+ );
74
+ --_nsr-ring: var(--nsr-ring, var(--nsr-primary));
75
+ --_nsr-switch-off: var(
76
+ --nsr-switch-off,
77
+ color-mix(in srgb, var(--nsr-text) 22%, var(--nsr-surface))
78
+ );
79
+ /* Off: the surface color sits on the tinted track. On: the primary text
80
+ color, which the palette already guarantees to contrast the primary. */
81
+ --_nsr-switch-thumb-off: var(--nsr-switch-thumb, var(--nsr-surface));
82
+ --_nsr-switch-thumb-on: var(--nsr-switch-thumb, var(--nsr-primary-text));
83
+ --_nsr-switch-thumb-ring: color-mix(in srgb, var(--nsr-text) 15%, transparent);
84
+ }
85
+
86
+ /* ---------------------------------------------------------------- reset */
87
+
88
+ .nsr-banner,
89
+ .nsr-banner *,
90
+ .nsr-settings-dialog,
91
+ .nsr-settings-dialog * {
92
+ box-sizing: border-box;
93
+ }
94
+
95
+ /* --------------------------------------------------------------- banner */
96
+
97
+ .nsr-banner {
98
+ position: fixed;
99
+ inset-inline: 0;
100
+ bottom: 0;
101
+ z-index: var(--nsr-z-banner);
102
+ /* A long description on a small phone scrolls inside the banner instead
103
+ of pushing the buttons off screen. */
104
+ max-height: 100vh;
105
+ overflow-y: auto;
106
+ border-top: 1px solid var(--_nsr-border);
107
+ background: color-mix(in srgb, var(--nsr-surface) 95%, transparent);
108
+ padding: 1rem;
109
+ /* Stay clear of the home indicator / rounded corners on notched phones. */
110
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
111
+ padding-left: max(1rem, env(safe-area-inset-left));
112
+ padding-right: max(1rem, env(safe-area-inset-right));
113
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
114
+ backdrop-filter: blur(12px);
115
+ -webkit-backdrop-filter: blur(12px);
116
+ font-family: var(--nsr-font);
117
+ color: var(--nsr-text);
118
+ }
119
+
120
+ .nsr-banner__card {
121
+ margin: 0 auto;
122
+ display: flex;
123
+ max-width: 72rem;
124
+ flex-direction: column;
125
+ gap: 1rem;
126
+ border-radius: var(--nsr-radius);
127
+ border: 1px solid var(--_nsr-border);
128
+ background: var(--nsr-surface);
129
+ padding: 1.25rem;
130
+ box-shadow:
131
+ 0 20px 25px -5px rgb(0 0 0 / 0.1),
132
+ 0 8px 10px -6px rgb(0 0 0 / 0.1);
133
+ }
134
+
135
+ .nsr-banner__text {
136
+ max-width: 48rem;
137
+ }
138
+
139
+ .nsr-banner__title {
140
+ margin: 0;
141
+ font-size: 1rem;
142
+ line-height: 1.5rem;
143
+ font-weight: 700;
144
+ color: var(--nsr-text);
145
+ }
146
+
147
+ .nsr-banner__description {
148
+ margin: 0.5rem 0 0;
149
+ font-size: 0.875rem;
150
+ line-height: 1.5rem;
151
+ color: var(--_nsr-muted);
152
+ }
153
+
154
+ .nsr-banner__link {
155
+ font-weight: 600;
156
+ color: var(--nsr-accent);
157
+ text-decoration: none;
158
+ text-underline-offset: 4px;
159
+ }
160
+
161
+ .nsr-banner__link:hover {
162
+ text-decoration: underline;
163
+ }
164
+
165
+ .nsr-banner__actions {
166
+ display: grid;
167
+ gap: 0.5rem;
168
+ }
169
+
170
+ @media (min-width: 640px) {
171
+ .nsr-banner__actions {
172
+ grid-template-columns: repeat(3, minmax(0, 1fr));
173
+ }
174
+ }
175
+
176
+ @media (min-width: 1024px) {
177
+ .nsr-banner__card {
178
+ flex-direction: row;
179
+ align-items: center;
180
+ justify-content: space-between;
181
+ }
182
+
183
+ .nsr-banner__actions {
184
+ min-width: 32rem;
185
+ }
186
+ }
187
+
188
+ /* --------------------------------------------------------------- button */
189
+
190
+ .nsr-button {
191
+ display: inline-flex;
192
+ min-height: 2.5rem;
193
+ align-items: center;
194
+ justify-content: center;
195
+ border-radius: calc(var(--nsr-radius) * 0.75);
196
+ border: 1px solid transparent;
197
+ padding: 0.5rem 1rem;
198
+ font: inherit;
199
+ font-size: 0.875rem;
200
+ line-height: 1.25rem;
201
+ font-weight: 600;
202
+ text-align: center;
203
+ cursor: pointer;
204
+ touch-action: manipulation;
205
+ transition:
206
+ background-color 0.15s ease,
207
+ color 0.15s ease;
208
+ }
209
+
210
+ .nsr-button:disabled {
211
+ pointer-events: none;
212
+ opacity: 0.5;
213
+ }
214
+
215
+ .nsr-button--primary {
216
+ background: var(--nsr-primary);
217
+ color: var(--nsr-primary-text);
218
+ }
219
+
220
+ .nsr-button--primary:hover {
221
+ background: var(--_nsr-primary-hover);
222
+ }
223
+
224
+ .nsr-button--secondary {
225
+ border-color: var(--_nsr-border);
226
+ background: var(--_nsr-secondary);
227
+ color: var(--_nsr-secondary-text);
228
+ }
229
+
230
+ .nsr-button--secondary:hover {
231
+ background: var(--_nsr-surface-muted);
232
+ }
233
+
234
+ .nsr-button--ghost {
235
+ background: transparent;
236
+ color: var(--_nsr-muted);
237
+ }
238
+
239
+ .nsr-button--ghost:hover {
240
+ background: var(--_nsr-surface-muted);
241
+ color: var(--nsr-text);
242
+ }
243
+
244
+ /* --------------------------------------------------------------- switch */
245
+
246
+ .nsr-switch {
247
+ position: relative;
248
+ display: inline-flex;
249
+ height: 1.5rem;
250
+ width: 2.75rem;
251
+ flex-shrink: 0;
252
+ align-items: center;
253
+ border-radius: 9999px;
254
+ border: 2px solid transparent;
255
+ padding: 0;
256
+ background: var(--_nsr-switch-off);
257
+ cursor: pointer;
258
+ touch-action: manipulation;
259
+ transition: background-color 0.15s ease;
260
+ }
261
+
262
+ /* The track is 24px tall; this pads the tap target to 44px without changing
263
+ how the switch looks. `inset` counts from the padding box, so the 2px
264
+ border is included: 12px - 2px = 10px beyond the visible edge. */
265
+ .nsr-switch::before {
266
+ content: "";
267
+ position: absolute;
268
+ inset: -0.75rem -0.375rem;
269
+ }
270
+
271
+ .nsr-switch[aria-checked="true"] {
272
+ background: var(--nsr-primary);
273
+ }
274
+
275
+ .nsr-switch:disabled {
276
+ cursor: not-allowed;
277
+ opacity: 0.6;
278
+ }
279
+
280
+ .nsr-switch__thumb {
281
+ pointer-events: none;
282
+ display: block;
283
+ height: 1.25rem;
284
+ width: 1.25rem;
285
+ border-radius: 9999px;
286
+ background: var(--_nsr-switch-thumb-off);
287
+ box-shadow:
288
+ 0 0 0 1px var(--_nsr-switch-thumb-ring),
289
+ 0 4px 6px -2px rgb(0 0 0 / 0.2);
290
+ transform: translateX(0);
291
+ transition:
292
+ transform 0.15s ease,
293
+ background-color 0.15s ease;
294
+ }
295
+
296
+ .nsr-switch[aria-checked="true"] .nsr-switch__thumb {
297
+ background: var(--_nsr-switch-thumb-on);
298
+ transform: translateX(1.25rem);
299
+ }
300
+
301
+ /* translateX has no logical form, so right-to-left moves the thumb the other way. */
302
+ .nsr-switch[aria-checked="true"]:dir(rtl) .nsr-switch__thumb {
303
+ transform: translateX(-1.25rem);
304
+ }
305
+
306
+ /* ---------------------------------------------------------- collapsible */
307
+
308
+ .nsr-collapsible__trigger {
309
+ display: flex;
310
+ width: 100%;
311
+ align-items: center;
312
+ justify-content: space-between;
313
+ gap: 0.5rem;
314
+ border: 0;
315
+ min-height: 2.75rem;
316
+ border-radius: 0.5rem;
317
+ background: transparent;
318
+ padding: 0.25rem 0;
319
+ font: inherit;
320
+ text-align: start;
321
+ cursor: pointer;
322
+ touch-action: manipulation;
323
+ }
324
+
325
+ .nsr-collapsible__label {
326
+ font-size: 0.75rem;
327
+ line-height: 1rem;
328
+ font-weight: 600;
329
+ color: var(--nsr-accent);
330
+ }
331
+
332
+ .nsr-collapsible__chevron {
333
+ height: 1.5rem;
334
+ width: 1.5rem;
335
+ flex-shrink: 0;
336
+ color: var(--nsr-accent);
337
+ transition: transform 0.2s ease;
338
+ }
339
+
340
+ .nsr-collapsible--open .nsr-collapsible__chevron {
341
+ transform: rotate(180deg);
342
+ }
343
+
344
+ /* --------------------------------------------------------------- dialog */
345
+
346
+ .nsr-settings-dialog {
347
+ position: fixed;
348
+ inset: 0;
349
+ z-index: var(--nsr-z-dialog);
350
+ margin: 0;
351
+ width: 100%;
352
+ height: 100%;
353
+ max-width: none;
354
+ max-height: none;
355
+ border: 0;
356
+ padding: 1rem;
357
+ background: transparent;
358
+ color: var(--nsr-text);
359
+ font-family: var(--nsr-font);
360
+ }
361
+
362
+ .nsr-settings-dialog[open] {
363
+ display: flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ }
367
+
368
+ /* Only exists while the dialog is open via showModal(). Inherits from the dialog. */
369
+ .nsr-settings-dialog::backdrop {
370
+ background: var(--nsr-backdrop, rgb(9 9 11 / 0.6));
371
+ backdrop-filter: blur(4px);
372
+ -webkit-backdrop-filter: blur(4px);
373
+ }
374
+
375
+ .nsr-dialog__overlay {
376
+ position: absolute;
377
+ inset: 0;
378
+ z-index: 0;
379
+ border: 0;
380
+ padding: 0;
381
+ background: transparent;
382
+ cursor: default;
383
+ }
384
+
385
+ .nsr-dialog__panel {
386
+ position: relative;
387
+ z-index: 1;
388
+ display: flex;
389
+ max-height: 90vh;
390
+ width: 100%;
391
+ max-width: 42rem;
392
+ flex-direction: column;
393
+ overflow: hidden;
394
+ border-radius: var(--nsr-radius);
395
+ border: 1px solid var(--_nsr-border);
396
+ background: var(--nsr-surface);
397
+ box-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
398
+ }
399
+
400
+ .nsr-dialog__header {
401
+ flex-shrink: 0;
402
+ border-bottom: 1px solid var(--_nsr-border);
403
+ padding: 1rem;
404
+ }
405
+
406
+ .nsr-dialog__title {
407
+ margin: 0;
408
+ font-size: 1.125rem;
409
+ line-height: 1.75rem;
410
+ font-weight: 700;
411
+ color: var(--nsr-text);
412
+ }
413
+
414
+ .nsr-dialog__description {
415
+ margin: 0.375rem 0 0;
416
+ font-size: 0.875rem;
417
+ line-height: 1.25rem;
418
+ color: var(--_nsr-muted);
419
+ }
420
+
421
+ .nsr-dialog__body {
422
+ min-height: 0;
423
+ flex: 1 1 auto;
424
+ display: grid;
425
+ align-content: start;
426
+ gap: 0.75rem;
427
+ overflow-y: auto;
428
+ padding: 1rem;
429
+ }
430
+
431
+ .nsr-dialog__footer {
432
+ display: flex;
433
+ flex-shrink: 0;
434
+ flex-direction: column-reverse;
435
+ gap: 0.5rem;
436
+ border-top: 1px solid var(--_nsr-border);
437
+ padding: 1rem;
438
+ }
439
+
440
+ .nsr-dialog__button {
441
+ width: 100%;
442
+ }
443
+
444
+ /* Phones: the dialog becomes a bottom sheet. The Save / Close buttons end up
445
+ under the thumb, the sheet respects the home indicator, and a long list of
446
+ categories scrolls inside the body while the footer stays put. */
447
+ @media (max-width: 639.98px) {
448
+ .nsr-settings-dialog {
449
+ padding: 0;
450
+ }
451
+
452
+ .nsr-settings-dialog[open] {
453
+ align-items: flex-end;
454
+ }
455
+
456
+ .nsr-dialog__panel {
457
+ max-height: 92vh;
458
+ border-bottom: 0;
459
+ border-bottom-left-radius: 0;
460
+ border-bottom-right-radius: 0;
461
+ }
462
+
463
+ .nsr-dialog__footer {
464
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
465
+ padding-left: max(1rem, env(safe-area-inset-left));
466
+ padding-right: max(1rem, env(safe-area-inset-right));
467
+ }
468
+ }
469
+
470
+ @media (min-width: 640px) {
471
+ .nsr-dialog__header {
472
+ padding: 1.5rem;
473
+ }
474
+
475
+ .nsr-dialog__title {
476
+ font-size: 1.25rem;
477
+ }
478
+
479
+ .nsr-dialog__description {
480
+ margin-top: 0.5rem;
481
+ line-height: 1.5rem;
482
+ }
483
+
484
+ .nsr-dialog__body {
485
+ padding: 1.5rem;
486
+ }
487
+
488
+ .nsr-dialog__footer {
489
+ flex-direction: row;
490
+ justify-content: flex-end;
491
+ gap: 0.75rem;
492
+ padding: 1.5rem;
493
+ }
494
+
495
+ .nsr-dialog__button {
496
+ width: auto;
497
+ }
498
+ }
499
+
500
+ /* Mobile browsers: size against the visible area, not the area behind the
501
+ address bar. `vh` above is the fallback where `dvh` is unsupported. */
502
+ @supports (height: 1dvh) {
503
+ .nsr-banner {
504
+ max-height: 100dvh;
505
+ }
506
+
507
+ .nsr-dialog__panel {
508
+ max-height: 90dvh;
509
+ }
510
+
511
+ @media (max-width: 639.98px) {
512
+ .nsr-dialog__panel {
513
+ max-height: 92dvh;
514
+ }
515
+ }
516
+ }
517
+
518
+ /* ------------------------------------------------------------- category */
519
+
520
+ .nsr-category {
521
+ border-radius: var(--nsr-radius);
522
+ border: 1px solid var(--_nsr-border);
523
+ padding: 1rem;
524
+ }
525
+
526
+ .nsr-category--required {
527
+ background: var(--_nsr-surface-muted);
528
+ }
529
+
530
+ .nsr-category__header {
531
+ display: flex;
532
+ align-items: flex-start;
533
+ justify-content: space-between;
534
+ gap: 1rem;
535
+ }
536
+
537
+ .nsr-category__title {
538
+ margin: 0;
539
+ font-size: 1rem;
540
+ line-height: 1.5rem;
541
+ font-weight: 600;
542
+ color: var(--nsr-text);
543
+ }
544
+
545
+ .nsr-category__description {
546
+ margin: 0.25rem 0 0;
547
+ font-size: 0.875rem;
548
+ line-height: 1.5rem;
549
+ color: var(--_nsr-muted);
550
+ }
551
+
552
+ .nsr-category__items {
553
+ margin-top: 0.5rem;
554
+ display: grid;
555
+ gap: 0.5rem;
556
+ border-top: 1px solid var(--_nsr-border);
557
+ padding-top: 0.75rem;
558
+ }
559
+
560
+ .nsr-item {
561
+ display: flex;
562
+ align-items: flex-start;
563
+ justify-content: space-between;
564
+ gap: 1rem;
565
+ border-radius: 0.75rem;
566
+ padding: 0.375rem 0.5rem;
567
+ }
568
+
569
+ .nsr-item__title {
570
+ margin: 0;
571
+ font-size: 0.875rem;
572
+ line-height: 1.25rem;
573
+ font-weight: 500;
574
+ color: var(--nsr-text);
575
+ }
576
+
577
+ .nsr-item__description {
578
+ margin: 0.125rem 0 0;
579
+ font-size: 0.75rem;
580
+ line-height: 1.25rem;
581
+ color: var(--_nsr-muted);
582
+ }
583
+
584
+ /* -------------------------------------------------------- settings link */
585
+
586
+ .nsr-settings-link {
587
+ display: inline-flex;
588
+ align-items: center;
589
+ min-height: 2.5rem;
590
+ border: 0;
591
+ padding: 0;
592
+ background: none;
593
+ font: inherit;
594
+ color: inherit;
595
+ text-align: start;
596
+ cursor: pointer;
597
+ touch-action: manipulation;
598
+ transition: color 0.15s ease;
599
+ }
600
+
601
+ .nsr-settings-link:hover {
602
+ color: var(--nsr-accent);
603
+ }
604
+
605
+ /* ---------------------------------------------------------------- focus */
606
+
607
+ .nsr-button:focus-visible,
608
+ .nsr-switch:focus-visible,
609
+ .nsr-collapsible__trigger:focus-visible,
610
+ .nsr-settings-link:focus-visible,
611
+ .nsr-banner__link:focus-visible {
612
+ outline: 2px solid var(--_nsr-ring);
613
+ outline-offset: 2px;
614
+ }
615
+
616
+ @media (prefers-reduced-motion: reduce) {
617
+ .nsr-button,
618
+ .nsr-switch,
619
+ .nsr-switch__thumb,
620
+ .nsr-collapsible__chevron,
621
+ .nsr-settings-link {
622
+ transition: none;
623
+ }
624
+ }