@allxsmith/bestax-bulma 5.22.0 → 5.23.0

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.
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  /**
2
3
  * Resolves a portal target: an `HTMLElement` is used directly, a non-empty
3
4
  * `string` is treated as a `document.querySelector` selector (falling back to
@@ -13,3 +14,64 @@
13
14
  * @returns The resolved DOM node to portal into.
14
15
  */
15
16
  export declare function resolvePortalContainer(container?: string | HTMLElement): HTMLElement;
17
+ /**
18
+ * Props for the Portal component.
19
+ */
20
+ export interface PortalProps {
21
+ /** Content to render into the container. */
22
+ children?: React.ReactNode;
23
+ /**
24
+ * Where the content goes: an element, or a `document.querySelector`
25
+ * selector. Omitted, empty, or a selector that matches nothing, it goes to
26
+ * `document.body`. A selector is looked up again on each render, so the
27
+ * content follows the target when it changes. Moving to another target
28
+ * remounts the children and resets their state, which includes a selector
29
+ * that only starts matching after the content has shown in `document.body`.
30
+ * Render the target first, or pass the element once you have it.
31
+ */
32
+ container?: string | HTMLElement;
33
+ /**
34
+ * Render the children in place instead, on the server as well as the
35
+ * client. Lets a component that portals only sometimes keep a single code
36
+ * path.
37
+ * @defaultValue false
38
+ */
39
+ disabled?: boolean;
40
+ }
41
+ /**
42
+ * Renders its children into another part of the page, `document.body` unless `container` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.
43
+ *
44
+ * React's server renderer can't render a portal, so `Portal` renders nothing
45
+ * on the server and during hydration, and mounts its children in the commit
46
+ * that follows. The first client render then matches the server markup. In an app
47
+ * without server rendering it portals on the first render.
48
+ *
49
+ * React context, such as `ConfigProvider`'s class prefix, reaches the
50
+ * portaled children, and their React events bubble through the React tree.
51
+ * CSS inheritance follows the DOM instead: a scoped (non-`isRoot`) `Theme`
52
+ * sets its variables on a wrapper element the portaled content has left, so
53
+ * that content sees the page-level theme. Point `container` at an element
54
+ * inside the themed area to keep it.
55
+ *
56
+ * Tab order and focus follow the DOM too. Content portaled from inside a
57
+ * focus trap is no longer inside the trapped element, so the trap neither
58
+ * reaches it nor holds focus there: render nested overlays inside the
59
+ * trapped element, or give them a trap of their own.
60
+ *
61
+ * @function
62
+ * @param {PortalProps} props - Props for the Portal component.
63
+ * @returns The portal, the children in place when `disabled`, or nothing
64
+ * before hydration.
65
+ *
66
+ * @example
67
+ * <Portal>
68
+ * <div className="box">Rendered at the end of document.body</div>
69
+ * </Portal>
70
+ *
71
+ * @example
72
+ * // Into a dedicated overlay root
73
+ * <Portal container="#overlays">
74
+ * <CommandPalette />
75
+ * </Portal>
76
+ */
77
+ export declare function Portal({ children, container, disabled }: PortalProps): React.JSX.Element | null;
@@ -49,6 +49,8 @@ export declare function getActiveElementInTree(node: Node | null | undefined): E
49
49
  * opener sits in. A closed shadow root cannot be entered, so focus inside one
50
50
  * reads as its host.
51
51
  *
52
+ * @param doc - The document to start from: the component's own, when it may
53
+ * render into one other than the page's (an iframe's). Defaults to `document`.
52
54
  * @returns The focused element, or `null` when the document has none.
53
55
  */
