@axiapps/axi-design 1.39.0 → 1.41.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/dist/axi.css CHANGED
@@ -1181,8 +1181,6 @@ button.axi-panel--tile:hover,
1181
1181
  transform: rotate(45deg);
1182
1182
  }
1183
1183
  .axi-radio:checked::after { opacity: 1; }
1184
- .axi-check:disabled,
1185
- .axi-radio:disabled { cursor: not-allowed; opacity: .5; }
1186
1184
 
1187
1185
  /* ---------- textarea ---------- */
1188
1186
  /* Not a component: the same .axi-input a single-line field uses, with the two
@@ -3055,7 +3053,8 @@ textarea.axi-input {
3055
3053
 
3056
3054
  /* --- utilities.css --- */
3057
3055
  /* axi design language - utilities.
3058
- Two families of single-purpose class, and the file is last in the cascade
3056
+ Two families of single-purpose class and one state, and the file is last in
3057
+ the cascade
3059
3058
  because that is the whole point of it: a utility has to be able to overrule
3060
3059
  the component it sits inside, and it is not allowed to buy that with
3061
3060
  !important or with a padded selector.
@@ -3108,3 +3107,73 @@ textarea.axi-input {
3108
3107
  .axi-edge-accent { border-color: var(--axi-accent); }
3109
3108
  .axi-edge-rule { border-color: var(--axi-rule); }
3110
3109
  .axi-edge-line { border-color: var(--axi-ink-line); }
3110
+
3111
+ /* ---------- the dead state ---------- */
3112
+ /* Twenty-four things in this language are interactive: twenty-three declare
3113
+ `cursor: pointer`, and the twenty-fourth is `.axi-input`, which both the
3114
+ single-line field and the textarea wear. Before this rule, two of the
3115
+ twenty-four said anything at all when they were disabled - the checkbox and
3116
+ the radio, which got `opacity: .5; cursor: not-allowed` in forms.css. The
3117
+ other twenty-three were, computed-style for computed-style, indistinguishable
3118
+ from their working selves: a disabled `.axi-btn` drew the same fill, the same
3119
+ border and the same ink as an enabled one, and still told the cursor it was a
3120
+ pointer. The control did not merely fail to look dead; it actively promised
3121
+ it was alive.
3122
+
3123
+ So every consumer invented the state. In the app this language was built
3124
+ for, twenty-four sites had written `disabled:opacity-50
3125
+ disabled:cursor-not-allowed` by hand - the same two declarations forms.css
3126
+ already contained, retyped once per control - and a replay stepper had
3127
+ invented a third answer, swapping the ink to a dimmer token instead.
3128
+
3129
+ Why opacity and the cursor, and deliberately nothing else. A disabled
3130
+ control has to stay recognisable as the control it is: whatever fill, border
3131
+ and ink said "primary button" or "danger action" a moment ago must still say
3132
+ it, only faded. Opacity does that to every layer at once without naming any
3133
+ of them, which is also the one form this can take that does not fight the
3134
+ ink layer below - the stepper's colour swap is exactly the defect the ink
3135
+ layer exists to prevent, because a disabled `.axi-action.axi-ink-danger`
3136
+ would lose its verdict rather than fade with it.
3137
+
3138
+ Why this file. A disabled state has to overrule the resting rule of the
3139
+ component it sits inside, and it is not allowed to buy that with
3140
+ !important - which is this file's whole reason for existing, and the reason
3141
+ the state lives here rather than beside each component. `:is()` carries its
3142
+ most specific argument's weight, so each of these selectors weighs one class
3143
+ and one pseudo-class: enough to beat any component's own resting rule, and
3144
+ nothing upstream sets `cursor` or `opacity` on a hover that could out-rank
3145
+ it.
3146
+
3147
+ Pointer events are left alone. `:disabled` already blocks activation
3148
+ natively, and `[aria-disabled="true"]` means "focusable, but ignore the
3149
+ action" - a control the reader can still reach and still read a title from.
3150
+ Removing pointer events would take away the tooltip that explains why the
3151
+ thing is dead, which is the one piece of help a dead control can offer. */
3152
+ .axi-accordion__head:is(:disabled, [aria-disabled="true"]),
3153
+ .axi-action:is(:disabled, [aria-disabled="true"]),
3154
+ .axi-btn:is(:disabled, [aria-disabled="true"]),
3155
+ .axi-card:is(:disabled, [aria-disabled="true"]),
3156
+ .axi-check:is(:disabled, [aria-disabled="true"]),
3157
+ .axi-chip--action:is(:disabled, [aria-disabled="true"]),
3158
+ .axi-drawer__close:is(:disabled, [aria-disabled="true"]),
3159
+ .axi-input:is(:disabled, [aria-disabled="true"]),
3160
+ .axi-link:is(:disabled, [aria-disabled="true"]),
3161
+ .axi-palette__row:is(:disabled, [aria-disabled="true"]),
3162
+ .axi-palette__trigger:is(:disabled, [aria-disabled="true"]),
3163
+ .axi-picker__btn:is(:disabled, [aria-disabled="true"]),
3164
+ .axi-picker__opt:is(:disabled, [aria-disabled="true"]),
3165
+ .axi-pill:is(:disabled, [aria-disabled="true"]),
3166
+ .axi-radio:is(:disabled, [aria-disabled="true"]),
3167
+ .axi-rail__item:is(:disabled, [aria-disabled="true"]),
3168
+ .axi-rail__subitem:is(:disabled, [aria-disabled="true"]),
3169
+ .axi-select:is(:disabled, [aria-disabled="true"]),
3170
+ .axi-switch:is(:disabled, [aria-disabled="true"]),
3171
+ .axi-table__sort:is(:disabled, [aria-disabled="true"]),
3172
+ .axi-menu__pop label:is(:disabled, [aria-disabled="true"]),
3173
+ .axi-prose a:is(:disabled, [aria-disabled="true"]),
3174
+ .axi-tabs a:is(:disabled, [aria-disabled="true"]),
3175
+ .axi-tabs button:is(:disabled, [aria-disabled="true"]),
3176
+ .axi-titlebar__btns button:is(:disabled, [aria-disabled="true"]) {
3177
+ opacity: .5;
3178
+ cursor: not-allowed;
3179
+ }
@@ -21,7 +21,7 @@
21
21
  --axi-border-panel: 1px;
