ionbase-ui 0.17.0 → 0.18.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.
- package/README.md +47 -10
- package/dist/meta/components.json +1 -1
- package/dist/meta/contrast.json +3613 -0
- package/dist/meta/index.json +1 -1
- package/dist/styles/alert.css +10 -5
- package/eslint-plugin/index.js +64 -0
- package/eslint-plugin/meta-data.js +66 -0
- package/eslint-plugin/rules/needs-accessible-name.js +88 -0
- package/eslint-plugin/rules/no-deprecated-props.js +74 -0
- package/eslint-plugin/rules/no-known-contrast-failure.js +75 -0
- package/eslint-plugin/rules/no-raw-style-values.js +107 -0
- package/eslint-plugin/rules/one-primary-action.js +128 -0
- package/package.json +28 -8
- package/stylelint-config.js +144 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ionbase-ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "IonBase Design System
|
|
3
|
+
"version": "0.18.1",
|
|
4
|
+
"description": "IonBase Design System — accessible React components, styles and design tokens in one package",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"./tokens-js": {
|
|
22
22
|
"types": "./dist/tokens-js.d.ts",
|
|
23
23
|
"default": "./dist/tokens-js.js"
|
|
24
|
-
}
|
|
24
|
+
},
|
|
25
|
+
"./stylelint-config": "./stylelint-config.js",
|
|
26
|
+
"./eslint-plugin": "./eslint-plugin/index.js"
|
|
25
27
|
},
|
|
26
28
|
"keywords": [
|
|
27
29
|
"design-system",
|
|
@@ -34,7 +36,9 @@
|
|
|
34
36
|
"ionbase"
|
|
35
37
|
],
|
|
36
38
|
"files": [
|
|
37
|
-
"dist"
|
|
39
|
+
"dist",
|
|
40
|
+
"eslint-plugin",
|
|
41
|
+
"stylelint-config.js"
|
|
38
42
|
],
|
|
39
43
|
"sideEffects": [
|
|
40
44
|
"**/*.css"
|
|
@@ -53,17 +57,22 @@
|
|
|
53
57
|
},
|
|
54
58
|
"scripts": {
|
|
55
59
|
"dev": "tsc --watch",
|
|
56
|
-
"build": "node scripts/sync-tokens.mjs && tsc --build --force && node scripts/copy-css.mjs && node scripts/verify-client-boundaries.mjs && node scripts/build-meta.mjs && node scripts/verify-meta.mjs",
|
|
60
|
+
"build": "node scripts/sync-tokens.mjs && tsc --build --force && node scripts/copy-css.mjs && node scripts/verify-client-boundaries.mjs && node scripts/verify-contrast.mjs && node scripts/build-meta.mjs && node scripts/verify-meta.mjs",
|
|
57
61
|
"typecheck": "tsc --noEmit",
|
|
58
62
|
"lint": "eslint . && stylelint \"src/styles/*.css\"",
|
|
59
63
|
"format": "prettier --check .",
|
|
60
64
|
"icons:verify": "node scripts/verify-icons.mjs",
|
|
61
65
|
"meta:build": "node scripts/build-meta.mjs",
|
|
62
|
-
"meta:verify": "node scripts/build-meta.mjs && node scripts/verify-meta.mjs"
|
|
66
|
+
"meta:verify": "node scripts/build-meta.mjs && node scripts/verify-meta.mjs",
|
|
67
|
+
"contrast": "node scripts/verify-contrast.mjs",
|
|
68
|
+
"contrast:list": "node scripts/verify-contrast.mjs --list"
|
|
63
69
|
},
|
|
64
70
|
"peerDependencies": {
|
|
65
71
|
"react": "^18.0.0 || ^19.0.0",
|
|
66
|
-
"react-dom": "^18.0.0 || ^19.0.0"
|
|
72
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
73
|
+
"stylelint": "^16.0.0 || ^17.0.0",
|
|
74
|
+
"stylelint-declaration-strict-value": "^1.10.0",
|
|
75
|
+
"eslint": "^8.57.0 || ^9.0.0"
|
|
67
76
|
},
|
|
68
77
|
"dependencies": {
|
|
69
78
|
"@react-stately/collections": "^3.13.1",
|
|
@@ -71,9 +80,20 @@
|
|
|
71
80
|
"react-aria": "^3.34.0",
|
|
72
81
|
"react-stately": "^3.48.0"
|
|
73
82
|
},
|
|
74
|
-
"//devDependencies": "lucide-react is a devDependency, not a dependency: nothing in src/ imports it. It is here only so scripts/verify-icons.mjs can compare the installed icon set against the Figma page. Consumers pick their own icon library. There is deliberately NO dependency on @ionbase-ui/tokens
|
|
83
|
+
"//devDependencies": "lucide-react is a devDependency, not a dependency: nothing in src/ imports it. It is here only so scripts/verify-icons.mjs can compare the installed icon set against the Figma page. Consumers pick their own icon library. There is deliberately NO dependency on @ionbase-ui/tokens — it is private and would publish as a version that does not exist on npm. Build ordering is expressed in turbo.json instead.",
|
|
75
84
|
"devDependencies": {
|
|
76
85
|
"lucide-react": "^1.27.0",
|
|
77
86
|
"typescript": "^5.5.2"
|
|
87
|
+
},
|
|
88
|
+
"peerDependenciesMeta": {
|
|
89
|
+
"stylelint": {
|
|
90
|
+
"optional": true
|
|
91
|
+
},
|
|
92
|
+
"stylelint-declaration-strict-value": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"eslint": {
|
|
96
|
+
"optional": true
|
|
97
|
+
}
|
|
78
98
|
}
|
|
79
99
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IonBase stylelint config — the token rules, shipped.
|
|
3
|
+
*
|
|
4
|
+
* // stylelint.config.js
|
|
5
|
+
* export default { extends: ['ionbase-ui/stylelint-config'] };
|
|
6
|
+
*
|
|
7
|
+
* This exists because the premise of IonBase is that the code consuming it may
|
|
8
|
+
* be written by an agent with no developer reviewing the result. A rule that
|
|
9
|
+
* lives only in this repo protects only this repo; the app is where the drift
|
|
10
|
+
* actually happens, and a lint error naming the fix is the one form of guidance
|
|
11
|
+
* an agent reliably acts on.
|
|
12
|
+
*
|
|
13
|
+
* It is deliberately NOT a superset of stylelint-config-standard. That config
|
|
14
|
+
* is about CSS hygiene and is the consumer's choice; this one is about design
|
|
15
|
+
* tokens, and pairs with whatever else they already run.
|
|
16
|
+
*
|
|
17
|
+
* Requires `stylelint-declaration-strict-value` alongside `stylelint`. Both are
|
|
18
|
+
* optional peer dependencies — installed only by projects that opt in.
|
|
19
|
+
*
|
|
20
|
+
* REPO NOTE: the root stylelint.config.js extends this file directly rather
|
|
21
|
+
* than re-declaring the rules. One source, many pointers — the same reason
|
|
22
|
+
* CLAUDE.md is a pointer to AGENTS.md. If you edit rules, edit them here.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** Properties where a raw value is a theming bug rather than a style choice. */
|
|
26
|
+
export const TOKENISED_PROPERTIES = [
|
|
27
|
+
'color',
|
|
28
|
+
'background-color',
|
|
29
|
+
'border-color',
|
|
30
|
+
'border-top-color',
|
|
31
|
+
'border-bottom-color',
|
|
32
|
+
'border-left-color',
|
|
33
|
+
'border-right-color',
|
|
34
|
+
'outline-color',
|
|
35
|
+
'font-size',
|
|
36
|
+
'font-family',
|
|
37
|
+
'font-weight',
|
|
38
|
+
'line-height',
|
|
39
|
+
'margin',
|
|
40
|
+
'margin-top',
|
|
41
|
+
'margin-bottom',
|
|
42
|
+
'margin-left',
|
|
43
|
+
'margin-right',
|
|
44
|
+
'padding',
|
|
45
|
+
'padding-top',
|
|
46
|
+
'padding-bottom',
|
|
47
|
+
'padding-left',
|
|
48
|
+
'padding-right',
|
|
49
|
+
'gap',
|
|
50
|
+
'border-radius',
|
|
51
|
+
'border-top-left-radius',
|
|
52
|
+
'border-top-right-radius',
|
|
53
|
+
'border-bottom-left-radius',
|
|
54
|
+
'border-bottom-right-radius',
|
|
55
|
+
'border-width',
|
|
56
|
+
'border-top-width',
|
|
57
|
+
'border-bottom-width',
|
|
58
|
+
'border-left-width',
|
|
59
|
+
'border-right-width',
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Values that are not tokens and never should be.
|
|
64
|
+
*
|
|
65
|
+
* The forced-colors block is the important half: under Windows High Contrast
|
|
66
|
+
* every authored colour is remapped, and these system keywords are the only
|
|
67
|
+
* values that survive. A token there would be silently discarded.
|
|
68
|
+
*/
|
|
69
|
+
export const ALLOWED_RAW_VALUES = [
|
|
70
|
+
'inherit',
|
|
71
|
+
'transparent',
|
|
72
|
+
'currentColor',
|
|
73
|
+
'currentcolor',
|
|
74
|
+
'0',
|
|
75
|
+
'none',
|
|
76
|
+
'auto',
|
|
77
|
+
'normal',
|
|
78
|
+
'100%',
|
|
79
|
+
'max-content',
|
|
80
|
+
'min-content',
|
|
81
|
+
'Canvas',
|
|
82
|
+
'CanvasText',
|
|
83
|
+
'Highlight',
|
|
84
|
+
'HighlightText',
|
|
85
|
+
'GrayText',
|
|
86
|
+
'ButtonText',
|
|
87
|
+
'ButtonFace',
|
|
88
|
+
'LinkText',
|
|
89
|
+
'Field',
|
|
90
|
+
'FieldText',
|
|
91
|
+
'SelectedItem',
|
|
92
|
+
'SelectedItemText',
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
/** @type {import('stylelint').Config} */
|
|
96
|
+
const config = {
|
|
97
|
+
plugins: ['stylelint-declaration-strict-value'],
|
|
98
|
+
rules: {
|
|
99
|
+
'color-no-hex': true,
|
|
100
|
+
|
|
101
|
+
// BEM. `.ion-button--primary-brand`, `.ion-tabs__item`.
|
|
102
|
+
'selector-class-pattern': null,
|
|
103
|
+
|
|
104
|
+
'scale-unlimited/declaration-strict-value': [
|
|
105
|
+
TOKENISED_PROPERTIES,
|
|
106
|
+
{
|
|
107
|
+
ignoreValues: ALLOWED_RAW_VALUES,
|
|
108
|
+
message:
|
|
109
|
+
'Raw CSS values are forbidden here. Use a design token — see `ionbase-ui/tokens` for the custom properties, or `ionbase-ui/meta/<Component>.json` for the tokens a given component consumes.',
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
|
|
113
|
+
/*
|
|
114
|
+
* No raw colour inside a shadow.
|
|
115
|
+
*
|
|
116
|
+
* Shadows are the one property where geometry and colour share a value.
|
|
117
|
+
* The offsets (`0 0 0 2px`) are inert and never theme, so requiring them to
|
|
118
|
+
* be tokens would buy nothing — but a raw colour is a place dark mode has to
|
|
119
|
+
* be fixed by hand, once per occurrence. This bans the colour half only,
|
|
120
|
+
* which is why it is a disallowed-list rather than declaration-strict-value.
|
|
121
|
+
*
|
|
122
|
+
* Correct: box-shadow: 0 0 0 2px var(--border-primary-strong);
|
|
123
|
+
* box-shadow: var(--ion-shadow-button-raised);
|
|
124
|
+
* Rejected: box-shadow: 0 1px 2px rgb(0 0 0 / 40%);
|
|
125
|
+
*/
|
|
126
|
+
'declaration-property-value-disallowed-list': {
|
|
127
|
+
'box-shadow': [/rgba?\(/i, /hsla?\(/i, /#[0-9a-f]{3,8}/i],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
overrides: [
|
|
132
|
+
{
|
|
133
|
+
// Wherever a project keeps its own elevation ramp, that file is where raw
|
|
134
|
+
// shadow values are SUPPOSED to live — it is the one place dark mode has
|
|
135
|
+
// to touch. Everywhere else must reference the token.
|
|
136
|
+
files: ['**/elevation.css'],
|
|
137
|
+
rules: { 'declaration-property-value-disallowed-list': null },
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
|
|
141
|
+
ignoreFiles: ['**/dist/**', '**/node_modules/**'],
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default config;
|