54
- export declare function getDeepestActiveElement(): Element | null;
56
+ export declare function getDeepestActiveElement(doc?: Document): Element | null;
@@ -0,0 +1,74 @@
1
+ import type { RefObject } from 'react';
2
+ /**
3
+ * Options for `useFocusTrap`.
4
+ */
5
+ export interface UseFocusTrapOptions {
6
+ /**
7
+ * Whether the trap is on. Turning it on moves focus into the container;
8
+ * turning it off (or unmounting) releases Tab and restores focus.
9
+ * @defaultValue true
10
+ */
11
+ active?: boolean;
12
+ /**
13
+ * The element to focus when the trap turns on. Without it, or while it
14
+ * points at nothing, focus goes to the first tab stop inside the container,
15
+ * and to the container itself when there is none.
16
+ */
17
+ initialFocusRef?: RefObject<HTMLElement | null>;
18
+ /**
19
+ * Where focus goes when the trap turns off. `true` returns it to the element
20
+ * that had focus when the trap turned on; a ref sends it to that element
21
+ * instead; `false` leaves it alone. Focus is only moved while the trap still
22
+ * holds it, so a click that already put focus somewhere else outside the
23
+ * container keeps it there.
24
+ *
25
+ * `true` reads focus after the container's content has mounted, so content
26
+ * that focuses itself as it mounts (an `autoFocus` input) hides the element
27
+ * that opened it. And some browsers don't focus a button when it is
28
+ * clicked. For a panel opened from a button, pass the button's ref.
29
+ * @defaultValue true
30
+ */
31
+ restoreFocus?: boolean | RefObject<HTMLElement | null>;
32
+ }
33
+ /**
34
+ * Keeps keyboard focus inside a container while it is active: focus moves in
35
+ * when the trap turns on, Tab and Shift+Tab wrap between the first and last
36
+ * tab stops, and focus goes back where it came from when the trap turns off.
37
+ *
38
+ * Tab stops are what the browser's Tab visits, in document order: links,
39
+ * form controls, frames, media with controls, a `<details>` summary, editable
40
+ * regions, anything with `tabIndex={0}`, and the content of open shadow
41
+ * roots. Hidden, disabled, inert and `tabIndex={-1}` elements are skipped,
42
+ * and a radio group counts once. Give the container `tabIndex={-1}` so it can
43
+ * hold focus itself when nothing inside can. The trap listens on the
44
+ * container, so a trap nested inside another handles Tab first and the outer
45
+ * one stands aside.
46
+ *
47
+ * The trap is about Tab. If a Tab it let through still takes focus out (a
48
+ * browser can leave out a stop the page has, such as links when its settings
49
+ * say to), it sends focus back to the other end. A pointer or a script moving
50
+ * focus out is left alone, because pulling focus back from a click is modal
51
+ * behaviour, and a modal also has to block the page behind it, which `Modal`
52
+ * does. Content the container renders through a portal lives elsewhere in
53
+ * the DOM, so it is outside the trap: render nested overlays inside the
54
+ * container, or give them a trap of their own.
55
+ *
56
+ * The container has to be in the DOM when the trap turns on. The trap waits
57
+ * for hydration, so a container that only appears once the page has
58
+ * hydrated, the way portaled content does, still has it attach in the commit
59
+ * where the container appears.
60
+ *
61
+ * @function useFocusTrap
62
+ * @param containerRef - Ref to the element focus stays inside.
63
+ * @param options - When the trap is on, and where focus starts and ends.
64
+ *
65
+ * @example
66
+ * const panelRef = useRef<HTMLDivElement>(null);
67
+ * useFocusTrap(panelRef, { active: isOpen });
68
+ * return isOpen ? (
69
+ * <div ref={panelRef} role="dialog" aria-label="Filters" tabIndex={-1}>
70
+ * …
71
+ * </div>
72
+ * ) : null;
73
+ */
74
+ export declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, options?: UseFocusTrapOptions): void;
@@ -110,6 +110,10 @@ export * from './helpers/Config.js';
110
110
  export { ClientOnly } from './helpers/ClientOnly.js';
111
111
  export type { ClientOnlyProps } from './helpers/ClientOnly.js';
112
112
  export { useIsHydrated } from './helpers/useIsHydrated.js';
113
+ export { Portal } from './helpers/portal.js';
114
+ export type { PortalProps } from './helpers/portal.js';
115
+ export { useFocusTrap } from './helpers/useFocusTrap.js';
116
+ export type { UseFocusTrapOptions } from './helpers/useFocusTrap.js';
113
117
  export * from './layout/Container.js';
114
118
  export * from './layout/Footer.js';
115
119
  export * from './layout/Hero.js';
@@ -1,3 +1,4 @@
1
+ import React from 'react';
1
2
  /**
2
3
  * Resolves a portal target: an `HTMLElement` is used directly, a non-empty
3
4
  * `string` is treated as a `document.querySelector` selector (falling back to
@@ -13,3 +14,64 @@
13
14
  * @returns The resolved DOM node to portal into.
14
15
  */
15
16
  export declare function resolvePortalContainer(container?: string | HTMLElement): HTMLElement;
