stablekit.ts 0.3.2 → 0.4.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/eslint.cjs +6 -11
- package/dist/eslint.d.cts +5 -5
- package/dist/eslint.d.ts +5 -5
- package/dist/eslint.js +6 -11
- package/llms.txt +4 -4
- package/package.json +1 -1
package/dist/eslint.cjs
CHANGED
|
@@ -87,7 +87,7 @@ function createArchitectureLint(options) {
|
|
|
87
87
|
stateTokens,
|
|
88
88
|
variantProps = [],
|
|
89
89
|
banColorUtilities = true,
|
|
90
|
-
|
|
90
|
+
classNameBlocked = [],
|
|
91
91
|
loadingPassthrough = ["LoadingBoundary"],
|
|
92
92
|
files = ["src/components/**/*.{tsx,jsx}"]
|
|
93
93
|
} = options;
|
|
@@ -208,18 +208,13 @@ function createArchitectureLint(options) {
|
|
|
208
208
|
selector: ":matches(JSXElement, JSXFragment) > JSXExpressionContainer > TemplateLiteral",
|
|
209
209
|
message: "Interpolated text in JSX children. Extract to a const above the return (the linter won't flag a plain variable). For state-driven values, use <StableCounter> for numbers or <StateSwap> for text variants."
|
|
210
210
|
},
|
|
211
|
-
// --- 5. className on
|
|
212
|
-
...
|
|
211
|
+
// --- 5. className on firewalled components ---
|
|
212
|
+
...classNameBlocked.length ? [
|
|
213
213
|
{
|
|
214
|
-
selector: `JSXOpeningElement[name.name=/^
|
|
215
|
-
message: "className on a
|
|
214
|
+
selector: `JSXOpeningElement[name.name=/^(${classNameBlocked.join("|")})$/] > JSXAttribute[name.name='className']`,
|
|
215
|
+
message: "className on a firewalled component. This component owns its own styling \u2014 use a data-attribute, variant prop, or CSS class internally instead of passing Tailwind utilities from the consumer."
|
|
216
216
|
}
|
|
217
|
-
] : [
|
|
218
|
-
{
|
|
219
|
-
selector: "JSXOpeningElement[name.name=/^[A-Z]/] > JSXAttribute[name.name='className']",
|
|
220
|
-
message: "className on a custom component. Components own their own styling \u2014 use a data-attribute, variant prop, or CSS class internally instead of passing Tailwind utilities from the consumer."
|
|
221
|
-
}
|
|
222
|
-
]
|
|
217
|
+
] : []
|
|
223
218
|
],
|
|
224
219
|
"stablekit/no-loading-conflict": ["error", { passthrough: loadingPassthrough }]
|
|
225
220
|
},
|
package/dist/eslint.d.cts
CHANGED
|
@@ -49,11 +49,11 @@ interface ArchitectureLintOptions {
|
|
|
49
49
|
* Colors must live in CSS — not in component classNames.
|
|
50
50
|
* @default true */
|
|
51
51
|
banColorUtilities?: boolean;
|
|
52
|
-
/** Components
|
|
53
|
-
*
|
|
54
|
-
* e.g. ["
|
|
55
|
-
* @default [] */
|
|
56
|
-
|
|
52
|
+
/** Components where className is banned (your firewalled primitives).
|
|
53
|
+
* Only these components are flagged — everything else is left alone.
|
|
54
|
+
* e.g. ["Badge", "Button", "Card", "Input", "IconButton"]
|
|
55
|
+
* @default [] (rule is off when empty) */
|
|
56
|
+
classNameBlocked?: string[];
|
|
57
57
|
/** Components where `loading` prop does NOT trigger a content swap
|
|
58
58
|
* (e.g. LoadingBoundary controls opacity, not geometry).
|
|
59
59
|
* These are excluded from the dual-paradigm conflict rule.
|
package/dist/eslint.d.ts
CHANGED
|
@@ -49,11 +49,11 @@ interface ArchitectureLintOptions {
|
|
|
49
49
|
* Colors must live in CSS — not in component classNames.
|
|
50
50
|
* @default true */
|
|
51
51
|
banColorUtilities?: boolean;
|
|
52
|
-
/** Components
|
|
53
|
-
*
|
|
54
|
-
* e.g. ["
|
|
55
|
-
* @default [] */
|
|
56
|
-
|
|
52
|
+
/** Components where className is banned (your firewalled primitives).
|
|
53
|
+
* Only these components are flagged — everything else is left alone.
|
|
54
|
+
* e.g. ["Badge", "Button", "Card", "Input", "IconButton"]
|
|
55
|
+
* @default [] (rule is off when empty) */
|
|
56
|
+
classNameBlocked?: string[];
|
|
57
57
|
/** Components where `loading` prop does NOT trigger a content swap
|
|
58
58
|
* (e.g. LoadingBoundary controls opacity, not geometry).
|
|
59
59
|
* These are excluded from the dual-paradigm conflict rule.
|
package/dist/eslint.js
CHANGED
|
@@ -63,7 +63,7 @@ function createArchitectureLint(options) {
|
|
|
63
63
|
stateTokens,
|
|
64
64
|
variantProps = [],
|
|
65
65
|
banColorUtilities = true,
|
|
66
|
-
|
|
66
|
+
classNameBlocked = [],
|
|
67
67
|
loadingPassthrough = ["LoadingBoundary"],
|
|
68
68
|
files = ["src/components/**/*.{tsx,jsx}"]
|
|
69
69
|
} = options;
|
|
@@ -184,18 +184,13 @@ function createArchitectureLint(options) {
|
|
|
184
184
|
selector: ":matches(JSXElement, JSXFragment) > JSXExpressionContainer > TemplateLiteral",
|
|
185
185
|
message: "Interpolated text in JSX children. Extract to a const above the return (the linter won't flag a plain variable). For state-driven values, use <StableCounter> for numbers or <StateSwap> for text variants."
|
|
186
186
|
},
|
|
187
|
-
// --- 5. className on
|
|
188
|
-
...
|
|
187
|
+
// --- 5. className on firewalled components ---
|
|
188
|
+
...classNameBlocked.length ? [
|
|
189
189
|
{
|
|
190
|
-
selector: `JSXOpeningElement[name.name=/^
|
|
191
|
-
message: "className on a
|
|
190
|
+
selector: `JSXOpeningElement[name.name=/^(${classNameBlocked.join("|")})$/] > JSXAttribute[name.name='className']`,
|
|
191
|
+
message: "className on a firewalled component. This component owns its own styling \u2014 use a data-attribute, variant prop, or CSS class internally instead of passing Tailwind utilities from the consumer."
|
|
192
192
|
}
|
|
193
|
-
] : [
|
|
194
|
-
{
|
|
195
|
-
selector: "JSXOpeningElement[name.name=/^[A-Z]/] > JSXAttribute[name.name='className']",
|
|
196
|
-
message: "className on a custom component. Components own their own styling \u2014 use a data-attribute, variant prop, or CSS class internally instead of passing Tailwind utilities from the consumer."
|
|
197
|
-
}
|
|
198
|
-
]
|
|
193
|
+
] : []
|
|
199
194
|
],
|
|
200
195
|
"stablekit/no-loading-conflict": ["error", { passthrough: loadingPassthrough }]
|
|
201
196
|
},
|
package/llms.txt
CHANGED
|
@@ -317,10 +317,10 @@ change to structure requires editing `.css`, a boundary has leaked.
|
|
|
317
317
|
or use a StableKit component (for state-driven swaps — StateSwap,
|
|
318
318
|
LayoutMap, LoadingBoundary, FadeTransition, StableField, StableCounter,
|
|
319
319
|
LayoutGroup). These rules are always on.
|
|
320
|
-
`
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
320
|
+
`classNameBlocked` declares your firewalled primitives (e.g.
|
|
321
|
+
`["Badge", "Button", "Card", "Input"]`). Only those components are flagged
|
|
322
|
+
for className — everything else (Lucide icons, Radix, React Router, etc.)
|
|
323
|
+
is left alone. The rule is off when `classNameBlocked` is empty.
|
|
324
324
|
A custom rule (`stablekit/no-loading-conflict`) catches dual-paradigm
|
|
325
325
|
conflicts: if a component has a `loading` prop (which triggers an internal
|
|
326
326
|
content swap via StateSwap), children must not be variables derived from
|
package/package.json
CHANGED