` element.
-@react-props TableRow.jsx
+@react-props TableRow.tsx
Style guide: components.table.react-tablerow
*/
@@ -81,7 +81,7 @@ Style guide: components.table.react-tablerow
`TableCell` dynamically renders a `` or ` ` element based on the parent component or user specified `component` prop. By default `TableCell` will automatically render a ` ` element if the parent component is `TableHead`, otherwise it will render a ` ` element.
-@react-props TableCell.jsx
+@react-props TableCell.tsx
Style guide: components.table.react-tablecell
*/
diff --git a/packages/design-system-docs/src/scripts/components/Footer.jsx b/packages/design-system-docs/src/scripts/components/Footer.jsx
index b6ddffb8b3..b9b56f8242 100644
--- a/packages/design-system-docs/src/scripts/components/Footer.jsx
+++ b/packages/design-system-docs/src/scripts/components/Footer.jsx
@@ -106,7 +106,7 @@ const Footer = () => {
(window.location.href = '#')}
data-privacy-policy="modal-trigger-footer"
>
diff --git a/packages/design-system-docs/src/scripts/components/ReactPropDoc.jsx b/packages/design-system-docs/src/scripts/components/ReactPropDoc.jsx
index b8b4af2288..e6e3c854e2 100644
--- a/packages/design-system-docs/src/scripts/components/ReactPropDoc.jsx
+++ b/packages/design-system-docs/src/scripts/components/ReactPropDoc.jsx
@@ -61,6 +61,10 @@ class ReactPropDoc extends React.PureComponent {
return `${propType}[${valueType}]`;
} else if (propType === 'node') {
return 'string, number, element, or array';
+ } else if (propType === 'enum') {
+ const { raw } = this.props.type;
+ // if its ReactText (meaning it accepts multiple types), display the types that are acceptable
+ return raw === 'ReactText' ? validValues : raw;
} else if (validValues) {
return validValues;
}
@@ -126,6 +130,7 @@ ReactPropDoc.propTypes = {
),
PropTypes.object, // shape
]),
+ raw: PropTypes.string,
}),
};
diff --git a/packages/design-system-docs/src/styles/components/_example.scss b/packages/design-system-docs/src/styles/components/_example.scss
index 6650f57a08..209eb34588 100644
--- a/packages/design-system-docs/src/styles/components/_example.scss
+++ b/packages/design-system-docs/src/styles/components/_example.scss
@@ -36,6 +36,15 @@
margin-top: $spacer-3;
padding: $spacer-2;
}
+
+.example--autocomplete {
+ .ds-c-autocomplete__search-all.ds-c-autocomplete__list-item--active {
+ a {
+ color: $color-white;
+ text-decoration-color: $color-white;
+ }
+ }
+}
// stylelint-enable
// Visualize grid layout
diff --git a/packages/design-system-docs/yarn.lock b/packages/design-system-docs/yarn.lock
index 3b64827040..fc01282eaa 100644
--- a/packages/design-system-docs/yarn.lock
+++ b/packages/design-system-docs/yarn.lock
@@ -16,10 +16,10 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@cmsgov/design-system@^2.5.0":
- version "2.5.0"
- resolved "https://registry.yarnpkg.com/@cmsgov/design-system/-/design-system-2.5.0.tgz#eb2174de9237aeddfcd859fe329989c716280e31"
- integrity sha512-jcqfS39xl/m7m+iPG/FiNAloQE/xAgeex8gB3DsXZhRY0+JWRpMsmRh+vR+k0RkzZtTQMUC9fgX7ThsjTScj9w==
+"@cmsgov/design-system@^2.7.1":
+ version "2.7.2"
+ resolved "https://registry.yarnpkg.com/@cmsgov/design-system/-/design-system-2.7.2.tgz#9aa9a4bad05b50721fc4472bae88a99326dfea87"
+ integrity sha512-Xy1ADo4eR+OnZq1heftcevy7z8zLWL8oE8+00XMVmDu6/R8chb8nJSXjkesCYoRcBZttN3nvNionQGkgGLaYyg==
dependencies:
"@popperjs/core" "^2.4.4"
classnames "^2.2.5"
@@ -42,15 +42,6 @@ classnames@^2.2.5:
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
-clipboard@^2.0.0:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
- integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==
- dependencies:
- good-listener "^1.2.2"
- select "^1.1.2"
- tiny-emitter "^2.0.0"
-
compute-scroll-into-view@^1.0.9:
version "1.0.16"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz#5b7bf4f7127ea2c19b750353d7ce6776a90ee088"
@@ -66,11 +57,6 @@ decode-uri-component@^0.2.0:
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
-delegate@^3.1.2:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
- integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
-
dom-helpers@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8"
@@ -142,13 +128,6 @@ global@^4.3.0:
min-document "^2.19.0"
process "^0.11.10"
-good-listener@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
- integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
- dependencies:
- delegate "^3.1.2"
-
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -189,11 +168,9 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
prismjs@^1.11.0:
- version "1.23.0"
- resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33"
- integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==
- optionalDependencies:
- clipboard "^2.0.0"
+ version "1.24.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.0.tgz#0409c30068a6c52c89ef7f1089b3ca4de56be2ac"
+ integrity sha512-SqV5GRsNqnzCL8k5dfAjCNhUrF3pR0A9lTDSCUZeh/LIshheXJEaP0hwLz2t4XHivd2J/v2HR+gRnigzeKe3cQ==
process@^0.11.10:
version "0.11.10"
@@ -290,11 +267,6 @@ regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
-select@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
- integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
-
source-map@0.5.6:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
@@ -332,11 +304,6 @@ tabbable@^3.1.2:
resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2"
integrity sha512-wjB6puVXTYO0BSFtCmWQubA/KIn7Xvajw0x0l6eJUudMG/EAiJvIUnyNX6xO4NpGrJ16lbD0eUseB9WxW0vlpQ==
-tiny-emitter@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
- integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
-
url-join@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
diff --git a/packages/design-system-scripts/gulp/docs/__tests__/processMarkdownPage.test.js b/packages/design-system-scripts/gulp/docs/__tests__/processMarkdownPage.test.js
index 514c02eb48..93f8a2e301 100644
--- a/packages/design-system-scripts/gulp/docs/__tests__/processMarkdownPage.test.js
+++ b/packages/design-system-scripts/gulp/docs/__tests__/processMarkdownPage.test.js
@@ -110,7 +110,9 @@ Guidance`;
expect(section.header).toBe('---');
expect(section.description.trim()).toBe('Guidance
');
expect(section.reference).toMatch(/[a-z]\.guidance$/);
- expect(section.referenceURI).toMatch(/[a-z]\/guidance$/);
+ // Another instance where both slashes are needed for windows compatibility
+ // eslint-disable-next-line no-useless-escape
+ expect(section.referenceURI).toMatch(/[a-z][\\\/]guidance$/);
});
});
});
diff --git a/packages/design-system-scripts/gulp/docs/extractReactData/parseReactFile.js b/packages/design-system-scripts/gulp/docs/extractReactData/parseReactFile.js
index 75acb53abf..5d00977c30 100644
--- a/packages/design-system-scripts/gulp/docs/extractReactData/parseReactFile.js
+++ b/packages/design-system-scripts/gulp/docs/extractReactData/parseReactFile.js
@@ -119,6 +119,7 @@ function parseComponent(file, options) {
!props.parent ||
!props.parent.fileName.includes('node_modules') ||
props.parent.fileName.includes('@cmsgov'),
+ shouldExtractValuesFromUnion: true,
};
// Use `react-docgen-typescript` for `tsx` files
docs = tsDocgen.withCustomConfig(path.resolve('tsconfig.json'), tsOptions).parse(file.path);
diff --git a/packages/design-system-scripts/gulp/docs/generatePages/processMarkdownPage.js b/packages/design-system-scripts/gulp/docs/generatePages/processMarkdownPage.js
index 714edd24aa..1bba5a2e15 100644
--- a/packages/design-system-scripts/gulp/docs/generatePages/processMarkdownPage.js
+++ b/packages/design-system-scripts/gulp/docs/generatePages/processMarkdownPage.js
@@ -50,7 +50,9 @@ function processMarkdownPage(filePath, body, options) {
depth = referenceURI.split('/').length;
} else {
// Temporarily keep filepath based legacy logic
- referenceURI = filePath.match(/src\/pages\/([a-z0-9-/]+)/i)[1];
+ // Both forward and back slashes are required for this to build on windows
+ // eslint-disable-next-line no-useless-escape
+ referenceURI = filePath.match(/src[\\\/]pages[\\\/]([a-z0-9-/\\]+)/i)[1];
depth = referenceURI.split('/').length;
if (referenceURI === 'index') {
diff --git a/packages/design-system-scripts/helpers/e2e/assertNoAxeViolations.js b/packages/design-system-scripts/helpers/e2e/assertNoAxeViolations.js
index f8ee19b15c..162b592aae 100644
--- a/packages/design-system-scripts/helpers/e2e/assertNoAxeViolations.js
+++ b/packages/design-system-scripts/helpers/e2e/assertNoAxeViolations.js
@@ -1,4 +1,4 @@
-/* global driver, axeBuilder */
+/* global driver, AxeBuilder */
const { RULESET_ALL } = require('./constants');
const chalk = require('chalk');
@@ -41,23 +41,25 @@ function printViolations(violations) {
violations.forEach(printViolation);
}
-module.exports = async function assertNoAxeViolations(url, disabledRules = []) {
+module.exports = function assertNoAxeViolations(url, disabledRules = []) {
if (url) {
- await driver.get(url);
+ return driver.get(url)
+ .then(() => {
+ const defaultDisabledRules = ['bypass'];
+ return new AxeBuilder(driver)
+ .withTags(RULESET_ALL)
+ .disableRules(defaultDisabledRules.concat(disabledRules))
+ .analyze((err, results) => {
+ if (results && results.violations.length >= 1) {
+ printViolations(results.violations);
+ }
+ if (err) {
+ // ESLint wants us to handle the error directly, but that's what
+ // our assertion does below.
+ }
+ expect(results.violations.length).toBe(0);
+ });
+ })
+ .catch((err) => { console.log(err)});
}
- const defaultDisabledRules = ['bypass'];
-
- await axeBuilder(driver)
- .withTags(RULESET_ALL)
- .disableRules(defaultDisabledRules.concat(disabledRules))
- .analyze((err, results) => {
- if (results.violations.length >= 1) {
- printViolations(results.violations);
- }
- if (err) {
- // ESLint wants us to handle the error directly, but that's what
- // our assertion does below.
- }
- expect(results.violations.length).toBe(0);
- });
};
diff --git a/packages/design-system-scripts/helpers/e2e/constants.js b/packages/design-system-scripts/helpers/e2e/constants.js
index 69e47566dd..25a7bb38a1 100644
--- a/packages/design-system-scripts/helpers/e2e/constants.js
+++ b/packages/design-system-scripts/helpers/e2e/constants.js
@@ -1,5 +1,5 @@
const ROOT_URL = 'http://localhost:3001';
-const RULESET_ALL = ['section508', 'wcag2a', 'wcag2aa', 'wcag21aa'];
+const RULESET_ALL = ['section508', 'wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'];
const RULESET_BEST_PRACTICE = ['best-practice'];
const RULESET_WCAG_TWO = ['section508', 'wcag2a', 'wcag2aa'];
const RULESET_508 = ['section508'];
diff --git a/packages/design-system-scripts/jest/e2e.environment.js b/packages/design-system-scripts/jest/e2e.environment.js
index 0f8b7ed271..aedf001d39 100644
--- a/packages/design-system-scripts/jest/e2e.environment.js
+++ b/packages/design-system-scripts/jest/e2e.environment.js
@@ -1,5 +1,5 @@
/* eslint-disable filenames/match-exported */
-const AxeBuilder = require('axe-webdriverjs');
+const AxeBuilder = require('@axe-core/webdriverjs');
const NodeEnvironment = require('jest-environment-node');
const { Builder, By, Key, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
@@ -33,7 +33,7 @@ class WebDriverEnvironment extends NodeEnvironment {
this.global.element.all = (locator) => this.driver.findElements(locator);
this.global.key = Key;
this.global.until = until;
- this.global.axeBuilder = AxeBuilder;
+ this.global.AxeBuilder = AxeBuilder;
}
async teardown() {
diff --git a/packages/design-system-scripts/package.json b/packages/design-system-scripts/package.json
index 1d6789d982..84f1ec52ec 100644
--- a/packages/design-system-scripts/package.json
+++ b/packages/design-system-scripts/package.json
@@ -12,6 +12,7 @@
"cmsds": "./cli.js"
},
"dependencies": {
+ "@axe-core/webdriverjs": "^4.2.2",
"@babel/core": "^7.8.4",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-transform-object-assign": "^7.10.4",
@@ -22,13 +23,12 @@
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.3.0",
"autoprefixer": "9.6.0",
- "axe-webdriverjs": "^2.3.0",
"babel-loader": "^8.0.0",
"babel-plugin-inline-react-svg": "^1.1.2",
"browser-sync": "2.26.7",
"bytes": "3.1.0",
"chalk": "^2.4.2",
- "chromedriver": "91.0.0",
+ "chromedriver": "93.0.0",
"cli-table2": "^0.2.0",
"colors": "1.3.3",
"cssnano": "4.1.10",
diff --git a/packages/design-system-scripts/yarn.lock b/packages/design-system-scripts/yarn.lock
index e462eca5b7..86729de79e 100644
--- a/packages/design-system-scripts/yarn.lock
+++ b/packages/design-system-scripts/yarn.lock
@@ -3169,15 +3169,6 @@ cli-width@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
-clipboard@^2.0.0:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
- integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==
- dependencies:
- good-listener "^1.2.2"
- select "^1.1.2"
- tiny-emitter "^2.0.0"
-
cliui@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
@@ -4051,11 +4042,6 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-delegate@^3.1.2:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
- integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
-
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -5472,13 +5458,6 @@ glogg@^1.0.0:
dependencies:
sparkles "^1.0.0"
-good-listener@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
- integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
- dependencies:
- delegate "^3.1.2"
-
got@^11.7.0:
version "11.8.1"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.1.tgz#df04adfaf2e782babb3daabc79139feec2f7e85d"
@@ -7276,9 +7255,9 @@ jsprim@^1.2.2:
verror "1.10.0"
jszip@^3.2.2:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6"
- integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9"
+ integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
@@ -8922,9 +8901,9 @@ path-key@^3.0.0, path-key@^3.1.0:
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-root-regex@^0.1.0:
version "0.1.2"
@@ -9418,12 +9397,10 @@ pretty-hrtime@^1.0.0:
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
-prismjs@1.23.0:
- version "1.23.0"
- resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.23.0.tgz#d3b3967f7d72440690497652a9d40ff046067f33"
- integrity sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==
- optionalDependencies:
- clipboard "^2.0.0"
+prismjs@1.24.0:
+ version "1.24.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.24.0.tgz#0409c30068a6c52c89ef7f1089b3ca4de56be2ac"
+ integrity sha512-SqV5GRsNqnzCL8k5dfAjCNhUrF3pR0A9lTDSCUZeh/LIshheXJEaP0hwLz2t4XHivd2J/v2HR+gRnigzeKe3cQ==
private@^0.1.8:
version "0.1.8"
@@ -10320,11 +10297,6 @@ scss-tokenizer@^0.2.3:
js-base64 "^2.1.8"
source-map "^0.4.2"
-select@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
- integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
-
selenium-webdriver@4.0.0-alpha.7:
version "4.0.0-alpha.7"
resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.0.0-alpha.7.tgz#e3879d8457fd7ad8e4424094b7dc0540d99e6797"
@@ -11333,11 +11305,6 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
-tiny-emitter@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
- integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
-
tmp@0.0.30:
version "0.0.30"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed"
diff --git a/packages/design-system/src/components/Alert/Alert.test.tsx b/packages/design-system/src/components/Alert/Alert.test.tsx
index 224ba2c707..732407155c 100644
--- a/packages/design-system/src/components/Alert/Alert.test.tsx
+++ b/packages/design-system/src/components/Alert/Alert.test.tsx
@@ -107,7 +107,7 @@ describe('Alert', function () {
});
it('sends analytics event tracking', () => {
- render({ tealiumMock, variation: 'warn' });
+ render({ variation: 'warn' });
expect(tealiumMock).toBeCalledWith({
ga_eventType: 'cmsds',
ga_eventValue: '',
@@ -116,35 +116,18 @@ describe('Alert', function () {
});
it('disables analytics event tracking', () => {
- const analyticsProps = {
- analytics: {
- onComponentDidMount: false,
- },
- };
- render({ tealiumMock, heading: 'dialog heading', variation: 'error', ...analyticsProps });
- expect(tealiumMock).not.toBeCalledWith(defaultEvent);
+ render({ heading: 'dialog heading', variation: 'error', analytics: false });
+ expect(tealiumMock).not.toBeCalled();
});
it('overrides analytics event tracking', () => {
- const analyticsProps = {
- analytics: {
- onComponentDidMount: {
- event_name: 'event name',
- event_type: 'event type',
- ga_eventCategory: 'event category',
- ga_eventAction: 'event action',
- ga_eventLabel: 'event label',
- ga_eventValue: 'event value',
- ga_other: 'other one',
- ga_other2: 'other two',
- ga_eventType: 'other type',
- heading: 'other heading',
- type: 'other type',
- },
- },
- };
- render({ tealiumMock, variation: 'success', ...analyticsProps });
- expect(tealiumMock).toBeCalledWith(analyticsProps.analytics.onComponentDidMount);
+ render({ variation: 'success', analyticsLabelOverride: 'other heading' });
+ expect(tealiumMock).toBeCalledWith(
+ expect.objectContaining({
+ ga_eventLabel: 'other heading',
+ heading: 'other heading',
+ })
+ );
});
});
});
diff --git a/packages/design-system/src/components/Alert/Alert.tsx b/packages/design-system/src/components/Alert/Alert.tsx
index 2c8597b51a..2c71cfb3a3 100644
--- a/packages/design-system/src/components/Alert/Alert.tsx
+++ b/packages/design-system/src/components/Alert/Alert.tsx
@@ -1,51 +1,26 @@
-import { EVENT_CATEGORY, MAX_LENGTH, sendAnalyticsEvent } from '../analytics/SendAnalytics';
+import { EVENT_CATEGORY, MAX_LENGTH, sendLinkEvent } from '../analytics/SendAnalytics';
import React from 'react';
import { alertSendsAnalytics } from '../flags';
import classNames from 'classnames';
-import get from 'lodash/get';
import uniqueId from 'lodash.uniqueid';
-// Omit props that we override with values from the ChoiceList
-type OmitAlertProps = 'role';
-
-/* eslint-disable camelcase */
-// disable linting since prop names must be in snake case for integration with Blast
-export interface AnalyticsEventShape {
- event_name: string;
- event_type: string;
- ga_eventAction: string;
- ga_eventCategory: string;
- ga_eventLabel: string;
- ga_eventType?: string;
- ga_eventValue?: string;
- heading: string;
- type: string;
-}
-/* eslint-enable camelcase */
-
-export interface AnalyticsObjectShape {
- onComponentDidMount?: boolean | AnalyticsEventShape;
-}
-
export type AlertHeadingLevel = '1' | '2' | '3' | '4' | '5' | '6';
-
export type AlertRole = 'alert' | 'alertdialog' | 'region' | 'status';
-
export type AlertVariation = 'error' | 'warn' | 'success';
+
export interface AlertProps {
/**
* Access a reference to the `alert` `div` element
*/
alertRef?: (...args: any[]) => any;
/**
- * Analytics events tracking is enabled by default.
- * The `analytics` prop is an object of events that is either a nested `objects` with key-value
- * pairs, or `boolean` for disabling the event tracking. To disable an event tracking, set the
- * event object value to `false`.
- * When an event is triggered, the object value is populated and sent to google analytics
- * if `window.utag` instance is loaded.
+ * Analytics events tracking is enabled by default. Set this value to `false` to disable tracking for this component instance.
+ */
+ analytics?: boolean;
+ /**
+ * An override for the dynamic content sent to analytics services. By default this content comes from the heading
*/
- analytics?: AnalyticsObjectShape;
+ analyticsLabelOverride?: string;
/**
* Sets the focus on Alert during the first mount
*/
@@ -83,20 +58,10 @@ export interface AlertProps {
[key: string]: any;
}
-// Default analytics object
-const defaultAnalytics = (heading = '', variation = '') => ({
- onComponentDidMount: {
- event_name: 'alert_impression',
- event_type: EVENT_CATEGORY.uiInteraction,
- ga_eventAction: 'alert impression',
- ga_eventCategory: EVENT_CATEGORY.uiComponents,
- ga_eventLabel: heading,
- heading: heading,
- type: variation,
- },
-});
-
-export class Alert extends React.Component<
+// Omit props that we override with values from the Alert
+type OmitAlertProps = 'role' | 'children' | 'className' | 'ref';
+
+export class Alert extends React.PureComponent<
Omit, OmitAlertProps> & AlertProps,
any
> {
@@ -110,7 +75,6 @@ export class Alert extends React.Component<
this.alertTextRef = null;
this.focusRef = null;
this.headingId = this.props.headingId || uniqueId('alert_');
- this.eventHeadingText = '';
if (process.env.NODE_ENV !== 'production') {
if (!props.heading && !props.children) {
@@ -127,29 +91,38 @@ export class Alert extends React.Component<
this.focusRef.focus();
}
- if (alertSendsAnalytics()) {
- const eventAction = 'onComponentDidMount';
- const eventHeading: string | React.ReactNode = this.props.heading || this.props.children;
+ const { analytics, analyticsLabelOverride, variation } = this.props;
+ if (alertSendsAnalytics() && analytics !== false) {
/* Send analytics event for `error`, `warn`, `success` alert variations */
- if (this.props.variation) {
- if (typeof eventHeading === 'string') {
- this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH);
+ if (variation) {
+ const heading = this.props.heading || this.props.children;
+ let eventHeadingText;
+
+ if (analyticsLabelOverride) {
+ eventHeadingText = analyticsLabelOverride;
+ } else if (typeof heading === 'string') {
+ eventHeadingText = heading.substring(0, MAX_LENGTH);
} else {
const eventHeadingTextElement =
(this.alertTextRef &&
this.alertTextRef.getElementsByClassName('ds-c-alert__heading')[0]) ||
(this.alertTextRef && this.alertTextRef.getElementsByClassName('ds-c-alert__body')[0]);
- this.eventHeadingText =
+ eventHeadingText =
eventHeadingTextElement && eventHeadingTextElement.textContent
? eventHeadingTextElement.textContent.substring(0, MAX_LENGTH)
: '';
}
- sendAnalyticsEvent(
- get(this.props.analytics, eventAction),
- get(defaultAnalytics(this.eventHeadingText, this.props.variation), eventAction)
- );
+ sendLinkEvent({
+ event_name: 'alert_impression',
+ event_type: EVENT_CATEGORY.uiInteraction,
+ ga_eventAction: 'alert impression',
+ ga_eventCategory: EVENT_CATEGORY.uiComponents,
+ ga_eventLabel: eventHeadingText,
+ heading: eventHeadingText,
+ type: variation,
+ });
}
}
}
diff --git a/packages/design-system/src/components/Autocomplete/Autocomplete.test.tsx b/packages/design-system/src/components/Autocomplete/Autocomplete.test.tsx
index 36b26cef95..4c5505ce67 100644
--- a/packages/design-system/src/components/Autocomplete/Autocomplete.test.tsx
+++ b/packages/design-system/src/components/Autocomplete/Autocomplete.test.tsx
@@ -40,6 +40,61 @@ describe('Autocomplete', () => {
expect(items.text()).toEqual('Cook County, IL');
});
+ it('renders items with children property', () => {
+ const items = [
+ {
+ id: '1',
+ name: 'Carrots (1)',
+ children: (
+ <>
+ Carrots (1)
+ >
+ ),
+ },
+ {
+ id: '2',
+ name: 'Cookies (3)',
+ children: (
+ <>
+ Cookies (3)
+ >
+ ),
+ },
+ {
+ id: '3',
+ name: 'Crackers (2)',
+ children: (
+ <>
+ Crackers (2)
+ >
+ ),
+ },
+ {
+ id: '4',
+ children: Search all snacks ,
+ },
+ ];
+
+ const { wrapper } = render({ items, isOpen: true }, true);
+ const ul = wrapper.find('ul');
+ expect(ul).toMatchSnapshot();
+ });
+
+ it('renders item with custom className', () => {
+ const items = [
+ { id: '1a', name: 'Normal item' },
+ { id: '5b', name: 'Special item', className: 'custom-class' },
+ ];
+ const { wrapper } = render({ isOpen: true, items }, true);
+
+ const list = wrapper.find('ul');
+ expect(list.exists()).toBe(true);
+
+ const listItems = list.find('li');
+ expect(listItems.at(0).prop('className')).toMatchSnapshot();
+ expect(listItems.at(1).prop('className')).toMatchSnapshot();
+ });
+
it('renders Autocomplete component without items', () => {
const { wrapper } = render({ items: undefined, isOpen: true }, true);
expect(wrapper.find('ul').exists()).toBe(false);
diff --git a/packages/design-system/src/components/Autocomplete/Autocomplete.tsx b/packages/design-system/src/components/Autocomplete/Autocomplete.tsx
index f07aadc8f0..3fe987d0bf 100644
--- a/packages/design-system/src/components/Autocomplete/Autocomplete.tsx
+++ b/packages/design-system/src/components/Autocomplete/Autocomplete.tsx
@@ -14,7 +14,7 @@
* an unacceptable regression of the user experience.
*/
-import Downshift, { DownshiftProps } from 'downshift';
+import Downshift, { A11yStatusMessageOptions, DownshiftProps } from 'downshift';
import Button from '../Button/Button';
import React from 'react';
import TextField from '../TextField/TextField';
@@ -25,8 +25,28 @@ import get from 'lodash/get';
import uniqueId from 'lodash.uniqueid';
export interface AutocompleteItems {
+ /**
+ * Unique identifier for this item
+ */
id?: string;
+ /**
+ * Displayed value of the item. May alternatively provide a `children` value
+ */
name?: string;
+ /**
+ * Custom React node as an alternative to a string-only `name`
+ */
+ children?: React.ReactNode;
+ /**
+ * Additional classes to be added to the root element.
+ * Useful for adding utility classes.
+ */
+ className?: string;
+ /**
+ * Whether this item should be counted as one of the results for the purpose of announcing the
+ * result count to screen readers
+ */
+ isResult?: boolean;
}
type PropsNotPassedToDownshift =
@@ -176,16 +196,14 @@ export class Autocomplete extends React.Component {
return items.map((item, index) => (
- {itemToString(item)}
+ {item.children ?? itemToString(item)}
));
}
@@ -230,7 +248,7 @@ export class Autocomplete extends React.Component {
: child.props.errorMessageClassName;
const propOverrides = {
'aria-autocomplete': 'list',
- 'aria-controls': isOpen ? this.listboxId : null,
+ 'aria-controls': this.listboxId,
'aria-expanded': isOpen,
'aria-labelledby': null,
'aria-owns': isOpen ? this.listboxId : null,
@@ -268,6 +286,32 @@ export class Autocomplete extends React.Component {
const rootClassName = classNames('ds-u-clearfix', 'ds-c-autocomplete', className);
+ if (items) {
+ // We allow items that aren't technically results to be rendered as items in the list, such as
+ // a button for viewing all results, but these non-result items should not be counted in the
+ // accessibility messages as results. It is not enough to set downshift's `itemCount` property
+ // because it will actually make any remaining items past the `itemCount` unselectable with
+ // the keyboard.
+ const resultCount = items.filter((item) => item.isResult !== false).length;
+ if (items.length !== resultCount) {
+ const getA11yStatusMessage =
+ autocompleteProps.getA11yStatusMessage ?? Downshift.defaultProps.getA11yStatusMessage;
+ autocompleteProps.getA11yStatusMessage = (
+ args: A11yStatusMessageOptions
+ ) => {
+ const newArgs = { ...args, resultCount };
+ if (args.previousResultCount === args.resultCount) {
+ // Since we are modifying the resultCount, we want to avoid a case where the resultCount
+ // doesn't match the previousResultCount when it naturally would. If there's an artificial
+ // mismatch between these two values, the result count will be announced each time the
+ // currently focused list item changes.
+ newArgs.previousResultCount = newArgs.resultCount;
+ }
+ return getA11yStatusMessage(newArgs);
+ };
+ }
+ }
+
return (
{({
diff --git a/packages/design-system/src/components/Autocomplete/__snapshots__/Autocomplete.test.tsx.snap b/packages/design-system/src/components/Autocomplete/__snapshots__/Autocomplete.test.tsx.snap
index 763a01247a..07e826bce4 100644
--- a/packages/design-system/src/components/Autocomplete/__snapshots__/Autocomplete.test.tsx.snap
+++ b/packages/design-system/src/components/Autocomplete/__snapshots__/Autocomplete.test.tsx.snap
@@ -14,8 +14,8 @@ exports[`Autocomplete renders a snapshot 1`] = `
>
`;
+
+exports[`Autocomplete renders item with custom className 1`] = `"ds-c-autocomplete__list-item"`;
+
+exports[`Autocomplete renders item with custom className 2`] = `"custom-class ds-c-autocomplete__list-item"`;
+
+exports[`Autocomplete renders items with children property 1`] = `
+
+`;
diff --git a/packages/design-system/src/components/Badge/Badge.tsx b/packages/design-system/src/components/Badge/Badge.tsx
index a2dda7535a..c4cff9ffc5 100644
--- a/packages/design-system/src/components/Badge/Badge.tsx
+++ b/packages/design-system/src/components/Badge/Badge.tsx
@@ -3,6 +3,7 @@ import classNames from 'classnames';
export type BadgeSize = 'big';
export type BadgeVariation = 'info' | 'success' | 'warn' | 'alert';
+
export interface BadgeProps {
/**
* Additional classes to be added to the root badge element.
diff --git a/packages/design-system/src/components/Button/Button.tsx b/packages/design-system/src/components/Button/Button.tsx
index 2ce8902050..089cfe9df7 100644
--- a/packages/design-system/src/components/Button/Button.tsx
+++ b/packages/design-system/src/components/Button/Button.tsx
@@ -8,13 +8,8 @@ export type ButtonType = 'button' | 'submit';
* A string corresponding to the button-component variation classes.
* The danger variation is deprecated and will be removed in a future release.
*/
-export type ButtonVariation =
- | 'primary'
- | 'secondary'
- | 'tertiary'
- | 'danger'
- | 'success'
- | 'transparent';
+export type ButtonVariation = 'primary' | 'danger' | 'success' | 'transparent';
+
export interface ButtonProps {
/**
* Label text or HTML
diff --git a/packages/design-system/src/components/Dialog/Dialog.jsx b/packages/design-system/src/components/Dialog/Dialog.jsx
index 942e2902c1..0540d05817 100644
--- a/packages/design-system/src/components/Dialog/Dialog.jsx
+++ b/packages/design-system/src/components/Dialog/Dialog.jsx
@@ -1,31 +1,10 @@
-import { EVENT_CATEGORY, MAX_LENGTH, sendAnalyticsEvent } from '../analytics/SendAnalytics';
+import { EVENT_CATEGORY, MAX_LENGTH, sendLinkEvent } from '../analytics/SendAnalytics';
import AriaModal from 'react-aria-modal';
import Button from '../Button/Button';
import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
import { dialogSendsAnalytics } from '../flags';
-import get from 'lodash/get';
-
-// Default analytics object
-const defaultAnalytics = (heading = '') => ({
- onComponentDidMount: {
- event_name: 'modal_impression',
- event_type: EVENT_CATEGORY.uiInteraction,
- ga_eventAction: 'modal impression',
- ga_eventCategory: EVENT_CATEGORY.uiComponents,
- ga_eventLabel: heading,
- heading: heading,
- },
- onComponentWillUnmount: {
- event_name: 'modal_closed',
- event_type: EVENT_CATEGORY.uiInteraction,
- ga_eventAction: 'closed modal',
- ga_eventCategory: EVENT_CATEGORY.uiComponents,
- ga_eventLabel: heading,
- heading: heading,
- },
-});
export class Dialog extends React.PureComponent {
constructor(props) {
@@ -53,12 +32,13 @@ export class Dialog extends React.PureComponent {
}
componentDidMount() {
- if (dialogSendsAnalytics()) {
- const eventAction = 'onComponentDidMount';
- const eventHeading = this.props.title || this.props.heading;
+ if (dialogSendsAnalytics() && this.props.analytics !== false) {
+ const heading = this.props.title || this.props.heading;
- if (typeof eventHeading === 'string') {
- this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH);
+ if (this.props.analyticsLabelOverride) {
+ this.eventHeadingText = this.props.analyticsLabelOverride;
+ } else if (typeof heading === 'string') {
+ this.eventHeadingText = heading.substring(0, MAX_LENGTH);
} else {
this.eventHeadingText =
this.headingRef && this.headingRef.textContent
@@ -67,21 +47,28 @@ export class Dialog extends React.PureComponent {
}
/* Send analytics event for dialog open */
- sendAnalyticsEvent(
- get(this.props.analytics, eventAction),
- get(defaultAnalytics(this.eventHeadingText), eventAction)
- );
+ sendLinkEvent({
+ event_name: 'modal_impression',
+ event_type: EVENT_CATEGORY.uiInteraction,
+ ga_eventAction: 'modal impression',
+ ga_eventCategory: EVENT_CATEGORY.uiComponents,
+ ga_eventLabel: this.eventHeadingText,
+ heading: this.eventHeadingText,
+ });
}
}
componentWillUnmount() {
- if (dialogSendsAnalytics()) {
- const eventAction = 'onComponentWillUnmount';
+ if (dialogSendsAnalytics() && this.props.analytics !== false) {
/* Send analytics event for dialog close */
- sendAnalyticsEvent(
- get(this.props.analytics, eventAction),
- get(defaultAnalytics(this.eventHeadingText), eventAction)
- );
+ sendLinkEvent({
+ event_name: 'modal_closed',
+ event_type: EVENT_CATEGORY.uiInteraction,
+ ga_eventAction: 'closed modal',
+ ga_eventCategory: EVENT_CATEGORY.uiComponents,
+ ga_eventLabel: this.eventHeadingText,
+ heading: this.eventHeadingText,
+ });
}
}
@@ -178,20 +165,6 @@ Dialog.defaultProps = {
underlayClickExits: false,
};
-/**
- * Defines the shape of an analytics event for tracking that is an object with key-value pairs
- */
-const AnalyticsEventShape = PropTypes.shape({
- event_name: PropTypes.string,
- event_type: PropTypes.string,
- ga_eventAction: PropTypes.string,
- ga_eventCategory: PropTypes.string,
- ga_eventLabel: PropTypes.string,
- ga_eventType: PropTypes.string,
- ga_eventValue: PropTypes.string,
- heading: PropTypes.string,
-});
-
// TODO: closeButtonText should be a string, but it is being used as a node in MCT,
// until we provide a better solution for customization, we type it as a node.
Dialog.propTypes = {
@@ -202,17 +175,13 @@ Dialog.propTypes = {
*/
alert: PropTypes.bool,
/**
- * Analytics events tracking is enabled by default.
- * The `analytics` prop is an object of events that is either a nested `objects` with key-value
- * pairs, or `boolean` for disabling the event tracking. To disable an event tracking, set the
- * event object value to `false`.
- * When an event is triggered, the object value is populated and sent to google analytics
- * if `window.utag` instance is loaded.
+ * Analytics events tracking is enabled by default. Set this value to `false` to disable tracking for this component instance.
+ */
+ analytics: PropTypes.bool,
+ /**
+ * An override for the dynamic content sent to analytics services. By default this content comes from the heading
*/
- analytics: PropTypes.shape({
- onComponentDidMount: PropTypes.oneOfType([PropTypes.bool, AnalyticsEventShape]),
- onComponentWillUnmount: PropTypes.oneOfType([PropTypes.bool, AnalyticsEventShape]),
- }),
+ analyticsLabelOverride: PropTypes.string,
/**
* Provide a **DOM node** which contains your page's content (which the modal should render
* outside of). When the modal is open this node will receive `aria-hidden="true"`.
diff --git a/packages/design-system/src/components/Dialog/Dialog.test.jsx b/packages/design-system/src/components/Dialog/Dialog.test.jsx
index 82c51771b9..ae509b2699 100644
--- a/packages/design-system/src/components/Dialog/Dialog.test.jsx
+++ b/packages/design-system/src/components/Dialog/Dialog.test.jsx
@@ -90,7 +90,7 @@ describe('Dialog', function () {
});
it('sends analytics event tracking on open dialog', () => {
- render({ tealiumMock, heading: 'dialog heading' });
+ render({ heading: 'dialog heading' });
expect(tealiumMock).toBeCalledWith({
ga_eventType: 'cmsds',
ga_eventValue: '',
@@ -99,34 +99,18 @@ describe('Dialog', function () {
});
it('disables analytics event tracking on open', () => {
- const analyticsProps = {
- analytics: {
- onComponentDidMount: false,
- },
- };
- render({ tealiumMock, heading: 'dialog heading', ...analyticsProps });
- expect(tealiumMock).not.toBeCalledWith(defaultEvent);
+ render({ heading: 'dialog heading', analytics: false });
+ expect(tealiumMock).not.toBeCalled();
});
it('overrides analytics event tracking on open', () => {
- const analyticsProps = {
- analytics: {
- onComponentDidMount: {
- event_name: 'event name',
- event_type: 'event type',
- ga_eventCategory: 'event category',
- ga_eventAction: 'event action',
- ga_eventLabel: 'event label',
- ga_eventValue: 'event value',
- ga_other: 'other one',
- ga_other2: 'other two',
- ga_eventType: 'other type',
- heading: 'other heading',
- },
- },
- };
- render({ tealiumMock, ...analyticsProps });
- expect(tealiumMock).toBeCalledWith(analyticsProps.analytics.onComponentDidMount);
+ render({ analyticsLabelOverride: 'other heading' });
+ expect(tealiumMock).toBeCalledWith(
+ expect.objectContaining({
+ ga_eventLabel: 'other heading',
+ heading: 'other heading',
+ })
+ );
});
});
});
diff --git a/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx b/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx
index 4a892ed643..e3cbf05b5d 100644
--- a/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx
+++ b/packages/design-system/src/components/HelpDrawer/HelpDrawer.jsx
@@ -1,31 +1,10 @@
-import { EVENT_CATEGORY, MAX_LENGTH, sendAnalyticsEvent } from '../analytics/SendAnalytics';
+import { EVENT_CATEGORY, MAX_LENGTH, sendLinkEvent } from '../analytics/SendAnalytics';
import Button from '../Button/Button';
import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
-import get from 'lodash/get';
import { helpDrawerSendsAnalytics } from '../flags';
-// Default analytics object
-const defaultAnalytics = (heading = '') => ({
- onComponentDidMount: {
- event_name: 'help_drawer_opened',
- event_type: EVENT_CATEGORY.uiInteraction,
- ga_eventAction: 'opened help drawer',
- ga_eventCategory: EVENT_CATEGORY.uiComponents,
- ga_eventLabel: heading,
- heading: heading,
- },
- onComponentWillUnmount: {
- event_name: 'help_drawer_closed',
- event_type: EVENT_CATEGORY.uiInteraction,
- ga_eventAction: 'closed help drawer',
- ga_eventCategory: EVENT_CATEGORY.uiComponents,
- ga_eventLabel: heading,
- heading: heading,
- },
-});
-
export class HelpDrawer extends React.PureComponent {
constructor(props) {
super(props);
@@ -49,12 +28,13 @@ export class HelpDrawer extends React.PureComponent {
componentDidMount() {
if (this.headingRef) this.headingRef.focus();
- if (helpDrawerSendsAnalytics()) {
- const eventAction = 'onComponentDidMount';
- const eventHeading = this.props.title || this.props.heading;
+ if (helpDrawerSendsAnalytics() && this.props.analytics !== false) {
+ const heading = this.props.title || this.props.heading;
- if (typeof eventHeading === 'string') {
- this.eventHeadingText = eventHeading.substring(0, MAX_LENGTH);
+ if (this.props.analyticsLabelOverride) {
+ this.eventHeadingText = this.props.analyticsLabelOverride;
+ } else if (typeof heading === 'string') {
+ this.eventHeadingText = heading.substring(0, MAX_LENGTH);
} else {
this.eventHeadingText =
this.headingRef && this.headingRef.textContent
@@ -63,21 +43,28 @@ export class HelpDrawer extends React.PureComponent {
}
/* Send analytics event for helpdrawer open */
- sendAnalyticsEvent(
- get(this.props.analytics, eventAction),
- get(defaultAnalytics(this.eventHeadingText), eventAction)
- );
+ sendLinkEvent({
+ event_name: 'help_drawer_opened',
+ event_type: EVENT_CATEGORY.uiInteraction,
+ ga_eventAction: 'opened help drawer',
+ ga_eventCategory: EVENT_CATEGORY.uiComponents,
+ ga_eventLabel: this.eventHeadingText,
+ heading: this.eventHeadingText,
+ });
}
}
componentWillUnmount() {
- if (helpDrawerSendsAnalytics()) {
- const eventAction = 'onComponentWillUnmount';
+ if (helpDrawerSendsAnalytics() && this.props.analytics !== false) {
/* Send analytics event for helpdrawer close */
- sendAnalyticsEvent(
- get(this.props.analytics, eventAction),
- get(defaultAnalytics(this.eventHeadingText), eventAction)
- );
+ sendLinkEvent({
+ event_name: 'help_drawer_closed',
+ event_type: EVENT_CATEGORY.uiInteraction,
+ ga_eventAction: 'closed help drawer',
+ ga_eventCategory: EVENT_CATEGORY.uiComponents,
+ ga_eventLabel: this.eventHeadingText,
+ heading: this.eventHeadingText,
+ });
}
}
@@ -144,35 +131,17 @@ HelpDrawer.defaultProps = {
headingLevel: '3',
};
-/**
- * Defines the shape of an analytics event for tracking that is an object with key-value pairs
- */
-const AnalyticsEventShape = PropTypes.shape({
- event_name: PropTypes.string,
- event_type: PropTypes.string,
- ga_eventAction: PropTypes.string,
- ga_eventCategory: PropTypes.string,
- ga_eventLabel: PropTypes.string,
- ga_eventType: PropTypes.string,
- ga_eventValue: PropTypes.string,
- heading: PropTypes.string,
-});
-
// TODO: closeButtonText, title/heading should be a string, but it is being used as a node in MCT,
// until we provide a better solution for customization, we type it as a node.
HelpDrawer.propTypes = {
/**
- * Analytics events tracking is enabled by default.
- * The `analytics` prop is an object of events that is either a nested `objects` with key-value
- * pairs, or `boolean` for disabling the event tracking. To disable an event tracking, set the
- * event object value to `false`.
- * When an event is triggered, the object value is populated and sent to google analytics
- * if `window.utag` instance is loaded.
+ * Analytics events tracking is enabled by default. Set this value to `false` to disable tracking for this component instance.
+ */
+ analytics: PropTypes.bool,
+ /**
+ * An override for the dynamic content sent to analytics services. By default this content comes from the heading
*/
- analytics: PropTypes.shape({
- onComponentDidMount: PropTypes.oneOfType([PropTypes.bool, AnalyticsEventShape]),
- onComponentWillUnmount: PropTypes.oneOfType([PropTypes.bool, AnalyticsEventShape]),
- }),
+ analyticsLabelOverride: PropTypes.string,
/**
* Helps give more context to screen readers on the button that closes the Help Drawer
*/
diff --git a/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx b/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx
index 89f0476d38..d210506434 100644
--- a/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx
+++ b/packages/design-system/src/components/HelpDrawer/HelpDrawer.test.jsx
@@ -71,7 +71,7 @@ describe('HelpDrawer', () => {
});
it('sends analytics event tracking on open help drawer', () => {
- renderHelpDrawer({ tealiumMock });
+ renderHelpDrawer();
expect(tealiumMock).toBeCalledWith({
ga_eventType: 'cmsds',
ga_eventValue: '',
@@ -80,58 +80,18 @@ describe('HelpDrawer', () => {
});
it('disables analytics event tracking on open', () => {
- const analyticsProps = {
- analytics: {
- // disables on open help drawer
- onComponentDidMount: false,
- },
- onCloseClick: () => {},
- heading: 'HelpDrawer title',
- };
- function renderDrawer(props) {
- props = Object.assign({}, analyticsProps, props);
- const wrapper = shallow(
-
- content
-
- );
- return { props, wrapper };
- }
- renderDrawer({ tealiumMock });
+ renderHelpDrawer({ analytics: false, onCloseClick: () => {} });
expect(tealiumMock).not.toBeCalledWith(defaultEvent);
});
it('overrides analytics event tracking on open', () => {
- const analyticsProps = {
- analytics: {
- // override default analytics on open help drawer
- onComponentDidMount: {
- event_name: 'event name',
- event_type: 'event type',
- ga_eventCategory: 'event category',
- ga_eventAction: 'event action',
- ga_eventLabel: 'event label',
- ga_eventValue: 'event value',
- ga_other: 'other one',
- ga_other2: 'other two',
- ga_eventType: 'other type',
- heading: 'other heading',
- },
- },
- onCloseClick: () => {},
- heading: 'HelpDrawer title',
- };
- function renderDrawer(props) {
- props = Object.assign({}, analyticsProps, props);
- const wrapper = shallow(
-
- content
-
- );
- return { props, wrapper };
- }
- renderDrawer({ tealiumMock });
- expect(tealiumMock).toBeCalledWith(analyticsProps.analytics.onComponentDidMount);
+ renderHelpDrawer({ analyticsLabelOverride: 'other heading', onCloseClick: () => {} });
+ expect(tealiumMock).toBeCalledWith(
+ expect.objectContaining({
+ ga_eventLabel: 'other heading',
+ heading: 'other heading',
+ })
+ );
});
});
});
diff --git a/packages/design-system/src/components/Spinner/Spinner.test.tsx b/packages/design-system/src/components/Spinner/Spinner.test.tsx
index bbb5f2a41a..da98a905a1 100644
--- a/packages/design-system/src/components/Spinner/Spinner.test.tsx
+++ b/packages/design-system/src/components/Spinner/Spinner.test.tsx
@@ -23,8 +23,8 @@ describe('Spinner', () => {
const data = shallowRender();
const wrapper = data.wrapper;
- expect(wrapper.prop('aria-valuetext')).toEqual('Loading');
- expect(wrapper.prop('role')).toEqual('progressbar');
+ expect(wrapper.text()).toEqual('Loading');
+ expect(wrapper.prop('role')).toEqual('status');
});
it('returns default class names', () => {
diff --git a/packages/design-system/src/components/Spinner/Spinner.tsx b/packages/design-system/src/components/Spinner/Spinner.tsx
index 1c68d73955..7f4f1bc632 100644
--- a/packages/design-system/src/components/Spinner/Spinner.tsx
+++ b/packages/design-system/src/components/Spinner/Spinner.tsx
@@ -2,6 +2,7 @@ import React from 'react';
import classNames from 'classnames';
export type SpinnerSize = 'small' | 'big';
+
export interface SpinnerProps {
/**
* The text announced to screen readers
@@ -39,12 +40,16 @@ export const Spinner: React.FunctionComponent = (props: SpinnerPro
props.className
);
- return ;
+ return (
+
+ {props['aria-valuetext']}
+
+ );
};
Spinner.defaultProps = {
'aria-valuetext': 'Loading',
- role: 'progressbar',
+ role: 'status',
};
export default Spinner;
diff --git a/packages/design-system/src/components/Table/Table.test.jsx b/packages/design-system/src/components/Table/Table.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/Table.test.jsx
rename to packages/design-system/src/components/Table/Table.test.tsx
diff --git a/packages/design-system/src/components/Table/Table.jsx b/packages/design-system/src/components/Table/Table.tsx
similarity index 67%
rename from packages/design-system/src/components/Table/Table.jsx
rename to packages/design-system/src/components/Table/Table.tsx
index e9b212cbaf..db828a1b5f 100644
--- a/packages/design-system/src/components/Table/Table.jsx
+++ b/packages/design-system/src/components/Table/Table.tsx
@@ -1,5 +1,4 @@
import Alert from '../Alert/Alert';
-import PropTypes from 'prop-types';
import React from 'react';
import TableCaption from './TableCaption';
import TableContext from './TableContext';
@@ -7,13 +6,67 @@ import classNames from 'classnames';
import get from 'lodash/get';
import uniqueId from 'lodash.uniqueid';
-function debounce(fn, ms) {
- let timer;
- return () => {
+export type TableStackableBreakpoint = 'sm' | 'md' | 'lg';
+
+export interface TableProps {
+ /**
+ * Applies the borderless variation of the table.
+ */
+ borderless?: boolean;
+ /**
+ * The table contents, usually `TableCaption`, `TableHead` and `TableBody`.
+ */
+ children: React.ReactNode;
+ /**
+ * Additional classes to be added to the root table element.
+ */
+ className?: string;
+ /**
+ * Applies the compact variation of the table.
+ */
+ compact?: boolean;
+ /**
+ * @hide-prop [Deprecated] Use compact instead.
+ */
+ dense?: boolean;
+ /**
+ * Applies a horizontal scrollbar and scrollable notice on `TableCaption` when the `Table`'s contents exceed the container width.
+ */
+ scrollable?: boolean;
+ /**
+ * Additional text or content to display when the horizontal scrollbar is visible to give the user notice of the scroll behavior.
+ * This prop will only be used when the `Table` `scrollable` prop is set and the table width is wider than the viewport.
+ */
+ scrollableNotice?: React.ReactNode;
+ /**
+ * A stackable variation of the table.
+ * When `stackable` is set, `id` or `headers` prop is required in `Table`
+ */
+ stackable?: boolean;
+ /**
+ * Applies responsive styles to vertically stacked rows at different viewport sizes.
+ */
+ stackableBreakpoint?: TableStackableBreakpoint;
+ /**
+ * A striped variation of the table.
+ */
+ striped?: boolean;
+ /**
+ * Disables the warning message on development console when a responsive stackable table cell does not contain an `id` or `headers`.
+ * It's recommended that accessibility with screen readers is tested to ensure the stacked table meets the requirement.
+ */
+ warningDisabled?: boolean;
+}
+
+type OmitProps = 'children' | 'className';
+
+function debounce(fn: (...args: Params) => any, ms: number) {
+ let timer: NodeJS.Timeout;
+ return (...args: any[]) => {
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
- fn.apply(this, arguments);
+ fn.apply(this, args);
}, ms);
};
}
@@ -23,15 +76,27 @@ function debounce(fn, ms) {
* @param {React.Node} child - a React component
* @return {Boolean} Is this a TableCaption component?
*/
-function isTableCaption(child) {
+function isTableCaption(child: React.ReactElement): boolean {
const componentName = get(child, 'type.displayName') || get(child, 'type.name');
// Check child.type first and as a fallback, check child.type.displayName follow by child.type.name
return child && (child.type === TableCaption || componentName === 'TableCaption');
}
-export class Table extends React.PureComponent {
- constructor(props) {
+export class Table extends React.Component<
+ Omit, OmitProps> & TableProps,
+ any
+> {
+ static defaultProps = {
+ scrollableNotice: (
+
+ Scroll using arrow keys to see more
+
+ ),
+ stackableBreakpoint: 'sm',
+ };
+
+ constructor(props: TableProps) {
super(props);
this.state = {
scrollActive: false,
@@ -44,7 +109,7 @@ export class Table extends React.PureComponent {
if (
props.scrollable &&
Array.isArray(props.children) &&
- !props.children.some((child) => isTableCaption(child))
+ !props.children.some((child: React.ReactElement) => isTableCaption(child))
) {
console.warn(
'The children prop in `Table` must include `TableCaption` component for scrollable tables.'
@@ -58,27 +123,31 @@ export class Table extends React.PureComponent {
}
}
- componentDidMount() {
+ componentDidMount(): void {
if (this.props.scrollable) {
window.addEventListener('resize', this.debounceHandleResize);
this.handleResize();
}
}
- componentWillUnmount() {
+ componentWillUnmount(): void {
if (this.props.scrollable) {
window.removeEventListener('resize', this.debounceHandleResize);
}
}
- handleResize() {
+ captionID: string;
+ container: any;
+ debounceHandleResize: (...args: any[]) => any;
+
+ handleResize(): void {
const { scrollWidth, clientWidth } = this.container;
const scrollActive = scrollWidth > clientWidth;
this.setState({ scrollActive });
}
- renderChildren() {
- return React.Children.map(this.props.children, (child) => {
+ renderChildren(): React.ReactNode[] {
+ return React.Children.map(this.props.children, (child: React.ReactElement) => {
if (isTableCaption(child)) {
// Extend props on TableCaption before rendering.
if (this.props.scrollable) {
@@ -93,7 +162,7 @@ export class Table extends React.PureComponent {
});
}
- render() {
+ render(): React.ReactNode {
const {
borderless,
className,
@@ -118,25 +187,26 @@ export class Table extends React.PureComponent {
className
);
- // Makes table container focusable and displays the scrollable notice when table width exceeds viewport
- // by setting `tabIndex = 0` attribute.
- // This provides context for screen readers to the table's via aria-labelleby
+ /**
+ * Makes table container focusable and displays the scrollable notice when table width exceeds viewport
+ * by setting `tabIndex = 0` attribute.
+ * This provides context for screen readers to the table's via aria-labelleby
+ */
const attributeScrollable = scrollable && {
className: 'ds-c-table__wrapper',
role: 'region',
'aria-labelledby': this.captionID,
- 'aria-live': 'polite',
- 'aria-relevant': 'additions',
- tabIndex: this.state.scrollActive ? '0' : null,
+ tabIndex: this.state.scrollActive ? 0 : null,
};
-
const contextValue = { stackable: !!stackable, warningDisabled: !!warningDisabled };
- return (
+ return scrollable ? (
{
this.container = container;
}}
+ aria-live="polite"
+ aria-relevant="additions"
{...attributeScrollable}
>
@@ -145,67 +215,14 @@ export class Table extends React.PureComponent {
+ ) : (
+
+
+ {this.renderChildren()}
+
+
);
}
}
-Table.defaultProps = {
- scrollableNotice: (
-
- Scroll using arrow keys to see more
-
- ),
- stackableBreakpoint: 'sm',
-};
-
-Table.propTypes = {
- /**
- * Applies the borderless variation of the table.
- */
- borderless: PropTypes.bool,
- /**
- * The table contents, usually `TableCaption`, `TableHead` and `TableBody`.
- */
- children: PropTypes.node.isRequired,
- /**
- * Additional classes to be added to the root table element.
- */
- className: PropTypes.string,
- /**
- * Applies the compact variation of the table.
- */
- compact: PropTypes.bool,
- /**
- * @hide-prop [Deprecated] Use compact instead.
- */
- dense: PropTypes.bool,
- /**
- * Applies a horizontal scrollbar and scrollable notice on `TableCaption` when the `Table`'s contents exceed the container width.
- */
- scrollable: PropTypes.bool,
- /**
- * Additional text or content to display when the horizontal scrollbar is visible to give the user notice of the scroll behavior.
- * This prop will only be used when the `Table` `scrollable` prop is set and the table width is wider than the viewport.
- */
- scrollableNotice: PropTypes.node,
- /**
- * Enables responsive styles to vertically stack rows at the specified `stackableBreakpoint`.
- * When `stackable` is set, `id` or `headers` prop is required in `TableCell`
- */
- stackable: PropTypes.bool,
- /**
- * The viewport size at which responsive vertically stacked row styles are applied. Only used when the `stackable` prop is set to `true`. [Read more on breakpoints](/guidelines/responsive/)
- */
- stackableBreakpoint: PropTypes.oneOf(['sm', 'md', 'lg']),
- /**
- * Applies the striped variation of the table.
- */
- striped: PropTypes.bool,
- /**
- * Disables the warning message on development console when a responsive stackable table cell does not contain an `id` or `headers`.
- * It's recommended that accessibility with screen readers is tested to ensure the stacked table meets the requirement.
- */
- warningDisabled: PropTypes.bool,
-};
-
export default Table;
diff --git a/packages/design-system/src/components/Table/TableBody.test.jsx b/packages/design-system/src/components/Table/TableBody.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/TableBody.test.jsx
rename to packages/design-system/src/components/Table/TableBody.test.tsx
diff --git a/packages/design-system/src/components/Table/TableBody.jsx b/packages/design-system/src/components/Table/TableBody.tsx
similarity index 54%
rename from packages/design-system/src/components/Table/TableBody.jsx
rename to packages/design-system/src/components/Table/TableBody.tsx
index 18556c745e..a39bfe3edb 100644
--- a/packages/design-system/src/components/Table/TableBody.jsx
+++ b/packages/design-system/src/components/Table/TableBody.tsx
@@ -1,7 +1,17 @@
-import PropTypes from 'prop-types';
import React from 'react';
-export const TableBody = ({ children, ...tableBodyProps }) => {
+export interface TableBodyProps {
+ /**
+ * The table body contents, usually `TableRow`.
+ */
+ children?: React.ReactNode;
+}
+
+type OmitProps = 'children';
+
+export const TableBody: React.FC<
+ Omit, OmitProps> & TableBodyProps
+> = ({ children, ...tableBodyProps }: TableBodyProps) => {
/* eslint-disable jsx-a11y/no-redundant-roles */
return (
@@ -11,11 +21,4 @@ export const TableBody = ({ children, ...tableBodyProps }) => {
/* eslint-enable jsx-a11y/no-redundant-roles */
};
-TableBody.propTypes = {
- /**
- * The table body contents, usually `TableRow`.
- */
- children: PropTypes.node,
-};
-
export default TableBody;
diff --git a/packages/design-system/src/components/Table/TableCaption.test.jsx b/packages/design-system/src/components/Table/TableCaption.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/TableCaption.test.jsx
rename to packages/design-system/src/components/Table/TableCaption.test.tsx
diff --git a/packages/design-system/src/components/Table/TableCaption.jsx b/packages/design-system/src/components/Table/TableCaption.tsx
similarity index 79%
rename from packages/design-system/src/components/Table/TableCaption.jsx
rename to packages/design-system/src/components/Table/TableCaption.tsx
index c7499c7c15..cdf9046f3c 100644
--- a/packages/design-system/src/components/Table/TableCaption.jsx
+++ b/packages/design-system/src/components/Table/TableCaption.tsx
@@ -1,15 +1,37 @@
-import PropTypes from 'prop-types';
import React from 'react';
import classNames from 'classnames';
-export const TableCaption = ({
+export interface TableCaptionProps {
+ /**
+ * The table caption contents.
+ */
+ children?: React.ReactNode;
+ /**
+ * Additional classes to be added to the caption element.
+ */
+ className?: string;
+ /**
+ * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
+ */
+ _id?: string;
+ /**
+ * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
+ */
+ _scrollActive?: boolean;
+ /**
+ * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
+ */
+ _scrollableNotice?: React.ReactNode;
+}
+
+export const TableCaption: React.FC = ({
children,
className,
_id,
_scrollActive,
_scrollableNotice,
...tableCaptionProps
-}) => {
+}: TableCaptionProps) => {
const classes = classNames('ds-c-table__caption', className);
return (
@@ -22,27 +44,4 @@ export const TableCaption = ({
// Set component name to make child.type.displayName available to other components (eg. Table)
TableCaption.displayName = 'TableCaption';
-TableCaption.propTypes = {
- /**
- * The table caption contents.
- */
- children: PropTypes.node,
- /**
- * Additional classes to be added to the caption element.
- */
- className: PropTypes.string,
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _id: PropTypes.string,
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _scrollActive: PropTypes.bool,
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _scrollableNotice: PropTypes.node,
-};
-
export default TableCaption;
diff --git a/packages/design-system/src/components/Table/TableCell.test.jsx b/packages/design-system/src/components/Table/TableCell.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/TableCell.test.jsx
rename to packages/design-system/src/components/Table/TableCell.test.tsx
diff --git a/packages/design-system/src/components/Table/TableCell.jsx b/packages/design-system/src/components/Table/TableCell.tsx
similarity index 83%
rename from packages/design-system/src/components/Table/TableCell.jsx
rename to packages/design-system/src/components/Table/TableCell.tsx
index f2f0314c80..b89a3d62ea 100644
--- a/packages/design-system/src/components/Table/TableCell.jsx
+++ b/packages/design-system/src/components/Table/TableCell.tsx
@@ -1,9 +1,69 @@
import React, { useContext } from 'react';
-import PropTypes from 'prop-types';
import TableContext from './TableContext';
import classNames from 'classnames';
-export const TableCell = ({
+export type TableCellScope = 'row' | 'col' | 'rowgroup' | 'colgroup';
+export type TableCellAlign = 'center' | 'left' | 'right';
+export type TableCellComponent = 'td' | 'th';
+
+export interface TableCellProps {
+ /**
+ * Set the text-align on the table cell content.
+ */
+ align?: TableCellAlign;
+ /**
+ * The table cell contents.
+ */
+ children?: React.ReactNode;
+ /**
+ * When provided, this will render the passed in component as the HTML element.
+ * If this prop is undefined, it renders a `` element if the parent component is `TableHead`,
+ * otherwise, it renders a ` ` element.
+ */
+ component?: TableCellComponent;
+ /**
+ * Additional classes to be added to the row element.
+ */
+ className?: string;
+ /**
+ * `TableCell` must define a `headers` prop for stackable tables with a ` ` element.
+ * The `headers` prop associates header and data cells for screen readers.
+ * `headers` consist of a list of space-separated ids that each correspond to a ` ` element.
+ * [Read more about the headers attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#Attributes).
+ */
+ headers?: string;
+ /**
+ * `TableCell` must define an `id` prop for stackable tables with a ` ` element.
+ * The `id` prop associates header and data cells for screen readers.
+ */
+ id?: string;
+ /**
+ * If this prop is undefined, the component sets a scope attribute of `col` when the parent
+ * component is `TableHead` to identify the header cell is a header for a column.
+ */
+ scope?: TableCellScope;
+ /**
+ * Additional classes to be added to the stacked Title element.
+ */
+ stackedClassName?: string;
+ /**
+ * Table data cell's corresponding header title, this stacked title is displayed as the row header
+ * when a responsive table is vertically stacked.
+ */
+ stackedTitle?: string;
+ /**
+ * @hide-prop This gets set from the parent `TableHead` component
+ */
+ _isTableHeadChild?: boolean;
+}
+
+type OmitProps = 'align' | 'children' | 'className' | 'headers' | 'id' | 'scope';
+
+export const TableCell: React.FC<
+ Omit, OmitProps> &
+ Omit, OmitProps> &
+ TableCellProps
+> = ({
align,
children,
className,
@@ -15,7 +75,7 @@ export const TableCell = ({
stackedClassName,
_isTableHeadChild,
...tableCellProps
-}) => {
+}: TableCellProps) => {
const { stackable, warningDisabled } = useContext(TableContext);
let Component;
@@ -82,55 +142,4 @@ TableCell.defaultProps = {
align: 'left',
};
-TableCell.propTypes = {
- /**
- * Set the text-align on the table cell content.
- */
- align: PropTypes.oneOf(['center', 'left', 'right']),
- /**
- * The table cell contents.
- */
- children: PropTypes.node,
- /**
- * Additional classes to be added to the row element.
- */
- className: PropTypes.string,
- /**
- * When provided, this will render the passed in component as the HTML element.
- * If this prop is undefined, it renders a `` element if the parent component is `TableHead`,
- * otherwise, it renders a ` ` element.
- */
- component: PropTypes.oneOf(['td', 'th']),
- /**
- * `TableCell` must define a `headers` prop for stackable tables with a ` ` element.
- * The `headers` prop associates header and data cells for screen readers.
- * `headers` consist of a list of space-separated ids that each correspond to a ` ` element.
- * [Read more about the headers attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#Attributes).
- */
- headers: PropTypes.string,
- /**
- * `TableCell` must define an `id` prop for stackable tables with a ` ` element.
- * The `id` prop associates header and data cells for screen readers.
- */
- id: PropTypes.string,
- /**
- * If this prop is undefined, the component sets a scope attribute of `col` when the parent
- * component is `TableHead` to identify the header cell is a header for a column.
- */
- scope: PropTypes.oneOf(['row', 'col', 'rowgroup', 'colgroup']),
- /**
- * Additional classes to be added to the stacked Title element.
- */
- stackedClassName: PropTypes.string,
- /**
- * Table data cell's corresponding header title, this stacked title is displayed as the row header
- * when a responsive table is vertically stacked.
- */
- stackedTitle: PropTypes.string,
- /**
- * @hide-prop This gets set from the parent `TableHead` component
- */
- _isTableHeadChild: PropTypes.bool,
-};
-
export default TableCell;
diff --git a/packages/design-system/src/components/Table/TableContext.js b/packages/design-system/src/components/Table/TableContext.js
deleted file mode 100644
index 4ca914ba50..0000000000
--- a/packages/design-system/src/components/Table/TableContext.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-const TableContext = React.createContext({ stackable: false, warningDisabled: false });
-
-export default TableContext;
diff --git a/packages/design-system/src/components/Table/TableContext.ts b/packages/design-system/src/components/Table/TableContext.ts
new file mode 100644
index 0000000000..347df4ef8e
--- /dev/null
+++ b/packages/design-system/src/components/Table/TableContext.ts
@@ -0,0 +1,13 @@
+import React from 'react';
+
+export interface TableContextType {
+ stackable: boolean;
+ warningDisabled: boolean;
+}
+
+export const TableContext = React.createContext({
+ stackable: false,
+ warningDisabled: false,
+} as TableContextType);
+
+export default TableContext;
diff --git a/packages/design-system/src/components/Table/TableHead.test.jsx b/packages/design-system/src/components/Table/TableHead.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/TableHead.test.jsx
rename to packages/design-system/src/components/Table/TableHead.test.tsx
diff --git a/packages/design-system/src/components/Table/TableHead.jsx b/packages/design-system/src/components/Table/TableHead.tsx
similarity index 62%
rename from packages/design-system/src/components/Table/TableHead.jsx
rename to packages/design-system/src/components/Table/TableHead.tsx
index 79ae99fa0c..2ad2610096 100644
--- a/packages/design-system/src/components/Table/TableHead.jsx
+++ b/packages/design-system/src/components/Table/TableHead.tsx
@@ -1,9 +1,19 @@
-import PropTypes from 'prop-types';
import React from 'react';
-export const TableHead = ({ children, ...tableHeadProps }) => {
+export interface TableHeadProps {
+ /**
+ * The table head contents, usually `TableRow`.
+ */
+ children?: React.ReactNode;
+}
+
+type OmitProps = 'children';
+
+export const TableHead: React.FC<
+ Omit, OmitProps> & TableHeadProps
+> = ({ children, ...tableHeadProps }: TableHeadProps) => {
const renderChildren = () => {
- return React.Children.map(children, (child) => {
+ return React.Children.map(children, (child: React.ReactElement) => {
// Extend props before rendering.
if (child && child.props) {
return React.cloneElement(child, {
@@ -23,11 +33,4 @@ export const TableHead = ({ children, ...tableHeadProps }) => {
/* eslint-enable jsx-a11y/no-redundant-roles */
};
-TableHead.propTypes = {
- /**
- * The table head contents, usually `TableRow`.
- */
- children: PropTypes.node,
-};
-
export default TableHead;
diff --git a/packages/design-system/src/components/Table/TableRow.test.jsx b/packages/design-system/src/components/Table/TableRow.test.tsx
similarity index 100%
rename from packages/design-system/src/components/Table/TableRow.test.jsx
rename to packages/design-system/src/components/Table/TableRow.test.tsx
diff --git a/packages/design-system/src/components/Table/TableRow.jsx b/packages/design-system/src/components/Table/TableRow.tsx
similarity index 53%
rename from packages/design-system/src/components/Table/TableRow.jsx
rename to packages/design-system/src/components/Table/TableRow.tsx
index 758c9edd84..a159d67fdd 100644
--- a/packages/design-system/src/components/Table/TableRow.jsx
+++ b/packages/design-system/src/components/Table/TableRow.tsx
@@ -1,9 +1,23 @@
-import PropTypes from 'prop-types';
import React from 'react';
-export const TableRow = ({ children, _isTableHeadChild, ...tableRowProps }) => {
+export interface TableRowProps {
+ /**
+ * The table row contents, usually `TableCell`.
+ */
+ children?: React.ReactNode;
+ /**
+ * @hide-prop This gets set from the parent `TableHead`
+ */
+ _isTableHeadChild?: boolean;
+}
+
+type OmitProps = 'children';
+
+export const TableRow: React.FC<
+ Omit, OmitProps> & TableRowProps
+> = ({ children, _isTableHeadChild, ...tableRowProps }: TableRowProps) => {
const renderChildren = () => {
- return React.Children.map(children, (child) => {
+ return React.Children.map(children, (child: React.ReactElement) => {
// Extend props before rendering.
if (child && child.props) {
return React.cloneElement(child, {
@@ -21,15 +35,4 @@ export const TableRow = ({ children, _isTableHeadChild, ...tableRowProps }) => {
);
};
-TableRow.propTypes = {
- /**
- * The table row contents, usually `TableCell`.
- */
- children: PropTypes.node,
- /**
- * @hide-prop This gets set from the parent `TableHead` component
- */
- _isTableHeadChild: PropTypes.bool,
-};
-
export default TableRow;
diff --git a/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/Table.test.tsx.snap
similarity index 78%
rename from packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/Table.test.tsx.snap
index 8ab91e56c1..64c7cc863b 100644
--- a/packages/design-system/src/components/Table/__snapshots__/Table.test.jsx.snap
+++ b/packages/design-system/src/components/Table/__snapshots__/Table.test.tsx.snap
@@ -97,49 +97,45 @@ exports[`Table table caption scrollable true applies scrollableNotice 1`] = `
`;
exports[`Table table responsive stacked table true applies responsive stacked table 1`] = `
-
-
+
+
`;
exports[`Table table responsive stacked table true applies responsive stacked table ContextProvider 1`] = `
-
-
+
+
`;
diff --git a/packages/design-system/src/components/Table/__snapshots__/TableBody.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/TableBody.test.tsx.snap
similarity index 100%
rename from packages/design-system/src/components/Table/__snapshots__/TableBody.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/TableBody.test.tsx.snap
diff --git a/packages/design-system/src/components/Table/__snapshots__/TableCaption.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/TableCaption.test.tsx.snap
similarity index 100%
rename from packages/design-system/src/components/Table/__snapshots__/TableCaption.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/TableCaption.test.tsx.snap
diff --git a/packages/design-system/src/components/Table/__snapshots__/TableCell.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/TableCell.test.tsx.snap
similarity index 100%
rename from packages/design-system/src/components/Table/__snapshots__/TableCell.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/TableCell.test.tsx.snap
diff --git a/packages/design-system/src/components/Table/__snapshots__/TableHead.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/TableHead.test.tsx.snap
similarity index 100%
rename from packages/design-system/src/components/Table/__snapshots__/TableHead.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/TableHead.test.tsx.snap
diff --git a/packages/design-system/src/components/Table/__snapshots__/TableRow.test.jsx.snap b/packages/design-system/src/components/Table/__snapshots__/TableRow.test.tsx.snap
similarity index 100%
rename from packages/design-system/src/components/Table/__snapshots__/TableRow.test.jsx.snap
rename to packages/design-system/src/components/Table/__snapshots__/TableRow.test.tsx.snap
diff --git a/packages/design-system/src/components/Table/index.js b/packages/design-system/src/components/Table/index.ts
similarity index 100%
rename from packages/design-system/src/components/Table/index.js
rename to packages/design-system/src/components/Table/index.ts
diff --git a/packages/design-system/src/components/analytics/SendAnalytics.test.ts b/packages/design-system/src/components/analytics/SendAnalytics.test.ts
index ee2cf4ea71..bfb069ccaa 100644
--- a/packages/design-system/src/components/analytics/SendAnalytics.test.ts
+++ b/packages/design-system/src/components/analytics/SendAnalytics.test.ts
@@ -1,6 +1,6 @@
-import { sendAnalyticsEvent } from './SendAnalytics';
+import { sendLinkEvent } from './SendAnalytics';
-describe('sendAnalyticsEvent', () => {
+describe('sendLinkEvent', () => {
const gaEventProps = {
ga_eventType: 'cmsds',
ga_eventCategory: 'test category',
@@ -13,7 +13,7 @@ describe('sendAnalyticsEvent', () => {
it('does nothing if window.utag does not exist', () => {
const mock = jest.fn();
window.utag = undefined;
- sendAnalyticsEvent({}, gaEventProps);
+ sendLinkEvent(gaEventProps);
expect(mock).not.toHaveBeenCalled();
});
});
@@ -29,24 +29,10 @@ describe('sendAnalyticsEvent', () => {
jest.resetAllMocks();
});
- it('calls window.utag.link with default props', () => {
- sendAnalyticsEvent({}, gaEventProps);
+ it('calls window.utag.link with event', () => {
+ sendLinkEvent(gaEventProps);
expect(window.utag?.link).toHaveBeenCalledWith(gaEventProps);
});
-
- it('calls window.utag.link with extra props', () => {
- const gaEventExtraProps = {
- ga_eventType: 'cmsds',
- ga_eventCategory: 'test category',
- ga_eventAction: 'test action',
- ga_eventLabel: 'test label',
- ga_eventValue: 'test value',
- ga_extraProps1: 'test extra props 1',
- ga_extraProps2: 'test extra props 2',
- };
- sendAnalyticsEvent(gaEventExtraProps, gaEventProps);
- expect(window.utag?.link).toHaveBeenCalledWith(gaEventExtraProps);
- });
});
describe('with Utag instance - errors', () => {
@@ -60,9 +46,7 @@ describe('sendAnalyticsEvent', () => {
throw 'test event';
}),
};
- expect(sendAnalyticsEvent({}, gaEventProps)).toBe(
- 'Error sending event to Tealium test event'
- );
+ expect(sendLinkEvent(gaEventProps)).toBe('Error sending event to Tealium test event');
});
it('retries on missing utag.link', () => {
@@ -70,7 +54,7 @@ describe('sendAnalyticsEvent', () => {
jest.useFakeTimers();
window.utag = { link: undefined };
- sendAnalyticsEvent({}, gaEventProps);
+ sendLinkEvent(gaEventProps);
expect(mock).not.toHaveBeenCalled();
window.utag = { link: mock };
@@ -82,7 +66,7 @@ describe('sendAnalyticsEvent', () => {
jest.useFakeTimers();
window.utag = { link: undefined };
- expect(sendAnalyticsEvent({}, gaEventProps)).toBe(undefined);
+ expect(sendLinkEvent(gaEventProps)).toBe(undefined);
jest.runAllTimers();
jest.runAllTimers();
diff --git a/packages/design-system/src/components/analytics/SendAnalytics.ts b/packages/design-system/src/components/analytics/SendAnalytics.ts
index d2eb631243..831f3eec46 100644
--- a/packages/design-system/src/components/analytics/SendAnalytics.ts
+++ b/packages/design-system/src/components/analytics/SendAnalytics.ts
@@ -1,4 +1,3 @@
-import merge from 'lodash/merge';
/**
* Functions for sending events to Tealium/Google Analytics
* Based on HRA Tool & SEP screener & Coverage Tools analytics service:
@@ -11,24 +10,14 @@ import merge from 'lodash/merge';
declare global {
interface Window {
utag?: {
- link: (params: AnalyticsPayload) => void;
+ link: (params: AnalyticsEvent) => void;
};
}
}
-type EventType = 'link';
-const MAX_RETRIES = 3;
-const TIMEOUT = 300;
+export type EventType = 'link';
-/* eslint-disable camelcase */
-export interface AnalyticsPayload {
- ga_eventAction: string;
- ga_eventCategory: string;
- ga_eventLabel: string;
- ga_eventType: string;
- ga_eventValue: string;
- [additional_props: string]: unknown;
-}
+export const MAX_LENGTH = 100;
export const EVENT_CATEGORY = {
contentTools: 'content tools',
@@ -36,9 +25,8 @@ export const EVENT_CATEGORY = {
uiInteraction: 'ui interaction',
};
-export const MAX_LENGTH = 100;
-
-interface AnalyticsEventProps {
+/* eslint-disable camelcase */
+export interface AnalyticsEvent {
ga_eventAction: string;
ga_eventCategory: string;
ga_eventLabel: string;
@@ -47,50 +35,36 @@ interface AnalyticsEventProps {
[additional_props: string]: unknown;
}
-export function sendAnalytics(event: EventType, props: AnalyticsPayload, retry = 0): string {
- if (window.utag && window.utag[event]) {
+const MAX_RETRIES = 3;
+const TIMEOUT = 300;
+
+export function sendAnalytics(
+ eventType: EventType,
+ event: Required
,
+ retry = 0
+): string {
+ if (window.utag && window.utag[eventType]) {
try {
- window.utag[event](props);
- return `Tealium event sent: ${props.ga_eventCategory} - ${props.ga_eventAction} - ${props.ga_eventLabel}`;
+ window.utag[eventType](event);
+ return `Tealium event sent: ${event.ga_eventCategory} - ${event.ga_eventAction} - ${event.ga_eventLabel}`;
} catch (e) {
return `Error sending event to Tealium ${e}`;
}
} else {
if (++retry <= MAX_RETRIES) {
- setTimeout(() => sendAnalytics(event, props, retry), retry * TIMEOUT);
+ setTimeout(() => sendAnalytics(eventType, event, retry), retry * TIMEOUT);
} else {
return `Tealium event max retries reached`;
}
}
}
-export function sendAnalyticsEvent(
- overrides: boolean | Record,
- defaultPayload: AnalyticsEventProps
-): string {
- const analyticsDisabled = overrides === false;
- if (window.utag && !analyticsDisabled) {
- const mergedPayload = merge(defaultPayload, overrides);
- const {
- ga_eventAction,
- ga_eventCategory,
- ga_eventLabel,
- ga_eventType = 'cmsds', // default value
- ga_eventValue = '', // default value
- ...other_props
- } = mergedPayload;
- const payload: AnalyticsPayload = {
- ga_eventAction,
- ga_eventCategory,
- ga_eventLabel,
- ga_eventType,
- ga_eventValue,
- ...other_props,
- };
- return sendAnalytics('link', payload);
- } else {
- return '';
- }
+export function sendLinkEvent(payload: AnalyticsEvent) {
+ return sendAnalytics('link', {
+ ga_eventType: 'cmsds', // default value
+ ga_eventValue: '', // default value
+ ...payload,
+ });
}
/* eslint-enable camelcase */
diff --git a/packages/design-system/src/components/analytics/index.ts b/packages/design-system/src/components/analytics/index.ts
index 00f847de38..4d27f55b35 100644
--- a/packages/design-system/src/components/analytics/index.ts
+++ b/packages/design-system/src/components/analytics/index.ts
@@ -1 +1 @@
-export { default as sendAnalytics } from './SendAnalytics';
+export { default as sendAnalytics, sendLinkEvent } from './SendAnalytics';
diff --git a/packages/design-system/src/styles/base/_link.scss b/packages/design-system/src/styles/base/_link.scss
index 4030b300e9..a595294e9b 100644
--- a/packages/design-system/src/styles/base/_link.scss
+++ b/packages/design-system/src/styles/base/_link.scss
@@ -1,5 +1,5 @@
/* stylelint-disable selector-class-pattern */
-@import '../settings/index.scss';
+@import '../settings/index.scss';
// Links
// Default link
diff --git a/packages/design-system/src/styles/components/_Button.scss b/packages/design-system/src/styles/components/_Button.scss
index 708a92aeb2..541f83b08b 100644
--- a/packages/design-system/src/styles/components/_Button.scss
+++ b/packages/design-system/src/styles/components/_Button.scss
@@ -96,6 +96,7 @@
.ds-c-button--transparent:visited,
.ds-c-button--transparent-inverse,
.ds-c-button--transparent-inverse:visited {
+ background-color: transparent;
border-color: transparent;
text-decoration: underline;
@@ -169,10 +170,10 @@
}
}
-/* stylelint-disable */
+/* stylelint-disable scss/at-extend-no-missing-placeholder */
%transparent-inverse-button {
- border-color: transparent;
background-color: transparent;
+ border-color: transparent;
// Default inverse focus styles are overridden above
@if $ds-include-focus-styles {
@@ -195,7 +196,7 @@
/**
* Not recommended usage
- * Equivalent to ".ds-c-button--inverse.ds-c-button--transparent"
+ * Equivalent to ".ds-c-button--inverse.ds-c-button--transparent"
*/
.ds-c-button--transparent-inverse,
.ds-c-button--transparent-inverse:visited {
@@ -217,14 +218,14 @@
/**
* Not recommended usage
- * Equivalent to ".ds-c-button--inverse.ds-c-button--disabled"
+ * Equivalent to ".ds-c-button--inverse.ds-c-button--disabled"
*/
.ds-c-button--disabled-inverse,
.ds-c-button--disabled-inverse:visited {
@extend .ds-c-button--inverse;
@extend %disabled-inverse-button;
}
-/* stylelint-enable */
+/* stylelint-enable scss/at-extend-no-missing-placeholder */
/**
* Status variants
diff --git a/packages/design-system/src/types/Table/Table.d.ts b/packages/design-system/src/types/Table/Table.d.ts
deleted file mode 100644
index 554e0c945e..0000000000
--- a/packages/design-system/src/types/Table/Table.d.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import * as React from 'react';
-
-export type TableStackableBreakpoint = 'sm' | 'md' | 'lg';
-
-export interface TableProps {
- /**
- * Applies the borderless variation of the table.
- */
- borderless?: boolean;
- /**
- * The table contents, usually `TableCaption`, `TableHead` and `TableBody`.
- */
- children: React.ReactNode;
- /**
- * Additional classes to be added to the root table element.
- */
- className?: string;
- /**
- * Applies the compact variation of the table.
- */
- compact?: boolean,
- /**
- * @hide-prop [Deprecated] Use compact instead.
- */
- dense?: boolean,
- /**
- * Applies a horizontal scrollbar and scrollable notice on `TableCaption` when the `Table`'s contents exceed the container width.
- */
- scrollable?: boolean;
- /**
- * Additional text or content to display when the horizontal scrollbar is visible to give the user notice of the scroll behavior.
- * This prop will only be used when the `Table` `scrollable` prop is set and the table width is wider than the viewport.
- */
- scrollableNotice?: React.ReactNode;
- /**
- * A stackable variation of the table.
- * When `stackable` is set, `id` or `headers` prop is required in `Table`
- */
- stackable?: boolean;
- /**
- * Applies responsive styles to vertically stacked rows at different viewport sizes.
- */
- stackableBreakpoint?: TableStackableBreakpoint;
- /**
- * A striped variation of the table.
- */
- striped?: boolean;
- /**
- * Disables the warning message on development console when a responsive stackable table cell does not contain an `id` or `headers`.
- * It's recommended that accessibility with screen readers is tested to ensure the stacked table meets the requirement.
- */
- warningDisabled?: boolean,
-}
-
-export default class Table extends React.Component<
- React.ComponentPropsWithRef<'table'> & TableProps,
- any
-> {
- render(): JSX.Element;
-}
diff --git a/packages/design-system/src/types/Table/TableBody.d.ts b/packages/design-system/src/types/Table/TableBody.d.ts
deleted file mode 100644
index 5eff89097c..0000000000
--- a/packages/design-system/src/types/Table/TableBody.d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import * as React from 'react';
-
-export interface TableBodyProps {
- /**
- * The table body contents, usually `TableRow`.
- */
- children?: React.ReactNode;
-}
-
-declare const TableBody: React.FC & TableBodyProps>;
-
-export default TableBody;
diff --git a/packages/design-system/src/types/Table/TableCaption.d.ts b/packages/design-system/src/types/Table/TableCaption.d.ts
deleted file mode 100644
index ae68529c23..0000000000
--- a/packages/design-system/src/types/Table/TableCaption.d.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import * as React from 'react';
-
-export interface TableCaptionProps {
- /**
- * The table caption contents.
- */
- children?: React.ReactNode;
- /**
- * Additional classes to be added to the caption element.
- */
- className?: string;
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _id?: string;
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _scrollActive?: boolean;
- /**
- * @hide-prop This gets passed from the parent `Table` component when the table `scrollable` prop is set.
- */
- _scrollableNotice?: React.ReactNode;
-}
-
-declare const TableCaption: React.FC;
-
-export default TableCaption;
diff --git a/packages/design-system/src/types/Table/TableCell.d.ts b/packages/design-system/src/types/Table/TableCell.d.ts
deleted file mode 100644
index f94ccee2ff..0000000000
--- a/packages/design-system/src/types/Table/TableCell.d.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import * as React from 'react';
-
-export type TableCellScope = 'row' | 'col' | 'rowgroup' | 'colgroup';
-export type TableCellAlign = 'center' | 'left' | 'right';
-export type TableCellComponent = 'td' | 'th';
-
-export interface TableCellProps {
- /**
- * Set the text-align on the table cell content.
- */
- align?: TableCellAlign;
- /**
- * The table cell contents.
- */
- children?: React.ReactNode;
- /**
- * When provided, this will render the passed in component as the HTML element.
- * If this prop is undefined, it renders a `` element if the parent component is `TableHead`,
- * otherwise, it renders a ` ` element.
- */
- component?: TableCellComponent;
- /**
- * Additional classes to be added to the row element.
- */
- className?: string;
- /**
- * `TableCell` must define a `headers` prop for stackable tables with a ` ` element.
- * The `headers` prop associates header and data cells for screen readers.
- * `headers` consist of a list of space-separated ids that each correspond to a ` ` element.
- * [Read more about the headers attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/td#Attributes).
- */
- headers?: string;
- /**
- * `TableCell` must define an `id` prop for stackable tables with a ` ` element.
- * The `id` prop associates header and data cells for screen readers.
- */
- id?: string;
- /**
- * If this prop is undefined, the component sets a scope attribute of `col` when the parent
- * component is `TableHead` to identify the header cell is a header for a column.
- */
- scope?: TableCellScope;
- /**
- * Additional classes to be added to the stacked Title element.
- */
- stackedClassName?: string;
- /**
- * Table data cell's corresponding header title, this stacked title is displayed as the row header
- * when a responsive table is vertically stacked.
- */
- stackedTitle?: string;
- /**
- * @hide-prop This gets set from the parent `TableHead` component
- */
- _isTableHeadChild?: boolean;
-}
-
-declare const TableCell: React.FC<
- React.ComponentPropsWithRef<'th'> &
- React.ComponentPropsWithRef<'td'> &
- TableCellProps
->;
-
-export default TableCell;
diff --git a/packages/design-system/src/types/Table/TableContext.d.ts b/packages/design-system/src/types/Table/TableContext.d.ts
deleted file mode 100644
index 3d3599d679..0000000000
--- a/packages/design-system/src/types/Table/TableContext.d.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as React from 'react';
-
-declare const TableContext: React.FC;
-
-export default TableContext;
diff --git a/packages/design-system/src/types/Table/TableHead.d.ts b/packages/design-system/src/types/Table/TableHead.d.ts
deleted file mode 100644
index 224f2b25cc..0000000000
--- a/packages/design-system/src/types/Table/TableHead.d.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import * as React from 'react';
-
-export interface TableHeadProps {
- /**
- * The table head contents, usually `TableRow`.
- */
- children?: React.ReactNode;
-}
-
-declare const TableHead: React.FC & TableHeadProps>;
-
-export default TableHead;
diff --git a/packages/design-system/src/types/Table/TableRow.d.ts b/packages/design-system/src/types/Table/TableRow.d.ts
deleted file mode 100644
index e1367e6abf..0000000000
--- a/packages/design-system/src/types/Table/TableRow.d.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import * as React from 'react';
-
-export interface TableRowProps {
- /**
- * The table row contents, usually `TableCell`.
- */
- children?: React.ReactNode;
- /**
- * @hide-prop This gets set from the parent `TableHead`
- */
- _isTableHeadChild?: boolean;
-}
-
-declare const TableRow: React.FC & TableRowProps>;
-
-export default TableRow;
diff --git a/packages/design-system/src/types/index.d.ts b/packages/design-system/src/types/index.d.ts
index cc01850fe0..06f63e3ade 100644
--- a/packages/design-system/src/types/index.d.ts
+++ b/packages/design-system/src/types/index.d.ts
@@ -8,12 +8,6 @@ export { default as MonthPicker, getMonthNames } from './MonthPicker/MonthPicker
export { default as Review } from './Review/Review';
export { default as SkipNav } from './SkipNav/SkipNav';
export { default as StepList } from './StepList/StepList';
-export { default as Table } from './Table/Table';
-export { default as TableBody } from './Table/TableBody';
-export { default as TableCaption } from './Table/TableCaption';
-export { default as TableCell } from './Table/TableCell';
-export { default as TableHead } from './Table/TableHead';
-export { default as TableRow } from './Table/TableRow';
export { default as Tabs } from './Tabs/Tabs';
export { default as TabPanel } from './Tabs/TabPanel';
export { default as Tooltip } from './Tooltip/Tooltip';
@@ -35,6 +29,7 @@ export * from './FormControl';
export * from './FormLabel';
export * from './InlineError';
export * from './Spinner';
+export * from './Table';
export * from './TextField';
export * from './Tooltip';
diff --git a/packages/design-system/yarn.lock b/packages/design-system/yarn.lock
index a1d7c39b61..08aa30a898 100644
--- a/packages/design-system/yarn.lock
+++ b/packages/design-system/yarn.lock
@@ -910,10 +910,10 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
-path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+path-parse@1.0.7, path-parse@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-platform@~0.11.15:
version "0.11.15"
diff --git a/packages/eslint-config-design-system/yarn.lock b/packages/eslint-config-design-system/yarn.lock
index a5f12a7e71..330a256414 100644
--- a/packages/eslint-config-design-system/yarn.lock
+++ b/packages/eslint-config-design-system/yarn.lock
@@ -597,10 +597,10 @@ path-exists@^3.0.0:
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
-path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+path-parse@1.0.7, path-parse@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-type@^2.0.0:
version "2.0.0"
diff --git a/yarn.lock b/yarn.lock
index 0e73e010e9..f578d70351 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,6 +2,13 @@
# yarn lockfile v1
+"@axe-core/webdriverjs@^4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@axe-core/webdriverjs/-/webdriverjs-4.2.2.tgz#430a3caf365e4dfa4314fe4ea644543fd5f868f3"
+ integrity sha512-h3VrFXAHAIinoHQU/u9bmLUET/gAfab3y7VpUt6HOHe4NKsk9wi+6zoM3L8yCZSWriItmK3nuVrn6byeC+/Pcw==
+ dependencies:
+ axe-core "^4.2.3"
+
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3":
version "7.8.3"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
@@ -3650,19 +3657,10 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
-axe-core@^3.3.1:
- version "3.5.5"
- resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227"
- integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q==
-
-axe-webdriverjs@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/axe-webdriverjs/-/axe-webdriverjs-2.3.0.tgz#92511fbce38624a57e1aa861dd8a3c73c6a3a972"
- integrity sha512-AuUsX5OFTXOJ6reIKjtGay4O656n5G+m8MzhfL1SC8MHINBFFFn3Taucckn8+UZYJuTtNEobllSfiuPTHyKnSA==
- dependencies:
- axe-core "^3.3.1"
- babel-runtime "^6.26.0"
- depd "^2.0.0"
+axe-core@^4.2.3:
+ version "4.3.3"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.3.tgz#b55cd8e8ddf659fe89b064680e1c6a4dceab0325"
+ integrity sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==
axios@0.19.0:
version "0.19.0"
@@ -3782,14 +3780,6 @@ babel-preset-jest@^25.5.0:
babel-plugin-jest-hoist "^25.5.0"
babel-preset-current-node-syntax "^0.1.2"
-babel-runtime@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
- integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
- dependencies:
- core-js "^2.4.0"
- regenerator-runtime "^0.11.0"
-
bach@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880"
@@ -4557,10 +4547,10 @@ chrome-trace-event@^1.0.2:
dependencies:
tslib "^1.9.0"
-chromedriver@91.0.0:
- version "91.0.0"
- resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-91.0.0.tgz#b8c07d715c1bde2ed5817757e923bd65565c8f94"
- integrity sha512-0eQGLDWvfVd1apkqQpt4452bCATrsj50whhVzMqPiazNSfCXXwfYWRonYxx3DVFCG3+RwSCLvsk8/vpuojCyJA==
+chromedriver@93.0.0:
+ version "93.0.0"
+ resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-93.0.0.tgz#6c136a074248b88efe5851bca7e41110aff5aeb9"
+ integrity sha512-WHntgiZf13rds6SjeFRgH02prad8k+wWrQSaj5QPi0kaNJUukdJNDJG7pn8OshWTKTJZ6oqgvMQ1mvnIIBY5GQ==
dependencies:
"@testim/chrome-version" "^1.0.7"
axios "^0.21.1"
@@ -4906,11 +4896,6 @@ compare-func@^1.3.1:
array-ify "^1.0.0"
dot-prop "^3.0.0"
-compare-versions@^3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62"
- integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==
-
component-bind@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
@@ -5159,11 +5144,6 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^2.4.0:
- version "2.6.11"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
- integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
-
core-js@^3.5.0, core-js@^3.6.5:
version "3.6.5"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
@@ -5769,11 +5749,6 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
-depd@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
- integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
-
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@@ -7193,13 +7168,6 @@ find-up@^4.0.0, find-up@^4.1.0:
locate-path "^5.0.0"
path-exists "^4.0.0"
-find-versions@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e"
- integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==
- dependencies:
- semver-regex "^2.0.0"
-
findup-sync@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
@@ -8502,21 +8470,10 @@ humanize-ms@^1.2.1:
dependencies:
ms "^2.0.0"
-husky@^4.2.5:
- version "4.2.5"
- resolved "https://registry.yarnpkg.com/husky/-/husky-4.2.5.tgz#2b4f7622673a71579f901d9885ed448394b5fa36"
- integrity sha512-SYZ95AjKcX7goYVZtVZF2i6XiZcHknw50iXvY7b0MiGoj5RwdgRQNEHdb+gPDPCXKlzwrybjFjkL6FOj8uRhZQ==
- dependencies:
- chalk "^4.0.0"
- ci-info "^2.0.0"
- compare-versions "^3.6.0"
- cosmiconfig "^6.0.0"
- find-versions "^3.2.0"
- opencollective-postinstall "^2.0.2"
- pkg-dir "^4.2.0"
- please-upgrade-node "^3.2.0"
- slash "^3.0.0"
- which-pm-runs "^1.0.0"
+husky@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.1.tgz#579f4180b5da4520263e8713cc832942b48e1f1c"
+ integrity sha512-gceRaITVZ+cJH9sNHqx5tFwbzlLCVxtVZcusME8JYQ8Edy5mpGDOqD8QBCdMhpyo9a+JXddnujQ4rpY2Ff9SJA==
iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@~0.4.13:
version "0.4.24"
@@ -9989,9 +9946,9 @@ jsx-ast-utils@^2.2.1, jsx-ast-utils@^2.2.3:
object.assign "^4.1.0"
jszip@^3.2.2:
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.5.0.tgz#b4fd1f368245346658e781fec9675802489e15f6"
- integrity sha512-WRtu7TPCmYePR1nazfrtuF216cIVon/3GWOvHS9QR5bIwSbnxtdpma6un3jyGGNhHsKCSzn5Ypk+EkDRvTGiFA==
+ version "3.7.1"
+ resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.7.1.tgz#bd63401221c15625a1228c556ca8a68da6fda3d9"
+ integrity sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
@@ -11874,11 +11831,6 @@ onetime@^5.1.0:
dependencies:
mimic-fn "^2.1.0"
-opencollective-postinstall@^2.0.2:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz#5657f1bede69b6e33a45939b061eb53d3c6c3a89"
- integrity sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==
-
openurl@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387"
@@ -12311,9 +12263,9 @@ path-key@^3.0.0, path-key@^3.1.0:
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.6:
- version "1.0.6"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
- integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-root-regex@^0.1.0:
version "0.1.2"
@@ -13654,11 +13606,6 @@ regenerate@^1.4.0:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
-regenerator-runtime@^0.11.0:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
- integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-
regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5:
version "0.13.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
@@ -14234,11 +14181,6 @@ semver-greatest-satisfied-range@^1.1.0:
dependencies:
sver-compat "^1.5.0"
-semver-regex@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338"
- integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==
-
"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
@@ -16536,11 +16478,6 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which-pm-runs@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
- integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=
-
which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"