@gallop.software/canon 2.1.0 → 2.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/dist/eslint/configs/recommended.d.ts +9 -10
- package/dist/eslint/configs/recommended.js +16 -12
- package/dist/eslint/configs/speedwell.d.ts +9 -10
- package/dist/eslint/configs/speedwell.js +16 -15
- package/dist/eslint/index.d.ts +13 -14
- package/dist/eslint/index.js +3 -1
- package/dist/eslint/rules/background-image-rounded.d.ts +3 -0
- package/dist/eslint/rules/background-image-rounded.js +122 -0
- package/package.json +1 -1
- package/patterns/019-background-image-rounded.md +52 -0
- package/schema.json +11 -1
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Recommended configuration
|
|
2
|
+
* Recommended configuration for ESLint flat config
|
|
3
3
|
* A sensible default for any Gallop-based template
|
|
4
4
|
*/
|
|
5
|
-
declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
5
|
+
declare const recommendedRules: {
|
|
6
|
+
readonly 'gallop/no-client-blocks': "warn";
|
|
7
|
+
readonly 'gallop/no-container-in-section': "warn";
|
|
8
|
+
readonly 'gallop/prefer-component-props': "warn";
|
|
9
|
+
readonly 'gallop/prefer-typography-components': "warn";
|
|
10
|
+
readonly 'gallop/prefer-layout-components': "warn";
|
|
11
|
+
readonly 'gallop/background-image-rounded': "warn";
|
|
13
12
|
};
|
|
14
|
-
export default
|
|
13
|
+
export default recommendedRules;
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Recommended configuration
|
|
2
|
+
* Recommended configuration for ESLint flat config
|
|
3
3
|
* A sensible default for any Gallop-based template
|
|
4
4
|
*/
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
const recommendedRules = {
|
|
6
|
+
// Blocks should be server components
|
|
7
|
+
'gallop/no-client-blocks': 'warn',
|
|
8
|
+
// Section already provides containment
|
|
9
|
+
'gallop/no-container-in-section': 'warn',
|
|
10
|
+
// Use component props instead of className for style values
|
|
11
|
+
'gallop/prefer-component-props': 'warn',
|
|
12
|
+
// Use Typography components instead of raw p/span tags
|
|
13
|
+
'gallop/prefer-typography-components': 'warn',
|
|
14
|
+
// Use Grid/Columns instead of raw div with grid classes
|
|
15
|
+
'gallop/prefer-layout-components': 'warn',
|
|
16
|
+
// Background images must have rounded="rounded-none"
|
|
17
|
+
'gallop/background-image-rounded': 'warn',
|
|
14
18
|
};
|
|
15
|
-
export default
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
19
|
+
export default recommendedRules;
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb21tZW5kZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvZXNsaW50L2NvbmZpZ3MvcmVjb21tZW5kZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBQ0gsTUFBTSxnQkFBZ0IsR0FBRztJQUN2QixxQ0FBcUM7SUFDckMseUJBQXlCLEVBQUUsTUFBTTtJQUVqQyx1Q0FBdUM7SUFDdkMsZ0NBQWdDLEVBQUUsTUFBTTtJQUV4Qyw0REFBNEQ7SUFDNUQsK0JBQStCLEVBQUUsTUFBTTtJQUV2Qyx1REFBdUQ7SUFDdkQscUNBQXFDLEVBQUUsTUFBTTtJQUU3Qyx3REFBd0Q7SUFDeEQsaUNBQWlDLEVBQUUsTUFBTTtJQUV6QyxxREFBcUQ7SUFDckQsaUNBQWlDLEVBQUUsTUFBTTtDQUNqQyxDQUFBO0FBRVYsZUFBZSxnQkFBZ0IsQ0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogUmVjb21tZW5kZWQgY29uZmlndXJhdGlvbiBmb3IgRVNMaW50IGZsYXQgY29uZmlnXG4gKiBBIHNlbnNpYmxlIGRlZmF1bHQgZm9yIGFueSBHYWxsb3AtYmFzZWQgdGVtcGxhdGVcbiAqL1xuY29uc3QgcmVjb21tZW5kZWRSdWxlcyA9IHtcbiAgLy8gQmxvY2tzIHNob3VsZCBiZSBzZXJ2ZXIgY29tcG9uZW50c1xuICAnZ2FsbG9wL25vLWNsaWVudC1ibG9ja3MnOiAnd2FybicsXG5cbiAgLy8gU2VjdGlvbiBhbHJlYWR5IHByb3ZpZGVzIGNvbnRhaW5tZW50XG4gICdnYWxsb3Avbm8tY29udGFpbmVyLWluLXNlY3Rpb24nOiAnd2FybicsXG5cbiAgLy8gVXNlIGNvbXBvbmVudCBwcm9wcyBpbnN0ZWFkIG9mIGNsYXNzTmFtZSBmb3Igc3R5bGUgdmFsdWVzXG4gICdnYWxsb3AvcHJlZmVyLWNvbXBvbmVudC1wcm9wcyc6ICd3YXJuJyxcblxuICAvLyBVc2UgVHlwb2dyYXBoeSBjb21wb25lbnRzIGluc3RlYWQgb2YgcmF3IHAvc3BhbiB0YWdzXG4gICdnYWxsb3AvcHJlZmVyLXR5cG9ncmFwaHktY29tcG9uZW50cyc6ICd3YXJuJyxcblxuICAvLyBVc2UgR3JpZC9Db2x1bW5zIGluc3RlYWQgb2YgcmF3IGRpdiB3aXRoIGdyaWQgY2xhc3Nlc1xuICAnZ2FsbG9wL3ByZWZlci1sYXlvdXQtY29tcG9uZW50cyc6ICd3YXJuJyxcblxuICAvLyBCYWNrZ3JvdW5kIGltYWdlcyBtdXN0IGhhdmUgcm91bmRlZD1cInJvdW5kZWQtbm9uZVwiXG4gICdnYWxsb3AvYmFja2dyb3VuZC1pbWFnZS1yb3VuZGVkJzogJ3dhcm4nLFxufSBhcyBjb25zdFxuXG5leHBvcnQgZGVmYXVsdCByZWNvbW1lbmRlZFJ1bGVzXG4iXX0=
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Speedwell template configuration
|
|
2
|
+
* Speedwell template configuration for ESLint flat config
|
|
3
3
|
* Enables all Gallop rules relevant to the Speedwell architecture
|
|
4
4
|
*/
|
|
5
|
-
declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
5
|
+
declare const speedwellRules: {
|
|
6
|
+
readonly 'gallop/no-client-blocks': "warn";
|
|
7
|
+
readonly 'gallop/no-container-in-section': "warn";
|
|
8
|
+
readonly 'gallop/prefer-component-props': "warn";
|
|
9
|
+
readonly 'gallop/prefer-typography-components': "warn";
|
|
10
|
+
readonly 'gallop/prefer-layout-components': "warn";
|
|
11
|
+
readonly 'gallop/background-image-rounded': "warn";
|
|
13
12
|
};
|
|
14
|
-
export default
|
|
13
|
+
export default speedwellRules;
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Speedwell template configuration
|
|
2
|
+
* Speedwell template configuration for ESLint flat config
|
|
3
3
|
* Enables all Gallop rules relevant to the Speedwell architecture
|
|
4
4
|
*/
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
5
|
+
const speedwellRules = {
|
|
6
|
+
// Blocks should be server components - extract client logic to components
|
|
7
|
+
'gallop/no-client-blocks': 'warn',
|
|
8
|
+
// Section already provides containment
|
|
9
|
+
'gallop/no-container-in-section': 'warn',
|
|
10
|
+
// Use component props instead of className for style values
|
|
11
|
+
'gallop/prefer-component-props': 'warn',
|
|
12
|
+
// Use Typography components instead of raw p/span tags
|
|
13
|
+
'gallop/prefer-typography-components': 'warn',
|
|
14
|
+
// Use Grid/Columns instead of raw div with grid classes
|
|
15
|
+
'gallop/prefer-layout-components': 'warn',
|
|
16
|
+
// Background images must have rounded="rounded-none"
|
|
17
|
+
'gallop/background-image-rounded': 'warn',
|
|
17
18
|
};
|
|
18
|
-
export default
|
|
19
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
19
|
+
export default speedwellRules;
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3BlZWR3ZWxsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VzbGludC9jb25maWdzL3NwZWVkd2VsbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxNQUFNLGNBQWMsR0FBRztJQUNyQiwwRUFBMEU7SUFDMUUseUJBQXlCLEVBQUUsTUFBTTtJQUVqQyx1Q0FBdUM7SUFDdkMsZ0NBQWdDLEVBQUUsTUFBTTtJQUV4Qyw0REFBNEQ7SUFDNUQsK0JBQStCLEVBQUUsTUFBTTtJQUV2Qyx1REFBdUQ7SUFDdkQscUNBQXFDLEVBQUUsTUFBTTtJQUU3Qyx3REFBd0Q7SUFDeEQsaUNBQWlDLEVBQUUsTUFBTTtJQUV6QyxxREFBcUQ7SUFDckQsaUNBQWlDLEVBQUUsTUFBTTtDQUNqQyxDQUFBO0FBRVYsZUFBZSxjQUFjLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFNwZWVkd2VsbCB0ZW1wbGF0ZSBjb25maWd1cmF0aW9uIGZvciBFU0xpbnQgZmxhdCBjb25maWdcbiAqIEVuYWJsZXMgYWxsIEdhbGxvcCBydWxlcyByZWxldmFudCB0byB0aGUgU3BlZWR3ZWxsIGFyY2hpdGVjdHVyZVxuICovXG5jb25zdCBzcGVlZHdlbGxSdWxlcyA9IHtcbiAgLy8gQmxvY2tzIHNob3VsZCBiZSBzZXJ2ZXIgY29tcG9uZW50cyAtIGV4dHJhY3QgY2xpZW50IGxvZ2ljIHRvIGNvbXBvbmVudHNcbiAgJ2dhbGxvcC9uby1jbGllbnQtYmxvY2tzJzogJ3dhcm4nLFxuXG4gIC8vIFNlY3Rpb24gYWxyZWFkeSBwcm92aWRlcyBjb250YWlubWVudFxuICAnZ2FsbG9wL25vLWNvbnRhaW5lci1pbi1zZWN0aW9uJzogJ3dhcm4nLFxuXG4gIC8vIFVzZSBjb21wb25lbnQgcHJvcHMgaW5zdGVhZCBvZiBjbGFzc05hbWUgZm9yIHN0eWxlIHZhbHVlc1xuICAnZ2FsbG9wL3ByZWZlci1jb21wb25lbnQtcHJvcHMnOiAnd2FybicsXG5cbiAgLy8gVXNlIFR5cG9ncmFwaHkgY29tcG9uZW50cyBpbnN0ZWFkIG9mIHJhdyBwL3NwYW4gdGFnc1xuICAnZ2FsbG9wL3ByZWZlci10eXBvZ3JhcGh5LWNvbXBvbmVudHMnOiAnd2FybicsXG5cbiAgLy8gVXNlIEdyaWQvQ29sdW1ucyBpbnN0ZWFkIG9mIHJhdyBkaXYgd2l0aCBncmlkIGNsYXNzZXNcbiAgJ2dhbGxvcC9wcmVmZXItbGF5b3V0LWNvbXBvbmVudHMnOiAnd2FybicsXG5cbiAgLy8gQmFja2dyb3VuZCBpbWFnZXMgbXVzdCBoYXZlIHJvdW5kZWQ9XCJyb3VuZGVkLW5vbmVcIlxuICAnZ2FsbG9wL2JhY2tncm91bmQtaW1hZ2Utcm91bmRlZCc6ICd3YXJuJyxcbn0gYXMgY29uc3RcblxuZXhwb3J0IGRlZmF1bHQgc3BlZWR3ZWxsUnVsZXNcbiJdfQ==
|
package/dist/eslint/index.d.ts
CHANGED
|
@@ -15,25 +15,24 @@ declare const plugin: {
|
|
|
15
15
|
};
|
|
16
16
|
'prefer-typography-components': import("eslint").Rule.RuleModule;
|
|
17
17
|
'prefer-layout-components': import("eslint").Rule.RuleModule;
|
|
18
|
+
'background-image-rounded': import("eslint").Rule.RuleModule;
|
|
18
19
|
};
|
|
19
20
|
configs: {
|
|
20
21
|
speedwell: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
};
|
|
22
|
+
readonly 'gallop/no-client-blocks': "warn";
|
|
23
|
+
readonly 'gallop/no-container-in-section': "warn";
|
|
24
|
+
readonly 'gallop/prefer-component-props': "warn";
|
|
25
|
+
readonly 'gallop/prefer-typography-components': "warn";
|
|
26
|
+
readonly 'gallop/prefer-layout-components': "warn";
|
|
27
|
+
readonly 'gallop/background-image-rounded': "warn";
|
|
28
28
|
};
|
|
29
29
|
recommended: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
30
|
+
readonly 'gallop/no-client-blocks': "warn";
|
|
31
|
+
readonly 'gallop/no-container-in-section': "warn";
|
|
32
|
+
readonly 'gallop/prefer-component-props': "warn";
|
|
33
|
+
readonly 'gallop/prefer-typography-components': "warn";
|
|
34
|
+
readonly 'gallop/prefer-layout-components': "warn";
|
|
35
|
+
readonly 'gallop/background-image-rounded': "warn";
|
|
37
36
|
};
|
|
38
37
|
};
|
|
39
38
|
};
|
package/dist/eslint/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import noContainerInSection from './rules/no-container-in-section.js';
|
|
|
3
3
|
import preferComponentProps from './rules/prefer-component-props.js';
|
|
4
4
|
import preferTypographyComponents from './rules/prefer-typography-components.js';
|
|
5
5
|
import preferLayoutComponents from './rules/prefer-layout-components.js';
|
|
6
|
+
import backgroundImageRounded from './rules/background-image-rounded.js';
|
|
6
7
|
import speedwellConfig from './configs/speedwell.js';
|
|
7
8
|
import recommendedConfig from './configs/recommended.js';
|
|
8
9
|
const plugin = {
|
|
@@ -16,6 +17,7 @@ const plugin = {
|
|
|
16
17
|
'prefer-component-props': preferComponentProps,
|
|
17
18
|
'prefer-typography-components': preferTypographyComponents,
|
|
18
19
|
'prefer-layout-components': preferLayoutComponents,
|
|
20
|
+
'background-image-rounded': backgroundImageRounded,
|
|
19
21
|
},
|
|
20
22
|
configs: {
|
|
21
23
|
speedwell: speedwellConfig,
|
|
@@ -23,4 +25,4 @@ const plugin = {
|
|
|
23
25
|
},
|
|
24
26
|
};
|
|
25
27
|
export default plugin;
|
|
26
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXNsaW50L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sY0FBYyxNQUFNLDZCQUE2QixDQUFBO0FBQ3hELE9BQU8sb0JBQW9CLE1BQU0sb0NBQW9DLENBQUE7QUFDckUsT0FBTyxvQkFBb0IsTUFBTSxtQ0FBbUMsQ0FBQTtBQUNwRSxPQUFPLDBCQUEwQixNQUFNLHlDQUF5QyxDQUFBO0FBQ2hGLE9BQU8sc0JBQXNCLE1BQU0scUNBQXFDLENBQUE7QUFDeEUsT0FBTyxzQkFBc0IsTUFBTSxxQ0FBcUMsQ0FBQTtBQUN4RSxPQUFPLGVBQWUsTUFBTSx3QkFBd0IsQ0FBQTtBQUNwRCxPQUFPLGlCQUFpQixNQUFNLDBCQUEwQixDQUFBO0FBRXhELE1BQU0sTUFBTSxHQUFHO0lBQ2IsSUFBSSxFQUFFO1FBQ0osSUFBSSxFQUFFLHNCQUFzQjtRQUM1QixPQUFPLEVBQUUsT0FBTztLQUNqQjtJQUNELEtBQUssRUFBRTtRQUNMLGtCQUFrQixFQUFFLGNBQWM7UUFDbEMseUJBQXlCLEVBQUUsb0JBQW9CO1FBQy9DLHdCQUF3QixFQUFFLG9CQUFvQjtRQUM5Qyw4QkFBOEIsRUFBRSwwQkFBMEI7UUFDMUQsMEJBQTBCLEVBQUUsc0JBQXNCO1FBQ2xELDBCQUEwQixFQUFFLHNCQUFzQjtLQUNuRDtJQUNELE9BQU8sRUFBRTtRQUNQLFNBQVMsRUFBRSxlQUFlO1FBQzFCLFdBQVcsRUFBRSxpQkFBaUI7S0FDL0I7Q0FDRixDQUFBO0FBRUQsZUFBZSxNQUFNLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbm9DbGllbnRCbG9ja3MgZnJvbSAnLi9ydWxlcy9uby1jbGllbnQtYmxvY2tzLmpzJ1xuaW1wb3J0IG5vQ29udGFpbmVySW5TZWN0aW9uIGZyb20gJy4vcnVsZXMvbm8tY29udGFpbmVyLWluLXNlY3Rpb24uanMnXG5pbXBvcnQgcHJlZmVyQ29tcG9uZW50UHJvcHMgZnJvbSAnLi9ydWxlcy9wcmVmZXItY29tcG9uZW50LXByb3BzLmpzJ1xuaW1wb3J0IHByZWZlclR5cG9ncmFwaHlDb21wb25lbnRzIGZyb20gJy4vcnVsZXMvcHJlZmVyLXR5cG9ncmFwaHktY29tcG9uZW50cy5qcydcbmltcG9ydCBwcmVmZXJMYXlvdXRDb21wb25lbnRzIGZyb20gJy4vcnVsZXMvcHJlZmVyLWxheW91dC1jb21wb25lbnRzLmpzJ1xuaW1wb3J0IGJhY2tncm91bmRJbWFnZVJvdW5kZWQgZnJvbSAnLi9ydWxlcy9iYWNrZ3JvdW5kLWltYWdlLXJvdW5kZWQuanMnXG5pbXBvcnQgc3BlZWR3ZWxsQ29uZmlnIGZyb20gJy4vY29uZmlncy9zcGVlZHdlbGwuanMnXG5pbXBvcnQgcmVjb21tZW5kZWRDb25maWcgZnJvbSAnLi9jb25maWdzL3JlY29tbWVuZGVkLmpzJ1xuXG5jb25zdCBwbHVnaW4gPSB7XG4gIG1ldGE6IHtcbiAgICBuYW1lOiAnZXNsaW50LXBsdWdpbi1nYWxsb3AnLFxuICAgIHZlcnNpb246ICcxLjAuMScsXG4gIH0sXG4gIHJ1bGVzOiB7XG4gICAgJ25vLWNsaWVudC1ibG9ja3MnOiBub0NsaWVudEJsb2NrcyxcbiAgICAnbm8tY29udGFpbmVyLWluLXNlY3Rpb24nOiBub0NvbnRhaW5lckluU2VjdGlvbixcbiAgICAncHJlZmVyLWNvbXBvbmVudC1wcm9wcyc6IHByZWZlckNvbXBvbmVudFByb3BzLFxuICAgICdwcmVmZXItdHlwb2dyYXBoeS1jb21wb25lbnRzJzogcHJlZmVyVHlwb2dyYXBoeUNvbXBvbmVudHMsXG4gICAgJ3ByZWZlci1sYXlvdXQtY29tcG9uZW50cyc6IHByZWZlckxheW91dENvbXBvbmVudHMsXG4gICAgJ2JhY2tncm91bmQtaW1hZ2Utcm91bmRlZCc6IGJhY2tncm91bmRJbWFnZVJvdW5kZWQsXG4gIH0sXG4gIGNvbmZpZ3M6IHtcbiAgICBzcGVlZHdlbGw6IHNwZWVkd2VsbENvbmZpZyxcbiAgICByZWNvbW1lbmRlZDogcmVjb21tZW5kZWRDb25maWcsXG4gIH0sXG59XG5cbmV4cG9ydCBkZWZhdWx0IHBsdWdpblxuIl19
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { getCanonUrl, getCanonPattern } from '../utils/canon.js';
|
|
2
|
+
const RULE_NAME = 'background-image-rounded';
|
|
3
|
+
const pattern = getCanonPattern(RULE_NAME);
|
|
4
|
+
const rule = {
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
docs: {
|
|
8
|
+
description: pattern?.summary || 'Background images must have rounded="rounded-none"',
|
|
9
|
+
recommended: true,
|
|
10
|
+
url: getCanonUrl(RULE_NAME),
|
|
11
|
+
},
|
|
12
|
+
messages: {
|
|
13
|
+
requireRoundedNone: `[Canon ${pattern?.id || '019'}] Background Image components (with absolute inset-0) must have rounded="rounded-none" to prevent corner clipping.`,
|
|
14
|
+
},
|
|
15
|
+
schema: [],
|
|
16
|
+
},
|
|
17
|
+
create(context) {
|
|
18
|
+
const filename = context.filename || context.getFilename();
|
|
19
|
+
// Only apply to block files
|
|
20
|
+
if (!filename.includes('/blocks/')) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
JSXOpeningElement(node) {
|
|
25
|
+
const elementName = node.name?.name;
|
|
26
|
+
// Only check Image components
|
|
27
|
+
if (elementName !== 'Image') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
// Check if className contains 'absolute' and 'inset-0'
|
|
31
|
+
const classNameAttr = node.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
|
|
32
|
+
attr.name?.name === 'className');
|
|
33
|
+
if (!classNameAttr) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const classValue = getClassNameValue(classNameAttr);
|
|
37
|
+
if (!classValue) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Check if this is a background image pattern
|
|
41
|
+
if (!isBackgroundImage(classValue)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// Check if rounded="rounded-none" is set
|
|
45
|
+
const roundedAttr = node.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
|
|
46
|
+
attr.name?.name === 'rounded');
|
|
47
|
+
if (!roundedAttr) {
|
|
48
|
+
context.report({
|
|
49
|
+
node,
|
|
50
|
+
messageId: 'requireRoundedNone',
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Check the value of rounded prop
|
|
55
|
+
const roundedValue = getRoundedValue(roundedAttr);
|
|
56
|
+
if (roundedValue !== 'rounded-none') {
|
|
57
|
+
context.report({
|
|
58
|
+
node,
|
|
59
|
+
messageId: 'requireRoundedNone',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Extract className value from attribute
|
|
68
|
+
*/
|
|
69
|
+
function getClassNameValue(attr) {
|
|
70
|
+
// Handle string literal
|
|
71
|
+
if (attr.value?.type === 'Literal' && typeof attr.value.value === 'string') {
|
|
72
|
+
return attr.value.value;
|
|
73
|
+
}
|
|
74
|
+
// Handle JSX expression container with template literal
|
|
75
|
+
if (attr.value?.type === 'JSXExpressionContainer') {
|
|
76
|
+
const expr = attr.value.expression;
|
|
77
|
+
if (expr.type === 'TemplateLiteral') {
|
|
78
|
+
// Combine all quasis
|
|
79
|
+
return expr.quasis?.map((q) => q.value?.raw || '').join(' ') || null;
|
|
80
|
+
}
|
|
81
|
+
// Handle clsx or other function calls - extract string arguments
|
|
82
|
+
if (expr.type === 'CallExpression') {
|
|
83
|
+
const strings = [];
|
|
84
|
+
for (const arg of expr.arguments || []) {
|
|
85
|
+
if (arg.type === 'Literal' && typeof arg.value === 'string') {
|
|
86
|
+
strings.push(arg.value);
|
|
87
|
+
}
|
|
88
|
+
if (arg.type === 'TemplateLiteral') {
|
|
89
|
+
strings.push(arg.quasis?.map((q) => q.value?.raw || '').join(' ') || '');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return strings.join(' ');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if className indicates a background image pattern
|
|
99
|
+
*/
|
|
100
|
+
function isBackgroundImage(classValue) {
|
|
101
|
+
const classes = classValue.split(/\s+/);
|
|
102
|
+
const hasAbsolute = classes.includes('absolute');
|
|
103
|
+
const hasInset0 = classes.includes('inset-0');
|
|
104
|
+
return hasAbsolute && hasInset0;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Extract rounded prop value
|
|
108
|
+
*/
|
|
109
|
+
function getRoundedValue(attr) {
|
|
110
|
+
if (attr.value?.type === 'Literal' && typeof attr.value.value === 'string') {
|
|
111
|
+
return attr.value.value;
|
|
112
|
+
}
|
|
113
|
+
if (attr.value?.type === 'JSXExpressionContainer') {
|
|
114
|
+
const expr = attr.value.expression;
|
|
115
|
+
if (expr.type === 'Literal' && typeof expr.value === 'string') {
|
|
116
|
+
return expr.value;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
export default rule;
|
|
122
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFja2dyb3VuZC1pbWFnZS1yb3VuZGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2VzbGludC9ydWxlcy9iYWNrZ3JvdW5kLWltYWdlLXJvdW5kZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQTtBQUVoRSxNQUFNLFNBQVMsR0FBRywwQkFBMEIsQ0FBQTtBQUM1QyxNQUFNLE9BQU8sR0FBRyxlQUFlLENBQUMsU0FBUyxDQUFDLENBQUE7QUFFMUMsTUFBTSxJQUFJLEdBQW9CO0lBQzVCLElBQUksRUFBRTtRQUNKLElBQUksRUFBRSxZQUFZO1FBQ2xCLElBQUksRUFBRTtZQUNKLFdBQVcsRUFBRSxPQUFPLEVBQUUsT0FBTyxJQUFJLG9EQUFvRDtZQUNyRixXQUFXLEVBQUUsSUFBSTtZQUNqQixHQUFHLEVBQUUsV0FBVyxDQUFDLFNBQVMsQ0FBQztTQUM1QjtRQUNELFFBQVEsRUFBRTtZQUNSLGtCQUFrQixFQUFFLFVBQVUsT0FBTyxFQUFFLEVBQUUsSUFBSSxLQUFLLG9IQUFvSDtTQUN2SztRQUNELE1BQU0sRUFBRSxFQUFFO0tBQ1g7SUFFRCxNQUFNLENBQUMsT0FBTztRQUNaLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFRLElBQUksT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFBO1FBRTFELDRCQUE0QjtRQUM1QixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ25DLE9BQU8sRUFBRSxDQUFBO1FBQ1gsQ0FBQztRQUVELE9BQU87WUFDTCxpQkFBaUIsQ0FBQyxJQUFTO2dCQUN6QixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQTtnQkFFbkMsOEJBQThCO2dCQUM5QixJQUFJLFdBQVcsS0FBSyxPQUFPLEVBQUUsQ0FBQztvQkFDNUIsT0FBTTtn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QVMsSUFBSSxPQUFPLElBQUksQ0FBQyxLQUFLLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDOUQsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFBO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBRUQsT0FBTyxJQUFJLENBQUE7QUFDYixDQUFDO0FBRUQsZUFBZSxJQUFJLENBQUEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFJ1bGUgfSBmcm9tICdlc2xpbnQnXG5pbXBvcnQgeyBnZXRDYW5vblVybCwgZ2V0Q2Fub25QYXR0ZXJuIH0gZnJvbSAnLi4vdXRpbHMvY2Fub24uanMnXG5cbmNvbnN0IFJVTEVfTkFNRSA9ICdiYWNrZ3JvdW5kLWltYWdlLXJvdW5kZWQnXG5jb25zdCBwYXR0ZXJuID0gZ2V0Q2Fub25QYXR0ZXJuKFJVTEVfTkFNRSlcblxuY29uc3QgcnVsZTogUnVsZS5SdWxlTW9kdWxlID0ge1xuICBtZXRhOiB7XG4gICAgdHlwZTogJ3N1Z2dlc3Rpb24nLFxuICAgIGRvY3M6IHtcbiAgICAgIGRlc2NyaXB0aW9uOiBwYXR0ZXJuPy5zdW1tYXJ5IHx8ICdCYWNrZ3JvdW5kIGltYWdlcyBtdXN0IGhhdmUgcm91bmRlZD1cInJvdW5kZWQtbm9uZVwiJyxcbiAgICAgIHJlY29tbWVuZGVkOiB0cnVlLFxuICAgICAgdXJsOiBnZXRDYW5vblVybChSVUxFX05BTUUpLFxuICAgIH0sXG4gICAgbWVzc2FnZXM6IHtcbiAgICAgIHJlcXVpcmVSb3VuZGVkTm9uZTogYFtDYW5vbiAke3BhdHRlcm4/LmlkIHx8ICcwMTknfV0gQmFja2dyb3VuZCBJbWFnZSBjb21wb25lbnRzICh3aXRoIGFic29sdXRlIGluc2V0LTApIG11c3QgaGF2ZSByb3VuZGVkPVwicm91bmRlZC1ub25lXCIgdG8gcHJldmVudCBjb3JuZXIgY2xpcHBpbmcuYCxcbiAgICB9LFxuICAgIHNjaGVtYTogW10sXG4gIH0sXG5cbiAgY3JlYXRlKGNvbnRleHQpIHtcbiAgICBjb25zdCBmaWxlbmFtZSA9IGNvbnRleHQuZmlsZW5hbWUgfHwgY29udGV4dC5nZXRGaWxlbmFtZSgpXG5cbiAgICAvLyBPbmx5IGFwcGx5IHRvIGJsb2NrIGZpbGVzXG4gICAgaWYgKCFmaWxlbmFtZS5pbmNsdWRlcygnL2Jsb2Nrcy8nKSkge1xuICAgICAgcmV0dXJuIHt9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIEpTWE9wZW5pbmdFbGVtZW50KG5vZGU6IGFueSkge1xuICAgICAgICBjb25zdCBlbGVtZW50TmFtZSA9IG5vZGUubmFtZT8ubmFtZVxuXG4gICAgICAgIC8vIE9ubHkgY2hlY2sgSW1hZ2UgY29tcG9uZW50c1xuICAgICAgICBpZiAoZWxlbWVudE5hbWUgIT09ICdJbWFnZScpIHtcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIGlmIGNsYXNzTmFtZSBjb250YWlucyAnYWJzb2x1dGUnIGFuZCAnaW5zZXQtMCdcbiAgICAgICAgY29uc3QgY2xhc3NOYW1lQXR0ciA9IG5vZGUuYXR0cmlidXRlcz8uZmluZChcbiAgICAgICAgICAoYXR0cjogYW55KSA9PlxuICAgICAgICAgICAgYXR0ci50eXBlID09PSAnSlNYQXR0cmlidXRlJyAmJlxuICAgICAgICAgICAgYXR0ci5uYW1lPy5uYW1lID09PSAnY2xhc3NOYW1lJ1xuICAgICAgICApXG5cbiAgICAgICAgaWYgKCFjbGFzc05hbWVBdHRyKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBjbGFzc1ZhbHVlID0gZ2V0Q2xhc3NOYW1lVmFsdWUoY2xhc3NOYW1lQXR0cilcbiAgICAgICAgaWYgKCFjbGFzc1ZhbHVlKSB7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cblxuICAgICAgICAvLyBDaGVjayBpZiB0aGlzIGlzIGEgYmFja2dyb3VuZCBpbWFnZSBwYXR0ZXJuXG4gICAgICAgIGlmICghaXNCYWNrZ3JvdW5kSW1hZ2UoY2xhc3NWYWx1ZSkpIHtcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIGlmIHJvdW5kZWQ9XCJyb3VuZGVkLW5vbmVcIiBpcyBzZXRcbiAgICAgICAgY29uc3Qgcm91bmRlZEF0dHIgPSBub2RlLmF0dHJpYnV0ZXM/LmZpbmQoXG4gICAgICAgICAgKGF0dHI6IGFueSkgPT5cbiAgICAgICAgICAgIGF0dHIudHlwZSA9PT0gJ0pTWEF0dHJpYnV0ZScgJiZcbiAgICAgICAgICAgIGF0dHIubmFtZT8ubmFtZSA9PT0gJ3JvdW5kZWQnXG4gICAgICAgIClcblxuICAgICAgICBpZiAoIXJvdW5kZWRBdHRyKSB7XG4gICAgICAgICAgY29udGV4dC5yZXBvcnQoe1xuICAgICAgICAgICAgbm9kZSxcbiAgICAgICAgICAgIG1lc3NhZ2VJZDogJ3JlcXVpcmVSb3VuZGVkTm9uZScsXG4gICAgICAgICAgfSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENoZWNrIHRoZSB2YWx1ZSBvZiByb3VuZGVkIHByb3BcbiAgICAgICAgY29uc3Qgcm91bmRlZFZhbHVlID0gZ2V0Um91bmRlZFZhbHVlKHJvdW5kZWRBdHRyKVxuICAgICAgICBpZiAocm91bmRlZFZhbHVlICE9PSAncm91bmRlZC1ub25lJykge1xuICAgICAgICAgIGNvbnRleHQucmVwb3J0KHtcbiAgICAgICAgICAgIG5vZGUsXG4gICAgICAgICAgICBtZXNzYWdlSWQ6ICdyZXF1aXJlUm91bmRlZE5vbmUnLFxuICAgICAgICAgIH0pXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfVxuICB9LFxufVxuXG4vKipcbiAqIEV4dHJhY3QgY2xhc3NOYW1lIHZhbHVlIGZyb20gYXR0cmlidXRlXG4gKi9cbmZ1bmN0aW9uIGdldENsYXNzTmFtZVZhbHVlKGF0dHI6IGFueSk6IHN0cmluZyB8IG51bGwge1xuICAvLyBIYW5kbGUgc3RyaW5nIGxpdGVyYWxcbiAgaWYgKGF0dHIudmFsdWU/LnR5cGUgPT09ICdMaXRlcmFsJyAmJiB0eXBlb2YgYXR0ci52YWx1ZS52YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gYXR0ci52YWx1ZS52YWx1ZVxuICB9XG5cbiAgLy8gSGFuZGxlIEpTWCBleHByZXNzaW9uIGNvbnRhaW5lciB3aXRoIHRlbXBsYXRlIGxpdGVyYWxcbiAgaWYgKGF0dHIudmFsdWU/LnR5cGUgPT09ICdKU1hFeHByZXNzaW9uQ29udGFpbmVyJykge1xuICAgIGNvbnN0IGV4cHIgPSBhdHRyLnZhbHVlLmV4cHJlc3Npb25cblxuICAgIGlmIChleHByLnR5cGUgPT09ICdUZW1wbGF0ZUxpdGVyYWwnKSB7XG4gICAgICAvLyBDb21iaW5lIGFsbCBxdWFzaXNcbiAgICAgIHJldHVybiBleHByLnF1YXNpcz8ubWFwKChxOiBhbnkpID0+IHEudmFsdWU/LnJhdyB8fCAnJykuam9pbignICcpIHx8IG51bGxcbiAgICB9XG5cbiAgICAvLyBIYW5kbGUgY2xzeCBvciBvdGhlciBmdW5jdGlvbiBjYWxscyAtIGV4dHJhY3Qgc3RyaW5nIGFyZ3VtZW50c1xuICAgIGlmIChleHByLnR5cGUgPT09ICdDYWxsRXhwcmVzc2lvbicpIHtcbiAgICAgIGNvbnN0IHN0cmluZ3M6IHN0cmluZ1tdID0gW11cbiAgICAgIGZvciAoY29uc3QgYXJnIG9mIGV4cHIuYXJndW1lbnRzIHx8IFtdKSB7XG4gICAgICAgIGlmIChhcmcudHlwZSA9PT0gJ0xpdGVyYWwnICYmIHR5cGVvZiBhcmcudmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgc3RyaW5ncy5wdXNoKGFyZy52YWx1ZSlcbiAgICAgICAgfVxuICAgICAgICBpZiAoYXJnLnR5cGUgPT09ICdUZW1wbGF0ZUxpdGVyYWwnKSB7XG4gICAgICAgICAgc3RyaW5ncy5wdXNoKGFyZy5xdWFzaXM/Lm1hcCgocTogYW55KSA9PiBxLnZhbHVlPy5yYXcgfHwgJycpLmpvaW4oJyAnKSB8fCAnJylcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHN0cmluZ3Muam9pbignICcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG51bGxcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBjbGFzc05hbWUgaW5kaWNhdGVzIGEgYmFja2dyb3VuZCBpbWFnZSBwYXR0ZXJuXG4gKi9cbmZ1bmN0aW9uIGlzQmFja2dyb3VuZEltYWdlKGNsYXNzVmFsdWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCBjbGFzc2VzID0gY2xhc3NWYWx1ZS5zcGxpdCgvXFxzKy8pXG4gIGNvbnN0IGhhc0Fic29sdXRlID0gY2xhc3Nlcy5pbmNsdWRlcygnYWJzb2x1dGUnKVxuICBjb25zdCBoYXNJbnNldDAgPSBjbGFzc2VzLmluY2x1ZGVzKCdpbnNldC0wJylcbiAgXG4gIHJldHVybiBoYXNBYnNvbHV0ZSAmJiBoYXNJbnNldDBcbn1cblxuLyoqXG4gKiBFeHRyYWN0IHJvdW5kZWQgcHJvcCB2YWx1ZVxuICovXG5mdW5jdGlvbiBnZXRSb3VuZGVkVmFsdWUoYXR0cjogYW55KTogc3RyaW5nIHwgbnVsbCB7XG4gIGlmIChhdHRyLnZhbHVlPy50eXBlID09PSAnTGl0ZXJhbCcgJiYgdHlwZW9mIGF0dHIudmFsdWUudmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgcmV0dXJuIGF0dHIudmFsdWUudmFsdWVcbiAgfVxuXG4gIGlmIChhdHRyLnZhbHVlPy50eXBlID09PSAnSlNYRXhwcmVzc2lvbkNvbnRhaW5lcicpIHtcbiAgICBjb25zdCBleHByID0gYXR0ci52YWx1ZS5leHByZXNzaW9uXG4gICAgaWYgKGV4cHIudHlwZSA9PT0gJ0xpdGVyYWwnICYmIHR5cGVvZiBleHByLnZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIGV4cHIudmFsdWVcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbnVsbFxufVxuXG5leHBvcnQgZGVmYXVsdCBydWxlXG4iXX0=
|
package/package.json
CHANGED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# 019: Background Image Rounded
|
|
2
|
+
|
|
3
|
+
**Category:** Components
|
|
4
|
+
**Status:** Stable
|
|
5
|
+
**Enforcement:** ESLint (`gallop/background-image-rounded`)
|
|
6
|
+
|
|
7
|
+
## Summary
|
|
8
|
+
|
|
9
|
+
When using the `Image` component as a background image (with `absolute inset-0` positioning), always set `rounded="rounded-none"`.
|
|
10
|
+
|
|
11
|
+
## Rationale
|
|
12
|
+
|
|
13
|
+
The Image component defaults to `rounded-lg` for rounded corners. When used as a full-bleed background image, these rounded corners:
|
|
14
|
+
|
|
15
|
+
- **Cause visual artifacts** - corners get clipped unexpectedly
|
|
16
|
+
- **Conflict with container rounding** - the parent container should control edge styling
|
|
17
|
+
- **Create inconsistent edges** - background images should fill their container completely
|
|
18
|
+
|
|
19
|
+
## Bad
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
{/* Background image without rounded prop - uses default rounded-lg */}
|
|
23
|
+
<Image
|
|
24
|
+
src="/images/hero-bg.jpg"
|
|
25
|
+
alt="Background"
|
|
26
|
+
className="absolute inset-0 w-full h-full object-cover"
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Good
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
{/* Background image with explicit rounded-none */}
|
|
34
|
+
<Image
|
|
35
|
+
src="/images/hero-bg.jpg"
|
|
36
|
+
alt="Background"
|
|
37
|
+
className="absolute inset-0 w-full h-full object-cover"
|
|
38
|
+
rounded="rounded-none"
|
|
39
|
+
/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Detection
|
|
43
|
+
|
|
44
|
+
The rule identifies background images by checking for:
|
|
45
|
+
- `Image` component usage
|
|
46
|
+
- `className` containing both `absolute` and `inset-0`
|
|
47
|
+
|
|
48
|
+
When detected, the rule requires `rounded="rounded-none"` to be explicitly set.
|
|
49
|
+
|
|
50
|
+
## Exceptions
|
|
51
|
+
|
|
52
|
+
This rule only applies to files in `/blocks/`. Component files that implement background image patterns internally are not flagged.
|
package/schema.json
CHANGED
|
@@ -220,6 +220,16 @@
|
|
|
220
220
|
"enforcement": "eslint",
|
|
221
221
|
"rule": "gallop/prefer-layout-components",
|
|
222
222
|
"summary": "Use Grid/Columns, not raw div with grid"
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"id": "019",
|
|
226
|
+
"title": "Background Image Rounded",
|
|
227
|
+
"file": "patterns/019-background-image-rounded.md",
|
|
228
|
+
"category": "components",
|
|
229
|
+
"status": "stable",
|
|
230
|
+
"enforcement": "eslint",
|
|
231
|
+
"rule": "gallop/background-image-rounded",
|
|
232
|
+
"summary": "Background images must have rounded=\"rounded-none\""
|
|
223
233
|
}
|
|
224
234
|
],
|
|
225
235
|
"guarantees": [
|
|
@@ -249,7 +259,7 @@
|
|
|
249
259
|
"name": "Design System Compliance",
|
|
250
260
|
"since": "1.0.0",
|
|
251
261
|
"status": "stable",
|
|
252
|
-
"patterns": ["003", "004", "009", "010", "011", "018"]
|
|
262
|
+
"patterns": ["003", "004", "009", "010", "011", "018", "019"]
|
|
253
263
|
}
|
|
254
264
|
]
|
|
255
265
|
}
|