diff --git a/.yarn/cache/cubic-bezier-npm-0.1.2-e7baa5c16d-db21ebda82.zip b/.yarn/cache/cubic-bezier-npm-0.1.2-e7baa5c16d-db21ebda82.zip new file mode 100644 index 000000000..87cd6d740 Binary files /dev/null and b/.yarn/cache/cubic-bezier-npm-0.1.2-e7baa5c16d-db21ebda82.zip differ diff --git a/package.json b/package.json index d17358267..a76f1faea 100644 --- a/package.json +++ b/package.json @@ -151,6 +151,7 @@ "@vanilla-extract/dynamic": "^2.1.1", "@vanilla-extract/sprinkles": "^1.6.2", "classnames": "^2.3.1", + "cubic-bezier": "^0.1.2", "lottie-react": "^2.4.0", "moment": "^2.29.1", "react-autosuggest": "^10.1.0", diff --git a/packages/generate-design-tokens/.yarn/cache/@telefonica-prettier-config-npm-2.0.0-44dbed316e-b7fe4ee936.zip b/packages/generate-design-tokens/.yarn/cache/@telefonica-prettier-config-npm-2.0.0-44dbed316e-b7fe4ee936.zip new file mode 100644 index 000000000..75caa3a11 Binary files /dev/null and b/packages/generate-design-tokens/.yarn/cache/@telefonica-prettier-config-npm-2.0.0-44dbed316e-b7fe4ee936.zip differ diff --git a/packages/generate-design-tokens/.yarn/cache/prettier-npm-3.3.3-e811f023f3-bc86043548.zip b/packages/generate-design-tokens/.yarn/cache/prettier-npm-3.3.3-e811f023f3-bc86043548.zip new file mode 100644 index 000000000..b14018ab5 Binary files /dev/null and b/packages/generate-design-tokens/.yarn/cache/prettier-npm-3.3.3-e811f023f3-bc86043548.zip differ diff --git a/playroom/snippets.tsx b/playroom/snippets.tsx index de988ce33..e5d43d8b2 100644 --- a/playroom/snippets.tsx +++ b/playroom/snippets.tsx @@ -4142,6 +4142,24 @@ const ratingSnippets: Array = [ }, ]; +const meterSnippets: Array = [ + { + group: 'Meter', + name: 'Meter Linear', + code: '', + }, + { + group: 'Meter', + name: 'Meter Angular', + code: '', + }, + { + group: 'Meter', + name: 'Meter Circular', + code: '', + }, +]; + export default [ ...buttonSnippets, ...formSnippets, @@ -4188,6 +4206,7 @@ export default [ ...sliderSnippets, ...cardSnippets, ...exampleScreens, + ...meterSnippets, { group: 'Progress', name: 'Stepper', diff --git a/src/__private_stories__/skin-components-story.tsx b/src/__private_stories__/skin-components-story.tsx index 0d1feef45..4a07528dd 100644 --- a/src/__private_stories__/skin-components-story.tsx +++ b/src/__private_stories__/skin-components-story.tsx @@ -51,6 +51,7 @@ import { Placeholder, NegativeBox, IconInvoicePlanFileRegular, + Meter, } from '..'; import avatarImg from '../__stories__/images/avatar.jpg'; import usingVrImg from '../__stories__/images/using-vr.jpg'; @@ -315,6 +316,28 @@ export const Default: StoryComponent = ({variant}) => { steps={['First', 'Second', 'Third', 'Fourth', 'Fifth']} /> + {/** Meter */} + + + + + + {/** TextLink */} {}}>This is a text link diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-0-1-snap.png new file mode 100644 index 000000000..b821f456a Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-100-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-100-1-snap.png new file mode 100644 index 000000000..e9c3b1be0 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-100-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-20-20-20-20-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-20-20-20-20-0-1-snap.png new file mode 100644 index 000000000..4aeedb633 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-20-20-20-20-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-33-33-1-snap.png new file mode 100644 index 000000000..54ff5ecdf Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-angular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-0-1-snap.png new file mode 100644 index 000000000..dbc29a211 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-100-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-100-1-snap.png new file mode 100644 index 000000000..010c50f2c Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-100-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-20-20-20-20-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-20-20-20-20-0-1-snap.png new file mode 100644 index 000000000..22bd931cc Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-20-20-20-20-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-33-33-1-snap.png new file mode 100644 index 000000000..a4240b7d6 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-circular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-0-1-snap.png new file mode 100644 index 000000000..b5ef63caa Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-100-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-100-1-snap.png new file mode 100644 index 000000000..e870eb296 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-100-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-20-20-20-20-0-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-20-20-20-20-0-1-snap.png new file mode 100644 index 000000000..fa9f6be23 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-20-20-20-20-0-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-33-33-1-snap.png new file mode 100644 index 000000000..2313ac1c1 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-default-linear-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-angular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-angular-33-33-1-snap.png new file mode 100644 index 000000000..7b599e3aa Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-angular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-circular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-circular-33-33-1-snap.png new file mode 100644 index 000000000..2e772fd4f Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-circular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-linear-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-linear-33-33-1-snap.png new file mode 100644 index 000000000..3d946a343 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-inverse-linear-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-angular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-angular-33-33-1-snap.png new file mode 100644 index 000000000..d1360aad7 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-angular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-circular-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-circular-33-33-1-snap.png new file mode 100644 index 000000000..ecd87d59a Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-circular-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-linear-33-33-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-linear-33-33-1-snap.png new file mode 100644 index 000000000..2d7067ee7 Binary files /dev/null and b/src/__screenshot_tests__/__image_snapshots__/meter-screenshot-test-tsx-meter-media-linear-33-33-1-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-3-snap.png index cea6117e8..328721ec6 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-alternative-3-snap.png index aac9ddf92..dc7af795a 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-dark-mode-3-snap.png index f9029ca56..547f931dc 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-3-snap.png index 0f83c2e42..121cda625 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-4-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-4-snap.png index 16f2decc7..265406cca 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-4-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-4-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-and-dark-mode-3-snap.png index b1d918593..300f21e40 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-blau-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-3-snap.png index c95e6ddf3..9a41ce9a6 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-alternative-3-snap.png index 6e1f26c7c..afd286ad9 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-dark-mode-3-snap.png index f2f358d65..032923629 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-3-snap.png index f57528c0a..8272268c7 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-and-dark-mode-3-snap.png index d27b9d3e1..13abe38cf 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-movistar-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-3-snap.png index 123e528ef..39fa3e5eb 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-alternative-3-snap.png index bd0620f44..4406fd959 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-dark-mode-3-snap.png index e6101adf9..ff207a137 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-3-snap.png index 80be1de25..878b9a4a9 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-and-dark-mode-3-snap.png index 0dfc2e7b9..2757b9140 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-3-snap.png index 70917892c..23fb83004 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-alternative-3-snap.png index 0344b1c61..bbeadc1c6 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-dark-mode-3-snap.png index fcc807484..498cfecbf 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-2-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-2-snap.png index cf63ba861..b1882a61a 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-2-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-2-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-3-snap.png index 3d96d2e61..35ba39d8c 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-4-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-4-snap.png index 0ad09a9ba..0f9cae6f1 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-4-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-4-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-and-dark-mode-3-snap.png index 5c6f62c07..0217ab049 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-o-2-new-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-3-snap.png index fc100da15..fe41d1ae9 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-alternative-3-snap.png index bede1f660..4898c28c3 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-dark-mode-3-snap.png index 12937e374..81f27687f 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-3-snap.png index 0a4d326dc..95eea6145 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-and-dark-mode-3-snap.png index 7a3e40729..2ec005423 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-telefonica-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-3-snap.png index cb5d48e40..f983c3794 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-alternative-3-snap.png index 0bcfdc8d2..cb90bd393 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-dark-mode-3-snap.png index 6125055bb..297e14038 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-3-snap.png index c4a0b1a1f..8aa6178d9 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-and-dark-mode-3-snap.png index c5c579c04..e1bbcacd8 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-tu-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-3-snap.png index d9a3408ae..78a37dd9c 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-alternative-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-alternative-3-snap.png index c1b167946..68aed81f5 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-alternative-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-alternative-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-dark-mode-3-snap.png index db778b8a9..046f9724a 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-3-snap.png index 009b0b56e..30f599a46 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-3-snap.png differ diff --git a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-and-dark-mode-3-snap.png b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-and-dark-mode-3-snap.png index a30f78b68..0a50dbf38 100644 Binary files a/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-and-dark-mode-3-snap.png and b/src/__screenshot_tests__/__image_snapshots__/private-skin-components-screenshot-test-tsx-components-in-vivo-new-inverse-and-dark-mode-3-snap.png differ diff --git a/src/__screenshot_tests__/meter-screenshot-test.tsx b/src/__screenshot_tests__/meter-screenshot-test.tsx new file mode 100644 index 000000000..e8cd4117a --- /dev/null +++ b/src/__screenshot_tests__/meter-screenshot-test.tsx @@ -0,0 +1,44 @@ +import {openStoryPage, screen} from '../test-utils'; + +test.each` + values | type | themeVariant + ${[0]} | ${'linear'} | ${'default'} + ${[0]} | ${'circular'} | ${'default'} + ${[0]} | ${'angular'} | ${'default'} + ${[100]} | ${'linear'} | ${'default'} + ${[100]} | ${'circular'} | ${'default'} + ${[100]} | ${'angular'} | ${'default'} + ${[33, 33]} | ${'linear'} | ${'default'} + ${[33, 33]} | ${'circular'} | ${'default'} + ${[33, 33]} | ${'angular'} | ${'default'} + ${[33, 33]} | ${'linear'} | ${'inverse'} + ${[33, 33]} | ${'circular'} | ${'inverse'} + ${[33, 33]} | ${'angular'} | ${'inverse'} + ${[33, 33]} | ${'linear'} | ${'media'} + ${[33, 33]} | ${'circular'} | ${'media'} + ${[33, 33]} | ${'angular'} | ${'media'} + ${[20, 20, 20, 20, 0]} | ${'linear'} | ${'default'} + ${[20, 20, 20, 20, 0]} | ${'circular'} | ${'default'} + ${[20, 20, 20, 20, 0]} | ${'angular'} | ${'default'} +`('Meter $themeVariant $type $values', async ({themeVariant, values, type}) => { + await openStoryPage({ + id: 'components-data-visualizations-meter--meter-story', + args: { + themeVariant, + width: 200, + type, + valuesCount: values.length, + ...values.reduce( + (acc: Array, value: number, index: number) => ({ + ...acc, + [`value${index + 1}`]: value, + }), + {} + ), + }, + }); + + const stepper = await screen.findByTestId('Meter'); + const image = await stepper.screenshot(); + expect(image).toMatchImageSnapshot(); +}); diff --git a/src/__stories__/meter-story.tsx b/src/__stories__/meter-story.tsx new file mode 100644 index 000000000..e59484730 --- /dev/null +++ b/src/__stories__/meter-story.tsx @@ -0,0 +1,127 @@ +import * as React from 'react'; +import {Box, Meter, ResponsiveLayout} from '..'; +import beachImg from './images/beach.jpg'; + +import type {MeterType} from '../meter'; + +export default { + title: 'Components/Data Visualizations/Meter', + argTypes: { + type: { + options: ['angular', 'circular', 'linear'] as Array, + control: {type: 'select'}, + }, + themeVariant: { + options: ['default', 'inverse', 'media'], + control: {type: 'select'}, + }, + valuesCount: { + control: {type: 'range', min: 1, max: 8, step: 1}, + }, + fullWidth: { + control: {type: 'boolean'}, + }, + width: { + if: {arg: 'fullWidth', eq: false}, + control: {type: 'range', min: 64, max: 600, step: 1}, + }, + value1: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value2: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value3: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value4: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value5: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value6: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value7: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + value8: { + control: {type: 'range', min: 0, max: 100, step: 1}, + }, + }, + parameters: { + fullScreen: true, + }, +}; + +type MeterStoryArgs = { + type: MeterType; + reverse: boolean; + ariaLabel: string; + themeVariant: 'default' | 'inverse' | 'media'; + fullWidth: boolean; + width: number; + valuesCount: number; + value1: number; + value2: number; + value3: number; + value4: number; + value5: number; + value6: number; + value7: number; + value8: number; +}; + +export const MeterStory: StoryComponent = ({ + type, + reverse, + themeVariant, + valuesCount, + fullWidth, + width, + ariaLabel, + ...valuesArgs +}) => { + const values = Object.values(valuesArgs).slice(0, valuesCount); + return ( +
+ + + + + +
+ ); +}; + +MeterStory.storyName = 'Meter'; +MeterStory.args = { + type: 'angular', + reverse: false, + ariaLabel: 'Meter example', + themeVariant: 'default', + fullWidth: false, + width: 400, + valuesCount: 8, + value1: 10, + value2: 10, + value3: 10, + value4: 10, + value5: 10, + value6: 10, + value7: 10, + value8: 10, +}; diff --git a/src/__tests__/meter-test.tsx b/src/__tests__/meter-test.tsx new file mode 100644 index 000000000..0148d0bff --- /dev/null +++ b/src/__tests__/meter-test.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import {screen, render} from '@testing-library/react'; +import ThemeContextProvider from '../theme-context-provider'; +import {makeTheme} from './test-utils'; +import Meter from '../meter'; + +test('Meter custom label', () => { + render( + + + + ); + + const meter = screen.getByRole('meter', {name: 'Patata'}); + expect(meter).toBeInTheDocument(); +}); + +test('Meter default label', () => { + render( + + + + ); + + const expectedLabel = + 'Indicador de progreso con 3 secciones, total 60% de 100%. Sección 1: 10%. Sección 2: 20%. Sección 3: 30%'; + + const meter = screen.getByRole('meter', {name: expectedLabel}); + expect(meter).toBeInTheDocument(); +}); diff --git a/src/__tests__/testid-test.tsx b/src/__tests__/testid-test.tsx index b5739a5d7..63c981c76 100644 --- a/src/__tests__/testid-test.tsx +++ b/src/__tests__/testid-test.tsx @@ -11,6 +11,7 @@ import { Image, HighlightedCard, IconShopRegular, + Meter, Placeholder, SearchField, Stack, @@ -278,3 +279,12 @@ test('MainSectionHeader test ids', () => { ] ); }); + +test('Meter test ids', () => { + checkTestIds(, [ + { + componentName: 'Meter', + internalTestIds: [], + }, + ]); +}); diff --git a/src/index.tsx b/src/index.tsx index e8d1dc47e..fe30cf331 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -64,6 +64,7 @@ export {default as HorizontalScroll} from './horizontal-scroll'; export {default as HighlightedCard} from './highlighted-card'; export {default as Stepper} from './stepper'; export {ProgressBar, ProgressBarStepped} from './progress-bar'; +export {default as Meter} from './meter'; export {Rating, InfoRating} from './rating'; export {VerticalMosaic, HorizontalMosaic} from './mosaic'; export {Timer, TextTimer} from './timer'; diff --git a/src/meter.tsx b/src/meter.tsx new file mode 100644 index 000000000..ea1cf6a90 --- /dev/null +++ b/src/meter.tsx @@ -0,0 +1,494 @@ +// https://www.figma.com/design/jWWCJ9kYl6I5uHLz3GcgRp/%F0%9F%94%B6-%5BREADY%5D-Data-Visualizations-Specs +'use client'; +import * as React from 'react'; +import {vars} from './skins/skin-contract.css'; +// @ts-expect-error - no types +import bezier from 'cubic-bezier'; +import {getPrefixedDataAttributes} from './utils/dom'; +import {useThemeVariant} from './theme-variant-context'; +import {useElementDimensions, useTheme} from './hooks'; +import {meterTotalLabel, meterSectionLabel} from './text-tokens'; +import {isRunningAcceptanceTest} from './utils/platform'; + +import type {DataAttributes} from './utils/types'; + +const VIEW_BOX_WIDTH = 100; +const CENTER_X = VIEW_BOX_WIDTH / 2; +const CENTER_Y = VIEW_BOX_WIDTH / 2; + +const STROKE_WIDTH_PX = 6; +const SEPARATION_PX = 2; + +const ANIMATION_DELAY_MS = 200; +const ANIMATION_DURATION_MS = 1000; +const ANIMATION_EPSILON = 1000 / 60 / ANIMATION_DURATION_MS / 4; + +const MAX_SEGMENT_VALUE = 100; +const SMALL_VALUE_THRESHOLD = 0.0001; + +const TYPE_LINEAR = 'linear'; +const TYPE_ANGULAR = 'angular'; +const TYPE_CIRCULAR = 'circular'; + +export type MeterType = typeof TYPE_LINEAR | typeof TYPE_ANGULAR | typeof TYPE_CIRCULAR; + +const DEFAULT_COLORS = [ + vars.colors.controlActivated, + vars.colors.warning, + vars.colors.success, + vars.colors.highlight, + vars.colors.promo, +]; + +const DEFAULT_COLORS_INVERSE = [ + vars.colors.controlActivatedInverse, + vars.colors.warning, + vars.colors.success, + vars.colors.highlight, + vars.colors.promo, +]; + +/** + * "start"/"end" values for each segment of the meter. The values are in the range [0, 1] + */ +type Segment = { + start: number; + end: number; +}; + +/** + * Cubic bezier easing function https://github.com/arian/cubic-bezier/blob/27d2512d15a0b873fa0fca8769069c7b290e80f8/index.js + * @param time - time in the range [0, 1] + */ +const timingFunction: (time: number) => number = bezier(0.75, 0, 0.27, 1, ANIMATION_EPSILON); + +const clamp = (n: number, min: number, max: number) => Math.min(Math.max(n, min), max); + +/** + * Calculate the start and end segment values for each segment of the meter + */ +const calculateSegments = ( + currentValues: Array, + targetValues: Array, + time: number, + reverse: boolean +): Array => { + const segments: Array = []; + + let startValue = 0; + let endValue = 0; + for (let i = 0; i < currentValues.length; i++) { + startValue += currentValues[i]; + endValue += targetValues[i]; + + // each segment has an accumulated delay time. The last segment has no delay + const delay = ANIMATION_DELAY_MS * (reverse ? i : currentValues.length - 1 - i); + const animationTime = clamp((time - delay) / ANIMATION_DURATION_MS, 0, 1); + + const t = clamp(timingFunction(animationTime), 0, 1); + const start = segments.at(-1)?.end || 0; + const end = clamp(startValue + (endValue - startValue) * t, 0, 1 - SMALL_VALUE_THRESHOLD); + segments.push({start, end}); + } + return segments; +}; + +const createPath = ({ + x1, + y1, + x2, + y2, + radius, + clockwise = 1, + largeArchFlag = 0, +}: { + x1: number; + y1: number; + x2: number; + y2: number; + radius: number; + clockwise?: 0 | 1 | boolean; + largeArchFlag?: 0 | 1 | boolean; +}): string => { + const xAxisRotation = 0; + if (radius) { + // https://www.nan.fyi/svg-paths/arcs + return `M ${x1} ${y1} A ${radius} ${radius} ${xAxisRotation} ${+largeArchFlag} ${+clockwise} ${x2} ${y2}`; + } else { + // https://www.nan.fyi/svg-paths/lines + return `M ${x1} ${y1} L ${x2} ${y2}`; + } +}; + +type MeterProps = { + type?: MeterType; + /** Position of the meter. 0 is at the start, 100 is at the end. The sum of the values must not exceed 100. */ + values: Array; + width?: number | string; + colors?: Array; + reverse?: boolean; + dataAttributes?: DataAttributes; + 'aria-hidden'?: boolean | 'true' | 'false'; + 'aria-label'?: string; + 'aria-labelledby'?: string; +}; + +const MeterComponent = ({ + type = TYPE_ANGULAR, + width: widthProp = '100%', + colors, + values: valuesProp, + reverse = false, + dataAttributes, + 'aria-hidden': ariaHidden = false, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, +}: MeterProps): JSX.Element => { + const {borderRadii, t} = useTheme(); + const {ref: containerRef, width: containerWidth} = useElementDimensions(); + const hasRoundLineCaps = parseInt(borderRadii.bar) !== 0; + const themeVariant = useThemeVariant(); + const isOverMedia = themeVariant === 'media'; + const isInverse = themeVariant === 'inverse'; + const segmentColors = colors || (isInverse || isOverMedia ? DEFAULT_COLORS_INVERSE : DEFAULT_COLORS); + const [width, setWidth] = React.useState(typeof widthProp === 'number' ? widthProp : 0); + const scaleFactor = width === 0 ? 1 : VIEW_BOX_WIDTH / width; + const lineCapRadiusPx = hasRoundLineCaps ? STROKE_WIDTH_PX / 2 : 0; + const lineCapRadius = lineCapRadiusPx * scaleFactor; + const strokeWidth = STROKE_WIDTH_PX * scaleFactor; + const radius = type === TYPE_LINEAR ? 0 : CENTER_X - strokeWidth / 2; + const separation = SEPARATION_PX * scaleFactor; + + const id = React.useId(); + const markerCurrentId = `marker-current-${id}`; + const markerStartId = `marker-start-${id}`; + const maskLastSegmentId = `mask-last-segment-${id}`; + const maskBarTrackId = `mask-bar-track-${id}`; + + const shouldAnimate = React.useMemo(() => { + return ( + window.matchMedia(`(prefers-reduced-motion: reduce)`).matches !== true && + !isRunningAcceptanceTest() + ); + }, []); + + const maxValue = + type === TYPE_LINEAR + ? VIEW_BOX_WIDTH - lineCapRadius * 2 + : type === TYPE_CIRCULAR + ? Math.PI * 2 + : Math.PI; + + const segmentSeparation = + type === TYPE_LINEAR ? separation / VIEW_BOX_WIDTH : separation / radius / maxValue; + + const height = + type === TYPE_LINEAR ? STROKE_WIDTH_PX : type === TYPE_CIRCULAR ? width : width / 2 + lineCapRadiusPx; + + const viewBoxHeight = + type === TYPE_LINEAR + ? strokeWidth + : type === TYPE_CIRCULAR + ? VIEW_BOX_WIDTH + : CENTER_X + lineCapRadius; + + const trackbarColor = isOverMedia + ? vars.colors.inverse + : isInverse + ? vars.colors.barTrackInverse + : vars.colors.barTrack; + + // scale values to the range [0, 1] + const values = React.useMemo(() => { + return valuesProp.map((v) => v / MAX_SEGMENT_VALUE); + }, [valuesProp]); + + // the animation starts with these values + const initialValuesRef = React.useRef>( + Array.from({length: values.length}, () => (reverse ? 1 : 0)) + ); + + const [segments, setSegments] = React.useState>(() => { + return values.map(() => ({start: 0, end: 0})); + }); + + // this is to know which are the first and last visible segments, which have special treatments + let firstNonZeroIndex = -1; + let lastNonZeroIndex = -1; + for (let i = 0; i < segments.length; i++) { + if (segments[i].end - segments[i].start > SMALL_VALUE_THRESHOLD) { + if (firstNonZeroIndex < 0) { + firstNonZeroIndex = i; + } + lastNonZeroIndex = i; + } + } + + const lastSegment: Segment | undefined = segments.at(-1); + + React.useEffect(() => { + if (typeof widthProp === 'number') { + setWidth(widthProp); + } else { + setWidth(containerWidth); + } + }, [widthProp, containerWidth]); + + React.useEffect(() => { + let raf: number; + const start = performance.now(); + const end = start + ANIMATION_DURATION_MS + ANIMATION_DELAY_MS * (values.length - 1); + let currentSegments: Array = []; + const animate = () => { + const now = performance.now(); + currentSegments = calculateSegments(initialValuesRef.current, values, now - start, reverse); + if (shouldAnimate && now < end) { + raf = requestAnimationFrame(animate); // request next frame + } else { + currentSegments = calculateSegments(initialValuesRef.current, values, end - start, reverse); // set the final values + initialValuesRef.current = values; + } + setSegments(currentSegments); + }; + animate(); + return () => { + cancelAnimationFrame(raf); + // animation was cancelled, snapshot current values + initialValuesRef.current = currentSegments.map((s) => s.end - s.start); + }; + }, [radius, values, type, reverse, shouldAnimate]); + + const getX = React.useCallback( + (value: number) => + type === TYPE_LINEAR + ? lineCapRadius + maxValue * value + : CENTER_X - radius * Math.cos(value * maxValue), + [lineCapRadius, maxValue, radius, type] + ); + + const getY = React.useCallback( + (value: number) => + type === TYPE_LINEAR ? strokeWidth / 2 : CENTER_Y - radius * Math.sin(value * maxValue), + [maxValue, radius, strokeWidth, type] + ); + + const getColor = (index: number) => segmentColors[index % segmentColors.length]; + + const totalPercent = Math.round((lastSegment?.end || 0) * 100); + + const valueText = + t(meterTotalLabel, values.length, totalPercent) + + ' ' + + values.map((v, i) => `${t(meterSectionLabel, i + 1, Math.round(v * 100))}`).join('. '); + + return ( +
+ +
+ ); +}; + +/** + * This wrapper is to force a remount when some specific props change + */ +const Meter = (props: MeterProps): JSX.Element => { + return ; +}; + +export default Meter; diff --git a/src/text-tokens.tsx b/src/text-tokens.tsx index 641582036..cbaec33f2 100644 --- a/src/text-tokens.tsx +++ b/src/text-tokens.tsx @@ -572,3 +572,25 @@ export const ratingQuantitativeLabel: TextToken = { de: '1$s von 2$s', pt: '1$s de 2$s', }; + +/** + * 1$s: segments count + * 2$s: total percentage value + */ +export const meterTotalLabel: TextToken = { + es: 'Indicador de progreso con 1$s secciones, total 2$s% de 100%.', + en: 'Gauge chart 1$s segments, total 2$s% out of 100%.', + de: 'Fortschrittsanzeige mit 1$s Abschnitten, insgesamt 2$s% von 100%.', + pt: 'Indicador de progresso com 1$s seções, total 2$s% de 100%.', +}; + +/** + * 1$s: segment number + * 2$s: segment percentage value + */ +export const meterSectionLabel: TextToken = { + es: 'Sección 1$s: 2$s%', + en: 'Segment 1$s: 2$s%', + de: 'Abschnitt 1$s: 2$s%', + pt: 'Seção 1$s: 2$s%', +}; diff --git a/src/theme-context-provider.tsx b/src/theme-context-provider.tsx index cb76786ec..30bcded89 100644 --- a/src/theme-context-provider.tsx +++ b/src/theme-context-provider.tsx @@ -133,8 +133,15 @@ const ThemeContextProvider = ({theme, children, as, withoutStyles = false}: Prop const language = localeToLanguage(theme.i18n.locale); const translate = React.useCallback( - (token: TextToken): string => { - return token[language] || token.en; + (token: TextToken, ...params: Array): string => { + const text = token[language] || token.en; + if (!params.length) { + return text; + } + // replace token parameters: 1$s, 2$s, 3$s, etc. + return text.replace(/\d+\$s/g, (substr) => { + return String(params[parseInt(substr) - 1] ?? substr); + }); }, [language] ); @@ -174,6 +181,7 @@ const ThemeContextProvider = ({theme, children, as, withoutStyles = false}: Prop ...sanitizeDimensions(theme.dimensions), }, textPresets, + borderRadii: theme.skin.borderRadii ?? defaultBorderRadiiConfig, Link: getMisticaLinkComponent(theme.Link), isDarkMode: isDarkModeEnabled, isIos: getPlatform(platformOverrides) === 'ios', diff --git a/src/theme.tsx b/src/theme.tsx index dc6d2e914..6aa5361da 100644 --- a/src/theme.tsx +++ b/src/theme.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import type {RegionCode} from './utils/region-code'; import type {Locale} from './utils/locale'; -import type {Colors, Skin, SkinName, TextPresetsConfig} from './skins/types'; +import type {BorderRadiiConfig, Colors, Skin, SkinName, TextPresetsConfig} from './skins/types'; import type {TrackingEvent} from './utils/types'; import type {Dictionary, TextToken} from './text-tokens'; @@ -162,11 +162,12 @@ export type Theme = { // TODO: rename this props to navigationBarHeight (or something similar) in next major dimensions: {headerMobileHeight: number; headerDesktopHeight: number}; colorValues: Colors; + borderRadii: BorderRadiiConfig; textPresets: TextPresetsConfig; Link: LinkComponent; isDarkMode: boolean; isIos: boolean; useHrefDecorator: () => (href: string) => string; - t: (token: TextToken) => string; + t: (token: TextToken, ...params: Array) => string; preventCopyInFormFields: boolean; }; diff --git a/yarn.lock b/yarn.lock index 15fc8821d..fc11ca58f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5543,6 +5543,7 @@ __metadata: classnames: ^2.3.1 cpx: ^1.5.0 cross-env: ^7.0.3 + cubic-bezier: ^0.1.2 detect-port: ^1.3.0 dpdm: ^3.8.0 es6-promise-pool: ^2.5.0 @@ -9479,6 +9480,13 @@ __metadata: languageName: node linkType: hard +"cubic-bezier@npm:^0.1.2": + version: 0.1.2 + resolution: "cubic-bezier@npm:0.1.2" + checksum: db21ebda82ab3662e1209dcff7612a3b265bb94e05892a609be01cf788ed681914ed9df8d277eb936012b4a58e5786846a8318b6e6bd0ec74087d6ad42566cc6 + languageName: node + linkType: hard + "cwd@npm:^0.10.0": version: 0.10.0 resolution: "cwd@npm:0.10.0"