22
22
  --axi-border-control: 1px;
23
23
  --axi-border-hairline: 1px;
24
- --axi-radius: 10px;
25
- --axi-radius-sm: 6px;
26
- --axi-radius-xs: 3px;
24
+ --axi-radius: 6px;
25
+ --axi-radius-sm: 4px;
26
+ --axi-radius-xs: 2px;
27
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiapps/axi-design",
3
- "version": "1.39.0",
3
+ "version": "1.41.0",
4
4
  "description": "The design language for the axi suite — flat and outlined, dark, drawn in saturated ink.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/forms.css CHANGED
@@ -73,8 +73,6 @@
73
73
  transform: rotate(45deg);
74
74
  }
75
75
  .axi-radio:checked::after { opacity: 1; }
76
- .axi-check:disabled,
77
- .axi-radio:disabled { cursor: not-allowed; opacity: .5; }
78
76
 
79
77
  /* ---------- textarea ---------- */
80
78
  /* Not a component: the same .axi-input a single-line field uses, with the two
package/src/utilities.css CHANGED
@@ -1,5 +1,6 @@
1
1
  /* axi design language - utilities.
2
- Two families of single-purpose class, and the file is last in the cascade
2
+ Two families of single-purpose class and one state, and the file is last in
3
+ the cascade
3
4
  because that is the whole point of it: a utility has to be able to overrule
4
5
  the component it sits inside, and it is not allowed to buy that with
5
6
  !important or with a padded selector.
@@ -52,3 +53,73 @@
52
53
  .axi-edge-accent { border-color: var(--axi-accent); }
53
54
  .axi-edge-rule { border-color: var(--axi-rule); }
54
55
  .axi-edge-line { border-color: var(--axi-ink-line); }
56
+
57
+ /* ---------- the dead state ---------- */
58
+ /* Twenty-four things in this language are interactive: twenty-three declare
59
+ `cursor: pointer`, and the twenty-fourth is `.axi-input`, which both the
60
+ single-line field and the textarea wear. Before this rule, two of the
61
+ twenty-four said anything at all when they were disabled - the checkbox and
62
+ the radio, which got `opacity: .5; cursor: not-allowed` in forms.css. The
63
+ other twenty-three were, computed-style for computed-style, indistinguishable
64
+ from their working selves: a disabled `.axi-btn` drew the same fill, the same
65
+ border and the same ink as an enabled one, and still told the cursor it was a
66
+ pointer. The control did not merely fail to look dead; it actively promised
67
+ it was alive.
68
+
69
+ So every consumer invented the state. In the app this language was built
70
+ for, twenty-four sites had written `disabled:opacity-50
71
+ disabled:cursor-not-allowed` by hand - the same two declarations forms.css
72
+ already contained, retyped once per control - and a replay stepper had
73
+ invented a third answer, swapping the ink to a dimmer token instead.
74
+
75
+ Why opacity and the cursor, and deliberately nothing else. A disabled
76
+ control has to stay recognisable as the control it is: whatever fill, border
77
+ and ink said "primary button" or "danger action" a moment ago must still say
78
+ it, only faded. Opacity does that to every layer at once without naming any
79
+ of them, which is also the one form this can take that does not fight the
80
+ ink layer below - the stepper's colour swap is exactly the defect the ink
81
+ layer exists to prevent, because a disabled `.axi-action.axi-ink-danger`
82
+ would lose its verdict rather than fade with it.
83
+
84
+ Why this file. A disabled state has to overrule the resting rule of the
85
+ component it sits inside, and it is not allowed to buy that with
86
+ !important - which is this file's whole reason for existing, and the reason
87
+ the state lives here rather than beside each component. `:is()` carries its
88
+ most specific argument's weight, so each of these selectors weighs one class
89
+ and one pseudo-class: enough to beat any component's own resting rule, and
90
+ nothing upstream sets `cursor` or `opacity` on a hover that could out-rank
91
+ it.
92
+
93
+ Pointer events are left alone. `:disabled` already blocks activation
94
+ natively, and `[aria-disabled="true"]` means "focusable, but ignore the
95
+ action" - a control the reader can still reach and still read a title from.
96
+ Removing pointer events would take away the tooltip that explains why the
97
+ thing is dead, which is the one piece of help a dead control can offer. */
98
+ .axi-accordion__head:is(:disabled, [aria-disabled="true"]),
99
+ .axi-action:is(:disabled, [aria-disabled="true"]),
100
+ .axi-btn:is(:disabled, [aria-disabled="true"]),
101
+ .axi-card:is(:disabled, [aria-disabled="true"]),
102
+ .axi-check:is(:disabled, [aria-disabled="true"]),
103
+ .axi-chip--action:is(:disabled, [aria-disabled="true"]),
104
+ .axi-drawer__close:is(:disabled, [aria-disabled="true"]),
105
+ .axi-input:is(:disabled, [aria-disabled="true"]),
106
+ .axi-link:is(:disabled, [aria-disabled="true"]),
107
+ .axi-palette__row:is(:disabled, [aria-disabled="true"]),
108
+ .axi-palette__trigger:is(:disabled, [aria-disabled="true"]),
109
+ .axi-picker__btn:is(:disabled, [aria-disabled="true"]),
110
+ .axi-picker__opt:is(:disabled, [aria-disabled="true"]),
111
+ .axi-pill:is(:disabled, [aria-disabled="true"]),
112
+ .axi-radio:is(:disabled, [aria-disabled="true"]),
113
+ .axi-rail__item:is(:disabled, [aria-disabled="true"]),
114
+ .axi-rail__subitem:is(:disabled, [aria-disabled="true"]),
115
+ .axi-select:is(:disabled, [aria-disabled="true"]),
116
+ .axi-switch:is(:disabled, [aria-disabled="true"]),
117
+ .axi-table__sort:is(:disabled, [aria-disabled="true"]),
118
+ .axi-menu__pop label:is(:disabled, [aria-disabled="true"]),
119
+ .axi-prose a:is(:disabled, [aria-disabled="true"]),
120
+ .axi-tabs a:is(:disabled, [aria-disabled="true"]),
121
+ .axi-tabs button:is(:disabled, [aria-disabled="true"]),
122
+ .axi-titlebar__btns button:is(:disabled, [aria-disabled="true"]) {
123
+ opacity: .5;
124
+ cursor: not-allowed;
125
+ }