@bitrise/bitkit-v2 0.3.365 → 0.3.367
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/AGENTS.md +3 -1
- package/dist/components/BitkitDialog/BitkitDialog.d.ts +4 -4
- package/dist/components/BitkitDialog/BitkitDialog.js +2 -1
- package/dist/components/BitkitDialog/BitkitDialog.js.map +1 -1
- package/dist/components/BitkitDialog/BitkitFormDialog.d.ts +31 -4
- package/dist/components/BitkitDialog/BitkitFormDialog.js +6 -5
- package/dist/components/BitkitDialog/BitkitFormDialog.js.map +1 -1
- package/dist/components/BitkitDialog/BitkitStepperDialog.d.ts +4 -4
- package/dist/components/BitkitDialog/BitkitStepperDialog.js +2 -1
- package/dist/components/BitkitDialog/BitkitStepperDialog.js.map +1 -1
- package/dist/components/BitkitDialog/DialogShell.d.ts +8 -0
- package/dist/components/BitkitDialog/DialogShell.js.map +1 -1
- package/dist/components/BitkitNativeSelect/BitkitNativeSelect.d.ts +3 -2
- package/dist/components/BitkitNativeSelect/BitkitNativeSelect.js +25 -1
- package/dist/components/BitkitNativeSelect/BitkitNativeSelect.js.map +1 -1
- package/dist/theme/slot-recipes/NativeSelect.recipe.js +5 -0
- package/dist/theme/slot-recipes/NativeSelect.recipe.js.map +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -121,7 +121,7 @@ Bitkit components use consistent prop names across the library:
|
|
|
121
121
|
```
|
|
122
122
|
- **Three dialog components, one shell** — pick by intent, never reach for low-level dialog primitives (there are none exported):
|
|
123
123
|
- `BitkitDialog` — header (title + close) + body (`children`) + footer. The body is the dialog's `children`. The footer is two slot props: `footerButtons` (action buttons, auto-wrapped in the standard right-aligned row — no manual wrapper) and `footerContent` (arbitrary content rendered raw, e.g. an inline `BitkitAlert`). Both can be combined (content first, then buttons); omit both for a passive dialog with no footer.
|
|
124
|
-
- `BitkitFormDialog` — same API as `BitkitDialog`, but the whole content is a `<form>`, so a `type="submit"` button in `footerButtons` submits natively.
|
|
124
|
+
- `BitkitFormDialog` — same API as `BitkitDialog`, but the whole content is a `<form>`, so a `type="submit"` button in `footerButtons` submits natively. On top of the shared dialog props it takes `onSubmit` (correctly typed as `FormEvent<HTMLFormElement>`) and `noValidate`, and nothing else off the native `<form>`.
|
|
125
125
|
- `BitkitStepperDialog` — a multi-step dialog. Pass `BitkitStepperDialog.Step` children (each with `label` for the steps header, `title`/`description` for the step body). It owns the step state and auto-renders the steps header; wire footer navigation via the `useStepperDialog()` hook (`{ step, setStep, next, prev, goTo, isFirst, isLast, totalSteps }`) from a component rendered in the footer slot. Controlled via `step`/`onStepChange`, or uncontrolled via `defaultStep`.
|
|
126
126
|
- All three expose `.ActionTrigger` (a thin re-export of Chakra's `Dialog.ActionTrigger`): wrap a footer button in it to close the dialog on click — the default way to dismiss a trigger-based (uncontrolled) dialog without wiring `open` state.
|
|
127
127
|
```tsx
|
|
@@ -133,6 +133,8 @@ Bitkit components use consistent prop names across the library:
|
|
|
133
133
|
</BitkitStepperDialog>
|
|
134
134
|
```
|
|
135
135
|
For closing on click, use controlled `open`/`onOpenChange`, or wrap a button in `BitkitDialog.ActionTrigger` (and the `BitkitFormDialog.ActionTrigger` / `BitkitStepperDialog.ActionTrigger` equivalents). For a fully custom dialog, compose raw Chakra `Dialog.*` atoms directly.
|
|
136
|
+
|
|
137
|
+
All three forward `data-*` attributes to the element carrying `role="dialog"` (`data-testid`, `data-clarity-unmask`), and nothing else — style props, `className` and `id` don't pass through.
|
|
136
138
|
- **Dialog non-dismissible + post-close callback** — works on all three: pass `closable={false}` to make the dialog fully non-dismissible (the close button is rendered but disabled, ESC is blocked, outside clicks are ignored — the only way out is an explicit footer action). Pass `onExitComplete` to run code after the close animation finishes (navigation, focus restoration, cleanup):
|
|
137
139
|
```tsx
|
|
138
140
|
<BitkitDialog closable={false} open={open} onOpenChange={…} title="Action required">…</BitkitDialog>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Dialog } from '@chakra-ui/react/dialog';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { DialogShellProps } from './DialogShell';
|
|
4
|
-
export
|
|
3
|
+
import { DialogDataAttributes, DialogShellProps } from './DialogShell';
|
|
4
|
+
export type BitkitDialogProps = {
|
|
5
5
|
children?: ReactNode;
|
|
6
6
|
closable?: boolean;
|
|
7
7
|
footerButtons?: ReactNode;
|
|
@@ -22,9 +22,9 @@ export interface BitkitDialogProps {
|
|
|
22
22
|
title: ReactNode;
|
|
23
23
|
trigger?: ReactNode;
|
|
24
24
|
variant?: 'overflowContent';
|
|
25
|
-
}
|
|
25
|
+
} & DialogDataAttributes;
|
|
26
26
|
declare const _default: {
|
|
27
|
-
({ children, closable, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, onExitComplete, onOpenChange, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant, }: BitkitDialogProps): import("react").JSX.Element;
|
|
27
|
+
({ children, closable, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, onExitComplete, onOpenChange, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant, ...dataAttributes }: BitkitDialogProps): import("react").JSX.Element;
|
|
28
28
|
displayName: string;
|
|
29
29
|
} & {
|
|
30
30
|
ActionTrigger: import('react').ForwardRefExoticComponent<Dialog.ActionTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -4,7 +4,7 @@ import DialogShell from "./DialogShell.js";
|
|
|
4
4
|
import { jsx } from "react/jsx-runtime";
|
|
5
5
|
import { Dialog } from "@chakra-ui/react/dialog";
|
|
6
6
|
//#region lib/components/BitkitDialog/BitkitDialog.tsx
|
|
7
|
-
var BitkitDialog = ({ children, closable = true, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, onExitComplete, onOpenChange, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant }) => /* @__PURE__ */ jsx(DialogShell, {
|
|
7
|
+
var BitkitDialog = ({ children, closable = true, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, onExitComplete, onOpenChange, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant, ...dataAttributes }) => /* @__PURE__ */ jsx(DialogShell, {
|
|
8
8
|
closable,
|
|
9
9
|
initialFocusEl,
|
|
10
10
|
onExitComplete,
|
|
@@ -17,6 +17,7 @@ var BitkitDialog = ({ children, closable = true, footerButtons, footerContent, h
|
|
|
17
17
|
variant,
|
|
18
18
|
children: /* @__PURE__ */ jsx(Dialog.Content, {
|
|
19
19
|
maxHeight,
|
|
20
|
+
...dataAttributes,
|
|
20
21
|
children: /* @__PURE__ */ jsx(DialogInner, {
|
|
21
22
|
closable,
|
|
22
23
|
footerButtons,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { type ReactNode } from 'react';\n\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport DialogInner from './DialogInner';\nimport DialogShell, { type DialogShellProps } from './DialogShell';\n\nexport
|
|
1
|
+
{"version":3,"file":"BitkitDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { type ReactNode } from 'react';\n\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport DialogInner from './DialogInner';\nimport DialogShell, { type DialogDataAttributes, type DialogShellProps } from './DialogShell';\n\nexport type BitkitDialogProps = {\n children?: ReactNode;\n closable?: boolean;\n footerButtons?: ReactNode;\n footerContent?: ReactNode;\n headerLabel?: string;\n /** Element to focus when the dialog opens, instead of the first focusable one. */\n initialFocusEl?: DialogShellProps['initialFocusEl'];\n maxHeight?: string;\n onExitComplete?: () => void;\n onOpenChange?: (details: { open: boolean }) => void;\n open?: boolean;\n preventScroll?: boolean;\n scrollBehavior?: 'inside' | 'outside';\n showScrollGradient?: boolean;\n size?: 'sm' | 'md' | 'lg' | 'full';\n title: ReactNode;\n trigger?: ReactNode;\n variant?: 'overflowContent';\n} & DialogDataAttributes;\n\nconst BitkitDialog = ({\n children,\n closable = true,\n footerButtons,\n footerContent,\n headerLabel,\n initialFocusEl,\n maxHeight,\n onExitComplete,\n onOpenChange,\n open,\n preventScroll,\n scrollBehavior,\n showScrollGradient,\n size,\n title,\n trigger,\n variant,\n ...dataAttributes\n}: BitkitDialogProps) => (\n <DialogShell\n closable={closable}\n initialFocusEl={initialFocusEl}\n onExitComplete={onExitComplete}\n onOpenChange={onOpenChange}\n open={open}\n preventScroll={preventScroll}\n scrollBehavior={scrollBehavior}\n size={size}\n trigger={trigger}\n variant={variant}\n >\n <Dialog.Content maxHeight={maxHeight} {...dataAttributes}>\n <DialogInner\n closable={closable}\n footerButtons={footerButtons}\n footerContent={footerContent}\n headerLabel={headerLabel}\n scrollBehavior={scrollBehavior}\n showScrollGradient={showScrollGradient}\n title={title}\n variant={variant}\n >\n {children}\n </DialogInner>\n </Dialog.Content>\n </DialogShell>\n);\n\nBitkitDialog.displayName = 'BitkitDialog';\n\nexport default withSubComponents(BitkitDialog, { ActionTrigger: Dialog.ActionTrigger });\n"],"mappings":";;;;;;AA4BA,IAAM,gBAAgB,EACpB,UACA,WAAW,MACX,eACA,eACA,aACA,gBACA,WACA,gBACA,cACA,MACA,eACA,gBACA,oBACA,MACA,OACA,SACA,SACA,GAAG,qBAEH,oBAAC,aAAD;CACY;CACM;CACA;CACF;CACR;CACS;CACC;CACV;CACG;CACA;CAET,UAAA,oBAAC,OAAO,SAAR;EAA2B;EAAW,GAAI;EACxC,UAAA,oBAAC,aAAD;GACY;GACK;GACA;GACF;GACG;GACI;GACb;GACE;GAER;EACU,CAAA;CACC,CAAA;AACL,CAAA;AAGf,aAAa,cAAc;AAE3B,IAAA,uBAAe,kBAAkB,cAAc,EAAE,eAAe,OAAO,cAAc,CAAC"}
|
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
import { Dialog } from '@chakra-ui/react/dialog';
|
|
2
|
-
import {
|
|
2
|
+
import { FormEventHandler } from 'react';
|
|
3
3
|
import { BitkitDialogProps } from './BitkitDialog';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export type BitkitFormDialogProps = BitkitDialogProps & {
|
|
5
|
+
/** Skips the browser's native constraint validation on submit. */
|
|
6
|
+
noValidate?: boolean;
|
|
7
|
+
onSubmit?: FormEventHandler<HTMLFormElement>;
|
|
8
|
+
};
|
|
9
|
+
declare const _default: import('react').ForwardRefExoticComponent<{
|
|
10
|
+
children?: import('react').ReactNode;
|
|
11
|
+
closable?: boolean;
|
|
12
|
+
footerButtons?: import('react').ReactNode;
|
|
13
|
+
footerContent?: import('react').ReactNode;
|
|
14
|
+
headerLabel?: string;
|
|
15
|
+
initialFocusEl?: import('./DialogShell').DialogShellProps["initialFocusEl"];
|
|
16
|
+
maxHeight?: string;
|
|
17
|
+
onExitComplete?: () => void;
|
|
18
|
+
onOpenChange?: (details: {
|
|
19
|
+
open: boolean;
|
|
20
|
+
}) => void;
|
|
21
|
+
open?: boolean;
|
|
22
|
+
preventScroll?: boolean;
|
|
23
|
+
scrollBehavior?: "inside" | "outside";
|
|
24
|
+
showScrollGradient?: boolean;
|
|
25
|
+
size?: "sm" | "md" | "lg" | "full";
|
|
26
|
+
title: import('react').ReactNode;
|
|
27
|
+
trigger?: import('react').ReactNode;
|
|
28
|
+
variant?: "overflowContent";
|
|
29
|
+
} & import('./DialogShell').DialogDataAttributes & {
|
|
30
|
+
/** Skips the browser's native constraint validation on submit. */
|
|
31
|
+
noValidate?: boolean;
|
|
32
|
+
onSubmit?: FormEventHandler<HTMLFormElement>;
|
|
33
|
+
} & import('react').RefAttributes<HTMLFormElement>> & {
|
|
7
34
|
ActionTrigger: import('react').ForwardRefExoticComponent<Dialog.ActionTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
8
35
|
};
|
|
9
36
|
export default _default;
|
|
@@ -8,12 +8,11 @@ import { Dialog } from "@chakra-ui/react/dialog";
|
|
|
8
8
|
//#region lib/components/BitkitDialog/BitkitFormDialog.tsx
|
|
9
9
|
/**
|
|
10
10
|
* A dialog whose entire content is a `<form>`, so a `type="submit"` button in the footer submits
|
|
11
|
-
* natively.
|
|
12
|
-
*
|
|
13
|
-
* does NOT accept Chakra style props (`width`, `padding`, …), which would override the `size` variant.
|
|
11
|
+
* natively. Like the other dialog overlays it owns its own layout, so the form surface is just
|
|
12
|
+
* `onSubmit` and `noValidate` — no Chakra style props, no `className`, no `id`.
|
|
14
13
|
*/
|
|
15
14
|
var BitkitFormDialog = forwardRef((props, ref) => {
|
|
16
|
-
const { children, closable = true, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, onExitComplete, onOpenChange, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant, ...
|
|
15
|
+
const { children, closable = true, footerButtons, footerContent, headerLabel, initialFocusEl, maxHeight, noValidate, onExitComplete, onOpenChange, onSubmit, open, preventScroll, scrollBehavior, showScrollGradient, size, title, trigger, variant, ...dataAttributes } = props;
|
|
17
16
|
return /* @__PURE__ */ jsx(DialogShell, {
|
|
18
17
|
closable,
|
|
19
18
|
initialFocusEl,
|
|
@@ -28,9 +27,11 @@ var BitkitFormDialog = forwardRef((props, ref) => {
|
|
|
28
27
|
children: /* @__PURE__ */ jsx(Dialog.Content, {
|
|
29
28
|
asChild: true,
|
|
30
29
|
maxHeight,
|
|
30
|
+
...dataAttributes,
|
|
31
31
|
children: /* @__PURE__ */ jsx(chakra.form, {
|
|
32
32
|
ref,
|
|
33
|
-
|
|
33
|
+
noValidate,
|
|
34
|
+
onSubmit,
|
|
34
35
|
children: /* @__PURE__ */ jsx(DialogInner, {
|
|
35
36
|
closable,
|
|
36
37
|
footerButtons,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitFormDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitFormDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { chakra } from '@chakra-ui/react/styled-system';\nimport { type
|
|
1
|
+
{"version":3,"file":"BitkitFormDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitFormDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { chakra } from '@chakra-ui/react/styled-system';\nimport { type FormEventHandler, forwardRef } from 'react';\n\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport { type BitkitDialogProps } from './BitkitDialog';\nimport DialogInner from './DialogInner';\nimport DialogShell from './DialogShell';\n\nexport type BitkitFormDialogProps = BitkitDialogProps & {\n /** Skips the browser's native constraint validation on submit. */\n noValidate?: boolean;\n onSubmit?: FormEventHandler<HTMLFormElement>;\n};\n\n/**\n * A dialog whose entire content is a `<form>`, so a `type=\"submit\"` button in the footer submits\n * natively. Like the other dialog overlays it owns its own layout, so the form surface is just\n * `onSubmit` and `noValidate` — no Chakra style props, no `className`, no `id`.\n */\nconst BitkitFormDialog = forwardRef<HTMLFormElement, BitkitFormDialogProps>((props, ref) => {\n const {\n children,\n closable = true,\n footerButtons,\n footerContent,\n headerLabel,\n initialFocusEl,\n maxHeight,\n noValidate,\n onExitComplete,\n onOpenChange,\n onSubmit,\n open,\n preventScroll,\n scrollBehavior,\n showScrollGradient,\n size,\n title,\n trigger,\n variant,\n ...dataAttributes\n } = props;\n\n return (\n <DialogShell\n closable={closable}\n initialFocusEl={initialFocusEl}\n onExitComplete={onExitComplete}\n onOpenChange={onOpenChange}\n open={open}\n preventScroll={preventScroll}\n scrollBehavior={scrollBehavior}\n size={size}\n trigger={trigger}\n variant={variant}\n >\n <Dialog.Content asChild maxHeight={maxHeight} {...dataAttributes}>\n <chakra.form ref={ref} noValidate={noValidate} onSubmit={onSubmit}>\n <DialogInner\n closable={closable}\n footerButtons={footerButtons}\n footerContent={footerContent}\n headerLabel={headerLabel}\n scrollBehavior={scrollBehavior}\n showScrollGradient={showScrollGradient}\n title={title}\n variant={variant}\n >\n {children}\n </DialogInner>\n </chakra.form>\n </Dialog.Content>\n </DialogShell>\n );\n});\n\nBitkitFormDialog.displayName = 'BitkitFormDialog';\n\nexport default withSubComponents(BitkitFormDialog, { ActionTrigger: Dialog.ActionTrigger });\n"],"mappings":";;;;;;;;;;;;;AAoBA,IAAM,mBAAmB,YAAoD,OAAO,QAAQ;CAC1F,MAAM,EACJ,UACA,WAAW,MACX,eACA,eACA,aACA,gBACA,WACA,YACA,gBACA,cACA,UACA,MACA,eACA,gBACA,oBACA,MACA,OACA,SACA,SACA,GAAG,mBACD;CAEJ,OACE,oBAAC,aAAD;EACY;EACM;EACA;EACF;EACR;EACS;EACC;EACV;EACG;EACA;EAET,UAAA,oBAAC,OAAO,SAAR;GAAgB,SAAA;GAAmB;GAAW,GAAI;GAChD,UAAA,oBAAC,OAAO,MAAR;IAAkB;IAAiB;IAAsB;IACvD,UAAA,oBAAC,aAAD;KACY;KACK;KACA;KACF;KACG;KACI;KACb;KACE;KAER;IACU,CAAA;GACF,CAAA;EACC,CAAA;CACL,CAAA;AAEjB,CAAC;AAED,iBAAiB,cAAc;AAE/B,IAAA,2BAAe,kBAAkB,kBAAkB,EAAE,eAAe,OAAO,cAAc,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Dialog } from '@chakra-ui/react/dialog';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
3
|
import { BitkitStepperDialogStepProps } from './BitkitStepperDialogStep';
|
|
4
|
-
import { DialogShellProps } from './DialogShell';
|
|
4
|
+
import { DialogDataAttributes, DialogShellProps } from './DialogShell';
|
|
5
5
|
export { useStepperDialog } from './StepperContext';
|
|
6
|
-
export
|
|
6
|
+
export type BitkitStepperDialogProps = {
|
|
7
7
|
/** `BitkitStepperDialog.Step` children, one per step. */
|
|
8
8
|
children: ReactNode;
|
|
9
9
|
closable?: boolean;
|
|
@@ -35,9 +35,9 @@ export interface BitkitStepperDialogProps {
|
|
|
35
35
|
title: ReactNode;
|
|
36
36
|
trigger?: ReactNode;
|
|
37
37
|
variant?: 'overflowContent';
|
|
38
|
-
}
|
|
38
|
+
} & DialogDataAttributes;
|
|
39
39
|
declare const _default: {
|
|
40
|
-
({ children, closable, defaultStep, initialFocusEl, footerContent, headerLabel, maxHeight, onExitComplete, onOpenChange, onStepChange, open, preventScroll, scrollBehavior, showScrollGradient, size, step: stepProp, title, trigger, variant, }: BitkitStepperDialogProps): import("react").JSX.Element;
|
|
40
|
+
({ children, closable, defaultStep, initialFocusEl, footerContent, headerLabel, maxHeight, onExitComplete, onOpenChange, onStepChange, open, preventScroll, scrollBehavior, showScrollGradient, size, step: stepProp, title, trigger, variant, ...dataAttributes }: BitkitStepperDialogProps): import("react").JSX.Element;
|
|
41
41
|
displayName: string;
|
|
42
42
|
} & {
|
|
43
43
|
ActionTrigger: import('react').ForwardRefExoticComponent<Dialog.ActionTriggerProps & import('react').RefAttributes<HTMLButtonElement>>;
|
|
@@ -13,7 +13,7 @@ import { Dialog } from "@chakra-ui/react/dialog";
|
|
|
13
13
|
* state, auto-renders the steps header, and shows only the active step's body. Footer navigation is
|
|
14
14
|
* wired by the consumer through the `useStepperDialog()` hook.
|
|
15
15
|
*/
|
|
16
|
-
var BitkitStepperDialog = ({ children, closable = true, defaultStep = 0, initialFocusEl, footerContent, headerLabel, maxHeight, onExitComplete, onOpenChange, onStepChange, open, preventScroll, scrollBehavior, showScrollGradient, size, step: stepProp, title, trigger, variant }) => {
|
|
16
|
+
var BitkitStepperDialog = ({ children, closable = true, defaultStep = 0, initialFocusEl, footerContent, headerLabel, maxHeight, onExitComplete, onOpenChange, onStepChange, open, preventScroll, scrollBehavior, showScrollGradient, size, step: stepProp, title, trigger, variant, ...dataAttributes }) => {
|
|
17
17
|
const [internalStep, setInternalStep] = useState(defaultStep);
|
|
18
18
|
const isControlled = stepProp !== void 0;
|
|
19
19
|
const rawStep = (isControlled ? stepProp : internalStep) ?? 0;
|
|
@@ -66,6 +66,7 @@ var BitkitStepperDialog = ({ children, closable = true, defaultStep = 0, initial
|
|
|
66
66
|
variant,
|
|
67
67
|
children: /* @__PURE__ */ jsx(Dialog.Content, {
|
|
68
68
|
maxHeight,
|
|
69
|
+
...dataAttributes,
|
|
69
70
|
children: /* @__PURE__ */ jsx(DialogInner, {
|
|
70
71
|
closable,
|
|
71
72
|
footerContent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitStepperDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitStepperDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { Children, isValidElement, type ReactElement, type ReactNode, useCallback, useMemo, useState } from 'react';\n\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitSteps from '../BitkitSteps/BitkitSteps';\nimport BitkitStepperDialogStep, { type BitkitStepperDialogStepProps } from './BitkitStepperDialogStep';\nimport DialogInner from './DialogInner';\nimport DialogShell, { type DialogShellProps } from './DialogShell';\nimport { StepperDialogProvider } from './StepperContext';\n\nexport { useStepperDialog } from './StepperContext';\n\nexport
|
|
1
|
+
{"version":3,"file":"BitkitStepperDialog.js","names":[],"sources":["../../../lib/components/BitkitDialog/BitkitStepperDialog.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { Children, isValidElement, type ReactElement, type ReactNode, useCallback, useMemo, useState } from 'react';\n\nimport { withSubComponents } from '../../utilities/withSubComponents';\nimport BitkitSteps from '../BitkitSteps/BitkitSteps';\nimport BitkitStepperDialogStep, { type BitkitStepperDialogStepProps } from './BitkitStepperDialogStep';\nimport DialogInner from './DialogInner';\nimport DialogShell, { type DialogDataAttributes, type DialogShellProps } from './DialogShell';\nimport { StepperDialogProvider } from './StepperContext';\n\nexport { useStepperDialog } from './StepperContext';\n\nexport type BitkitStepperDialogProps = {\n /** `BitkitStepperDialog.Step` children, one per step. */\n children: ReactNode;\n closable?: boolean;\n /** Initial step when uncontrolled. Resets to this when the dialog closes. */\n defaultStep?: number;\n /** Element to focus when the dialog opens, instead of the first focusable one. */\n initialFocusEl?: DialogShellProps['initialFocusEl'];\n /**\n * Footer content rendered raw. Stepper footers are space-between (Cancel left, Prev/Next right),\n * so build the nav row here with `useStepperDialog()` — there is no `footerButtons` slot, which\n * would force right-alignment.\n */\n footerContent?: ReactNode;\n headerLabel?: string;\n maxHeight?: string;\n onExitComplete?: () => void;\n onOpenChange?: (details: { open: boolean }) => void;\n /** Called whenever the active step changes (controlled or uncontrolled). */\n onStepChange?: (step: number) => void;\n open?: boolean;\n preventScroll?: boolean;\n scrollBehavior?: 'inside' | 'outside';\n showScrollGradient?: boolean;\n size?: 'sm' | 'md' | 'lg' | 'full';\n /** Controlled active step. Omit for uncontrolled (see `defaultStep`). */\n step?: number;\n title: ReactNode;\n trigger?: ReactNode;\n variant?: 'overflowContent';\n} & DialogDataAttributes;\n\n/**\n * A dialog that walks through a sequence of `BitkitStepperDialog.Step` children. It owns the step\n * state, auto-renders the steps header, and shows only the active step's body. Footer navigation is\n * wired by the consumer through the `useStepperDialog()` hook.\n */\nconst BitkitStepperDialog = ({\n children,\n closable = true,\n defaultStep = 0,\n initialFocusEl,\n footerContent,\n headerLabel,\n maxHeight,\n onExitComplete,\n onOpenChange,\n onStepChange,\n open,\n preventScroll,\n scrollBehavior,\n showScrollGradient,\n size,\n step: stepProp,\n title,\n trigger,\n variant,\n ...dataAttributes\n}: BitkitStepperDialogProps) => {\n const [internalStep, setInternalStep] = useState(defaultStep);\n const isControlled = stepProp !== undefined;\n const rawStep = (isControlled ? stepProp : internalStep) ?? 0;\n const steps = Children.toArray(children).filter(\n (child): child is ReactElement<BitkitStepperDialogStepProps> =>\n isValidElement(child) && child.type === BitkitStepperDialogStep,\n );\n const totalSteps = steps.length;\n const step = Math.max(0, Math.min(rawStep, Math.max(0, totalSteps - 1)));\n\n const setStep = useCallback(\n (next: number) => {\n const clamped = Math.max(0, Math.min(next, totalSteps - 1));\n if (!isControlled) setInternalStep(clamped);\n onStepChange?.(clamped);\n },\n [isControlled, onStepChange, totalSteps],\n );\n\n const ctx = useMemo(\n () => ({\n goTo: setStep,\n isFirst: step === 0,\n isLast: step === totalSteps - 1,\n next: () => setStep(step + 1),\n prev: () => setStep(step - 1),\n setStep,\n step,\n totalSteps,\n }),\n [setStep, step, totalSteps],\n );\n\n const handleOpenChange = (details: { open: boolean }) => {\n if (!details.open && !isControlled) setInternalStep(defaultStep);\n onOpenChange?.(details);\n };\n\n const stepsHeader = (\n <BitkitSteps step={step}>\n {steps.map((child, index) => (\n <BitkitSteps.Item key={index} label={child.props.label} />\n ))}\n </BitkitSteps>\n );\n\n return (\n <StepperDialogProvider value={ctx}>\n <DialogShell\n closable={closable}\n initialFocusEl={initialFocusEl}\n onExitComplete={onExitComplete}\n onOpenChange={handleOpenChange}\n open={open}\n preventScroll={preventScroll}\n scrollBehavior={scrollBehavior}\n size={size}\n trigger={trigger}\n variant={variant}\n >\n <Dialog.Content maxHeight={maxHeight} {...dataAttributes}>\n <DialogInner\n closable={closable}\n footerContent={footerContent}\n headerExtra={stepsHeader}\n headerLabel={headerLabel}\n scrollBehavior={scrollBehavior}\n showScrollGradient={showScrollGradient}\n title={title}\n variant={variant}\n >\n {steps[step]}\n </DialogInner>\n </Dialog.Content>\n </DialogShell>\n </StepperDialogProvider>\n );\n};\n\nBitkitStepperDialog.displayName = 'BitkitStepperDialog';\n\nexport default withSubComponents(BitkitStepperDialog, {\n ActionTrigger: Dialog.ActionTrigger,\n Step: BitkitStepperDialogStep,\n});\n"],"mappings":";;;;;;;;;;;;;;;AAiDA,IAAM,uBAAuB,EAC3B,UACA,WAAW,MACX,cAAc,GACd,gBACA,eACA,aACA,WACA,gBACA,cACA,cACA,MACA,eACA,gBACA,oBACA,MACA,MAAM,UACN,OACA,SACA,SACA,GAAG,qBAC2B;CAC9B,MAAM,CAAC,cAAc,mBAAmB,SAAS,WAAW;CAC5D,MAAM,eAAe,aAAa,KAAA;CAClC,MAAM,WAAW,eAAe,WAAW,iBAAiB;CAC5D,MAAM,QAAQ,SAAS,QAAQ,QAAQ,CAAC,CAAC,QACtC,UACC,eAAe,KAAK,KAAK,MAAM,SAAS,uBAC5C;CACA,MAAM,aAAa,MAAM;CACzB,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC;CAEvE,MAAM,UAAU,aACb,SAAiB;EAChB,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,aAAa,CAAC,CAAC;EAC1D,IAAI,CAAC,cAAc,gBAAgB,OAAO;EAC1C,eAAe,OAAO;CACxB,GACA;EAAC;EAAc;EAAc;CAAU,CACzC;CAEA,MAAM,MAAM,eACH;EACL,MAAM;EACN,SAAS,SAAS;EAClB,QAAQ,SAAS,aAAa;EAC9B,YAAY,QAAQ,OAAO,CAAC;EAC5B,YAAY,QAAQ,OAAO,CAAC;EAC5B;EACA;EACA;CACF,IACA;EAAC;EAAS;EAAM;CAAU,CAC5B;CAEA,MAAM,oBAAoB,YAA+B;EACvD,IAAI,CAAC,QAAQ,QAAQ,CAAC,cAAc,gBAAgB,WAAW;EAC/D,eAAe,OAAO;CACxB;CAEA,MAAM,cACJ,oBAAC,qBAAD;EAAmB;EAChB,UAAA,MAAM,KAAK,OAAO,UACjB,oBAAC,oBAAY,MAAb,EAA8B,OAAO,MAAM,MAAM,MAAQ,GAAlC,KAAkC,CAC1D;CACU,CAAA;CAGf,OACE,oBAAC,uBAAD;EAAuB,OAAO;EAC5B,UAAA,oBAAC,aAAD;GACY;GACM;GACA;GAChB,cAAc;GACR;GACS;GACC;GACV;GACG;GACA;GAET,UAAA,oBAAC,OAAO,SAAR;IAA2B;IAAW,GAAI;IACxC,UAAA,oBAAC,aAAD;KACY;KACK;KACf,aAAa;KACA;KACG;KACI;KACb;KACE;KAER,UAAA,MAAM;IACI,CAAA;GACC,CAAA;EACL,CAAA;CACQ,CAAA;AAE3B;AAEA,oBAAoB,cAAc;AAElC,IAAA,8BAAe,kBAAkB,qBAAqB;CACpD,eAAe,OAAO;CACtB,MAAM;AACR,CAAC"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { Dialog } from '@chakra-ui/react/dialog';
|
|
2
2
|
import { ComponentProps, ReactNode } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Data attributes every dialog flavour forwards to its content element — the one carrying
|
|
5
|
+
* `role="dialog"`. The case this exists for is `data-clarity-unmask`, which opts a region out of
|
|
6
|
+
* session replay masking, exactly where support needs to read it.
|
|
7
|
+
*/
|
|
8
|
+
export interface DialogDataAttributes {
|
|
9
|
+
[dataAttribute: `data-${string}`]: string | undefined;
|
|
10
|
+
}
|
|
3
11
|
export interface DialogShellProps {
|
|
4
12
|
/** The `Dialog.Content` element (rendered inside the positioner). */
|
|
5
13
|
children: ReactNode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialogShell.js","names":[],"sources":["../../../lib/components/BitkitDialog/DialogShell.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { type ComponentProps, type ReactNode } from 'react';\n\nimport { resolveScrollBehavior } from './DialogBodyContext';\n\nexport interface DialogShellProps {\n /** The `Dialog.Content` element (rendered inside the positioner). */\n children: ReactNode;\n closable?: boolean;\n /** Element to focus when the dialog opens, instead of the first focusable one. */\n initialFocusEl?: ComponentProps<typeof Dialog.Root>['initialFocusEl'];\n onExitComplete?: () => void;\n onOpenChange?: (details: { open: boolean }) => void;\n open?: boolean;\n preventScroll?: boolean;\n scrollBehavior?: 'inside' | 'outside';\n size?: 'sm' | 'md' | 'lg' | 'full';\n trigger?: ReactNode;\n variant?: 'overflowContent';\n}\n\n/**\n * Shared overlay shell for every Bitkit dialog flavour: `Dialog.Root` + optional trigger + portal +\n * backdrop + positioner. Dismiss policy is derived from `closable` for ESC/close-trigger; outside\n * clicks are always ignored (`closeOnInteractOutside={false}`). Note that `closable` does not reach\n * `ActionTrigger` -- a footer button wired to it closes the dialog either way, so a caller that has\n * to block every route out disables that button itself.\n * The caller passes the `Dialog.Content` (or a `Dialog.Content asChild` wrapper) as children.\n **/\n\nconst DialogShell = ({\n children,\n closable = true,\n initialFocusEl,\n onExitComplete,\n onOpenChange,\n open,\n preventScroll = true,\n scrollBehavior: scrollBehaviorProp,\n size,\n trigger,\n variant,\n}: DialogShellProps) => {\n const scrollBehavior = resolveScrollBehavior(variant, scrollBehaviorProp);\n\n return (\n <Dialog.Root\n closeOnEscape={closable}\n closeOnInteractOutside={false}\n initialFocusEl={initialFocusEl}\n onExitComplete={onExitComplete}\n onOpenChange={onOpenChange}\n open={open}\n preventScroll={preventScroll}\n scrollBehavior={scrollBehavior}\n size={size}\n variant={variant}\n >\n {trigger && <Dialog.Trigger asChild>{trigger}</Dialog.Trigger>}\n <Portal>\n <Dialog.Backdrop />\n <Dialog.Positioner>{children}</Dialog.Positioner>\n </Portal>\n </Dialog.Root>\n );\n};\n\nexport default DialogShell;\n"],"mappings":";;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"DialogShell.js","names":[],"sources":["../../../lib/components/BitkitDialog/DialogShell.tsx"],"sourcesContent":["import { Dialog } from '@chakra-ui/react/dialog';\nimport { Portal } from '@chakra-ui/react/portal';\nimport { type ComponentProps, type ReactNode } from 'react';\n\nimport { resolveScrollBehavior } from './DialogBodyContext';\n\n/**\n * Data attributes every dialog flavour forwards to its content element — the one carrying\n * `role=\"dialog\"`. The case this exists for is `data-clarity-unmask`, which opts a region out of\n * session replay masking, exactly where support needs to read it.\n */\nexport interface DialogDataAttributes {\n [dataAttribute: `data-${string}`]: string | undefined;\n}\n\nexport interface DialogShellProps {\n /** The `Dialog.Content` element (rendered inside the positioner). */\n children: ReactNode;\n closable?: boolean;\n /** Element to focus when the dialog opens, instead of the first focusable one. */\n initialFocusEl?: ComponentProps<typeof Dialog.Root>['initialFocusEl'];\n onExitComplete?: () => void;\n onOpenChange?: (details: { open: boolean }) => void;\n open?: boolean;\n preventScroll?: boolean;\n scrollBehavior?: 'inside' | 'outside';\n size?: 'sm' | 'md' | 'lg' | 'full';\n trigger?: ReactNode;\n variant?: 'overflowContent';\n}\n\n/**\n * Shared overlay shell for every Bitkit dialog flavour: `Dialog.Root` + optional trigger + portal +\n * backdrop + positioner. Dismiss policy is derived from `closable` for ESC/close-trigger; outside\n * clicks are always ignored (`closeOnInteractOutside={false}`). Note that `closable` does not reach\n * `ActionTrigger` -- a footer button wired to it closes the dialog either way, so a caller that has\n * to block every route out disables that button itself.\n * The caller passes the `Dialog.Content` (or a `Dialog.Content asChild` wrapper) as children.\n **/\n\nconst DialogShell = ({\n children,\n closable = true,\n initialFocusEl,\n onExitComplete,\n onOpenChange,\n open,\n preventScroll = true,\n scrollBehavior: scrollBehaviorProp,\n size,\n trigger,\n variant,\n}: DialogShellProps) => {\n const scrollBehavior = resolveScrollBehavior(variant, scrollBehaviorProp);\n\n return (\n <Dialog.Root\n closeOnEscape={closable}\n closeOnInteractOutside={false}\n initialFocusEl={initialFocusEl}\n onExitComplete={onExitComplete}\n onOpenChange={onOpenChange}\n open={open}\n preventScroll={preventScroll}\n scrollBehavior={scrollBehavior}\n size={size}\n variant={variant}\n >\n {trigger && <Dialog.Trigger asChild>{trigger}</Dialog.Trigger>}\n <Portal>\n <Dialog.Backdrop />\n <Dialog.Positioner>{children}</Dialog.Positioner>\n </Portal>\n </Dialog.Root>\n );\n};\n\nexport default DialogShell;\n"],"mappings":";;;;;;;;;;;;;AAwCA,IAAM,eAAe,EACnB,UACA,WAAW,MACX,gBACA,gBACA,cACA,MACA,gBAAgB,MAChB,gBAAgB,oBAChB,MACA,SACA,cACsB;CACtB,MAAM,iBAAiB,sBAAsB,SAAS,kBAAkB;CAExE,OACE,qBAAC,OAAO,MAAR;EACE,eAAe;EACf,wBAAwB;EACR;EACA;EACF;EACR;EACS;EACC;EACV;EACG;EAVX,UAAA,CAYG,WAAW,oBAAC,OAAO,SAAR;GAAgB,SAAA;GAAS,UAAA;EAAwB,CAAA,GAC7D,qBAAC,QAAD,EAAA,UAAA,CACE,oBAAC,OAAO,UAAR,CAAkB,CAAA,GAClB,oBAAC,OAAO,YAAR,EAAoB,SAA4B,CAAA,CAC1C,EAAA,CAAA,CACG;;AAEjB"}
|
|
@@ -22,8 +22,9 @@ export interface BitkitNativeSelectProps extends Omit<BitkitFieldProps, 'childre
|
|
|
22
22
|
/** Field size — controls height and typography. */
|
|
23
23
|
size?: 'md' | 'lg';
|
|
24
24
|
/**
|
|
25
|
-
* Field state. `error`/`warning` are also implied by `errorText`/`warningText
|
|
26
|
-
* `readOnly`
|
|
25
|
+
* Field state. `error`/`warning` are also implied by `errorText`/`warningText`. `disabled` takes the
|
|
26
|
+
* field out of the form altogether; `readOnly` keeps it focusable and submitted, only pinning the
|
|
27
|
+
* selected value.
|
|
27
28
|
*/
|
|
28
29
|
state?: 'disabled' | 'error' | 'readOnly' | 'warning';
|
|
29
30
|
/** Controlled selected value. Pair with `onValueChange` or the native `onChange`. */
|
|
@@ -15,6 +15,21 @@ var FIELD_PROPS = [
|
|
|
15
15
|
"placeholder",
|
|
16
16
|
"value"
|
|
17
17
|
];
|
|
18
|
+
var READ_ONLY_ALLOWED_KEYS = [
|
|
19
|
+
"Enter",
|
|
20
|
+
"Escape",
|
|
21
|
+
"Tab"
|
|
22
|
+
];
|
|
23
|
+
var READ_ONLY_PROPS = {
|
|
24
|
+
"aria-readonly": true,
|
|
25
|
+
onKeyDown: (event) => {
|
|
26
|
+
if (READ_ONLY_ALLOWED_KEYS.includes(event.key) || event.ctrlKey || event.metaKey) return;
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
},
|
|
29
|
+
onMouseDown: (event) => {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
18
33
|
/**
|
|
19
34
|
* A dropdown built on the native `<select>` — pass the `<option>` elements as children. Reflect the
|
|
20
35
|
* selection with `value` + `onValueChange` (or the native `onChange`); `selectProps` is the escape
|
|
@@ -22,6 +37,7 @@ var FIELD_PROPS = [
|
|
|
22
37
|
*/
|
|
23
38
|
var BitkitNativeSelect = forwardRef((props, ref) => {
|
|
24
39
|
const { children, onValueChange, selectProps, size = "md", state, ...rest } = props;
|
|
40
|
+
const isReadOnly = state === "readOnly";
|
|
25
41
|
const [nativeFieldProps, bitkitFieldProps] = splitProps(rest, [...FIELD_PROPS]);
|
|
26
42
|
const styles = useSlotRecipe({ key: "nativeSelect" })();
|
|
27
43
|
const hasWarning = state === "warning" || !!bitkitFieldProps.warningText;
|
|
@@ -53,12 +69,20 @@ var BitkitNativeSelect = forwardRef((props, ref) => {
|
|
|
53
69
|
ref,
|
|
54
70
|
onChange: handleChange,
|
|
55
71
|
...restFieldProps,
|
|
72
|
+
...isReadOnly && READ_ONLY_PROPS,
|
|
56
73
|
children
|
|
57
74
|
}),
|
|
58
75
|
statusIcon,
|
|
59
76
|
/* @__PURE__ */ jsx(NativeSelect.Indicator, {
|
|
60
77
|
asChild: true,
|
|
61
|
-
children: /* @__PURE__ */ jsx(AssetSelectChevron, {
|
|
78
|
+
children: /* @__PURE__ */ jsx(AssetSelectChevron, {
|
|
79
|
+
pointerEvents: "none",
|
|
80
|
+
...isReadOnly && {
|
|
81
|
+
_groupFocusWithin: { color: "icon/on-disabled" },
|
|
82
|
+
_groupHover: { color: "icon/on-disabled" },
|
|
83
|
+
color: "icon/on-disabled"
|
|
84
|
+
}
|
|
85
|
+
})
|
|
62
86
|
})
|
|
63
87
|
]
|
|
64
88
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BitkitNativeSelect.js","names":[],"sources":["../../../lib/components/BitkitNativeSelect/BitkitNativeSelect.tsx"],"sourcesContent":["import { NativeSelect, type NativeSelectRootProps } from '@chakra-ui/react/native-select';\nimport { useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { splitProps } from '@zag-js/utils';\nimport { type ChangeEventHandler, forwardRef, type ReactNode } from 'react';\n\nimport { IconErrorCircleFilled, IconWarningYellow } from '../../icons';\nimport AssetSelectChevron from '../../utilities/AssetSelectChevron.tsx';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField.tsx';\n\nconst FIELD_PROPS = ['defaultValue', 'name', 'onChange', 'placeholder', 'value'] as const;\n\nexport interface BitkitNativeSelectProps extends Omit<\n BitkitFieldProps,\n 'children' | 'disabled' | 'invalid' | 'onChange' | 'readOnly'\n> {\n /** The `<option>` (and `<optgroup>`) elements to render inside the select. */\n children: ReactNode;\n /** Initially selected option value, for uncontrolled usage. */\n defaultValue?: string;\n /** Form field name submitted with the enclosing form. */\n name?: string;\n /**\n * Native `change` event of the underlying `<select>`. Reach for `onValueChange` when you only need\n * the selected value.\n */\n onChange?: ChangeEventHandler<HTMLSelectElement>;\n /** Convenience change handler that receives the selected value directly, without `event.target.value`. */\n onValueChange?: (value: string) => void;\n /** Placeholder option shown while no value is selected. */\n placeholder?: string;\n /** Escape hatch for the underlying Chakra `NativeSelect.Root` wrapper. */\n selectProps?: NativeSelectRootProps;\n /** Field size — controls height and typography. */\n size?: 'md' | 'lg';\n /**\n * Field state. `error`/`warning` are also implied by `errorText`/`warningText
|
|
1
|
+
{"version":3,"file":"BitkitNativeSelect.js","names":[],"sources":["../../../lib/components/BitkitNativeSelect/BitkitNativeSelect.tsx"],"sourcesContent":["import { NativeSelect, type NativeSelectRootProps } from '@chakra-ui/react/native-select';\nimport { useSlotRecipe } from '@chakra-ui/react/styled-system';\nimport { splitProps } from '@zag-js/utils';\nimport { type ChangeEventHandler, forwardRef, type KeyboardEvent, type MouseEvent, type ReactNode } from 'react';\n\nimport { IconErrorCircleFilled, IconWarningYellow } from '../../icons';\nimport AssetSelectChevron from '../../utilities/AssetSelectChevron.tsx';\nimport BitkitField, { type BitkitFieldProps } from '../BitkitField/BitkitField.tsx';\n\nconst FIELD_PROPS = ['defaultValue', 'name', 'onChange', 'placeholder', 'value'] as const;\n\n// Keys a closed `<select>` cannot change its value with, so read-only has no reason to swallow them:\n// Tab moves on, Escape dismisses an enclosing overlay, and Enter still submits the surrounding form.\nconst READ_ONLY_ALLOWED_KEYS: readonly string[] = ['Enter', 'Escape', 'Tab'];\n\n// A native `<select>` has no read-only mode: the browser ignores the `readonly` attribute on it, so\n// the state has to be enforced by hand. Blocking the interaction rather than the control is the\n// point of read-only over `disabled` — the field stays focusable and its value is still submitted.\nconst READ_ONLY_PROPS = {\n 'aria-readonly': true,\n onKeyDown: (event: KeyboardEvent<HTMLSelectElement>) => {\n // Ctrl/Cmd shortcuts belong to the browser and never reach the select's value. Alt is not on the\n // list: Alt+Arrow opens the dropdown.\n if (READ_ONLY_ALLOWED_KEYS.includes(event.key) || event.ctrlKey || event.metaKey) {\n return;\n }\n\n event.preventDefault();\n },\n // Preventing the default also suppresses the click's focus, which is what we want: Chrome treats a\n // clicked `<select>` as focus-visible, so the field would take the focus ring on a mere click. It\n // stays reachable by Tab, and BitkitSelect's read-only trigger shows nothing on click either.\n onMouseDown: (event: MouseEvent<HTMLSelectElement>) => {\n event.preventDefault();\n },\n} as const;\n\nexport interface BitkitNativeSelectProps extends Omit<\n BitkitFieldProps,\n 'children' | 'disabled' | 'invalid' | 'onChange' | 'readOnly'\n> {\n /** The `<option>` (and `<optgroup>`) elements to render inside the select. */\n children: ReactNode;\n /** Initially selected option value, for uncontrolled usage. */\n defaultValue?: string;\n /** Form field name submitted with the enclosing form. */\n name?: string;\n /**\n * Native `change` event of the underlying `<select>`. Reach for `onValueChange` when you only need\n * the selected value.\n */\n onChange?: ChangeEventHandler<HTMLSelectElement>;\n /** Convenience change handler that receives the selected value directly, without `event.target.value`. */\n onValueChange?: (value: string) => void;\n /** Placeholder option shown while no value is selected. */\n placeholder?: string;\n /** Escape hatch for the underlying Chakra `NativeSelect.Root` wrapper. */\n selectProps?: NativeSelectRootProps;\n /** Field size — controls height and typography. */\n size?: 'md' | 'lg';\n /**\n * Field state. `error`/`warning` are also implied by `errorText`/`warningText`. `disabled` takes the\n * field out of the form altogether; `readOnly` keeps it focusable and submitted, only pinning the\n * selected value.\n */\n state?: 'disabled' | 'error' | 'readOnly' | 'warning';\n /** Controlled selected value. Pair with `onValueChange` or the native `onChange`. */\n value?: string;\n}\n\n/**\n * A dropdown built on the native `<select>` — pass the `<option>` elements as children. Reflect the\n * selection with `value` + `onValueChange` (or the native `onChange`); `selectProps` is the escape\n * hatch for the underlying wrapper. Includes the standard label and helper/error/warning chrome.\n */\nconst BitkitNativeSelect = forwardRef<HTMLSelectElement, BitkitNativeSelectProps>(\n (props: BitkitNativeSelectProps, ref) => {\n const { children, onValueChange, selectProps, size = 'md', state, ...rest } = props;\n const isReadOnly = state === 'readOnly';\n const [nativeFieldProps, bitkitFieldProps] = splitProps(rest, [...FIELD_PROPS]);\n\n const recipe = useSlotRecipe({ key: 'nativeSelect' });\n const styles = recipe();\n\n const hasWarning = state === 'warning' || !!bitkitFieldProps.warningText;\n const isInvalid = state === 'error' || !!bitkitFieldProps.errorText;\n\n let statusIcon = undefined;\n if (isInvalid) {\n statusIcon = (\n <IconErrorCircleFilled size={size === 'lg' ? '24' : '16'} css={styles.statusIcon} color=\"icon/negative\" />\n );\n } else if (hasWarning) {\n statusIcon = <IconWarningYellow size={size === 'lg' ? '24' : '16'} css={styles.statusIcon} />;\n }\n\n // `onValueChange` fires alongside the native `onChange`, with the selected value.\n const { onChange: fieldOnChange, ...restFieldProps } = nativeFieldProps;\n const handleChange: ChangeEventHandler<HTMLSelectElement> | undefined =\n onValueChange || fieldOnChange\n ? (event) => {\n onValueChange?.(event.target.value);\n fieldOnChange?.(event);\n }\n : undefined;\n\n return (\n <BitkitField state={state} {...bitkitFieldProps}>\n <NativeSelect.Root size={size} {...selectProps} className=\"group\">\n <NativeSelect.Field\n ref={ref}\n onChange={handleChange}\n {...restFieldProps}\n {...(isReadOnly && READ_ONLY_PROPS)}\n >\n {children}\n </NativeSelect.Field>\n {statusIcon}\n <NativeSelect.Indicator asChild>\n {/*\n A read-only chevron is inert, so it takes BitkitSelect's read-only indicator colour and\n drops both affordances: hover, and focus-within — which a plain click triggers. Chakra's\n `NativeSelect.Indicator` forwards only `data-disabled`/`data-invalid`, so the recipe's\n `indicator` slot cannot see the read-only state and this has to live here.\n */}\n <AssetSelectChevron\n pointerEvents=\"none\"\n {...(isReadOnly && {\n _groupFocusWithin: { color: 'icon/on-disabled' },\n _groupHover: { color: 'icon/on-disabled' },\n color: 'icon/on-disabled',\n })}\n />\n </NativeSelect.Indicator>\n </NativeSelect.Root>\n </BitkitField>\n );\n },\n);\n\nBitkitNativeSelect.displayName = 'BitkitNativeSelect';\n\nexport default BitkitNativeSelect;\n"],"mappings":";;;;;;;;;;AASA,IAAM,cAAc;CAAC;CAAgB;CAAQ;CAAY;CAAe;AAAO;AAI/E,IAAM,yBAA4C;CAAC;CAAS;CAAU;AAAK;AAK3E,IAAM,kBAAkB;CACtB,iBAAiB;CACjB,YAAY,UAA4C;EAGtD,IAAI,uBAAuB,SAAS,MAAM,GAAG,KAAK,MAAM,WAAW,MAAM,SACvE;EAGF,MAAM,eAAe;CACvB;CAIA,cAAc,UAAyC;EACrD,MAAM,eAAe;CACvB;AACF;;;;;;AAwCA,IAAM,qBAAqB,YACxB,OAAgC,QAAQ;CACvC,MAAM,EAAE,UAAU,eAAe,aAAa,OAAO,MAAM,OAAO,GAAG,SAAS;CAC9E,MAAM,aAAa,UAAU;CAC7B,MAAM,CAAC,kBAAkB,oBAAoB,WAAW,MAAM,CAAC,GAAG,WAAW,CAAC;CAG9E,MAAM,SADS,cAAc,EAAE,KAAK,eAAe,CACpC,CAAA,CAAO;CAEtB,MAAM,aAAa,UAAU,aAAa,CAAC,CAAC,iBAAiB;CAC7D,MAAM,YAAY,UAAU,WAAW,CAAC,CAAC,iBAAiB;CAE1D,IAAI,aAAa,KAAA;CACjB,IAAI,WACF,aACE,oBAAC,uBAAD;EAAuB,MAAM,SAAS,OAAO,OAAO;EAAM,KAAK,OAAO;EAAY,OAAM;CAAiB,CAAA;MAEtG,IAAI,YACT,aAAa,oBAAC,mBAAD;EAAmB,MAAM,SAAS,OAAO,OAAO;EAAM,KAAK,OAAO;CAAa,CAAA;CAI9F,MAAM,EAAE,UAAU,eAAe,GAAG,mBAAmB;CACvD,MAAM,eACJ,iBAAiB,iBACZ,UAAU;EACT,gBAAgB,MAAM,OAAO,KAAK;EAClC,gBAAgB,KAAK;CACvB,IACA,KAAA;CAEN,OACE,oBAAC,aAAD;EAAoB;EAAO,GAAI;EAC7B,UAAA,qBAAC,aAAa,MAAd;GAAyB;GAAM,GAAI;GAAa,WAAU;GAA1D,UAAA;IACE,oBAAC,aAAa,OAAd;KACO;KACL,UAAU;KACV,GAAI;KACJ,GAAK,cAAc;KAElB;IACiB,CAAA;IACnB;IACD,oBAAC,aAAa,WAAd;KAAwB,SAAA;KAOtB,UAAA,oBAAC,oBAAD;MACE,eAAc;MACd,GAAK,cAAc;OACjB,mBAAmB,EAAE,OAAO,mBAAmB;OAC/C,aAAa,EAAE,OAAO,mBAAmB;OACzC,OAAO;MACT;KACD,CAAA;IACqB,CAAA;GACP;;CACR,CAAA;AAEjB,CACF;AAEA,mBAAmB,cAAc"}
|
|
@@ -29,6 +29,11 @@ var nativeSelectSlotRecipe = defineSlotRecipe({
|
|
|
29
29
|
background: "background/disabled",
|
|
30
30
|
cursor: "not-allowed"
|
|
31
31
|
},
|
|
32
|
+
_readOnly: {
|
|
33
|
+
_hover: { borderColor: "border/strong" },
|
|
34
|
+
background: "background/disabled",
|
|
35
|
+
cursor: "default"
|
|
36
|
+
},
|
|
32
37
|
_placeholderShown: { color: "input/text/placeholder" }
|
|
33
38
|
},
|
|
34
39
|
statusIcon: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeSelect.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/NativeSelect.recipe.ts"],"sourcesContent":["import { nativeSelectAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst nativeSelectSlotRecipe = defineSlotRecipe({\n className: 'native-select',\n slots: [...nativeSelectAnatomy.keys(), 'statusIcon'],\n base: {\n root: {\n position: 'relative',\n },\n field: {\n width: '100%',\n minWidth: 0,\n appearance: 'none',\n borderRadius: '4',\n borderWidth: '1',\n borderColor: 'border/strong',\n background: 'background/primary',\n transition: '200ms',\n color: 'input/text/inputValue',\n _hover: {\n borderColor: 'border/hover',\n _invalid: {\n borderColor: 'border/error',\n },\n },\n _invalid: {\n borderColor: 'border/error',\n },\n _disabled: {\n _hover: {\n borderColor: 'border/disabled',\n },\n _placeholder: {\n color: 'text/disabled',\n },\n color: 'text/disabled',\n background: 'background/disabled',\n cursor: 'not-allowed',\n },\n _placeholderShown: {\n color: 'input/text/placeholder',\n },\n },\n statusIcon: {\n position: 'absolute',\n top: '50%',\n right: '48',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n },\n indicator: {\n position: 'absolute',\n top: '50%',\n right: rem(15),\n transform: 'translateY(-50%)',\n },\n },\n variants: {\n size: {\n md: {\n field: { paddingInline: rem(11), paddingBlock: rem(9), textStyle: 'body/md/regular' },\n },\n lg: {\n field: { paddingInline: rem(15), paddingBlock: rem(11), textStyle: 'body/lg/regular' },\n },\n },\n },\n defaultVariants: {\n size: 'lg',\n },\n});\n\nexport default nativeSelectSlotRecipe;\n"],"mappings":";;;;AAKA,IAAM,yBAAyB,iBAAiB;CAC9C,WAAW;CACX,OAAO,CAAC,GAAG,oBAAoB,KAAK,GAAG,YAAY;CACnD,MAAM;EACJ,MAAM,EACJ,UAAU,WACZ;EACA,OAAO;GACL,OAAO;GACP,UAAU;GACV,YAAY;GACZ,cAAc;GACd,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,OAAO;GACP,QAAQ;IACN,aAAa;IACb,UAAU,EACR,aAAa,eACf;GACF;GACA,UAAU,EACR,aAAa,eACf;GACA,WAAW;IACT,QAAQ,EACN,aAAa,kBACf;IACA,cAAc,EACZ,OAAO,gBACT;IACA,OAAO;IACP,YAAY;IACZ,QAAQ;GACV;GACA,mBAAmB,EACjB,OAAO,yBACT;EACF;EACA,YAAY;GACV,UAAU;GACV,KAAK;GACL,OAAO;GACP,WAAW;GACX,eAAe;EACjB;EACA,WAAW;GACT,UAAU;GACV,KAAK;GACL,OAAO,IAAI,EAAE;GACb,WAAW;EACb;CACF;CACA,UAAU,EACR,MAAM;EACJ,IAAI,EACF,OAAO;GAAE,eAAe,IAAI,EAAE;GAAG,cAAc,IAAI,CAAC;GAAG,WAAW;EAAkB,EACtF;EACA,IAAI,EACF,OAAO;GAAE,eAAe,IAAI,EAAE;GAAG,cAAc,IAAI,EAAE;GAAG,WAAW;EAAkB,EACvF;CACF,EACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"NativeSelect.recipe.js","names":[],"sources":["../../../lib/theme/slot-recipes/NativeSelect.recipe.ts"],"sourcesContent":["import { nativeSelectAnatomy } from '@chakra-ui/react/anatomy';\nimport { defineSlotRecipe } from '@chakra-ui/react/styled-system';\n\nimport { rem } from '../themeUtils';\n\nconst nativeSelectSlotRecipe = defineSlotRecipe({\n className: 'native-select',\n slots: [...nativeSelectAnatomy.keys(), 'statusIcon'],\n base: {\n root: {\n position: 'relative',\n },\n field: {\n width: '100%',\n minWidth: 0,\n appearance: 'none',\n borderRadius: '4',\n borderWidth: '1',\n borderColor: 'border/strong',\n background: 'background/primary',\n transition: '200ms',\n color: 'input/text/inputValue',\n _hover: {\n borderColor: 'border/hover',\n _invalid: {\n borderColor: 'border/error',\n },\n },\n _invalid: {\n borderColor: 'border/error',\n },\n _disabled: {\n _hover: {\n borderColor: 'border/disabled',\n },\n _placeholder: {\n color: 'text/disabled',\n },\n color: 'text/disabled',\n background: 'background/disabled',\n cursor: 'not-allowed',\n },\n _readOnly: {\n _hover: {\n borderColor: 'border/strong',\n },\n background: 'background/disabled',\n cursor: 'default',\n },\n _placeholderShown: {\n color: 'input/text/placeholder',\n },\n },\n statusIcon: {\n position: 'absolute',\n top: '50%',\n right: '48',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n },\n indicator: {\n position: 'absolute',\n top: '50%',\n right: rem(15),\n transform: 'translateY(-50%)',\n },\n },\n variants: {\n size: {\n md: {\n field: { paddingInline: rem(11), paddingBlock: rem(9), textStyle: 'body/md/regular' },\n },\n lg: {\n field: { paddingInline: rem(15), paddingBlock: rem(11), textStyle: 'body/lg/regular' },\n },\n },\n },\n defaultVariants: {\n size: 'lg',\n },\n});\n\nexport default nativeSelectSlotRecipe;\n"],"mappings":";;;;AAKA,IAAM,yBAAyB,iBAAiB;CAC9C,WAAW;CACX,OAAO,CAAC,GAAG,oBAAoB,KAAK,GAAG,YAAY;CACnD,MAAM;EACJ,MAAM,EACJ,UAAU,WACZ;EACA,OAAO;GACL,OAAO;GACP,UAAU;GACV,YAAY;GACZ,cAAc;GACd,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,OAAO;GACP,QAAQ;IACN,aAAa;IACb,UAAU,EACR,aAAa,eACf;GACF;GACA,UAAU,EACR,aAAa,eACf;GACA,WAAW;IACT,QAAQ,EACN,aAAa,kBACf;IACA,cAAc,EACZ,OAAO,gBACT;IACA,OAAO;IACP,YAAY;IACZ,QAAQ;GACV;GACA,WAAW;IACT,QAAQ,EACN,aAAa,gBACf;IACA,YAAY;IACZ,QAAQ;GACV;GACA,mBAAmB,EACjB,OAAO,yBACT;EACF;EACA,YAAY;GACV,UAAU;GACV,KAAK;GACL,OAAO;GACP,WAAW;GACX,eAAe;EACjB;EACA,WAAW;GACT,UAAU;GACV,KAAK;GACL,OAAO,IAAI,EAAE;GACb,WAAW;EACb;CACF;CACA,UAAU,EACR,MAAM;EACJ,IAAI,EACF,OAAO;GAAE,eAAe,IAAI,EAAE;GAAG,cAAc,IAAI,CAAC;GAAG,WAAW;EAAkB,EACtF;EACA,IAAI,EACF,OAAO;GAAE,eAAe,IAAI,EAAE;GAAG,cAAc,IAAI,EAAE;GAAG,WAAW;EAAkB,EACvF;CACF,EACF;CACA,iBAAiB,EACf,MAAM,KACR;AACF,CAAC"}
|