@orianatech/pire 0.11.0 → 0.13.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.
@@ -11,11 +11,13 @@ a:hover{color:var(--text-link-hover)}
11
11
  a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible{outline:var(--focus-w) solid var(--focus-color);outline-offset:var(--focus-offset)}
12
12
  code,kbd,samp{font:var(--type-code)}
13
13
  table{border-collapse:collapse}
14
- @keyframes pire-toast-in{from{opacity:0;transform:translate(var(--pire-toast-tx,-50%),8px)}to{opacity:1}}
15
- @keyframes pire-dialog-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}
16
- @keyframes pire-fade-in{from{opacity:0}to{opacity:1}}
17
- .pire-numeric{font:var(--type-numeric);letter-spacing:var(--ls-numeric);font-variant-numeric:tabular-nums}
18
- .pire-eyebrow{font:var(--type-label);letter-spacing:var(--ls-caps);text-transform:uppercase;color:var(--text-secondary)}
19
- /* Announced but not drawn. Clip rather than display:none or visibility:hidden, both of which
20
- remove the node from the accessibility tree along with the pixels. */
21
- .pire-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
14
+ /* Element resets only — no classes, no keyframes.
15
+
16
+ This is the one part of the stylesheet a consumer can legitimately skip: the element-level
17
+ rules above collide with Tailwind Preflight, so a product migrating gradually has to leave it
18
+ out while the two coexist. Anything the component code or components.css references must
19
+ therefore live in components.css, or skipping the resets silently breaks a component.
20
+
21
+ That is not hypothetical. Through 0.11.0 this file also held `.pire-sr-only`, `.pire-numeric`,
22
+ `.pire-eyebrow` and the toast/dialog/fade keyframes, so skipping it dropped a class ChartFrame
23
+ needs — and every chart rendered its screen-reader data table in full view. */
@@ -17,9 +17,31 @@
17
17
  --red-10:#fdeaea;--red-30:#eda3a7;--red-50:#c0242e;--red-60:#991c25;
18
18
  --purple-10:#f0edfb;--purple-50:#5a3fc0;
19
19
 
20
- /* --- Text ------------------------------------------------------------- */
21
- --text-primary:var(--gray-90);--text-secondary:var(--gray-60);--text-tertiary:var(--gray-50);
20
+ /* --- Text ---------------------------------------------------------------
21
+ The scale sits one step darker than it used to. `--text-tertiary` was
22
+ gray-50, which held only 2.95:1 on the page surface and 3.22:1 on a card —
23
+ under the 4.5:1 that body text needs, in 21 rules of components.css.
24
+
25
+ Moving tertiary alone was not possible: the first value that clears 4.5:1 on
26
+ the page surface lands within 0.3 contrast points of secondary, so the two
27
+ would have read as one weight and the third level would have been decorative.
28
+ Both moved instead, which keeps three steps that are actually distinguishable.
29
+
30
+ `--text-secondary` and `--text-label` now resolve to the same gray-70. They
31
+ stay separate tokens because they mean different things — secondary is body
32
+ text, label names a field — and either may move again on its own. Do not
33
+ "simplify" one into the other.
34
+
35
+ `--text-disabled` deliberately stays at gray-40 and below 4.5:1: WCAG 1.4.3
36
+ exempts inactive components, and darkening it removes the signal that the
37
+ control is disabled. */
38
+ --text-primary:var(--gray-90);--text-secondary:var(--gray-70);--text-tertiary:var(--gray-60);
22
39
  --text-disabled:var(--gray-40);--text-inverse:var(--gray-0);--text-on-accent:var(--gray-0);
40
+ /* Text on a solid status fill — today only the IconButton count badge. Separate from
41
+ `--text-inverse` because the two flip in opposite directions: the shell and toasts are dark in
42
+ both themes and always want light text, while the status fills invert (red-60 in light,
43
+ red-30 in dark) and so want the opposite. Sharing one token put white on light pink at 1.94:1. */
44
+ --text-on-status:var(--gray-0);
23
45
  --text-link:var(--blue-60);--text-link-hover:var(--blue-70);--text-label:var(--gray-70);
24
46
  --text-numeric:var(--gray-90);
25
47
 
@@ -1,8 +1,14 @@
1
1
  /* Theming contract: structure is hardcoded, colour is swappable.
2
2
  Consumers re-point the alias layer only — never the ramps, never geometry. */
