@atlaskit/css 0.10.4 → 0.10.5

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @atlaskit/css
2
2
 
3
+ ## 0.10.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#135712](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/135712)
8
+ [`fa9caa5adb7a3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/fa9caa5adb7a3) -
9
+ Improvements to `xcss()` -> `cssMap()` codemod.
10
+ - Updated dependencies
11
+
3
12
  ## 0.10.4
4
13
 
5
14
  ### Patch Changes
@@ -4,7 +4,6 @@ import type {
4
4
  default as core,
5
5
  FileInfo,
6
6
  ImportDeclaration,
7
- Node,
8
7
  Options,
9
8
  } from 'jscodeshift';
10
9
 
@@ -96,6 +95,7 @@ function replaceXcssWithCssMap(
96
95
  let firstXcssPath: ASTPath<core.CallExpression> | null = null;
97
96
  let firstUsagePath: ASTPath<core.Node> | null = null;
98
97
  const styleVariables = new Set<string>();
98
+ const variableDependencies = new Map<string, Set<string>>();
99
99
 
100
100
  source
101
101
  .find(j.CallExpression, {
@@ -119,6 +119,23 @@ function replaceXcssWithCssMap(
119
119
  if (variableDeclarator && variableDeclarator.type === 'VariableDeclarator') {
120
120
  const variableName = variableDeclarator.id.name; // e.g. buttonStyles
121
121
  styleVariables.add(variableName);
122
+
123
+ // find dependencies in the xcss object
124
+ const dependencies = new Set<string>();
125
+ if (args[0].type === 'ObjectExpression') {
126
+ args[0].properties.forEach((prop) => {
127
+ if (prop.type === 'ObjectProperty' && prop.value.type === 'TemplateLiteral') {
128
+ prop.value.expressions.forEach((expr) => {
129
+ if (expr.type === 'Identifier') {
130
+ dependencies.add(expr.name);
131
+ }
132
+ });
133
+ }
134
+ });
135
+ }
136
+ if (dependencies.size > 0) {
137
+ variableDependencies.set(variableName, dependencies);
138
+ }
122
139
  }
123
140
  }
124
141
  }
@@ -198,40 +215,164 @@ function replaceXcssWithCssMap(
198
215
  // insert the cssMap declaration before its first usage
199
216
  if (firstUsagePath) {
200
217
  const programBody = source.get().node.program.body;
201
- const firstUsageIndex = programBody.findIndex((node: Node) => {
202
- const nodeStart = node.loc?.start;
203
- const usageStart = firstUsagePath?.node.loc?.start;
204
-
205
- if (!nodeStart || !usageStart) {
206
- return false;
218
+ let insertIndex = 0;
219
+
220
+ // find the last variable declaration that any style depends on
221
+ let lastDependencyIndex = -1;
222
+ for (let i = 0; i < programBody.length; i++) {
223
+ const node = programBody[i];
224
+ if (node.type === 'VariableDeclaration') {
225
+ const varName = node.declarations[0]?.id.name;
226
+ if (varName) {
227
+ // check if this variable is a dependency of any style
228
+ for (const [, deps] of variableDependencies.entries()) {
229
+ if (deps.has(varName)) {
230
+ lastDependencyIndex = i;
231
+ break;
232
+ }
233
+ }
234
+ }
207
235
  }
236
+ }
208
237
 
209
- return (
210
- nodeStart.line > usageStart.line ||
211
- (nodeStart.line === usageStart.line && nodeStart.column > usageStart.column)
238
+ // insert after the last dependency
239
+ if (lastDependencyIndex !== -1) {
240
+ insertIndex = lastDependencyIndex + 1;
241
+ } else {
242
+ // if no dependencies, find the first non-import/type declaration
243
+ insertIndex = programBody.findIndex(
244
+ (node: { type: string }) =>
245
+ node.type !== 'ImportDeclaration' &&
246
+ node.type !== 'TypeAlias' &&
247
+ node.type !== 'InterfaceDeclaration',
212
248
  );
213
- });
214
-
215
- if (firstUsageIndex !== -1) {
216
- // find the last import or variable declaration before the first usage
217
- let insertIndex = firstUsageIndex;
218
- while (insertIndex > 0) {
219
- const node = programBody[insertIndex - 1];
220
- if (
221
- node.type === 'ImportDeclaration' ||
222
- node.type === 'VariableDeclaration' ||
223
- node.type === 'TypeAlias' ||
224
- node.type === 'InterfaceDeclaration'
225
- ) {
226
- break;
227
- }
228
- insertIndex--;
229
- }
230
- programBody.splice(insertIndex, 0, cssMapVariableDeclaration);
231
249
  }
250
+
251
+ programBody.splice(insertIndex, 0, cssMapVariableDeclaration);
232
252
  }
233
253
  }
234
254
 
255
+ // First handle backgroundColor transformation for Box components
256
+ source
257
+ .find(j.JSXAttribute, {
258
+ name: {
259
+ type: 'JSXIdentifier',
260
+ name: 'xcss',
261
+ },
262
+ })
263
+ .forEach((path) => {
264
+ const value = path.node.value;
265
+ if (value && value.type === 'JSXExpressionContainer') {
266
+ const expression = value.expression;
267
+ const parentElement = path.parentPath?.node;
268
+ const isBoxComponent = parentElement?.name?.name === 'Box';
269
+
270
+ if (isBoxComponent) {
271
+ if (expression.type === 'Identifier') {
272
+ const styleKey = getCssMapKey(expression.name);
273
+ const styleObject = cssMapProperties.find(
274
+ (prop) => prop.key.type === 'Identifier' && prop.key.name === styleKey,
275
+ )?.value;
276
+ if (styleObject?.type === 'ObjectExpression') {
277
+ const backgroundColorProp = styleObject.properties.find(
278
+ (prop) =>
279
+ prop.type === 'ObjectProperty' &&
280
+ prop.key.type === 'Identifier' &&
281
+ prop.key.name === 'backgroundColor',
282
+ );
283
+ if (
284
+ backgroundColorProp?.type === 'ObjectProperty' &&
285
+ backgroundColorProp.value.type === 'StringLiteral'
286
+ ) {
287
+ // add backgroundColor prop to Box component
288
+ parentElement.attributes.push(
289
+ j.jsxAttribute(
290
+ j.jsxIdentifier('backgroundColor'),
291
+ j.stringLiteral(backgroundColorProp.value.value),
292
+ ),
293
+ );
294
+ // remove backgroundColor from cssMap
295
+ styleObject.properties = styleObject.properties.filter(
296
+ (prop) =>
297
+ !(
298
+ prop.type === 'ObjectProperty' &&
299
+ prop.key.type === 'Identifier' &&
300
+ prop.key.name === 'backgroundColor'
301
+ ),
302
+ );
303
+ }
304
+ }
305
+ } else if (expression.type === 'ArrayExpression') {
306
+ // handle array of styles
307
+ const backgroundColorValues: string[] = [];
308
+ expression.elements.forEach((element) => {
309
+ if (element?.type === 'Identifier') {
310
+ const styleKey = getCssMapKey(element.name);
311
+ const styleObject = cssMapProperties.find(
312
+ (prop) => prop.key.type === 'Identifier' && prop.key.name === styleKey,
313
+ )?.value;
314
+ if (styleObject?.type === 'ObjectExpression') {
315
+ const backgroundColorProp = styleObject.properties.find(
316
+ (prop) =>
317
+ prop.type === 'ObjectProperty' &&
318
+ prop.key.type === 'Identifier' &&
319
+ prop.key.name === 'backgroundColor',
320
+ );
321
+ if (
322
+ backgroundColorProp?.type === 'ObjectProperty' &&
323
+ backgroundColorProp.value.type === 'StringLiteral'
324
+ ) {
325
+ backgroundColorValues.push(backgroundColorProp.value.value);
326
+ // remove backgroundColor from cssMap
327
+ styleObject.properties = styleObject.properties.filter(
328
+ (prop) =>
329
+ !(
330
+ prop.type === 'ObjectProperty' &&
331
+ prop.key.type === 'Identifier' &&
332
+ prop.key.name === 'backgroundColor'
333
+ ),
334
+ );
335
+ }
336
+ }
337
+ }
338
+ });
339
+
340
+ // if we found backgroundColor values, add to Box component
341
+ if (backgroundColorValues.length > 0) {
342
+ if (backgroundColorValues.length === 1) {
343
+ // single backgroundColor value
344
+ parentElement.attributes.push(
345
+ j.jsxAttribute(
346
+ j.jsxIdentifier('backgroundColor'),
347
+ j.stringLiteral(backgroundColorValues[0]),
348
+ ),
349
+ );
350
+ } else {
351
+ // multiple backgroundColor values - use ternary for conditional
352
+ const conditions = expression.elements
353
+ .map((element, index) => {
354
+ if (
355
+ element?.type === 'LogicalExpression' &&
356
+ element.left.type === 'Identifier'
357
+ ) {
358
+ return `${element.left.name} ? "${backgroundColorValues[index]}" :`;
359
+ }
360
+ return `"${backgroundColorValues[index]}"`;
361
+ })
362
+ .join(' ');
363
+ parentElement.attributes.push(
364
+ j.jsxAttribute(
365
+ j.jsxIdentifier('backgroundColor'),
366
+ j.jsxExpressionContainer(j.identifier(conditions)),
367
+ ),
368
+ );
369
+ }
370
+ }
371
+ }
372
+ }
373
+ }
374
+ });
375
+
235
376
  // update the xcss prop references to use the new cssMap object
236
377
  source
237
378
  .find(j.JSXAttribute, {
@@ -249,7 +390,7 @@ function replaceXcssWithCssMap(
249
390
  // <Box xcss={buttonStyles} /> -> <Box xcss={styles.button} />
250
391
  expression.name = `styles.${getCssMapKey(expression.name)}`;
251
392
  } else if (expression.type === 'ArrayExpression') {
252
- // <Box xcss={[baseStyles, otherStyles]} /> -> <Box xcss={[styles.base, styles.otherStyles]} />
393
+ // <Box xcss={[baseStyles, otherStyles]} /> -> <Box xcss={[styles.base, styles.other]} />
253
394
  expression.elements.forEach((element) => {
254
395
  if (element?.type === 'Identifier') {
255
396
  element.name = `styles.${getCssMapKey(element.name)}`;
@@ -39,7 +39,7 @@ values, such as `color: 'rgba(123, 45, 67)'` nor `padding: 8`. Typically, only t
39
39
  allowed. Additionally, there are some restrictions, such as `zIndex`, which only supports a limited
40
40
  set of numeric values.
41
41
 
42
- ### cssMap
42
+ ### cssMap()
43
43
 
44
44
  We recommend using `cssMap` to create style maps. These maps can be applied and reused on both
45
45
  native elements and React components using `props.css` and `props.xcss` respectively.
@@ -48,6 +48,22 @@ Make sure to define the styles before using them in your components, i.e. at the
48
48
 
49
49
  <Example Component={CssMapExample} packageName="@atlaskit/css" />
50
50
 
51
+ ### css()
52
+
53
+ The `css()` function is a lower-level API that creates a single style object. Unlike `cssMap()`,
54
+ it's best suited for one-off styles. Use it with elements that accept a `css` prop. While `css()` is
55
+ simpler to use, we recommend `cssMap()` for most cases because it provides better reusability and
56
+ type safety.
57
+
58
+ ```tsx
59
+ const styles = css({
60
+ padding: token('space.100'),
61
+ color: token('color.text'),
62
+ });
63
+
64
+ <div css={styles}>Hello world!</div>;
65
+ ```
66
+
51
67
  ### Primitives
52
68
 
53
69
  When using `@atlaskit/css`, it's important to note that it's not compatible with the Emotion variant
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/css",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "description": "Style components backed by Atlassian Design System design tokens powered by Compiled CSS-in-JS.",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "license": "Apache-2.0",
@@ -48,7 +48,7 @@
48
48
  "./test-utils": "./src/test-utils/index.tsx"
49
49
  },
50
50
  "dependencies": {
51
- "@atlaskit/tokens": "^4.5.0",
51
+ "@atlaskit/tokens": "^4.6.0",
52
52
  "@babel/runtime": "^7.0.0",
53
53
  "@compiled/react": "^0.18.3"
54
54
  },
@@ -57,9 +57,9 @@
57
57
  },
58
58
  "devDependencies": {
59
59
  "@af/visual-regression": "^1.3.0",
60
- "@atlaskit/button": "^22.0.0",
60
+ "@atlaskit/button": "^23.0.0",
61
61
  "@atlaskit/ds-lib": "^4.0.0",
62
- "@atlaskit/primitives": "^14.2.0",
62
+ "@atlaskit/primitives": "^14.3.0",
63
63
  "@emotion/react": "^11.7.1",
64
64
  "@testing-library/react": "^13.4.0",
65
65
  "@types/jscodeshift": "^0.11.0",