diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..b782dbeec Binary files /dev/null and b/.DS_Store differ diff --git a/.changeset/sharp-bees-grin.md b/.changeset/sharp-bees-grin.md new file mode 100644 index 000000000..e55b47f2e --- /dev/null +++ b/.changeset/sharp-bees-grin.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": patch +--- + +TS fix for combobox diff --git a/.changeset/sixty-experts-marry.md b/.changeset/sixty-experts-marry.md new file mode 100644 index 000000000..dc3b97d2c --- /dev/null +++ b/.changeset/sixty-experts-marry.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": minor +--- + +Add area chart diff --git a/.changeset/slimy-items-change.md b/.changeset/slimy-items-change.md new file mode 100644 index 000000000..e56e08676 --- /dev/null +++ b/.changeset/slimy-items-change.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": patch +--- + +fix(table): replaced column-type of "row-header" with boolean row-header diff --git a/.changeset/thirty-walls-notice.md b/.changeset/thirty-walls-notice.md new file mode 100644 index 000000000..96a359a6f --- /dev/null +++ b/.changeset/thirty-walls-notice.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": patch +--- + +Upgrade dependencies diff --git a/.changeset/wet-wombats-roll.md b/.changeset/wet-wombats-roll.md new file mode 100644 index 000000000..2e10ba609 --- /dev/null +++ b/.changeset/wet-wombats-roll.md @@ -0,0 +1,5 @@ +--- +"@ebay/ebayui-core": patch +--- + +Updated the component-browser.ts file to reference shared attributes from tags-html.d.ts and added the Textbox class implementation. diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 7dcbef084..c16543b18 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -51,7 +51,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: coverage/lcov.info - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 # Deployment job deploy: diff --git a/.gitignore b/.gitignore index 5b22ef625..256eb9667 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ yarn.lock .env _cdn __screenshots__ +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1c4632b33..0e11df6a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,10 +41,10 @@ "@commitlint/config-conventional": "^19", "@ebay/browserslist-config": "^2.10.0", "@ebay/skin": "~18.6.0", - "@marko/compiler": "^5.37.23", + "@marko/compiler": "^5.39.10", "@marko/prettyprint": "^3.0.1", "@marko/testing-library": "^6", - "@marko/type-check": "^1.2.4", + "@marko/type-check": "^1.3.12", "@marko/vite": "^4.1.20", "@storybook/addon-a11y": "^8.3.6", "@storybook/addon-docs": "^8.3.6", @@ -72,7 +72,7 @@ "libphonenumber-js": "^1.11.17", "lint-staged": "^15.2.11", "lintspaces-cli": "^1.0.0", - "marko": "^5.35.32", + "marko": "^5.37.10", "playwright": "^1.49.1", "postcss-less": "^6.0.0", "prettier": "^3.4.2", @@ -215,12 +215,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", - "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", + "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", + "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", - "@babel/types": "^7.26.0", + "@babel/parser": "^7.26.5", + "@babel/types": "^7.26.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -383,9 +384,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -426,19 +427,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", - "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", @@ -508,11 +496,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", - "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.5.tgz", + "integrity": "sha512-SRJ4jYmXRqV1/Xc+TIVG84WjHBXKlxO9sHQnA2Pf12QQEAp1LOh6kDzNHXcUnbH1QI0FDoPPVOt+vyUDucxpaw==", + "license": "MIT", "dependencies": { - "@babel/types": "^7.26.0" + "@babel/types": "^7.26.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -1086,14 +1075,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", - "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", + "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-simple-access": "^7.25.9" + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1560,14 +1548,14 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", - "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.5.tgz", + "integrity": "sha512-GJhPO0y8SD5EYVCy2Zr+9dSZcEgaSmq5BLR0Oc25TOEhC+ba49vUAGZFjy8v79z9E1mdldq4x9d1xgh4L1d5dQ==", "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.25.9", "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-plugin-utils": "^7.26.5", "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", "@babel/plugin-syntax-typescript": "^7.25.9" }, @@ -1825,16 +1813,16 @@ } }, "node_modules/@babel/traverse": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", - "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.5.tgz", + "integrity": "sha512-rkOSPOw+AXbgtwUga3U4u8RpoK9FEFWBNAlTpcnkLFjL5CT+oyHNuUUC/xx6XefEJ16r38r8Bc/lfp6rYuHeJQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/generator": "^7.25.9", - "@babel/parser": "^7.25.9", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.5", + "@babel/parser": "^7.26.5", "@babel/template": "^7.25.9", - "@babel/types": "^7.25.9", + "@babel/types": "^7.26.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1843,9 +1831,9 @@ } }, "node_modules/@babel/types": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", - "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "version": "7.26.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.5.tgz", + "integrity": "sha512-L6mZmwFDK6Cjh1nRCLXpa6no13ZIioJDz7mdkzHv399pThrTa/k0nUlNaenOeh2kWu/iaOQYElEpKPUswUa9Vg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -3760,55 +3748,62 @@ "marko": "^4.12.4 || ^5" } }, - "node_modules/@marko/babel-utils": { - "version": "6.5.10", - "resolved": "https://registry.npmjs.org/@marko/babel-utils/-/babel-utils-6.5.10.tgz", - "integrity": "sha512-ziaYtREMoFCpUp2GByDz2ELj5n5SrO9ATlhuBt5TPYAKElHWck1pqq71WVnHvJ9qqRhT92bWQ6N1eyWjTDNy/Q==", - "dependencies": { - "@babel/runtime": "^7.26.0", - "jsesc": "^3.0.2", - "relative-import-path": "^1.0.0" - } - }, "node_modules/@marko/compiler": { - "version": "5.37.23", - "resolved": "https://registry.npmjs.org/@marko/compiler/-/compiler-5.37.23.tgz", - "integrity": "sha512-LRaRheDcCzZrARINcQtbMEUokfXM8ia4itcQbBWok/pIScSwAD8ahGjqneHaS6Y3H07vilflSqjHzBqSzS1SGw==", + "version": "5.39.10", + "resolved": "https://registry.npmjs.org/@marko/compiler/-/compiler-5.39.10.tgz", + "integrity": "sha512-bq1mLsyi1swyb2mJOuqOlHCUCBN/SnbtL13fZvYftmVvHMT2sd/U2uBfW1AAJwoWyOww1jcwdyiM8Bd2IvCzZA==", + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/core": "^7.26.0", - "@babel/generator": "^7.26.2", - "@babel/parser": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", "@babel/plugin-syntax-typescript": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.25.9", - "@babel/plugin-transform-typescript": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/plugin-transform-typescript": "^7.26.3", "@babel/runtime": "^7.26.0", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.26.0", + "@babel/traverse": "^7.26.4", + "@babel/types": "^7.26.3", "@luxass/strip-json-comments": "^1.3.2", - "@marko/babel-utils": "^6.5.10", "complain": "^1.6.1", "he": "^1.2.0", - "htmljs-parser": "^5.5.2", - "jsesc": "^3.0.2", + "htmljs-parser": "^5.5.3", + "jsesc": "^3.1.0", "kleur": "^4.1.5", "lasso-package-root": "^1.0.1", "raptor-regexp": "^1.0.1", "raptor-util": "^3.2.0", + "relative-import-path": "^1.0.0", "resolve-from": "^5.0.0", "self-closing-tags": "^1.0.1", "source-map-support": "^0.5.21" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@marko/compiler/node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" } }, "node_modules/@marko/language-tools": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/@marko/language-tools/-/language-tools-2.4.5.tgz", - "integrity": "sha512-8nYK1KFUaDn9O6FWe9Ueq7PkQm0zfjilpvf9qChxrl43ftJ/23mtDkXBX3bizbSc+1REFuuiVyE+VQqDJCGePA==", + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@marko/language-tools/-/language-tools-2.5.12.tgz", + "integrity": "sha512-fftw8n5kpknSpZT/mQLpl6IG8bHVFh/q6lxpARxlhIQkgnwSU88d7BsnZ7OyA8CRMg1xI4+MfbyJpKg/l/7flQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.2", + "@babel/parser": "^7.26.3", "@luxass/strip-json-comments": "^1.3.2", - "htmljs-parser": "^5.5.2", + "htmljs-parser": "^5.5.3", "relative-import-path": "^1.0.0" }, "peerDependencies": { @@ -3975,33 +3970,19 @@ "marko": "^3 || ^4 || ^5" } }, - "node_modules/@marko/translator-default": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/@marko/translator-default/-/translator-default-6.0.23.tgz", - "integrity": "sha512-F7IuNidVbOcZnir29EkYhGu+pfR9Fz1RE2MFtE0HOhghkAFTUnY2XUcx+6iVkCRZbgEq54ROl+3xsr7ORWLJWA==", - "dependencies": { - "@babel/runtime": "^7.26.0", - "@marko/babel-utils": "^6.5.10", - "magic-string": "^0.30.12", - "self-closing-tags": "^1.0.1" - }, - "peerDependencies": { - "@marko/compiler": "^5.16.1", - "marko": "^5.17.2" - } - }, "node_modules/@marko/type-check": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@marko/type-check/-/type-check-1.2.4.tgz", - "integrity": "sha512-nMq5c8NxvfKSPUfzIXj6TJ+7gJJdBDMvqWHY3icsvGb7Nfoj2ojXQXJ+T2C/00A133zvUvnDrRK1VGBbmSRyww==", + "version": "1.3.12", + "resolved": "https://registry.npmjs.org/@marko/type-check/-/type-check-1.3.12.tgz", + "integrity": "sha512-SWVQ+vf7w0vG0JAOwRxGX6Ot6J8kSDhtSpxx08zkC/rc9bq1q2Yptcc5xvy8X1vWzPKexqh7EqvGtC/8IXB9uA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", "@luxass/strip-json-comments": "^1.3.2", - "@marko/language-tools": "^2.4.5", + "@marko/language-tools": "^2.5.12", "arg": "^5.0.2", "kleur": "^4.1.5", - "typescript": "^5.6.3" + "typescript": "^5.7.2" }, "bin": { "marko-type-check": "dist/cli.js", @@ -9877,9 +9858,9 @@ } }, "node_modules/htmljs-parser": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/htmljs-parser/-/htmljs-parser-5.5.2.tgz", - "integrity": "sha512-5pNHk0dSIFLA0ucC2NJv4ikhOdAFKT2X3zo69uAd5fqt3AX4kaXD9F17k/98LKCn5u4Dd9PXeso2iJ0bFw0X+Q==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/htmljs-parser/-/htmljs-parser-5.5.3.tgz", + "integrity": "sha512-uX5BWkdIJV2qfxTVMcFJGPSqx9EYZGfZQv7THtNfA3cIr2zfwlzjojqO7jHDntO3cJUQauRSjBETBkiaCi3wtA==", "license": "MIT" }, "node_modules/htmlparser2": { @@ -11798,9 +11779,9 @@ } }, "node_modules/magic-string": { - "version": "0.30.12", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", - "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -11950,12 +11931,13 @@ } }, "node_modules/marko": { - "version": "5.35.32", - "resolved": "https://registry.npmjs.org/marko/-/marko-5.35.32.tgz", - "integrity": "sha512-LuzveiXXQZoiRqdoRdlWXrC/JxZWMItfMixnHZ8T3XY2FPAFa8f8UwscIXsu8BSFD3Vzi60hCL1RHHf7W6nFtw==", + "version": "5.37.10", + "resolved": "https://registry.npmjs.org/marko/-/marko-5.37.10.tgz", + "integrity": "sha512-UUBDJNG1VzGAWRUiLqxG5R91OkJnYKvnUsFRFKE9/xkfO1Sp0eP2mWOwfcRbhaQtfj1DvUkR+Q9pxtoaF7/fUg==", + "license": "MIT", "dependencies": { - "@marko/compiler": "^5.37.23", - "@marko/translator-default": "^6.0.23", + "@babel/runtime": "^7.26.0", + "@marko/compiler": "^5.39.9", "app-module-path": "^2.2.0", "argly": "^1.2.0", "browser-refresh-client": "1.1.4", @@ -11963,6 +11945,7 @@ "csstype": "^3.1.3", "events-light": "^1.0.5", "listener-tracker": "^2.0.0", + "magic-string": "^0.30.17", "minimatch": "^9.0.5", "raptor-util": "^3.2.0", "resolve-from": "^5.0.0", @@ -11971,6 +11954,9 @@ }, "bin": { "markoc": "bin/markoc" + }, + "engines": { + "node": "18 || 20 || >=22" } }, "node_modules/marko/node_modules/brace-expansion": { @@ -15784,9 +15770,9 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index 797cba9b0..0080de007 100644 --- a/package.json +++ b/package.json @@ -101,10 +101,10 @@ "@commitlint/config-conventional": "^19", "@ebay/browserslist-config": "^2.10.0", "@ebay/skin": "~18.6.0", - "@marko/compiler": "^5.37.23", + "@marko/compiler": "^5.39.10", "@marko/prettyprint": "^3.0.1", "@marko/testing-library": "^6", - "@marko/type-check": "^1.2.4", + "@marko/type-check": "^1.3.12", "@marko/vite": "^4.1.20", "@storybook/addon-a11y": "^8.3.6", "@storybook/addon-docs": "^8.3.6", @@ -132,7 +132,7 @@ "libphonenumber-js": "^1.11.17", "lint-staged": "^15.2.11", "lintspaces-cli": "^1.0.0", - "marko": "^5.35.32", + "marko": "^5.37.10", "playwright": "^1.49.1", "postcss-less": "^6.0.0", "prettier": "^3.4.2", diff --git a/src/common/charts/shared.ts b/src/common/charts/shared.ts index 46b7351a0..e4c689c87 100644 --- a/src/common/charts/shared.ts +++ b/src/common/charts/shared.ts @@ -1,8 +1,8 @@ export const chartFontFamily = '"Market Sans", Arial, sans-serif', backgroundColor = "var(--color-background-primary)", gridColor = "var(--color-data-viz-grid)", - labelsColor = "var(--color-data-viz-labels)", - legendColor = "var(--color-data-viz-legend)", + labelsColor = "var(--color-foreground-secondary)", + legendColor = "var(--color-foreground-primary)", legendInactiveColor = "var(--color-data-viz-legend-inactive)", legendHoverColor = "var(--color-data-viz-legend-hover)", tooltipBackgroundColor = "var(--color-background-primary)", @@ -79,6 +79,7 @@ export const chartFontFamily = '"Market Sans", Arial, sans-serif', const color = strokeColorMapping[i % strokeColorMapping.length]; series[i].lineColor = color; series[i].borderColor = color; + series[i].fillOpacity = 1; } }, setDonutColors = function (series: any) { @@ -110,4 +111,25 @@ export const chartFontFamily = '"Market Sans", Arial, sans-serif', }); return colors.map((color: any) => color.lineColor); + }, + setSeriesMarkerStyles = function (series: Highcharts.PlotAreaOptions[]) { + series.forEach((s, i) => { + s.zIndex = series.length - i; + s.marker = { + symbol: "circle", + lineWidth: 1, + fillColor: "black", + lineColor: "white", + states: { + hover: { + animation: { duration: 0 }, + radius: 4, + lineWidth: 2, + }, + normal: { + animation: false, + }, + }, + }; + }); }; diff --git a/src/components/ebay-area-chart/README.md b/src/components/ebay-area-chart/README.md index 779c8170d..396a18cd5 100644 --- a/src/components/ebay-area-chart/README.md +++ b/src/components/ebay-area-chart/README.md @@ -8,3 +8,9 @@ The area chart displays one to five series of data points as an interactive stacked area chart + +## Examples and Documentation + +- [Storybook](https://ebay.github.io/ebayui-core/?path=/docs/charts-ebay-area-chart) +- [Storybook Docs](https://ebay.github.io/ebayui-core/?path=/docs/charts-ebay-area-chart) +- [Code Examples](https://github.com/eBay/ebayui-core/tree/master/src/components/ebay-area-chart/examples) diff --git a/src/components/ebay-area-chart/area-chart.stories-ignore.ts b/src/components/ebay-area-chart/area-chart.stories-ignore.ts deleted file mode 100644 index 4ba576e1c..000000000 --- a/src/components/ebay-area-chart/area-chart.stories-ignore.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { tagToString } from "../../common/storybook/storybook-code-source"; -import { addRenderBodies } from "../../common/storybook/utils"; -import Readme from "./README.md"; -import Component from "./index.marko"; -import sampleSeriesData from "./examples/data.json"; -import { Story } from "@storybook/marko"; -import type { Input } from "./component"; - -const Template: Story = (args) => ({ - input: addRenderBodies(args), -}); - -export default { - title: "charts/ebay-area-chart", - excludeStories: ".*", - component: Component, - parameters: { - docs: { - description: { - component: Readme, - }, - }, - }, - argTypes: { - title: { - type: { name: "string", required: false }, - description: "A title displayed above the graph", - }, - description: { - type: { name: "string", required: true }, - description: "A description of what the chart is displaying", - }, - series: { - type: { name: "object", required: true }, - description: - "The series is an array of one to five arrays of point objects, each point contains an `x`, `y`, and `label`. `x` is an epoch/unix time code, `y` is a numeric value, `label` is what is displayed for the `y` value in the tool tip", - }, - xAxisLabelFormat: { - type: { name: "string", required: false }, - description: - "Used to modify the display of the x-axis labels. Accepts a string like `{value:%Y-%m-%d}`. Refer to https://api.highcharts.com/class-reference/Highcharts.Time#dateFormat for available format keys", - table: { - defaultValue: { - summary: "{value:%b %e}", - }, - }, - }, - xAxisPositioner: { - type: { name: "function", required: false }, - description: - "A custom function that returns an array of epoch/unix time values where x-axis labels will be displayed. You can access `this.dataMin` and `this.dataMax` from the function to help determine positions.", - }, - yAxisLabels: { - type: { name: "array", required: false }, - description: - "An array of labels to use on the y-axis. Use in conjunction with yAxisPositioner. Make sure the length of the yAxisLabels match the length of the positions array returned by the yAxisPositioner function", - }, - yAxisPositioner: { - type: { name: "function", required: false }, - description: - "A custom function that returns an array of numeric values where y-axis labels will be displayed. You can access `this.dataMin` and `this.dataMax` from the function to help determine positions", - }, - class: { - type: { name: "string", require: false }, - description: - "A class name that will be added to the main chart container", - }, - }, -}; - -export const Standard = Template.bind({}); -Standard.args = { - title: "Single series sample area chart", - description: "this chart displays 30 days of sample values", - series: sampleSeriesData.slice(0, 1) as any, -}; -Standard.parameters = { - docs: { - source: { - code: tagToString("bar-chart", Standard.args), - }, - }, -}; - -export const TwoSeries = Template.bind({}); -TwoSeries.args = { - title: "Two series sample area chart", - description: - "this chart displays 30 days of values for sample1 and sample2", - series: sampleSeriesData.slice(0, 2) as any, -}; -TwoSeries.parameters = { - docs: { - source: { - code: tagToString("bar-chart", TwoSeries.args), - }, - }, -}; - -export const ThreeSeries = Template.bind({}); -ThreeSeries.args = { - title: "Three series sample area chart", - description: - "this chart displays 30 days of values for sample1, sample2 and sample3", - series: sampleSeriesData.slice(0, 3) as any, -}; -ThreeSeries.parameters = { - docs: { - source: { - code: tagToString("bar-chart", ThreeSeries.args), - }, - }, -}; - -export const FourSeries = Template.bind({}); -FourSeries.args = { - title: "Four series sample area chart", - description: - "this chart displays 30 days of values for sample1, sample2, sample3, and sample4", - series: sampleSeriesData.slice(0, 4) as any, -}; -FourSeries.parameters = { - docs: { - source: { - code: tagToString("bar-chart", FourSeries.args), - }, - }, -}; - -export const FiveSeries = Template.bind({}); -FiveSeries.args = { - title: "Five series sample area chart", - description: - "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", - series: sampleSeriesData as any, -}; -FiveSeries.parameters = { - docs: { - source: { - code: tagToString("bar-chart", FiveSeries.args), - }, - }, -}; diff --git a/src/components/ebay-area-chart/area-chart.stories.ts b/src/components/ebay-area-chart/area-chart.stories.ts new file mode 100644 index 000000000..918c61e47 --- /dev/null +++ b/src/components/ebay-area-chart/area-chart.stories.ts @@ -0,0 +1,229 @@ +import { tagToString } from "../../common/storybook/storybook-code-source"; +import { addRenderBodies } from "../../common/storybook/utils"; +import Readme from "./README.md"; +import Component from "./index.marko"; +import sampleSeriesData from "./examples/data.json"; +import { Story } from "@storybook/marko"; +import type { Input } from "./component"; + +const Template: Story = (args) => ({ + input: addRenderBodies(args), +}); + +const seriesDataWithoutLabels = sampleSeriesData.map((series) => { + const { data, ...rest } = series; + return { + ...rest, + data: data.map((point) => { + const { label, ...rest } = point; + return rest; + }), + }; +}) + +export default { + title: "charts/ebay-area-chart", + component: Component, + parameters: { + docs: { + description: { + component: Readme, + }, + }, + }, + argTypes: { + title: { + type: { name: "string", required: false }, + description: "A title displayed above the graph", + }, + description: { + type: { name: "string", required: true }, + description: "A description of what the chart is displaying", + }, + series: { + type: { name: "object", required: true }, + description: + "The series is an array of one to five arrays of point objects, each point contains an `x`, `y`, and `label`. `x` is an epoch/unix time code, `y` is a numeric value, `label` is what is displayed for the `y` value in the tool tip", + }, + highchartOptions: { + type: { name: "object", required: false }, + description: + "A highcharts options object that will be merged with the default options", + }, + xLabelFormatter: { + type: { name: "function", required: false }, + description: + "A function that will be used to format the x-axis labels. Provides the value and a date formatter function. By default is formatted as `MMM dd`. Refer to https://api.highcharts.com/class-reference/Highcharts.Time#dateFormat for available format keys", + }, + yLabelFormatter: { + type: { name: "function", required: false }, + description: + "A function that will be used to format the y-axis labels. By default is formatted as USD currency.", + }, + tooltipValueFormatter: { + type: { name: "function", required: false }, + description: + "A function that will be used to format the tooltip series values and total. By default is formatted as USD currency.", + }, + areaType: { + type: { name: "string", required: false }, + description: + "The type of area chart to display. By default is `spline`. Options are `spline` and `area`", + }, + class: { + type: { name: "string", require: false }, + description: + "A class name that will be added to the main chart container", + }, + }, +}; + +export const Standard = Template.bind({}); +Standard.args = { + title: "Single series sample area chart", + description: "this chart displays 30 days of sample values", + series: sampleSeriesData.slice(0, 1) as Highcharts.SeriesAreaOptions[], +}; +Standard.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", Standard.args), + }, + }, +}; + +export const TwoSeries = Template.bind({}); +TwoSeries.args = { + title: "Two series sample area chart", + description: + "this chart displays 30 days of values for sample1 and sample2", + series: sampleSeriesData.slice(0, 2) as Highcharts.SeriesAreaOptions[], +}; +TwoSeries.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", TwoSeries.args), + }, + }, +}; + +export const ThreeSeries = Template.bind({}); +ThreeSeries.args = { + title: "Three series sample area chart", + description: + "this chart displays 30 days of values for sample1, sample2 and sample3", + series: sampleSeriesData.slice(0, 3) as Highcharts.SeriesAreaOptions[], +}; +ThreeSeries.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", ThreeSeries.args), + }, + }, +}; + +export const FourSeries = Template.bind({}); +FourSeries.args = { + title: "Four series sample area chart", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, and sample4", + series: sampleSeriesData.slice(0, 4) as Highcharts.SeriesAreaOptions[], +}; +FourSeries.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", FourSeries.args), + }, + }, +}; + +export const FiveSeries = Template.bind({}); +FiveSeries.args = { + title: "Five series sample area chart", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", + series: sampleSeriesData as Highcharts.SeriesAreaOptions[], +}; +FiveSeries.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", FiveSeries.args), + }, + }, +}; + +export const WithUnitlessYFormat = Template.bind({}); +WithUnitlessYFormat.args = { + title: "Custom y-axis label and tooltip value format", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", + series: seriesDataWithoutLabels as Highcharts.SeriesAreaOptions[], + yLabelFormatter: (value) => `${value}`, + tooltipValueFormatter: (value) => `${value}`, +}; +WithUnitlessYFormat.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", WithUnitlessYFormat.args), + }, + }, +}; + +export const WithXLabelFormat = Template.bind({}); +WithXLabelFormat.args = { + title: "Custom x-axis label format", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", + series: sampleSeriesData as Highcharts.SeriesAreaOptions[], + xLabelFormatter: (value, dateFormat) => { + if (typeof value !== "number") { + return value; + } + return dateFormat("%A", value); + }, + tooltipTitleFormatter(value, dateFormat) { + if (typeof value !== "number") { + return value; + } + return dateFormat("%A", value); + }, +}; + +WithXLabelFormat.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", WithXLabelFormat.args), + }, + }, +}; + +export const NonSpline = Template.bind({}); +NonSpline.args = { + title: "Area chart with non-spline type", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", + series: sampleSeriesData.slice(0, 1) as Highcharts.SeriesAreaOptions[], + areaType: "area", +}; + +NonSpline.parameters = { + docs: { + source: { + code: tagToString("ebay-area-chart", NonSpline.args), + }, + }, +}; + +export const CustomHighchartOptions = Template.bind({}); +CustomHighchartOptions.args = { + title: "Custom highchart options", + description: + "this chart displays 30 days of values for sample1, sample2, sample3, sample4, and sample5", + series: sampleSeriesData.slice(0, 1) as Highcharts.SeriesAreaOptions[], + highchartOptions: { + yAxis: { + ceiling: 45000, + tickAmount: 4, + }, + }, +}; \ No newline at end of file diff --git a/src/components/ebay-area-chart/component.ts b/src/components/ebay-area-chart/component.ts index 18217f339..4106caeda 100644 --- a/src/components/ebay-area-chart/component.ts +++ b/src/components/ebay-area-chart/component.ts @@ -11,41 +11,49 @@ import { tooltipShadows, setSeriesColors, colorMapping, + setSeriesMarkerStyles, } from "../../common/charts/shared"; -import { debounce } from "../../common/event-utils"; import { ebayLegend } from "../../common/charts/legend"; import type { WithNormalizedProps } from "../../global"; +import tooltipTemplate from "./tooltip.marko"; +import type { Input as TooltipInput } from "./tooltip.marko"; import type HighchartsTypes from "highcharts"; declare const Highcharts: typeof HighchartsTypes; +// Extend highcharts series data with a label property +declare module "highcharts" { + export interface Point { + label?: string; + } +} + interface AreaChartInput extends Omit, `on${string}`> { - title: Highcharts.TitleOptions["text"]; - /** - * input.xAxisLabelFormat allows overriding the default short month / day label. - * refer to https://api.highcharts.com/class-reference/Highcharts.Time#dateFormat to customize - **/ - "x-axis-label-format"?: Highcharts.XAxisLabelsOptions["format"]; - "x-axis-positioner"?: Highcharts.XAxisOptions["tickPositioner"]; - "y-axis-labels"?: Highcharts.YAxisLabelsOptions["format"]; - "y-axis-positioner"?: Highcharts.YAxisOptions["tickPositioner"]; + title?: Highcharts.TitleOptions["text"]; description?: Highcharts.SeriesAccessibilityOptionsObject["description"]; + series: Highcharts.SeriesAreaOptions | Highcharts.SeriesAreaOptions[]; + tooltipValueFormatter?: (value: string | number) => string; + tooltipTitleFormatter?: ( + value: string | number, + dateFormat: typeof Highcharts.dateFormat, + ) => string; + xLabelFormatter?: ( + value: string | number, + dateFormat: typeof Highcharts.dateFormat, + ) => string; + yLabelFormatter?: (value: string | number) => string; + areaType?: "areaspline" | "area"; + highchartOptions?: Highcharts.Options; "cdn-highcharts"?: string; "cdn-highcharts-accessibility"?: string; "cdn-highcharts-pattern-fill"?: string; version?: string; - series: Highcharts.SeriesAreaOptions | Highcharts.SeriesAreaOptions[]; - "on-load-error": (err: Error) => void; + "on-load-error"?: (err: Error) => void; } export interface Input extends WithNormalizedProps {} -const pointSize = 1.5; - class AreaChart extends Marko.Component { declare chartRef: Highcharts.Chart; - declare mouseOut: ReturnType; - declare mouseOver: ReturnType; - declare points: Highcharts.Point[]; onInput() { // if chartRef does not exist do not try to run setupCharts as it may be server side and highcharts only works on the client side @@ -68,45 +76,35 @@ class AreaChart extends Marko.Component { handleError(err: Error) { this.emit("load-error", err); } + handleSuccess() { this._initializeHighchartExtensions(); - this._setupEvents(); this._setupCharts(); } + getContainerId() { return `ebay-bar-chart-${this.id}`; } + + /** + * Initialize the highchart extensions + */ _initializeHighchartExtensions() { // add custom legend wrapper function - // eslint-disable-next-line no-undef,new-cap ebayLegend(Highcharts); } - _setupEvents() { - // bind functions to keep scope and setup debounced versions of function calls - this.debounce = debounce.bind(this); - this.handleMouseOver = this.handleMouseOver.bind(this); - this.handleMouseOut = this.handleMouseOut.bind(this); - this.mouseOut = this.debounce(() => this.handleMouseOut(), 80); // 80ms delay for debounce - this.mouseOver = this.debounce( - (e: Event) => this.handleMouseOver(e), - 85, - ); // 85ms delay for debounce so it doesn't colide with mouseOut debounce calls - } + + /** + * Set up the chart with the input data and configuration options. + */ _setupCharts() { // check if a single series was passed in for series and if so add it to a new array const series = Array.isArray(this.input.series) ? this.input.series : [this.input.series]; - // update the zIndex of each series object so they render in the correct order - // and configure the markers that are displayed on hover - series.forEach((s, i) => { - s.zIndex = series.length - i; - s.marker = { - symbol: "circle", - lineWidth: 3, - }; - }); + setSeriesMarkerStyles(series); + setSeriesColors(series); const config: Highcharts.Options = { @@ -114,7 +112,7 @@ class AreaChart extends Marko.Component { chart: this.getChartConfig(), colors: colorMapping, xAxis: this.getXAxisConfig(), - yAxis: this.getYAxisConfig(series), + yAxis: this.getYAxisConfig(), legend: this.getLegendConfig(), tooltip: this.getTooltipConfig(), plotOptions: this.getPlotOptions(), @@ -124,285 +122,265 @@ class AreaChart extends Marko.Component { }, }; // initialize and keep reference to chart - // eslint-disable-next-line no-undef,new-cap - this.chartRef = Highcharts.chart(this.getContainerId(), config); + this.chartRef = Highcharts.chart( + this.getContainerId(), + this._mergeConfigs(config, this.input.highchartOptions ?? {}), + ); + } + + /** + * Default format function for the tooltip titles + */ + _tooltipTitleFormatter( + value: number | string, + dateFormat: typeof Highcharts.dateFormat, + ) { + if (typeof value === "string") { + value = parseFloat(value); + } + return dateFormat("%b %e, %Y", value); } + + /** + * Default format function for the tooltip values + */ + _tooltipValueFormatter(value: number | string) { + if (typeof value === "string") { + value = parseFloat(value); + } + return Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + }).format(value); + } + + /** + * Default format function for the yAxis labels + */ + _yLabelFormatter(value: number | string) { + if (typeof value === "string") { + value = parseFloat(value); + } + return Intl.NumberFormat("en-US", { + notation: "compact", + style: "currency", + currency: "USD", + maximumSignificantDigits: 4, + }).format(value); + } + + /** + * Merge the source Highcharts config into the target Highcharts config + * + * Allows for custom overrides of ebay default Highcharts configuration settings + */ + _mergeConfigs( + source: { [key: string]: any }, + target: { [key: string]: any }, + ) { + for (const key in source) { + if (source[key] instanceof Object) + Object.assign( + source[key], + this._mergeConfigs(target[key], source[key]), + ); + } + Object.assign(target || {}, source); + return target; + } + + /** + * Get the title configuration for the chart + */ getTitleConfig(): Highcharts.TitleOptions { return { text: this.input.title, align: "left", useHTML: true, style: { - // styles are set in JS since they are rendered in the SVG fontSize: "18px", fontWeight: "700", }, }; } + + /** + * Get the chart configuration for the chart + */ getChartConfig(): Highcharts.ChartOptions { + const type = this.input.areaType ?? "areaspline"; return { - type: "area", + type, + animation: false, backgroundColor: backgroundColor, style: { - // styles are set in JS since they are rendered in the SVG fontFamily: chartFontFamily, }, }; } + + /** + * Get the xAxis configuration for the chart + */ getXAxisConfig(): Highcharts.XAxisOptions { + const xLabelFormatter = this.input.xLabelFormatter; return { // currently setup to support epoch time values for xAxisLabels. // It is possible to set custom non datetime xAxisLabels but will need changes to this component type: "datetime", labels: { - format: this.input.xAxisLabelFormat - ? this.input.xAxisLabelFormat - : "{value:%b %e}", + formatter: xLabelFormatter + ? function () { + return xLabelFormatter?.( + this.value, + Highcharts.dateFormat, + ); + } + : undefined, + format: "{value:%b %e}", align: "center", style: { - color: labelsColor, // setting label colors + color: labelsColor, }, }, tickWidth: 0, // hide the vertical tick on xAxis labels crosshair: { - zIndex: 3, // make sure the vertical crosshair line on hover shows up on top + color: "rgba(0, 0, 0, 0.2)", + zIndex: 3, }, - tickPositioner: this.input.xAxisPositioner, // optional input to allow configuring the position of xAxis tick marks }; } - getYAxisConfig( - series: Highcharts.SeriesAreaOptions[], - ): Highcharts.YAxisOptions { - const component = this; // component reference used in formatter functions that don't have the same scope - let yLabelsIterator = 0; // used when yAxisLabels array is provided in input - let maxYAxisValue = 0; // use to determine the highest yAxis value - series.forEach((s) => { - maxYAxisValue = s.data!.reduce( - (p: number, c: any) => (c > p ? c : p), - maxYAxisValue, - ) as number; - }); + + /** + * Get the yAxis configuration for the chart + */ + getYAxisConfig(): Highcharts.YAxisOptions { + // Formatter function for the yAxis labels + const yLabelFormatter = + this.input.yLabelFormatter ?? this._yLabelFormatter; + return { - gridLineColor: gridColor, // sets the horizontal grid line colors + gridLineColor: gridColor, opposite: true, // moves yAxis labels to the right side of the chart reversedStacks: false, // makes so series one starts at the bottom of the yAxis, by default this is true labels: { - // if yAxisLabels are not passed in display the standard label - format: this.input.yAxisLabels ?? "${text}", - // if yAxisLabels array is passed in this formatter function is needed to - // return the proper label for each yAxis tick mark - formatter: this.input.yAxisLabels - ? function () { - if (this.isFirst) { - yLabelsIterator = -1; - } - yLabelsIterator = yLabelsIterator + 1; - return ( - component.input.yAxisLabels?.[yLabelsIterator] ?? - "" - ); - } - : undefined, + formatter: function () { + return yLabelFormatter(this.value); + }, style: { - color: labelsColor, // setting label colors + color: labelsColor, }, }, - max: maxYAxisValue, title: { - enabled: false, // hide the axis label next to the axis + enabled: false, } as Highcharts.YAxisTitleOptions, - offset: 0, // set to zero for no offset refer to https://api.highcharts.com/highcharts/yAxis.offset - // passed in function for yAxisPositioner refer to https://api.highcharts.com/highcharts/yAxis.tickPositioner for use - tickPositioner: this.input.yAxisPositioner, + offset: 0, }; } - getLegendConfig() { + + /** + * Get the legend configuration for the chart + */ + getLegendConfig(): Highcharts.LegendOptions { return { - // if only a single series is provided do not display the legend + // If only a single series is provided do not display the legend enabled: Array.isArray(this.input.series) && this.input.series.length > 1, - symbolRadius: 2, // corner radius on legend identifiers svg element - symbolWidth: 12, // setting the width of the legend identifiers svg element - symbolHeight: 12, // setting the height of the legend identifiers svg element + symbolRadius: 2, + symbolWidth: 12, + symbolHeight: 12, itemStyle: { - color: legendColor, // set the color of the text in the legend + color: legendColor, + fontWeight: "normal", }, + align: "left", itemHiddenStyle: { - color: legendInactiveColor, // set legend text color when legend item has been clicked and hidden + color: legendInactiveColor, }, itemHoverStyle: { - color: legendHoverColor, // set legend text color on hover of legend element + color: legendHoverColor, }, }; } - getTooltipConfig() { - const component = this; // component reference used in formatter functions that don't have the same scope + /** + * Get the tooltip configuration for the chart + */ + getTooltipConfig(): Highcharts.TooltipOptions { + const tooltipValueFormatter = + this.input.tooltipValueFormatter ?? this._tooltipValueFormatter; + + const tooltipTitleFormatter = + this.input.tooltipTitleFormatter ?? this._tooltipTitleFormatter; + return { - formatter: function (this: any) { - // refer to https://api.highcharts.com/class-reference/Highcharts.Time#dateFormat for dateFormat variables - // s is used to compile html string of formatted tooltip data - - // TODO need to change this to use a component - // eslint-disable-next-line no-undef,new-cap - let s = `${Highcharts.dateFormat( - "%b %e, %Y", - this.x, - false, - )}
`; // sets the displayed date at the top of the tooltip - if (component.chartRef.series.length > 1) { - // setup html for multi series tooltip - component.chartRef.series.forEach((serie) => { - // cycle through each series - serie.data.forEach((d) => { - // cycle through each series data array to match x value with active hovered xAxis position - if (d.x === this.x) { - // when the x value matches the hovered xAxis position - s += `
${serie.name}${d.name}
`; - } - }); - }); - } else { - // setup html for single series tooltip - // cycle through points of the single series and find the one that matches the active xAxis - component.points.forEach((d) => { - if (d.x === this.x) { - // when the x value matches the hovered xAxis position - s += `
${d.name}
`; - } - }); - } - return s; - } as any, - useHTML: true, // allows defining html to format tooltip content - backgroundColor: tooltipBackgroundColor, // sets tooltip background color - borderWidth: 0, // hide the default border stroke - borderRadius: 10, // set the border radius of the tooltip - outside: true, // used to render the tooltip outside of the main SVG element - shadow: false, // hide the default shadow as it conflicts with designs - shared: true, // shared means that if there are multipe series passed in there will be a single tooltip element per xAxis point + formatter: function (this) { + const date = tooltipTitleFormatter( + this.x ?? 0, + Highcharts.dateFormat, + ); + + // Display formatted total, only if there are more than one points + const total = + this.points && + this.points.length > 1 && + this.points.reduce( + (acc, curr) => acc + (curr.y ?? 0) * 100, + 0, + ) / 100; + + return tooltipTemplate.renderToString({ + date, + total: total || 0, + points: this.points, + valueFormatter: tooltipValueFormatter, + } as TooltipInput); + }, + useHTML: true, + backgroundColor: tooltipBackgroundColor, + borderWidth: 0, + borderRadius: 10, + outside: true, + shadow: false, + shared: true, style: { - filter: tooltipShadows, // sets tooltip shadows + filter: tooltipShadows, fontSize: "12px", }, }; } + /** + * Get the plot options configuration for the chart + */ getPlotOptions(): Highcharts.PlotOptions { + const type = this.input.areaType ?? "areaspline"; return { series: { accessibility: { - description: this.input.description, // set the description that was passed in + description: this.input.description, }, - // config stacking to normal to make sure series stack without overlapping - // refer to https://api.highcharts.com/highcharts/plotOptions.area.stacking stacking: "normal", - point: { - // assign mouse events to point hovers - events: { - mouseOver: this.mouseOver, - mouseOut: this.mouseOut, + states: { + hover: { + halo: { size: 0 }, }, }, + marker: { + enabled: false, + animation: { duration: 0 }, + }, }, - area: { - className: "ebay-area-chart", // add class to area chart to allow targetted styles from style.less file - lineWidth: 1, // set the border line width for each series item. - // states: { // set if we do not want series to fade out on legend hover uncomment this block - // inactive: { - // opacity: 1, - // } - // } + [type]: { + className: "ebay-area-chart", + lineWidth: 1, }, }; } - // debounce used to help improve performance on mouse interactions - debounce void>(func: T, timeout = 100) { - let timer: NodeJS.Timeout; - return (...args: Parameters) => { - clearTimeout(timer); - timer = setTimeout(() => { - func.apply(this, args); - }, timeout); - }; - } - handleMouseOut() { - // this function is debounced to improve performance - this.chartRef.series.forEach((s) => { - s.data.forEach((d) => { - // check if hover is on the xAxis (onTick) for each item, - // and if they have a className remove and disable the marker - if (d.getClassName() !== null) { - d.update( - { - className: undefined, // nullify className if not active - marker: { - enabled: false, // disable marker if not active - }, - }, - false, // disable auto redraw - false, // disable auto animation - ); - } else if (d.getClassName() === null) { - d.update( - { - className: "ebay-area-chart__marker--visible", // set classname - marker: { - enabled: true, // set marker enabled - radius: pointSize, // set the size of marker - lineColor: backgroundColor, // set border color of hover markers - lineWidth: 4, // set border width of hover markers - fillColor: "#000000", // set fill color of markers - }, - }, - false, // disable auto redraw - false, // disable auto animation - ); - } - }); - }); - this.chartRef.redraw(); // trigger redraw after all points have been updated - } - handleMouseOver(e: any) { - // this function is debounced to improve performance - this.chartRef.series.forEach((s) => { - s.data.forEach((d) => { - if (d.x === e.target.x) { - // if active xAxis hover position matches the data point x update the marker to display - d.update( - { - className: "ebay-area-chart__marker--visible", // sets the classname - marker: { - enabled: true, // set marker enabled - radius: pointSize, // set the size of marker - lineColor: backgroundColor, // set border color of hover markers - lineWidth: 4, // set border width of hover markers - fillColor: "#000000", // set fill color of markers - }, - }, - false, // disable auto redraw - false, // disable auto animation - ); - } else if (d.getClassName() !== null) { - d.update( - { - className: undefined, // nullify className if not active - marker: { - enabled: false, // disable marker - }, - }, - false, // disable auto redraw - false, // disable auto animation - ); - } - }); - }); - this.chartRef.redraw(); // trigger redraw after all points have been updated - } onDestroy() { - this.chartRef.destroy(); + this.chartRef?.destroy(); } } diff --git a/src/components/ebay-area-chart/examples/data.json b/src/components/ebay-area-chart/examples/data.json index bb2307cba..392e11c19 100644 --- a/src/components/ebay-area-chart/examples/data.json +++ b/src/components/ebay-area-chart/examples/data.json @@ -9,147 +9,147 @@ { "x": 1643760000000, "y": 3529.13, - "label": "$3529.13" + "label": "$3,529.13" }, { "x": 1643846400000, "y": 7290.99, - "label": "$7290.99" + "label": "$7,290.99" }, { "x": 1643932800000, "y": 7598.54, - "label": "$7598.54" + "label": "$7,598.54" }, { "x": 1644019200000, "y": 6014.85, - "label": "$6014.85" + "label": "$6,014.85" }, { "x": 1644105600000, "y": 7197.59, - "label": "$7197.59" + "label": "$7,197.59" }, { "x": 1644192000000, "y": 7054.97, - "label": "$7054.97" + "label": "$7,054.97" }, { "x": 1644278400000, "y": 8813.92, - "label": "$8813.92" + "label": "$8,813.92" }, { "x": 1644364800000, "y": 11303.55, - "label": "$11303.55" + "label": "$11,303.55" }, { "x": 1644451200000, "y": 11425.54, - "label": "$11425.54" + "label": "$11,425.54" }, { "x": 1644537600000, "y": 14767.84, - "label": "$14767.84" + "label": "$14,767.84" }, { "x": 1644624000000, "y": 14595.77, - "label": "$14595.77" + "label": "$14,595.77" }, { "x": 1644710400000, "y": 14896.37, - "label": "$14896.37" + "label": "$14,896.37" }, { "x": 1644796800000, "y": 18686.42, - "label": "$18686.42" + "label": "$18,686.42" }, { "x": 1644883200000, "y": 19397.06, - "label": "$19397.06" + "label": "$19,397.06" }, { "x": 1644969600000, "y": 17377.38, - "label": "$17377.38" + "label": "$17,377.38" }, { "x": 1645056000000, "y": 19762.2, - "label": "$19762.2" + "label": "$19,762.20" }, { "x": 1645142400000, "y": 22693.32, - "label": "$22693.32" + "label": "$22,693.32" }, { "x": 1645228800000, "y": 25474.69, - "label": "$25474.69" + "label": "$25,474.69" }, { "x": 1645315200000, "y": 25716.96, - "label": "$25716.96" + "label": "$25,716.96" }, { "x": 1645401600000, "y": 28229.64, - "label": "$28229.64" + "label": "$28,229.64" }, { "x": 1645488000000, "y": 30802.49, - "label": "$30802.49" + "label": "$30,802.49" }, { "x": 1645574400000, "y": 30784.09, - "label": "$30784.09" + "label": "$30,784.09" }, { "x": 1645660800000, "y": 31268.12, - "label": "$31268.12" + "label": "$31,268.12" }, { "x": 1645747200000, "y": 33762.26, - "label": "$33762.26" + "label": "$33,762.26" }, { "x": 1645833600000, "y": 35829.81, - "label": "$35829.81" + "label": "$35,829.81" }, { "x": 1645920000000, "y": 35459.05, - "label": "$35459.05" + "label": "$35,459.05" }, { "x": 1646006400000, "y": 38357.93, - "label": "$38357.93" + "label": "$38,357.93" }, { "x": 1646092800000, "y": 41968.57, - "label": "$41968.57" + "label": "$41,968.57" }, { "x": 1646179200000, "y": 43848.26, - "label": "$43848.26" + "label": "$43,848.26" } ], "name": "Value 1" @@ -159,152 +159,152 @@ { "x": 1643673600000, "y": 2191.95, - "label": "$2191.95" + "label": "$2,191.95" }, { "x": 1643760000000, "y": 2401.84, - "label": "$2401.84" + "label": "$2,401.84" }, { "x": 1643846400000, "y": 2212.28, - "label": "$2212.28" + "label": "$2,212.28" }, { "x": 1643932800000, "y": 2608.39, - "label": "$2608.39" + "label": "$2,608.39" }, { "x": 1644019200000, "y": 2000.86, - "label": "$2000.86" + "label": "$2,000.86" }, { "x": 1644105600000, "y": 3931.71, - "label": "$3931.71" + "label": "$3,931.71" }, { "x": 1644192000000, "y": 4094.93, - "label": "$4094.93" + "label": "$4,094.93" }, { "x": 1644278400000, "y": 7666.27, - "label": "$7666.27" + "label": "$7,666.27" }, { "x": 1644364800000, "y": 6413, - "label": "$6413" + "label": "$6,413" }, { "x": 1644451200000, "y": 9924.87, - "label": "$9924.87" + "label": "$9,924.87" }, { "x": 1644537600000, "y": 11485.98, - "label": "$11485.98" + "label": "$11,485.98" }, { "x": 1644624000000, "y": 13416.08, - "label": "$13416.08" + "label": "$13,416.08" }, { "x": 1644710400000, "y": 16068.24, - "label": "$16068.24" + "label": "$16,068.24" }, { "x": 1644796800000, "y": 15855.76, - "label": "$15855.76" + "label": "$15,855.76" }, { "x": 1644883200000, "y": 19313.94, - "label": "$19313.94" + "label": "$19,313.94" }, { "x": 1644969600000, "y": 20328.31, - "label": "$20328.31" + "label": "$20,328.31" }, { "x": 1645056000000, "y": 21482.19, - "label": "$21482.19" + "label": "$21,482.19" }, { "x": 1645142400000, "y": 24732.07, - "label": "$24732.07" + "label": "$24,732.07" }, { "x": 1645228800000, "y": 26000.25, - "label": "$26000.25" + "label": "$26,000.25" }, { "x": 1645315200000, "y": 28788.89, - "label": "$28788.89" + "label": "$28,788.89" }, { "x": 1645401600000, "y": 30438.55, - "label": "$30438.55" + "label": "$30,438.55" }, { "x": 1645488000000, "y": 33025.77, - "label": "$33025.77" + "label": "$33,025.77" }, { "x": 1645574400000, "y": 33232.63, - "label": "$33232.63" + "label": "$33,232.63" }, { "x": 1645660800000, "y": 35412.85, - "label": "$35412.85" + "label": "$35,412.85" }, { "x": 1645747200000, "y": 35418.1, - "label": "$35418.1" + "label": "$35,418.10" }, { "x": 1645833600000, "y": 34787.87, - "label": "$34787.87" + "label": "$34,787.87" }, { "x": 1645920000000, "y": 35379.97, - "label": "$35379.97" + "label": "$35,379.97" }, { "x": 1646006400000, "y": 35058.06, - "label": "$35058.06" + "label": "$35,058.06" }, { "x": 1646092800000, "y": 36941.95, - "label": "$36941.95" + "label": "$36,941.95" }, { "x": 1646179200000, "y": 35433.32, - "label": "$35433.32" + "label": "$35,433.32" } ], "name": "Value 2" @@ -319,147 +319,147 @@ { "x": 1643760000000, "y": 1972.03, - "label": "$1972.03" + "label": "$1,972.03" }, { "x": 1643846400000, "y": 2605.21, - "label": "$2605.21" + "label": "$2,605.21" }, { "x": 1643932800000, "y": 2688.03, - "label": "$2688.03" + "label": "$2,688.03" }, { "x": 1644019200000, "y": 3693.2, - "label": "$3693.2" + "label": "$3,693.02" }, { "x": 1644105600000, "y": 6620.37, - "label": "$6620.37" + "label": "$6,620.37" }, { "x": 1644192000000, "y": 9938.94, - "label": "$9938.94" + "label": "$9,938.94" }, { "x": 1644278400000, "y": 9041.09, - "label": "$9041.09" + "label": "$9,041.09" }, { "x": 1644364800000, "y": 8988.36, - "label": "$8988.36" + "label": "$8,988.36" }, { "x": 1644451200000, "y": 10127.2, - "label": "$10127.2" + "label": "$10,127.20" }, { "x": 1644537600000, "y": 13612.53, - "label": "$13612.53" + "label": "$13,612.53" }, { "x": 1644624000000, "y": 14706.86, - "label": "$14706.86" + "label": "$14,706.86" }, { "x": 1644710400000, "y": 13564.87, - "label": "$13564.87" + "label": "$13,564.87" }, { "x": 1644796800000, "y": 12415.62, - "label": "$12415.62" + "label": "$12,415.62" }, { "x": 1644883200000, "y": 16964.94, - "label": "$16964.94" + "label": "$16,964.94" }, { "x": 1644969600000, "y": 18740.34, - "label": "$18740.34" + "label": "$18,740.34" }, { "x": 1645056000000, "y": 18716.07, - "label": "$18716.07" + "label": "$18,716.07" }, { "x": 1645142400000, "y": 21154.56, - "label": "$21154.56" + "label": "$21,154.56" }, { "x": 1645228800000, "y": 21750.07, - "label": "$21750.07" + "label": "$21,750.07" }, { "x": 1645315200000, "y": 22922.59, - "label": "$22922.59" + "label": "$22,922.59" }, { "x": 1645401600000, "y": 26768.79, - "label": "$26768.79" + "label": "$26,768.79" }, { "x": 1645488000000, "y": 26399.77, - "label": "$26399.77" + "label": "$26,399.77" }, { "x": 1645574400000, "y": 29910.73, - "label": "$29910.73" + "label": "$29,910.73" }, { "x": 1645660800000, "y": 32231.86, - "label": "$32231.86" + "label": "$32,231.86" }, { "x": 1645747200000, "y": 34040.09, - "label": "$34040.09" + "label": "$34,040.09" }, { "x": 1645833600000, "y": 31844.54, - "label": "$31844.54" + "label": "$31,844.54" }, { "x": 1645920000000, "y": 34033.48, - "label": "$34033.48" + "label": "$34,033.48" }, { "x": 1646006400000, "y": 34140.3, - "label": "$34140.3" + "label": "$34,140.30" }, { "x": 1646092800000, "y": 33203.36, - "label": "$33203.36" + "label": "$33,203.36" }, { "x": 1646179200000, "y": 35918.18, - "label": "$35918.18" + "label": "$35,918.18" } ], "name": "Value 3" @@ -469,152 +469,152 @@ { "x": 1643673600000, "y": 3714.81, - "label": "$3714.81" + "label": "$3,714.81" }, { "x": 1643760000000, "y": 3515.59, - "label": "$3515.59" + "label": "$3,515.59" }, { "x": 1643846400000, "y": 5668.89, - "label": "$5668.89" + "label": "$5,668.89" }, { "x": 1643932800000, "y": 7707.67, - "label": "$7707.67" + "label": "$7,707.67" }, { "x": 1644019200000, "y": 7065.82, - "label": "$7065.82" + "label": "$7,065.82" }, { "x": 1644105600000, "y": 10961.2, - "label": "$10961.2" + "label": "$10,961.20" }, { "x": 1644192000000, "y": 10810.1, - "label": "$10810.1" + "label": "$10,810.10" }, { "x": 1644278400000, "y": 9299.88, - "label": "$9299.88" + "label": "$9,299.88" }, { "x": 1644364800000, "y": 12175.1, - "label": "$12175.1" + "label": "$12,175.10" }, { "x": 1644451200000, "y": 15678.8, - "label": "$15678.8" + "label": "$15,678.80" }, { "x": 1644537600000, "y": 13403.74, - "label": "$13403.74" + "label": "$13,403.74" }, { "x": 1644624000000, "y": 14934.49, - "label": "$14934.49" + "label": "$14,934.49" }, { "x": 1644710400000, "y": 18195.71, - "label": "$18195.71" + "label": "$18,195.71" }, { "x": 1644796800000, "y": 21630.27, - "label": "$21630.27" + "label": "$21,630.27" }, { "x": 1644883200000, "y": 19205.48, - "label": "$19205.48" + "label": "$19,205.48" }, { "x": 1644969600000, "y": 18236.22, - "label": "$18236.22" + "label": "$18,236.22" }, { "x": 1645056000000, "y": 20057.18, - "label": "$20057.18" + "label": "$20,057.18" }, { "x": 1645142400000, "y": 21599.02, - "label": "$21599.02" + "label": "$21,599.02" }, { "x": 1645228800000, "y": 22092.15, - "label": "$22092.15" + "label": "$22,092.15" }, { "x": 1645315200000, "y": 22049.95, - "label": "$22049.95" + "label": "$22,049.95" }, { "x": 1645401600000, "y": 25488.9, - "label": "$25488.9" + "label": "$25,488.90" }, { "x": 1645488000000, "y": 23560.32, - "label": "$23560.32" + "label": "$23,560.32" }, { "x": 1645574400000, "y": 23287.49, - "label": "$23287.49" + "label": "$23,287.49" }, { "x": 1645660800000, "y": 23291.42, - "label": "$23291.42" + "label": "$23,291.42" }, { "x": 1645747200000, "y": 22578.91, - "label": "$22578.91" + "label": "$22,578.91" }, { "x": 1645833600000, "y": 23359.51, - "label": "$23359.51" + "label": "$23,359.51" }, { "x": 1645920000000, "y": 26612.42, - "label": "$26612.42" + "label": "$26,612.42" }, { "x": 1646006400000, "y": 27406.05, - "label": "$27406.05" + "label": "$27,406.05" }, { "x": 1646092800000, "y": 26739.38, - "label": "$26739.38" + "label": "$26,739.38" }, { "x": 1646179200000, "y": 31025.67, - "label": "$31025.67" + "label": "$31,025.67" } ], "name": "Value 4" @@ -624,152 +624,152 @@ { "x": 1643673600000, "y": 2634.55, - "label": "$2634.55" + "label": "$2,634.55" }, { "x": 1643760000000, "y": 5550.37, - "label": "$5550.37" + "label": "$5,550.37" }, { "x": 1643846400000, "y": 8362.35, - "label": "$8362.35" + "label": "$8,362.35" }, { "x": 1643932800000, "y": 8892.21, - "label": "$8892.21" + "label": "$8,892.21" }, { "x": 1644019200000, "y": 8832.23, - "label": "$8832.23" + "label": "$8,832.23" }, { "x": 1644105600000, "y": 11513.81, - "label": "$11513.81" + "label": "$11,513.81" }, { "x": 1644192000000, "y": 10620.6, - "label": "$10620.6" + "label": "$10,620.60" }, { "x": 1644278400000, "y": 10006.53, - "label": "$10006.53" + "label": "$10,006.53" }, { "x": 1644364800000, "y": 11226.84, - "label": "$11226.84" + "label": "$11,226.84" }, { "x": 1644451200000, "y": 12663.56, - "label": "$12663.56" + "label": "$12,663.56" }, { "x": 1644537600000, "y": 13521.25, - "label": "$13521.25" + "label": "$13,521.25" }, { "x": 1644624000000, "y": 17157.52, - "label": "$17157.52" + "label": "$17,157.52" }, { "x": 1644710400000, "y": 17379.93, - "label": "$17379.93" + "label": "$17,379.93" }, { "x": 1644796800000, "y": 18145.16, - "label": "$18145.16" + "label": "$18,145.16" }, { "x": 1644883200000, "y": 18417.28, - "label": "$18417.28" + "label": "$18,417.28" }, { "x": 1644969600000, "y": 20505.13, - "label": "$20505.13" + "label": "$20,505.13" }, { "x": 1645056000000, "y": 23222.51, - "label": "$23222.51" + "label": "$23,222.51" }, { "x": 1645142400000, "y": 22161.92, - "label": "$22161.92" + "label": "$22,161.92" }, { "x": 1645228800000, "y": 24232.12, - "label": "$24232.12" + "label": "$24,232.12" }, { "x": 1645315200000, "y": 25948.31, - "label": "$25948.31" + "label": "$25,948.31" }, { "x": 1645401600000, "y": 26334.97, - "label": "$26334.97" + "label": "$26,334.97" }, { "x": 1645488000000, "y": 27880.25, - "label": "$27880.25" + "label": "$27,880.25" }, { "x": 1645574400000, "y": 26813.33, - "label": "$26813.33" + "label": "$26,813.33" }, { "x": 1645660800000, "y": 29132.31, - "label": "$29132.31" + "label": "$29,132.31" }, { "x": 1645747200000, "y": 28896.25, - "label": "$28896.25" + "label": "$28,896.25" }, { "x": 1645833600000, "y": 30834.8, - "label": "$30834.8" + "label": "$30,834.80" }, { "x": 1645920000000, "y": 29546.97, - "label": "$29546.97" + "label": "$29,546.97" }, { "x": 1646006400000, "y": 31693.82, - "label": "$31693.82" + "label": "$31,693.82" }, { "x": 1646092800000, "y": 31394.2, - "label": "$31394.2" + "label": "$31,394.20" }, { "x": 1646179200000, "y": 34090.57, - "label": "$34090.57" + "label": "$34,090.57" } ], "name": "Value 5" diff --git a/src/components/ebay-area-chart/examples/default.marko b/src/components/ebay-area-chart/examples/default.marko new file mode 100644 index 000000000..15bded884 --- /dev/null +++ b/src/components/ebay-area-chart/examples/default.marko @@ -0,0 +1,3 @@ +import data from "./data.json"; + + diff --git a/src/components/ebay-area-chart/index.marko b/src/components/ebay-area-chart/index.marko index 71eafe3bd..5a6add459 100644 --- a/src/components/ebay-area-chart/index.marko +++ b/src/components/ebay-area-chart/index.marko @@ -1,23 +1,16 @@ -import { processHtmlAttributes } from "../../common/html-attributes" - +import { processHtmlAttributes } from "../../common/html-attributes"; $ const { data, class: inputClass, series, title, description, - xAxisLabelFormat, - yAxisLabels, - xAxisPositioner, - yAxisPositioner, + xLabelFormatter, + yLabelFormatter, + highchartOptions, ...restInput -} = input +} = input; -
- +
+
diff --git a/src/components/ebay-area-chart/style.less b/src/components/ebay-area-chart/style.less deleted file mode 100644 index e237ac012..000000000 --- a/src/components/ebay-area-chart/style.less +++ /dev/null @@ -1,23 +0,0 @@ -.ebay-area-chart { - .highcharts-point { - opacity: 0; // overriding the default highcharts opacity to 0 - stroke-width: 2px; // and adjusting the stroke width - } - - .ebay-area-chart__marker--visible { - opacity: 1; - } - - .highcharts-legend-item { - .highcharts-point { - opacity: 1; // displays the legend marker symbols which are hidden by the highcharts-point opacity - stroke-width: 1; // sets the stroke width on the plot point markers - } - } - - @media (prefers-color-scheme: dark) { - .highcharts-halo { - fill-opacity: 0.8; // this inverses the default 0.2 fill opacity in from light mode - } - } -} diff --git a/src/components/ebay-area-chart/tests/__snapshots__/test.server.js.snap b/src/components/ebay-area-chart/tests/__snapshots__/test.server.js.snap new file mode 100644 index 000000000..0f6bbce0e --- /dev/null +++ b/src/components/ebay-area-chart/tests/__snapshots__/test.server.js.snap @@ -0,0 +1,73 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`section-title > renders defaults 1`] = ` +" +  +  + 
 +" +`; + +exports[`section-title > renders with five series 1`] = ` +" +  +  + 
 +" +`; + +exports[`section-title > renders with non-spline param 1`] = ` +" +  +  +  +" +`; + +exports[`section-title > renders with two series 1`] = ` +" +  +  +  +" +`; + +exports[`section-title > renders with x-axis label format 1`] = ` +" +  +  +  +" +`; diff --git a/src/components/ebay-area-chart/tests/test.server.js b/src/components/ebay-area-chart/tests/test.server.js new file mode 100644 index 000000000..ab4bfe7fe --- /dev/null +++ b/src/components/ebay-area-chart/tests/test.server.js @@ -0,0 +1,31 @@ +import { describe, it } from "vitest"; + +import { composeStories } from "@storybook/marko"; +import { snapshotHTML } from "../../../common/test-utils/snapshots"; +import * as stories from "../area-chart.stories"; + +const { Standard, TwoSeries, FiveSeries, WithXLabelFormat, NonSpline } = + composeStories(stories); +const htmlSnap = snapshotHTML(__dirname); + +describe("section-title", () => { + it("renders defaults", async () => { + await htmlSnap(Standard); + }); + + it("renders with two series", async () => { + await htmlSnap(TwoSeries); + }); + + it("renders with five series", async () => { + await htmlSnap(FiveSeries); + }); + + it("renders with x-axis label format", async () => { + await htmlSnap(WithXLabelFormat); + }); + + it("renders with non-spline param", async () => { + await htmlSnap(NonSpline); + }); +}); diff --git a/src/components/ebay-area-chart/tooltip.marko b/src/components/ebay-area-chart/tooltip.marko new file mode 100644 index 000000000..a60fbd27c --- /dev/null +++ b/src/components/ebay-area-chart/tooltip.marko @@ -0,0 +1,35 @@ +import type HighchartsTypes from "highcharts"; +export interface Input { + date: string; + points: HighchartsTypes.TooltipFormatterContextObject[] | undefined; + total: number; + valueFormatter: (value: number | string) => string; +} + +${input.date} + +
