From 8313746b4e36841f1cda9f705a0f9734c21dcb1b Mon Sep 17 00:00:00 2001 From: Zhen Wang Date: Wed, 17 Jun 2026 14:35:26 +0200 Subject: [PATCH] feat(v11): add Carbon v11 support --- .gitignore | 1 + packages/component-list/package.json | 5 + packages/component-list/src/helpers.js | 9 +- .../src/libraries/carbon-v11.js | 171 +++ .../libraries/carbon-web-components-v11.js | 30 + .../component-list/src/libraries/carbon.js | 1 + .../src/libraries/cloud-cognitive-v11.js | 36 + .../src/libraries/ibmdotcom-v11.js | 29 + .../component-list/src/libraries/index.js | 4 + packages/component-list/webpack.js | 18 + packages/web-extension/package.json | 11 +- .../src/globals/componentList.js | 12 +- .../src/globals/prefixSelectors.js | 5 +- .../web-extension/src/globals/setPrefix.js | 5 +- .../src/inject/components/Grid/2x/index.scss | 23 +- .../components/Grid/mini-unit/index.scss | 9 +- .../inject/components/Highlight/index.scss | 4 +- .../src/inject/components/Inventory/index.js | 25 +- .../components/Specs/Color/getThemeName.js | 64 +- .../inject/components/Specs/Color/index.js | 90 +- .../Specs/Color/searchCarbonTokens.js | 22 +- .../components/Specs/Color/themeKeys.js | 75 +- .../components/Specs/Spacing/index.scss | 4 +- .../src/inject/components/Tooltip/index.scss | 7 +- packages/web-extension/src/manifest.json | 2 +- .../src/popup/components/ComingSoon/index.js | 16 +- .../popup/components/ComingSoon/index.scss | 16 + .../src/popup/components/Inventory/index.js | 15 +- .../src/popup/components/Inventory/index.scss | 14 +- .../src/popup/components/Main/index.js | 7 - .../src/popup/components/Main/index.scss | 8 + packages/web-extension/src/popup/index.js | 24 +- packages/web-extension/src/popup/index.scss | 2 + packages/web-extension/src/validate/index.js | 13 + version-updates-summary.md | 53 - yarn.lock | 1038 ++++++++++++++++- 36 files changed, 1678 insertions(+), 190 deletions(-) create mode 100644 packages/component-list/src/libraries/carbon-v11.js create mode 100644 packages/component-list/src/libraries/carbon-web-components-v11.js create mode 100644 packages/component-list/src/libraries/cloud-cognitive-v11.js create mode 100644 packages/component-list/src/libraries/ibmdotcom-v11.js create mode 100644 packages/web-extension/src/popup/components/ComingSoon/index.scss delete mode 100644 version-updates-summary.md diff --git a/.gitignore b/.gitignore index 2feb00f3..64daa815 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ dist out .DS_Store .yarn/install-state.gz +.instructions diff --git a/packages/component-list/package.json b/packages/component-list/package.json index 8e3e7a75..b1ae958f 100644 --- a/packages/component-list/package.json +++ b/packages/component-list/package.json @@ -19,15 +19,20 @@ "dependencies": { "@carbon/colors": "^10.37.5", "@carbon/ibm-products": "^1.73.6", + "@carbon/ibm-products-v2": "npm:@carbon/ibm-products@^2.92.1", "@carbon/ibm-security": "^1.47.0", "@carbon/ibmdotcom-react": "^1.66.1", "@carbon/ibmdotcom-web-components": "^1.51.1", + "@carbon/ibmdotcom-web-components-v2": "npm:@carbon/ibmdotcom-web-components@^2.54.0", "@carbon/icons-react": "^10.49.6", "@carbon/import-once": "^10.7.2", "@carbon/layout": "^10.37.5", "@carbon/motion": "^10.29.5", + "@carbon/react": "^1.109.0", "@carbon/themes": "^10.55.6", + "@carbon/themes-v11": "npm:@carbon/themes@^11.75.0", "@carbon/type": "^10.45.6", + "@carbon/web-components": "^2.56.0", "carbon-components": "^10.59.2", "carbon-components-react": "^7.60.5", "carbon-icons": "^7.0.7", diff --git a/packages/component-list/src/helpers.js b/packages/component-list/src/helpers.js index 187729d9..efab11da 100644 --- a/packages/component-list/src/helpers.js +++ b/packages/component-list/src/helpers.js @@ -107,7 +107,10 @@ function buildReactComponentList( const candidates = [ cleanupSelector(className, prefix), cleanupSelector(className, prefix, { includeModifiers: true }), - ].filter((candidate, index, arr) => candidate && arr.indexOf(candidate) === index); + ].filter( + (candidate, index, arr) => + candidate && arr.indexOf(candidate) === index + ); let matched = false; @@ -125,7 +128,9 @@ function buildReactComponentList( } if (!matched) { - console.log(`${prefix}${compKey}: Failed to find a unique identifier.`); + console.log( + `${prefix}${compKey}: Failed to find a unique identifier.` + ); fail(); } } else { diff --git a/packages/component-list/src/libraries/carbon-v11.js b/packages/component-list/src/libraries/carbon-v11.js new file mode 100644 index 00000000..ca825b72 --- /dev/null +++ b/packages/component-list/src/libraries/carbon-v11.js @@ -0,0 +1,171 @@ +import * as componentList from '@carbon/react'; +import { buildReactComponentList } from '../helpers.js'; + +const prefix = 'cds--'; + +const mockedProps = { + pageSizes: [0], + items: [], +}; + +// Components that fail auto-detection and need manual selectors +const ignoredComponents = [ + 'ActionableNotification', + 'Breadcrumb', + 'BreadcrumbItem', + 'ComboBox', + 'ContentSwitcher', + 'DataTable', + 'DatePicker', + 'ExpandableSearch', + 'ExpandableTile', + 'FileUploader', + 'FileUploaderSkeleton', + 'FileUploaderItem', + 'Form', + 'FormItem', + 'HeaderContainer', + 'HeaderNavigation', + 'Layer', + 'Modal', + 'ModalFooter', + 'ModalHeader', + 'MultiSelect', + 'NumberInput', + 'NumberInputSkeleton', + 'OrderedList', + 'OverflowMenu', + 'PasswordInput', + 'ProgressIndicator', + 'RadioButtonGroup', + 'RadioButtonSkeleton', + 'Select', + 'SelectSkeleton', + 'SideNavLink', + 'SideNavMenu', + 'SkeletonIcon', + 'SkeletonPlaceholder', + 'Slider', + 'SliderSkeleton', + 'Stack', + 'SwitcherDivider', + 'Tab', + 'TableBatchAction', + 'TableBody', + 'TableCell', + 'TableHead', + 'TableHeader', + 'TableRow', + 'TableSelectRow', + 'TextArea', + 'TextAreaSkeleton', + 'TextInputSkeleton', + 'Tile', + 'TileAboveTheFoldContent', + 'TileBelowTheFoldContent', + 'TimePicker', + 'TimePickerSelect', + 'Toggle', + 'ToggleSkeleton', + 'TooltipDefinition', + 'UnorderedList', +]; + +// v11 cds-- selectors for components that can't be auto-detected +const manualComponentSelectors = { + ActionableNotification: '.cds--actionable-notification', + Breadcrumb: '.cds--breadcrumb', + BreadcrumbItem: '.cds--breadcrumb-item', + ComboBox: '.cds--combo-box', + ContentSwitcher: '.cds--content-switcher', + DataTable: 'table.cds--data-table', + DatePicker: '.cds--date-picker', + ExpandableSearch: '.cds--search--expandable', + ExpandableTile: '.cds--tile--expandable', + FileUploader: '.cds--file', + FileUploaderSkeleton: '.cds--file.cds--skeleton', + FileUploaderItem: '.cds--file__selected-file', + Form: '.cds--form', + FormItem: '.cds--form-item', + HeaderContainer: '.cds--header', + HeaderNavigation: '.cds--header__nav', + Layer: '.cds--layer', + Modal: '.cds--modal', + ModalFooter: '.cds--modal-footer', + ModalHeader: '.cds--modal-header', + MultiSelect: '.cds--multi-select', + NumberInput: '.cds--number', + NumberInputSkeleton: '.cds--number.cds--skeleton', + OrderedList: '.cds--list--ordered', + OverflowMenu: '.cds--overflow-menu', + PasswordInput: '.cds--text-input-wrapper--password', + ProgressIndicator: '.cds--progress', + RadioButtonGroup: '.cds--radio-button-group', + RadioButtonSkeleton: '.cds--radio-button.cds--skeleton', + Select: '.cds--select', + SelectSkeleton: '.cds--select.cds--skeleton', + SideNavLink: '.cds--side-nav__link', + SideNavMenu: '.cds--side-nav__menu', + SkeletonIcon: '.cds--skeleton__icon', + SkeletonPlaceholder: '.cds--skeleton__placeholder', + Slider: '.cds--slider', + SliderSkeleton: '.cds--slider.cds--skeleton', + Stack: '.cds--stack', + SwitcherDivider: '.cds--switcher__item', + Tab: '.cds--tabs', + TableBatchAction: '.cds--batch-actions__action', + TableBody: 'table.cds--data-table tbody', + TableCell: 'table.cds--data-table tbody td', + TableHead: 'table.cds--data-table thead', + TableHeader: 'table.cds--data-table thead th', + TableRow: 'table.cds--data-table tbody tr', + TableSelectRow: 'table.cds--data-table tbody tr .cds--checkbox', + TextArea: '.cds--text-area', + TextAreaSkeleton: '.cds--text-area--skeleton', + TextInputSkeleton: '.cds--text-input--skeleton', + Tile: '.cds--tile', + TileAboveTheFoldContent: '.cds--tile-content__above-the-fold', + TileBelowTheFoldContent: '.cds--tile-content__below-the-fold', + TimePicker: '.cds--time-picker', + TimePickerSelect: '.cds--time-picker__select', + Toggle: '.cds--toggle', + ToggleSkeleton: '.cds--toggle.cds--skeleton', + TooltipDefinition: '.cds--definition-tooltip', + UnorderedList: '.cds--list--unordered', +}; + +const filterByTheseComponents = []; + +const { _stats, ...components } = buildReactComponentList( + componentList, + prefix, + mockedProps, + [], + filterByTheseComponents, + ignoredComponents +); + +const existingComponentNames = new Set(Object.values(components)); +let manualAddedCount = 0; + +Object.entries(manualComponentSelectors).forEach(([name, selector]) => { + if (!selector || existingComponentNames.has(name)) { + return; + } + + components[selector] = name; + existingComponentNames.add(name); + manualAddedCount += 1; +}); + +_stats.success += manualAddedCount; +_stats.total += manualAddedCount; + +const carbonReactV11 = { + name: 'Carbon v11', + version: 'v11', + components, + _stats, +}; + +export { carbonReactV11 }; diff --git a/packages/component-list/src/libraries/carbon-web-components-v11.js b/packages/component-list/src/libraries/carbon-web-components-v11.js new file mode 100644 index 00000000..d90d6dc8 --- /dev/null +++ b/packages/component-list/src/libraries/carbon-web-components-v11.js @@ -0,0 +1,30 @@ +import fs from 'fs'; +import { carbonV11Prefix } from '../../../web-extension/src/globals/prefixSelectors.js'; +import { _initStats, camelCase } from '../helpers.js'; + +const _carbonWebComponentsV11Dir = + '../../node_modules/@carbon/web-components/es/components'; +const { _stats, success } = new _initStats(); +const carbonWebComponentsV11 = { + name: 'Carbon web components', + version: 'v11', + components: {}, + _stats, +}; + +try { + const components = fs.readdirSync(_carbonWebComponentsV11Dir); + + components.forEach((file) => { + const name = camelCase(file.replace(/-/g, ' ')); + // @carbon/web-components v2 uses `cds-` prefixed custom elements + const identifier = `${carbonV11Prefix}-${file}`; + + carbonWebComponentsV11.components[identifier] = name; + success(); + }); +} catch (e) { + console.log(e); +} + +export { carbonWebComponentsV11 }; diff --git a/packages/component-list/src/libraries/carbon.js b/packages/component-list/src/libraries/carbon.js index e74f8b85..6412dc9b 100644 --- a/packages/component-list/src/libraries/carbon.js +++ b/packages/component-list/src/libraries/carbon.js @@ -175,6 +175,7 @@ _stats.total += manualAddedCount; const carbonReact = { name: 'Carbon', + version: 'v10', components, _stats, }; diff --git a/packages/component-list/src/libraries/cloud-cognitive-v11.js b/packages/component-list/src/libraries/cloud-cognitive-v11.js new file mode 100644 index 00000000..9e0691e9 --- /dev/null +++ b/packages/component-list/src/libraries/cloud-cognitive-v11.js @@ -0,0 +1,36 @@ +import * as _CloudCognitiveV11 from '@carbon/ibm-products-v2'; +import { _initStats } from '../helpers.js'; + +const { _stats, success } = new _initStats(); + +let { + pkg: { + devtoolsAttribute: cloudCognitiveDevtoolsAttributeV11, + getDevtoolsId: getCloudCognitiveDevtoolsIdV11, + }, + ...cloudCognitiveV11 +} = _CloudCognitiveV11; + +cloudCognitiveV11 = Object.values(cloudCognitiveV11).reduce( + (components, { displayName }) => { + components[ + `[${cloudCognitiveDevtoolsAttributeV11}="${getCloudCognitiveDevtoolsIdV11( + displayName + )}"]` + ] = displayName; + + success(); + + return components; + }, + {} +); + +cloudCognitiveV11 = { + name: 'Carbon for IBM Products', + version: 'v11', + components: cloudCognitiveV11, + _stats, +}; + +export { cloudCognitiveV11 }; diff --git a/packages/component-list/src/libraries/ibmdotcom-v11.js b/packages/component-list/src/libraries/ibmdotcom-v11.js new file mode 100644 index 00000000..beb8a6b7 --- /dev/null +++ b/packages/component-list/src/libraries/ibmdotcom-v11.js @@ -0,0 +1,29 @@ +import fs from 'fs'; +import { dotcomPrefix } from '../../../web-extension/src/globals/prefixSelectors.js'; +import { _initStats, camelCase } from '../helpers.js'; + +const _ibmdotcomWebComponentsV11Dir = + '../../node_modules/@carbon/ibmdotcom-web-components-v2/es/components'; +const { _stats, success } = new _initStats(); +const ibmdotcomV11 = { + name: 'Carbon for IBM.com', + version: 'v11', + components: {}, + _stats, +}; + +try { + const components = fs.readdirSync(_ibmdotcomWebComponentsV11Dir); + + components.forEach((file) => { + const name = camelCase(file.replace(/-/g, ' ')).replace('Cta', 'CTA'); + const identifier = `[data-autoid="${dotcomPrefix}--${file}"]`; + + ibmdotcomV11.components[identifier] = name; + success(); + }); +} catch (e) { + console.log(e); +} + +export { ibmdotcomV11 }; diff --git a/packages/component-list/src/libraries/index.js b/packages/component-list/src/libraries/index.js index c157234d..d1f85df0 100644 --- a/packages/component-list/src/libraries/index.js +++ b/packages/component-list/src/libraries/index.js @@ -1,6 +1,10 @@ export * from './carbon'; +export * from './carbon-v11'; export * from './carbon-web-components'; +export * from './carbon-web-components-v11'; export * from './ibmdotcom'; +export * from './ibmdotcom-v11'; export * from './cloud-cognitive'; +export * from './cloud-cognitive-v11'; export * from './security'; export * from './cloud-pal'; diff --git a/packages/component-list/webpack.js b/packages/component-list/webpack.js index f4ed8917..9097e1a4 100644 --- a/packages/component-list/webpack.js +++ b/packages/component-list/webpack.js @@ -17,8 +17,26 @@ module.exports = { loader: 'babel-loader', }, }, + // Allow ESM modules in node_modules (e.g. @carbon/react, @floating-ui) + // to be resolved without requiring fully-specified extensions. + { + test: /\.m?js/, + include: /node_modules/, + resolve: { + fullySpecified: false, + }, + }, ], }, + resolve: { + extensions: ['.js', '.jsx', '.mjs'], + alias: { + // React 16 does not ship jsx-runtime; provide a compatibility shim path + 'react/jsx-runtime': require.resolve('react/cjs/react.development.js'), + 'react/jsx-dev-runtime': + require.resolve('react/cjs/react.development.js'), + }, + }, output: { filename: 'index.js', path: path.resolve(__dirname, 'dist'), diff --git a/packages/web-extension/package.json b/packages/web-extension/package.json index f59f000b..833f7cf4 100644 --- a/packages/web-extension/package.json +++ b/packages/web-extension/package.json @@ -1,8 +1,8 @@ { - "name": "carbon-devtools-v10", - "version": "2.8.6", + "name": "carbon-devtools", + "version": "3.0.0", "private": true, - "description": "A basic set of tools for teams building live Carbon pages for Carbon v10.", + "description": "A basic set of tools for teams building live Carbon pages for Carbon v10 and v11.", "main": "dist/manifest.json", "scripts": { "build": "webpack --config webpack.prod.js", @@ -24,15 +24,20 @@ "@carbon/devtools-component-list": "^2.8.4", "@carbon/grid": "^10.43.5", "@carbon/ibm-products": "^1.73.6", + "@carbon/ibm-products-v2": "npm:@carbon/ibm-products@^2.92.1", "@carbon/ibm-security": "^1.47.0", "@carbon/ibmdotcom-react": "^1.66.1", "@carbon/ibmdotcom-utilities": "^1.66.1", + "@carbon/ibmdotcom-web-components-v2": "npm:@carbon/ibmdotcom-web-components@^2.54.0", "@carbon/icons": "^10.48.6", "@carbon/import-once": "^10.7.2", "@carbon/layout": "^10.37.5", "@carbon/motion": "^10.29.5", + "@carbon/react": "^1.109.0", "@carbon/themes": "^10.55.6", + "@carbon/themes-v11": "npm:@carbon/themes@^11.75.0", "@carbon/type": "^10.45.6", + "@carbon/web-components": "^2.56.0", "carbon-components": "^10.59.2", "carbon-components-react": "^7.60.5", "carbon-icons": "^7.0.7", diff --git a/packages/web-extension/src/globals/componentList.js b/packages/web-extension/src/globals/componentList.js index 4df75939..c348f3ee 100644 --- a/packages/web-extension/src/globals/componentList.js +++ b/packages/web-extension/src/globals/componentList.js @@ -7,7 +7,15 @@ const libraryKeys = Object.keys(libraries); const allComponents = {}; libraryKeys.forEach((key) => { - Object.assign(allComponents, libraries[key]); + Object.assign(allComponents, libraries[key].components); }); -export { allComponents }; +// Per-version component maps for Carbon v10 and v11 +const v10Components = libraries.carbonReact + ? { ...libraries.carbonReact.components } + : {}; +const v11Components = libraries.carbonReactV11 + ? { ...libraries.carbonReactV11.components } + : {}; + +export { allComponents, v10Components, v11Components }; diff --git a/packages/web-extension/src/globals/prefixSelectors.js b/packages/web-extension/src/globals/prefixSelectors.js index 23d7d871..ca8357b9 100644 --- a/packages/web-extension/src/globals/prefixSelectors.js +++ b/packages/web-extension/src/globals/prefixSelectors.js @@ -14,13 +14,15 @@ const { */ const carbonPrefix = carbonSettings.carbonPrefix || carbonSettings.prefix; +const carbonV11Prefix = 'cds'; // Carbon v11 uses the `cds` prefix const { stablePrefix: dotcomPrefix } = dotcomSettings; const securityPrefix = getSecurityPrefix(''); const cloudPalPrefix = 'pal'; // static hardcoded const cloudCognitiveDevtoolsId = getCloudCognitiveDevtoolsId(''); const prefixSelectors = [ - `class*="${carbonPrefix}--"`, // Carbon + `class*="${carbonPrefix}--"`, // Carbon v10 + `class*="${carbonV11Prefix}--"`, // Carbon v11 `${cloudCognitiveDevtoolsAttribute}*="${cloudCognitiveDevtoolsId}"`, // Cloud & Cognitive — https://github.com/carbon-design-system/ibm-cloud-cognitive `data-autoid*="${dotcomPrefix}--"`, // IBM.com `data-auto-id*="${dotcomPrefix}--"`, // IBM.com @@ -35,6 +37,7 @@ const prefixSelectors = [ export { prefixSelectors, carbonPrefix, + carbonV11Prefix, dotcomPrefix, securityPrefix, cloudPalPrefix, diff --git a/packages/web-extension/src/globals/setPrefix.js b/packages/web-extension/src/globals/setPrefix.js index 12d30cc5..230980e4 100644 --- a/packages/web-extension/src/globals/setPrefix.js +++ b/packages/web-extension/src/globals/setPrefix.js @@ -1,3 +1,6 @@ import settings from 'carbon-components/es/globals/js/settings'; -settings.carbonPrefix = settings.prefix; +// Save the real Carbon v10 prefix before overriding it with the devtools +// namespace so the grid overlay does not collide with page styles. +// The fallback 'bx' ensures this is safe even if the import is tree-shaken. +settings.carbonPrefix = settings.prefix || 'bx'; settings.prefix = 'bx-dev'; diff --git a/packages/web-extension/src/inject/components/Grid/2x/index.scss b/packages/web-extension/src/inject/components/Grid/2x/index.scss index e325f455..978f2eb4 100644 --- a/packages/web-extension/src/inject/components/Grid/2x/index.scss +++ b/packages/web-extension/src/inject/components/Grid/2x/index.scss @@ -34,7 +34,9 @@ $grid-outer-border-opacity: $grid-border-opacity; left: 0; width: 100%; height: 100vh; - transition: height $transition-in, padding $transition-fade; + transition: + height $transition-in, + padding $transition-fade; &--hide, .#{$prefix}--grid--hide & { @@ -60,8 +62,11 @@ $grid-outer-border-opacity: $grid-border-opacity; &, &::before { - transition: height $transition-in, top $transition-in, - box-shadow $transition-in, opacity $transition-fade, + transition: + height $transition-in, + top $transition-in, + box-shadow $transition-in, + opacity $transition-fade, background-color $transition-fade; } @@ -97,7 +102,8 @@ $grid-outer-border-opacity: $grid-border-opacity; // gutter &--outer { [class*='#{$prefix}--col-']::before { - box-shadow: math.div($carbon--grid-gutter, 2) 0 0 + box-shadow: + math.div($carbon--grid-gutter, 2) 0 0 rgba($grid-outer-color, $grid-outer-opacity), math.div($carbon--grid-gutter, 2) * -1 0 0 rgba($grid-outer-color, $grid-outer-opacity); @@ -107,7 +113,8 @@ $grid-outer-border-opacity: $grid-border-opacity; // column border &--inner-border { [class*='#{$prefix}--col-']::before { - box-shadow: $grid-inner-border-size 0 0 + box-shadow: + $grid-inner-border-size 0 0 rgba($grid-inner-border-color, $grid-inner-border-opacity), ($grid-inner-border-size * -1) 0 0 rgba($grid-inner-border-color, $grid-inner-border-opacity); @@ -117,7 +124,8 @@ $grid-outer-border-opacity: $grid-border-opacity; // gutter + column border &--outer.#{$prefix}--grid-2x--inner-border { [class*='#{$prefix}--col-']::before { - box-shadow: math.div($carbon--grid-gutter, 2) 0 0 + box-shadow: + math.div($carbon--grid-gutter, 2) 0 0 rgba($grid-outer-color, $grid-outer-opacity), (math.div($carbon--grid-gutter, 2) * -1) 0 0 rgba($grid-outer-color, $grid-outer-opacity), @@ -131,7 +139,8 @@ $grid-outer-border-opacity: $grid-border-opacity; // gutter divider &--outer-border { [class*='#{$prefix}--col-'] { - box-shadow: $grid-outer-border-size 0 0 + box-shadow: + $grid-outer-border-size 0 0 rgba($grid-outer-border-color, $grid-outer-border-opacity), inset $grid-outer-border-size 0 0 rgba($grid-outer-border-color, $grid-outer-border-opacity); diff --git a/packages/web-extension/src/inject/components/Grid/mini-unit/index.scss b/packages/web-extension/src/inject/components/Grid/mini-unit/index.scss index 451f8cf0..83dbfb58 100644 --- a/packages/web-extension/src/inject/components/Grid/mini-unit/index.scss +++ b/packages/web-extension/src/inject/components/Grid/mini-unit/index.scss @@ -7,10 +7,8 @@ $grid-mini-unit-border-opacity: $grid-opacity; .#{$prefix}--grid-mini-unit { $miniUnitSVG: "data:image/svg+xml;charset=UTF-8,%3csvg width='8px' height='8px' viewBox='0 0 8 8' xmlns='http://www.w3.org/2000/svg'%3e%3crect x='1' y='1' fill='#{$grid-mini-unit-color}' fill-opacity='#{$grid-mini-unit-opacity/2}' width='7' height='7'%3e%3c/rect%3e%3c/svg%3e"; - $miniUnitGradient: rgba( - $grid-mini-unit-border-color, - $grid-mini-unit-border-opacity - ) + $miniUnitGradient: + rgba($grid-mini-unit-border-color, $grid-mini-unit-border-opacity) $grid-mini-unit-border-size, transparent $grid-mini-unit-border-size; @@ -85,7 +83,8 @@ $grid-mini-unit-border-opacity: $grid-opacity; &--horizontal.#{$prefix}--grid-mini-unit--vertical { &::after { // opacity: 1; - background-image: linear-gradient(to right, $miniUnitGradient), + background-image: + linear-gradient(to right, $miniUnitGradient), linear-gradient(to bottom, $miniUnitGradient); } } diff --git a/packages/web-extension/src/inject/components/Highlight/index.scss b/packages/web-extension/src/inject/components/Highlight/index.scss index 69d699c4..8db4777e 100644 --- a/packages/web-extension/src/inject/components/Highlight/index.scss +++ b/packages/web-extension/src/inject/components/Highlight/index.scss @@ -5,7 +5,9 @@ $highlight-opacity: 0.5; .#{$prefix}--highlight { position: absolute; opacity: 0; - transition: opacity $transition-fade, background-color $transition-fade, + transition: + opacity $transition-fade, + background-color $transition-fade, box-shadow $transition-fade; &--grid, diff --git a/packages/web-extension/src/inject/components/Inventory/index.js b/packages/web-extension/src/inject/components/Inventory/index.js index 2064908b..f67df620 100644 --- a/packages/web-extension/src/inject/components/Inventory/index.js +++ b/packages/web-extension/src/inject/components/Inventory/index.js @@ -188,15 +188,26 @@ function getInventory(reset = true) { for (let i = 0; i < libraryKeys.length; i++) { const libraryId = libraryKeys[i]; const libraryName = libraries[libraryId].name; + const libraryVersion = libraries[libraryId].version; const librarySelectors = libraries[libraryId].components; - getInventoryCollection(libraryId, libraryName, librarySelectors); + getInventoryCollection( + libraryId, + libraryName, + libraryVersion, + librarySelectors + ); } return inventory; } -function getInventoryCollection(libraryId, libraryName, componentList) { +function getInventoryCollection( + libraryId, + libraryName, + libraryVersion, + componentList +) { // TODO: prefix check first? // document.querySelector('.bx--'); @@ -210,6 +221,7 @@ function getInventoryCollection(libraryId, libraryName, componentList) { const inventoryData = updateInventory( componentName, libraryName, + libraryVersion, components ); @@ -218,6 +230,7 @@ function getInventoryCollection(libraryId, libraryName, componentList) { // set the library in place if it doesn't exist yet inventory.libraries[libraryId] = { name: libraryName, + version: libraryVersion, components: {}, }; inventory._results[libraryId] = { @@ -245,7 +258,12 @@ function getInventoryCollection(libraryId, libraryName, componentList) { return inventory; } -function updateInventory(componentName, libraryName, components) { +function updateInventory( + componentName, + libraryName, + libraryVersion, + components +) { const inventory = []; if (components.length > 0) { @@ -270,6 +288,7 @@ function updateInventory(componentName, libraryName, components) { if (push) { inventory.push({ library: libraryName, + version: libraryVersion, name: componentName, uniqueID: uniqueID, outerHTML: component.outerHTML, diff --git a/packages/web-extension/src/inject/components/Specs/Color/getThemeName.js b/packages/web-extension/src/inject/components/Specs/Color/getThemeName.js index c2f0aa3d..377b4597 100644 --- a/packages/web-extension/src/inject/components/Specs/Color/getThemeName.js +++ b/packages/web-extension/src/inject/components/Specs/Color/getThemeName.js @@ -1,28 +1,72 @@ import { themes } from '@carbon/themes'; -import { themeKeys } from './themeKeys'; -import { searchCarbonTokens } from './searchCarbonTokens'; +import { themes as themesV11 } from '@carbon/themes-v11'; +import { themeKeys, themeKeysV11 } from './themeKeys'; +import { searchCarbonTokens, prioritizeThemesV11 } from './searchCarbonTokens'; + +/** + * Detect whether the target element is in a Carbon v11 context by checking + * for the closest ancestor carrying a `cds--` class. Falls back to v10. + */ +function isCarbonV11Context(target) { + let el = target; + + while (el && el !== document.body) { + if (el.classList) { + for (const cls of el.classList) { + if (cls.startsWith('cds--')) { + return true; + } + } + } + + el = el.parentElement; + } + + return false; +} function getThemeName(target) { - // check ui background because as of writing this it has a unique value within each theme. + if (isCarbonV11Context(target)) { + // v11: unique identifier token is `background` + const background = getComputedStyle(target) + .getPropertyValue('--cds-background') + .replace(/ /g, ''); + + if (background) { + const searchResults = searchCarbonTokens( + themesV11, + background, + ['background'].concat(themeKeysV11.theme), + '', + prioritizeThemesV11 + ); + + if (searchResults) { + return [searchResults.name.split('-')[0]]; + } + } + + return false; + } + + // v10: check ui background because it has a unique value within each theme. const uiBackground = getComputedStyle(target) .getPropertyValue('--cds-ui-background') .replace(/ /g, ''); - let theme = false; if (uiBackground) { - // find the matching token among all theme tokens in carbon - let searchResults = searchCarbonTokens( + const searchResults = searchCarbonTokens( themes, uiBackground, ['uiBackground'].concat(themeKeys.theme) ); + if (searchResults) { - // parse out the theme name which should be the first segment - theme = [searchResults.name.split('-')[0]]; + return [searchResults.name.split('-')[0]]; } } - return theme; + return false; } -export { getThemeName }; +export { getThemeName, isCarbonV11Context }; diff --git a/packages/web-extension/src/inject/components/Specs/Color/index.js b/packages/web-extension/src/inject/components/Specs/Color/index.js index 50bb04f3..c5833e5f 100644 --- a/packages/web-extension/src/inject/components/Specs/Color/index.js +++ b/packages/web-extension/src/inject/components/Specs/Color/index.js @@ -11,9 +11,10 @@ import { getComponentName } from '@carbon/devtools-utilities/src/getComponentNam import { doesItHaveText } from '@carbon/devtools-utilities/src/doesItHaveText'; import { colors } from '@carbon/colors'; import { themes } from '@carbon/themes'; -import { searchCarbonTokens } from './searchCarbonTokens'; -import { themeKeys } from './themeKeys'; -import { getThemeName } from './getThemeName'; +import { themes as themesV11 } from '@carbon/themes-v11'; +import { searchCarbonTokens, prioritizeThemesV11 } from './searchCarbonTokens'; +import { themeKeys, themeKeysV11 } from './themeKeys'; +import { getThemeName, isCarbonV11Context } from './getThemeName'; import Color from 'color'; const { prefix } = settings; @@ -30,9 +31,19 @@ function escapeHTML(str) { function highlightSpecsColor(target) { if (target) { const styles = window.getComputedStyle(target); + const isV11 = isCarbonV11Context(target); + const activeThemeKeys = isV11 ? themeKeysV11 : themeKeys; + const activeThemes = isV11 ? themesV11 : themes; + const activePrioritizeFn = isV11 ? prioritizeThemesV11 : undefined; const themeName = getThemeName(target); - const themes = themeName || themeKeys.theme; // do we know the current theme? If not give them all of them. - const borderColorGroups = combineBorderColors(styles, themes); + const themeScope = themeName || activeThemeKeys.theme; // do we know the current theme? If not give them all of them. + const borderColorGroups = combineBorderColors( + styles, + themeScope, + activeThemeKeys, + activeThemes, + activePrioritizeFn + ); let tooltipGroups = []; @@ -40,7 +51,12 @@ function highlightSpecsColor(target) { tooltipGroups.push({ eyebrow: '', title: 'Type color', - content: tooltipContent(styles.color, themeKeys.text.concat(themes)), + content: tooltipContent( + styles.color, + activeThemeKeys.text.concat(themeScope), + activeThemes, + activePrioritizeFn + ), }); } @@ -50,7 +66,9 @@ function highlightSpecsColor(target) { title: 'Background color', content: tooltipContent( styles.backgroundColor, - themeKeys.background.concat(themes) + activeThemeKeys.background.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } @@ -59,7 +77,12 @@ function highlightSpecsColor(target) { tooltipGroups.push({ eyebrow: '', title: 'Fill', - content: tooltipContent(styles.fill, themeKeys.icon.concat(themes)), + content: tooltipContent( + styles.fill, + activeThemeKeys.icon.concat(themeScope), + activeThemes, + activePrioritizeFn + ), }); } @@ -82,7 +105,13 @@ function highlightSpecsColor(target) { } } -function combineBorderColors(styles, themes) { +function combineBorderColors( + styles, + themeScope, + activeThemeKeys, + activeThemes, + activePrioritizeFn +) { let borderGroups = []; const validate = { @@ -117,7 +146,9 @@ function combineBorderColors(styles, themes) { title: 'Border color', content: tooltipContent( styles.borderTopColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } else { @@ -127,7 +158,9 @@ function combineBorderColors(styles, themes) { title: 'Horizontal borders color', content: tooltipContent( styles.borderTopColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } else { @@ -137,7 +170,9 @@ function combineBorderColors(styles, themes) { title: 'Border top color', content: tooltipContent( styles.borderTopColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } @@ -148,7 +183,9 @@ function combineBorderColors(styles, themes) { title: 'Border bottom color', content: tooltipContent( styles.borderBottomColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } @@ -160,7 +197,9 @@ function combineBorderColors(styles, themes) { title: 'Vertical borders color', content: tooltipContent( styles.borderRightColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } else { @@ -170,7 +209,9 @@ function combineBorderColors(styles, themes) { title: 'Border right color', content: tooltipContent( styles.borderRightColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } @@ -181,7 +222,9 @@ function combineBorderColors(styles, themes) { title: 'Border left color', content: tooltipContent( styles.borderLeftColor, - themeKeys.border.concat(themes) + activeThemeKeys.border.concat(themeScope), + activeThemes, + activePrioritizeFn ), }); } @@ -191,7 +234,12 @@ function combineBorderColors(styles, themes) { return borderGroups; } -function tooltipContent(value, scopedKeys) { +function tooltipContent( + value, + scopedKeys, + activeThemes = themes, + activePrioritizeFn = undefined +) { let html = ''; if (value) { @@ -206,7 +254,13 @@ function tooltipContent(value, scopedKeys) { html += `