@carissa-io/theme-default 0.3.1 → 0.3.3

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/DESIGN.md CHANGED
@@ -45,12 +45,19 @@ Both modes ship in the same package; dark is **opt-in per app** with `data-mode`
45
45
  | `disabled-text` | `#a3a3a3` | `#737373` |
46
46
  | `disabled-border` | `#d4d4d4` | `#404040` |
47
47
  | `error` | `#dc3545` | `#f87171` |
48
+ | `success` | `#15803d` | `#4ade80` |
49
+ | `warning` | `#a16207` | `#fbbf24` |
50
+ | `info` | `#1d4ed8` | `#60a5fa` |
48
51
  | `focus` | `#000000` | `#ffffff` |
49
52
 
50
53
  Decisions: dark inverts the contrast of the light theme, it does not invent a new look (near-black ground, the primary action becomes white,
51
54
  square corners and the 1px focus ring stay). The ground is `#0a0a0a`, not pure black, so surfaces (`#171717`) can be told apart. Primary and focus
52
55
  are pure white as black is in light. The error red is lighter (`#f87171`) because `#dc3545` is too dim on a dark ground.
53
56
 
57
+ The status roles `success`, `warning` and `info` (with `error`, the four colors of the Alert) are chosen to pass 4.5:1 as text on both `background` and
58
+ `surface` in each mode (the same value is 3:1 or more as a border or an icon on the background). In light they are the 700 steps of green, amber and blue
59
+ (`#15803d`, `#a16207`, `#1d4ed8`); in dark the 400 steps (`#4ade80`, `#fbbf24`, `#60a5fa`). The light warning on the surface is the tightest pair (4.52).
60
+
54
61
  Contrast (WCAG 2.x): text 4.5:1, borders and the focus ring 3:1.
55
62
 
56
63
  | Pair | Light | Dark |
@@ -61,8 +68,14 @@ Contrast (WCAG 2.x): text 4.5:1, borders and the focus ring 3:1.
61
68
  | `on-primary` on `primary` | 21.00 | 21.00 |
62
69
  | `error` on `background` | 4.53 | 7.16 |
63
70
  | `focus` on `background` | 21.00 | 19.80 |
71
+ | `success` on `background` / on `surface` | 5.02 / 4.60 | 11.36 / 10.29 |
72
+ | `warning` on `background` / on `surface` | 4.92 / 4.52 | 11.86 / 10.74 |
73
+ | `info` on `background` / on `surface` | 6.70 / 6.15 | 7.79 / 7.05 |
74
+ | `error` on `surface` | 4.15 | 6.48 |
64
75
  | `disabled-text` on `surface` (disabled, exempt) | 2.31 | 3.78 |
65
76
 
77
+ The light `error` on `surface` (4.15) is below 4.5 for text, so the Alert never sets text in the status color (only the icon and the accent border, which need 3:1).
78
+
66
79
  `muted` on `surface` in light (4.35) is a known gap that already existed (muted text on the hover surface); the disabled states are exempt from
67
80
  WCAG but are listed in the backlog for a contrast review. Known gap in dark: the 0-width listbox option separator keeps the component default
68
81
  (`#dee2e6`); it draws nothing today.
@@ -224,6 +237,22 @@ field has the focus. The clear button appears on the right only while there is t
224
237
  Errors, required marker and disabled look are the Input's. The Input and Textarea accept `start` and `end` content (a prefix
225
238
  icon, a unit) in the same muted color (`#737373`) with `0.5rem` between the content and the text.
226
239
 
