opui-css 5.0.1 → 5.1.1

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/MIGRATING.md +11 -0
  3. package/README.md +1 -1
  4. package/components/Accordion/Accordion.astro +12 -2
  5. package/components/Anchor/Anchor.astro +5 -1
  6. package/components/ButtonGroup/ButtonGroup.astro +8 -1
  7. package/components/Card/Card.astro +3 -1
  8. package/components/Checkbox/Checkbox.astro +3 -3
  9. package/components/ClassicSelect/ClassicSelect.astro +3 -3
  10. package/components/Dialog/Dialog.astro +3 -1
  11. package/components/Radio/Radio.astro +3 -3
  12. package/components/Select/Select.astro +3 -3
  13. package/components/Switch/Switch.astro +3 -3
  14. package/components/TextField/TextField.astro +3 -3
  15. package/components/Textarea/Textarea.astro +3 -3
  16. package/core/normalize.css +16 -10
  17. package/core/palette.css +313 -58
  18. package/core/utils.css +2 -2
  19. package/css/components/accordion.css +7 -7
  20. package/css/components/anchor.css +23 -23
  21. package/css/components/badge.css +4 -4
  22. package/css/components/button-group.css +28 -14
  23. package/css/components/button.css +29 -17
  24. package/css/components/callout.css +95 -92
  25. package/css/components/card.css +6 -8
  26. package/css/components/checkbox.css +209 -203
  27. package/css/components/chip.css +11 -6
  28. package/css/components/description-list.css +2 -1
  29. package/css/components/dialog.css +2 -1
  30. package/css/components/drawer.css +167 -167
  31. package/css/components/form.css +8 -7
  32. package/css/components/icon-button.css +32 -13
  33. package/css/components/list.css +10 -12
  34. package/css/components/progress.css +4 -3
  35. package/css/components/radio.css +168 -170
  36. package/css/components/range.css +14 -9
  37. package/css/components/select.css +9 -6
  38. package/css/components/spinner.css +4 -3
  39. package/css/components/switch.css +8 -5
  40. package/css/components/table.css +4 -10
  41. package/css/components/tabs.css +17 -16
  42. package/css/components/text-field.css +9 -10
  43. package/css/components/text-input.css +8 -4
  44. package/css/components/textarea.css +3 -1
  45. package/css/components/toast.css +156 -157
  46. package/css/components/toggle-button.css +76 -72
  47. package/css/components/tooltip.css +59 -56
  48. package/css/components/typography.css +31 -31
  49. package/css/imports.css +5 -4
  50. package/css/theme.css +14 -20
  51. package/dist/op.css +0 -62
  52. package/dist/op.css.map +1 -1
  53. package/dist/opui.components.css +1259 -1184
  54. package/dist/opui.components.css.map +1 -1
  55. package/dist/opui.css +1719 -1393
  56. package/dist/opui.css.map +1 -1
  57. package/open-props.css +0 -1
  58. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,50 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.1 - 2026-05-29
