@kaizen/components 1.43.0 → 1.44.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.
- package/dist/cjs/Modal/ConfirmationModal/ConfirmationModal.cjs +4 -2
- package/dist/cjs/Modal/ContextModal/ContextModal.cjs +4 -2
- package/dist/cjs/Modal/GenericModal/GenericModal.cjs +12 -9
- package/dist/cjs/Modal/InputEditModal/InputEditModal.cjs +4 -2
- package/dist/cjs/RichTextEditor/utils/plugins/LinkManager/components/LinkModal/LinkModal.cjs +5 -1
- package/dist/cjs/index.css +1 -1
- package/dist/esm/Modal/ConfirmationModal/ConfirmationModal.mjs +4 -2
- package/dist/esm/Modal/ContextModal/ContextModal.mjs +4 -2
- package/dist/esm/Modal/GenericModal/GenericModal.mjs +12 -9
- package/dist/esm/Modal/InputEditModal/InputEditModal.mjs +4 -2
- package/dist/esm/RichTextEditor/utils/plugins/LinkManager/components/LinkModal/LinkModal.mjs +5 -1
- package/dist/esm/index.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/types/Modal/ConfirmationModal/ConfirmationModal.d.ts +4 -1
- package/dist/types/Modal/ContextModal/ContextModal.d.ts +4 -1
- package/dist/types/Modal/GenericModal/GenericModal.d.ts +4 -1
- package/dist/types/Modal/InputEditModal/InputEditModal.d.ts +4 -1
- package/package.json +1 -1
- package/src/Modal/ConfirmationModal/ConfirmationModal.tsx +5 -0
- package/src/Modal/ContextModal/ContextModal.tsx +5 -0
- package/src/Modal/GenericModal/GenericModal.tsx +18 -10
- package/src/Modal/GenericModal/_docs/GenericModal.spec.stories.tsx +124 -0
- package/src/Modal/InputEditModal/InputEditModal.tsx +5 -0
- package/src/Modal/InputEditModal/_docs/InputEditModal.mdx +11 -0
- package/src/Modal/InputEditModal/_docs/InputEditModal.stories.tsx +63 -1
- package/src/RichTextEditor/utils/plugins/LinkManager/components/LinkModal/LinkModal.tsx +1 -0
|
@@ -13,6 +13,9 @@ export type ConfirmationModalProps = {
|
|
|
13
13
|
title: string;
|
|
14
14
|
onConfirm?: () => void;
|
|
15
15
|
onDismiss: () => void;
|
|
16
|
+
/** A callback that is triggered after the modal is opened. */
|
|
17
|
+
onAfterEnter?: () => void;
|
|
18
|
+
/** A callback that is triggered after the modal is closed. */
|
|
16
19
|
onAfterLeave?: () => void;
|
|
17
20
|
confirmLabel?: string;
|
|
18
21
|
dismissLabel?: string;
|
|
@@ -32,7 +35,7 @@ type Mood = "positive" | "informative" | "negative" | "cautionary" | "assertive"
|
|
|
32
35
|
* {@link https://cultureamp.design/?path=/docs/components-modals-confirmationmodal--docs Storybook}
|
|
33
36
|
*/
|
|
34
37
|
export declare const ConfirmationModal: {
|
|
35
|
-
({ isOpen, isProminent, unpadded, mood, title, onConfirm, onAfterLeave, confirmLabel, dismissLabel, confirmWorking, onDismiss: propsOnDismiss, children, ...props }: ConfirmationModalProps): JSX.Element;
|
|
38
|
+
({ isOpen, isProminent, unpadded, mood, title, onConfirm, onAfterLeave, onAfterEnter, confirmLabel, dismissLabel, confirmWorking, onDismiss: propsOnDismiss, children, ...props }: ConfirmationModalProps): JSX.Element;
|
|
36
39
|
displayName: string;
|
|
37
40
|
};
|
|
38
41
|
export {};
|
|
@@ -16,6 +16,9 @@ export type ContextModalProps = Readonly<{
|
|
|
16
16
|
title: string;
|
|
17
17
|
onConfirm?: () => void;
|
|
18
18
|
onDismiss: () => void;
|
|
19
|
+
/** A callback that is triggered after the modal is opened. */
|
|
20
|
+
onAfterEnter?: () => void;
|
|
21
|
+
/** A callback that is triggered after the modal is closed. */
|
|
19
22
|
onAfterLeave?: () => void;
|
|
20
23
|
confirmLabel?: string;
|
|
21
24
|
confirmWorking?: {
|
|
@@ -36,6 +39,6 @@ export type ContextModalProps = Readonly<{
|
|
|
36
39
|
* {@link https://cultureamp.design/?path=/docs/components-modals--contextmodal--docs Storybook}
|
|
37
40
|
*/
|
|
38
41
|
export declare const ContextModal: {
|
|
39
|
-
({ isOpen, unpadded, layout, title, onConfirm, onDismiss: propsOnDismiss, onAfterLeave, confirmLabel, confirmWorking, renderBackground, children, contentHeader, image, secondaryLabel, onSecondaryAction, ...props }: ContextModalProps): JSX.Element;
|
|
42
|
+
({ isOpen, unpadded, layout, title, onConfirm, onDismiss: propsOnDismiss, onAfterLeave, onAfterEnter, confirmLabel, confirmWorking, renderBackground, children, contentHeader, image, secondaryLabel, onSecondaryAction, ...props }: ContextModalProps): JSX.Element;
|
|
40
43
|
displayName: string;
|
|
41
44
|
};
|
|
@@ -6,9 +6,12 @@ export type GenericModalProps = {
|
|
|
6
6
|
focusLockDisabled?: boolean;
|
|
7
7
|
onEscapeKeyup?: (event: KeyboardEvent) => void;
|
|
8
8
|
onOutsideModalClick?: (event: React.MouseEvent) => void;
|
|
9
|
+
/** A callback that is triggered after the modal is opened. */
|
|
10
|
+
onAfterEnter?: () => void;
|
|
11
|
+
/** A callback that is triggered after the modal is closed. */
|
|
9
12
|
onAfterLeave?: () => void;
|
|
10
13
|
};
|
|
11
14
|
export declare const GenericModal: {
|
|
12
|
-
({ id: propsId, children, isOpen, focusLockDisabled, onEscapeKeyup, onOutsideModalClick, onAfterLeave: propsOnAfterLeave, }: GenericModalProps): JSX.Element;
|
|
15
|
+
({ id: propsId, children, isOpen, focusLockDisabled, onEscapeKeyup, onOutsideModalClick, onAfterEnter, onAfterLeave: propsOnAfterLeave, }: GenericModalProps): JSX.Element;
|
|
13
16
|
displayName: string;
|
|
14
17
|
};
|
|
@@ -7,6 +7,9 @@ export type InputEditModalProps = {
|
|
|
7
7
|
onSubmit: () => void;
|
|
8
8
|
onSecondaryAction?: () => void;
|
|
9
9
|
onDismiss: () => void;
|
|
10
|
+
/** A callback that is triggered after the modal is opened. */
|
|
11
|
+
onAfterEnter?: () => void;
|
|
12
|
+
/** A callback that is triggered after the modal is closed. */
|
|
10
13
|
onAfterLeave?: () => void;
|
|
11
14
|
localeDirection?: "rtl" | "ltr";
|
|
12
15
|
submitLabel?: string;
|
|
@@ -27,6 +30,6 @@ export type InputEditModalProps = {
|
|
|
27
30
|
* {@link https://cultureamp.design/?path=/docs/components-modals-inputeditmodal--docs Storybook}
|
|
28
31
|
*/
|
|
29
32
|
export declare const InputEditModal: {
|
|
30
|
-
({ isOpen, mood, title, onSubmit, onSecondaryAction, onAfterLeave, localeDirection, submitLabel, dismissLabel, secondaryLabel, submitWorking, children, unpadded, onDismiss: propsOnDismiss, ...props }: InputEditModalProps): JSX.Element;
|
|
33
|
+
({ isOpen, mood, title, onSubmit, onSecondaryAction, onAfterLeave, localeDirection, submitLabel, dismissLabel, secondaryLabel, submitWorking, children, unpadded, onDismiss: propsOnDismiss, onAfterEnter, ...props }: InputEditModalProps): JSX.Element;
|
|
31
34
|
displayName: string;
|
|
32
35
|
};
|
package/package.json
CHANGED
|
@@ -39,6 +39,9 @@ export type ConfirmationModalProps = {
|
|
|
39
39
|
title: string
|
|
40
40
|
onConfirm?: () => void
|
|
41
41
|
onDismiss: () => void
|
|
42
|
+
/** A callback that is triggered after the modal is opened. */
|
|
43
|
+
onAfterEnter?: () => void
|
|
44
|
+
/** A callback that is triggered after the modal is closed. */
|
|
42
45
|
onAfterLeave?: () => void
|
|
43
46
|
confirmLabel?: string
|
|
44
47
|
dismissLabel?: string
|
|
@@ -99,6 +102,7 @@ export const ConfirmationModal = ({
|
|
|
99
102
|
title,
|
|
100
103
|
onConfirm,
|
|
101
104
|
onAfterLeave,
|
|
105
|
+
onAfterEnter,
|
|
102
106
|
confirmLabel = "Confirm",
|
|
103
107
|
dismissLabel = "Cancel",
|
|
104
108
|
confirmWorking,
|
|
@@ -134,6 +138,7 @@ export const ConfirmationModal = ({
|
|
|
134
138
|
onEscapeKeyup={onDismiss}
|
|
135
139
|
onOutsideModalClick={onDismiss}
|
|
136
140
|
onAfterLeave={onAfterLeave}
|
|
141
|
+
onAfterEnter={onAfterEnter}
|
|
137
142
|
>
|
|
138
143
|
<div className={styles.modal} data-modal {...props}>
|
|
139
144
|
<ModalHeader onDismiss={onDismiss}>
|
|
@@ -32,6 +32,9 @@ export type ContextModalProps = Readonly<
|
|
|
32
32
|
title: string
|
|
33
33
|
onConfirm?: () => void
|
|
34
34
|
onDismiss: () => void
|
|
35
|
+
/** A callback that is triggered after the modal is opened. */
|
|
36
|
+
onAfterEnter?: () => void
|
|
37
|
+
/** A callback that is triggered after the modal is closed. */
|
|
35
38
|
onAfterLeave?: () => void
|
|
36
39
|
confirmLabel?: string
|
|
37
40
|
confirmWorking?: { label: string; labelHidden?: boolean }
|
|
@@ -59,6 +62,7 @@ export const ContextModal = ({
|
|
|
59
62
|
onConfirm,
|
|
60
63
|
onDismiss: propsOnDismiss,
|
|
61
64
|
onAfterLeave,
|
|
65
|
+
onAfterEnter,
|
|
62
66
|
confirmLabel = "Confirm",
|
|
63
67
|
confirmWorking,
|
|
64
68
|
renderBackground,
|
|
@@ -100,6 +104,7 @@ export const ContextModal = ({
|
|
|
100
104
|
onEscapeKeyup={onDismiss}
|
|
101
105
|
onOutsideModalClick={onDismiss}
|
|
102
106
|
onAfterLeave={onAfterLeave}
|
|
107
|
+
onAfterEnter={onAfterEnter}
|
|
103
108
|
>
|
|
104
109
|
<div className={styles.modal} data-modal {...props}>
|
|
105
110
|
{renderBackground && renderBackground()}
|
|
@@ -13,6 +13,9 @@ export type GenericModalProps = {
|
|
|
13
13
|
focusLockDisabled?: boolean
|
|
14
14
|
onEscapeKeyup?: (event: KeyboardEvent) => void
|
|
15
15
|
onOutsideModalClick?: (event: React.MouseEvent) => void
|
|
16
|
+
/** A callback that is triggered after the modal is opened. */
|
|
17
|
+
onAfterEnter?: () => void
|
|
18
|
+
/** A callback that is triggered after the modal is closed. */
|
|
16
19
|
onAfterLeave?: () => void
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -23,6 +26,7 @@ export const GenericModal = ({
|
|
|
23
26
|
focusLockDisabled,
|
|
24
27
|
onEscapeKeyup,
|
|
25
28
|
onOutsideModalClick,
|
|
29
|
+
onAfterEnter,
|
|
26
30
|
onAfterLeave: propsOnAfterLeave,
|
|
27
31
|
}: GenericModalProps): JSX.Element => {
|
|
28
32
|
const reactId = useId()
|
|
@@ -50,18 +54,19 @@ export const GenericModal = ({
|
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
53
|
-
const
|
|
54
|
-
if
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
if (labelElement) {
|
|
58
|
-
labelElement.focus()
|
|
59
|
-
}
|
|
57
|
+
const focusOnAccessibleLabel = (): void => {
|
|
58
|
+
// Check if focus already exists within the modal
|
|
59
|
+
if (modalLayer?.contains(document.activeElement)) {
|
|
60
|
+
return
|
|
60
61
|
}
|
|
62
|
+
|
|
63
|
+
const labelElement: HTMLElement | null =
|
|
64
|
+
document.getElementById(labelledByID)
|
|
65
|
+
|
|
66
|
+
labelElement?.focus()
|
|
61
67
|
}
|
|
62
68
|
|
|
63
69
|
const a11yWarn = (): void => {
|
|
64
|
-
if (!modalLayer) return
|
|
65
70
|
// Ensure that consumers have provided an element that labels the modal
|
|
66
71
|
// to meet ARIA accessibility guidelines.
|
|
67
72
|
if (!document.getElementById(labelledByID)) {
|
|
@@ -86,8 +91,11 @@ export const GenericModal = ({
|
|
|
86
91
|
|
|
87
92
|
const onAfterEnterHandler = (): void => {
|
|
88
93
|
scrollModalToTop()
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
if (modalLayer) {
|
|
95
|
+
onAfterEnter?.()
|
|
96
|
+
focusOnAccessibleLabel()
|
|
97
|
+
a11yWarn()
|
|
98
|
+
}
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
const onBeforeEnterHandler = (): void => {
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from "react"
|
|
2
|
+
import { action } from "@storybook/addon-actions"
|
|
3
|
+
import { Meta, StoryObj } from "@storybook/react"
|
|
4
|
+
import { expect, userEvent, within, waitFor } from "@storybook/test"
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
GenericModal,
|
|
8
|
+
ModalAccessibleLabel,
|
|
9
|
+
ModalBody,
|
|
10
|
+
ModalHeader,
|
|
11
|
+
} from "../index"
|
|
12
|
+
|
|
13
|
+
const meta: Meta<typeof GenericModal> = {
|
|
14
|
+
title: "Components/Modals/Generic Modal/Tests",
|
|
15
|
+
component: GenericModal,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default meta
|
|
19
|
+
|
|
20
|
+
type Story = StoryObj<typeof GenericModal>
|
|
21
|
+
|
|
22
|
+
export const TestBase: Story = {
|
|
23
|
+
render: ({ isOpen: propsIsOpen, ...args }) => {
|
|
24
|
+
const [isOpen, setIsOpen] = React.useState<boolean>(propsIsOpen)
|
|
25
|
+
const handleDismiss = (): void => setIsOpen(false)
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<button
|
|
30
|
+
type="button"
|
|
31
|
+
className="border border-gray-500"
|
|
32
|
+
onClick={() => setIsOpen(true)}
|
|
33
|
+
>
|
|
34
|
+
Open Modal
|
|
35
|
+
</button>
|
|
36
|
+
<GenericModal
|
|
37
|
+
{...args}
|
|
38
|
+
isOpen={isOpen}
|
|
39
|
+
onOutsideModalClick={handleDismiss}
|
|
40
|
+
onEscapeKeyup={handleDismiss}
|
|
41
|
+
id="GenericModalTestId"
|
|
42
|
+
>
|
|
43
|
+
<ModalHeader>
|
|
44
|
+
<ModalAccessibleLabel>Test Modal</ModalAccessibleLabel>
|
|
45
|
+
</ModalHeader>
|
|
46
|
+
<ModalBody>
|
|
47
|
+
<form>
|
|
48
|
+
<label htmlFor="modal-input-play-test">Add link</label>
|
|
49
|
+
<input type="text" id="modal-input-play-test" />
|
|
50
|
+
</form>
|
|
51
|
+
</ModalBody>
|
|
52
|
+
</GenericModal>
|
|
53
|
+
</>
|
|
54
|
+
)
|
|
55
|
+
},
|
|
56
|
+
play: async ({ canvasElement, step }) => {
|
|
57
|
+
const { getByRole } = within(canvasElement)
|
|
58
|
+
|
|
59
|
+
const openModalButton = getByRole("button", { name: "Open Modal" })
|
|
60
|
+
|
|
61
|
+
await step("Open modal", async () => {
|
|
62
|
+
await userEvent.click(openModalButton)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
await step("Default focus is shifted to the Accessible title", async () => {
|
|
66
|
+
await waitFor(() => {
|
|
67
|
+
// document has to be use as Modal will append to document body
|
|
68
|
+
expect(document.activeElement).toHaveTextContent("Test Modal")
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const ModalAccessibleLabelRetainsFocus: Story = {
|
|
75
|
+
...TestBase,
|
|
76
|
+
name: "ModalAccessibleLabel retains focus if onAfterEnter is called",
|
|
77
|
+
args: {
|
|
78
|
+
onAfterEnter: () => action("openCallBack"),
|
|
79
|
+
},
|
|
80
|
+
play: async ({ canvasElement, step }) => {
|
|
81
|
+
const { getByRole } = within(canvasElement)
|
|
82
|
+
|
|
83
|
+
const openModalButton = getByRole("button", { name: "Open Modal" })
|
|
84
|
+
|
|
85
|
+
await step("Open modal", async () => {
|
|
86
|
+
await userEvent.click(openModalButton)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
await step("Accessible title still has focus", async () => {
|
|
90
|
+
await waitFor(() => {
|
|
91
|
+
expect(document.activeElement).toHaveTextContent("Test Modal")
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const TriggerOnAfterEnterFocus: Story = {
|
|
98
|
+
...TestBase,
|
|
99
|
+
args: {
|
|
100
|
+
onAfterEnter: () =>
|
|
101
|
+
document.getElementById("modal-input-play-test")?.focus(),
|
|
102
|
+
},
|
|
103
|
+
name: "onAfterEnter can shift focus to internal elements of the modal",
|
|
104
|
+
play: async ({ canvasElement, step }) => {
|
|
105
|
+
const canvas = within(canvasElement)
|
|
106
|
+
const openModalButton = canvas.getByRole("button", { name: "Open Modal" })
|
|
107
|
+
|
|
108
|
+
await step("Open modal", async () => {
|
|
109
|
+
await userEvent.click(openModalButton)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
await step("Expect activeElement to be the Input", async () => {
|
|
113
|
+
await waitFor(() => {
|
|
114
|
+
expect(document.activeElement).toHaveAccessibleName("Add link")
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
await step("Expect to be able to type without shifting focus", async () => {
|
|
119
|
+
await userEvent.keyboard(
|
|
120
|
+
"All lorem and no ipsum make dolar a dull boy..."
|
|
121
|
+
)
|
|
122
|
+
})
|
|
123
|
+
},
|
|
124
|
+
}
|
|
@@ -19,6 +19,9 @@ export type InputEditModalProps = {
|
|
|
19
19
|
onSubmit: () => void
|
|
20
20
|
onSecondaryAction?: () => void
|
|
21
21
|
onDismiss: () => void
|
|
22
|
+
/** A callback that is triggered after the modal is opened. */
|
|
23
|
+
onAfterEnter?: () => void
|
|
24
|
+
/** A callback that is triggered after the modal is closed. */
|
|
22
25
|
onAfterLeave?: () => void
|
|
23
26
|
localeDirection?: "rtl" | "ltr"
|
|
24
27
|
submitLabel?: string
|
|
@@ -51,6 +54,7 @@ export const InputEditModal = ({
|
|
|
51
54
|
children,
|
|
52
55
|
unpadded = false,
|
|
53
56
|
onDismiss: propsOnDismiss,
|
|
57
|
+
onAfterEnter,
|
|
54
58
|
...props
|
|
55
59
|
}: InputEditModalProps): JSX.Element => {
|
|
56
60
|
const onDismiss = submitWorking ? undefined : propsOnDismiss
|
|
@@ -79,6 +83,7 @@ export const InputEditModal = ({
|
|
|
79
83
|
isOpen={isOpen}
|
|
80
84
|
onEscapeKeyup={onDismiss}
|
|
81
85
|
onAfterLeave={onAfterLeave}
|
|
86
|
+
onAfterEnter={onAfterEnter}
|
|
82
87
|
>
|
|
83
88
|
<div className={styles.modal} dir={localeDirection} data-modal {...props}>
|
|
84
89
|
<ModalHeader onDismiss={onDismiss}>
|
|
@@ -39,3 +39,14 @@ When your modal is preforming a destructive action eg. delete customer data.
|
|
|
39
39
|
### Unpadded
|
|
40
40
|
|
|
41
41
|
<Canvas of={InputEditModalStories.Unpadded} />
|
|
42
|
+
|
|
43
|
+
## onAfterEnter and shifting focus
|
|
44
|
+
|
|
45
|
+
It is an important accessibility consideration that any time we shift focus on the page, no important content is skipped that may provide context to assistive technologies. This is why the default behaviour for our modals is to shift focus to the accessible title.
|
|
46
|
+
|
|
47
|
+
There are instances, such as single input modals, where shifting focus may not impact the users context. In these instances, we can leverage the `onAfterEnter` callback to shift focus to an input.
|
|
48
|
+
|
|
49
|
+
<Canvas of={InputEditModalStories.OnAfterEnter} sourceState="shown" />
|
|
50
|
+
|
|
51
|
+
As both the button and input label have clear intent and the focus does not skip past crucial content, this should provide enough context for an end user.
|
|
52
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from "react"
|
|
1
|
+
import React, { useRef, useState } from "react"
|
|
2
2
|
import { Meta, StoryObj } from "@storybook/react"
|
|
3
3
|
import { fn } from "@storybook/test"
|
|
4
4
|
import isChromatic from "chromatic"
|
|
@@ -101,3 +101,65 @@ export const Unpadded: Story = {
|
|
|
101
101
|
args: { unpadded: true },
|
|
102
102
|
...chromaticModalSettings,
|
|
103
103
|
}
|
|
104
|
+
|
|
105
|
+
export const OnAfterEnter: Story = {
|
|
106
|
+
...chromaticModalSettings,
|
|
107
|
+
args: {
|
|
108
|
+
title: "Create new link",
|
|
109
|
+
submitLabel: "Add link",
|
|
110
|
+
},
|
|
111
|
+
render: args => {
|
|
112
|
+
const [isOpen, setIsOpen] = useState(IS_CHROMATIC)
|
|
113
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
114
|
+
const handleOpen = (): void => setIsOpen(true)
|
|
115
|
+
const handleClose = (): void => setIsOpen(false)
|
|
116
|
+
|
|
117
|
+
return (
|
|
118
|
+
<>
|
|
119
|
+
<button
|
|
120
|
+
type="button"
|
|
121
|
+
className="border border-gray-500"
|
|
122
|
+
onClick={handleOpen}
|
|
123
|
+
>
|
|
124
|
+
Create a link
|
|
125
|
+
</button>
|
|
126
|
+
<InputEditModal
|
|
127
|
+
{...args}
|
|
128
|
+
isOpen={isOpen}
|
|
129
|
+
onSubmit={handleClose}
|
|
130
|
+
onDismiss={handleClose}
|
|
131
|
+
onAfterEnter={() => inputRef.current?.focus()}
|
|
132
|
+
>
|
|
133
|
+
<form>
|
|
134
|
+
<TextField inputRef={inputRef} labelText="Link URL" />
|
|
135
|
+
</form>
|
|
136
|
+
</InputEditModal>
|
|
137
|
+
</>
|
|
138
|
+
)
|
|
139
|
+
},
|
|
140
|
+
parameters: {
|
|
141
|
+
docs: {
|
|
142
|
+
source: {
|
|
143
|
+
code: `
|
|
144
|
+
// The label of the button and the input it is focused to may provide enough context.
|
|
145
|
+
<button
|
|
146
|
+
onClick={handleOpen}
|
|
147
|
+
>
|
|
148
|
+
Create a link
|
|
149
|
+
</button>
|
|
150
|
+
<InputEditModal
|
|
151
|
+
{...args}
|
|
152
|
+
isOpen={isOpen}
|
|
153
|
+
onSubmit={handleClose}
|
|
154
|
+
onDismiss={handleClose}
|
|
155
|
+
onAfterEnter={() => inputRef.current?.focus()}
|
|
156
|
+
>
|
|
157
|
+
<form>
|
|
158
|
+
<TextField inputRef={inputRef} labelText="Link URL" />
|
|
159
|
+
</form>
|
|
160
|
+
</InputEditModal>
|
|
161
|
+
`,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
}
|