3
3
  [data-theme="dark"]{
4
- --text-primary:var(--gray-05);--text-secondary:var(--gray-40);--text-tertiary:var(--gray-50);
5
- --text-disabled:var(--gray-60);--text-inverse:var(--gray-100);--text-label:var(--gray-30);
4
+ /* Shifted one step lighter, mirroring the light scale's move a step darker and for the same
5
+ reason: tertiary at gray-50 held only 3.77:1 on `--surface-raised`, the darkest surface text
6
+ ever lands on. Menus and popovers use that surface, so it is not an edge case. */
7
+ --text-primary:var(--gray-05);--text-secondary:var(--gray-30);--text-tertiary:var(--gray-40);
8
+ /* --text-inverse stays light here. It names text on a permanently dark ground — the shell bar,
9
+ toasts, tooltips, avatars — not "the opposite of the current theme". Pointing it at gray-100
10
+ put near-black text on the near-black shell: 1.02:1, invisible, and shipped. */
11
+ --text-disabled:var(--gray-60);--text-inverse:var(--gray-05);--text-on-status:var(--gray-100);--text-label:var(--gray-30);
6
12
  --text-link:var(--blue-30);--text-link-hover:var(--blue-20);--text-numeric:var(--gray-05);
7
13
  --surface-page:var(--gray-100);--surface-card:var(--gray-90);--surface-sunken:#111922;
8
14
  --surface-raised:var(--gray-80);--surface-hover:var(--gray-80);--surface-active:var(--gray-70);
@@ -11,7 +17,11 @@
11
17
  --surface-nav:var(--gray-90);--surface-toolbar:var(--gray-90);--surface-overlay:rgba(4,16,31,.66);
12
18
  --border-subtle:#28333d;--border-default:var(--gray-70);--border-strong:var(--gray-50);
13
19
  --border-field:var(--gray-50);--border-focus:var(--blue-30);--border-accent:var(--blue-30);
14
- --accent-bg:var(--blue-50);--accent-bg-hover:var(--blue-40);--accent-bg-active:var(--blue-30);
20
+ /* Hover and press deepen here rather than lighten, the same direction as the light theme. Going
21
+ lighter is the usual dark-theme reflex and it broke the contrast: the fill lightened while
22
+ `--accent-fg` stayed white, so a hovered primary button was 3.19:1 and a pressed one 1.99:1.
23
+ Only CI caught it, because a local run leaves the pointer off the button. */
24
+ --accent-bg:var(--blue-50);--accent-bg-hover:var(--blue-60);--accent-bg-active:var(--blue-70);
15
25
  --accent-subtle-bg:var(--blue-90);--accent-subtle-fg:var(--blue-20);
16
26
  --status-positive-fg:var(--green-30);--status-positive-bg:#0e2b1c;--status-positive-border:var(--green-50);
17
27
  --status-critical-fg:var(--amber-30);--status-critical-bg:#31210a;--status-critical-border:var(--amber-50);
@@ -25,5 +35,14 @@
25
35
  --viz-4:var(--viz-gold-40);--viz-5:var(--viz-violet-40);--viz-6:var(--viz-jade-40);
26
36
  --viz-other:var(--gray-50);--viz-grid:#28333d;--viz-axis:var(--gray-70);
27
37
  }
28
- /* Accessibility scope: 3:1 non-text contrast on every control edge */
29
- [data-contrast="high"]{--border-subtle:var(--gray-50);--border-default:var(--gray-70);--border-field:var(--gray-80);--text-secondary:var(--gray-80)}
38
+ /* Accessibility scope: 3:1 non-text contrast on every control edge.
39
+ Tertiary darkens alongside secondary here — it did not before, which left the
40
+ scope's lightest text at the same value as the default theme's. */
41
+ [data-contrast="high"]{--border-subtle:var(--gray-50);--border-default:var(--gray-70);--border-field:var(--gray-80);--text-secondary:var(--gray-80);--text-tertiary:var(--gray-70)}
42
+
43
+ /* The high-contrast scope above darkens text, which is only correct on a light ground. Combined
44
+ with the dark theme it inverted the intent: `--text-secondary` resolved to gray-80, the same
45
+ value as `--surface-raised`, giving 1.00:1 — text the exact colour of what it sits on. Neither
46
+ scope is gated alone, so nothing caught it; both are gated now.
47
+ Order matters — this must follow both blocks it corrects. */
48
+ [data-theme="dark"][data-contrast="high"]{--text-secondary:var(--gray-05);--text-tertiary:var(--gray-20);--border-subtle:var(--gray-50);--border-default:var(--gray-40);--border-field:var(--gray-30)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orianatech/pire",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Oriana Pire Design System — React components for ERP interfaces, built on React Aria.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -97,6 +97,9 @@
97
97
  "test": "vitest run",
98
98
  "test:watch": "vitest",
99
99
  "test:storybook": "vitest run --project=storybook",
100
+ "test:a11y:dark": "STORYBOOK_THEME=dark vitest run --project=storybook",
101
+ "test:a11y:contrast": "STORYBOOK_CONTRAST=high vitest run --project=storybook",
102
+ "test:a11y:dark-contrast": "STORYBOOK_THEME=dark STORYBOOK_CONTRAST=high vitest run --project=storybook",
100
103
  "test:unit": "vitest run --project=unit",
101
104
  "pack:check": "publint --strict && attw --pack . --exclude-entrypoints ./styles.css ./tokens.css ./components.css",
102
105
  "fonts:vendor": "node scripts/vendor-fonts.mjs"