@planningcenter/tapestry-migration-cli 3.8.1-rc.0 → 3.8.1-rc.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/tapestry-migration-cli",
3
- "version": "3.8.1-rc.0",
3
+ "version": "3.8.1-rc.1",
4
4
  "description": "CLI tool for Tapestry migrations",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "devDependencies": {
32
32
  "@emotion/react": "^11.14.0",
33
- "@planningcenter/tapestry": "^3.8.1-rc.0",
33
+ "@planningcenter/tapestry": "^3.8.1-rc.1",
34
34
  "@planningcenter/tapestry-react": "^4.11.5",
35
35
  "@types/jscodeshift": "^17.3.0",
36
36
  "@types/node": "^20.0.0",
@@ -50,5 +50,5 @@
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "aa87cfcc57842e31caa4f410e2d4276722e54035"
53
+ "gitHead": "9ec1c85d356014aab7e0bde375c9766fdab3b410"
54
54
  }
@@ -70,14 +70,8 @@ describe("preflight: convertStyleProps across all tapestry-react components", ()
70
70
  return (
71
71
  <Stack
72
72
  style={{
73
- paddingTop: "128px",
74
- paddingRight: "128px",
75
- paddingBottom: "128px",
76
- paddingLeft: "128px",
77
- marginTop: "64px",
78
- marginRight: "64px",
79
- marginBottom: "64px",
80
- marginLeft: "64px"
73
+ padding: "128px",
74
+ margin: "64px"
81
75
  }} />
82
76
  );
83
77
  }
@@ -294,25 +294,59 @@ describe("stylePropTransformFactory", () => {
294
294
  })
295
295
 
296
296
  // Literal values flow through splitStyles, which expands shorthands like
