prime-ui-kit 0.7.1 → 0.7.2
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/components/button/examples/destructive-confirm.d.ts.map +1 -1
- package/dist/components/index.css +5 -2
- package/dist/components/index.css.map +2 -2
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +421 -295
- package/dist/components/index.js.map +4 -4
- package/dist/components/modal/Modal.d.ts +28 -7
- package/dist/components/modal/Modal.d.ts.map +1 -1
- package/dist/components/modal/examples/canonical-maximal.d.ts.map +1 -1
- package/dist/components/modal/examples/pattern-close-behavior.d.ts.map +1 -1
- package/dist/components/modal/examples/pattern-controlled.d.ts.map +1 -1
- package/dist/components/modal/examples/pattern-portal-and-scroll.d.ts.map +1 -1
- package/dist/components/modal/examples/scenario-confirm-delete.d.ts.map +1 -1
- package/dist/components/modal/examples/scenario-edit-entity.d.ts.map +1 -1
- package/dist/components/modal/examples/scenario-legal-consent.d.ts.map +1 -1
- package/dist/components/modal/examples/scenario-multi-field-form.d.ts.map +1 -1
- package/dist/components/select/Select.d.ts.map +1 -1
- package/dist/hooks/useModalKeyboard.d.ts +14 -0
- package/dist/hooks/useModalKeyboard.d.ts.map +1 -0
- package/dist/index.css +5 -2
- package/dist/index.css.map +2 -2
- package/dist/index.js +421 -295
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/components/button/examples/destructive-confirm.tsx +13 -9
- package/src/components/modal/COMPONENT.md +35 -17
- package/src/components/modal/examples/canonical-maximal.tsx +13 -9
- package/src/components/modal/examples/pattern-close-behavior.tsx +9 -5
- package/src/components/modal/examples/pattern-controlled.tsx +7 -3
- package/src/components/modal/examples/pattern-portal-and-scroll.tsx +7 -3
- package/src/components/modal/examples/scenario-confirm-delete.tsx +13 -9
- package/src/components/modal/examples/scenario-edit-entity.tsx +16 -12
- package/src/components/modal/examples/scenario-legal-consent.tsx +9 -5
- package/src/components/modal/examples/scenario-multi-field-form.tsx +13 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prime-ui-kit",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "React 19 UI kit: CSS Modules, semantic design tokens (--prime-sys-*), composable components — forms, modals, selects, tables, navigation, overlays. TypeScript, ESM, a11y-oriented.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -17,16 +17,20 @@ export default function DestructiveConfirmExample() {
|
|
|
17
17
|
<Modal.Panel
|
|
18
18
|
title="Delete this project?"
|
|
19
19
|
footer={
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<Button.Root variant="
|
|
23
|
-
|
|
20
|
+
<Modal.Footer
|
|
21
|
+
primary={
|
|
22
|
+
<Button.Root variant="error" mode="filled" onClick={() => setOpen(false)}>
|
|
23
|
+
Delete
|
|
24
24
|
</Button.Root>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
}
|
|
26
|
+
secondary={
|
|
27
|
+
<Modal.Close>
|
|
28
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
29
|
+
Cancel
|
|
30
|
+
</Button.Root>
|
|
31
|
+
</Modal.Close>
|
|
32
|
+
}
|
|
33
|
+
/>
|
|
30
34
|
}
|
|
31
35
|
>
|
|
32
36
|
<p style={{ margin: 0 }}>This permanently removes the project and its data.</p>
|
|
@@ -12,10 +12,11 @@ Centered overlay dialog with a portal, backdrop, focus trap, scroll lock, and op
|
|
|
12
12
|
|
|
13
13
|
## Composition
|
|
14
14
|
|
|
15
|
-
- **`Modal.Root`** — holds open state (controlled via **`open`** / **`onOpenChange`** or uncontrolled via **`defaultOpen`**), and options **`closeOnEscape`** / **`closeOnOverlayClick
|
|
15
|
+
- **`Modal.Root`** — holds open state (controlled via **`open`** / **`onOpenChange`** or uncontrolled via **`defaultOpen`**), and options **`closeOnEscape`** / **`closeOnOverlayClick`**, **`confirmOnEnter`** / **`onEnterConfirm`** (подтверждение по Enter). Renders **`children`** only (no DOM wrapper).
|
|
16
16
|
- **`Modal.Trigger`** — optional; **`React.Children.only`**: pass **exactly one** React element; its **`onClick`** is merged to call **`onOpen`** when the event is not **`defaultPrevented`**.
|
|
17
17
|
- **`Modal.Panel`** — when open: **`createPortal`** (default container `document.body`), fullscreen **`role="presentation"`** overlay, then **`role="dialog"`** with **`aria-modal="true"`**. If **`title`** is set, renders an internal header (**`h2`**, optional description, optional built-in close icon button), wraps **`children`** in an internal body, and optional **`footer`**. Without **`title`**, **`children`** render directly inside the dialog surface—supply **`aria-label`** or **`aria-labelledby`** (and **`aria-describedby`** when needed).
|
|
18
|
-
- **`Modal.Close`** — same single-child contract as **`Trigger`**; merges **`onClick`**
|
|
18
|
+
- **`Modal.Close`** — same single-child contract as **`Trigger`**; merges **`onClick`** and **`ref`** to the child so **`Modal.Footer`** **`primary`** can register the DOM node for Enter. Typical placement: a control inside **`Modal.Footer`** (for example **Cancel** or **Save** when saving should dismiss the dialog).
|
|
19
|
+
- **`Modal.Footer`** — **`footer`** prop on **`Modal.Panel`**: предпочтительно **`Modal.Footer`** со слотами **`secondary`** (отмена, слева/раньше в разметке), **`extra`** (дополнительные кнопки между отменой и подтверждением), **`primary`** (основное действие и цель **Enter** при **`confirmOnEnter`**). Порядок в DOM: **`secondary` → `extra` → `primary`** (в LTR с **`justify-content: flex-end`** основная кнопка справа). **`primary`** — один **`React.ReactElement`** (например **`Button.Root`** или **`Modal.Close`** с кнопкой). Произвольная разметка без **`Modal.Footer`** — допустима как **`footer`**, но подтверждение по Enter к целевой кнопке не привязывается.
|
|
19
20
|
- **Order:** **`Modal.Root`** → **`Modal.Trigger`** (if any) and **`Modal.Panel`** as siblings (or only **`Modal.Panel`** in controlled flows).
|
|
20
21
|
|
|
21
22
|
### Minimal example
|
|
@@ -39,7 +40,7 @@ export function Example() {
|
|
|
39
40
|
|
|
40
41
|
### Canonical example (full shell)
|
|
41
42
|
|
|
42
|
-
Use this when you want the complete header row (**`title`**, **`description`**, **`icon`**), a form field in the body, and a **`
|
|
43
|
+
Use this when you want the complete header row (**`title`**, **`description`**, **`icon`**), a form field in the body, and a **`Modal.Footer`** with **`secondary`** (**Cancel** via **`Modal.Close`**) and **`primary`**. The header still shows the built-in icon close button by default (`showClose`).
|
|
43
44
|
|
|
44
45
|
```tsx
|
|
45
46
|
import { Button, Icon, Input, Modal } from "prime-ui-kit";
|
|
@@ -57,16 +58,20 @@ export function InviteTeammateModal() {
|
|
|
57
58
|
description="We will send one invitation email. The recipient can accept or decline."
|
|
58
59
|
icon={<Icon name="field.email" tone="subtle" />}
|
|
59
60
|
footer={
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
<Button.Root variant="
|
|
63
|
-
|
|
61
|
+
<Modal.Footer
|
|
62
|
+
primary={
|
|
63
|
+
<Button.Root variant="primary" type="button">
|
|
64
|
+
Send invite
|
|
64
65
|
</Button.Root>
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
}
|
|
67
|
+
secondary={
|
|
68
|
+
<Modal.Close>
|
|
69
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
70
|
+
Cancel
|
|
71
|
+
</Button.Root>
|
|
72
|
+
</Modal.Close>
|
|
73
|
+
}
|
|
74
|
+
/>
|
|
70
75
|
}
|
|
71
76
|
>
|
|
72
77
|
<Input.Root label="Email address" hint="Work email preferred">
|
|
@@ -116,11 +121,12 @@ Runnable examples use `@/` in the workspace; published consumers import **`prime
|
|
|
116
121
|
- **Dismiss on primary action:** wrap the confirming button in **`Modal.Close`** when the action should close the dialog immediately (see **edit entity** example). If you must await an API call, keep the dialog open until success, then call **`onOpenChange(false)`** from the parent.
|
|
117
122
|
- **Consent / wizard steps:** set **`closeOnOverlayClick={false}`** (and optionally **`closeOnEscape={false}`**) when accidental dismiss would lose legal or multi-step state; still provide an explicit **`Modal.Close`** (or header close) path where appropriate.
|
|
118
123
|
- **Long body content:** constrain scroll to the body via **`bodyStyle`** / **`bodyClassName`** (see `playground/snippets/modal/features.tsx`); overlay scroll lock remains active.
|
|
124
|
+
- **Enter to confirm:** при **`confirmOnEnter={true}`** (по умолчанию) **Enter** внутри диалога имитирует **`click()`** по элементу из слота **`Modal.Footer`** **`primary`** (логика в **`useModalKeyboard`** вместе с Escape). В шапке (**`header`**) нативное поведение **Enter** на кнопке закрытия сохраняется; в **`textarea`** / **`select`** и ряде типов **`input`** подтверждение по Enter не срабатывает. Полностью своё поведение — **`onEnterConfirm`** на **`Modal.Root`**; отключить — **`confirmOnEnter={false}`**.
|
|
119
125
|
- **Headless dialog surface:** omit **`title`** on **`Modal.Panel`** and supply **`aria-label`** or **`aria-labelledby`** / **`aria-describedby`** yourself; inner body wrapper is not used, so **`bodyClassName`** / **`bodyStyle`** do not apply.
|
|
120
126
|
|
|
121
127
|
### Note for LLMs
|
|
122
128
|
|
|
123
|
-
When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and **`Modal.Close`** each require **exactly one** child element—no fragments or multiple nodes. (2) Prefer **`Modal.Panel`** with **`title`** (and usually **`description`**) so **`aria-labelledby`** / **`aria-describedby`** are wired automatically. (3)
|
|
129
|
+
When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and **`Modal.Close`** each require **exactly one** child element—no fragments or multiple nodes. (2) Prefer **`Modal.Panel`** with **`title`** (and usually **`description`**) so **`aria-labelledby`** / **`aria-describedby`** are wired automatically. (3) Use **`Modal.Footer`** with **`secondary`** (**`Modal.Close`** + cancel) and **`primary`** (main action) unless the design relies only on the header icon. (4) Do not wrap kit components to restyle them; use **`size`**, **`variant`**, **`mode`**, and documented props only. (5) For copy-paste starting points, mirror **`examples/canonical-maximal.tsx`** first, then **`examples/pattern-*`** or scenario files; playground **`playground/snippets/modal/*.tsx`** are the live-demo source of truth.
|
|
124
130
|
|
|
125
131
|
## Rules
|
|
126
132
|
|
|
@@ -133,7 +139,7 @@ When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and *
|
|
|
133
139
|
- **Focus:** focus is trapped inside the dialog while open; initial focus follows browser / trap behavior—ensure a focusable control or manage focus if the first paint is static text only.
|
|
134
140
|
- **`showClose`** (default **`true`** when a header is shown) controls the header icon button; **`closeAriaLabel`** defaults to **`"Close"`**.
|
|
135
141
|
- **`container`** on **`Modal.Panel`** overrides the portal target (for tests or custom stacking); default is **`document.body`**.
|
|
136
|
-
- **`overlayClassName`**, **`footerClassName`**, **`bodyClassName`**, and **`bodyStyle`** target the overlay, **`<footer
|
|
142
|
+
- **`overlayClassName`**, **`footerClassName`**, **`bodyClassName`**, and **`bodyStyle`** target the overlay, the **`footer`** element (merged into **`Modal.Footer`** when **`footer`** is **`Modal.Footer`**, else a wrapper **`<footer>`** for arbitrary content), and body wrapper respectively; without **`title`**, **`bodyClassName`** / **`bodyStyle`** do not apply (no inner body wrapper).
|
|
137
143
|
|
|
138
144
|
## API
|
|
139
145
|
|
|
@@ -146,6 +152,8 @@ When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and *
|
|
|
146
152
|
| onOpenChange | `(open: boolean) => void` | — | No | Fires when open state changes |
|
|
147
153
|
| closeOnEscape | `boolean` | `true` | No | Whether Escape closes the dialog |
|
|
148
154
|
| closeOnOverlayClick | `boolean` | `true` | No | Whether a direct backdrop click closes |
|
|
155
|
+
| confirmOnEnter | `boolean` | `true` | No | Whether Enter triggers the default confirmation action (primary button) |
|
|
156
|
+
| onEnterConfirm | `(event: KeyboardEvent) => void` | — | No | Replaces default Enter confirmation; call `event.preventDefault()` if needed to suppress native control behavior |
|
|
149
157
|
| children | `React.ReactNode` | — | No | e.g. `Modal.Trigger` and `Modal.Panel` |
|
|
150
158
|
|
|
151
159
|
### Modal.Trigger
|
|
@@ -158,7 +166,17 @@ When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and *
|
|
|
158
166
|
|
|
159
167
|
| Prop | Type | Default | Required | Description |
|
|
160
168
|
|------|------|---------|----------|-------------|
|
|
161
|
-
| children | `React.ReactElement<{ onClick?: React.MouseEventHandler; className?: string; size?: "s" \| "m" \| "l" \| "xl" }>` | — | Yes | Single element whose `onClick`
|
|
169
|
+
| children | `React.ReactElement<{ onClick?: React.MouseEventHandler; ref?: React.Ref<HTMLElement>; className?: string; size?: "s" \| "m" \| "l" \| "xl" }>` | — | Yes | Single element whose `onClick` and `ref` are composed with close |
|
|
170
|
+
|
|
171
|
+
### Modal.Footer
|
|
172
|
+
|
|
173
|
+
| Prop | Type | Default | Required | Description |
|
|
174
|
+
|------|------|---------|----------|-------------|
|
|
175
|
+
| primary | `React.ReactElement` (e.g. `Button.Root`) | — | No | Main action; target for Enter when `confirmOnEnter` and no `onEnterConfirm` |
|
|
176
|
+
| secondary | `React.ReactNode` | — | No | Usually cancel / `Modal.Close` |
|
|
177
|
+
| extra | `React.ReactNode` | — | No | Additional buttons between `secondary` and `primary` |
|
|
178
|
+
| className | `string` | — | No | Class on the `<footer>` |
|
|
179
|
+
| …rest | `Omit<React.HTMLAttributes<HTMLElement>, "children">` | — | No | Other attributes on `<footer>` |
|
|
162
180
|
|
|
163
181
|
### Modal.Panel
|
|
164
182
|
|
|
@@ -170,10 +188,10 @@ When generating **Modal** markup for this library: (1) **`Modal.Trigger`** and *
|
|
|
170
188
|
| showClose | `boolean` | `true` | No | Header close icon button when `title` is set |
|
|
171
189
|
| closeAriaLabel | `string` | `"Close"` | No | `aria-label` for the header close control |
|
|
172
190
|
| children | `React.ReactNode` | — | No | Main content; wrapped in internal body when `title` is set |
|
|
173
|
-
| footer | `React.ReactNode` | — | No |
|
|
191
|
+
| footer | `React.ReactNode` | — | No | Prefer **`Modal.Footer`**; arbitrary nodes are wrapped in **`<footer>`** without Enter binding |
|
|
174
192
|
| container | `HTMLElement \| null` | `document.body` | No | Portal mount node |
|
|
175
193
|
| overlayClassName | `string` | — | No | Class on the fullscreen backdrop |
|
|
176
|
-
| footerClassName | `string` | — | No |
|
|
194
|
+
| footerClassName | `string` | — | No | Merged into **`Modal.Footer`** `className` when **`footer`** is **`Modal.Footer`**; else on wrapper **`<footer>`** |
|
|
177
195
|
| bodyClassName | `string` | — | No | Class on the internal body when `title` is set |
|
|
178
196
|
| bodyStyle | `React.CSSProperties` | — | No | Inline style on the internal body when `title` is set |
|
|
179
197
|
| aria-label | `string` | — | No | Dialog name when there is no `title`-driven label |
|
|
@@ -18,16 +18,20 @@ export default function ModalCanonicalMaximalExample() {
|
|
|
18
18
|
<Modal.Panel
|
|
19
19
|
description="We will send one invitation email. The recipient can accept or decline."
|
|
20
20
|
footer={
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<Button.Root variant="
|
|
24
|
-
|
|
21
|
+
<Modal.Footer
|
|
22
|
+
primary={
|
|
23
|
+
<Button.Root variant="primary" type="button">
|
|
24
|
+
Send invite
|
|
25
25
|
</Button.Root>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
}
|
|
27
|
+
secondary={
|
|
28
|
+
<Modal.Close>
|
|
29
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
30
|
+
Cancel
|
|
31
|
+
</Button.Root>
|
|
32
|
+
</Modal.Close>
|
|
33
|
+
}
|
|
34
|
+
/>
|
|
31
35
|
}
|
|
32
36
|
icon={<Icon name="field.email" tone="subtle" />}
|
|
33
37
|
title="Invite teammate"
|
|
@@ -34,11 +34,15 @@ export default function ModalPatternCloseBehaviorExample() {
|
|
|
34
34
|
<Modal.Panel
|
|
35
35
|
description="With both flags false, only buttons dismiss the dialog."
|
|
36
36
|
footer={
|
|
37
|
-
<Modal.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
<Modal.Footer
|
|
38
|
+
primary={
|
|
39
|
+
<Modal.Close>
|
|
40
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
41
|
+
OK
|
|
42
|
+
</Button.Root>
|
|
43
|
+
</Modal.Close>
|
|
44
|
+
}
|
|
45
|
+
/>
|
|
42
46
|
}
|
|
43
47
|
icon={<Icon name="status.locked" />}
|
|
44
48
|
showClose={false}
|
|
@@ -22,9 +22,13 @@ export default function ModalPatternControlledExample() {
|
|
|
22
22
|
closeAriaLabel="Close"
|
|
23
23
|
description="Open and close are driven by `open` and `onOpenChange` on the root."
|
|
24
24
|
footer={
|
|
25
|
-
<Modal.
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
<Modal.Footer
|
|
26
|
+
primary={
|
|
27
|
+
<Modal.Close>
|
|
28
|
+
<Button.Root variant="primary">Done</Button.Root>
|
|
29
|
+
</Modal.Close>
|
|
30
|
+
}
|
|
31
|
+
/>
|
|
28
32
|
}
|
|
29
33
|
icon={<Icon name="action.copy" />}
|
|
30
34
|
title="Externally controlled"
|
|
@@ -63,9 +63,13 @@ export default function ModalPatternPortalAndScrollExample() {
|
|
|
63
63
|
closeAriaLabel="Close"
|
|
64
64
|
description="Cap the body height with `bodyStyle` (or `bodyClassName`) so only the panel scrolls."
|
|
65
65
|
footer={
|
|
66
|
-
<Modal.
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
<Modal.Footer
|
|
67
|
+
primary={
|
|
68
|
+
<Modal.Close>
|
|
69
|
+
<Button.Root variant="primary">Close</Button.Root>
|
|
70
|
+
</Modal.Close>
|
|
71
|
+
}
|
|
72
|
+
/>
|
|
69
73
|
}
|
|
70
74
|
icon={<Icon name="nav.itemDot" />}
|
|
71
75
|
title="Scroll inside panel"
|
|
@@ -15,16 +15,20 @@ export default function ModalConfirmDeleteExample() {
|
|
|
15
15
|
<Modal.Panel
|
|
16
16
|
description="This removes the project, its boards, and history. Connected integrations will stop receiving events."
|
|
17
17
|
footer={
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
<Button.Root variant="
|
|
21
|
-
|
|
18
|
+
<Modal.Footer
|
|
19
|
+
primary={
|
|
20
|
+
<Button.Root variant="error" type="button">
|
|
21
|
+
Delete permanently
|
|
22
22
|
</Button.Root>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
}
|
|
24
|
+
secondary={
|
|
25
|
+
<Modal.Close>
|
|
26
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
27
|
+
Cancel
|
|
28
|
+
</Button.Root>
|
|
29
|
+
</Modal.Close>
|
|
30
|
+
}
|
|
31
|
+
/>
|
|
28
32
|
}
|
|
29
33
|
icon={<Icon name="action.close" tone="subtle" />}
|
|
30
34
|
title="Delete “Northwind rollout”?"
|
|
@@ -19,18 +19,22 @@ export default function ModalEditEntityExample() {
|
|
|
19
19
|
<Modal.Panel
|
|
20
20
|
description="The new name appears on invoices and in the member directory."
|
|
21
21
|
footer={
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
<Modal.Footer
|
|
23
|
+
primary={
|
|
24
|
+
<Modal.Close>
|
|
25
|
+
<Button.Root variant="primary" type="button">
|
|
26
|
+
Save changes
|
|
27
|
+
</Button.Root>
|
|
28
|
+
</Modal.Close>
|
|
29
|
+
}
|
|
30
|
+
secondary={
|
|
31
|
+
<Modal.Close>
|
|
32
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
33
|
+
Cancel
|
|
34
|
+
</Button.Root>
|
|
35
|
+
</Modal.Close>
|
|
36
|
+
}
|
|
37
|
+
/>
|
|
34
38
|
}
|
|
35
39
|
icon={<Icon name="nav.layoutGrid" tone="subtle" />}
|
|
36
40
|
title="Edit account name"
|
|
@@ -15,11 +15,15 @@ export default function ModalLegalConsentExample() {
|
|
|
15
15
|
<Modal.Panel
|
|
16
16
|
description="Please read the following before continuing to use the service."
|
|
17
17
|
footer={
|
|
18
|
-
<Modal.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
<Modal.Footer
|
|
19
|
+
primary={
|
|
20
|
+
<Modal.Close>
|
|
21
|
+
<Button.Root variant="primary" type="button">
|
|
22
|
+
I agree
|
|
23
|
+
</Button.Root>
|
|
24
|
+
</Modal.Close>
|
|
25
|
+
}
|
|
26
|
+
/>
|
|
23
27
|
}
|
|
24
28
|
icon={<Icon name="status.locked" tone="subtle" />}
|
|
25
29
|
title="Terms and data processing"
|
|
@@ -24,16 +24,20 @@ export default function ModalMultiFieldFormExample() {
|
|
|
24
24
|
<Modal.Panel
|
|
25
25
|
description="Include enough detail for our team to reproduce or route the issue."
|
|
26
26
|
footer={
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<Button.Root variant="
|
|
30
|
-
|
|
27
|
+
<Modal.Footer
|
|
28
|
+
primary={
|
|
29
|
+
<Button.Root variant="primary" type="submit" form="modal-ticket-form">
|
|
30
|
+
Submit ticket
|
|
31
31
|
</Button.Root>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
}
|
|
33
|
+
secondary={
|
|
34
|
+
<Modal.Close>
|
|
35
|
+
<Button.Root variant="neutral" mode="stroke">
|
|
36
|
+
Cancel
|
|
37
|
+
</Button.Root>
|
|
38
|
+
</Modal.Close>
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
37
41
|
}
|
|
38
42
|
icon={<Icon name="nav.itemDot" tone="subtle" />}
|
|
39
43
|
title="Contact support"
|