@prairielearn/browser-utils 2.2.5 → 2.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/encode-data.js +1 -1
- package/dist/encode-data.js.map +1 -1
- package/dist/focus.js +5 -1
- package/dist/focus.js.map +1 -1
- package/package.json +6 -6
- package/src/encode-data.ts +2 -2
- package/src/focus.ts +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @prairielearn/browser-utils
|
|
2
2
|
|
|
3
|
+
## 2.2.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [984dc62]
|
|
8
|
+
- @prairielearn/html@4.0.11
|
|
9
|
+
|
|
10
|
+
## 2.2.6
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- 11766e0: Prevent scrolling when restoring focus after a focus trap is deactivated
|
|
15
|
+
- 49bb3fa: Upgrade all JavaScript dependencies
|
|
16
|
+
- Updated dependencies [49bb3fa]
|
|
17
|
+
- @prairielearn/html@4.0.10
|
|
18
|
+
|
|
3
19
|
## 2.2.5
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/encode-data.js
CHANGED
package/dist/encode-data.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encode-data.js","sourceRoot":"","sources":["../src/encode-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,
|
|
1
|
+
{"version":3,"file":"encode-data.js","sourceRoot":"","sources":["../src/encode-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAuB,IAAI,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAc,IAAO,EAAE,SAAiB;IACjE,MAAM,WAAW,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7D,OAAO,IAAI,CAAA,eAAe,SAAS;MAC/B,WAAW;YACL,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAU,SAAiB;IACnD,MAAM,UAAU,GAAG,QAAQ,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC;IACnE,IAAI,UAAU,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,qCAAqC,SAAS,GAAG,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["import { decode, encode } from 'js-base64';\n\nimport { type HtmlSafeString, html, unsafeHtml } from '@prairielearn/html';\n\n/**\n * Use this function as an HTML component encode data that will be passed to the client.\n *\n * @param data The data to encode.\n * @param elementId The element ID to use for the encoded data.\n *\n */\nexport function EncodedData<T = unknown>(data: T, elementId: string): HtmlSafeString {\n const encodedData = unsafeHtml(encode(JSON.stringify(data)));\n return html`<script id=\"${elementId}\" type=\"application/base64\">\n ${encodedData}\n </script>`;\n}\n\n/**\n * Decode data that was passed to the client from in HTML component using EncodeData().\n *\n * @param elementId The element ID that stores the encoded data, from from EncodedData().\n * @returns The decoded data.\n */\nexport function decodeData<T = any>(elementId: string): T {\n const base64Data = document.getElementById(elementId)?.textContent;\n if (base64Data == null) {\n throw new Error(`No data found in element with ID \"${elementId}\"`);\n }\n const jsonData = decode(base64Data);\n const data = JSON.parse(jsonData);\n return data;\n}\n"]}
|
package/dist/focus.js
CHANGED
|
@@ -77,7 +77,11 @@ export function trapFocus(element) {
|
|
|
77
77
|
return {
|
|
78
78
|
deactivate() {
|
|
79
79
|
document.removeEventListener('keydown', keyDown);
|
|
80
|
-
|
|
80
|
+
// Restore focus to the previously active element, but only if focus is
|
|
81
|
+
// currently inside the trap container.
|
|
82
|
+
if (element.contains(document.activeElement)) {
|
|
83
|
+
previousActiveElement?.focus({ preventScroll: true });
|
|
84
|
+
}
|
|
81
85
|
},
|
|
82
86
|
};
|
|
83
87
|
}
|
package/dist/focus.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../src/focus.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../src/focus.ts"],"names":[],"mappings":"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","sourcesContent":["// Borrowed from Bootstrap:\n// https://github.com/twbs/bootstrap/blob/5f75413735d8779aeefe0097af9dc5a416208ae5/js/src/dom/selector-engine.js#L67\nconst FOCUSABLE_SELECTOR = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]',\n]\n .map((selector) => `${selector}:not([tabindex^=\"-\"]):not(.btn-close)`)\n .join(',');\n\nfunction isElement(object: Element) {\n return typeof object?.nodeType !== 'undefined';\n}\n\nfunction isVisible(element: Element) {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false;\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible';\n // Handle `details` element as its content may falsly appear visible when it is closed\n const closedDetails = element.closest('details:not([open])');\n\n if (!closedDetails) {\n return elementIsVisible;\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary');\n if (summary && summary.parentNode !== closedDetails) {\n return false;\n }\n\n if (summary === null) {\n return false;\n }\n }\n\n return elementIsVisible;\n}\n\nfunction isDisabled(element: Element) {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true;\n }\n\n if (typeof (element as any).disabled !== 'undefined') {\n return (element as any).disabled;\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false';\n}\n\nfunction focusableChildren(element: Element): HTMLElement[] {\n const focusableChildren = element.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR);\n return Array.from(focusableChildren).filter((child) => !isDisabled(child) && isVisible(child));\n}\n\nexport interface FocusTrap {\n deactivate(): void;\n}\n\nexport function trapFocus(element: Element): FocusTrap {\n // Store the previous active element so we can restore it later.\n const previousActiveElement = document.activeElement ?? document.body;\n\n function keyDown(e: KeyboardEvent) {\n if (e.key !== 'Tab') return;\n\n const focusable = focusableChildren(element);\n const firstFocusable = focusable[0];\n const lastFocusable = focusable[focusable.length - 1];\n\n if (e.shiftKey) {\n // Tabbing backwards\n if (document.activeElement === firstFocusable) {\n (focusable[focusable.length - 1] as HTMLElement).focus();\n e.preventDefault();\n }\n } else {\n // Tabbing forwards\n if (document.activeElement === lastFocusable) {\n (focusable[0] as HTMLElement).focus();\n e.preventDefault();\n }\n }\n }\n\n document.addEventListener('keydown', keyDown);\n\n return {\n deactivate() {\n document.removeEventListener('keydown', keyDown);\n // Restore focus to the previously active element, but only if focus is\n // currently inside the trap container.\n if (element.contains(document.activeElement)) {\n (previousActiveElement as HTMLElement)?.focus({ preventScroll: true });\n }\n },\n };\n}\n\nexport function focusFirstFocusableChild(el: HTMLElement) {\n // In case the user (or more frequently, Cypress) is too fast and focuses a\n // specific element inside the container before this script runs, don't transfer\n // focus to a different element.\n if (el.contains(document.activeElement)) return;\n\n // Escape hatch: if the first element isn't the one that should be focused,\n // add the `autofocus` attribute to the element that should be.\n const autofocusElement = el.querySelector<HTMLElement>('[autofocus]');\n if (autofocusElement) {\n autofocusElement.focus();\n return;\n }\n\n const focusablePopoverChildren = focusableChildren(el);\n if (focusablePopoverChildren.length > 0) {\n focusablePopoverChildren[0].focus();\n return;\n }\n\n // If we still couldn't find a child element, focus the container itself.\n el.focus();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prairielearn/browser-utils",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.7",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"sideEffects": false,
|
|
7
5
|
"repository": {
|
|
8
6
|
"type": "git",
|
|
9
7
|
"url": "https://github.com/PrairieLearn/PrairieLearn.git",
|
|
10
8
|
"directory": "packages/browser-utils"
|
|
11
9
|
},
|
|
10
|
+
"main": "dist/index.js",
|
|
12
11
|
"scripts": {
|
|
13
12
|
"build": "tsc",
|
|
14
13
|
"dev": "tsc --watch --preserveWatchOutput"
|
|
15
14
|
},
|
|
16
15
|
"dependencies": {
|
|
17
|
-
"@prairielearn/html": "^4.0.
|
|
16
|
+
"@prairielearn/html": "^4.0.11",
|
|
18
17
|
"js-base64": "^3.7.7"
|
|
19
18
|
},
|
|
20
19
|
"devDependencies": {
|
|
21
20
|
"@prairielearn/tsconfig": "^0.0.0",
|
|
22
|
-
"typescript": "^5.
|
|
23
|
-
}
|
|
21
|
+
"typescript": "^5.8.2"
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false
|
|
24
24
|
}
|
package/src/encode-data.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { decode, encode } from 'js-base64';
|
|
2
2
|
|
|
3
|
-
import { html, unsafeHtml
|
|
3
|
+
import { type HtmlSafeString, html, unsafeHtml } from '@prairielearn/html';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Use this function as an HTML component encode data that will be passed to the client.
|
package/src/focus.ts
CHANGED
|
@@ -96,7 +96,11 @@ export function trapFocus(element: Element): FocusTrap {
|
|
|
96
96
|
return {
|
|
97
97
|
deactivate() {
|
|
98
98
|
document.removeEventListener('keydown', keyDown);
|
|
99
|
-
|
|
99
|
+
// Restore focus to the previously active element, but only if focus is
|
|
100
|
+
// currently inside the trap container.
|
|
101
|
+
if (element.contains(document.activeElement)) {
|
|
102
|
+
(previousActiveElement as HTMLElement)?.focus({ preventScroll: true });
|
|
103
|
+
}
|
|
100
104
|
},
|
|
101
105
|
};
|
|
102
106
|
}
|