240
+ ## Card
241
+ From [components-card](components/components-card): `Card` with `CardHeader`, `CardBody` and `CardFooter`; the title and description are the Typography
242
+ `Heading` (level 4 size) and the small muted `Text`. Square corners (`$radius`), 1.5rem at the sides and 1.25rem above and below each part. Colors come only
243
+ from the custom properties, so the card works in both modes.
244
+
245
+ - **Outlined (default):** `--c-background` with a 1px `--c-muted` border.
246
+ - **Filled:** `--c-surface`, same border.
247
+ - **Elevated:** the outlined card plus a subtle layered shadow (`0 1px 2px` and `0 4px 12px` of black at 6% and 8%). The border stays on purpose: a shadow
248
+ is almost invisible on the dark ground, the border keeps the edge in dark mode.
249
+
250
+ ## Alert
251
+ From [components-alert](components/components-alert): `Alert` in `info`, `success`, `warning` and `error`. A box **tinted with the variant color** (12% of `--c-info`, `--c-success`, `--c-warning` or `--c-error` mixed over `--c-background` with `color-mix`, so it follows the mode) with a 1px border at 35% of the same color
252
+ and a **4px accent on the left edge** in the variant color (`--c-info`, `--c-success`, `--c-warning`, `--c-error`); the icon, when given, has the same color.
253
+ The text and the title are `--c-text`, 14.8:1 or more on every tint in both modes; the accent and the icon are at least 3.8:1 on the tint (the status colors are not used for text: see the contrast notes in [Dark mode](#dark-mode)). The title is bold, the text
254
+ 0.875rem, square corners. The dismiss button is a plain "x" in `--c-muted`, `--c-text` on hover, with the usual focus ring.
255
+
227
256
  ## Keyboard focus (all controls)
228
257
  One rule keeps the controls coherent: **an outlined control thickens its own border from 1px to 2px, black** (text fields,
229
258
  select, combobox, date picker, textarea, upload, empty checkbox, off switch, radio, secondary and ghost buttons); **a filled
package/README.md CHANGED
@@ -29,7 +29,7 @@ peer dependencies).
29
29
  ## Color modes
30
30
  The theme has a light and a dark palette in one package. The palette is a set of CSS custom properties (`--c-background`, `--c-text`,
31
31
  `--c-muted`, `--c-surface`, `--c-surface-active`, `--c-primary`, `--c-on-primary`, `--c-primary-hover`, `--c-primary-active`,
32
- `--c-disabled-text`, `--c-disabled-border`, `--c-error`, `--c-focus`) that every component reads. **Dark is opt-in per app**: without
32
+ `--c-disabled-text`, `--c-disabled-border`, `--c-error`, `--c-success`, `--c-warning`, `--c-info`, `--c-focus`) that every component reads. **Dark is opt-in per app**: without
33
33
  the attribute below the app is light, exactly as before.
34
34
 
35
35
  An app opts in with one line in the file where it imports the theme (`App/theme.js`), setting the mode on `<html>`:
@@ -86,6 +86,9 @@ change.
86
86
  | `$disabled-text` | `#a3a3a3` | disabled text and marks |
87
87
  | `$disabled-border` | `#d4d4d4` | disabled borders |
88
88
  | `$error` | `#dc3545` | error text and borders |
89
+ | `$success` | `#15803d` | success accent and icon (Alert) |
90
+ | `$warning` | `#a16207` | warning accent and icon (Alert) |
91
+ | `$info` | `#1d4ed8` | info accent and icon (Alert) |
89
92
  | `$font-family` | `'Helvetica Neue', Helvetica, Arial, 'Liberation Sans', sans-serif` | type stack |
90
93
  | `$font-family-mono` | `ui-monospace, 'SFMono-Regular', Menlo, Consolas, 'Liberation Mono', monospace` | monospace stack for system data and code |
91
94
  | `$radius` | `0` | corner radius |
@@ -139,7 +142,7 @@ it: check the names against the theme's `scss/_tokens.scss` before you switch.
139
142
 
140
143
  ## What it configures
141
144
  `components-input`, `-button`, `-checkbox`, `-switch`, `-radio-group`, `-slider`, `-popover`, `-listbox`, `-select`,
142
- `-combobox`, `-upload`, `-calendar`, `-date-picker`, `-search` and `-typography`. `components-email`, `-password`, `-url` and `-textarea`
145
+ `-combobox`, `-upload`, `-calendar`, `-date-picker`, `-search`, `-typography`, `-card` and `-alert`. `components-email`, `-password`, `-url` and `-textarea`
143
146
  are styled through the input.
