@clearstory/drywall-react 4.1.4 → 4.2.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 CHANGED
@@ -35,3 +35,13 @@ function App() {
35
35
 
36
36
  export default App;
37
37
  ```
38
+
39
+ ## ESLint Rules
40
+
41
+ This library includes custom ESLint rules to help enforce best practices. Add to your `eslint.config.js`:
42
+
43
+ ```js
44
+ import drywallReact from "@clearstory/drywall-react/eslint-config";
45
+
46
+ export default [drywallReact];
47
+ ```
@@ -0,0 +1,5 @@
1
+ import { ESLint, Linter } from 'eslint';
2
+ declare const drywallPlugin: ESLint.Plugin;
3
+ declare const config: Linter.Config;
4
+ export default config;
5
+ export { drywallPlugin as plugin };
@@ -0,0 +1,29 @@
1
+ import e from "./no-system-props.js";
2
+ const r = {
3
+ rules: {
4
+ "no-system-props": e
5
+ },
6
+ configs: {}
7
+ };
8
+ r.configs.recommended = {
9
+ name: "@clearstory/drywall-react/recommended",
10
+ plugins: {
11
+ "@clearstory/drywall-react": r
12
+ },
13
+ rules: {
14
+ "@clearstory/drywall-react/no-system-props": "error"
15
+ }
16
+ };
17
+ const s = {
18
+ name: "@clearstory/drywall-react",
19
+ plugins: {
20
+ "@clearstory/drywall-react": r
21
+ },
22
+ rules: {
23
+ "@clearstory/drywall-react/no-system-props": "error"
24
+ }
25
+ };
26
+ export {
27
+ s as default,
28
+ r as plugin
29
+ };
@@ -0,0 +1,3 @@
1
+ import { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -0,0 +1,284 @@
1
+ const b = [
2
+ // borders
3
+ "border",
4
+ "borderTop",
5
+ "borderRight",
6
+ "borderBottom",
7
+ "borderLeft",
8
+ "borderColor",
9
+ "borderTopColor",
10
+ "borderRightColor",
11
+ "borderBottomColor",
12
+ "borderLeftColor",
13
+ "outline",
14
+ "outlineColor",
15
+ "borderRadius",
16
+ // colors
17
+ "color",
18
+ "bgcolor",
19
+ "backgroundColor",
20
+ // spacing
21
+ "p",
22
+ "pt",
23
+ "pr",
24
+ "pb",
25
+ "pl",
26
+ "px",
27
+ "py",
28
+ "padding",
29
+ "paddingTop",
30
+ "paddingRight",
31
+ "paddingBottom",
32
+ "paddingLeft",
33
+ "paddingX",
34
+ "paddingY",
35
+ "paddingInline",
36
+ "paddingInlineStart",
37
+ "paddingInlineEnd",
38
+ "paddingBlock",
39
+ "paddingBlockStart",
40
+ "paddingBlockEnd",
41
+ "m",
42
+ "mt",
43
+ "mr",
44
+ "mb",
45
+ "ml",
46
+ "mx",
47
+ "my",
48
+ "margin",
49
+ "marginTop",
50
+ "marginRight",
51
+ "marginBottom",
52
+ "marginLeft",
53
+ "marginX",
54
+ "marginY",
55
+ "marginInline",
56
+ "marginInlineStart",
57
+ "marginInlineEnd",
58
+ "marginBlock",
59
+ "marginBlockStart",
60
+ "marginBlockEnd",
61
+ // display
62
+ "displayPrint",
63
+ "display",
64
+ "overflow",
65
+ "textOverflow",
66
+ "visibility",
67
+ "whiteSpace",
68
+ // flexbox
69
+ "flexBasis",
70
+ "flexDirection",
71
+ "flexWrap",
72
+ "justifyContent",
73
+ "alignItems",
74
+ "alignContent",
75
+ "order",
76
+ "flex",
77
+ "flexGrow",
78
+ "flexShrink",
79
+ "alignSelf",
80
+ "justifyItems",
81
+ "justifySelf",
82
+ "gap",
83
+ "rowGap",
84
+ "columnGap",
85
+ // grid
86
+ "gridColumn",
87
+ "gridRow",
88
+ "gridAutoFlow",
89
+ "gridAutoColumns",
90
+ "gridAutoRows",
91
+ "gridTemplateColumns",
92
+ "gridTemplateRows",
93
+ "gridTemplateAreas",
94
+ "gridArea",
95
+ // positions
96
+ "position",
97
+ "zIndex",
98
+ "top",
99
+ "right",
100
+ "bottom",
101
+ "left",
102
+ // shadows
103
+ "boxShadow",
104
+ // sizing
105
+ "width",
106
+ "maxWidth",
107
+ "minWidth",
108
+ "height",
109
+ "maxHeight",
110
+ "minHeight",
111
+ "boxSizing",
112
+ // typography
113
+ "font",
114
+ "fontFamily",
115
+ "fontSize",
116
+ "fontStyle",
117
+ "fontWeight",
118
+ "letterSpacing",
119
+ "textTransform",
120
+ "lineHeight",
121
+ "textAlign",
122
+ "typography",
123
+ // other common system props
124
+ "spacing"
125
+ ], S = ["Box", "Stack", "Typography", "Link"], w = {
126
+ Typography: ["color"],
127
+ // semantic colors only
128
+ Link: ["color"]
129
+ }, T = {
130
+ meta: {
131
+ type: "problem",
132
+ docs: {
133
+ description: "Disallow system props on @clearstory/drywall-react components",
134
+ category: "Best Practices",
135
+ recommended: !0
136
+ },
137
+ fixable: "code",
138
+ messages: {
139
+ systemProp: 'System prop "{{prop}}" should be moved to the sx prop on {{component}} component'
140
+ },
141
+ schema: []
142
+ },
143
+ create(s) {
144
+ const o = /* @__PURE__ */ new Set(), u = /* @__PURE__ */ new Set(), g = s.getSourceCode();
145
+ return {
146
+ ImportDeclaration(l) {
147
+ const e = l;
148
+ e.source.value === "@clearstory/drywall-react" && e.specifiers.forEach((r) => {
149
+ r.type === "ImportSpecifier" && r.imported && S.includes(r.imported.name) ? o.add(r.local.name) : r.type === "ImportNamespaceSpecifier" && u.add(r.local.name);
150
+ });
151
+ },
152
+ JSXOpeningElement(l) {
153
+ const e = l;
154
+ let r;
155
+ if ("name" in e.name) {
156
+ if (r = e.name.name, !o.has(r))
157
+ return;
158
+ } else if (e.name.type === "JSXMemberExpression") {
159
+ const a = e.name.object.name;
160
+ if (r = e.name.property.name, !u.has(a) || !S.includes(r))
161
+ return;
162
+ } else
163
+ return;
164
+ const p = [];
165
+ let x = null;
166
+ e.attributes.forEach((a) => {
167
+ const t = a;
168
+ if (t.type !== "JSXAttribute" || !t.name)
169
+ return;
170
+ const d = t.name.name;
171
+ if (d === "sx") {
172
+ x = t;
173
+ return;
174
+ }
175
+ if (!b.includes(d))
176
+ return;
177
+ const y = w[r];
178
+ if (y && y.includes(d))
179
+ if (d === "color" && t.value) {
180
+ const h = $(t.value);
181
+ if (C(h))
182
+ return;
183
+ } else
184
+ return;
185
+ p.push(
186
+ t
187
+ );
188
+ }), p.forEach((a) => {
189
+ s.report({
190
+ node: a,
191
+ messageId: "systemProp",
192
+ data: {
193
+ prop: a.name.name,
194
+ component: r
195
+ },
196
+ fix(t) {
197
+ return I(
198
+ t,
199
+ l,
200
+ p,
201
+ x,
202
+ g
203
+ );
204
+ }
205
+ });
206
+ });
207
+ }
208
+ };
209
+ }
210
+ };
211
+ function $(s) {
212
+ if (!s) return null;
213
+ const o = s;
214
+ if (o.type === "Literal")
215
+ return String(o.value);
216
+ if (o.type === "JSXExpressionContainer" && o.expression) {
217
+ if (o.expression.type === "Literal")
218
+ return String(o.expression.value);
219
+ if (o.expression.type === "Identifier")
220
+ return o.expression.name || null;
221
+ }
222
+ return null;
223
+ }
224
+ function C(s) {
225
+ return [
226
+ "inherit",
227
+ "primary",
228
+ "secondary",
229
+ "error",
230
+ "warning",
231
+ "info",
232
+ "success"
233
+ ].includes(s || "");
234
+ }
235
+ function I(s, o, u, g, l) {
236
+ const e = o, r = "name" in e.name ? e.name.name : e.name.type === "JSXMemberExpression" ? `${e.name.object.name}.${e.name.property.name}` : "UnknownComponent", p = u.map((i) => {
237
+ const n = i.name.name, m = i.value;
238
+ if (!m)
239
+ return `${n}: true`;
240
+ const c = m;
241
+ if (c.type === "Literal")
242
+ return `${n}: ${JSON.stringify(c.value)}`;
243
+ if (c.type === "JSXExpressionContainer" && c.expression) {
244
+ const f = l.getText(c.expression);
245
+ return `${n}: ${f}`;
246
+ }
247
+ return `${n}: true`;
248
+ }), x = new Set(
249
+ u.map((i) => i.name.name)
250
+ ), a = [];
251
+ e.attributes.forEach((i) => {
252
+ const n = i;
253
+ if (n.type !== "JSXAttribute" || !n.name) {
254
+ a.push(l.getText(i));
255
+ return;
256
+ }
257
+ const m = n.name.name;
258
+ x.has(m) || m === "sx" && g || a.push(l.getText(i));
259
+ });
260
+ let t;
261
+ if (g) {
262
+ const i = l.getText(g.value);
263
+ if (i.startsWith("{") && i.endsWith("}")) {
264
+ const n = i.slice(1, -1).trim();
265
+ if (n.startsWith("{") && n.endsWith("}"))
266
+ t = `sx={{ ${p.join(", ")}, ...${n} }}`;
267
+ else if (n.startsWith("[") && n.endsWith("]"))
268
+ t = `sx={[{ ${p.join(", ")} }, ...${n}]}`;
269
+ else {
270
+ const m = n.trimStart(), f = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(
271
+ m
272
+ ) ? m : n;
273
+ t = `sx={[{ ${p.join(", ")} }, ...(Array.isArray(${f}) ? ${f} : [${f}])]}`;
274
+ }
275
+ } else
276
+ t = `sx={{ ${p.join(", ")} }}`;
277
+ } else
278
+ t = `sx={{ ${p.join(", ")} }}`;
279
+ const d = [...a, t], y = d.length > 0 ? " " + d.join(" ") : "", h = `<${r}${y}${e.selfClosing ? " />" : ">"}`;
280
+ return [s.replaceText(o, h)];
281
+ }
282
+ export {
283
+ T as default
284
+ };
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,11 +1,19 @@
1
1
  {
2
2
  "name": "@clearstory/drywall-react",
3
- "version": "4.1.4",
3
+ "version": "4.2.1",
4
4
  "license": "UNLICENSED",
5
5
  "description": "a Clearstory software design system",
6
6
  "type": "module",
7
- "main": "dist/main.js",
8
- "types": "dist/main.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/main.d.ts",
10
+ "import": "./dist/main.js"
11
+ },
12
+ "./eslint-config": {
13
+ "types": "./dist/eslint-config/index.d.ts",
14
+ "import": "./dist/eslint-config/index.js"
15
+ }
16
+ },
9
17
  "publishConfig": {
10
18
  "access": "public"
11
19
  },
@@ -78,6 +86,6 @@
78
86
  "preview": "vite preview",
79
87
  "storybook": "storybook dev -p 6006",
80
88
  "build-storybook": "storybook build",
81
- "test": "vitest --project=storybook"
89
+ "test": "vitest"
82
90
  }
83
91
  }