@reykjavik/hanna-react 0.10.125 → 0.10.126

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 CHANGED
@@ -4,6 +4,15 @@
4
4
 
5
5
  - ... <!-- Add new lines here. -->
6
6
 
7
+ ## 0.10.126
8
+
9
+ _2024-06-05_
10
+
11
+ - `FocusTrap`:
12
+ - feat: Add className to wrapper element
13
+ - fix: Exclude `FocusTrap` elements from list of eligible focusables
14
+ - fix: Mishandled focus-managment of `Modal` while open
15
+
7
16
  ## 0.10.125
8
17
 
9
18
  _2024-04-10_
package/FocusTrap.d.ts CHANGED
@@ -11,8 +11,9 @@ export type FocusTrapProps = {
11
11
  depth?: number;
12
12
  };
13
13
  /**
14
- * A focus trap element that can be used to keep keyboard focus within a container block.
14
+ * A focus trap element that can be used to keep keyboard focus within a
15
+ * container block.
15
16
  *
16
- * Make sure you only trap focus when a modal or
17
+ * Make sure you only trap focus when a modal or dialog is open
17
18
  */
18
19
  export declare const FocusTrap: (props: FocusTrapProps) => JSX.Element;
package/FocusTrap.js CHANGED
@@ -4,13 +4,14 @@ exports.FocusTrap = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  /**
7
- * A focus trap element that can be used to keep keyboard focus within a container block.
7
+ * A focus trap element that can be used to keep keyboard focus within a
8
+ * container block.
8
9
  *
9
- * Make sure you only trap focus when a modal or
10
+ * Make sure you only trap focus when a modal or dialog is open
10
11
  */