17
+ /**
18
+ * Props for the Portal component.
19
+ */
20
+ export interface PortalProps {
21
+ /** Content to render into the container. */
22
+ children?: React.ReactNode;
23
+ /**
24
+ * Where the content goes: an element, or a `document.querySelector`
25
+ * selector. Omitted, empty, or a selector that matches nothing, it goes to
26
+ * `document.body`. A selector is looked up again on each render, so the
27
+ * content follows the target when it changes. Moving to another target
28
+ * remounts the children and resets their state, which includes a selector
29
+ * that only starts matching after the content has shown in `document.body`.
30
+ * Render the target first, or pass the element once you have it.
31
+ */
32
+ container?: string | HTMLElement;
33
+ /**
34
+ * Render the children in place instead, on the server as well as the
35
+ * client. Lets a component that portals only sometimes keep a single code
36
+ * path.
37
+ * @defaultValue false
38
+ */
39
+ disabled?: boolean;
40
+ }
41
+ /**
42
+ * Renders its children into another part of the page, `document.body` unless `container` says otherwise, so floating content escapes an ancestor's `overflow`, `transform` or stacking context.
43
+ *
44
+ * React's server renderer can't render a portal, so `Portal` renders nothing
45
+ * on the server and during hydration, and mounts its children in the commit
46
+ * that follows. The first client render then matches the server markup. In an app
47
+ * without server rendering it portals on the first render.
48
+ *
49
+ * React context, such as `ConfigProvider`'s class prefix, reaches the
50
+ * portaled children, and their React events bubble through the React tree.
51
+ * CSS inheritance follows the DOM instead: a scoped (non-`isRoot`) `Theme`
52
+ * sets its variables on a wrapper element the portaled content has left, so
53
+ * that content sees the page-level theme. Point `container` at an element
54
+ * inside the themed area to keep it.
55
+ *
56
+ * Tab order and focus follow the DOM too. Content portaled from inside a
57
+ * focus trap is no longer inside the trapped element, so the trap neither
58
+ * reaches it nor holds focus there: render nested overlays inside the
59
+ * trapped element, or give them a trap of their own.
60
+ *
61
+ * @function
62
+ * @param {PortalProps} props - Props for the Portal component.
63
+ * @returns The portal, the children in place when `disabled`, or nothing
64
+ * before hydration.
65
+ *
66
+ * @example
67
+ * <Portal>
68
+ * <div className="box">Rendered at the end of document.body</div>
69
+ * </Portal>
70
+ *
71
+ * @example
72
+ * // Into a dedicated overlay root
73
+ * <Portal container="#overlays">
74
+ * <CommandPalette />
75
+ * </Portal>
76
+ */
77
+ export declare function Portal({ children, container, disabled }: PortalProps): React.JSX.Element | null;
@@ -49,6 +49,8 @@ export declare function getActiveElementInTree(node: Node | null | undefined): E
49
49
  * opener sits in. A closed shadow root cannot be entered, so focus inside one
50
50
  * reads as its host.
51
51
  *
52
+ * @param doc - The document to start from: the component's own, when it may
53
+ * render into one other than the page's (an iframe's). Defaults to `document`.
52
54
  * @returns The focused element, or `null` when the document has none.
53
55
  */
