torch-glare 2.4.2 → 2.4.4
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/apps/lib/components/FormBuilder/context.ts +2 -5
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +2 -7
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +1 -18
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +1 -6
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +1 -3
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +10 -15
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +6 -32
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +1 -2
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +2 -9
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +1 -2
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +24 -23
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +1 -7
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +3 -13
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +1 -19
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +1 -6
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +1 -2
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +22 -26
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +5 -14
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +1 -7
- package/apps/lib/components/FormBuilder/form-builder.tsx +22 -36
- package/apps/lib/components/FormBuilder/header.tsx +2 -6
- package/apps/lib/components/FormBuilder/index.ts +1 -5
- package/apps/lib/components/FormBuilder/stepper.tsx +88 -15
- package/apps/lib/components/FormBuilder/submit.tsx +1 -4
- package/apps/lib/components/FormBuilder/types.ts +2 -5
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +9 -2
- package/apps/lib/components/FormRenderer/detail.tsx +207 -0
- package/apps/lib/components/FormRenderer/form-renderer.tsx +55 -14
- package/apps/lib/components/FormRenderer/index.ts +7 -5
- package/apps/lib/components/FormRenderer/types.ts +2 -3
- package/apps/lib/components/Popover.tsx +6 -2
- package/apps/lib/components/SearchableSelect.tsx +7 -2
- package/apps/lib/layouts/FieldSection.tsx +25 -22
- package/apps/lib/registry.json +1 -1
- package/apps/lib/tsconfig.tsbuildinfo +1 -1
- package/dist/src/shared/tailwindInit.d.ts.map +1 -1
- package/dist/src/shared/tailwindInit.js +3 -0
- package/dist/src/shared/tailwindInit.js.map +1 -1
- package/docs/components/form-builder.md +22 -29
- package/docs/components/form-renderer.md +72 -11
- package/docs/components/searchable-select.md +50 -46
- package/docs/how-to/forms-with-form-builder.md +68 -11
- package/docs/reference/tailwind-plugins.md +11 -1
- package/docs/tutorials/getting-started.md +9 -0
- package/package.json +1 -1
- package/apps/lib/components/FormBuilder/DisplayField.tsx +0 -40
- package/apps/lib/components/FormBuilder/viewFormat.tsx +0 -137
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
import { cn } from "../../utils/cn";
|
|
4
|
-
|
|
5
|
-
export interface DisplayFieldProps {
|
|
6
|
-
label?: ReactNode;
|
|
7
|
-
/** Plain string value — falls back to an em-dash when empty. */
|
|
8
|
-
value?: string | null;
|
|
9
|
-
/** Rich value (badges, chips, formatted nodes) — takes precedence over `value`. */
|
|
10
|
-
valueNode?: ReactNode;
|
|
11
|
-
className?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Read-only field: a label above its value. Used by FormBuilder's `mode: "view"`
|
|
16
|
-
* so the same config renders as a detail view. Mirrors the products-services
|
|
17
|
-
* `DisplayField` (label + value/valueNode, em-dash fallback).
|
|
18
|
-
*/
|
|
19
|
-
export function DisplayField({ label, value, valueNode, className }: DisplayFieldProps) {
|
|
20
|
-
return (
|
|
21
|
-
<div className={cn("flex w-full flex-col gap-1.5", className)}>
|
|
22
|
-
{label != null && (
|
|
23
|
-
<p className="typography-body-small-regular text-content-presentation-global-secondary">
|
|
24
|
-
{label}
|
|
25
|
-
</p>
|
|
26
|
-
)}
|
|
27
|
-
{valueNode != null ? (
|
|
28
|
-
<div className="typography-body-medium-medium text-content-presentation-global-primary">
|
|
29
|
-
{valueNode}
|
|
30
|
-
</div>
|
|
31
|
-
) : (
|
|
32
|
-
<span className="typography-body-medium-medium text-content-presentation-global-primary">
|
|
33
|
-
{value != null && value !== "" ? value : "—"}
|
|
34
|
-
</span>
|
|
35
|
-
)}
|
|
36
|
-
</div>
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
DisplayField.displayName = "DisplayField";
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { ReactNode } from "react";
|
|
2
|
-
import type { OutputData } from "@editorjs/editorjs";
|
|
3
|
-
|
|
4
|
-
import { Badge } from "../Badge";
|
|
5
|
-
import { RichTextField } from "../TextEditor/RichTextField";
|
|
6
|
-
import { formatNumber } from "./numberFormat";
|
|
7
|
-
|
|
8
|
-
/** A read-only value for `DisplayField`: a plain string, or a rich node. */
|
|
9
|
-
export interface FieldView {
|
|
10
|
-
value?: string;
|
|
11
|
-
valueNode?: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface OptionItem {
|
|
15
|
-
label: string;
|
|
16
|
-
value: string;
|
|
17
|
-
icon?: ReactNode;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** The read-only "kind" a field formats as (a superset grouping of field types). */
|
|
21
|
-
export type ViewKind =
|
|
22
|
-
| "text"
|
|
23
|
-
| "number"
|
|
24
|
-
| "currency"
|
|
25
|
-
| "option"
|
|
26
|
-
| "boolean"
|
|
27
|
-
| "date"
|
|
28
|
-
| "daterange"
|
|
29
|
-
| "dates"
|
|
30
|
-
| "multi"
|
|
31
|
-
| "richtext"
|
|
32
|
-
| "file";
|
|
33
|
-
|
|
34
|
-
export interface ViewFormatOptions {
|
|
35
|
-
kind: ViewKind;
|
|
36
|
-
value: unknown;
|
|
37
|
-
options?: OptionItem[];
|
|
38
|
-
currencySymbol?: ReactNode;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function optionLabel(options: OptionItem[] | undefined, value: unknown): string {
|
|
42
|
-
const found = options?.find((o) => o.value === value);
|
|
43
|
-
return found ? found.label : value == null ? "" : String(value);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function formatDate(value: unknown): string {
|
|
47
|
-
if (!(value instanceof Date) || Number.isNaN(value.getTime())) return "";
|
|
48
|
-
const y = value.getFullYear();
|
|
49
|
-
const m = String(value.getMonth() + 1).padStart(2, "0");
|
|
50
|
-
const d = String(value.getDate()).padStart(2, "0");
|
|
51
|
-
return `${y}/${m}/${d}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function multiLabels(options: OptionItem[] | undefined, value: unknown): string[] {
|
|
55
|
-
if (!Array.isArray(value)) return [];
|
|
56
|
-
return value.map((v) => {
|
|
57
|
-
if (v != null && typeof v === "object") {
|
|
58
|
-
const o = v as { name?: string; label?: string; value?: string };
|
|
59
|
-
return o.name ?? o.label ?? optionLabel(options, o.value);
|
|
60
|
-
}
|
|
61
|
-
return optionLabel(options, v);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Formats a field value as read-only content for `mode: "view"`. */
|
|
66
|
-
export function formatFieldView({
|
|
67
|
-
kind,
|
|
68
|
-
value,
|
|
69
|
-
options,
|
|
70
|
-
currencySymbol,
|
|
71
|
-
}: ViewFormatOptions): FieldView {
|
|
72
|
-
switch (kind) {
|
|
73
|
-
case "number":
|
|
74
|
-
return { value: formatNumber(value) };
|
|
75
|
-
|
|
76
|
-
case "currency":
|
|
77
|
-
return {
|
|
78
|
-
value:
|
|
79
|
-
value == null || value === ""
|
|
80
|
-
? ""
|
|
81
|
-
: `${currencySymbol ? `${currencySymbol} ` : ""}${formatNumber(value)}`,
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
case "option":
|
|
85
|
-
return { value: optionLabel(options, value) };
|
|
86
|
-
|
|
87
|
-
case "boolean":
|
|
88
|
-
return {
|
|
89
|
-
valueNode: <Badge size="S" color={value ? "green" : "gray"} label={value ? "Yes" : "No"} />,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
case "date":
|
|
93
|
-
return { value: formatDate(value) };
|
|
94
|
-
|
|
95
|
-
case "daterange": {
|
|
96
|
-
const r = value as { from?: unknown; to?: unknown } | null | undefined;
|
|
97
|
-
if (!r || (!r.from && !r.to)) return { value: "" };
|
|
98
|
-
return { value: `${formatDate(r.from)} – ${formatDate(r.to)}` };
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
case "dates": {
|
|
102
|
-
const arr = Array.isArray(value) ? value : [];
|
|
103
|
-
return { value: arr.map(formatDate).filter(Boolean).join(", ") };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
case "multi": {
|
|
107
|
-
const labels = multiLabels(options, value);
|
|
108
|
-
if (labels.length === 0) return { value: "" };
|
|
109
|
-
return {
|
|
110
|
-
valueNode: (
|
|
111
|
-
<div className="flex flex-wrap gap-1">
|
|
112
|
-
{labels.map((label, i) => (
|
|
113
|
-
<Badge key={`${label}-${i}`} size="S" color="ocean" label={label} />
|
|
114
|
-
))}
|
|
115
|
-
</div>
|
|
116
|
-
),
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
case "richtext":
|
|
121
|
-
if (!value) return { value: "" };
|
|
122
|
-
return { valueNode: <RichTextField readOnly data={value as OutputData} /> };
|
|
123
|
-
|
|
124
|
-
case "file": {
|
|
125
|
-
const files = Array.isArray(value) ? value : value ? [value] : [];
|
|
126
|
-
if (files.length === 0) return { value: "" };
|
|
127
|
-
const names = files.map((f) =>
|
|
128
|
-
f instanceof File ? f.name : typeof f === "string" ? f : "file",
|
|
129
|
-
);
|
|
130
|
-
return { value: names.join(", ") };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
case "text":
|
|
134
|
-
default:
|
|
135
|
-
return { value: value == null ? "" : String(value) };
|
|
136
|
-
}
|
|
137
|
-
}
|