144
147
 
145
148
  ## Change a value
package/dist/index.css CHANGED
@@ -11,6 +11,9 @@
11
11
  --c-disabled-text: #a3a3a3;
12
12
  --c-disabled-border: #d4d4d4;
13
13
  --c-error: #dc3545;
14
+ --c-success: #15803d;
15
+ --c-warning: #a16207;
16
+ --c-info: #1d4ed8;
14
17
  --c-focus: #000;
15
18
  color-scheme: light;
16
19
  }
@@ -28,6 +31,9 @@
28
31
  --c-disabled-text: #a3a3a3;
29
32
  --c-disabled-border: #d4d4d4;
30
33
  --c-error: #dc3545;
34
+ --c-success: #15803d;
35
+ --c-warning: #a16207;
36
+ --c-info: #1d4ed8;
31
37
  --c-focus: #000;
32
38
  color-scheme: light;
33
39
  }
@@ -45,6 +51,9 @@
45
51
  --c-disabled-text: #737373;
46
52
  --c-disabled-border: #404040;
47
53
  --c-error: #f87171;
54
+ --c-success: #4ade80;
55
+ --c-warning: #fbbf24;
56
+ --c-info: #60a5fa;
48
57
  --c-focus: #fff;
49
58
  color-scheme: dark;
50
59
  }
@@ -63,6 +72,9 @@
63
72
  --c-disabled-text: #737373;
64
73
  --c-disabled-border: #404040;
65
74
  --c-error: #f87171;
75
+ --c-success: #4ade80;
76
+ --c-warning: #fbbf24;
77
+ --c-info: #60a5fa;
66
78
  --c-focus: #fff;
67
79
  color-scheme: dark;
68
80
  }
@@ -1336,3 +1348,153 @@
1336
1348
  .c-text--muted {
1337
1349
  color: var(--c-muted);
1338
1350
  }