54
- export declare function getDeepestActiveElement(): Element | null;
56
+ export declare function getDeepestActiveElement(doc?: Document): Element | null;
@@ -0,0 +1,74 @@
1
+ import type { RefObject } from 'react';
2
+ /**
3
+ * Options for `useFocusTrap`.
4
+ */
5
+ export interface UseFocusTrapOptions {
6
+ /**
7
+ * Whether the trap is on. Turning it on moves focus into the container;
8
+ * turning it off (or unmounting) releases Tab and restores focus.
9
+ * @defaultValue true
10
+ */
11
+ active?: boolean;
12
+ /**
13
+ * The element to focus when the trap turns on. Without it, or while it
14
+ * points at nothing, focus goes to the first tab stop inside the container,
15
+ * and to the container itself when there is none.
16
+ */
17
+ initialFocusRef?: RefObject<HTMLElement | null>;
18
+ /**
19
+ * Where focus goes when the trap turns off. `true` returns it to the element
20
+ * that had focus when the trap turned on; a ref sends it to that element
21
+ * instead; `false` leaves it alone. Focus is only moved while the trap still
22
+ * holds it, so a click that already put focus somewhere else outside the
23
+ * container keeps it there.
24
+ *
25
+ * `true` reads focus after the container's content has mounted, so content
26
+ * that focuses itself as it mounts (an `autoFocus` input) hides the element
27
+ * that opened it. And some browsers don't focus a button when it is
28
+ * clicked. For a panel opened from a button, pass the button's ref.
29
+ * @defaultValue true
30
+ */
31
+ restoreFocus?: boolean | RefObject<HTMLElement | null>;
32
+ }
33
+ /**
34
+ * Keeps keyboard focus inside a container while it is active: focus moves in
35
+ * when the trap turns on, Tab and Shift+Tab wrap between the first and last
36
+ * tab stops, and focus goes back where it came from when the trap turns off.
37
+ *
38
+ * Tab stops are what the browser's Tab visits, in document order: links,
39
+ * form controls, frames, media with controls, a `<details>` summary, editable
40
+ * regions, anything with `tabIndex={0}`, and the content of open shadow
41
+ * roots. Hidden, disabled, inert and `tabIndex={-1}` elements are skipped,
42
+ * and a radio group counts once. Give the container `tabIndex={-1}` so it can
43
+ * hold focus itself when nothing inside can. The trap listens on the
44
+ * container, so a trap nested inside another handles Tab first and the outer
45
+ * one stands aside.
46
+ *
47
+ * The trap is about Tab. If a Tab it let through still takes focus out (a
48
+ * browser can leave out a stop the page has, such as links when its settings
49
+ * say to), it sends focus back to the other end. A pointer or a script moving
50
+ * focus out is left alone, because pulling focus back from a click is modal
51
+ * behaviour, and a modal also has to block the page behind it, which `Modal`
52
+ * does. Content the container renders through a portal lives elsewhere in
53
+ * the DOM, so it is outside the trap: render nested overlays inside the
54
+ * container, or give them a trap of their own.
55
+ *
56
+ * The container has to be in the DOM when the trap turns on. The trap waits
57
+ * for hydration, so a container that only appears once the page has
58
+ * hydrated, the way portaled content does, still has it attach in the commit
59
+ * where the container appears.
60
+ *
61
+ * @function useFocusTrap
62
+ * @param containerRef - Ref to the element focus stays inside.
63
+ * @param options - When the trap is on, and where focus starts and ends.
64
+ *
65
+ * @example
66
+ * const panelRef = useRef<HTMLDivElement>(null);
67
+ * useFocusTrap(panelRef, { active: isOpen });
68
+ * return isOpen ? (
69
+ * <div ref={panelRef} role="dialog" aria-label="Filters" tabIndex={-1}>
70
+ * …
71
+ * </div>
72
+ * ) : null;
73
+ */
74
+ export declare function useFocusTrap(containerRef: RefObject<HTMLElement | null>, options?: UseFocusTrapOptions): void;
@@ -110,6 +110,10 @@ export * from './helpers/Config.js';
110
110
  export { ClientOnly } from './helpers/ClientOnly.js';
111
111
  export type { ClientOnlyProps } from './helpers/ClientOnly.js';
112
112
  export { useIsHydrated } from './helpers/useIsHydrated.js';
113
+ export { Portal } from './helpers/portal.js';
114
+ export type { PortalProps } from './helpers/portal.js';
115
+ export { useFocusTrap } from './helpers/useFocusTrap.js';
116
+ export type { UseFocusTrapOptions } from './helpers/useFocusTrap.js';
113
117
  export * from './layout/Container.js';
114
118
  export * from './layout/Footer.js';
115
119
  export * from './layout/Hero.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allxsmith/bestax-bulma",
3
- "version": "5.22.0",
3
+ "version": "5.23.0",
4
4
  "description": "A fully-typed React component library for the Bulma CSS framework. Build modern UIs quickly with reusable, accessible, and customizable Bulma-based React components.",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.esm.js",
@@ -1,7 +0,0 @@
1
- import * as React from 'react';
2
- interface UseFocusTrapOptions {
3
- initialFocusRef?: React.RefObject<HTMLElement | null>;
4
- restoreFocus?: boolean;
5
- }
6
- export declare function useFocusTrap(containerRef: React.RefObject<HTMLElement | null>, active: boolean, options?: UseFocusTrapOptions): void;
7
- export {};
@@ -1,7 +0,0 @@
1
- import * as React from 'react';
2
- interface UseFocusTrapOptions {
3
- initialFocusRef?: React.RefObject<HTMLElement | null>;
4
- restoreFocus?: boolean;
5
- }
6
- export declare function useFocusTrap(containerRef: React.RefObject<HTMLElement | null>, active: boolean, options?: UseFocusTrapOptions): void;
7
- export {};