11
12
  const FocusTrap = (props) => {
12
13
  const Tag = props.Tag || 'span';
13
- return (react_1.default.createElement(Tag, { tabIndex: 0, onFocus: (e) => {
14
+ return (react_1.default.createElement(Tag, { className: "FocusTrap", tabIndex: 0, onFocus: (e) => {
14
15
  var _a;
15
16
  let container = e.currentTarget;
16
17
  let depth = Math.max(props.depth || 1, 1);
@@ -20,7 +21,7 @@ const FocusTrap = (props) => {
20
21
  if (!container) {
21
22
  return;
22
23
  }
23
- const focusables = container.querySelectorAll('a,input, select, textarea,button, [tabindex]');
24
+ const focusables = container.querySelectorAll('a, input, select, textarea, button, [tabindex]:not(.FocusTrap):not([tabindex="-1"])');
24
25
  const targetIdx = props.atTop ? focusables.length - 1 : 0;
25
26
  (_a = focusables[targetIdx]) === null || _a === void 0 ? void 0 : _a.focus();
26
27
  } }));
@@ -45,9 +45,10 @@ export type AbstractModalProps = {
45
45
  * defined then `stable` takes precedence.
46
46
  */
47
47
  fickle?: boolean;
48
- /** Convenience callback that runs as soon as the `open` flag flips to `true` – including on initial opening.
48
+ /**
49
+ * Convenience callback that runs as soon as the `open` flag flips to `true` – including on initial opening.
49
50
  *
50
- * However, the initial `onOpen` is skipped `startOpen` is set to `true`.
51
+ * However, the initial `onOpen` is skipped when `startOpen` is set to `true`.
51
52
  */
52
53
  onOpen?: () => void;
53
54
  /**
@@ -62,9 +62,9 @@ const AbstractModal = (props) => {
62
62
  addToModalStack(privateDomId);
63
63
  setTimeout(() => {
64
64
  setOpen(true);
65
- props.onOpen && props.onOpen();
66
- (0, focusElm_1.focusElm)(modalElmRef.current);
67
- }, 100);
65
+ (0, focusElm_1.focusElm)(modalElmRef.current, { delay: 50 });
66
+ props.onOpen && props.onOpen(); // allow onOpen to move focus to a new place....
67
+ }, 50);
68
68
  }
69
69
  };
70
70
  const closeModal = () => {
@@ -126,6 +126,6 @@ const AbstractModal = (props) => {
126
126
  react_1.default.createElement("div", { className: (0, classUtils_1.modifiedClass)(bem, modifier), ref: modalElmRef },
127
127
  children,
128
128
  isBrowser && !props.noCloseButton && (react_1.default.createElement("button", { className: `${bem}__closebutton`, type: "button", onClick: closeModal, "aria-label": closeButtonLabel, "aria-controls": domid, title: closeButtonLabel }, txt.closeButton))),
129
- isBrowser && react_1.default.createElement(FocusTrap_js_1.FocusTrap, { atTop: true }))));
129
+ isBrowser && react_1.default.createElement(FocusTrap_js_1.FocusTrap, null))));
130
130
  };
131
131
  exports.AbstractModal = AbstractModal;
@@ -11,8 +11,9 @@ export type FocusTrapProps = {
11
11
  depth?: number;
12
12
  };
13
13
  /**
14
- * A focus trap element that can be used to keep keyboard focus within a container block.
14
+ * A focus trap element that can be used to keep keyboard focus within a
15
+ * container block.
15
16
  *
16
- * Make sure you only trap focus when a modal or
17
+ * Make sure you only trap focus when a modal or dialog is open
17
18
  */
18
19
  export declare const FocusTrap: (props: FocusTrapProps) => JSX.Element;
package/esm/FocusTrap.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import React from 'react';
2
2
  /**
3
- * A focus trap element that can be used to keep keyboard focus within a container block.
3
+ * A focus trap element that can be used to keep keyboard focus within a
4
+ * container block.
4
5
  *
5
- * Make sure you only trap focus when a modal or
6
+ * Make sure you only trap focus when a modal or dialog is open
6
7
  */
7
8
  export const FocusTrap = (props) => {
8
9
  const Tag = props.Tag || 'span';
9
- return (React.createElement(Tag, { tabIndex: 0, onFocus: (e) => {
10
+ return (React.createElement(Tag, { className: "FocusTrap", tabIndex: 0, onFocus: (e) => {
10
11
  var _a;
11
12
  let container = e.currentTarget;
12
13
  let depth = Math.max(props.depth || 1, 1);
@@ -16,7 +17,7 @@ export const FocusTrap = (props) => {
16
17
  if (!container) {
17
18
  return;
18
19
  }
19
- const focusables = container.querySelectorAll('a,input, select, textarea,button, [tabindex]');
20
+ const focusables = container.querySelectorAll('a, input, select, textarea, button, [tabindex]:not(.FocusTrap):not([tabindex="-1"])');
20
21
  const targetIdx = props.atTop ? focusables.length - 1 : 0;
21
22
  (_a = focusables[targetIdx]) === null || _a === void 0 ? void 0 : _a.focus();
22
23
  } }));
@@ -45,9 +45,10 @@ export type AbstractModalProps = {
45
45
  * defined then `stable` takes precedence.
46
46
  */
47
47
  fickle?: boolean;
48
- /** Convenience callback that runs as soon as the `open` flag flips to `true` – including on initial opening.
48
+ /**
49
+ * Convenience callback that runs as soon as the `open` flag flips to `true` – including on initial opening.
49
50
  *
50
- * However, the initial `onOpen` is skipped `startOpen` is set to `true`.
51
+ * However, the initial `onOpen` is skipped when `startOpen` is set to `true`.
51
52
  */
52
53
  onOpen?: () => void;
53
54
  /**
@@ -58,9 +58,9 @@ export const AbstractModal = (props) => {
58
58
  addToModalStack(privateDomId);
59
59
  setTimeout(() => {
60
60
  setOpen(true);
61
- props.onOpen && props.onOpen();
62
- focusElm(modalElmRef.current);
63
- }, 100);
61
+ focusElm(modalElmRef.current, { delay: 50 });
62
+ props.onOpen && props.onOpen(); // allow onOpen to move focus to a new place....
63
+ }, 50);
64
64
  }
65
65
  };
66
66
  const closeModal = () => {
@@ -122,5 +122,5 @@ export const AbstractModal = (props) => {
122
122
  React.createElement("div", { className: modifiedClass(bem, modifier), ref: modalElmRef },
123
123
  children,
124
124
  isBrowser && !props.noCloseButton && (React.createElement("button", { className: `${bem}__closebutton`, type: "button", onClick: closeModal, "aria-label": closeButtonLabel, "aria-controls": domid, title: closeButtonLabel }, txt.closeButton))),
125
- isBrowser && React.createElement(FocusTrap, { atTop: true }))));
125
+ isBrowser && React.createElement(FocusTrap, null))));
126
126
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reykjavik/hanna-react",
3
- "version": "0.10.125",
3
+ "version": "0.10.126",
4
4
  "author": "Reykjavík (http://www.reykjavik.is)",
5
5
  "contributors": [
6
6
  "Hugsmiðjan ehf (http://www.hugsmidjan.is)",