From 1db6751ba1d286b15aea9b882d271bff7b044d25 Mon Sep 17 00:00:00 2001 From: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:08:53 -0700 Subject: [PATCH 1/5] Add namespace support to replace-static-breakpoint-mixins migration --- .../replace-static-breakpoint-mixins.ts | 52 +++++--- .../replace-static-breakpoint-mixins.test.ts | 7 +- .../tests/with-namespace.input.scss | 120 ++++++++++++++++++ .../tests/with-namespace.output.scss | 120 ++++++++++++++++++ polaris-migrator/src/utilities/sass.ts | 13 ++ 5 files changed, 295 insertions(+), 17 deletions(-) create mode 100644 polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.input.scss create mode 100644 polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.output.scss diff --git a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/replace-static-breakpoint-mixins.ts b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/replace-static-breakpoint-mixins.ts index 2401a22ef55..75e3cf69432 100644 --- a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/replace-static-breakpoint-mixins.ts +++ b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/replace-static-breakpoint-mixins.ts @@ -1,6 +1,12 @@ -import {FileInfo} from 'jscodeshift'; +import {FileInfo, API, Options} from 'jscodeshift'; import postcss, {Plugin} from 'postcss'; +import { + NamespaceOptions, + identTokenRegExp, + publicIdentifierRegExp, +} from '../../utilities/sass'; + /** Mapping of static breakpoint mixins from old to new */ const staticBreakpointMixins = { 'page-content-when-partially-condensed': '#{$p-breakpoints-lg-down}', @@ -25,25 +31,39 @@ const isStaticBreakpointMixin = ( ): mixinName is keyof typeof staticBreakpointMixins => Object.keys(staticBreakpointMixins).includes(mixinName as string); -const plugin = (): Plugin => ({ - postcssPlugin: 'ReplaceStaticBreakpointMixins', - AtRule(atRule) { - if (atRule.name !== 'include') return; +interface PluginOptions extends Options, NamespaceOptions {} + +const plugin = (options: PluginOptions = {}): Plugin => { + const namespacedMixinRegExp = options.namespace + ? new RegExp( + String.raw`^${options.namespace}\.(${publicIdentifierRegExp.source})`, + ) + : new RegExp(String.raw`^(${identTokenRegExp.source})`); - // Extract mixin name e.g. name from `@include name;` or `@include name();` - const mixinName = atRule.params.match(/^([a-zA-Z0-9_-]+)/)?.[1]; + return { + postcssPlugin: 'ReplaceStaticBreakpointMixins', + AtRule(atRule) { + if (atRule.name !== 'include') return; - if (!isStaticBreakpointMixin(mixinName)) return; + // Extract mixin name e.g. name from `@include name;` or `@include name();` + const mixinName = atRule.params.match(namespacedMixinRegExp)?.[1]; - atRule.assign({ - name: 'media', - params: staticBreakpointMixins[mixinName], - }); - }, -}); + if (!isStaticBreakpointMixin(mixinName)) return; + + atRule.assign({ + name: 'media', + params: staticBreakpointMixins[mixinName], + }); + }, + }; +}; -export default function replaceStaticBreakpointMixins(fileInfo: FileInfo) { - return postcss(plugin()).process(fileInfo.source, { +export default function replaceStaticMixinsWithDeclarations( + fileInfo: FileInfo, + _: API, + options: Options, +) { + return postcss(plugin(options)).process(fileInfo.source, { syntax: require('postcss-scss'), }).css; } diff --git a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/replace-static-breakpoint-mixins.test.ts b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/replace-static-breakpoint-mixins.test.ts index 785fe142335..f622bab5ec3 100644 --- a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/replace-static-breakpoint-mixins.test.ts +++ b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/replace-static-breakpoint-mixins.test.ts @@ -1,12 +1,17 @@ import {check} from '../../../utilities/testUtils'; const migration = 'replace-static-breakpoint-mixins'; -const fixtures = ['replace-static-breakpoint-mixins']; +const fixtures = ['replace-static-breakpoint-mixins', 'with-namespace']; for (const fixture of fixtures) { check(__dirname, { fixture, migration, extension: 'scss', + options: { + namespace: fixture.includes('with-namespace') + ? 'legacy-polaris-v8' + : undefined, + }, }); } diff --git a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.input.scss b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.input.scss new file mode 100644 index 00000000000..38437c954b4 --- /dev/null +++ b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.input.scss @@ -0,0 +1,120 @@ +@use 'global-styles/legacy-polaris-v8'; + +.root { + @include legacy-polaris-v8.page-content-when-partially-condensed { + padding-bottom: spacing(loose); + + &.Active { + border-bottom: rem(3px) solid color('ink'); + } + + @include legacy-polaris-v8.page-content-when-not-partially-condensed { + padding: 0 spacing(extra-loose); + } + } + + @include legacy-polaris-v8.page-content-when-fully-condensed { + margin: 0 spacing(loose) spacing(tight); + } + + @include legacy-polaris-v8.page-content-when-not-fully-condensed { + border-radius: spacing(tight); + } + + @include legacy-polaris-v8.page-when-not-max-width { + border-radius: spacing(tight); + } + + @include legacy-polaris-v8.page-content-when-layout-stacked { + @include legacy-polaris-v8.stacked-elements; + } + + @include legacy-polaris-v8.page-content-when-layout-not-stacked { + border-radius: spacing(tight); + } + + @include legacy-polaris-v8.page-after-resource-list-small { + border-radius: spacing(tight); + } + + @include legacy-polaris-v8.page-before-resource-list-small { + border-radius: spacing(tight); + } + + @include legacy-polaris-v8.after-topbar-sheet { + max-width: $content-max-width + (2 * spacing(extra-loose)); + + > li { + margin-right: spacing(); + } + + &.TwoColumn > li { + flex: 0 calc(50% - #{spacing(extra-loose)}); + } + } + + @include legacy-polaris-v8.frame-with-nav-when-not-max-width { + padding: spacing(tight) 0; + } + + @mixin global-nav-offset { + @include legacy-polaris-v8.frame-when-nav-displayed { + left: $global-nav-width; + width: calc(100% - #{$global-nav-width}); + } + } + + .Large { + @include legacy-polaris-v8.frame-when-nav-displayed { + width: $sheet-desktop-width-large; + } + } + + @include legacy-polaris-v8.frame-when-nav-displayed { + @include legacy-polaris-v8.breakpoint-after( + layout-width(page-content, not-condensed) + layout-width(nav) + ) { + @content; + } + } + + @include legacy-polaris-v8.frame-when-nav-hidden { + @include legacy-polaris-v8.stick-to-bottom-container; + } + + .MinimizableVideoToolbar { + &.Inline { + @include legacy-polaris-v8.frame-when-nav-hidden { + display: none; + } + } + } + + @include legacy-polaris-v8.frame-when-nav-hidden { + @include legacy-polaris-v8.page-content-when-not-partially-condensed { + width: rem(200px); + } + } + + @mixin breakpoint-tablet-not-condensed { + @include legacy-polaris-v8.frame-when-nav-hidden { + @include legacy-polaris-v8.page-content-when-not-partially-condensed { + @content; + } + } + + @include legacy-polaris-v8.frame-when-nav-displayed { + @include legacy-polaris-v8.breakpoint-after( + layout-width(page-content, not-condensed) + layout-width(nav) + ) { + @content; + } + } + } + + > *:not(:last-child) { + @include legacy-polaris-v8.when-typography-condensed { + margin-bottom: var(--p-space-4); + } + } +} diff --git a/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.output.scss b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.output.scss new file mode 100644 index 00000000000..9bc631dce3c --- /dev/null +++ b/polaris-migrator/src/migrations/replace-static-breakpoint-mixins/tests/with-namespace.output.scss @@ -0,0 +1,120 @@ +@use 'global-styles/legacy-polaris-v8'; + +.root { + @media #{$p-breakpoints-lg-down} { + padding-bottom: spacing(loose); + + &.Active { + border-bottom: rem(3px) solid color('ink'); + } + + @media #{$p-breakpoints-md-up} { + padding: 0 spacing(extra-loose); + } + } + + @media #{$p-breakpoints-sm-down} { + margin: 0 spacing(loose) spacing(tight); + } + + @media #{$p-breakpoints-sm-up} { + border-radius: spacing(tight); + } + + @media #{$p-breakpoints-lg-down} { + border-radius: spacing(tight); + } + + @media #{$p-breakpoints-lg-down} { + @include legacy-polaris-v8.stacked-elements; + } + + @media #{$p-breakpoints-md-up} { + border-radius: spacing(tight); + } + + @media #{$p-breakpoints-sm-up} { + border-radius: spacing(tight); + } + + @media #{$p-breakpoints-sm-down} { + border-radius: spacing(tight); + } + + @media #{$p-breakpoints-sm-up} { + max-width: $content-max-width + (2 * spacing(extra-loose)); + + > li { + margin-right: spacing(); + } + + &.TwoColumn > li { + flex: 0 calc(50% - #{spacing(extra-loose)}); + } + } + + @media #{$p-breakpoints-lg-down} { + padding: spacing(tight) 0; + } + + @mixin global-nav-offset { + @media #{$p-breakpoints-md-up} { + left: $global-nav-width; + width: calc(100% - #{$global-nav-width}); + } + } + + .Large { + @media #{$p-breakpoints-md-up} { + width: $sheet-desktop-width-large; + } + } + + @media #{$p-breakpoints-md-up} { + @include legacy-polaris-v8.breakpoint-after( + layout-width(page-content, not-condensed) + layout-width(nav) + ) { + @content; + } + } + + @media #{$p-breakpoints-md-down} { + @include legacy-polaris-v8.stick-to-bottom-container; + } + + .MinimizableVideoToolbar { + &.Inline { + @media #{$p-breakpoints-md-down} { + display: none; + } + } + } + + @media #{$p-breakpoints-md-down} { + @media #{$p-breakpoints-md-up} { + width: rem(200px); + } + } + + @mixin breakpoint-tablet-not-condensed { + @media #{$p-breakpoints-md-down} { + @media #{$p-breakpoints-md-up} { + @content; + } + } + + @media #{$p-breakpoints-md-up} { + @include legacy-polaris-v8.breakpoint-after( + layout-width(page-content, not-condensed) + layout-width(nav) + ) { + @content; + } + } + } + + > *:not(:last-child) { + @media #{$p-breakpoints-md-down} { + margin-bottom: var(--p-space-4); + } + } +} diff --git a/polaris-migrator/src/utilities/sass.ts b/polaris-migrator/src/utilities/sass.ts index 45210328ff9..c13d0f296a1 100644 --- a/polaris-migrator/src/utilities/sass.ts +++ b/polaris-migrator/src/utilities/sass.ts @@ -1,5 +1,18 @@ import type {Node, ParsedValue, FunctionNode} from 'postcss-value-parser'; +/** + * Non-exhaustive CSS ident token RegExp: + * - https://drafts.csswg.org/css-syntax-3/#ident-token-diagram + * - https://www.w3.org/TR/CSS21/syndata.html#:~:text=%5B%2D%5D%3F%7Bnmstart%7D%7Bnmchar%7D* + */ +export const identTokenRegExp = /-?[_a-zA-Z][_a-zA-Z0-9-]*/; + +/** + * Non-exhaustive Sass module public identifier RegExp: + * - https://github.com/sass/sass/blob/main/spec/modules.md#syntax + */ +export const publicIdentifierRegExp = /[a-zA-Z][_a-zA-Z0-9-]*/; + function getNamespace(options?: NamespaceOptions) { return options?.namespace || ''; } From 5dede70a8e9038964a1cdcdeecedd5d3698c9640 Mon Sep 17 00:00:00 2001 From: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:14:50 -0700 Subject: [PATCH 2/5] Add migration documentation to the README --- polaris-migrator/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/polaris-migrator/README.md b/polaris-migrator/README.md index 32ceb92c875..209e67c4e7a 100644 --- a/polaris-migrator/README.md +++ b/polaris-migrator/README.md @@ -72,6 +72,19 @@ Replace the legacy Sass `spacing()` function with the supported CSS custom prope npx @shopify/polaris-migrator replace-sass-spacing ``` +### `replace-static-breakpoint-mixins` + +Replace legacy static breakpoint mixins with the new Polaris tokens [media query variables](https://github.com/Shopify/polaris/blob/main/documentation/guides/migrating-from-v9-to-v10.md#media-query-variables). + +```diff +- @include page-content-when-layout-not-stacked {} ++ @media #{$p-breakpoints-md-up} {} +``` + +```sh +npx @shopify/polaris-migrator replace-static-breakpoint-mixins +``` + ## Creating a migration ### Setup From 83b6ab860a9542b9108291ea21a85e60f0168a26 Mon Sep 17 00:00:00 2001 From: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:18:05 -0700 Subject: [PATCH 3/5] Add changeset entry --- .changeset/sharp-phones-film.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sharp-phones-film.md diff --git a/.changeset/sharp-phones-film.md b/.changeset/sharp-phones-film.md new file mode 100644 index 00000000000..55e3cf13b77 --- /dev/null +++ b/.changeset/sharp-phones-film.md @@ -0,0 +1,5 @@ +--- +'@shopify/polaris-migrator': patch +--- + +Add namespace support to the `replace-static-breakpoint-mixins` migration From d994b8a9af7c77288aad202c858e0ba7cad52eaa Mon Sep 17 00:00:00 2001 From: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Date: Mon, 3 Oct 2022 12:23:49 -0700 Subject: [PATCH 4/5] Update polaris-migrator/README.md --- polaris-migrator/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris-migrator/README.md b/polaris-migrator/README.md index 209e67c4e7a..ddd9a75bb33 100644 --- a/polaris-migrator/README.md +++ b/polaris-migrator/README.md @@ -74,7 +74,7 @@ npx @shopify/polaris-migrator replace-sass-spacing ### `replace-static-breakpoint-mixins` -Replace legacy static breakpoint mixins with the new Polaris tokens [media query variables](https://github.com/Shopify/polaris/blob/main/documentation/guides/migrating-from-v9-to-v10.md#media-query-variables). +Replace legacy static breakpoint mixins with the new Polaris [media query variables](https://github.com/Shopify/polaris/blob/main/documentation/guides/migrating-from-v9-to-v10.md#media-query-variables). ```diff - @include page-content-when-layout-not-stacked {} From 21f304c80f575be7466141b8e53ea88ab91bf25e Mon Sep 17 00:00:00 2001 From: Aaron Casanova <32409546+aaronccasanova@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:48:08 -0700 Subject: [PATCH 5/5] Remove getNamespace export --- polaris-migrator/src/utilities/sass.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/polaris-migrator/src/utilities/sass.ts b/polaris-migrator/src/utilities/sass.ts index 2b83518696b..43603df000f 100644 --- a/polaris-migrator/src/utilities/sass.ts +++ b/polaris-migrator/src/utilities/sass.ts @@ -11,7 +11,7 @@ import {isKeyOf} from './type-guards'; const defaultNamespace = ''; -export function getNamespace(options?: NamespaceOptions) { +function getNamespace(options?: NamespaceOptions) { return options?.namespace || defaultNamespace; }