@deftui/addons 0.2.3 → 0.2.5
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/modal-registry/provider.mjs +1 -0
- package/dist/modal-registry/registry.mjs +39 -2
- package/dist/modal-registry/types.d.mts +20 -7
- package/dist/modal.d.mts +2 -2
- package/dist/react-hook-form/field.d.mts +6 -0
- package/dist/react-hook-form/field.mjs +2 -2
- package/dist/react-hook-form/widgets/combobox.d.mts +3 -2
- package/dist/react-hook-form/widgets/select.d.mts +3 -2
- package/package.json +3 -3
|
@@ -14,6 +14,7 @@ function ModalRenderer({ view, onPresent, onError }) {
|
|
|
14
14
|
}, child.id)) : null;
|
|
15
15
|
const { root: Root, component: Content } = view.definition;
|
|
16
16
|
return /* @__PURE__ */ jsxs(Root, {
|
|
17
|
+
...view.rootConfig,
|
|
17
18
|
...view.rootProps,
|
|
18
19
|
children: [/* @__PURE__ */ jsx(Content, {
|
|
19
20
|
...view.props,
|
|
@@ -41,6 +41,9 @@ function createModalRegistry(options) {
|
|
|
41
41
|
function getServerSnapshot() {
|
|
42
42
|
return EMPTY;
|
|
43
43
|
}
|
|
44
|
+
function getServerOpenSnapshot() {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
44
47
|
function createRootProps(instance) {
|
|
45
48
|
return {
|
|
46
49
|
open: instance.phase !== "closing",
|
|
@@ -57,13 +60,14 @@ function createModalRegistry(options) {
|
|
|
57
60
|
const children = [...instance.children].map(build);
|
|
58
61
|
const open = instance.phase !== "closing";
|
|
59
62
|
const existing = instance.view;
|
|
60
|
-
if (existing && existing.definition === instance.definition && existing.props === instance.props && existing.rootProps.open === open && sameViews(existing.children, children)) return existing;
|
|
63
|
+
if (existing && existing.definition === instance.definition && existing.props === instance.props && existing.rootConfig === instance.rootConfig && existing.rootProps.open === open && sameViews(existing.children, children)) return existing;
|
|
61
64
|
return instance.view = {
|
|
62
65
|
id: instance.id,
|
|
63
66
|
definition: instance.definition,
|
|
64
67
|
props: instance.props,
|
|
65
68
|
modal: instance.modal,
|
|
66
69
|
rootProps: createRootProps(instance),
|
|
70
|
+
rootConfig: instance.rootConfig,
|
|
67
71
|
children
|
|
68
72
|
};
|
|
69
73
|
}
|
|
@@ -201,6 +205,19 @@ function createModalRegistry(options) {
|
|
|
201
205
|
if (!parent || parent.phase !== "active") throw new Error("A child call cannot be opened from a settled parent.");
|
|
202
206
|
parentId = id;
|
|
203
207
|
}
|
|
208
|
+
if (options?.id) for (const instance of instances.values()) {
|
|
209
|
+
if (instance.phase !== "active" || instance.definition !== definition || instance.dedupeKey !== options.id) continue;
|
|
210
|
+
instance.props = {
|
|
211
|
+
...instance.props,
|
|
212
|
+
...props
|
|
213
|
+
};
|
|
214
|
+
if (options.rootProps) instance.rootConfig = {
|
|
215
|
+
...instance.rootConfig,
|
|
216
|
+
...options.rootProps
|
|
217
|
+
};
|
|
218
|
+
publish();
|
|
219
|
+
return instance.call;
|
|
220
|
+
}
|
|
204
221
|
const id = nextId++;
|
|
205
222
|
let resolveResult;
|
|
206
223
|
let rejectResult;
|
|
@@ -231,6 +248,8 @@ function createModalRegistry(options) {
|
|
|
231
248
|
parentId,
|
|
232
249
|
children: /* @__PURE__ */ new Set(),
|
|
233
250
|
props,
|
|
251
|
+
rootConfig: { ...options?.rootProps },
|
|
252
|
+
dedupeKey: options?.id,
|
|
234
253
|
phase: "active",
|
|
235
254
|
presented: false,
|
|
236
255
|
resolveResult,
|
|
@@ -252,10 +271,28 @@ function createModalRegistry(options) {
|
|
|
252
271
|
function dismissAll() {
|
|
253
272
|
for (const instance of [...roots].reverse()) finish(instance, { status: "dismissed" });
|
|
254
273
|
}
|
|
274
|
+
function dismissTop() {
|
|
275
|
+
let top;
|
|
276
|
+
for (const instance of instances.values()) {
|
|
277
|
+
if (instance.phase !== "active") continue;
|
|
278
|
+
if (!top || instance.id > top.id) top = instance;
|
|
279
|
+
}
|
|
280
|
+
if (top) finish(top, { status: "dismissed" });
|
|
281
|
+
}
|
|
282
|
+
function isAnyModalOpen() {
|
|
283
|
+
for (const instance of instances.values()) if (instance.phase !== "closing") return true;
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
function useAnyModalOpen() {
|
|
287
|
+
return useSyncExternalStore(subscribe, isAnyModalOpen, getServerOpenSnapshot);
|
|
288
|
+
}
|
|
255
289
|
const registry = {
|
|
256
290
|
Provider,
|
|
257
291
|
define,
|
|
258
|
-
dismissAll
|
|
292
|
+
dismissAll,
|
|
293
|
+
dismissTop,
|
|
294
|
+
isAnyModalOpen,
|
|
295
|
+
useAnyModalOpen
|
|
259
296
|
};
|
|
260
297
|
if (cache && options) cache.set(options.key, registry);
|
|
261
298
|
return registry;
|
|
@@ -6,9 +6,11 @@ export interface ModalRootProps {
|
|
|
6
6
|
onOpenChangeComplete: (open: boolean) => void;
|
|
7
7
|
}
|
|
8
8
|
/** A Base UI root component controlled by the registry. */
|
|
9
|
-
export type ModalRootComponent = ComponentType<ModalRootProps & {
|
|
9
|
+
export type ModalRootComponent<RootProps extends object = {}> = ComponentType<ModalRootProps & RootProps & {
|
|
10
10
|
children?: ReactNode;
|
|
11
11
|
}>;
|
|
12
|
+
/** Root props the caller may override for one call. */
|
|
13
|
+
export type ModalRootOverrides<RootProps extends object> = Partial<Omit<RootProps, keyof ModalRootProps | "children">>;
|
|
12
14
|
/** Per-call controls exposed to the modal component. */
|
|
13
15
|
export interface ModalController<Props extends object = {}, Output = void> {
|
|
14
16
|
/** The current call, suitable for `show(..., { parent: modal.call })`. */
|
|
@@ -41,18 +43,23 @@ export interface ModalCall<Props, Output> extends Promise<ModalResult<Output>>,
|
|
|
41
43
|
dismiss: () => void;
|
|
42
44
|
}
|
|
43
45
|
/** A callable definition doubles as a Fast Refresh-compatible component handle. */
|
|
44
|
-
export type ModalDefinition<Props extends object = {}, Output = void> = FunctionComponent<{}> & {
|
|
46
|
+
export type ModalDefinition<Props extends object = {}, Output = void, RootProps extends object = {}> = FunctionComponent<{}> & {
|
|
45
47
|
/** Open this definition through its owning registry. */
|
|
46
|
-
readonly show: ModalShow<Props, Output>;
|
|
48
|
+
readonly show: ModalShow<Props, Output, RootProps>;
|
|
47
49
|
};
|
|
48
|
-
export interface ModalShowOptions {
|
|
50
|
+
export interface ModalShowOptions<RootProps extends object = {}> {
|
|
51
|
+
/** Reuse the active call with the same id for this definition. */
|
|
52
|
+
id?: string;
|
|
49
53
|
/** Render this call inside the parent call's root. */
|
|
50
54
|
parent?: ModalHandle;
|
|
55
|
+
/** Root props to shallow-merge for this call. */
|
|
56
|
+
rootProps?: ModalRootOverrides<RootProps>;
|
|
51
57
|
}
|
|
52
58
|
type ModalArguments<Props> = {} extends Props ? [props?: Props] : [props: Props];
|
|
53
|
-
|
|
59
|
+
type ModalShowOptionsArguments<Props, RootProps extends object> = {} extends Props ? [props: Props | undefined, options: ModalShowOptions<RootProps>] : [props: Props, options: ModalShowOptions<RootProps>];
|
|
60
|
+
interface ModalShow<Props, Output, RootProps extends object = {}> {
|
|
54
61
|
(...args: ModalArguments<Props>): ModalCall<Props, Output>;
|
|
55
|
-
(
|
|
62
|
+
(...args: ModalShowOptionsArguments<Props, RootProps>): ModalCall<Props, Output>;
|
|
56
63
|
}
|
|
57
64
|
export interface ModalRegistry {
|
|
58
65
|
/** Mount once around the application. Unmounting dismisses pending calls. */
|
|
@@ -60,9 +67,15 @@ export interface ModalRegistry {
|
|
|
60
67
|
children?: ReactNode;
|
|
61
68
|
}>;
|
|
62
69
|
/** Register a modal component. The registry controls the root and injects child calls through its children. */
|
|
63
|
-
define<Props extends object, Output = void>(root: ModalRootComponent
|
|
70
|
+
define<Props extends object, Output = void, RootProps extends object = {}>(root: ModalRootComponent<RootProps>, component: ComponentType<Modal<Props, Output>>): ModalDefinition<Props, Output, RootProps>;
|
|
64
71
|
/** Dismiss every active call, waiting for children to exit before their parents. */
|
|
65
72
|
dismissAll: () => void;
|
|
73
|
+
/** Dismiss the most recently opened active call. */
|
|
74
|
+
dismissTop: () => void;
|
|
75
|
+
/** Whether at least one modal root is open. Closing roots no longer count. */
|
|
76
|
+
isAnyModalOpen: () => boolean;
|
|
77
|
+
/** Reactive form of `isAnyModalOpen` for React components. */
|
|
78
|
+
useAnyModalOpen: () => boolean;
|
|
66
79
|
}
|
|
67
80
|
export interface ModalRegistryOptions {
|
|
68
81
|
/** The registration module's `import.meta.hot`. */
|
package/dist/modal.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { Modal, ModalCall, ModalController, ModalDefinition, ModalHandle, ModalRegistry, ModalRegistryOptions, ModalResult, ModalRootComponent, ModalRootProps, ModalShowOptions } from "./modal-registry/types.mjs";
|
|
1
|
+
import { Modal, ModalCall, ModalController, ModalDefinition, ModalHandle, ModalRegistry, ModalRegistryOptions, ModalResult, ModalRootComponent, ModalRootOverrides, ModalRootProps, ModalShowOptions } from "./modal-registry/types.mjs";
|
|
2
2
|
import { createModalRegistry } from "./modal-registry/registry.mjs";
|
|
3
|
-
export { type Modal, type ModalCall, type ModalController, type ModalDefinition, type ModalHandle, type ModalRegistry, type ModalRegistryOptions, type ModalResult, type ModalRootComponent, type ModalRootProps, type ModalShowOptions, createModalRegistry };
|
|
3
|
+
export { type Modal, type ModalCall, type ModalController, type ModalDefinition, type ModalHandle, type ModalRegistry, type ModalRegistryOptions, type ModalResult, type ModalRootComponent, type ModalRootOverrides, type ModalRootProps, type ModalShowOptions, createModalRegistry };
|
|
@@ -10,6 +10,12 @@ interface RHFFieldProps<Values extends FieldValues, Name extends FieldPath<Value
|
|
|
10
10
|
label?: React.ReactNode;
|
|
11
11
|
/** Supporting text referenced by the control's aria-describedby. */
|
|
12
12
|
description?: React.ReactNode;
|
|
13
|
+
/**
|
|
14
|
+
* Associates the label with the control's ID via htmlFor.
|
|
15
|
+
*
|
|
16
|
+
* @default false
|
|
17
|
+
*/
|
|
18
|
+
associateLabel?: boolean;
|
|
13
19
|
/**
|
|
14
20
|
* Injects id, aria-invalid, and aria-describedby into a single non-Fragment element returned by children.
|
|
15
21
|
*
|
|
@@ -4,7 +4,7 @@ import { useController } from "react-hook-form";
|
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
// src/react-hook-form/field.tsx
|
|
6
6
|
function RHFField(props) {
|
|
7
|
-
const { label, description, injectControlProps = true, children, ...controllerProps } = props;
|
|
7
|
+
const { label, associateLabel = false, description, injectControlProps = true, children, ...controllerProps } = props;
|
|
8
8
|
const id = useId();
|
|
9
9
|
const controller = useController(controllerProps);
|
|
10
10
|
const hasError = Boolean(controller.fieldState.error?.message);
|
|
@@ -23,7 +23,7 @@ function RHFField(props) {
|
|
|
23
23
|
"data-disabled": controller.field.disabled,
|
|
24
24
|
children: [
|
|
25
25
|
label != null && /* @__PURE__ */ jsx(Field.Label, {
|
|
26
|
-
htmlFor: controlId,
|
|
26
|
+
htmlFor: associateLabel ? controlId : void 0,
|
|
27
27
|
children: label
|
|
28
28
|
}),
|
|
29
29
|
control ? cloneElement(control, {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { OnValueChange, Options } from "./types.mjs";
|
|
2
2
|
import { Combobox } from "@deftui/react";
|
|
3
3
|
import { ComponentProps } from "react";
|
|
4
|
-
type Props<V extends string>
|
|
4
|
+
type Props<V extends string> // oxfmt-ignore
|
|
5
|
+
= Omit<ComponentProps<typeof Combobox>, "items" | "children"> & Pick<ComponentProps<typeof Combobox.Input>, "size" | "placeholder" | "showClear" | "className"> & {
|
|
5
6
|
options: Options<V>;
|
|
6
7
|
emptyLabel?: string;
|
|
7
8
|
onChange?: OnValueChange;
|
|
8
|
-
}
|
|
9
|
+
};
|
|
9
10
|
export declare function RHFCombobox<V extends string>(props: Props<V>): import("react").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { OnValueChange, Options } from "./types.mjs";
|
|
2
2
|
import { Select } from "@deftui/react";
|
|
3
3
|
import { ComponentProps } from "react";
|
|
4
|
-
type Props<V extends string>
|
|
4
|
+
type Props<V extends string> // oxfmt-ignore
|
|
5
|
+
= Omit<ComponentProps<typeof Select>, "items" | "children"> & Pick<ComponentProps<typeof Select.Trigger>, "size" | "className"> & Pick<ComponentProps<typeof Select.Value>, "placeholder" | "className"> & {
|
|
5
6
|
options: Options<V>;
|
|
6
7
|
onChange?: OnValueChange;
|
|
7
|
-
}
|
|
8
|
+
};
|
|
8
9
|
export declare function RHFSelect<V extends string>(props: Props<V>): import("react").JSX.Element;
|
|
9
10
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deftui/addons",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/KiriRainCat/deftui.git",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"fix": "vp check --fix"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
|
-
"@deftui/react": "^0.2.
|
|
43
|
+
"@deftui/react": "^0.2.5",
|
|
44
44
|
"@tanstack/react-router": "^1.170.46",
|
|
45
45
|
"@types/react": "^19.3.0",
|
|
46
46
|
"@types/react-dom": "^19.3.0",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"vite-plus": "catalog:"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@deftui/react": "^0.2.
|
|
52
|
+
"@deftui/react": "^0.2.5",
|
|
53
53
|
"@tanstack/react-router": "^1.170.0",
|
|
54
54
|
"react": "^19.0.0",
|
|
55
55
|
"react-dom": "^19.0.0",
|