@pixpilot/formily-shadcn 0.9.1 → 0.11.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/README.md +102 -1
- package/dist/components/array-base/components/array-item-label.cjs +1 -1
- package/dist/components/array-base/components/array-item-label.js +1 -1
- package/dist/components/checkbox.d.ts +2 -2
- package/dist/components/column.d.ts +2 -2
- package/dist/components/context/context.d.cts +1 -1
- package/dist/components/context/context.d.ts +1 -1
- package/dist/components/context/form-context.d.cts +52 -19
- package/dist/components/context/form-context.d.ts +52 -19
- package/dist/components/context/index.d.cts +1 -1
- package/dist/components/context/index.d.ts +1 -1
- package/dist/components/date-picker.d.cts +3 -3
- package/dist/components/date-picker.d.ts +3 -3
- package/dist/components/file-upload/file-upload-inline.d.cts +8 -8
- package/dist/components/file-upload/file-upload-inline.d.ts +8 -8
- package/dist/components/file-upload/file-upload.d.cts +8 -8
- package/dist/components/file-upload/file-upload.d.ts +8 -8
- package/dist/components/file-upload/use-file-upload-feedback.cjs +2 -2
- package/dist/components/file-upload/use-file-upload-feedback.js +2 -2
- package/dist/components/form-grid.d.cts +2 -2
- package/dist/components/form-grid.d.ts +2 -2
- package/dist/components/form-item/base-form-item.cjs +85 -0
- package/dist/components/form-item/base-form-item.d.cts +2 -0
- package/dist/components/form-item/base-form-item.d.ts +2 -0
- package/dist/components/form-item/base-form-item.js +80 -0
- package/dist/components/form-item/connected-form-item.cjs +47 -0
- package/dist/components/form-item/connected-form-item.d.cts +13 -0
- package/dist/components/form-item/connected-form-item.d.ts +13 -0
- package/dist/components/form-item/connected-form-item.js +44 -0
- package/dist/components/form-item/form-item-description-popover.cjs +42 -0
- package/dist/components/form-item/form-item-description-popover.js +37 -0
- package/dist/components/form-item/form-item-label.cjs +29 -0
- package/dist/components/form-item/form-item-label.js +25 -0
- package/dist/components/form-item/form-item-types.d.cts +23 -0
- package/dist/components/form-item/form-item-types.d.ts +23 -0
- package/dist/components/form-item/form-item.cjs +2 -0
- package/dist/components/form-item/form-item.d.cts +4 -0
- package/dist/components/form-item/form-item.d.ts +4 -0
- package/dist/components/form-item/form-item.js +2 -0
- package/dist/components/form-item/index.cjs +3 -0
- package/dist/components/form-item/index.d.cts +4 -0
- package/dist/components/form-item/index.d.ts +4 -0
- package/dist/components/form-item/index.js +3 -0
- package/dist/components/form-item/spacing-config.cjs +24 -0
- package/dist/components/form-item/spacing-config.js +23 -0
- package/dist/components/form-items-container.cjs +3 -5
- package/dist/components/form-items-container.js +3 -5
- package/dist/components/form.cjs +5 -14
- package/dist/components/form.d.cts +4 -7
- package/dist/components/form.d.ts +2 -5
- package/dist/components/form.js +5 -14
- package/dist/components/icon-picker.cjs +2 -2
- package/dist/components/icon-picker.d.cts +3 -3
- package/dist/components/icon-picker.d.ts +3 -3
- package/dist/components/icon-picker.js +2 -2
- package/dist/components/input.d.cts +2 -2
- package/dist/components/input.d.ts +2 -2
- package/dist/components/json-schema-form-renderer/index.cjs +4 -0
- package/dist/components/json-schema-form-renderer/index.d.cts +5 -0
- package/dist/components/json-schema-form-renderer/index.d.ts +5 -0
- package/dist/components/json-schema-form-renderer/index.js +4 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-basic.cjs +35 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-basic.d.cts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-basic.d.ts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-basic.js +32 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-extended.cjs +35 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-extended.d.cts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-extended.d.ts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-extended.js +32 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-renderer.cjs +57 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-renderer.d.cts +7 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-renderer.d.ts +7 -0
- package/dist/components/json-schema-form-renderer/json-schema-form-renderer.js +51 -0
- package/dist/components/json-schema-form-renderer/json-schema-form.cjs +36 -0
- package/dist/components/json-schema-form-renderer/json-schema-form.d.cts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form.d.ts +14 -0
- package/dist/components/json-schema-form-renderer/json-schema-form.js +33 -0
- package/dist/components/json-schema-form-renderer/types.d.cts +23 -0
- package/dist/components/json-schema-form-renderer/types.d.ts +23 -0
- package/dist/components/number-input.d.cts +2 -2
- package/dist/components/number-input.d.ts +2 -2
- package/dist/components/object-container.cjs +42 -9
- package/dist/components/object-container.js +43 -10
- package/dist/components/radio.d.cts +2 -2
- package/dist/components/radio.d.ts +2 -2
- package/dist/components/rich-text-editor.cjs +1 -1
- package/dist/components/rich-text-editor.js +1 -1
- package/dist/components/row.d.cts +2 -2
- package/dist/components/row.d.ts +2 -2
- package/dist/components/schema-field/index.d.cts +3 -3
- package/dist/components/schema-field/index.d.ts +3 -3
- package/dist/components/schema-field/index.js +3 -3
- package/dist/components/schema-field/schema-field-basics.cjs +67 -24
- package/dist/components/schema-field/schema-field-basics.d.cts +283 -198
- package/dist/components/schema-field/schema-field-basics.d.ts +283 -198
- package/dist/components/schema-field/schema-field-basics.js +65 -23
- package/dist/components/schema-field/schema-field-extended.cjs +23 -8
- package/dist/components/schema-field/schema-field-extended.d.cts +442 -307
- package/dist/components/schema-field/schema-field-extended.d.ts +442 -307
- package/dist/components/schema-field/schema-field-extended.js +23 -9
- package/dist/components/schema-field/schema-field.cjs +23 -8
- package/dist/components/schema-field/schema-field.d.cts +338 -237
- package/dist/components/schema-field/schema-field.d.ts +338 -237
- package/dist/components/schema-field/schema-field.js +23 -9
- package/dist/components/separator.d.ts +2 -2
- package/dist/components/slider.d.cts +2 -2
- package/dist/components/slider.d.ts +2 -2
- package/dist/components/switch.d.ts +2 -2
- package/dist/components/tags-input-inline.d.cts +2 -2
- package/dist/components/tags-input-inline.d.ts +2 -2
- package/dist/components/textarea.d.ts +2 -2
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/use-form-context.cjs +5 -0
- package/dist/hooks/use-form-context.js +5 -1
- package/dist/hooks/use-label.cjs +9 -2
- package/dist/hooks/use-label.js +9 -2
- package/dist/index.cjs +17 -6
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +11 -6
- package/dist/types/form-item.d.cts +5 -0
- package/dist/types/form-item.d.ts +5 -0
- package/dist/types/form.d.cts +0 -6
- package/dist/types/form.d.ts +0 -6
- package/dist/utils/extract-components.cjs +11 -0
- package/dist/utils/extract-components.js +10 -0
- package/dist/utils/extract-fields-decorators.cjs +37 -0
- package/dist/utils/extract-fields-decorators.js +36 -0
- package/dist/utils/index.cjs +2 -0
- package/dist/utils/index.js +3 -1
- package/dist/utils/resolve-responsive-space.cjs +45 -89
- package/dist/utils/resolve-responsive-space.js +42 -83
- package/dist/utils/transform-schema.cjs +9 -2
- package/dist/utils/transform-schema.js +9 -2
- package/dist/utils/validate-schema-components.cjs +45 -0
- package/dist/utils/validate-schema-components.js +43 -0
- package/package.json +4 -3
- package/dist/components/form-item.cjs +0 -118
- package/dist/components/form-item.d.cts +0 -22
- package/dist/components/form-item.d.ts +0 -22
- package/dist/components/form-item.js +0 -112
- package/dist/components/json-schema-form-renderer.cjs +0 -31
- package/dist/components/json-schema-form-renderer.d.cts +0 -15
- package/dist/components/json-schema-form-renderer.d.ts +0 -15
- package/dist/components/json-schema-form-renderer.js +0 -27
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_use_form_context = require('../../hooks/use-form-context.cjs');
|
|
3
|
+
const require_use_label = require('../../hooks/use-label.cjs');
|
|
4
|
+
require('../../hooks/index.cjs');
|
|
5
|
+
const require_form_item_label = require('./form-item-label.cjs');
|
|
6
|
+
const require_spacing_config = require('./spacing-config.cjs');
|
|
7
|
+
let __formily_react = require("@formily/react");
|
|
8
|
+
__formily_react = require_rolldown_runtime.__toESM(__formily_react);
|
|
9
|
+
let react = require("react");
|
|
10
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
11
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
12
|
+
react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
|
|
13
|
+
let __pixpilot_shadcn = require("@pixpilot/shadcn");
|
|
14
|
+
__pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
|
|
15
|
+
|
|
16
|
+
//#region src/components/form-item/base-form-item.tsx
|
|
17
|
+
function resolveLegacyDescriptionPlacement(labelPlacement) {
|
|
18
|
+
return labelPlacement === "top" ? "top" : "bottom";
|
|
19
|
+
}
|
|
20
|
+
const BaseFormItem = ({ className, children, label, description, descriptionPlacement, asterisk, feedbackStatus, feedbackText, labelPlacement = "top",...props }) => {
|
|
21
|
+
const field = (0, __formily_react.useField)();
|
|
22
|
+
const fieldProps = field?.componentProps ?? {};
|
|
23
|
+
const effectiveLabel = require_use_label.useLabel(label);
|
|
24
|
+
const { layout } = require_use_form_context.useFormContext();
|
|
25
|
+
const { classes } = layout?.itemProps || {};
|
|
26
|
+
const contextDescriptionPlacement = layout?.descriptionPlacement;
|
|
27
|
+
const effectiveLabelPlacement = fieldProps.labelPlacement ?? labelPlacement;
|
|
28
|
+
const resolvedDescriptionPlacement = fieldProps.descriptionPlacement ?? descriptionPlacement ?? contextDescriptionPlacement ?? resolveLegacyDescriptionPlacement(effectiveLabelPlacement);
|
|
29
|
+
const id = field?.componentProps?.id ?? `form-${field?.address?.toString()?.replace(/\./gu, "-")}`;
|
|
30
|
+
const descriptionId = react.default.useId();
|
|
31
|
+
const feedbackId = react.default.useId();
|
|
32
|
+
const descriptionRenderedInline = description != null && resolvedDescriptionPlacement !== "popover";
|
|
33
|
+
const spacingConfig = require_spacing_config.getSpacingConfig(resolvedDescriptionPlacement, descriptionRenderedInline);
|
|
34
|
+
const ariaDescribedBy = [descriptionRenderedInline ? descriptionId : void 0, feedbackText != null ? feedbackId : void 0].filter(Boolean).join(" ");
|
|
35
|
+
const labelElement = effectiveLabel != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_form_item_label.FormItemLabel, {
|
|
36
|
+
id,
|
|
37
|
+
label: effectiveLabel,
|
|
38
|
+
asterisk,
|
|
39
|
+
error: feedbackStatus === "error",
|
|
40
|
+
shrink: effectiveLabelPlacement === "end" || effectiveLabelPlacement === "start",
|
|
41
|
+
labelClassName: (0, __pixpilot_shadcn.cn)(spacingConfig.label, classes?.label),
|
|
42
|
+
description,
|
|
43
|
+
descriptionInPopover: resolvedDescriptionPlacement === "popover" && description != null
|
|
44
|
+
});
|
|
45
|
+
const inputElement = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
46
|
+
className: (0, __pixpilot_shadcn.cn)("relative", classes?.inputWrapper),
|
|
47
|
+
children: react.default.isValidElement(children) ? react.default.cloneElement(children, {
|
|
48
|
+
id,
|
|
49
|
+
"aria-describedby": ariaDescribedBy || void 0,
|
|
50
|
+
"aria-invalid": feedbackStatus === "error" ? "true" : void 0
|
|
51
|
+
}) : children
|
|
52
|
+
});
|
|
53
|
+
const descriptionElement = descriptionRenderedInline ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
54
|
+
id: descriptionId,
|
|
55
|
+
className: (0, __pixpilot_shadcn.cn)("text-muted-foreground text-[0.8rem]", spacingConfig.description, classes?.description),
|
|
56
|
+
children: description
|
|
57
|
+
}) : null;
|
|
58
|
+
const contentElement = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
59
|
+
effectiveLabelPlacement === "top" && labelElement,
|
|
60
|
+
resolvedDescriptionPlacement === "top" && descriptionElement,
|
|
61
|
+
(effectiveLabelPlacement === "start" || effectiveLabelPlacement === "end") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
62
|
+
className: (0, __pixpilot_shadcn.cn)("flex items-center gap-2", effectiveLabelPlacement === "start" && "flex-row"),
|
|
63
|
+
children: [
|
|
64
|
+
effectiveLabelPlacement === "start" && labelElement,
|
|
65
|
+
inputElement,
|
|
66
|
+
effectiveLabelPlacement === "end" && labelElement
|
|
67
|
+
]
|
|
68
|
+
}),
|
|
69
|
+
effectiveLabelPlacement === "top" && inputElement,
|
|
70
|
+
resolvedDescriptionPlacement === "bottom" && descriptionElement
|
|
71
|
+
] });
|
|
72
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
73
|
+
"data-slot": "form-item",
|
|
74
|
+
className: (0, __pixpilot_shadcn.cn)("flex flex-col ", className),
|
|
75
|
+
...props,
|
|
76
|
+
children: [contentElement, Boolean(feedbackText) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
77
|
+
id: feedbackId,
|
|
78
|
+
className: (0, __pixpilot_shadcn.cn)("text-[0.8rem]", spacingConfig.feedback, feedbackStatus === "error" && "text-destructive font-medium", feedbackStatus === "warning" && "text-amber-600", feedbackStatus === "success" && "text-green-600", classes?.errorMessage),
|
|
79
|
+
children: typeof feedbackText === "string" ? feedbackText.split("\n").map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.default.Fragment, { children: [line, index < feedbackText.split("\n").length - 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("br", {})] }, index)) : feedbackText
|
|
80
|
+
})]
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
//#endregion
|
|
85
|
+
exports.BaseFormItem = BaseFormItem;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useFormContext } from "../../hooks/use-form-context.js";
|
|
2
|
+
import { useLabel } from "../../hooks/use-label.js";
|
|
3
|
+
import "../../hooks/index.js";
|
|
4
|
+
import { FormItemLabel } from "./form-item-label.js";
|
|
5
|
+
import { getSpacingConfig } from "./spacing-config.js";
|
|
6
|
+
import { useField } from "@formily/react";
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
import { cn } from "@pixpilot/shadcn";
|
|
10
|
+
|
|
11
|
+
//#region src/components/form-item/base-form-item.tsx
|
|
12
|
+
function resolveLegacyDescriptionPlacement(labelPlacement) {
|
|
13
|
+
return labelPlacement === "top" ? "top" : "bottom";
|
|
14
|
+
}
|
|
15
|
+
const BaseFormItem = ({ className, children, label, description, descriptionPlacement, asterisk, feedbackStatus, feedbackText, labelPlacement = "top",...props }) => {
|
|
16
|
+
const field = useField();
|
|
17
|
+
const fieldProps = field?.componentProps ?? {};
|
|
18
|
+
const effectiveLabel = useLabel(label);
|
|
19
|
+
const { layout } = useFormContext();
|
|
20
|
+
const { classes } = layout?.itemProps || {};
|
|
21
|
+
const contextDescriptionPlacement = layout?.descriptionPlacement;
|
|
22
|
+
const effectiveLabelPlacement = fieldProps.labelPlacement ?? labelPlacement;
|
|
23
|
+
const resolvedDescriptionPlacement = fieldProps.descriptionPlacement ?? descriptionPlacement ?? contextDescriptionPlacement ?? resolveLegacyDescriptionPlacement(effectiveLabelPlacement);
|
|
24
|
+
const id = field?.componentProps?.id ?? `form-${field?.address?.toString()?.replace(/\./gu, "-")}`;
|
|
25
|
+
const descriptionId = React.useId();
|
|
26
|
+
const feedbackId = React.useId();
|
|
27
|
+
const descriptionRenderedInline = description != null && resolvedDescriptionPlacement !== "popover";
|
|
28
|
+
const spacingConfig = getSpacingConfig(resolvedDescriptionPlacement, descriptionRenderedInline);
|
|
29
|
+
const ariaDescribedBy = [descriptionRenderedInline ? descriptionId : void 0, feedbackText != null ? feedbackId : void 0].filter(Boolean).join(" ");
|
|
30
|
+
const labelElement = effectiveLabel != null && /* @__PURE__ */ jsx(FormItemLabel, {
|
|
31
|
+
id,
|
|
32
|
+
label: effectiveLabel,
|
|
33
|
+
asterisk,
|
|
34
|
+
error: feedbackStatus === "error",
|
|
35
|
+
shrink: effectiveLabelPlacement === "end" || effectiveLabelPlacement === "start",
|
|
36
|
+
labelClassName: cn(spacingConfig.label, classes?.label),
|
|
37
|
+
description,
|
|
38
|
+
descriptionInPopover: resolvedDescriptionPlacement === "popover" && description != null
|
|
39
|
+
});
|
|
40
|
+
const inputElement = /* @__PURE__ */ jsx("div", {
|
|
41
|
+
className: cn("relative", classes?.inputWrapper),
|
|
42
|
+
children: React.isValidElement(children) ? React.cloneElement(children, {
|
|
43
|
+
id,
|
|
44
|
+
"aria-describedby": ariaDescribedBy || void 0,
|
|
45
|
+
"aria-invalid": feedbackStatus === "error" ? "true" : void 0
|
|
46
|
+
}) : children
|
|
47
|
+
});
|
|
48
|
+
const descriptionElement = descriptionRenderedInline ? /* @__PURE__ */ jsx("p", {
|
|
49
|
+
id: descriptionId,
|
|
50
|
+
className: cn("text-muted-foreground text-[0.8rem]", spacingConfig.description, classes?.description),
|
|
51
|
+
children: description
|
|
52
|
+
}) : null;
|
|
53
|
+
const contentElement = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
54
|
+
effectiveLabelPlacement === "top" && labelElement,
|
|
55
|
+
resolvedDescriptionPlacement === "top" && descriptionElement,
|
|
56
|
+
(effectiveLabelPlacement === "start" || effectiveLabelPlacement === "end") && /* @__PURE__ */ jsxs("div", {
|
|
57
|
+
className: cn("flex items-center gap-2", effectiveLabelPlacement === "start" && "flex-row"),
|
|
58
|
+
children: [
|
|
59
|
+
effectiveLabelPlacement === "start" && labelElement,
|
|
60
|
+
inputElement,
|
|
61
|
+
effectiveLabelPlacement === "end" && labelElement
|
|
62
|
+
]
|
|
63
|
+
}),
|
|
64
|
+
effectiveLabelPlacement === "top" && inputElement,
|
|
65
|
+
resolvedDescriptionPlacement === "bottom" && descriptionElement
|
|
66
|
+
] });
|
|
67
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
68
|
+
"data-slot": "form-item",
|
|
69
|
+
className: cn("flex flex-col ", className),
|
|
70
|
+
...props,
|
|
71
|
+
children: [contentElement, Boolean(feedbackText) && /* @__PURE__ */ jsx("p", {
|
|
72
|
+
id: feedbackId,
|
|
73
|
+
className: cn("text-[0.8rem]", spacingConfig.feedback, feedbackStatus === "error" && "text-destructive font-medium", feedbackStatus === "warning" && "text-amber-600", feedbackStatus === "success" && "text-green-600", classes?.errorMessage),
|
|
74
|
+
children: typeof feedbackText === "string" ? feedbackText.split("\n").map((line, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [line, index < feedbackText.split("\n").length - 1 && /* @__PURE__ */ jsx("br", {})] }, index)) : feedbackText
|
|
75
|
+
})]
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { BaseFormItem };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_base_form_item = require('./base-form-item.cjs');
|
|
3
|
+
let __formily_react = require("@formily/react");
|
|
4
|
+
__formily_react = require_rolldown_runtime.__toESM(__formily_react);
|
|
5
|
+
let __formily_core = require("@formily/core");
|
|
6
|
+
__formily_core = require_rolldown_runtime.__toESM(__formily_core);
|
|
7
|
+
|
|
8
|
+
//#region src/components/form-item/connected-form-item.tsx
|
|
9
|
+
/**
|
|
10
|
+
* FormItem component connected to Formily field state.
|
|
11
|
+
* Automatically maps field validation state to component props.
|
|
12
|
+
*/
|
|
13
|
+
const FormItem = (0, __formily_react.connect)(require_base_form_item.BaseFormItem, (0, __formily_react.mapProps)((props, field) => {
|
|
14
|
+
if ((0, __formily_core.isVoidField)(field)) return {
|
|
15
|
+
label: field.title ?? props.label,
|
|
16
|
+
description: props.description ?? field.description,
|
|
17
|
+
asterisk: props.asterisk
|
|
18
|
+
};
|
|
19
|
+
const takeFeedbackStatus = () => {
|
|
20
|
+
if (field.validating) return void 0;
|
|
21
|
+
if (field.selfErrors?.length) return "error";
|
|
22
|
+
if (field.selfWarnings?.length) return "warning";
|
|
23
|
+
if (field.selfSuccesses?.length) return "success";
|
|
24
|
+
};
|
|
25
|
+
const takeFeedbackText = () => {
|
|
26
|
+
if (field.validating) return void 0;
|
|
27
|
+
if (props.feedbackText != null) return props.feedbackText;
|
|
28
|
+
if (field.selfErrors?.length) return field.selfErrors.join(", ");
|
|
29
|
+
if (field.selfWarnings?.length) return field.selfWarnings.join(", ");
|
|
30
|
+
if (field.selfSuccesses?.length) return field.selfSuccesses.join(", ");
|
|
31
|
+
};
|
|
32
|
+
const takeAsterisk = () => {
|
|
33
|
+
if (field.required && field.pattern !== "readPretty") return true;
|
|
34
|
+
if ("asterisk" in props) return Boolean(props.asterisk);
|
|
35
|
+
return false;
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
label: props.label ?? field.title,
|
|
39
|
+
description: props.description ?? field.description,
|
|
40
|
+
feedbackStatus: takeFeedbackStatus(),
|
|
41
|
+
feedbackText: takeFeedbackText(),
|
|
42
|
+
asterisk: takeAsterisk()
|
|
43
|
+
};
|
|
44
|
+
}));
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
exports.FormItem = FormItem;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FormItemProps } from "./form-item-types.cjs";
|
|
2
|
+
import * as react1341 from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/form-item/connected-form-item.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* FormItem component connected to Formily field state.
|
|
7
|
+
* Automatically maps field validation state to component props.
|
|
8
|
+
*/
|
|
9
|
+
declare const FormItem: react1341.ForwardRefExoticComponent<Omit<Partial<FormItemProps & {
|
|
10
|
+
children?: react1341.ReactNode | undefined;
|
|
11
|
+
}>, "ref"> & react1341.RefAttributes<unknown>>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { FormItem };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { FormItemProps } from "./form-item-types.js";
|
|
2
|
+
import * as react1341 from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/form-item/connected-form-item.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* FormItem component connected to Formily field state.
|
|
7
|
+
* Automatically maps field validation state to component props.
|
|
8
|
+
*/
|
|
9
|
+
declare const FormItem: react1341.ForwardRefExoticComponent<Omit<Partial<FormItemProps & {
|
|
10
|
+
children?: react1341.ReactNode | undefined;
|
|
11
|
+
}>, "ref"> & react1341.RefAttributes<unknown>>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { FormItem };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { BaseFormItem } from "./base-form-item.js";
|
|
2
|
+
import { connect, mapProps } from "@formily/react";
|
|
3
|
+
import { isVoidField } from "@formily/core";
|
|
4
|
+
|
|
5
|
+
//#region src/components/form-item/connected-form-item.tsx
|
|
6
|
+
/**
|
|
7
|
+
* FormItem component connected to Formily field state.
|
|
8
|
+
* Automatically maps field validation state to component props.
|
|
9
|
+
*/
|
|
10
|
+
const FormItem = connect(BaseFormItem, mapProps((props, field) => {
|
|
11
|
+
if (isVoidField(field)) return {
|
|
12
|
+
label: field.title ?? props.label,
|
|
13
|
+
description: props.description ?? field.description,
|
|
14
|
+
asterisk: props.asterisk
|
|
15
|
+
};
|
|
16
|
+
const takeFeedbackStatus = () => {
|
|
17
|
+
if (field.validating) return void 0;
|
|
18
|
+
if (field.selfErrors?.length) return "error";
|
|
19
|
+
if (field.selfWarnings?.length) return "warning";
|
|
20
|
+
if (field.selfSuccesses?.length) return "success";
|
|
21
|
+
};
|
|
22
|
+
const takeFeedbackText = () => {
|
|
23
|
+
if (field.validating) return void 0;
|
|
24
|
+
if (props.feedbackText != null) return props.feedbackText;
|
|
25
|
+
if (field.selfErrors?.length) return field.selfErrors.join(", ");
|
|
26
|
+
if (field.selfWarnings?.length) return field.selfWarnings.join(", ");
|
|
27
|
+
if (field.selfSuccesses?.length) return field.selfSuccesses.join(", ");
|
|
28
|
+
};
|
|
29
|
+
const takeAsterisk = () => {
|
|
30
|
+
if (field.required && field.pattern !== "readPretty") return true;
|
|
31
|
+
if ("asterisk" in props) return Boolean(props.asterisk);
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
label: props.label ?? field.title,
|
|
36
|
+
description: props.description ?? field.description,
|
|
37
|
+
feedbackStatus: takeFeedbackStatus(),
|
|
38
|
+
feedbackText: takeFeedbackText(),
|
|
39
|
+
asterisk: takeAsterisk()
|
|
40
|
+
};
|
|
41
|
+
}));
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { FormItem };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
let react = require("react");
|
|
3
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
4
|
+
let lucide_react = require("lucide-react");
|
|
5
|
+
lucide_react = require_rolldown_runtime.__toESM(lucide_react);
|
|
6
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
|
+
react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
|
|
8
|
+
let __pixpilot_shadcn = require("@pixpilot/shadcn");
|
|
9
|
+
__pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
|
|
10
|
+
|
|
11
|
+
//#region src/components/form-item/form-item-description-popover.tsx
|
|
12
|
+
function FormItemDescriptionPopover({ description, className }) {
|
|
13
|
+
const [open, setOpen] = react.default.useState(false);
|
|
14
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__pixpilot_shadcn.Popover, {
|
|
15
|
+
open,
|
|
16
|
+
onOpenChange: setOpen,
|
|
17
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.PopoverTrigger, {
|
|
18
|
+
asChild: true,
|
|
19
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
20
|
+
type: "button",
|
|
21
|
+
"aria-label": "Show description",
|
|
22
|
+
className: (0, __pixpilot_shadcn.cn)("text-muted-foreground inline-flex items-center justify-center rounded-sm hover:text-foreground transition-colors", className),
|
|
23
|
+
onMouseEnter: () => setOpen(true),
|
|
24
|
+
onMouseLeave: () => setOpen(false),
|
|
25
|
+
onClick: () => setOpen((prev) => !prev),
|
|
26
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.HelpCircleIcon, { className: "h-4 w-4" })
|
|
27
|
+
})
|
|
28
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__pixpilot_shadcn.PopoverContent, {
|
|
29
|
+
side: "top",
|
|
30
|
+
className: "w-80 bg-card border border-border",
|
|
31
|
+
onMouseEnter: () => setOpen(true),
|
|
32
|
+
onMouseLeave: () => setOpen(false),
|
|
33
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
34
|
+
className: "text-sm leading-relaxed text-foreground",
|
|
35
|
+
children: description
|
|
36
|
+
})
|
|
37
|
+
})]
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
exports.FormItemDescriptionPopover = FormItemDescriptionPopover;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { HelpCircleIcon } from "lucide-react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger, cn } from "@pixpilot/shadcn";
|
|
5
|
+
|
|
6
|
+
//#region src/components/form-item/form-item-description-popover.tsx
|
|
7
|
+
function FormItemDescriptionPopover({ description, className }) {
|
|
8
|
+
const [open, setOpen] = React.useState(false);
|
|
9
|
+
return /* @__PURE__ */ jsxs(Popover, {
|
|
10
|
+
open,
|
|
11
|
+
onOpenChange: setOpen,
|
|
12
|
+
children: [/* @__PURE__ */ jsx(PopoverTrigger, {
|
|
13
|
+
asChild: true,
|
|
14
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
"aria-label": "Show description",
|
|
17
|
+
className: cn("text-muted-foreground inline-flex items-center justify-center rounded-sm hover:text-foreground transition-colors", className),
|
|
18
|
+
onMouseEnter: () => setOpen(true),
|
|
19
|
+
onMouseLeave: () => setOpen(false),
|
|
20
|
+
onClick: () => setOpen((prev) => !prev),
|
|
21
|
+
children: /* @__PURE__ */ jsx(HelpCircleIcon, { className: "h-4 w-4" })
|
|
22
|
+
})
|
|
23
|
+
}), /* @__PURE__ */ jsx(PopoverContent, {
|
|
24
|
+
side: "top",
|
|
25
|
+
className: "w-80 bg-card border border-border",
|
|
26
|
+
onMouseEnter: () => setOpen(true),
|
|
27
|
+
onMouseLeave: () => setOpen(false),
|
|
28
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
29
|
+
className: "text-sm leading-relaxed text-foreground",
|
|
30
|
+
children: description
|
|
31
|
+
})
|
|
32
|
+
})]
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { FormItemDescriptionPopover };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_form_item_description_popover = require('./form-item-description-popover.cjs');
|
|
3
|
+
let react = require("react");
|
|
4
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
5
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
6
|
+
react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
|
|
7
|
+
let __pixpilot_shadcn = require("@pixpilot/shadcn");
|
|
8
|
+
__pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
|
|
9
|
+
|
|
10
|
+
//#region src/components/form-item/form-item-label.tsx
|
|
11
|
+
function FormItemLabel({ id, label, asterisk, error, shrink, labelClassName, description, descriptionInPopover }) {
|
|
12
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
13
|
+
htmlFor: id,
|
|
14
|
+
"data-slot": "form-label",
|
|
15
|
+
"data-error": Boolean(error),
|
|
16
|
+
className: (0, __pixpilot_shadcn.cn)("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", error && "text-destructive", shrink && "shrink-0", labelClassName),
|
|
17
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
18
|
+
className: "inline-flex items-center gap-1",
|
|
19
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), descriptionInPopover && description != null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_form_item_description_popover.FormItemDescriptionPopover, { description })]
|
|
20
|
+
}), asterisk && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
21
|
+
className: "text-destructive ml-1",
|
|
22
|
+
"aria-label": "required",
|
|
23
|
+
children: "*"
|
|
24
|
+
})]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
exports.FormItemLabel = FormItemLabel;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FormItemDescriptionPopover } from "./form-item-description-popover.js";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { cn } from "@pixpilot/shadcn";
|
|
5
|
+
|
|
6
|
+
//#region src/components/form-item/form-item-label.tsx
|
|
7
|
+
function FormItemLabel({ id, label, asterisk, error, shrink, labelClassName, description, descriptionInPopover }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("label", {
|
|
9
|
+
htmlFor: id,
|
|
10
|
+
"data-slot": "form-label",
|
|
11
|
+
"data-error": Boolean(error),
|
|
12
|
+
className: cn("text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", error && "text-destructive", shrink && "shrink-0", labelClassName),
|
|
13
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
14
|
+
className: "inline-flex items-center gap-1",
|
|
15
|
+
children: [/* @__PURE__ */ jsx("span", { children: label }), descriptionInPopover && description != null && /* @__PURE__ */ jsx(FormItemDescriptionPopover, { description })]
|
|
16
|
+
}), asterisk && /* @__PURE__ */ jsx("span", {
|
|
17
|
+
className: "text-destructive ml-1",
|
|
18
|
+
"aria-label": "required",
|
|
19
|
+
children: "*"
|
|
20
|
+
})]
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { FormItemLabel };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DescriptionPlacement } from "../../types/form-item.cjs";
|
|
2
|
+
import { SyncReactNode } from "../../types/react.cjs";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/form-item/form-item-types.d.ts
|
|
6
|
+
type LabelPlacement = 'top' | 'bottom' | 'start' | 'end';
|
|
7
|
+
interface FormItemProps extends React.ComponentProps<'div'> {
|
|
8
|
+
label?: SyncReactNode;
|
|
9
|
+
description?: SyncReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Controls where `description` is rendered relative to the input.
|
|
12
|
+
* - `top`: above the input
|
|
13
|
+
* - `bottom`: below the input
|
|
14
|
+
* - `popover`: show a help icon before the label and render the description in a hover popover
|
|
15
|
+
*/
|
|
16
|
+
descriptionPlacement?: DescriptionPlacement;
|
|
17
|
+
asterisk?: boolean;
|
|
18
|
+
feedbackStatus?: 'error' | 'warning' | 'success';
|
|
19
|
+
feedbackText?: SyncReactNode;
|
|
20
|
+
labelPlacement?: LabelPlacement;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { FormItemProps, LabelPlacement };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DescriptionPlacement } from "../../types/form-item.js";
|
|
2
|
+
import { SyncReactNode } from "../../types/react.js";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
//#region src/components/form-item/form-item-types.d.ts
|
|
6
|
+
type LabelPlacement = 'top' | 'bottom' | 'start' | 'end';
|
|
7
|
+
interface FormItemProps extends React.ComponentProps<'div'> {
|
|
8
|
+
label?: SyncReactNode;
|
|
9
|
+
description?: SyncReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Controls where `description` is rendered relative to the input.
|
|
12
|
+
* - `top`: above the input
|
|
13
|
+
* - `bottom`: below the input
|
|
14
|
+
* - `popover`: show a help icon before the label and render the description in a hover popover
|
|
15
|
+
*/
|
|
16
|
+
descriptionPlacement?: DescriptionPlacement;
|
|
17
|
+
asterisk?: boolean;
|
|
18
|
+
feedbackStatus?: 'error' | 'warning' | 'success';
|
|
19
|
+
feedbackText?: SyncReactNode;
|
|
20
|
+
labelPlacement?: LabelPlacement;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { FormItemProps, LabelPlacement };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/components/form-item/spacing-config.ts
|
|
3
|
+
const FEEDBACK = "mt-1";
|
|
4
|
+
const LABE_DEFAULT = "mb-2";
|
|
5
|
+
function getSpacingConfig(descriptionPlacement, hasDescription) {
|
|
6
|
+
if (descriptionPlacement === "top" && hasDescription) return {
|
|
7
|
+
label: "mb-1",
|
|
8
|
+
description: "mb-1.5",
|
|
9
|
+
feedback: FEEDBACK
|
|
10
|
+
};
|
|
11
|
+
if (descriptionPlacement === "bottom" && hasDescription) return {
|
|
12
|
+
label: LABE_DEFAULT,
|
|
13
|
+
description: "mt-1",
|
|
14
|
+
feedback: FEEDBACK
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
label: LABE_DEFAULT,
|
|
18
|
+
description: "",
|
|
19
|
+
feedback: FEEDBACK
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
//#endregion
|
|
24
|
+
exports.getSpacingConfig = getSpacingConfig;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/components/form-item/spacing-config.ts
|
|
2
|
+
const FEEDBACK = "mt-1";
|
|
3
|
+
const LABE_DEFAULT = "mb-2";
|
|
4
|
+
function getSpacingConfig(descriptionPlacement, hasDescription) {
|
|
5
|
+
if (descriptionPlacement === "top" && hasDescription) return {
|
|
6
|
+
label: "mb-1",
|
|
7
|
+
description: "mb-1.5",
|
|
8
|
+
feedback: FEEDBACK
|
|
9
|
+
};
|
|
10
|
+
if (descriptionPlacement === "bottom" && hasDescription) return {
|
|
11
|
+
label: LABE_DEFAULT,
|
|
12
|
+
description: "mt-1",
|
|
13
|
+
feedback: FEEDBACK
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
label: LABE_DEFAULT,
|
|
17
|
+
description: "",
|
|
18
|
+
feedback: FEEDBACK
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { getSpacingConfig };
|
|
@@ -12,11 +12,9 @@ __pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
|
|
|
12
12
|
//#region src/components/form-items-container.tsx
|
|
13
13
|
const FormItemContainer = (props) => {
|
|
14
14
|
const { as: Component = "div", className,...rest } = props;
|
|
15
|
-
const {
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
responsive
|
|
19
|
-
});
|
|
15
|
+
const { layout } = require_use_form_context.useFormContext();
|
|
16
|
+
const { density } = layout || {};
|
|
17
|
+
const spaceClass = require_resolve_responsive_space.resolveResponsiveSpaceClass({ density });
|
|
20
18
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
21
19
|
...rest,
|
|
22
20
|
className: (0, __pixpilot_shadcn.cn)(spaceClass, className)
|
|
@@ -8,11 +8,9 @@ import { cn } from "@pixpilot/shadcn";
|
|
|
8
8
|
//#region src/components/form-items-container.tsx
|
|
9
9
|
const FormItemContainer = (props) => {
|
|
10
10
|
const { as: Component = "div", className,...rest } = props;
|
|
11
|
-
const {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
responsive
|
|
15
|
-
});
|
|
11
|
+
const { layout } = useFormContext();
|
|
12
|
+
const { density } = layout || {};
|
|
13
|
+
const spaceClass = resolveResponsiveSpaceClass({ density });
|
|
16
14
|
return /* @__PURE__ */ jsx(Component, {
|
|
17
15
|
...rest,
|
|
18
16
|
className: cn(spaceClass, className)
|
package/dist/components/form.cjs
CHANGED
|
@@ -15,7 +15,7 @@ __pixpilot_shadcn = require_rolldown_runtime.__toESM(__pixpilot_shadcn);
|
|
|
15
15
|
/**
|
|
16
16
|
* Form component - wraps FormProvider and provides form context
|
|
17
17
|
*/
|
|
18
|
-
function Form({ form, className, style, children, onSubmit, onAutoSubmit,
|
|
18
|
+
function Form({ form, className, style, children, onSubmit, onAutoSubmit, layout, settings }) {
|
|
19
19
|
const handleSubmit = (e) => {
|
|
20
20
|
e.preventDefault();
|
|
21
21
|
form.submit((values) => {
|
|
@@ -26,24 +26,15 @@ function Form({ form, className, style, children, onSubmit, onAutoSubmit, itemPr
|
|
|
26
26
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_context.Provider, {
|
|
27
27
|
value: react.default.useMemo(() => {
|
|
28
28
|
return {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
density,
|
|
32
|
-
responsive,
|
|
33
|
-
config
|
|
29
|
+
layout,
|
|
30
|
+
settings
|
|
34
31
|
};
|
|
35
|
-
}, [
|
|
36
|
-
itemProps,
|
|
37
|
-
objectContainerProps,
|
|
38
|
-
density,
|
|
39
|
-
responsive,
|
|
40
|
-
config
|
|
41
|
-
]),
|
|
32
|
+
}, [layout, settings]),
|
|
42
33
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__formily_react.FormProvider, {
|
|
43
34
|
form,
|
|
44
35
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_form_items_container.FormItemContainer, {
|
|
45
36
|
as: "form",
|
|
46
|
-
className: (0, __pixpilot_shadcn.cn)(
|
|
37
|
+
className: (0, __pixpilot_shadcn.cn)(className),
|
|
47
38
|
style,
|
|
48
39
|
onSubmit: handleSubmit,
|
|
49
40
|
children
|