+ ${points.point.series.name} + + ${points.point.label} + + + ${input.valueFormatter(points.point.y)} + +
+ + +
+ Total + ${input.valueFormatter(input.total)} +
+ + +style.less { + .ebay-area-chart__tooltip-value { + display: flex; + justify-content: space-between; + gap: var(--spacing-100); + width: 100%; + } +} diff --git a/src/components/ebay-breadcrumbs/examples/page-custom-attrs.marko b/src/components/ebay-breadcrumbs/examples/page-custom-attrs.marko index a0f9d0c2e..10b174b10 100644 --- a/src/components/ebay-breadcrumbs/examples/page-custom-attrs.marko +++ b/src/components/ebay-breadcrumbs/examples/page-custom-attrs.marko @@ -1,6 +1,6 @@ - <@item href="http://www.ebay.com/" navsrc="{}" _sp="p2345.m909.l34">eBay - <@item href="https://www.ebay.com/rpp/cell-phone-pda" navsrc="{}" _sp="p2345.m909.l34">Cell Phones, Smart Watches & Accessories - <@item href="https://www.ebay.com/b/Smart-Watch-Accessories/182064/bn_16565905" navsrc="{}" _sp="p2345.m909.l34">Smart Watch Accessories + <@item href="http://www.ebay.com/">eBay + <@item href="https://www.ebay.com/rpp/cell-phone-pda">Cell Phones, Smart Watches & Accessories + <@item href="https://www.ebay.com/b/Smart-Watch-Accessories/182064/bn_16565905">Smart Watch Accessories <@item>Smart Watch Bands diff --git a/src/components/ebay-combobox/component.ts b/src/components/ebay-combobox/component.ts index dbf4caf76..27776e721 100644 --- a/src/components/ebay-combobox/component.ts +++ b/src/components/ebay-combobox/component.ts @@ -4,7 +4,7 @@ import Expander from "makeup-expander"; import { scroll } from "../../common/element-scroll"; import * as eventUtils from "../../common/event-utils"; import safeRegex from "../../common/build-safe-regex"; -import type { AttrClass } from "marko/tags-html"; +import type { AttrClass, AttrString } from "marko/tags-html"; import type { WithNormalizedProps } from "../../global"; export interface ComboboxOption { @@ -26,7 +26,7 @@ interface ComboboxInput extends Omit, `on${string}`> { fluid?: boolean; autocomplete?: "list" | "none"; "list-selection"?: "manual" | "automatic"; - "floating-label"?: boolean; + "floating-label"?: AttrString; "view-all-options"?: boolean; button?: Marko.Input<"button"> & Marko.AttrTag<{ diff --git a/src/components/ebay-combobox/examples/floating-label.marko b/src/components/ebay-combobox/examples/floating-label.marko index aaa6059c2..e61268f7a 100644 --- a/src/components/ebay-combobox/examples/floating-label.marko +++ b/src/components/ebay-combobox/examples/floating-label.marko @@ -1,4 +1,4 @@ - + <@option text="August Campaign"/> <@option text="4th of July Sale (paused)"/> <@option text="Basic Offer"/> diff --git a/src/components/ebay-progress-stepper/index.marko b/src/components/ebay-progress-stepper/index.marko index 8b870393c..e8591feb6 100644 --- a/src/components/ebay-progress-stepper/index.marko +++ b/src/components/ebay-progress-stepper/index.marko @@ -5,9 +5,9 @@ import type { AttrString } from 'marko/tags-html'; export interface Step extends Omit, `on${string}` | "title"> { current?: boolean; a11yText?: string; - title?: Omit, `on${string}`> & { + title?: Marko.AttrTag, `on${string}`> & { as?: keyof Marko.NativeTags; - } + }> } static interface ProgressStepperInput extends Omit, `on${string}`> { diff --git a/src/components/ebay-segmented-buttons/index.marko b/src/components/ebay-segmented-buttons/index.marko index bf41bf376..b0cf570e0 100644 --- a/src/components/ebay-segmented-buttons/index.marko +++ b/src/components/ebay-segmented-buttons/index.marko @@ -11,7 +11,7 @@ export interface SegmentedButtonsEvent { export interface SegmentedButton extends Omit, `on${string}`> { selected?: boolean; - icon?: Marko.Renderable; + icon?: Marko.AttrTag<{ renderBody: Marko.Body }>; } static interface SegmentedButtonsInput extends Omit, `on${string}`> { diff --git a/src/components/ebay-table/component.ts b/src/components/ebay-table/component.ts index 7b456dd81..e6028550f 100644 --- a/src/components/ebay-table/component.ts +++ b/src/components/ebay-table/component.ts @@ -4,25 +4,26 @@ import { CheckboxEvent } from "../ebay-checkbox/component-browser"; export type TableSort = "asc" | "desc" | "none"; export interface TableHeader extends Omit, `on${string}`> { - columnType?: "normal" | "numeric" | "row-header" | "layout" | "icon-action"; + "column-type"?: "normal" | "numeric" | "layout" | "icon-action"; + "row-header"?: boolean; name?: string; sort?: TableSort | boolean; href?: AttrString; renderBody: Marko.Body; } + export interface TableCell - extends Omit & Marko.Input<"th">, `on${string}`> { - renderBody: Marko.Body; -} + extends Omit & Marko.Input<"th">, `on${string}`> {} + export interface TableRow extends Omit, `on${string}`> { name?: string; selected?: boolean; - cell: Marko.AttrTag; + cell?: Marko.AttrTag; } export interface TableInput extends Omit, `on${string}`> { - header: Marko.AttrTag; + header: Marko.AttrTag>; mode?: "none" | "selection"; - allSelected?: AttrTriState; + "all-selected"?: AttrTriState; row?: Marko.AttrTag; density?: "compact" | "relaxed" | "none"; "a11y-select-all-text"?: string; @@ -33,6 +34,7 @@ export interface TableInput extends Omit, `on${string}`> { }) => void; "on-sort"?: (event: { sorted: Record }) => void; } + export interface Input extends WithNormalizedProps {} interface State { diff --git a/src/components/ebay-table/examples/default.marko b/src/components/ebay-table/examples/default.marko index b8b1d347c..155c7d852 100644 --- a/src/components/ebay-table/examples/default.marko +++ b/src/components/ebay-table/examples/default.marko @@ -1,7 +1,7 @@ import data from "./data.json"; - <@header column-type="row-header"> + <@header row-header> Seller <@header>Item diff --git a/src/components/ebay-table/examples/selection.marko b/src/components/ebay-table/examples/selection.marko index 55764de9b..a4620fff2 100644 --- a/src/components/ebay-table/examples/selection.marko +++ b/src/components/ebay-table/examples/selection.marko @@ -1,7 +1,7 @@ import data from "./data.json"; - <@header column-type="row-header"> + <@header row-header> Seller <@header>Item diff --git a/src/components/ebay-table/examples/sort-client-side.marko b/src/components/ebay-table/examples/sort-client-side.marko index 59010280a..441d8e321 100644 --- a/src/components/ebay-table/examples/sort-client-side.marko +++ b/src/components/ebay-table/examples/sort-client-side.marko @@ -36,7 +36,7 @@ class { } } - <@header name="sellerCol" column-type="row-header"> + <@header name="sellerCol" row-header> Seller <@header name="itemCol"> diff --git a/src/components/ebay-table/examples/sort-with-link.marko b/src/components/ebay-table/examples/sort-with-link.marko index f920ce90f..31e6d2891 100644 --- a/src/components/ebay-table/examples/sort-with-link.marko +++ b/src/components/ebay-table/examples/sort-with-link.marko @@ -2,7 +2,7 @@ import data from "./data.json"; <@header - column-type="row-header" + row-header sort=("asc" as const) href="https://www.ebay.com" > diff --git a/src/components/ebay-table/examples/sort.marko b/src/components/ebay-table/examples/sort.marko index 0c60a7540..9008c82c1 100644 --- a/src/components/ebay-table/examples/sort.marko +++ b/src/components/ebay-table/examples/sort.marko @@ -16,7 +16,7 @@ class { <@header name="sellerCol" - column-type="row-header" + row-header sort=(state.sorted.sellerCol || "none") > Seller diff --git a/src/components/ebay-table/examples/with-actions.marko b/src/components/ebay-table/examples/with-actions.marko index 5c8a3e30e..f3f7aec4c 100644 --- a/src/components/ebay-table/examples/with-actions.marko +++ b/src/components/ebay-table/examples/with-actions.marko @@ -1,7 +1,7 @@ import data from "./data.json"; - <@header column-type="row-header"> + <@header row-header> Seller <@header>Item diff --git a/src/components/ebay-table/index.marko b/src/components/ebay-table/index.marko index 41142fa7e..8ffeb461a 100644 --- a/src/components/ebay-table/index.marko +++ b/src/components/ebay-table/index.marko @@ -41,6 +41,7 @@ $ const { $ const { columnType = "normal", + rowHeader, class: thClass, name = `${headerIndex}`, sort, @@ -73,9 +74,7 @@ $ const { sortEleAttr = { href }; } else if (sortOrder) { sortEleAttr = { - type: "button", - "aria-pressed": - sortOrder !== "none" ? "true" : "false", + type: "button" }; } <${href ? "a" : sortOrder ? "button" : null} @@ -136,7 +135,7 @@ $ const { ) && `table-cell--${header.columnType}`, ]; - <${header.columnType === "row-header" ? "th" : "td"} + <${header.rowHeader ? "th" : "td"} ...processHtmlAttributes(tdInput) class=[cellBaseClass, tdClass] > diff --git a/src/components/ebay-table/marko-tag.json b/src/components/ebay-table/marko-tag.json index 2e55528da..3d0154037 100644 --- a/src/components/ebay-table/marko-tag.json +++ b/src/components/ebay-table/marko-tag.json @@ -19,8 +19,9 @@ }, "@html-attributes": "expression", "@column-type": { - "enum": ["normal", "numeric", "row-header", "layout", "icon-action"] - } + "enum": ["normal", "numeric", "layout", "icon-action"] + }, + "@row-header": "boolean" }, "@row []": { "attribute-groups": ["html-attributes"], diff --git a/src/components/ebay-table/table.stories.ts b/src/components/ebay-table/table.stories.ts index f15b02c21..e2e288833 100644 --- a/src/components/ebay-table/table.stories.ts +++ b/src/components/ebay-table/table.stories.ts @@ -47,6 +47,14 @@ export default { category: "@attribute tags", }, }, + rowHeader: { + name: "row-header", + control: { type: "boolean" }, + description: "If true, the cell will be rendered as a row header", + table: { + category: "@header attribute tags", + }, + }, row: { name: "@row", description: "row attribute tags", @@ -68,12 +76,14 @@ export default { options: [ "normal", "numeric", - "row-header", "layout", "icon-action", ], table: { category: "@header attribute tags", + defaultValue: { + summary: "normal", + }, }, }, href: { diff --git a/src/components/ebay-table/test/__snapshots__/test.server.js.snap b/src/components/ebay-table/test/__snapshots__/test.server.js.snap index de34290fa..020e01efe 100644 --- a/src/components/ebay-table/test/__snapshots__/test.server.js.snap +++ b/src/components/ebay-table/test/__snapshots__/test.server.js.snap @@ -15,7 +15,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell" >  Seller @@ -45,7 +44,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell" >  Item @@ -75,7 +73,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell" >  Status @@ -95,7 +92,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell table-cell--numeric" >  List Price @@ -115,7 +111,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell table-cell--numeric" >  Quantity Available @@ -135,7 +130,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell" >  Orders @@ -155,7 +149,6 @@ exports[`ebay-table > renders ColumnSorting 1`] = ` class="table-cell table-cell--numeric" >  Watchers @@ -173,7 +166,17 @@ exports[`ebay-table > renders ColumnSorting 1`] = `   +  + Protection +   +  renders ColumnSortingClientSide 1`] = ` @@ -205,7 +208,6 @@ exports[`ebay-table > renders ColumnSortingClientSide 1`] = ` class="table-cell table-cell--numeric" >  List Price @@ -235,7 +237,6 @@ exports[`ebay-table > renders ColumnSortingClientSide 1`] = ` class="table-cell table-cell--numeric" >  Quantity Available @@ -374,7 +375,11 @@ exports[`ebay-table > renders ColumnSortingClientSide 1`] = ` >  + 00-10542-89507 +  +  + ..." `; exports[`ebay-table > renders ColumnSortingWithLink 1`] = ` diff --git a/src/components/ebay-table/test/sort/test.browser.js b/src/components/ebay-table/test/sort/test.browser.js index b934743bf..e74f42f78 100644 --- a/src/components/ebay-table/test/sort/test.browser.js +++ b/src/components/ebay-table/test/sort/test.browser.js @@ -26,7 +26,6 @@ describe("given sortable table with Seller column is sorted in ascending order ( it("then proper sort event should be emitted", async () => { expect(sellerColumn).toMatchInlineSnapshot(`