From bba0fa665a454ab2f261952da7e8534dc97e6903 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 12 Oct 2023 21:32:05 +0000 Subject: [PATCH 01/15] Break out config file types --- __tests__/no-unused-vars.js | 3 ++ index.js | 84 ++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 10 deletions(-) diff --git a/__tests__/no-unused-vars.js b/__tests__/no-unused-vars.js index 93a8a805..a07dae30 100644 --- a/__tests__/no-unused-vars.js +++ b/__tests__/no-unused-vars.js @@ -9,6 +9,7 @@ describe('primer/no-unused-vars', () => { it('finds unused vars', () => { const config = { plugins: [pluginPath], + customSyntax: 'postcss-scss', rules: { [ruleName]: [true, {files: fixture('*.scss')}], }, @@ -27,6 +28,7 @@ describe('primer/no-unused-vars', () => { it(`doesn't run when disabled`, () => { const config = { plugins: [pluginPath], + customSyntax: 'postcss-scss', rules: { [ruleName]: false, }, @@ -45,6 +47,7 @@ describe('primer/no-unused-vars', () => { it(`talks a lot with {verbose: true}`, () => { const config = { plugins: [pluginPath], + customSyntax: 'postcss-scss', rules: { [ruleName]: [true, {files: fixture('*.scss'), verbose: true}], }, diff --git a/index.js b/index.js index d6c3d80b..e92532b2 100644 --- a/index.js +++ b/index.js @@ -3,12 +3,10 @@ const propertyOrder = require('./property-order') module.exports = { extends: ['stylelint-config-standard'], - customSyntax: require('postcss-scss'), ignoreFiles: ['**/*.js', '**/*.cjs'], plugins: [ 'stylelint-no-unsupported-browser-features', 'stylelint-order', - 'stylelint-scss', './plugins/borders', './plugins/box-shadow', './plugins/colors', @@ -75,14 +73,6 @@ module.exports = { 'primer/spacing': true, 'primer/typography': true, 'primer/utilities': null, - 'scss/at-extend-no-missing-placeholder': true, - 'scss/at-rule-no-unknown': true, - 'scss/declaration-nested-properties-no-divided-groups': true, - 'scss/dollar-variable-no-missing-interpolation': true, - 'scss/function-quote-no-quoted-strings-inside': true, - 'scss/function-unquote-no-unquoted-strings-inside': true, - 'scss/no-duplicate-mixins': true, - 'scss/selector-no-redundant-nesting-selector': true, 'selector-class-pattern': null, 'selector-max-compound-selectors': 3, 'selector-max-id': 0, @@ -100,4 +90,78 @@ module.exports = { 'media-query-no-invalid': null, 'media-feature-range-notation': ['prefix'], }, + overrides: [ + { + files: ['*.scss', '**/*.scss'], + customSyntax: require('postcss-scss'), + plugins: ['stylelint-scss'], + rules: { + 'scss/at-extend-no-missing-placeholder': true, + 'scss/at-rule-no-unknown': true, + 'scss/declaration-nested-properties-no-divided-groups': true, + 'scss/dollar-variable-no-missing-interpolation': true, + 'scss/function-quote-no-quoted-strings-inside': true, + 'scss/function-unquote-no-unquoted-strings-inside': true, + 'scss/no-duplicate-mixins': true, + 'scss/selector-no-redundant-nesting-selector': true, + }, + }, + { + files: ['*.tsx', '**/*.tsx'], + rules: { + 'order/properties-order': null, + 'rule-empty-line-before': null, + 'declaration-empty-line-before': null, + 'comment-empty-line-before': null, + 'length-zero-no-unit': null, + 'scss/selector-no-redundant-nesting-selector': null, + 'selector-max-type': null, + 'primer/spacing': null, + 'primer/colors': null, + 'primer/borders': null, + 'primer/typography': null, + 'primer/box-shadow': null, + 'primer/no-deprecated-colors': [ + true, + { + inlineFallback: true, + }, + ], + 'primer/no-scale-colors': null, + 'primer/utilities': null, + 'property-no-unknown': [ + true, + { + ignoreProperties: ['@container', 'container-type'], + }, + ], + 'scss/at-rule-no-unknown': [ + true, + { + ignoreAtRules: ['container', 'container-type'], + }, + ], + 'primer/no-override': null, + }, + }, + { + files: ['*.pcss', '**/*.pcss'], + rules: { + 'custom-property-pattern': null, + 'selector-class-pattern': null, + 'keyframes-name-pattern': null, + 'no-descending-specificity': null, + 'declaration-block-no-redundant-longhand-properties': null, + 'color-function-notation': 'legacy', + 'selector-nested-pattern': '^&\\s?\\W', + 'at-rule-no-unknown': [ + true, + { + ignoreAtRules: ['mixin', 'define-mixin'], + }, + ], + 'primer/no-deprecated-colors': true, + }, + }, + ], } From 60ad3dd37bdd90e6dccafe06fb2e460deca57b11 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Thu, 12 Oct 2023 21:42:36 +0000 Subject: [PATCH 02/15] Moving some primer plugins to scss --- index.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index e92532b2..8cfcb8be 100644 --- a/index.js +++ b/index.js @@ -7,7 +7,6 @@ module.exports = { plugins: [ 'stylelint-no-unsupported-browser-features', 'stylelint-order', - './plugins/borders', './plugins/box-shadow', './plugins/colors', './plugins/no-deprecated-colors', @@ -17,8 +16,6 @@ module.exports = { './plugins/no-undefined-vars', './plugins/no-unused-vars', './plugins/responsive-widths', - './plugins/spacing', - './plugins/typography', './plugins/utilities', ], rules: { @@ -53,7 +50,6 @@ module.exports = { 'number-max-precision': null, 'order/properties-order': propertyOrder, 'plugin/no-unsupported-browser-features': [true, {severity: 'warning', browsers}], - 'primer/borders': true, 'primer/box-shadow': true, 'primer/colors': true, 'primer/no-deprecated-colors': true, @@ -70,8 +66,6 @@ module.exports = { ], 'primer/no-unused-vars': [true, {severity: 'warning'}], 'primer/responsive-widths': true, - 'primer/spacing': true, - 'primer/typography': true, 'primer/utilities': null, 'selector-class-pattern': null, 'selector-max-compound-selectors': 3, @@ -94,7 +88,7 @@ module.exports = { { files: ['*.scss', '**/*.scss'], customSyntax: require('postcss-scss'), - plugins: ['stylelint-scss'], + plugins: ['stylelint-scss', './plugins/borders', './plugins/typography', './plugins/spacing'], rules: { 'scss/at-extend-no-missing-placeholder': true, 'scss/at-rule-no-unknown': true, @@ -104,6 +98,9 @@ module.exports = { 'scss/function-unquote-no-unquoted-strings-inside': true, 'scss/no-duplicate-mixins': true, 'scss/selector-no-redundant-nesting-selector': true, + 'primer/borders': true, + 'primer/spacing': true, + 'primer/typography': true }, }, { From 2b0ee78c222eed2b95e2f07c3c23c8457f066210 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Tue, 16 Apr 2024 23:06:17 +0000 Subject: [PATCH 03/15] Some cleanup after merge conflicts --- index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 0b7e7ad7..2df03a07 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,5 @@ import browsers from '@github/browserslist-config' import propertyOrder from './property-order.js' -import scssSyntax from 'postcss-scss' import borders from './plugins/borders.js' import boxShadow from './plugins/box-shadow.js' @@ -24,7 +23,6 @@ export default { plugins: [ 'stylelint-no-unsupported-browser-features', 'stylelint-order', - 'stylelint-scss', borders, boxShadow, colors, @@ -72,6 +70,7 @@ export default { 'number-max-precision': null, 'order/properties-order': propertyOrder, 'plugin/no-unsupported-browser-features': [true, {severity: 'warning', browsers}], + 'primer/borders': true, 'primer/box-shadow': true, 'primer/colors': true, 'primer/no-deprecated-colors': true, @@ -82,6 +81,8 @@ export default { ], 'primer/no-unused-vars': [true, {severity: 'warning'}], 'primer/responsive-widths': true, + 'primer/spacing': true, + 'primer/typography': true, 'primer/utilities': null, 'selector-class-pattern': null, 'selector-max-compound-selectors': 3, @@ -103,8 +104,8 @@ export default { overrides: [ { files: ['*.scss', '**/*.scss'], - customSyntax: scssSyntax, - plugins: ['stylelint-scss', './plugins/borders', './plugins/typography', './plugins/spacing'], + customSyntax: 'postcss-scss', + plugins: ['stylelint-scss'], rules: { 'scss/at-extend-no-missing-placeholder': true, 'scss/at-rule-no-unknown': true, From b525d1d45d3aa9a140b490819d9e4df7ced6eb5b Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 00:00:37 +0000 Subject: [PATCH 04/15] Some adjusting --- .stylelintrc.json | 2 +- __tests__/__fixtures__/good/example.scss | 89 ++++++++++++++++++++++++ index.js | 14 +++- package-lock.json | 17 ++++- package.json | 3 +- 5 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 __tests__/__fixtures__/good/example.scss diff --git a/.stylelintrc.json b/.stylelintrc.json index 8e7a8122..89430a61 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1 +1 @@ -{ "extends": ["./index"] } \ No newline at end of file +{ "extends": ["./dist/index"] } \ No newline at end of file diff --git a/__tests__/__fixtures__/good/example.scss b/__tests__/__fixtures__/good/example.scss new file mode 100644 index 00000000..85582424 --- /dev/null +++ b/__tests__/__fixtures__/good/example.scss @@ -0,0 +1,89 @@ +.sugest { + position: relative; + top: 0; + left: 0; + min-width: 180px; + padding: 0; + margin: 0; + margin-top: $spacer-4; + list-style: none; + cursor: pointer; + background: var(--overlay-bgColor); + border: $border-width $border-style var(--borderColor-default); + border-radius: $border-radius; + box-shadow: var(--shadow-resting-medium); + + .li { + display: block; + padding: $spacer-1 $spacer-2; + font-weight: $font-weight-semibold; + border-bottom: $border-width $border-style var(--borderColor-muted); + + .foo { + font-weight: $font-weight-normal; + color: var(--fgColor-muted); + } + + &:last-child { + border-bottom: 0; + border-bottom-right-radius: $border-radius; + border-bottom-left-radius: $border-radius; + } + + &:first-child { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + } + + &:hover { + color: var(--fgColor-onEmphasis); + text-decoration: none; + background: var(--bgColor-accent-emphasis); + + .foo { + color: var(--fgColor-onEmphasis); + } + + .svgicon { + color: inherit !important; + } + } + + &[aria-selected='true'], + &.nav-focus { + color: var(--fgColor-onEmphasis); + text-decoration: none; + background: var(--bgColor-accent-emphasis); + + .foo { + color: var(--fgColor-onEmphasis); + } + + .svgicon { + color: inherit !important; + } + } + } +} + +.sugest-container { + position: absolute; + top: 0; + left: 0; + z-index: 30; +} + +// Responsive + +.responsive-page { + @media (max-width: $width-sm) { + .sugest-container { + right: $spacer-2 !important; + left: $spacer-2 !important; + } + + .sugest .li { + padding: $spacer-2 $spacer-3; + } + } +} \ No newline at end of file diff --git a/index.js b/index.js index 2df03a07..16ecc2e3 100644 --- a/index.js +++ b/index.js @@ -69,7 +69,14 @@ export default { 'no-invalid-position-at-import-rule': [true, {ignoreAtRules: ['use']}], 'number-max-precision': null, 'order/properties-order': propertyOrder, - 'plugin/no-unsupported-browser-features': [true, {severity: 'warning', browsers}], + 'plugin/no-unsupported-browser-features': [ + true, + { + severity: 'warning', + ignore: ['css-nesting'], + browsers, + }, + ], 'primer/borders': true, 'primer/box-shadow': true, 'primer/colors': true, @@ -119,13 +126,13 @@ export default { }, { files: ['*.tsx', '**/*.tsx'], + customSyntax: 'postcss-styled-syntax', rules: { 'order/properties-order': null, 'rule-empty-line-before': null, 'declaration-empty-line-before': null, 'comment-empty-line-before': null, 'length-zero-no-unit': null, - 'scss/selector-no-redundant-nesting-selector': null, 'selector-max-type': null, 'primer/spacing': null, 'primer/colors': null, @@ -138,7 +145,8 @@ export default { inlineFallback: true, }, ], - 'primer/no-scale-colors': null, + 'primer/no-scale-colors': true, + 'primer/no-display-colors': true, 'primer/utilities': null, 'property-no-unknown': [ true, diff --git a/package-lock.json b/package-lock.json index 7f1da197..fa5bf9ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "anymatch": "^3.1.1", "globby": "^11.0.1", "postcss-scss": "^4.0.2", + "postcss-styled-syntax": "^0.6.4", "postcss-value-parser": "^4.0.2", "string.prototype.matchall": "^4.0.2", "stylelint": "^16.3.1", @@ -8296,6 +8297,20 @@ "postcss": "^8.4.20" } }, + "node_modules/postcss-styled-syntax": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/postcss-styled-syntax/-/postcss-styled-syntax-0.6.4.tgz", + "integrity": "sha512-uWiLn+9rKgIghUYmTHvXMR6MnyPULMe9Gv3bV537Fg4FH6CA6cn21WMjKss2Qb98LUhT847tKfnRGG3FhSOgUQ==", + "dependencies": { + "typescript": "^5.3.3" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", @@ -10022,8 +10037,6 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "devOptional": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index e83e02c8..0f71c593 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build": "rollup -c", "clean": "rimraf dist", "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --coverage false", - "test:stylelint": "stylelint __tests__/__fixtures__/uses-vars.scss", + "test:stylelint": "stylelint __tests__/__fixtures__/good/", "lint": "eslint .", "release": "changeset publish" }, @@ -46,6 +46,7 @@ "anymatch": "^3.1.1", "globby": "^11.0.1", "postcss-scss": "^4.0.2", + "postcss-styled-syntax": "^0.6.4", "postcss-value-parser": "^4.0.2", "string.prototype.matchall": "^4.0.2", "stylelint": "^16.3.1", From 393fb813b9ec03711bf0a554401af38477efded9 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 00:06:08 +0000 Subject: [PATCH 05/15] use cjs for local linting --- .stylelintrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index 89430a61..4107cc7d 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1 +1 @@ -{ "extends": ["./dist/index"] } \ No newline at end of file +{ "extends": ["./dist/index.cjs"] } \ No newline at end of file From 1a4f2a956f1a1b48afd743f2fd23494e9bfec5be Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 00:06:16 +0000 Subject: [PATCH 06/15] Ignore partial support --- index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/index.js b/index.js index 16ecc2e3..dee0d225 100644 --- a/index.js +++ b/index.js @@ -74,6 +74,7 @@ export default { { severity: 'warning', ignore: ['css-nesting'], + ignorePartialSupport: true, browsers, }, ], From d1303d813227990d293ebdcdc18d1082cd63c226 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 00:21:51 +0000 Subject: [PATCH 07/15] Add pcss example --- __tests__/__fixtures__/good/example.pcss | 427 +++++++++++++++++++++++ index.js | 5 +- 2 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 __tests__/__fixtures__/good/example.pcss diff --git a/__tests__/__fixtures__/good/example.pcss b/__tests__/__fixtures__/good/example.pcss new file mode 100644 index 00000000..468ccd18 --- /dev/null +++ b/__tests__/__fixtures__/good/example.pcss @@ -0,0 +1,427 @@ +/* stylelint-disable primer/borders */ +/* stylelint-disable primer/typography */ +/* stylelint-disable primer/spacing */ + +/* CSS for Button */ + +/* temporary, pre primitives release */ +:root { + --duration-fast: 80ms; + --easing-easeInOut: cubic-bezier(0.65, 0, 0.35, 1); +} + +/* base button */ +.Button { + position: relative; + display: inline-flex; + min-width: max-content; + height: var(--control-medium-size); + padding: 0 var(--control-medium-paddingInline-normal); + font-size: var(--text-body-size-medium); + font-weight: var(--base-text-weight-medium); + color: var(--button-default-fgColor-rest); + text-align: center; + cursor: pointer; + flex-direction: row; + user-select: none; + background-color: transparent; + border: var(--borderWidth-thin) $border-style; + border-color: transparent; + border-radius: var(--borderRadius-medium); + transition: var(--duration-fast) var(--easing-easeInOut); + transition-property: color, fill, background-color, border-color; + justify-content: space-between; + align-items: center; + gap: var(--base-size-4); + + /* mobile friendly sizing */ + @media (pointer: coarse) { + &::before { + @mixin minTouchTarget 48px, 48px; + } + } + + /* base states */ + + &:hover { + transition-duration: var(--duration-fast); + } + + &:active { + transition: none; + } + + &:disabled, + &[aria-disabled='true'] { + cursor: not-allowed; + box-shadow: none; + } + + &.Button--iconOnly { + color: var(--fgColor-muted); + } +} + +/* wrap grid content to allow trailingAction to lock-right */ +.Button-content { + flex: 1 0 auto; + display: grid; + grid-template-areas: 'leadingVisual text trailingVisual'; + grid-template-columns: min-content minmax(0, auto) min-content; + align-items: center; + place-content: center; + + /* padding-bottom: 1px; optical alignment for firefox */ + + & > :not(:last-child) { + margin-right: var(--control-medium-gap); + } +} + +/* center child elements for fullWidth */ +.Button-content--alignStart { + justify-content: start; +} + +/* button child elements */ + +/* align svg */ +.Button-visual { + display: flex; + pointer-events: none; /* allow click handler to work, avoiding visuals */ + + & .counta { + color: inherit; + background-color: var(--buttonCounter-default-bgColor-rest); + } +} + +.Button-label { + line-height: var(--text-body-lineHeight-medium); + white-space: nowrap; + grid-area: text; +} + +.Button-leadingVisual { + grid-area: leadingVisual; +} + +.Button-leadingVisual .svg { + fill: currentcolor; +} + +.Button-trailingVisual { + grid-area: trailingVisual; +} + +.Button-trailingAction { + margin-right: calc(var(--base-size-4) * -1); +} + +/* sizes */ + +.Button--small { + height: var(--control-small-size); + padding: 0 var(--control-small-paddingInline-condensed); + font-size: var(--text-body-size-small); + gap: var(--control-small-gap); + + & .Button-label { + line-height: var(--text-body-lineHeight-small); + } + + & .Button-content { + & > :not(:last-child) { + margin-right: var(--control-small-gap); + } + } +} + +.Button--large { + height: var(--control-large-size); + padding: 0 var(--control-large-paddingInline-spacious); + gap: var(--control-large-gap); + + & .Button-label { + line-height: var(--text-body-lineHeight-large); + } + + & .Button-content { + & > :not(:last-child) { + margin-right: var(--control-large-gap); + } + } +} + +.Button--fullWidth { + width: 100%; +} + +/* allow button label text to wrap */ + +.Button--labelWrap { + min-width: fit-content; + height: unset; + min-height: var(--control-medium-size); + + & .Button-content { + flex: 1 1 auto; + align-self: stretch; + padding-block: calc(var(--control-medium-paddingBlock) - 2px); + } + + & .Button-label { + white-space: unset; + } + + &.Button--small { + height: unset; + min-height: var(--control-small-size); + + & .Button-content { + padding-block: calc(var(--control-small-paddingBlock) - 2px); + } + } + + &.Button--large { + height: unset; + min-height: var(--control-large-size); + padding-inline: var(--control-large-paddingInline-spacious); + + & .Button-content { + padding-block: calc(var(--control-large-paddingBlock) - 2px); + } + } +} + +/* variants */ + +/* primary */ +.Button--primary { + color: var(--button-primary-fgColor-rest); + fill: var(--button-primary-iconColor-rest); + background-color: var(--button-primary-bgColor-rest); + border-color: var(--button-primary-borderColor-rest); + box-shadow: var(--shadow-resting-small, var(--color-btn-primary-shadow)); + + &.Button--iconOnly { + color: var(--button-primary-iconColor-rest); + } + + &:hover:not(:disabled, .Button--inactive) { + background-color: var(--button-primary-bgColor-hover); + border-color: var(--button-primary-borderColor-hover); + } + + /* fallback :focus state */ + &:focus { + @mixin focusOutlineOnEmphasis; + + /* remove fallback :focus if :focus-visible is supported */ + &:not(:focus-visible) { + outline: solid 1px transparent; + box-shadow: none; + } + } + + /* default focus state */ + &:focus-visible { + @mixin focusOutlineOnEmphasis; + } + + &:active:not(:disabled), + &[aria-pressed='true'] { + background-color: var(--button-primary-bgColor-active); + box-shadow: var(--button-primary-shadow-selected); + } + + &:disabled, + &[aria-disabled='true'] { + color: var(--button-primary-fgColor-disabled); + fill: var(--button-primary-fgColor-disabled); + background-color: var(--button-primary-bgColor-disabled); + border-color: var(--button-primary-borderColor-disabled); + } + + & .counta { + color: inherit; + background-color: var(--buttonCounter-primary-bgColor-rest); + } +} + +/* default (secondary) */ +.Button--secondary { + color: var(--button-default-fgColor-rest); + fill: var(--fgColor-muted); /* help this */ + background-color: var(--button-default-bgColor-rest); + border-color: var(--button-default-borderColor-rest); + box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset); + + &:hover:not(:disabled, .Button--inactive) { + background-color: var(--button-default-bgColor-hover); + border-color: var(--button-default-borderColor-hover); + } + + &:active:not(:disabled) { + background-color: var(--button-default-bgColor-active); + border-color: var(--button-default-borderColor-active); + } + + &[aria-pressed='true'] { + background-color: var(--button-default-bgColor-selected); + box-shadow: var(--shadow-inset); + } + + &:disabled, + &[aria-disabled='true'] { + color: var(--control-fgColor-disabled); + fill: var(--control-fgColor-disabled); + background-color: var(--button-default-bgColor-disabled); + border-color: var(--button-default-borderColor-disabled); + } +} + +.Button--invisible { + color: var(--button-default-fgColor-rest); + + &.Button--iconOnly { + color: var(--button-invisible-iconColor-rest, var(--color-fg-muted)); + } + + &:hover:not(:disabled, .Button--inactive) { + background-color: var(--control-transparent-bgColor-hover, var(--color-action-list-item-default-hover-bg)); + } + + &[aria-pressed='true'], + &:active:not(:disabled) { + background-color: var(--button-invisible-bgColor-active); + } + + &:disabled, + &[aria-disabled='true'] { + color: var(--button-invisible-fgColor-disabled); + fill: var(--button-invisible-fgColor-disabled); + background-color: var(--button-invisible-bgColor-disabled); + border-color: var(--button-invisible-borderColor-disabled); + } + + /* if button has no visuals, use link blue for text */ + &.Button--invisible-noVisuals .Button-label { + color: var(--button-invisible-fgColor-rest); + } + + & .Button-visual { + color: var(--button-invisible-iconColor-rest, var(--color-fg-muted)); + + & .counta { + color: var(--fgColor-default); + } + } +} + +.Button--link { + display: inline-block; + min-width: fit-content; + height: unset; + padding: 0; + font-size: inherit; + color: var(--fgColor-link); + fill: var(--fgColor-link); + + &:hover:not(:disabled, .Button--inactive) { + text-decoration: underline; + } + + &:focus-visible, + &:focus { + outline-offset: 2px; + } + + &:disabled, + &[aria-disabled='true'] { + color: var(--control-fgColor-disabled); + fill: var(--control-fgColor-disabled); + background-color: transparent; + border-color: transparent; + } + + & .Button-label { + white-space: unset; + } +} + +/* danger */ +.Button--danger { + color: var(--button-danger-fgColor-rest); + fill: var(--button-danger-iconColor-rest); + background-color: var(--button-danger-bgColor-rest); + border-color: var(--button-danger-borderColor-rest); + box-shadow: var(--button-default-shadow-resting), var(--button-default-shadow-inset); + + &.Button--iconOnly { + color: var(--button-danger-iconColor-rest); + } + + &:hover:not(:disabled, .Button--inactive) { + color: var(--button-danger-fgColor-hover); + fill: var(--button-danger-fgColor-hover); + background-color: var(--button-danger-bgColor-hover); + border-color: var(--button-danger-borderColor-hover); + box-shadow: var(--shadow-resting-small); + + & .counta { + color: var(--buttonCounter-danger-fgColor-hover); + background-color: var(--buttonCounter-danger-bgColor-hover); + } + } + + &:active:not(:disabled), + &[aria-pressed='true'] { + color: var(--button-danger-fgColor-active); + fill: var(--button-danger-fgColor-active); + background-color: var(--button-danger-bgColor-active); + border-color: var(--button-danger-borderColor-active); + box-shadow: var(--button-danger-shadow-selected); + } + + &:disabled, + &[aria-disabled='true'] { + color: var(--button-danger-fgColor-disabled); + fill: var(--button-danger-fgColor-disabled); + background-color: var(--button-danger-bgColor-disabled); + border-color: var(--button-default-borderColor-disabled); + + & .counta { + color: var(--buttonCounter-danger-fgColor-disabled); + background-color: var(--buttonCounter-danger-bgColor-disabled); + } + } + + & .counta { + color: var(--buttonCounter-danger-fgColor-rest); + background-color: var(--buttonCounter-danger-bgColor-rest); + } +} + +.Button--iconOnly { + display: inline-grid; + width: var(--control-medium-size); + padding: unset; + place-content: center; + + &.Button--small { + width: var(--control-small-size); + } + + &.Button--large { + width: var(--control-large-size); + } +} + +/* `disabled` takes precedence over `inactive` */ +.Button--inactive:not([aria-disabled='true'], :disabled) { + color: var(--button-inactive-fgColor); + cursor: default; + background-color: var(--button-inactive-bgColor); + border: 0; +} \ No newline at end of file diff --git a/index.js b/index.js index dee0d225..f3b7a577 100644 --- a/index.js +++ b/index.js @@ -20,6 +20,7 @@ import noDisplayColors from './plugins/no-display-colors.js' export default { extends: ['stylelint-config-standard'], ignoreFiles: ['**/*.js', '**/*.cjs'], + reportNeedlessDisables: true, plugins: [ 'stylelint-no-unsupported-browser-features', 'stylelint-order', @@ -122,7 +123,7 @@ export default { 'scss/function-quote-no-quoted-strings-inside': true, 'scss/function-unquote-no-unquoted-strings-inside': true, 'scss/no-duplicate-mixins': true, - 'scss/selector-no-redundant-nesting-selector': true + 'scss/selector-no-redundant-nesting-selector': true, }, }, { @@ -167,6 +168,8 @@ export default { { files: ['*.pcss', '**/*.pcss'], rules: { + 'media-feature-range-notation': null, + 'import-notation': null, 'custom-property-pattern': null, 'selector-class-pattern': null, 'keyframes-name-pattern': null, From 9f83db57fee6fdad04b5123ec021e90cd4c58dc4 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 03:26:16 +0000 Subject: [PATCH 08/15] Fixes for typescriptreact --- .stylelintrc.json | 2 +- __tests__/__fixtures__/good/example.tsx | 180 ++++++++++++++++++++++++ index.js | 6 - 3 files changed, 181 insertions(+), 7 deletions(-) create mode 100644 __tests__/__fixtures__/good/example.tsx diff --git a/.stylelintrc.json b/.stylelintrc.json index 4107cc7d..89430a61 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1 +1 @@ -{ "extends": ["./dist/index.cjs"] } \ No newline at end of file +{ "extends": ["./dist/index"] } \ No newline at end of file diff --git a/__tests__/__fixtures__/good/example.tsx b/__tests__/__fixtures__/good/example.tsx new file mode 100644 index 00000000..13f849b6 --- /dev/null +++ b/__tests__/__fixtures__/good/example.tsx @@ -0,0 +1,180 @@ +import {testIdProps} from '@github-ui/test-id-props' +import {AlertIcon, CheckCircleIcon, InfoIcon, StopIcon, XIcon} from '@primer/octicons-react' +import {Box, Octicon, sx, type SxProp, Text, themeGet} from '@primer/react' +import {useCallback, useEffect, useRef} from 'react' +import styled, {keyframes} from 'styled-components' + +import {TOAST_ANIMATION_LENGTH, type ToastItem, ToastType} from './types' + +type IToastCloseButtonProps = Omit, 'color'> + +const StyledButton = styled.button` + padding: 8px; + margin: 8px 10px 8px 0px; + border-radius: 3px; + color: ${themeGet('colors.fg.onEmphasis')}; + border: 0; + background: transparent; + outline: none; + cursor: pointer; + + /* can be removed if using Primer IconButton component */ + &:focus { + box-shadow: 0 0 0 2px ${themeGet('colors.accent.fg')}; + } +` + +const ToastCloseButton = (props: IToastCloseButtonProps) => ( + + + +) + +/** + * Lookup for converting toast types into Primer colors + */ +export const stateColorMap = { + [ToastType.default]: 'accent.emphasis', + [ToastType.success]: 'success.emphasis', + [ToastType.warning]: 'attention.emphasis', + [ToastType.error]: 'danger.emphasis', +} + +const DefaultIcon = +const SuccessIcon = +export const WarningIcon = +const ErrorIcon = + +const stateMap = { + [ToastType.default]: DefaultIcon, + [ToastType.success]: SuccessIcon, + [ToastType.warning]: WarningIcon, + [ToastType.error]: ErrorIcon, +} + +const toastEnter = keyframes` + from { + transform: translateX(-400px); + } + to { + transform: translateX(0); + } +` + +const toastLeave = keyframes` + from { + transform: translateX(0); + } + to { + transform: translateX(-460px); + } + +` + +export const IconContainer = styled(Box)` + flex-shrink: 0; + padding: ${themeGet('space.3')}; +` + +export const StyledToast = styled.div` + position: fixed; + display: flex; + gap: ${themeGet('space.2')}; + box-shadow: ${themeGet('shadows.shadow.large')}; + background-color: ${themeGet('colors.neutral.emphasisPlus')}; + border-radius: ${themeGet('radii.2')}; + align-items: stretch; + box-sizing: border-box; + overflow: hidden; + max-width: 400px; + bottom: 66px; + left: 12px;z-index:99; + + animation: ${toastEnter} ${TOAST_ANIMATION_LENGTH}ms cubic-bezier(0.25, 1, 0.5, 1); + + &.toast-leave { + animation: ${toastLeave} ${TOAST_ANIMATION_LENGTH}ms cubic-bezier(0.5, 0, 0.75, 0) forwards; + } +` + +export const ToastAction = styled.button` + background-color: transparent; + border: 0; + font-weight: ${themeGet('fontWeights.bold')}; + margin-left: ${themeGet('space.2')}; + + margin-top: ${themeGet('space.3')}; + margin-bottom: ${themeGet('space.3')}; + color: ${themeGet('colors.fg.onEmphasis')}; + font-size: ${themeGet('fontSizes.1')}; + font-family: inherit; + outline: none; + padding: 0; + white-space: nowrap; + + &:hover { + text-decoration: underline; + } + + &:focus { + border-color: transparent; + box-shadow: 0 0 0 3px ${themeGet('colors.border.default')}; + } + ${sx} +` + +interface ToastProps { + removeToast: (id: number) => void + startRemovingToast: (id: number) => void + toast: ToastItem +} + +/** + * Component for rendering a toast within the application + */ +const Toast = (props: ToastProps) => { + const {toast, startRemovingToast} = props + const callToActionRef = useRef(null) + + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + // eslint-disable-next-line @github-ui/ui-commands/no-manual-shortcut-logic + if (callToActionRef.current && event.ctrlKey && event.key === 't') { + callToActionRef.current.focus() + toast.timeout?.cancel() + } + } + document.addEventListener('keydown', handleKeyDown) + return () => { + document.removeEventListener('keydown', handleKeyDown) + } + }, [toast]) + + const toastIcon = toast.icon ? ( + + ) : ( + stateMap[toast.type] + ) + + const handleActionClick = useCallback(() => { + toast.action?.handleClick() + startRemovingToast(toast.id) + }, [toast, startRemovingToast]) + + return ( + + + {toastIcon} + + {toast.message} + {toast.action && ( + + {toast.action.text} + + )} + startRemovingToast(toast.id)} /> + + ) +} + +export default Toast \ No newline at end of file diff --git a/index.js b/index.js index f3b7a577..0a399dba 100644 --- a/index.js +++ b/index.js @@ -156,12 +156,6 @@ export default { ignoreProperties: ['@container', 'container-type'], }, ], - 'scss/at-rule-no-unknown': [ - true, - { - ignoreAtRules: ['container', 'container-type'], - }, - ], 'primer/no-override': null, }, }, From 6c976048ba9ff15f9722e17cad8afd8223bf0ce9 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 03:26:59 +0000 Subject: [PATCH 09/15] don't need duplicate file selectors --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 0a399dba..c70aeb31 100644 --- a/index.js +++ b/index.js @@ -112,7 +112,7 @@ export default { }, overrides: [ { - files: ['*.scss', '**/*.scss'], + files: ['**/*.scss'], customSyntax: 'postcss-scss', plugins: ['stylelint-scss'], rules: { @@ -127,7 +127,7 @@ export default { }, }, { - files: ['*.tsx', '**/*.tsx'], + files: ['**/*.tsx'], customSyntax: 'postcss-styled-syntax', rules: { 'order/properties-order': null, @@ -160,7 +160,7 @@ export default { }, }, { - files: ['*.pcss', '**/*.pcss'], + files: ['**/*.pcss'], rules: { 'media-feature-range-notation': null, 'import-notation': null, From a3dfe886a68928f60329b1777f3b0c8e84853a0f Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 03:33:20 +0000 Subject: [PATCH 10/15] Adding a module --- .stylelintrc.json | 2 +- .../__fixtures__/good/example.module.css | 144 ++++++++++++++++++ index.js | 6 + 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 __tests__/__fixtures__/good/example.module.css diff --git a/.stylelintrc.json b/.stylelintrc.json index 89430a61..4633d4ee 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1 +1 @@ -{ "extends": ["./dist/index"] } \ No newline at end of file +{ "extends": ["./dist/index"], "cache": false } \ No newline at end of file diff --git a/__tests__/__fixtures__/good/example.module.css b/__tests__/__fixtures__/good/example.module.css new file mode 100644 index 00000000..5721ba48 --- /dev/null +++ b/__tests__/__fixtures__/good/example.module.css @@ -0,0 +1,144 @@ +.header { + height: 264px; + overflow: hidden; +} + +.gradient { + --offset: -500px; + + position: absolute; + top: 0; + /* stylelint-disable-next-line primer/responsive-widths */ + width: 1000px; + height: 800px; +} + +.octicon { + display: inline-block; +} + +.gradient-left { + /* stylelint-disable primer/no-undefined-vars */ + top: var(--offset); + left: var(--offset); + /* stylelint-disable-next-line primer/colors */ + background: radial-gradient(30% 70% at 50% 50%, rgb(130 80 223 / 0.2) 0%, rgb(130 80 223 / 0) 100%); +} + +.gradient-right { + right: var(--offset); + /* stylelint-disable-next-line primer/colors */ + background: radial-gradient(30% 70% at 50% 50%, rgb(9 107 222 / 0.3) 0%, rgb(9 107 222 / 0) 100%); +} + +.header-background, +.header-copilot { + user-select: none; +} + +.header-background { + top: -220px; + right: -110px; + height: 580px; +} + +.header-copilot { + top: -35%; + right: 100px; + height: 146px; +} + +.header-content { + position: relative; + z-index: 1; +} + +.negative-margin { + /* stylelint-disable-next-line primer/spacing */ + margin: -0.5rem; +} + +.search-input { + max-width: 600px; +} + +.marketplace-featured-grid, +.marketplace-list-grid { + display: grid; + gap: 1rem; +} + +.marketplace-featured-grid { + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + max-width: 100%; +} + +.marketplace-list-grid { + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + max-width: 100%; +} + +.marketplace-item { + box-shadow: var(--shadow-resting-small, var(--color-shadow-small)); +} + +.marketplace-item:hover, +.marketplace-item:focus-within { + background-color: var(--bgColor-muted, var(--color-canvas-subtle)); +} + +.marketplace-item:focus-within { + outline: 2px solid var(--fgColor-accent, var(--color-accent-fg)); +} + +.marketplace-item-link { + color: var(--fgColor-default, var(--color-fg-default)); +} + +.marketplace-item-link:hover { + color: inherit; + text-decoration: none; +} + +.marketplace-item-link:focus { + outline: none; +} + +.marketplace-item-link::before { + position: absolute; + cursor: pointer; + content: ""; + inset: 0; +} + +.marketplace-logo { + --container-size: var(--base-size-40); + --logo-size: var(--base-size-32); + + display: grid; + place-items: center; + width: var(--container-size); + height: var(--container-size); + /* stylelint-disable-next-line primer/spacing */ + padding: var(--space-xsmall); +} + +.marketplace-logo--large { + --container-size: var(--base-size-96); + --logo-size: var(--base-size-80); +} + +.marketplace-logo-img { + width: var(--logo-size); + height: var(--logo-size); +} + +.details { + &[open] .down-icon { + display: none !important; + } + + &:not([open]) .up-icon { + display: none !important; + } +} \ No newline at end of file diff --git a/index.js b/index.js index c70aeb31..4d84c7c0 100644 --- a/index.js +++ b/index.js @@ -180,5 +180,11 @@ export default { 'primer/no-deprecated-colors': true, }, }, + { + files: ['**/*.module.css'], + rules: { + 'primer/no-override': null, + }, + }, ], } From 9e3c41dae13a8796afd695f6635b313eb31ada6f Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 16:35:35 +0000 Subject: [PATCH 11/15] Ignore fixtures folder in tests --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f71c593..64cad943 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,8 @@ ], "testPathIgnorePatterns": [ "/node_modules/", - "__tests__/utils" + "__tests__/utils", + "__tests__/__fixtures__" ] } } From 46315ecc0df56586d551b8fc0a4dde43e8f3dd65 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 16:41:53 +0000 Subject: [PATCH 12/15] Build after install --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 64cad943..5460f910 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "node": ">16.0.0" }, "scripts": { + "postinstall": "npm run build", "build": "rollup -c", "clean": "rimraf dist", "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --coverage false", From 41ee806873825e9df1ff711f9219f00a6afbcfad Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 10:08:18 -0700 Subject: [PATCH 13/15] Create real-goats-applaud.md --- .changeset/real-goats-applaud.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/real-goats-applaud.md diff --git a/.changeset/real-goats-applaud.md b/.changeset/real-goats-applaud.md new file mode 100644 index 00000000..55197090 --- /dev/null +++ b/.changeset/real-goats-applaud.md @@ -0,0 +1,5 @@ +--- +"@primer/stylelint-config": minor +--- + +Change config to accept multiple file types `.css, .scss, .modules.css, .tsx, .pcss` From a4fb0276fc39aecd73c4de24945695f9eb379748 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 17:53:20 +0000 Subject: [PATCH 14/15] Make cjs the default --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5460f910..5f16f09a 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "author": "GitHub, Inc.", "license": "MIT", "type": "module", + "main": "./dist/index.cjs", "exports": { ".": { "import": "./dist/index.js", From 91d79a769f5f71a1717eb05ad0b09bf91d045c27 Mon Sep 17 00:00:00 2001 From: Jon Rohan Date: Wed, 17 Apr 2024 19:59:20 +0000 Subject: [PATCH 15/15] adjust testing --- .github/workflows/ci.yml | 1 - .stylelintrc.json | 2 +- package.json | 5 +++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 766a4366..53d9c0e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,6 @@ jobs: - uses: actions/setup-node@v3 - run: npm ci - run: npm run test - - run: npm run test:stylelint lint: runs-on: ubuntu-latest steps: diff --git a/.stylelintrc.json b/.stylelintrc.json index 4633d4ee..623a2fea 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -1 +1 @@ -{ "extends": ["./dist/index"], "cache": false } \ No newline at end of file +{ "extends": ["./dist/index.cjs"], "cache": false } \ No newline at end of file diff --git a/package.json b/package.json index 5f16f09a..160b4b9a 100644 --- a/package.json +++ b/package.json @@ -33,10 +33,11 @@ "node": ">16.0.0" }, "scripts": { - "postinstall": "npm run build", + "pretest": "npm run build", "build": "rollup -c", "clean": "rimraf dist", - "test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --coverage false", + "test": "npm run test:jest && npm run test:stylelint", + "test:jest": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --coverage false", "test:stylelint": "stylelint __tests__/__fixtures__/good/", "lint": "eslint .", "release": "changeset publish"