1351
+
1352
+ .c-card {
1353
+ box-sizing: border-box;
1354
+ min-width: 0;
1355
+ color: var(--c-text);
1356
+ background: var(--c-background);
1357
+ border: 1px solid var(--c-muted);
1358
+ border-radius: 0;
1359
+ }
1360
+
1361
+ .c-card--filled {
1362
+ background: var(--c-surface);
1363
+ }
1364
+
1365
+ .c-card--elevated {
1366
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.08);
1367
+ }
1368
+
1369
+ .c-card__header {
1370
+ display: flex;
1371
+ flex-wrap: wrap;
1372
+ gap: 0.25rem;
1373
+ align-items: flex-start;
1374
+ justify-content: space-between;
1375
+ padding: 1.25rem 1.5rem;
1376
+ }
1377
+
1378
+ .c-card__title-block {
1379
+ display: flex;
1380
+ flex: 1 1 auto;
1381
+ flex-direction: column;
1382
+ gap: 0.25rem;
1383
+ min-width: 0;
1384
+ }
1385
+
1386
+ .c-card__actions {
1387
+ display: flex;
1388
+ flex: none;
1389
+ gap: 0.25rem;
1390
+ align-items: center;
1391
+ }
1392
+
1393
+ .c-card__body {
1394
+ padding: 1.25rem 1.5rem;
1395
+ }
1396
+
1397
+ .c-card__footer {
1398
+ padding: 1.25rem 1.5rem;
1399
+ }
1400
+
1401
+ .c-alert {
1402
+ box-sizing: border-box;
1403
+ display: flex;
1404
+ gap: 0.75rem;
1405
+ align-items: flex-start;
1406
+ padding: 0.875rem 1rem;
1407
+ font-size: 0.875rem;
1408
+ border: 1px solid;
1409
+ border-left-width: 4px;
1410
+ border-radius: 0;
1411
+ }
1412
+
1413
+ .c-alert__icon {
1414
+ display: inline-flex;
1415
+ flex: none;
1416
+ }
1417
+
1418
+ .c-alert__content {
1419
+ flex: 1 1 auto;
1420
+ min-width: 0;
1421
+ }
1422
+
1423
+ .c-alert__title {
1424
+ display: block;
1425
+ font-weight: 700;
1426
+ }
1427
+
1428
+ .c-alert__dismiss {
1429
+ display: inline-flex;
1430
+ flex: none;
1431
+ align-items: center;
1432
+ justify-content: center;
1433
+ padding: 0;
1434
+ margin-left: auto;
1435
+ font-size: 1rem;
1436
+ line-height: 1;
1437
+ color: var(--c-muted);
1438
+ cursor: pointer;
1439
+ background: none;
1440
+ border: 0;
1441
+ }
1442
+ .c-alert__dismiss:hover {
1443
+ color: var(--c-text);
1444
+ }
1445
+ .c-alert__dismiss:focus-visible {
1446
+ outline: 2px solid currentColor;
1447
+ outline-offset: 2px;
1448
+ }
1449
+
1450
+ .c-alert--info {
1451
+ color: var(--c-text);
1452
+ background: color-mix(in srgb, var(--c-info) 12%, var(--c-background));
1453
+ border-color: color-mix(in srgb, var(--c-info) 35%, var(--c-background));
1454
+ border-left-color: var(--c-info);
1455
+ }
1456
+ .c-alert--info .c-alert__icon {
1457
+ color: var(--c-info);
1458
+ }
1459
+ .c-alert--info .c-alert__title {
1460
+ color: var(--c-text);
1461
+ }
1462
+
1463
+ .c-alert--success {
1464
+ color: var(--c-text);
1465
+ background: color-mix(in srgb, var(--c-success) 12%, var(--c-background));
1466
+ border-color: color-mix(in srgb, var(--c-success) 35%, var(--c-background));
1467
+ border-left-color: var(--c-success);
1468
+ }
1469
+ .c-alert--success .c-alert__icon {
1470
+ color: var(--c-success);
1471
+ }
1472
+ .c-alert--success .c-alert__title {
1473
+ color: var(--c-text);
1474
+ }
1475
+
1476
+ .c-alert--warning {
1477
+ color: var(--c-text);
1478
+ background: color-mix(in srgb, var(--c-warning) 12%, var(--c-background));
1479
+ border-color: color-mix(in srgb, var(--c-warning) 35%, var(--c-background));
1480
+ border-left-color: var(--c-warning);
1481
+ }
1482
+ .c-alert--warning .c-alert__icon {
1483
+ color: var(--c-warning);
1484
+ }
1485
+ .c-alert--warning .c-alert__title {
1486
+ color: var(--c-text);
1487
+ }
1488
+
1489
+ .c-alert--error {
1490
+ color: var(--c-text);
1491
+ background: color-mix(in srgb, var(--c-error) 12%, var(--c-background));
1492
+ border-color: color-mix(in srgb, var(--c-error) 35%, var(--c-background));
1493
+ border-left-color: var(--c-error);
1494
+ }
1495
+ .c-alert--error .c-alert__icon {
1496
+ color: var(--c-error);
1497
+ }
1498
+ .c-alert--error .c-alert__title {
1499
+ color: var(--c-text);
1500
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carissa-io/theme-default",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Carissa UI: the default theme (Swiss minimalism) as SCSS variable overrides of the Carissa components, with a compiled CSS build",
5
5
  "type": "module",
6
6
  "style": "dist/index.css",
@@ -52,7 +52,9 @@
52
52
  "@carissa-io/components-calendar": "^0.1.1",
53
53
  "@carissa-io/components-date-picker": "^0.1.1",
54
54
  "@carissa-io/components-search": "^0.1.1",
55
- "@carissa-io/components-typography": "^0.1.0"
55
+ "@carissa-io/components-typography": "^0.1.0",
56
+ "@carissa-io/components-card": "^0.1.0",
57
+ "@carissa-io/components-alert": "^0.1.0"
56
58
  },