4
+
5
+ ### Added
6
+
7
+ - Added CSS `@property` types to the palette (`--color-*` and `--gray-*`) variables to hopefully improve perf.
8
+
9
+ ### Changed
10
+
11
+ - Cleaned up comments and theme variable organization in `css/theme.css`.
12
+
13
+ ## 5.1.0 - 2026-05-28
14
+
15
+ ### Fixed
16
+
17
+ - [#351](https://github.com/felix-bohlin/ui/issues/351): (Attempted to) fix performance issue caused by palette being defined on `*` instead of `:root`. This was causing style recalculations on every element when the palette changed, oops. Hopefully now, recalculations will only happen on elements that use palette variables.
18
+
19
+ The heavy color math is now properly scoped down to `:root`, severity classes (ex `.ui-warning`), and invalid components (`[class*="ui-"]:has(:user-invalid)`).
20
+
21
+ - Palette no longer is included in the openprops layer, instead it's been placed in the `theme.palette` layer, so hopefully it will solve some potential specificity issues.
22
+
23
+ ### Changed
24
+
25
+ - Renamed the `critical` prop to `error` for validation in form components (`TextField`, `Checkbox`, `Radio`, `Switch`, `Select`, `ClassicSelect`, `Textarea`). While `critical` remains the standard for severity coloring (e.g. Buttons, Callouts, Badges), `error` makes more contextual sense for validation states.
26
+
27
+ ### Added
28
+
29
+ - Added a new `.ui-palette` util class. If you are building something where you want to make use of the palette you can just use that class and be able to use the palette right there.
30
+
31
+ ### Migration
32
+
33
+ The `opui-css/open-props` export no longer bundles OPUI's custom palette variables (`--color-*` and `--gray-*`). It now strictly represents the underlying Open Props tokens.
34
+
35
+ If you were relying on OPUI’s dynamic palette colors while importing the `open-props` subpath, you must now explicitly import the palette module alongside it:
36
+
37
+ ```diff
38
+ import 'opui-css/open-props';
39
+ + import 'opui-css/core/palette.css';
40
+ ```
41
+
42
+ Alternately, you can import the default full bundle (`import 'opui-css';`) which includes everything.
43
+
44
+ ### Thank you
45
+
46
+ - [yinhx3](https://github.com/yinhx3) for reporting [#351](https://github.com/felix-bohlin/ui/issues/351)!
47
+
3
48
  ## 5.0.1 - 2026-05-26
4
49
 
5
50
  ### Breaking
package/MIGRATING.md CHANGED
@@ -1,3 +1,14 @@
1
+ # Migrating from v5.0 to v5.1
2
+
3
+ In v5.1.0, the `critical` prop has been renamed to `error` on all form components (`TextField`, `Checkbox`, `Radio`, `Switch`, `Select`, `ClassicSelect`, `Textarea`).
4
+
5
+ ```diff
6
+ - <TextField critical label="Name" />
7
+ + <TextField error label="Name" />
8
+ ```
9
+
10
+ Note: Components that use `critical` for severity styling (such as `Button`, `Callout`, `Badge`) still use the `critical` prop.
11
+
1
12
  # Migrating from v4 to v5
2
13
 
3
14
  v5 prefixes every OPUI-owned class with `ui-`. The component prop API is unchanged; only the rendered class names change.
package/README.md CHANGED
@@ -55,7 +55,7 @@ If you do have a bundler that resolves CSS `@import`s (Vite, Astro, webpack, …
55
55
  The library defines this layer order:
56
56
 
57
57
  ```css
58
- @layer openprops, normalize, theme, components.root, components.extended, utils;
58
+ @layer openprops, theme, normalize, components.root, components.extended, utils;
59
59
  ```
60
60
 
61
61
  Wrap your own styles in a layer above `utils` (or unlayered) to override.
@@ -18,7 +18,12 @@ const contentId = $id("content")
18
18
 
19
19
  <details
20
20
  name={name}
21
- class:list={["ui-accordion", "ui-card", variant && `ui-${variant}`, className]}
21
+ class:list={[
22
+ "ui-accordion",
23
+ "ui-card",
24
+ variant && `ui-${variant}`,
25
+ className,
26
+ ]}
22
27
  open={open}
23
28
  {...rest}
24
29
  >
@@ -27,7 +32,12 @@ const contentId = $id("content")
27
32
  <summary id={summaryId} aria-controls={contentId}><slot name="summary" /><slot name="marker" /></summary>
28
33
 
29
34
  <!-- Content -->
30
- <div id={contentId} class="ui-content" role="region" aria-labelledby={summaryId}>
35
+ <div
36
+ id={contentId}
37
+ class="ui-content"
38
+ role="region"
39
+ aria-labelledby={summaryId}
40
+ >
31
41
  <slot />
32
42
  </div>
33
43
 
@@ -45,7 +45,11 @@ const positionArea = alignment
45
45
  <slot />
46
46
  )
47
47
  }
48
- <span class="ui-anchor-floating" id={id} popover={isHover ? "hint" : undefined}>
48
+ <span
49
+ class="ui-anchor-floating"
50
+ id={id}
51
+ popover={isHover ? "hint" : undefined}
52
+ >
49
53
  <slot name="anchored" />
50
54
  </span>
51
55
  </span>
@@ -21,7 +21,14 @@ const {
21
21
  ---
22
22
 
23
23
  <div
24
- class:list={["ui-button-group", color && `ui-${color}`, size && `ui-${size}`, variant && `ui-${variant}`, orientation && `ui-${orientation}`, className]}
24
+ class:list={[
25
+ "ui-button-group",
26
+ color && `ui-${color}`,
27
+ size && `ui-${size}`,
28
+ variant && `ui-${variant}`,
29
+ orientation && `ui-${orientation}`,
30
+ className,
31
+ ]}
25
32
  role="group"
26
33
  {...rest}
27
34
  >
@@ -28,7 +28,9 @@ const { variant, actionsAlign, class: className, ...rest } = Astro.props
28
28
  <slot />
29
29
  {
30
30
  Astro.slots.has("actions") && (
31
- <div class:list={["ui-actions", actionsAlign && `ui-align-${actionsAlign}`]}>
31
+ <div
32
+ class:list={["ui-actions", actionsAlign && `ui-align-${actionsAlign}`]}
33
+ >
32
34
  <slot name="actions" />
33
35
  </div>
34
36
  )
@@ -5,7 +5,7 @@ type Props = {
5
5
  [key: string]: any
6
6
  checked?: boolean
7
7
  class?: string
8
- critical?: boolean
8
+ error?: boolean
9
9
  disabled?: boolean
10
10
  hideLabel?: boolean
11
11
  id?: string
@@ -23,7 +23,7 @@ export const title = "Checkbox"
23
23
  const {
24
24
  checked,
25
25
  class: className,
26
- critical,
26
+ error,
27
27
  disabled,
28
28
  hideLabel,
29
29
  id,
@@ -53,7 +53,7 @@ const finalName = name || currentFieldName
53
53
  },
54
54
  className,
55
55
  ]}
56
- data-invalid={critical || undefined}
56
+ data-invalid={error || undefined}
57
57
  >
58
58
  <CheckboxInput
59
59
  aria-describedby={endTextId}
@@ -8,7 +8,7 @@ type Props = {
8
8
  [key: string]: any
9
9
  class?: string
10
10
  disabled?: boolean
11
- critical?: boolean
11
+ error?: boolean
12
12
  id?: string
13
13
  items?: Item[]
14
14
  label?: string
@@ -25,7 +25,7 @@ export const title = "Classic Select"
25
25
  const {
26
26
  class: className,
27
27
  disabled,
28
- critical,
28
+ error,
29
29
  id,
30
30
  items = [],
31
31
  label,
@@ -52,7 +52,7 @@ const labelId = $id("select-label")
52
52
  },
53
53
  className,
54
54
  ]}
55
- data-invalid={critical || undefined}
55
+ data-invalid={error || undefined}
56
56
  >
57
57
  {
58
58
  label && (
@@ -33,7 +33,9 @@ const { actionsAlign, class: className, closedby, ...rest } = Astro.props
33
33
  <slot />
34
34
  {
35
35
  Astro.slots.has("actions") && (
36
- <div class:list={["ui-actions", actionsAlign && `ui-align-${actionsAlign}`]}>
36
+ <div
37
+ class:list={["ui-actions", actionsAlign && `ui-align-${actionsAlign}`]}
38
+ >
37
39
  <slot name="actions" />
38
40
  </div>
39
41
  )
@@ -6,7 +6,7 @@ type Props = {
6
6
  checked?: boolean
7
7
  class?: string
8
8
  disabled?: boolean
9
- critical?: boolean
9
+ error?: boolean
10
10
  hideLabel?: boolean
11
11
  id?: string
12
12
  name?: string
@@ -22,7 +22,7 @@ const {
22
22
  checked,
23
23
  class: className,
24
24
  disabled,
25
- critical,
25
+ error,
26
26
  hideLabel,
27
27
  id,
28
28
  name,
@@ -48,7 +48,7 @@ const finalName = name || currentFieldName
48
48
  },
49
49
  className,
50
50
  ]}
51
- data-invalid={critical || undefined}
51
+ data-invalid={error || undefined}
52
52
  >
53
53
  <RadioInput
54
54
  aria-describedby={endTextId}
@@ -9,7 +9,7 @@ type Props = {
9
9
  class?: string
10
10
  description?: string
11
11
  disabled?: boolean
12
- critical?: boolean
12
+ error?: boolean
13
13
  dense?: boolean
14
14
  id?: string
15
15
  items?: Item[]
@@ -29,7 +29,7 @@ const {
29
29
  class: className,
30
30
  description,
31
31
  disabled,
32
- critical,
32
+ error,
33
33
  dense,
34
34
  id,
35
35
  items = [],
@@ -60,7 +60,7 @@ const labelId = $id("select-label")
60
60
  },
61
61
  className,
62
62
  ]}
63
- data-invalid={critical || undefined}
63
+ data-invalid={error || undefined}
64
64
  >
65
65
  {
66
66
  (label || Astro.slots.has("label")) && (
@@ -6,7 +6,7 @@ type Props = {
6
6
  checked?: boolean
7
7
  class?: string
8
8
  disabled?: boolean
9
- critical?: boolean
9
+ error?: boolean
10
10
  hideLabel?: boolean
11
11
  id?: string
12
12
  name?: string
@@ -23,7 +23,7 @@ const {
23
23
  checked,
24
24
  class: className,
25
25
  disabled,
26
- critical,
26
+ error,
27
27
  hideLabel,
28
28
  id,
29
29
  name,
@@ -62,7 +62,7 @@ if (
62
62
  },
63
63
  className,
64
64
  ]}
65
- data-invalid={critical || undefined}
65
+ data-invalid={error || undefined}
66
66
  >
67
67
  {
68
68
  Astro.slots.has("icon-unchecked") && (
@@ -3,7 +3,7 @@ type Props = {
3
3
  [key: string]: any
4
4
  autoFit?: boolean
5
5
  class?: string
6
- critical?: boolean
6
+ error?: boolean
7
7
  description?: string
8
8
  disabled?: boolean
9
9
  endText?: string
@@ -43,7 +43,7 @@ export const title = "Text Field"
43
43
  const {
44
44
  autoFit,
45
45
  class: className,
46
- critical,
46
+ error,
47
47
  description,
48
48
  disabled,
49
49
  endText,
@@ -82,7 +82,7 @@ const fieldName = name || currentFieldName
82
82
  },
83
83
  className,
84
84
  ]}
85
- data-invalid={critical || undefined}
85
+ data-invalid={error || undefined}
86
86
  {...rest}
87
87
  >
88
88
  {
@@ -6,7 +6,7 @@ type Props = {
6
6
  cols?: number
7
7
  description?: string
8
8
  disabled?: boolean
9
- critical?: boolean
9
+ error?: boolean
10
10
  filled?: boolean
11
11
  id?: string
12
12
  label?: string
@@ -30,7 +30,7 @@ const {
30
30
  cols,
31
31
  description,
32
32
  disabled,
33
- critical,
33
+ error,
34
34
  filled,
35
35
  id,
36
36
  label,
@@ -63,7 +63,7 @@ const fieldName = name || currentFieldName
63
63
  },
64
64
  className,
65
65
  ]}
66
- data-invalid={critical || undefined}
66
+ data-invalid={error || undefined}
67
67
  {...rest}
68
68
  >
69
69
  {
@@ -1,5 +1,4 @@
1
1
  @layer normalize {
2
-
3
2
  *,
4
3
  ::before,
5
4
  ::after {
@@ -58,7 +57,6 @@
58
57
  outline: none !important;
59
58
  }
60
59
 
61
-
62
60
  :where(:not(fieldset, progress, meter)) {
63
61
  background-origin: border-box;
64
62
  background-repeat: no-repeat;
@@ -114,7 +112,9 @@
114
112
 
115
113
  :focus-visible {
116
114
  /* Inverts the --_page-bg-color */
117
- --_focus-visible-color: rgb(from var(--_page-bg-color) calc(255 - r) calc(255 - g) calc(255 - b));
115
+ --_focus-visible-color: rgb(
116
+ from var(--_page-bg-color) calc(255 - r) calc(255 - g) calc(255 - b)
117
+ );
118
118
 
119
119
  border-radius: var(--border-radius, 0px);
120
120
  outline: 2px solid var(--_focus-visible-color);
@@ -123,7 +123,7 @@
123
123
 
124
124
  @media (prefers-reduced-motion: no-preference) {
125
125
  :where(:focus-visible) {
126
- transition: outline-offset .15 var(--ease-2);
126
+ transition: outline-offset 0.15 var(--ease-2);
127
127
  }
128
128
 
129
129
  :where(:not(:active):focus-visible) {
@@ -135,23 +135,28 @@
135
135
  outline-offset: var(--outline-offset, 0px);
136
136
  }
137
137
 
138
- :where(a[href],
138
+ :where(
139
+ a[href],
139
140
  area,
140
141
  button,
141
- input:not([type="text"],
142
+ input:not(
143
+ [type="text"],
142
144
  [type="email"],
143
145
  [type="number"],
144
146
  [type="password"],
145
147
  [type=""],
146
148
  [type="tel"],
147
- [type="url"]),
149
+ [type="url"]
150
+ ),
148
151
  label[for],
149
152
  select,
150
- summary) {
153
+ summary
154
+ ) {
151
155
  cursor: pointer;
152
156
  }
153
157
 
154
- :where(a[href],
158
+ :where(
159
+ a[href],
155
160
  area,
156
161
  button,
157
162
  [role="button"],
@@ -160,7 +165,8 @@
160
165
  select,
161
166
  summary,
162
167
  textarea,
163
- [tabindex]:not([tabindex*="-"])) {
168
+ [tabindex]:not([tabindex*="-"])
169
+ ) {
164
170
  -webkit-tap-highlight-color: transparent;
165
171
  touch-action: manipulation;
166
172
  }