diff --git a/package-lock.json b/package-lock.json
index 6da10054600..cfe8299300e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3075,9 +3075,9 @@
}
},
"node_modules/@formatjs/ts-transformer/node_modules/@types/node": {
- "version": "16.18.94",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.94.tgz",
- "integrity": "sha512-X8q3DoKq8t/QhA0Rk/9wJUajxtXRDiCK+cVaONKLxpsjPhu+xX6uZuEj4UKGLQ4p0obTdFxa0cP/BMvf9mOYZA==",
+ "version": "16.18.96",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.96.tgz",
+ "integrity": "sha512-84iSqGXoO+Ha16j8pRZ/L90vDMKX04QTYMTfYeE1WrjWaZXuchBehGUZEpNgx7JnmlrIHdnABmpjrQjhCnNldQ==",
"dev": true
},
"node_modules/@formatjs/ts-transformer/node_modules/ansi-styles": {
@@ -8736,23 +8736,23 @@
}
},
"node_modules/@testing-library/dom": {
- "version": "9.3.4",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz",
- "integrity": "sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.0.0.tgz",
+ "integrity": "sha512-PmJPnogldqoVFf+EwbHvbBJ98MmqASV8kLrBYgsDNxQcFMeIS7JFL48sfyXvuMtgmWO/wMhh25odr+8VhDmn4g==",
"dev": true,
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"@babel/runtime": "^7.12.5",
"@types/aria-query": "^5.0.1",
- "aria-query": "5.1.3",
+ "aria-query": "5.3.0",
"chalk": "^4.1.0",
"dom-accessibility-api": "^0.5.9",
"lz-string": "^1.5.0",
"pretty-format": "^27.0.2"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
}
},
"node_modules/@testing-library/dom/node_modules/ansi-styles": {
@@ -9141,9 +9141,9 @@
"dev": true
},
"node_modules/@types/aws-lambda": {
- "version": "8.10.136",
- "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.136.tgz",
- "integrity": "sha512-cmmgqxdVGhxYK9lZMYYXYRJk6twBo53ivtXjIUEFZxfxe4TkZTZBK3RRWrY2HjJcUIix0mdifn15yjOAat5lTA==",
+ "version": "8.10.137",
+ "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.137.tgz",
+ "integrity": "sha512-YNFwzVarXAOXkjuFxONyDw1vgRNzyH8AuyN19s0bM+ChSu/bzxb5XPxYFLXoqoM+tvgzwR3k7fXcEOW125yJxg==",
"dev": true
},
"node_modules/@types/babel__core": {
@@ -9313,9 +9313,9 @@
}
},
"node_modules/@types/express-serve-static-core": {
- "version": "4.17.43",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz",
- "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==",
+ "version": "4.19.0",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz",
+ "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
@@ -9789,9 +9789,9 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "20.12.4",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.4.tgz",
- "integrity": "sha512-E+Fa9z3wSQpzgYQdYmme5X3OTuejnnTx88A6p6vkkJosR3KBz+HpE3kqNm98VE6cfLFcISx7zW7MsJkH6KwbTw==",
+ "version": "20.12.6",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.6.tgz",
+ "integrity": "sha512-3KurE8taB8GCvZBPngVbp0lk5CKi8M9f9k1rsADh0Evdz5SzJ+Q+Hx9uHoFGsLnLnd1xmkDQr2hVhlA0Mn0lKQ==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -9863,9 +9863,9 @@
"dev": true
},
"node_modules/@types/react": {
- "version": "18.2.74",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.74.tgz",
- "integrity": "sha512-9AEqNZZyBx8OdZpxzQlaFEVCSFUM2YXJH46yPOiOpm078k6ZLOCcuAzGum/zK8YBwY+dbahVNbHrbgrAwIRlqw==",
+ "version": "18.2.75",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.75.tgz",
+ "integrity": "sha512-+DNnF7yc5y0bHkBTiLKqXFe+L4B3nvOphiMY3tuA5X10esmjqk7smyBZzbGTy2vsiy/Bnzj8yFIBL8xhRacoOg==",
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -10284,9 +10284,9 @@
}
},
"node_modules/@wdio/cli/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -10649,9 +10649,9 @@
}
},
"node_modules/@wdio/reporter/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -10789,9 +10789,9 @@
}
},
"node_modules/@wdio/sync/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -11160,9 +11160,9 @@
}
},
"node_modules/@wdio/types/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -11863,12 +11863,12 @@
}
},
"node_modules/aria-query": {
- "version": "5.1.3",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz",
- "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==",
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
+ "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
"dev": true,
"dependencies": {
- "deep-equal": "^2.0.5"
+ "dequal": "^2.0.3"
}
},
"node_modules/array-buffer-byte-length": {
@@ -12277,9 +12277,9 @@
"optional": true
},
"node_modules/aws-sdk": {
- "version": "2.1592.0",
- "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1592.0.tgz",
- "integrity": "sha512-iwmS46jOEHMNodfrpNBJ5eHwjKAY05t/xYV2cp+KyzMX2yGgt2/EtWWnlcoMGBKR31qKTsjMj5ZPouC9/VeDOA==",
+ "version": "2.1595.0",
+ "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1595.0.tgz",
+ "integrity": "sha512-ee0FaplSMz9Y6XJnnyDCHv6SLziJ2YCI4SsO0VRFUKK4Jtk/KErp20CJI/4ZsS+oz7k2/vQ3JqGQXCz95nU8Ww==",
"dev": true,
"hasInstallScript": true,
"optional": true,
@@ -13070,9 +13070,9 @@
"dev": true
},
"node_modules/builtins": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
- "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz",
+ "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==",
"dev": true,
"dependencies": {
"semver": "^7.0.0"
@@ -13752,9 +13752,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001605",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz",
- "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==",
+ "version": "1.0.30001607",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001607.tgz",
+ "integrity": "sha512-WcvhVRjXLKFB/kmOFVwELtMxyhq3iM/MvmXcyCe2PNf166c39mptscOc/45TTS96n2gpNV2z7+NakArTWZCQ3w==",
"dev": true,
"funding": [
{
@@ -15454,38 +15454,6 @@
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==",
"dev": true
},
- "node_modules/deep-equal": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
- "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
- "dev": true,
- "dependencies": {
- "array-buffer-byte-length": "^1.0.0",
- "call-bind": "^1.0.5",
- "es-get-iterator": "^1.1.3",
- "get-intrinsic": "^1.2.2",
- "is-arguments": "^1.1.1",
- "is-array-buffer": "^3.0.2",
- "is-date-object": "^1.0.5",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "isarray": "^2.0.5",
- "object-is": "^1.1.5",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.5.1",
- "side-channel": "^1.0.4",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -15751,9 +15719,9 @@
"dev": true
},
"node_modules/devtools/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -16257,9 +16225,9 @@
}
},
"node_modules/electron-to-chromium": {
- "version": "1.4.726",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.726.tgz",
- "integrity": "sha512-xtjfBXn53RORwkbyKvDfTajtnTp0OJoPOIBzXvkNbb7+YYvCHJflba3L7Txyx/6Fov3ov2bGPr/n5MTixmPhdQ==",
+ "version": "1.4.730",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.730.tgz",
+ "integrity": "sha512-oJRPo82XEqtQAobHpJIR3zW5YO3sSRRkPz2an4yxi1UvqhsGm54vR/wzTFV74a3soDOJ8CKW7ajOOX5ESzddwg==",
"dev": true
},
"node_modules/email-addresses": {
@@ -16384,9 +16352,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.11.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.1.tgz",
- "integrity": "sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==",
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.12.0.tgz",
+ "integrity": "sha512-Iw9rQJBGpJRd3rwXm9ft/JiGoAZmLxxJZELYDQoPRZ4USVhkKtIcNBPw6U+/K2mBpaqM25JSV6Yl4Az9vO2wJg==",
"dev": true,
"bin": {
"envinfo": "dist/cli.js"
@@ -16627,26 +16595,6 @@
"node": ">= 0.4"
}
},
- "node_modules/es-get-iterator": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
- "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "is-arguments": "^1.1.1",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.7",
- "isarray": "^2.0.5",
- "stop-iteration-iterator": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/es-iterator-helpers": {
"version": "1.0.18",
"resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
@@ -17142,15 +17090,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
}
},
- "node_modules/eslint-plugin-jsx-a11y/node_modules/aria-query": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
- "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
- "dependencies": {
- "dequal": "^2.0.3"
- }
- },
"node_modules/eslint-plugin-jsx-a11y/node_modules/axe-core": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
@@ -18659,9 +18598,9 @@
"dev": true
},
"node_modules/focus-lock": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.4.tgz",
- "integrity": "sha512-Gv0N3mvej3pD+HWkNryrF8sExzEHqhQ6OSFxD4DPxm9n5HGCaHme98ZMBZroNEAJcsdtHxk+skvThGKyUeoEGA==",
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-1.3.5.tgz",
+ "integrity": "sha512-QFaHbhv9WPUeLYBDe/PAuLKJ4Dd9OPvKs9xZBr3yLXnUrDNaVXKu2baDBXe3naPY30hgHYSsf2JW4jzas2mDEQ==",
"dependencies": {
"tslib": "^2.0.3"
},
@@ -21087,6 +21026,7 @@
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
"dev": true,
+ "optional": true,
"dependencies": {
"call-bind": "^1.0.2",
"has-tostringtag": "^1.0.0"
@@ -34291,18 +34231,6 @@
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"dev": true
},
- "node_modules/stop-iteration-iterator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
- "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
- "dev": true,
- "dependencies": {
- "internal-slot": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
"node_modules/stream-buffers": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-3.0.2.tgz",
@@ -38059,9 +37987,9 @@
}
},
"node_modules/webdriver/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -38106,9 +38034,9 @@
}
},
"node_modules/webdriverio/node_modules/@types/node": {
- "version": "18.19.29",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.29.tgz",
- "integrity": "sha512-5pAX7ggTmWZdhUrhRWLPf+5oM7F80bcKVCBbr0zwEkTNzTJL2CWQjznpFgHYy6GrzkYi2Yjy7DHKoynFxqPV8g==",
+ "version": "18.19.31",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz",
+ "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
@@ -38132,15 +38060,6 @@
"node": ">= 10"
}
},
- "node_modules/webdriverio/node_modules/aria-query": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
- "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
- "dev": true,
- "dependencies": {
- "dequal": "^2.0.3"
- }
- },
"node_modules/webdriverio/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
diff --git a/packages/terra-framework-docs/CHANGELOG.md b/packages/terra-framework-docs/CHANGELOG.md
index e8882335bed..74cd0854e21 100644
--- a/packages/terra-framework-docs/CHANGELOG.md
+++ b/packages/terra-framework-docs/CHANGELOG.md
@@ -3,6 +3,7 @@
## Unreleased
* Added
+ * Added documentation for subsections in `terra-table`.
* Added examples and tests for `isAutoFocusEnabled` prop for `terra-data-grid`.
* Changed
diff --git a/packages/terra-framework-docs/src/terra-dev-site/doc/table/About.1.doc.mdx b/packages/terra-framework-docs/src/terra-dev-site/doc/table/About.1.doc.mdx
index 45f2e193190..46070ca1b72 100644
--- a/packages/terra-framework-docs/src/terra-dev-site/doc/table/About.1.doc.mdx
+++ b/packages/terra-framework-docs/src/terra-dev-site/doc/table/About.1.doc.mdx
@@ -45,27 +45,27 @@ See the following example of a default table:
* [Column Error Indicator](/components/cerner-terra-framework-docs/table/examples/table-column-states)
## Examples
-|Link to Example| Description|
-|-|-|
-|[Default Table](/components/cerner-terra-framework-docs/table/examples/default-table)|An example demonstrating a basic table populated with tabular information and no interactive elements.|
-|[Auto Layout Table](/components/cerner-terra-framework-docs/table/examples/auto-layout-table)|An example demonstrating a basic with tabular information and no interactive elements using the auto layout for column widths.|
-|[Zebra Striped Table](/components/cerner-terra-framework-docs/table/examples/zebra-striped-table)|An example demonstrating the ability to enable zebra striping for table rows.|
-|[Pinned Columns](/components/cerner-terra-framework-docs/table/examples/pinned-columns)|An example demonstrating pinned columns (frozen leftmost columns) and overflow columns.|
-|[Sortable Table](/components/cerner-terra-framework-docs/table/examples/sortable-table)|An example demonstrating how to enable sorting on a table. Heading cells of sortable columns are interactive and include an icon indicating sort direction.|
-|[Table Column States](/components/cerner-terra-framework-docs/table/examples/table-column-states)|An example demonstrating column states and interactions such as an error or sort. Header cells include an icon that represents the state of the information in the column.|
-|[Table with Focusable Cells](/components/cerner-terra-framework-docs/table/examples/table-focusable-cell)|An example demonstrating tab stop behavior on a table with interactive elements. Each tabbable element on a table is a separate tab stop.|
-|[Single Row Selection](/components/cerner-terra-framework-docs/table/examples/table-single-row-selection)|An example demonstrating a table with single row selection mode. Consumers control the selection state with the **onRowSelect** callback and **isSelected** row property.|
-|[Multiple Row Selection](/components/cerner-terra-framework-docs/table/examples/table-multiple-row-selection)|An example demonstrating a table with multiple row selection mode. Consumers control the selection state with the **onRowSelect** callback and **isSelected** row property.|
-|[Table with Sections](/components/cerner-terra-framework-docs/table/examples/table-with-sections)|An example demonstrating how to create a table with sections.|
-|[Table Without Headers](/components/cerner-terra-framework-docs/table/examples/table-without-headers)|An example demonstrating how to hide table column headers. The column headers still exist in the Document Object Model (DOM) for accessibility.|
+| Link to Example | Description |
+| ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Default Table](/components/cerner-terra-framework-docs/table/examples/default-table) | An example demonstrating a basic table populated with tabular information and no interactive elements. |
+| [Auto Layout Table](/components/cerner-terra-framework-docs/table/examples/auto-layout-table) | An example demonstrating a basic with tabular information and no interactive elements using the auto layout for column widths. |
+| [Zebra Striped Table](/components/cerner-terra-framework-docs/table/examples/zebra-striped-table) | An example demonstrating the ability to enable zebra striping for table rows. |
+| [Pinned Columns](/components/cerner-terra-framework-docs/table/examples/pinned-columns) | An example demonstrating pinned columns (frozen leftmost columns) and overflow columns. |
+| [Sortable Table](/components/cerner-terra-framework-docs/table/examples/sortable-table) | An example demonstrating how to enable sorting on a table. Heading cells of sortable columns are interactive and include an icon indicating sort direction. |
+| [Table Column States](/components/cerner-terra-framework-docs/table/examples/table-column-states) | An example demonstrating column states and interactions such as an error or sort. Header cells include an icon that represents the state of the information in the column. |
+| [Table with Focusable Cells](/components/cerner-terra-framework-docs/table/examples/table-focusable-cell) | An example demonstrating tab stop behavior on a table with interactive elements. Each tabbable element on a table is a separate tab stop. |
+| [Single Row Selection](/components/cerner-terra-framework-docs/table/examples/table-single-row-selection) | An example demonstrating a table with single row selection mode. Consumers control the selection state with the **onRowSelect** callback and **isSelected** row property. |
+| [Multiple Row Selection](/components/cerner-terra-framework-docs/table/examples/table-multiple-row-selection) | An example demonstrating a table with multiple row selection mode. Consumers control the selection state with the **onRowSelect** callback and **isSelected** row property. |
+| [Table with Sections](/components/cerner-terra-framework-docs/table/examples/table-with-sections) | An example demonstrating how to create a table with sections. |
+| [Table Without Headers](/components/cerner-terra-framework-docs/table/examples/table-without-headers) | An example demonstrating how to hide table column headers. The column headers still exist in the Document Object Model (DOM) for accessibility. |
## Accessibility
### Keyboard Interactions
-|Keys|Description|
-|---|---|
-|HOME| Selects the first element on the table when the currently active element is not editable.|
-|END | Selects the last element on the table when the currently active element is not editable.|
+| Keys | Description |
+| ---- | ----------------------------------------------------------------------------------------- |
+| HOME | Selects the first element on the table when the currently active element is not editable. |
+| END | Selects the last element on the table when the currently active element is not editable. |
### Assistive Technology Support
#### WAI ARIA Roles and States
@@ -112,33 +112,33 @@ In addition, ensure that you memoize callback functions using methods such as th
### Table Constants
Enumeration: TableConstants
-|Constant|Type|Description|
-|---|---|---|
-|**ROW_SELECTION_COLUMN_WIDTH**|Number|The width of the row selection column.|
-|**TABLE_MARGIN_RIGHT**|Number|The margin right of the table to allow resizing of the last column.|
+| Constant | Type | Description |
+| ------------------------------ | ------ | ------------------------------------------------------------------- |
+| **ROW_SELECTION_COLUMN_WIDTH** | Number | The width of the row selection column. |
+| **TABLE_MARGIN_RIGHT** | Number | The margin right of the table to allow resizing of the last column. |
Enumeration: RowSelectionModes
-|Constant|Type|Description|
-|---|---|---|
-|**SINGLE**|String|Single row selection mode.|
-|**MULTIPLE**|String|Multiple row selection mode.|
+| Constant | Type | Description |
+| ------------ | ------ | ---------------------------- |
+| **SINGLE** | String | Single row selection mode. |
+| **MULTIPLE** | String | Multiple row selection mode. |
### Column
A column specifies the information to render a cell in the header row of the Worklist Data Grid component.
-|Name|Type|Required|Default Value|Description|
-|---|---|---|---|---|
-|**id**|String|Required|None|An identifier to uniquely identify the column in the grid.|
-|**displayName**|String|Optional|None|A string of text to render in the column header cell.|
-|**action**|object|optional|none|An object containing label and onClick properties for column action button, which will be displayed in an additional row below the column header row.
-|**hasError**|Bool|Optional|None|A Boolean value indicating whether the column information has an error.|
-|**isResizable**|Bool|Optional|None|A Boolean value indicating whether the column header is resizable. This value is ignored when for a table with auto layout enabled.|
-|**isSelectable**|Bool|Optional|None|A Boolean value indicating whether the column header is selectable.|
-|**minimumWidth**|Number|Optional|None|A number that specifies the minimum column width in pixels.|
-|**maximumWidth**|Number|Optional|None|A number that specifies the maximum column width in pixels.|
-|**width**|unionOf: [type: 'number',type: 'string',],|Optional|None|The width can be either a numeric or string value. When a number is provided, it is the number (in px) specifying the width of the column. If not provided, the Table's default column width will be used. When a string is provided, it specifies the default column width and can be any valid CSS width value|
-|**sortIndicator**|Custom|Optional|None|A string indicating which sorting indicator is rendered (`ascending` or `descending`). A sorting indicator is rendered only if a value is provided.
+| Name | Type | Required | Default Value | Description |
+| ----------------- | ------------------------------------------ | ----------------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **id** | String | Required | None | An identifier to uniquely identify the column in the grid. |
+| **displayName** | String | Optional | None | A string of text to render in the column header cell. |
+| **action** | object | optional | none | An object containing label and onClick properties for column action button, which will be displayed in an additional row below the column header row. |
+| **hasError** | Bool | Optional | None | A Boolean value indicating whether the column information has an error. |
+| **isResizable** | Bool | Optional | None | A Boolean value indicating whether the column header is resizable. This value is ignored when for a table with auto layout enabled. |
+| **isSelectable** | Bool | Optional | None | A Boolean value indicating whether the column header is selectable. |
+| **minimumWidth** | Number | Optional | None | A number that specifies the minimum column width in pixels. |
+| **maximumWidth** | Number | Optional | None | A number that specifies the maximum column width in pixels. |
+| **width** | unionOf: [type: 'number',type: 'string',], | Optional | None | The width can be either a numeric or string value. When a number is provided, it is the number (in px) specifying the width of the column. If not provided, the Table's default column width will be used. When a string is provided, it specifies the default column width and can be any valid CSS width value |
+| **sortIndicator** | Custom | Optional | None | A string indicating which sorting indicator is rendered (`ascending` or `descending`). A sorting indicator is rendered only if a value is provided. |
### Section
@@ -147,32 +147,45 @@ Due to poor support in Apple VoiceOver for spanned table headings, Table compone
A section defines the rows rendered in the section.
-|Name|Type|Required|Default Value|Description|
-|---|---|---|---|---|
-|**id**|String|Required|None|An identifier to uniquely identify the section in the grid.|
-|**isCollapsible**|Bool|Optional|False|A Boolean value indicating whether the the section is collapsible.|
-|**isCollapsed**|Bool|Optional|False|A Boolean value indicating whether the section is collapsed. If true, the contents of the section is not displayed.|
-|**text**|String|Optional|None|A text string to render in the section header.|
-|**rows**|Array|Optional|[]|An array of row objects to be rendered in the section.|
+| Name | Type | Required | Default Value | Description |
+| ----------------- | ------ | ----------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------- |
+| **id** | String | Required | None | An identifier to uniquely identify the section in the grid. |
+| **isCollapsible** | Bool | Optional | False | A Boolean value indicating whether the the section is collapsible. |
+| **isCollapsed** | Bool | Optional | False | A Boolean value indicating whether the section is collapsed. If true, the contents of the section is not displayed. |
+| **text** | String | Optional | None | A text string to render in the section header. |
+| **rows** | Array | Optional | [] | An array of row objects to be rendered in the section. |
+| **subsections** | Array | Optional | [] | An array of subsections objects to be rendered within the section. |
+
+#### Subsection
+
+Subsections objects are virtually identical to section objects.
+
+| Name | Type | Required | Default Value | Description |
+| ----------------- | ------ | ----------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------- |
+| **id** | String | Required | None | An identifier to uniquely identify the subsection in the grid. |
+| **isCollapsible** | Bool | Optional | False | A Boolean value indicating whether the the subsection is collapsible. |
+| **isCollapsed** | Bool | Optional | False | A Boolean value indicating whether the subsection is collapsed. If true, the contents of the subsection is not displayed. |
+| **text** | String | Optional | None | A text string to render in the subsection header. |
+| **rows** | Array | Optional | [] | An array of row objects to be rendered in the subsection. |
### Row
A row defines the cells rendered in the row.
-|Name|Type|Required|Default Value|Description|
-|---|---|---|---|---|
-|**id**|String|Required|None|An identifier to uniquely identify the row in the grid.|
-|**cells**|Array|Optional|[]|An array of cell objects that define the content to be rendered in the row. Cells are rendered in the order given and are expected to match the column order.|
-|**isSelected**|Bool|Optional|None|A Boolean value indicating whether the row is rendered as selected.|
-|**ariaLabel**|String|Optional|None|A string identifier used to describe the row contents. This value is used for accessibility when announcing the row selection or deselection.|
+| Name | Type | Required | Default Value | Description |
+| -------------- | ------ | ----------------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **id** | String | Required | None | An identifier to uniquely identify the row in the grid. |
+| **cells** | Array | Optional | [] | An array of cell objects that define the content to be rendered in the row. Cells are rendered in the order given and are expected to match the column order. |
+| **isSelected** | Bool | Optional | None | A Boolean value indicating whether the row is rendered as selected. |
+| **ariaLabel** | String | Optional | None | A string identifier used to describe the row contents. This value is used for accessibility when announcing the row selection or deselection. |
### Cell
A cell defines the content rendered at the intersection of a row and a column.
-|Name|Type|Required|Default Value|Description|
-|---|---|---|---|---|
-|**content**|Content|Optional|None|The content to render in the cell.|
-|**isMasked**|Bool|Optional|None|A Boolean value indicating whether the cell content is masked.|
-|**maskedLabel**|Bool|Optional|None|A Boolean value that provides a custom string for screen readers to read masked cells. This value is only applied if the cell is masked.|
+| Name | Type | Required | Default Value | Description |
+| --------------- | ------- | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
+| **content** | Content | Optional | None | The content to render in the cell. |
+| **isMasked** | Bool | Optional | None | A Boolean value indicating whether the cell content is masked. |
+| **maskedLabel** | Bool | Optional | None | A Boolean value that provides a custom string for screen readers to read masked cells. This value is only applied if the cell is masked. |
## Terra Standards
* [Cross-Browser Support](https://engineering.cerner.com/terra-ui/about/terra-ui/component-standards#cross-browser-support)
diff --git a/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithCollapsibleSectionsAndSubSections.test.jsx b/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithCollapsibleSectionsAndSubSections.test.jsx
new file mode 100644
index 00000000000..015c318f621
--- /dev/null
+++ b/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithCollapsibleSectionsAndSubSections.test.jsx
@@ -0,0 +1,172 @@
+import React, { useState } from 'react';
+import Table from 'terra-table';
+
+const tableData = {
+ cols: [
+ {
+ id: 'Column-0', displayName: 'Patient', sortIndicator: 'ascending', isSelectable: true,
+ },
+ {
+ id: 'Column-1', displayName: 'Location', isSelectable: true,
+ },
+ { id: 'Column-2', displayName: 'Illness Severity', isSelectable: true },
+ { id: 'Column-3', displayName: 'Visit' },
+ { id: 'Column-4', displayName: 'Allergy' },
+ { id: 'Column-5', displayName: 'Primary Contact' },
+
+ ],
+ sections: [{
+ id: 'section-0',
+ isCollapsible: true,
+ isCollapsed: true,
+ text: 'Test Section',
+ subsections: [
+ {
+ id: 'subsection-0',
+ text: 'Test SubSection',
+ rows: [
+ {
+ id: '1',
+ cells: [
+ { content: 'Fleck, Arthur' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Quinzell, Harleen' },
+ ],
+ },
+ {
+ id: '2',
+ cells: [
+ { content: 'Wayne, Bruce' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'Grayson, Richard' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'subsection-1',
+ text: 'Test SubSection #2',
+ rows: [
+ {
+ id: '3',
+ cells: [
+ { content: 'Fleck, Arthur' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Quinzell, Harleen' },
+ ],
+ },
+ {
+ id: '4',
+ cells: [
+ { content: 'Wayne, Bruce' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'Grayson, Richard' },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'section-1',
+ isCollapsible: true,
+ isCollapsed: true,
+ text: 'Test Section #2',
+ subsections: [
+ {
+ id: 'subsection-2',
+ text: 'Test SubSection',
+ rows: [
+ {
+ id: '5',
+ cells: [
+ { content: 'Parker, Peter' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Octopus, Doctor' },
+ ],
+ },
+ {
+ id: '6',
+ cells: [
+ { content: 'Stark, Tony' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'America, Captain' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'subsection-3',
+ text: 'Test SubSection #2',
+ rows: [
+ {
+ id: '7',
+ cells: [
+ { content: 'Parker, Peter' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Octopus, Doctor' },
+ ],
+ },
+ {
+ id: '8',
+ cells: [
+ { content: 'Stark, Tony' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'America, Captain' },
+ ],
+ },
+ ],
+ },
+ ],
+ }],
+};
+
+const TableWithCollapsibleSections = () => {
+ const [tableSections, setTableSections] = useState(tableData.sections);
+
+ const handleSectionSelect = (sectionId) => {
+ const newSections = [...tableSections];
+ const sectionIndex = newSections.findIndex(section => section.id === sectionId);
+
+ if (sectionIndex > -1) {
+ newSections[sectionIndex].isCollapsed = !newSections[sectionIndex].isCollapsed;
+ }
+
+ setTableSections(newSections);
+ };
+
+ return (
+
+ );
+};
+
+export default TableWithCollapsibleSections;
diff --git a/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithSubSections.test.jsx b/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithSubSections.test.jsx
new file mode 100644
index 00000000000..7c10aedf78a
--- /dev/null
+++ b/packages/terra-framework-docs/src/terra-dev-site/test/table/TableWithSubSections.test.jsx
@@ -0,0 +1,135 @@
+import React, { useState } from 'react';
+import Table from 'terra-table';
+
+const tableData = {
+ cols: [
+ {
+ id: 'Column-0', displayName: 'Patient', sortIndicator: 'ascending', isSelectable: true,
+ },
+ {
+ id: 'Column-1', displayName: 'Location', isSelectable: true,
+ },
+ { id: 'Column-2', displayName: 'Illness Severity', isSelectable: true },
+ { id: 'Column-3', displayName: 'Visit' },
+ { id: 'Column-4', displayName: 'Allergy' },
+ { id: 'Column-5', displayName: 'Primary Contact' },
+
+ ],
+ sections: [{
+ id: 'section-0',
+ text: 'Test Section',
+ subsections: [
+ {
+ id: 'subsection-0',
+ text: 'Test SubSection',
+ rows: [
+ {
+ id: '1',
+ cells: [
+ { content: 'Fleck, Arthur' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Quinzell, Harleen' },
+ ],
+ },
+ {
+ id: '2',
+ cells: [
+ { content: 'Wayne, Bruce' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'Grayson, Richard' },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'subsection-1',
+ text: 'Test SubSection #2',
+ rows: [
+ {
+ id: '3',
+ cells: [
+ { content: 'Fleck, Arthur' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Quinzell, Harleen' },
+ ],
+ },
+ {
+ id: '4',
+ cells: [
+ { content: 'Wayne, Bruce' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'Grayson, Richard' },
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'section-1',
+ text: 'Test Section #2',
+ rows: [
+ {
+ id: '5',
+ cells: [
+ { content: 'Parker, Peter' },
+ { content: '1007-MTN' },
+ { content: 'Unstable' },
+ { content: 'Inpatient, 2 months' },
+ { content: '' },
+ { content: 'Octopus, Doctor' },
+ ],
+ },
+ {
+ id: '6',
+ cells: [
+ { content: 'Stark, Tony' },
+ { content: '1007-MTN-DR' },
+ { content: 'Stable' },
+ { content: 'Outpatient, 2 days' },
+ { content: 'Phytochemicals' },
+ { content: 'America, Captain' },
+ ],
+ },
+ ],
+ }],
+};
+
+const TableWithSections = () => {
+ const [tableSections, setTableSections] = useState(tableData.sections);
+
+ const handleSectionSelect = (sectionId) => {
+ const newSections = [...tableSections];
+ const sectionIndex = newSections.findIndex(section => section.id === sectionId);
+
+ if (sectionIndex > -1) {
+ newSections[sectionIndex].isCollapsed = !newSections[sectionIndex].isCollapsed;
+ }
+
+ setTableSections(newSections);
+ };
+
+ return (
+
+ );
+};
+
+export default TableWithSections;
diff --git a/packages/terra-table/CHANGELOG.md b/packages/terra-table/CHANGELOG.md
index 81965911f32..a6c24482713 100644
--- a/packages/terra-table/CHANGELOG.md
+++ b/packages/terra-table/CHANGELOG.md
@@ -2,6 +2,9 @@
## Unreleased
+* Added
+ * (flowsheet-data-grid only) Added support for subsections.
+
* Changed
* Updated the cell component auto focus logic to be configured by the grid context.
diff --git a/packages/terra-table/src/Table.jsx b/packages/terra-table/src/Table.jsx
index 1604bf60f78..33b49a2ca31 100644
--- a/packages/terra-table/src/Table.jsx
+++ b/packages/terra-table/src/Table.jsx
@@ -328,10 +328,18 @@ function Table(props) {
const headerRowCount = hasVisibleColumnHeaders ? (hasColumnHeaderActions ? 2 : 1) : 0;
// Calculate total table row count
+ const subSectionReducer = (rowCount, currentSubsection) => {
+ // eslint-disable-next-line no-param-reassign
+ currentSubsection.subSectionRowIndex = rowCount + 1;
+ return rowCount + currentSubsection.rows.length + 1;
+ };
const tableSectionReducer = (rowCount, currentSection) => {
if (currentSection.id !== defaultSectionRef.current) {
// eslint-disable-next-line no-param-reassign
currentSection.sectionRowIndex = rowCount + 1;
+ if (currentSection.subsections) {
+ return currentSection.subsections.reduce(subSectionReducer, rowCount + 1);
+ }
return rowCount + currentSection.rows.length + 1;
}
// eslint-disable-next-line no-param-reassign
@@ -373,7 +381,12 @@ function Table(props) {
// useEffect for row updates
useEffect(() => {
const previousSelectedRows = [...selectedRows.current];
- const selectableRows = tableSections.flatMap(section => (section.rows.map(row => (row))));
+ const selectableRows = tableSections.flatMap(section => {
+ if (section.subsections) {
+ return section.subsections.flatMap(subsection => (subsection.rows.map(row => (row))));
+ }
+ return section.rows.map(row => (row));
+ });
selectedRows.current = selectableRows.filter((row) => row.isSelected).map(row => (row.id));
if (previousSelectedRows.length > 0 && selectedRows.current.length === 0) {
@@ -685,6 +698,7 @@ function Table(props) {
isTableStriped={isStriped}
text={section.text}
rows={section.rows}
+ subsections={section.subsections}
rowHeight={rowHeight}
rowSelectionMode={rowSelectionMode}
displayedColumns={displayedColumns}
diff --git a/packages/terra-table/src/clinical-lowlight-theme/Section.module.scss b/packages/terra-table/src/clinical-lowlight-theme/Section.module.scss
index 34bf413272a..f721115a197 100644
--- a/packages/terra-table/src/clinical-lowlight-theme/Section.module.scss
+++ b/packages/terra-table/src/clinical-lowlight-theme/Section.module.scss
@@ -3,5 +3,8 @@
--terra-table-cell-border-left: 1px solid #181b1d;
--terra-table-cell-border-right: 1px solid #181b1d;
--terra-table-section-focus-outline: 3px dashed #fff;
+
+ --terra-table-subsection-border-bottom: #161616;
+ --terra-section-header-background: #161616;
}
}
diff --git a/packages/terra-table/src/orion-fusion-theme/Section.module.scss b/packages/terra-table/src/orion-fusion-theme/Section.module.scss
index 188af1b770a..802a8d788c2 100644
--- a/packages/terra-table/src/orion-fusion-theme/Section.module.scss
+++ b/packages/terra-table/src/orion-fusion-theme/Section.module.scss
@@ -2,6 +2,7 @@
.orion-fusion-theme {
--terra-table-cell-border-left: 1px solid #c8cacb;
--terra-table-cell-border-right: 1px solid #c8cacb;
+ --terra-section-header-font-size: 1rem;
/* stylelint-disable selector-max-compound-selectors */
&.header-row {
@@ -15,6 +16,5 @@
--terra-table-section-focus-outline: none;
}
}
- /* stylelint-enable selector-max-compound-selectors */
}
}
diff --git a/packages/terra-table/src/proptypes/sectionShape.js b/packages/terra-table/src/proptypes/sectionShape.js
index f0d930090f1..983f56365c1 100644
--- a/packages/terra-table/src/proptypes/sectionShape.js
+++ b/packages/terra-table/src/proptypes/sectionShape.js
@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import rowShape from './rowShape';
+import subsectionShape from './subsectionShape';
const sectionShape = PropTypes.shape({
/**
@@ -22,6 +23,10 @@ const sectionShape = PropTypes.shape({
* An array of row objects to be rendered within the section.
*/
rows: PropTypes.arrayOf(rowShape),
+ /**
+ * An array of subsections objects to be rendered within the section.
+ */
+ subsections: PropTypes.arrayOf(subsectionShape),
});
export default sectionShape;
diff --git a/packages/terra-table/src/proptypes/subsectionShape.js b/packages/terra-table/src/proptypes/subsectionShape.js
new file mode 100644
index 00000000000..8b8569ce3e0
--- /dev/null
+++ b/packages/terra-table/src/proptypes/subsectionShape.js
@@ -0,0 +1,19 @@
+import PropTypes from 'prop-types';
+import rowShape from './rowShape';
+
+const sectionShape = PropTypes.shape({
+ /**
+ * An identifier for the section. This identifier should be unique across the set of sections provided.
+ */
+ id: PropTypes.string.isRequired,
+ /**
+ * A text string to render within the section header.
+ */
+ text: PropTypes.string,
+ /**
+ * An array of row objects to be rendered within the section.
+ */
+ rows: PropTypes.arrayOf(rowShape),
+});
+
+export default sectionShape;
diff --git a/packages/terra-table/src/proptypes/validators.js b/packages/terra-table/src/proptypes/validators.js
index 2661dcf9e7b..34a2f5d1c1a 100644
--- a/packages/terra-table/src/proptypes/validators.js
+++ b/packages/terra-table/src/proptypes/validators.js
@@ -1,4 +1,4 @@
-import ERRORS from '../utils/constants';
+import { ERRORS } from '../utils/constants';
// eslint-disable-next-line consistent-return
const validateRowHeaderIndex = (props) => {
diff --git a/packages/terra-table/src/subcomponents/Cell.jsx b/packages/terra-table/src/subcomponents/Cell.jsx
index 62d3f0b1d80..6ade8ca9f9e 100644
--- a/packages/terra-table/src/subcomponents/Cell.jsx
+++ b/packages/terra-table/src/subcomponents/Cell.jsx
@@ -47,6 +47,11 @@ const propTypes = {
*/
sectionId: PropTypes.string,
+ /**
+ * An identifier for the subsection.
+ */
+ subsectionId: PropTypes.string,
+
/**
* Unique identifier for the parent table
*/
@@ -172,6 +177,7 @@ function Cell(props) {
rowIndex,
rowMinimumHeight,
sectionId,
+ subsectionId,
tableId,
firstRowId,
lastRowId,
@@ -255,6 +261,7 @@ function Cell(props) {
if (!isFocusTrapEnabled) {
onCellSelect({
sectionId,
+ subsectionId,
rowId,
rowIndex: (rowIndex - 1),
columnId,
@@ -318,6 +325,7 @@ function Cell(props) {
}
onCellSelect({
sectionId,
+ subsectionId,
rowId,
rowIndex: (rowIndex - 1),
columnId,
@@ -387,6 +395,7 @@ function Cell(props) {
const columnHeaderId = `${tableId}-${columnId}-headerCell`;
const rowHeaderId = !isRowHeader && rowHeaderIndex !== -1 ? `${tableId}-rowheader-${rowId} ` : '';
const sectionHeaderId = sectionId ? `${tableId}-${sectionId} ` : '';
+ const subsectionHeaderId = subsectionId ? `${tableId}-${sectionId}-${subsectionId} ` : '';
let columnHighlight = {};
if (columnHighlightColor) {
@@ -414,7 +423,7 @@ function Cell(props) {
ref={isGridContext || rowSelectionMode ? cellRef : undefined}
aria-selected={isSelected || undefined}
aria-label={ariaLabel}
- headers={`${sectionHeaderId}${rowHeaderId}${columnHeaderId}`}
+ headers={`${sectionHeaderId}${subsectionHeaderId}${rowHeaderId}${columnHeaderId}`}
tabIndex={isGridContext ? -1 : undefined}
className={className}
onMouseDown={onCellSelect ? handleMouseDown : undefined}
diff --git a/packages/terra-table/src/subcomponents/Row.jsx b/packages/terra-table/src/subcomponents/Row.jsx
index 1f138ece6e9..7394cb50436 100644
--- a/packages/terra-table/src/subcomponents/Row.jsx
+++ b/packages/terra-table/src/subcomponents/Row.jsx
@@ -33,6 +33,11 @@ const propTypes = {
*/
sectionId: PropTypes.string,
+ /**
+ * An identifier for the subsection.
+ */
+ subsectionId: PropTypes.string,
+
/**
* String that specifies height of the row. Any valid CSS width value is accepted.
*/
@@ -116,6 +121,7 @@ function Row(props) {
id,
tableId,
sectionId,
+ subsectionId,
isSelected,
isTableStriped,
cells,
@@ -181,6 +187,7 @@ function Row(props) {
rowIndex={rowIndex}
columnIndex={cellColumnIndex}
sectionId={sectionId}
+ subsectionId={subsectionId}
tableId={tableId}
key={`${id}_${columnId}`}
isSelected={!rowSelectionMode && cellData.isSelected}
diff --git a/packages/terra-table/src/subcomponents/Section.jsx b/packages/terra-table/src/subcomponents/Section.jsx
index 2be07907c8b..26af903d429 100644
--- a/packages/terra-table/src/subcomponents/Section.jsx
+++ b/packages/terra-table/src/subcomponents/Section.jsx
@@ -1,4 +1,3 @@
-// TODO: fix linter error
/* eslint-disable jsx-a11y/control-has-associated-label */
import React, { useCallback, useContext } from 'react';
@@ -8,9 +7,11 @@ import PropTypes from 'prop-types';
import SectionHeader from 'terra-section-header';
import ThemeContext from 'terra-theme-context';
import GridContext, { GridConstants } from '../utils/GridContext';
+import { SUBSECTION_HEADER_LEVEL } from '../utils/constants';
import Row from './Row';
import rowShape from '../proptypes/rowShape';
+import subsectionShape from '../proptypes/subsectionShape';
import columnShape from '../proptypes/columnShape';
import styles from './Section.module.scss';
@@ -58,6 +59,11 @@ const propTypes = {
*/
rows: PropTypes.arrayOf(rowShape),
+ /**
+ * An array of subsection objects to be rendered within the section.
+ */
+ subsections: PropTypes.arrayOf(subsectionShape),
+
/**
* Enables row selection capabilities for the table.
* Use 'single' for single row selection and 'multiple' for multi-row selection.
@@ -144,6 +150,7 @@ function Section(props) {
rowHeight,
rowHeaderIndex,
rows,
+ subsections,
onSectionSelect,
rowMinimumHeight,
boundingWidth,
@@ -162,37 +169,109 @@ function Section(props) {
onSectionSelect(id);
}, [id, onSectionSelect]);
+ const sectionHeader = (
+
+ {/* Render section rows */}
+ {!isHidden && (
+
+
+
+ |
+
+ )}
+
+ );
+
+ const rowProps = {
+ displayedColumns,
+ firstRowId,
+ height: rowHeight,
+ isTableStriped,
+ lastRowId,
+ onCellSelect,
+ rowHeaderIndex,
+ rowMinimumHeight,
+ rowSelectionMode,
+ sectionId: !isHidden ? id : undefined,
+ tableId,
+ };
+
+ if (subsections) {
+ return (
+ <>
+ {sectionHeader}
+ {!isCollapsed && subsections.map((subsection) => (
+ <>
+
+
+
+
+
+
+ |
+
+
+
+ {/* Render subsection rows */}
+ {!isCollapsed && subsection.rows.map((row, rowIndex) => (
+
+ ))}
+
+ >
+ ))}
+ >
+ );
+ }
+
return (
<>
-
- {/* Render section rows */}
- {!isHidden && (
-
-
-
- |
-
- )}
-
+ {sectionHeader}
))}
diff --git a/packages/terra-table/src/subcomponents/Section.module.scss b/packages/terra-table/src/subcomponents/Section.module.scss
index a2353edd1d0..1e0c42bd239 100644
--- a/packages/terra-table/src/subcomponents/Section.module.scss
+++ b/packages/terra-table/src/subcomponents/Section.module.scss
@@ -15,8 +15,8 @@
border-right: var(--terra-table-cell-border-right, 1px solid #dedfe0);
padding: 0;
- /* stylelint-disable selector-max-compound-selectors */
- &:focus {
+ /* stylelint-disable selector-max-compound-selectors, max-nesting-depth */
+ &:focus {
outline: none;
}
@@ -25,11 +25,23 @@
outline-offset: var(--terra-table-section-focus-outline-offset, -5px);
}
-
.section-header:focus-within {
--terra-section-header-focus-within-outline-offset: -5px;
}
+
+ .subsection-header-row{
+ // stylelint-disable-next-line terra/custom-property-namespace
+ background: var(--terra-section-header-background, #dedfe0);
+ border-bottom: var(--terra-table-subsection-border-bottom, 1px solid #c8cacb);
+
+ span {
+ // stylelint-disable-next-line terra/custom-property-namespace
+ font-size: var(--terra-section-header-font-size, 0.808571428571rem);
+ left: var(--terra-table-subsection-header-left, 1.2142857143rem);
+ }
+ }
+
/* stylelint-enable selector-max-compound-selectors */
}
}
-}
+}
\ No newline at end of file
diff --git a/packages/terra-table/src/utils/constants.js b/packages/terra-table/src/utils/constants.js
index 34a838deb3b..36aaa562337 100644
--- a/packages/terra-table/src/utils/constants.js
+++ b/packages/terra-table/src/utils/constants.js
@@ -7,4 +7,9 @@ const ERRORS = {
ACTION_ONCLICK_IS_NOT_A_FUNCTION: 'Column action onClick property type is not a function.',
};
-export default ERRORS;
+const SUBSECTION_HEADER_LEVEL = 3;
+
+export {
+ ERRORS,
+ SUBSECTION_HEADER_LEVEL,
+};
diff --git a/packages/terra-table/src/utils/tableUtils.js b/packages/terra-table/src/utils/tableUtils.js
index 9104818e45d..50d7a212632 100644
--- a/packages/terra-table/src/utils/tableUtils.js
+++ b/packages/terra-table/src/utils/tableUtils.js
@@ -15,7 +15,12 @@ const getFirstAndLastVisibleRowData = (sections) => {
return rowData;
}
- const findNotEmptyOrCollapsed = section => section.rows.length > 0 && !section.isCollapsed;
+ const findNotEmptyOrCollapsed = section => {
+ if (section.subsections) {
+ return section.subsections.length > 0 && !section.isCollapsed;
+ }
+ return section.rows.length > 0 && !section.isCollapsed;
+ };
const visibleSections = sections.filter(findNotEmptyOrCollapsed);
if (visibleSections.length < 1) {
diff --git a/packages/terra-table/tests/jest/Section.test.jsx b/packages/terra-table/tests/jest/Section.test.jsx
index f282cb3bb57..e52989d2b81 100644
--- a/packages/terra-table/tests/jest/Section.test.jsx
+++ b/packages/terra-table/tests/jest/Section.test.jsx
@@ -9,6 +9,55 @@ const tableData = {
{ id: 'Column-1', displayName: 'March 16' },
{ id: 'Column-2', displayName: 'March 17', isSelectable: false },
],
+ subsections: [
+ {
+ id: 'subsection-0',
+ text: 'Test SubSection',
+ subSectionRowIndex: 2,
+ rows: [
+ {
+ id: '1',
+ cells: [
+ { content: 'Heart Rate Monitored (bpm)', isSelectable: false },
+ { content: '' },
+ { content: '66', isMasked: true },
+ ],
+ },
+ {
+ id: '2',
+ cells: [
+ { content: 'Temperature Oral (degC)' },
+ { content: '36.7' },
+ { content: '36.9', isMasked: true },
+ ],
+ },
+ ],
+ },
+ {
+ id: 'subsection-1',
+ text: 'Test SubSection #2',
+ subSectionRowIndex: 5,
+ rows: [
+ {
+ id: '3',
+ cells: [
+ { content: 'Cardiac Index (L/min/m2)' },
+ { content: '2.25' },
+ { content: '2.28', isMasked: true },
+ ],
+ },
+ {
+ id: '4',
+ isSelected: true,
+ cells: [
+ { content: 'Oxygen Flow Rate (L/min)' },
+ { content: '63' },
+ { content: '47' },
+ ],
+ },
+ ],
+ },
+ ],
rows: [
{
id: '1',
@@ -63,6 +112,24 @@ describe('Section', () => {
expect(wrapper.find(Row)).toHaveLength(tableData.rows.length);
});
+ it('verifies that the section created is consistent with the subsections rows', () => {
+ const wrapper = enzyme.shallow(
+ ,
+ );
+
+ const subSectionReducer = (rowCount, currentSubsection) => rowCount + currentSubsection.rows.length;
+
+ // The number of rows should match the given data.
+ expect(wrapper.find(Row)).toHaveLength(tableData.subsections.reduce(subSectionReducer, 0));
+ });
+
it('verifies the rows are created with the right props', () => {
const verifyRow = (rowIndex, rowComponent, data, overflowColumns) => {
expect(rowComponent.props.displayedColumns).toEqual(overflowColumns);
@@ -93,6 +160,37 @@ describe('Section', () => {
verifyRow(2, rows.get(2), tableData.rows[2], tableData.cols);
});
+ it('verifies the rows are created with the right props when in subsections', () => {
+ const verifyRow = (rowIndex, rowComponent, data, overflowColumns, subsectionIndex) => {
+ expect(rowComponent.props.displayedColumns).toEqual(overflowColumns);
+ expect(rowComponent.props.rowSelectionMode).toBeUndefined();
+ expect(rowComponent.props.tableId).toBe('test-table');
+ expect(rowComponent.key).toEqual(data.id);
+ expect(rowComponent.props.onCellSelect).toBeUndefined();
+ expect(rowComponent.props.rowHeaderIndex).toEqual(0);
+ expect(rowComponent.props.rowIndex).toEqual(rowIndex + subsectionIndex);
+ expect(rowComponent.props.cells).toEqual(data.cells);
+ };
+
+ const wrapper = enzyme.shallow(
+ ,
+ );
+
+ const rows = wrapper.find(Row);
+ expect(rows).toHaveLength(tableData.rows.length);
+ verifyRow(1, rows.get(0), tableData.subsections[0].rows[0], tableData.cols, tableData.subsections[0].subSectionRowIndex);
+ verifyRow(2, rows.get(1), tableData.subsections[0].rows[1], tableData.cols, tableData.subsections[0].subSectionRowIndex);
+ verifyRow(1, rows.get(2), tableData.subsections[1].rows[0], tableData.cols, tableData.subsections[1].subSectionRowIndex);
+ verifyRow(2, rows.get(3), tableData.subsections[1].rows[1], tableData.cols, tableData.subsections[1].subSectionRowIndex);
+ });
+
it('verifies the rows receive the correct props when table is zebra striped', () => {
const wrapper = enzyme.shallow(
{
jest.spyOn(console, 'error').mockImplementation();
@@ -400,6 +491,75 @@ describe('Table', () => {
expect(section2Row1Cell2.props().headers).toBe('test-terra-table-section-1 test-terra-table-rowheader-3 test-terra-table-Column-1-headerCell');
});
+ it('verifies ARIA attributes for a table with subsections', () => {
+ const wrapper = enzymeIntl.mountWithIntl(
+ ,
+ );
+
+ // Validate table properties
+ const table = wrapper.find('table');
+ expect(table.props().id).toBe('test-terra-table');
+ expect(table.props().role).toBe('table');
+ expect(table.props()['aria-rowcount']).toBe(8);
+
+ // Validate column header id attribute
+ const columnHeaderCell = wrapper.find('.column-header').at(0);
+ expect(columnHeaderCell.props().id).toBe('test-terra-table-Column-0-headerCell');
+
+ // Retrieve first section
+ const tableSections = wrapper.find(Section);
+ const section1 = tableSections.at(0);
+
+ // Validate section header row of the first section
+ const section1HeaderRow = section1.find('.header-row');
+ expect(section1HeaderRow.at(0).props()['aria-rowindex']).toBe(2);
+ expect(section1HeaderRow.at(1).props()['aria-rowindex']).toBe(3);
+ expect(section1HeaderRow.at(2).props()['aria-rowindex']).toBe(6);
+
+ // Validate table header element of the first section
+ const sectionHeader1 = section1HeaderRow.find('th');
+ expect(sectionHeader1.at(0).props().id).toBe('test-terra-table-section-0');
+ expect(sectionHeader1.at(0).props().colSpan).toBe(tableSectionData.cols.length);
+ expect(sectionHeader1.at(0).props().scope).toBe('col');
+ // Validate table header element of the first subsection
+ expect(sectionHeader1.at(1).props().id).toBe('test-terra-table-section-0-subsection-0');
+ expect(sectionHeader1.at(1).props().colSpan).toBe(tableSectionData.cols.length);
+ expect(sectionHeader1.at(1).props().scope).toBe('col');
+ // Validate table header element of the 2nd subsection
+ expect(sectionHeader1.at(2).props().id).toBe('test-terra-table-section-0-subsection-1');
+ expect(sectionHeader1.at(2).props().colSpan).toBe(tableSectionData.cols.length);
+ expect(sectionHeader1.at(2).props().scope).toBe('col');
+
+ // Validate rows of the first subsection
+ const section1Row1 = section1.find('.row').at(0);
+
+ expect(section1Row1.props()['aria-rowindex']).toBe(4);
+ expect(section1Row1.props()['data-row-id']).toBe('1');
+ const section1Row2 = section1.find('.row').at(1);
+ expect(section1Row2.props()['aria-rowindex']).toBe(5);
+ expect(section1Row2.props()['data-row-id']).toBe('2');
+
+ // Validate cells of the first row
+ const row1Cell1 = section1Row1.find('.cell').at(0);
+ expect(row1Cell1.props().headers).toBe('test-terra-table-section-0 test-terra-table-section-0-subsection-0 test-terra-table-Column-0-headerCell');
+ expect(row1Cell1.props().id).toBe('test-terra-table-rowheader-1');
+ const row1Cell2 = section1Row1.find('.cell').at(1);
+ expect(row1Cell2.props().headers).toBe('test-terra-table-section-0 test-terra-table-section-0-subsection-0 test-terra-table-rowheader-1 test-terra-table-Column-1-headerCell');
+
+ // Validate rows of the second subsection
+ const section1Row3 = section1.find('.row').at(2);
+
+ expect(section1Row3.props()['aria-rowindex']).toBe(7);
+ expect(section1Row3.props()['data-row-id']).toBe('3');
+ const section1Row4 = section1.find('.row').at(3);
+ expect(section1Row4.props()['aria-rowindex']).toBe(8);
+ expect(section1Row4.props()['data-row-id']).toBe('4');
+ });
+
it('verifies ARIA rowcount and rowindex attributes for a table with header actions (with sections)', () => {
const wrapper = enzymeIntl.mountWithIntl(
{
});
});
+ describe('Table with subsections', () => {
+ const tableWithSubSectionsSelector = '#table-with-sub-sections';
+
+ it('validates a table with subsections', () => {
+ browser.url('/raw/tests/cerner-terra-framework-docs/table/table-with-sub-sections');
+ expect(browser.$('//*[@id="table-with-sub-sections"]/tbody[3]')).not.toExist();
+ Terra.validates.element('table-with-subsections', { selector: tableWithSubSectionsSelector });
+ });
+
+ it('validates a table with with collapsed sections', () => {
+ browser.url('/raw/tests/cerner-terra-framework-docs/table/table-with-collapsible-sections-and-sub-sections');
+ expect(browser.$('//*[@id="table-with-sub-sections"]/tbody[3]')).toHaveChildren(2);
+ Terra.validates.element('table-with-collasped-subsections', { selector: tableWithSubSectionsSelector });
+ });
+ });
+
describe('With row selection', () => {
const rowSelectionTableSelector = '#table-with-row-selections';