57
59
  "peerDependenciesMeta": {
58
60
  "@carissa-io/components-input": {
@@ -111,11 +113,19 @@
111
113
  },
112
114
  "@carissa-io/components-typography": {
113
115
  "optional": true
116
+ },
117
+ "@carissa-io/components-card": {
118
+ "optional": true
119
+ },
120
+ "@carissa-io/components-alert": {
121
+ "optional": true
114
122
  }
115
123
  },
116
124
  "devDependencies": {
125
+ "@carissa-io/components-alert": "^0.1.0",
117
126
  "@carissa-io/components-button": "^0.1.1",
118
127
  "@carissa-io/components-calendar": "^0.1.1",
128
+ "@carissa-io/components-card": "^0.1.0",
119
129
  "@carissa-io/components-checkbox": "^0.1.1",
120
130
  "@carissa-io/components-combobox": "^0.1.1",
121
131
  "@carissa-io/components-date-picker": "^0.1.1",
package/scss/_modes.scss CHANGED
@@ -24,6 +24,9 @@ $light: (
24
24
  'disabled-text': t.$disabled-text,
25
25
  'disabled-border': t.$disabled-border,
26
26
  'error': t.$error,
27
+ 'success': t.$success,
28
+ 'warning': t.$warning,
29
+ 'info': t.$info,
27
30
  'focus': t.$focus-color,
28
31
  );
29
32
 
@@ -41,6 +44,9 @@ $dark: (
41
44
  'disabled-text': #737373,
42
45
  'disabled-border': #404040,
43
46
  'error': #f87171,
47
+ 'success': #4ade80,
48
+ 'warning': #fbbf24,
49
+ 'info': #60a5fa,
44
50
  'focus': #fff,
45
51
  );
46
52
 
@@ -57,6 +63,9 @@ $var-primary-active: var(--c-primary-active);
57
63
  $var-disabled-text: var(--c-disabled-text);
58
64
  $var-disabled-border: var(--c-disabled-border);
59
65
  $var-error: var(--c-error);
66
+ $var-success: var(--c-success);
67
+ $var-warning: var(--c-warning);
68
+ $var-info: var(--c-info);
60
69
  $var-focus: var(--c-focus);
61
70
 
62
71
  // The dropdown arrow of Select, Combobox and Date picker (the same roles as the `$arrow-*` tokens).
package/scss/_tokens.scss CHANGED
@@ -17,6 +17,10 @@ $primary-active: #404040;
17
17
  $disabled-text: #a3a3a3;
18
18
  $disabled-border: #d4d4d4;
19
19
  $error: #dc3545;
20
+ // Status roles for Alert (AA text contrast on white and on $surface, see DESIGN.md); $error is the fourth one.
21
+ $success: #15803d;
22
+ $warning: #a16207;
23
+ $info: #1d4ed8;
20
24
 
21
25
  // Values shared by every component, so the whole theme moves together.
22
26
  $font-family: ('Helvetica Neue', Helvetica, Arial, 'Liberation Sans', sans-serif);
package/scss/index.scss CHANGED
@@ -485,7 +485,7 @@
485
485
  // Typography: Heading and Text, the hierarchy of every screen. The scale follows DESIGN.md: black (900) with tight
486
486
  // tracking for display, 1 and 2, bold (700) from 3 down, regular body; the overline is the field-label style, and the
487
487
  // mono variant uses the $font-family-mono token. No margins (spacing belongs to the layout). No other component block
488
- // forwards it, so it can go anywhere; it stays last.
488
+ // forwards it, so it can go anywhere, except after Card, which does: it comes before the Card block below.
489
489
  @use '@carissa-io/components-typography/scss' as typography with (
490
490
  // Headings
491
491
  $c-heading-font-family: $font-family,
@@ -559,3 +559,74 @@
559
559
  $c-text-mono-font-weight: $font-weight-regular,
560
560
  $c-text-mono-line-height: $line-height-normal
561
561
  );
562
+
563
+ // Card: a surface with a header, a body and a footer. Its index forwards the typography styles, already loaded and
564
+ // configured above, so this block goes after the Typography one. Outlined = the page background with a muted 1px border;
565
+ // filled = the surface color; elevated = a subtle layered shadow plus the same border, so it still reads in dark mode.
566
+ // Only custom properties for colors (dark mode); the shadow is a plain rgb() with an alpha, no Sass color math.
567
+ @use '@carissa-io/components-card/scss' as card with (
568
+ $c-card-background: $var-background,
569
+ $c-card-color: $var-text,
570
+ $c-card-border-width: 1px,
571
+ $c-card-border-color: $var-muted,
572
+ $c-card-radius: $radius,
573
+ $c-card-filled-background: $var-surface,
574
+ $c-card-shadow: (0 1px 2px rgb(0 0 0 / 0.06), 0 4px 12px rgb(0 0 0 / 0.08)),
575
+
576
+ // Spacing: generous, 24px at the sides
577
+ $c-card-header-padding-x: 1.5rem,
578
+ $c-card-header-padding-y: 1.25rem,
579
+ $c-card-body-padding-x: 1.5rem,
580
+ $c-card-body-padding-y: 1.25rem,
581
+ $c-card-footer-padding-x: 1.5rem,
582
+ $c-card-footer-padding-y: 1.25rem,
583
+ $c-card-gap: 0.25rem
584
+ );
585
+
586
+ // Alert: a message about a state. A surface background with a 1px muted border and a 4px accent on the left edge in the
587
+ // variant color (the status roles, $error for the error); the text is the normal text color, the icon carries the
588
+ // variant color. The title keeps the text color too: the light $error is 4.15:1 on the surface, short of AA for text.
589
+ @use '@carissa-io/components-alert/scss' as alert with (
590
+ $c-alert-radius: $radius,
591
+ $c-alert-padding-x: 1rem,
592
+ $c-alert-padding-y: 0.875rem,
593
+ $c-alert-gap: 0.75rem,
594
+ $c-alert-border-width: 1px,
595
+ $c-alert-border-left-width: 4px,
596
+ $c-alert-font-size: $font-size-small,
597
+ $c-alert-title-font-weight: $font-weight-bold,
598
+ $c-alert-dismiss-color: $var-muted,
599
+ $c-alert-dismiss-color-hover: $var-text,
600
+
601
+ // Info
602
+ $c-alert-info-background: color-mix(in srgb, $var-info 12%, $var-background),
603
+ $c-alert-info-border-color: color-mix(in srgb, $var-info 35%, $var-background),
604
+ $c-alert-info-accent-color: $var-info,
605
+ $c-alert-info-color: $var-text,
606
+ $c-alert-info-icon-color: $var-info,
607
+ $c-alert-info-title-color: $var-text,
608
+
609
+ // Success
610
+ $c-alert-success-background: color-mix(in srgb, $var-success 12%, $var-background),
611
+ $c-alert-success-border-color: color-mix(in srgb, $var-success 35%, $var-background),
612
+ $c-alert-success-accent-color: $var-success,
613
+ $c-alert-success-color: $var-text,
614
+ $c-alert-success-icon-color: $var-success,
615
+ $c-alert-success-title-color: $var-text,
616
+
617
+ // Warning
618
+ $c-alert-warning-background: color-mix(in srgb, $var-warning 12%, $var-background),
619
+ $c-alert-warning-border-color: color-mix(in srgb, $var-warning 35%, $var-background),
620
+ $c-alert-warning-accent-color: $var-warning,
621
+ $c-alert-warning-color: $var-text,
622
+ $c-alert-warning-icon-color: $var-warning,
623
+ $c-alert-warning-title-color: $var-text,
624
+
625
+ // Error
626
+ $c-alert-error-background: color-mix(in srgb, $var-error 12%, $var-background),
627
+ $c-alert-error-border-color: color-mix(in srgb, $var-error 35%, $var-background),
628
+ $c-alert-error-accent-color: $var-error,
629
+ $c-alert-error-color: $var-text,
630
+ $c-alert-error-icon-color: $var-error,
631
+ $c-alert-error-title-color: $var-text
632
+ );