297
- // `marginHorizontal` into the underlying CSS properties. No TODO needed.
298
- it("expands `marginHorizontal` string literals via splitStyles without a TODO", () => {
297
+ // `marginHorizontal` into the underlying CSS properties; since left and
298
+ // right resolve to the same value, they're folded back into the
299
+ // `marginInline` logical shorthand. No TODO needed.
300
+ it("collapses `marginHorizontal` string literals to `marginInline` via splitStyles without a TODO", () => {
299
301
  const input = `import { Box } from "@planningcenter/tapestry-react";<Box marginHorizontal="8px" />`
300
302
  const result = applyTransform(transform, input)
301
303
  expect(result).toMatchInlineSnapshot(`
302
304
  "import { Box } from "@planningcenter/tapestry-react";<Box style={{
303
- marginRight: "8px",
304
- marginLeft: "8px"
305
+ marginInline: "8px"
305
306
  }} />"
306
307
  `)
307
308
  })
308
309
 
309
- it("expands `paddingHorizontal` numeric literals via splitStyles without a TODO", () => {
310
+ it("collapses `paddingHorizontal` numeric literals to `paddingInline` via splitStyles without a TODO", () => {
310
311
  const input = `import { Box } from "@planningcenter/tapestry-react";<Box paddingHorizontal={1} />`
311
312
  const result = applyTransform(transform, input)
312
313
  expect(result).toMatchInlineSnapshot(`
313
314
  "import { Box } from "@planningcenter/tapestry-react";<Box style={{
314
- paddingRight: "8px",
315
- paddingLeft: "8px"
315
+ paddingInline: "8px"
316
+ }} />"
317
+ `)
318
+ })
319
+
320
+ it("collapses `padding` two-value CSS shorthand strings to `paddingBlock`/`paddingInline`", () => {
321
+ const input = `import { Box } from "@planningcenter/tapestry-react";<Box padding="4px 8px" />`
322
+ const result = applyTransform(transform, input)
323
+ expect(result).toMatchInlineSnapshot(`
324
+ "import { Box } from "@planningcenter/tapestry-react";<Box style={{
325
+ paddingInline: "8px",
326
+ paddingBlock: "4px"
327
+ }} />"
328
+ `)
329
+ })
330
+
331
+ it("collapses `padding` uniform CSS shorthand strings to the `padding` shorthand", () => {
332
+ const input = `import { Box } from "@planningcenter/tapestry-react";<Box padding="8px" />`
333
+ const result = applyTransform(transform, input)
334
+ expect(result).toMatchInlineSnapshot(`
335
+ "import { Box } from "@planningcenter/tapestry-react";<Box style={{
336
+ padding: "8px"
337
+ }} />"
338
+ `)
339
+ })
340
+
341
+ it("leaves `padding` four-value CSS shorthand strings fully expanded when no sides match", () => {
342
+ const input = `import { Box } from "@planningcenter/tapestry-react";<Box padding="1px 2px 3px 4px" />`
343
+ const result = applyTransform(transform, input)
344
+ expect(result).toMatchInlineSnapshot(`
345
+ "import { Box } from "@planningcenter/tapestry-react";<Box style={{
346
+ paddingTop: "1px",
347
+ paddingRight: "2px",
348
+ paddingBottom: "3px",
349
+ paddingLeft: "4px"
316
350
  }} />"
317
351
  `)
318
352
  })
@@ -165,6 +165,120 @@ function processKeepStyleProps({
165
165
  return { directProps, manualReviewEntries, processedNames, themeProps }
166
166
  }
167
167
 
168
+ // splitStyles (vendored from tapestry-react) always fans padding/margin/
169
+ // borderWidth/radius out into their per-side (or per-corner) longhand
170
+ // properties. Fold them back into a shorthand when the resolved values make
171
+ // that lossless: all four sides equal -> the physical shorthand; only the
172
+ // left/right or top/bottom pair equal -> the CSS logical axis shorthand
173
+ // (inline/block). Corners have no axis shorthand, so borderRadius only
174
+ // collapses on the full four-corner match.
175
+ type QuadShorthandGroup = {
176
+ blockShorthand: string
177
+ bottom: string
178
+ inlineShorthand: string
179
+ left: string
180
+ right: string
181
+ shorthand: string
182
+ top: string
183
+ }
184
+
185
+ const quadShorthandGroups: QuadShorthandGroup[] = [
186
+ {
187
+ blockShorthand: "paddingBlock",
188
+ bottom: "paddingBottom",
189
+ inlineShorthand: "paddingInline",
190
+ left: "paddingLeft",
191
+ right: "paddingRight",
192
+ shorthand: "padding",
193
+ top: "paddingTop",
194
+ },
195
+ {
196
+ blockShorthand: "marginBlock",
197
+ bottom: "marginBottom",
198
+ inlineShorthand: "marginInline",
199
+ left: "marginLeft",
200
+ right: "marginRight",
201
+ shorthand: "margin",
202
+ top: "marginTop",
203
+ },
204
+ {
205
+ blockShorthand: "borderBlockWidth",
206
+ bottom: "borderBottomWidth",
207
+ inlineShorthand: "borderInlineWidth",
208
+ left: "borderLeftWidth",
209
+ right: "borderRightWidth",
210
+ shorthand: "borderWidth",
211
+ top: "borderTopWidth",
212
+ },
213
+ ]
214
+
215
+ const cornerShorthandGroup = {
216
+ corners: [
217
+ "borderTopLeftRadius",
218
+ "borderTopRightRadius",
219
+ "borderBottomRightRadius",
220
+ "borderBottomLeftRadius",
221
+ ],
222
+ shorthand: "borderRadius",
223
+ }
224
+
225
+ function collapseUniformShorthands(
226
+ styles: Record<string, unknown>
227
+ ): Record<string, unknown> {
228
+ const result = { ...styles }
229
+
230
+ for (const group of quadShorthandGroups) {
231
+ const { shorthand, top, right, bottom, left } = group
232
+ if (shorthand in result) continue
233
+
234
+ const sideValues = [top, right, bottom, left].map((key) => result[key])
235
+ if (
236
+ sideValues.every((value) => value !== undefined) &&
237
+ sideValues.every((value) => value === sideValues[0])
238
+ ) {
239
+ result[shorthand] = sideValues[0]
240
+ delete result[top]
241
+ delete result[right]
242
+ delete result[bottom]
243
+ delete result[left]
244
+ continue
245
+ }
246
+
247
+ if (
248
+ !(group.inlineShorthand in result) &&
249
+ result[left] !== undefined &&
250
+ result[left] === result[right]
251
+ ) {
252
+ result[group.inlineShorthand] = result[left]
253
+ delete result[left]
254
+ delete result[right]
255
+ }
256
+
257
+ if (
258
+ !(group.blockShorthand in result) &&
259
+ result[top] !== undefined &&
260
+ result[top] === result[bottom]
261
+ ) {
262
+ result[group.blockShorthand] = result[top]
263
+ delete result[top]
264
+ delete result[bottom]
265
+ }
266
+ }
267
+
268
+ if (!(cornerShorthandGroup.shorthand in result)) {
269
+ const cornerValues = cornerShorthandGroup.corners.map((key) => result[key])
270
+ if (
271
+ cornerValues.every((value) => value !== undefined) &&
272
+ cornerValues.every((value) => value === cornerValues[0])
273
+ ) {
274
+ result[cornerShorthandGroup.shorthand] = cornerValues[0]
275
+ cornerShorthandGroup.corners.forEach((key) => delete result[key])
276
+ }
277
+ }
278
+
279
+ return result
280
+ }
281
+
168
282
  function isInlineableStyleValue(value: unknown): boolean {
169
283
  return (
170
284
  value === null ||
@@ -465,7 +579,10 @@ export function stylePropTransformFactory(config: {
465
579
  plugin: config.plugin,
466
580
  })
467
581
  const cssObject = result.css(defaultTheme)
468
- styles = { ...styles, ...(cssObject[0] || {}) }
582
+ styles = collapseUniformShorthands({
583
+ ...styles,
584
+ ...(cssObject[0] || {}),
585
+ })
469
586
  }
470
587
 
471
588
  styles = { ...styles, ...directStyleProps }