@braedonsaunders/appkit-forms 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +74 -0
- package/canvas-editor.d.ts +24 -0
- package/canvas-editor.d.ts.map +1 -0
- package/canvas-editor.js +115 -0
- package/canvas-editor.js.map +1 -0
- package/canvas-runtime.d.ts +12 -0
- package/canvas-runtime.d.ts.map +1 -0
- package/canvas-runtime.js +54 -0
- package/canvas-runtime.js.map +1 -0
- package/element-preview.d.ts +9 -0
- package/element-preview.d.ts.map +1 -0
- package/element-preview.js +167 -0
- package/element-preview.js.map +1 -0
- package/form-designer.d.ts +29 -0
- package/form-designer.d.ts.map +1 -0
- package/form-designer.js +214 -0
- package/form-designer.js.map +1 -0
- package/form-flow-validation.d.ts +5 -0
- package/form-flow-validation.d.ts.map +1 -0
- package/form-flow-validation.js +154 -0
- package/form-flow-validation.js.map +1 -0
- package/form-renderer.d.ts +37 -0
- package/form-renderer.d.ts.map +1 -0
- package/form-renderer.js +282 -0
- package/form-renderer.js.map +1 -0
- package/formula-builder.d.ts +25 -0
- package/formula-builder.d.ts.map +1 -0
- package/formula-builder.js +310 -0
- package/formula-builder.js.map +1 -0
- package/generated-copy.d.ts +17 -0
- package/generated-copy.d.ts.map +1 -0
- package/generated-copy.js +396 -0
- package/generated-copy.js.map +1 -0
- package/index.d.ts +27 -0
- package/index.d.ts.map +1 -0
- package/index.js +25 -0
- package/index.js.map +1 -0
- package/logic-builder.d.ts +27 -0
- package/logic-builder.d.ts.map +1 -0
- package/logic-builder.js +106 -0
- package/logic-builder.js.map +1 -0
- package/package.json +54 -0
- package/photo-field-state.d.ts +9 -0
- package/photo-field-state.d.ts.map +1 -0
- package/photo-field-state.js +11 -0
- package/photo-field-state.js.map +1 -0
- package/production-designer-adapter.d.ts +100 -0
- package/production-designer-adapter.d.ts.map +1 -0
- package/production-designer-adapter.js +2 -0
- package/production-designer-adapter.js.map +1 -0
- package/production-file-upload.d.ts +27 -0
- package/production-file-upload.d.ts.map +1 -0
- package/production-file-upload.js +105 -0
- package/production-file-upload.js.map +1 -0
- package/production-form-designer.d.ts +3 -0
- package/production-form-designer.d.ts.map +1 -0
- package/production-form-designer.js +1124 -0
- package/production-form-designer.js.map +1 -0
- package/production-form-renderer.d.ts +16 -0
- package/production-form-renderer.d.ts.map +1 -0
- package/production-form-renderer.js +2134 -0
- package/production-form-renderer.js.map +1 -0
- package/production-runtime-adapter.d.ts +187 -0
- package/production-runtime-adapter.d.ts.map +1 -0
- package/production-runtime-adapter.js +2 -0
- package/production-runtime-adapter.js.map +1 -0
- package/production-runtime-context.d.ts +29 -0
- package/production-runtime-context.d.ts.map +1 -0
- package/production-runtime-context.js +35 -0
- package/production-runtime-context.js.map +1 -0
- package/production-runtime-layout.d.ts +21 -0
- package/production-runtime-layout.d.ts.map +1 -0
- package/production-runtime-layout.js +33 -0
- package/production-runtime-layout.js.map +1 -0
- package/properties.d.ts +36 -0
- package/properties.d.ts.map +1 -0
- package/properties.js +133 -0
- package/properties.js.map +1 -0
- package/record-actions-panel.d.ts +28 -0
- package/record-actions-panel.d.ts.map +1 -0
- package/record-actions-panel.js +136 -0
- package/record-actions-panel.js.map +1 -0
- package/record-behavior-panel.d.ts +15 -0
- package/record-behavior-panel.d.ts.map +1 -0
- package/record-behavior-panel.js +59 -0
- package/record-behavior-panel.js.map +1 -0
- package/record-config.d.ts +44 -0
- package/record-config.d.ts.map +1 -0
- package/record-config.js +2 -0
- package/record-config.js.map +1 -0
- package/record-list-panel.d.ts +16 -0
- package/record-list-panel.d.ts.map +1 -0
- package/record-list-panel.js +86 -0
- package/record-list-panel.js.map +1 -0
- package/risk-matrix.d.ts +93 -0
- package/risk-matrix.d.ts.map +1 -0
- package/risk-matrix.js +239 -0
- package/risk-matrix.js.map +1 -0
- package/runtime-controls.d.ts +19 -0
- package/runtime-controls.d.ts.map +1 -0
- package/runtime-controls.js +61 -0
- package/runtime-controls.js.map +1 -0
- package/sketch-pad-client.d.ts +4 -0
- package/sketch-pad-client.d.ts.map +1 -0
- package/sketch-pad-client.js +54 -0
- package/sketch-pad-client.js.map +1 -0
- package/sketch-pad.d.ts +13 -0
- package/sketch-pad.d.ts.map +1 -0
- package/sketch-pad.js +17 -0
- package/sketch-pad.js.map +1 -0
- package/styles.css +7 -0
- package/text.d.ts +5 -0
- package/text.d.ts.map +1 -0
- package/text.js +10 -0
- package/text.js.map +1 -0
- package/workflow-properties.d.ts +16 -0
- package/workflow-properties.d.ts.map +1 -0
- package/workflow-properties.js +31 -0
- package/workflow-properties.js.map +1 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import type { EntityAttrsByField } from '@braedonsaunders/appkit-forms-core';
|
|
2
|
+
import type { FinalizeUploadAction, RequestUploadAction } from '@braedonsaunders/appkit-ui';
|
|
3
|
+
export type ProductionDataColumn = {
|
|
4
|
+
key: string;
|
|
5
|
+
label: string;
|
|
6
|
+
type: 'text' | 'number' | 'date' | 'boolean';
|
|
7
|
+
};
|
|
8
|
+
export type ProductionDataRow = Record<string, unknown>;
|
|
9
|
+
export type ProductionDataQuery = {
|
|
10
|
+
sourceKey: string;
|
|
11
|
+
where?: {
|
|
12
|
+
column: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
}[];
|
|
15
|
+
filterColumn?: string;
|
|
16
|
+
filterValue?: unknown;
|
|
17
|
+
search?: string;
|
|
18
|
+
page?: number;
|
|
19
|
+
pageSize?: number;
|
|
20
|
+
valueColumn?: string;
|
|
21
|
+
selectedValue?: unknown;
|
|
22
|
+
};
|
|
23
|
+
export type ProductionDataQueryResult = {
|
|
24
|
+
columns: ProductionDataColumn[];
|
|
25
|
+
rows: ProductionDataRow[];
|
|
26
|
+
total: number;
|
|
27
|
+
page: number;
|
|
28
|
+
pageSize: number;
|
|
29
|
+
selectedRow: ProductionDataRow | null;
|
|
30
|
+
};
|
|
31
|
+
export type ProductionDataAggregate = {
|
|
32
|
+
sourceKey: string;
|
|
33
|
+
fn: 'count' | 'sum' | 'avg' | 'min' | 'max';
|
|
34
|
+
column?: string;
|
|
35
|
+
groupBy?: string;
|
|
36
|
+
where?: {
|
|
37
|
+
column: string;
|
|
38
|
+
value: unknown;
|
|
39
|
+
}[];
|
|
40
|
+
filterColumn?: string;
|
|
41
|
+
filterValue?: unknown;
|
|
42
|
+
groupLimit?: number;
|
|
43
|
+
};
|
|
44
|
+
export type ProductionDataAggregateResult = {
|
|
45
|
+
value: number | null;
|
|
46
|
+
groups?: {
|
|
47
|
+
key: string;
|
|
48
|
+
value: number;
|
|
49
|
+
}[];
|
|
50
|
+
total: number;
|
|
51
|
+
};
|
|
52
|
+
export type ProductionPhotoAnalysis = {
|
|
53
|
+
overallRisk: 'none' | 'low' | 'medium' | 'high' | 'critical';
|
|
54
|
+
summary?: string;
|
|
55
|
+
ppe: {
|
|
56
|
+
item: string;
|
|
57
|
+
status: 'present' | 'missing' | 'incorrect';
|
|
58
|
+
detail: string | null;
|
|
59
|
+
}[];
|
|
60
|
+
hazards: {
|
|
61
|
+
type: string;
|
|
62
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
63
|
+
detail: string;
|
|
64
|
+
}[];
|
|
65
|
+
};
|
|
66
|
+
export type ProductionFormRuntimeAdapter = {
|
|
67
|
+
createDraft(input: {
|
|
68
|
+
templateId: string;
|
|
69
|
+
obligationId?: string | null;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
ok: true;
|
|
72
|
+
responseId: string;
|
|
73
|
+
} | {
|
|
74
|
+
ok: false;
|
|
75
|
+
error: string;
|
|
76
|
+
}>;
|
|
77
|
+
saveDraft(input: {
|
|
78
|
+
responseId: string;
|
|
79
|
+
values: Record<string, unknown>;
|
|
80
|
+
rows: Record<string, Array<Record<string, unknown>>>;
|
|
81
|
+
stepIndex: number;
|
|
82
|
+
clientSessionId: string;
|
|
83
|
+
clientSequence: number;
|
|
84
|
+
baseRevision: number;
|
|
85
|
+
}): Promise<{
|
|
86
|
+
ok: true;
|
|
87
|
+
savedAt: string;
|
|
88
|
+
revision: number;
|
|
89
|
+
sequence: number;
|
|
90
|
+
} | {
|
|
91
|
+
ok: false;
|
|
92
|
+
error: string;
|
|
93
|
+
}>;
|
|
94
|
+
submit(input: {
|
|
95
|
+
templateId: string;
|
|
96
|
+
data: Record<string, unknown>;
|
|
97
|
+
siteId?: string | null;
|
|
98
|
+
obligationId?: string | null;
|
|
99
|
+
responseId?: string | null;
|
|
100
|
+
returnTo?: string | null;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
ok: boolean;
|
|
103
|
+
responseId?: string;
|
|
104
|
+
errors?: {
|
|
105
|
+
fieldId: string;
|
|
106
|
+
message: string;
|
|
107
|
+
}[];
|
|
108
|
+
}>;
|
|
109
|
+
updateField(input: {
|
|
110
|
+
responseId: string;
|
|
111
|
+
fieldId: string;
|
|
112
|
+
value: unknown;
|
|
113
|
+
}): Promise<{
|
|
114
|
+
ok: true;
|
|
115
|
+
} | {
|
|
116
|
+
ok: false;
|
|
117
|
+
error: string;
|
|
118
|
+
}>;
|
|
119
|
+
fetchEntityAttributes(input: {
|
|
120
|
+
templateId: string;
|
|
121
|
+
fieldId: string;
|
|
122
|
+
entityId: string;
|
|
123
|
+
}): Promise<{
|
|
124
|
+
ok: true;
|
|
125
|
+
attrs: Record<string, unknown>;
|
|
126
|
+
} | {
|
|
127
|
+
ok: false;
|
|
128
|
+
error: string;
|
|
129
|
+
}>;
|
|
130
|
+
listHierarchyOptions(level: string): Promise<{
|
|
131
|
+
id: string;
|
|
132
|
+
name: string;
|
|
133
|
+
code: string | null;
|
|
134
|
+
}[]>;
|
|
135
|
+
queryData(input: ProductionDataQuery): Promise<ProductionDataQueryResult>;
|
|
136
|
+
aggregateData(input: ProductionDataAggregate): Promise<ProductionDataAggregateResult>;
|
|
137
|
+
analyzePhotos?(input: {
|
|
138
|
+
attachmentIds: string[];
|
|
139
|
+
}): Promise<{
|
|
140
|
+
ok: true;
|
|
141
|
+
analysis: ProductionPhotoAnalysis;
|
|
142
|
+
} | {
|
|
143
|
+
ok: false;
|
|
144
|
+
error: string;
|
|
145
|
+
}>;
|
|
146
|
+
requestUpload?: RequestUploadAction;
|
|
147
|
+
finalizeUpload?: FinalizeUploadAction;
|
|
148
|
+
/** Optional endpoint used by the source save-on-unload protocol. */
|
|
149
|
+
draftBeaconUrl?: string;
|
|
150
|
+
};
|
|
151
|
+
export type ProductionFormRuntimeInput = {
|
|
152
|
+
templateId: string;
|
|
153
|
+
templateName: string;
|
|
154
|
+
version: number;
|
|
155
|
+
schema: import('@braedonsaunders/appkit-forms-core').FormSchemaV1 & {
|
|
156
|
+
workflow: NonNullable<import('@braedonsaunders/appkit-forms-core').FormSchemaV1['workflow']>;
|
|
157
|
+
};
|
|
158
|
+
sites: {
|
|
159
|
+
id: string;
|
|
160
|
+
name: string;
|
|
161
|
+
}[];
|
|
162
|
+
people: {
|
|
163
|
+
id: string;
|
|
164
|
+
firstName: string;
|
|
165
|
+
lastName: string;
|
|
166
|
+
employeeNo?: string | null;
|
|
167
|
+
}[];
|
|
168
|
+
entitiesByField: EntityAttrsByField;
|
|
169
|
+
currentUser: {
|
|
170
|
+
personId: string | null;
|
|
171
|
+
name: string | null;
|
|
172
|
+
};
|
|
173
|
+
initialResponseId?: string | null;
|
|
174
|
+
initialValues?: Record<string, unknown>;
|
|
175
|
+
initialRows?: Record<string, Array<Record<string, unknown>>>;
|
|
176
|
+
initialStepIndex?: number;
|
|
177
|
+
initialDraftRevision?: number;
|
|
178
|
+
isResumed?: boolean;
|
|
179
|
+
returnTo?: string | null;
|
|
180
|
+
recordsHref: string;
|
|
181
|
+
readOnly?: boolean;
|
|
182
|
+
responseStatus?: string | null;
|
|
183
|
+
reviewHref?: string | null;
|
|
184
|
+
complianceObligationId?: string | null;
|
|
185
|
+
inlineAutosave?: boolean;
|
|
186
|
+
};
|
|
187
|
+
//# sourceMappingURL=production-runtime-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-adapter.d.ts","sourceRoot":"","sources":["../src/production-runtime-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-adapter.js","sourceRoot":"","sources":["../src/production-runtime-adapter.ts"],"names":[],"mappings":"","sourcesContent":["import type { EntityAttrsByField } from '@braedonsaunders/appkit-forms-core'\nimport type {\n FinalizeUploadAction,\n RequestUploadAction,\n} from '@braedonsaunders/appkit-ui'\n\nexport type ProductionDataColumn = {\n key: string\n label: string\n type: 'text' | 'number' | 'date' | 'boolean'\n}\n\nexport type ProductionDataRow = Record<string, unknown>\n\nexport type ProductionDataQuery = {\n sourceKey: string\n where?: { column: string; value: unknown }[]\n filterColumn?: string\n filterValue?: unknown\n search?: string\n page?: number\n pageSize?: number\n valueColumn?: string\n selectedValue?: unknown\n}\n\nexport type ProductionDataQueryResult = {\n columns: ProductionDataColumn[]\n rows: ProductionDataRow[]\n total: number\n page: number\n pageSize: number\n selectedRow: ProductionDataRow | null\n}\n\nexport type ProductionDataAggregate = {\n sourceKey: string\n fn: 'count' | 'sum' | 'avg' | 'min' | 'max'\n column?: string\n groupBy?: string\n where?: { column: string; value: unknown }[]\n filterColumn?: string\n filterValue?: unknown\n groupLimit?: number\n}\n\nexport type ProductionDataAggregateResult = {\n value: number | null\n groups?: { key: string; value: number }[]\n total: number\n}\n\nexport type ProductionPhotoAnalysis = {\n overallRisk: 'none' | 'low' | 'medium' | 'high' | 'critical'\n summary?: string\n ppe: {\n item: string\n status: 'present' | 'missing' | 'incorrect'\n detail: string | null\n }[]\n hazards: { type: string; severity: 'low' | 'medium' | 'high' | 'critical'; detail: string }[]\n}\n\nexport type ProductionFormRuntimeAdapter = {\n createDraft(input: {\n templateId: string\n obligationId?: string | null\n }): Promise<{ ok: true; responseId: string } | { ok: false; error: string }>\n saveDraft(input: {\n responseId: string\n values: Record<string, unknown>\n rows: Record<string, Array<Record<string, unknown>>>\n stepIndex: number\n clientSessionId: string\n clientSequence: number\n baseRevision: number\n }): Promise<\n | { ok: true; savedAt: string; revision: number; sequence: number }\n | { ok: false; error: string }\n >\n submit(input: {\n templateId: string\n data: Record<string, unknown>\n siteId?: string | null\n obligationId?: string | null\n responseId?: string | null\n returnTo?: string | null\n }): Promise<{\n ok: boolean\n responseId?: string\n errors?: { fieldId: string; message: string }[]\n }>\n updateField(input: {\n responseId: string\n fieldId: string\n value: unknown\n }): Promise<{ ok: true } | { ok: false; error: string }>\n fetchEntityAttributes(input: {\n templateId: string\n fieldId: string\n entityId: string\n }): Promise<\n | { ok: true; attrs: Record<string, unknown> }\n | { ok: false; error: string }\n >\n listHierarchyOptions(level: string): Promise<\n { id: string; name: string; code: string | null }[]\n >\n queryData(input: ProductionDataQuery): Promise<ProductionDataQueryResult>\n aggregateData(input: ProductionDataAggregate): Promise<ProductionDataAggregateResult>\n analyzePhotos?(input: {\n attachmentIds: string[]\n }): Promise<\n | { ok: true; analysis: ProductionPhotoAnalysis }\n | { ok: false; error: string }\n >\n requestUpload?: RequestUploadAction\n finalizeUpload?: FinalizeUploadAction\n /** Optional endpoint used by the source save-on-unload protocol. */\n draftBeaconUrl?: string\n}\n\nexport type ProductionFormRuntimeInput = {\n templateId: string\n templateName: string\n version: number\n schema: import('@braedonsaunders/appkit-forms-core').FormSchemaV1 & {\n workflow: NonNullable<import('@braedonsaunders/appkit-forms-core').FormSchemaV1['workflow']>\n }\n sites: { id: string; name: string }[]\n people: {\n id: string\n firstName: string\n lastName: string\n employeeNo?: string | null\n }[]\n entitiesByField: EntityAttrsByField\n currentUser: { personId: string | null; name: string | null }\n initialResponseId?: string | null\n initialValues?: Record<string, unknown>\n initialRows?: Record<string, Array<Record<string, unknown>>>\n initialStepIndex?: number\n initialDraftRevision?: number\n isResumed?: boolean\n returnTo?: string | null\n recordsHref: string\n readOnly?: boolean\n responseStatus?: string | null\n reviewHref?: string | null\n complianceObligationId?: string | null\n inlineAutosave?: boolean\n}\n"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type AppLocale } from '@braedonsaunders/appkit-i18n';
|
|
3
|
+
import type { ProductionFormRuntimeAdapter } from './production-runtime-adapter.js';
|
|
4
|
+
import { type GeneratedCopyTranslator } from './generated-copy.js';
|
|
5
|
+
export type ProductionRuntimeLabels = {
|
|
6
|
+
lookingUp: string;
|
|
7
|
+
searchRecords: (input: {
|
|
8
|
+
field: string;
|
|
9
|
+
}) => string;
|
|
10
|
+
};
|
|
11
|
+
type ProductionRuntimeContextValue = {
|
|
12
|
+
adapter: ProductionFormRuntimeAdapter;
|
|
13
|
+
locale: AppLocale;
|
|
14
|
+
labels: ProductionRuntimeLabels;
|
|
15
|
+
};
|
|
16
|
+
export declare function ProductionFormRuntimeProvider({ adapter, locale, labels, translateGenerated, children, }: {
|
|
17
|
+
adapter: ProductionFormRuntimeAdapter;
|
|
18
|
+
locale?: AppLocale;
|
|
19
|
+
labels?: Partial<ProductionRuntimeLabels>;
|
|
20
|
+
translateGenerated?: GeneratedCopyTranslator;
|
|
21
|
+
children: React.ReactNode;
|
|
22
|
+
}): React.JSX.Element;
|
|
23
|
+
export declare function useProductionFormRuntime(): ProductionRuntimeContextValue;
|
|
24
|
+
export declare function useProductionLocale(): AppLocale;
|
|
25
|
+
export declare function useProductionTranslations(_namespace?: string): (key: 'lookingUp' | 'searchRecords', values?: {
|
|
26
|
+
field?: string;
|
|
27
|
+
}) => string;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=production-runtime-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-context.d.ts","sourceRoot":"","sources":["../src/production-runtime-context.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAA;AAChF,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,kBAAkB,CAAA;AAEzB,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAA;CACpD,CAAA;AAOD,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,4BAA4B,CAAA;IACrC,MAAM,EAAE,SAAS,CAAA;IACjB,MAAM,EAAE,uBAAuB,CAAA;CAChC,CAAA;AAID,wBAAgB,6BAA6B,CAAC,EAC5C,OAAO,EACP,MAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,QAAQ,GACT,EAAE;IACD,OAAO,EAAE,4BAA4B,CAAA;IACrC,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAA;IACzC,kBAAkB,CAAC,EAAE,uBAAuB,CAAA;IAC5C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,qBAWA;AAED,wBAAgB,wBAAwB,IAAI,6BAA6B,CAMxE;AAED,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED,wBAAgB,yBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,eAAe,EAAE,MAAM,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,MAAM,CAK1I"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { DEFAULT_LOCALE } from '@braedonsaunders/appkit-i18n';
|
|
5
|
+
import { GeneratedCopyProvider, } from './generated-copy.js';
|
|
6
|
+
const DEFAULT_LABELS = {
|
|
7
|
+
lookingUp: 'Looking up…',
|
|
8
|
+
searchRecords: ({ field }) => `Search ${field}…`,
|
|
9
|
+
};
|
|
10
|
+
const ProductionRuntimeContext = React.createContext(null);
|
|
11
|
+
export function ProductionFormRuntimeProvider({ adapter, locale = DEFAULT_LOCALE, labels, translateGenerated, children, }) {
|
|
12
|
+
const value = React.useMemo(() => ({
|
|
13
|
+
adapter,
|
|
14
|
+
locale,
|
|
15
|
+
labels: { ...DEFAULT_LABELS, ...labels },
|
|
16
|
+
}), [adapter, labels, locale]);
|
|
17
|
+
return (_jsx(ProductionRuntimeContext.Provider, { value: value, children: _jsx(GeneratedCopyProvider, { translate: translateGenerated, children: children }) }));
|
|
18
|
+
}
|
|
19
|
+
export function useProductionFormRuntime() {
|
|
20
|
+
const value = React.useContext(ProductionRuntimeContext);
|
|
21
|
+
if (!value) {
|
|
22
|
+
throw new Error('Production form runtime requires ProductionFormRuntimeProvider.');
|
|
23
|
+
}
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
export function useProductionLocale() {
|
|
27
|
+
return useProductionFormRuntime().locale;
|
|
28
|
+
}
|
|
29
|
+
export function useProductionTranslations(_namespace) {
|
|
30
|
+
const { labels } = useProductionFormRuntime();
|
|
31
|
+
return (key, values) => key === 'lookingUp'
|
|
32
|
+
? labels.lookingUp
|
|
33
|
+
: labels.searchRecords({ field: values?.field ?? 'records' });
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=production-runtime-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-context.js","sourceRoot":"","sources":["../src/production-runtime-context.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,cAAc,EAAkB,MAAM,8BAA8B,CAAA;AAE7E,OAAO,EACL,qBAAqB,GAEtB,MAAM,kBAAkB,CAAA;AAOzB,MAAM,cAAc,GAA4B;IAC9C,SAAS,EAAE,aAAa;IACxB,aAAa,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,UAAU,KAAK,GAAG;CACjD,CAAA;AAQD,MAAM,wBAAwB,GAAG,KAAK,CAAC,aAAa,CAAuC,IAAI,CAAC,CAAA;AAEhG,MAAM,UAAU,6BAA6B,CAAC,EAC5C,OAAO,EACP,MAAM,GAAG,cAAc,EACvB,MAAM,EACN,kBAAkB,EAClB,QAAQ,GAOT;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAgC,GAAG,EAAE,CAAC,CAAC;QAChE,OAAO;QACP,MAAM;QACN,MAAM,EAAE,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE;KACzC,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9B,OAAO,CACL,KAAC,wBAAwB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAC7C,KAAC,qBAAqB,IAAC,SAAS,EAAE,kBAAkB,YAAG,QAAQ,GAAyB,GACtD,CACrC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,wBAAwB,CAAC,CAAA;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,wBAAwB,EAAE,CAAC,MAAM,CAAA;AAC1C,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,UAAmB;IAC3D,MAAM,EAAE,MAAM,EAAE,GAAG,wBAAwB,EAAE,CAAA;IAC7C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,KAAK,WAAW;QACzC,CAAC,CAAC,MAAM,CAAC,SAAS;QAClB,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAA;AACjE,CAAC","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { DEFAULT_LOCALE, type AppLocale } from '@braedonsaunders/appkit-i18n'\nimport type { ProductionFormRuntimeAdapter } from './production-runtime-adapter'\nimport {\n GeneratedCopyProvider,\n type GeneratedCopyTranslator,\n} from './generated-copy'\n\nexport type ProductionRuntimeLabels = {\n lookingUp: string\n searchRecords: (input: { field: string }) => string\n}\n\nconst DEFAULT_LABELS: ProductionRuntimeLabels = {\n lookingUp: 'Looking up…',\n searchRecords: ({ field }) => `Search ${field}…`,\n}\n\ntype ProductionRuntimeContextValue = {\n adapter: ProductionFormRuntimeAdapter\n locale: AppLocale\n labels: ProductionRuntimeLabels\n}\n\nconst ProductionRuntimeContext = React.createContext<ProductionRuntimeContextValue | null>(null)\n\nexport function ProductionFormRuntimeProvider({\n adapter,\n locale = DEFAULT_LOCALE,\n labels,\n translateGenerated,\n children,\n}: {\n adapter: ProductionFormRuntimeAdapter\n locale?: AppLocale\n labels?: Partial<ProductionRuntimeLabels>\n translateGenerated?: GeneratedCopyTranslator\n children: React.ReactNode\n}) {\n const value = React.useMemo<ProductionRuntimeContextValue>(() => ({\n adapter,\n locale,\n labels: { ...DEFAULT_LABELS, ...labels },\n }), [adapter, labels, locale])\n return (\n <ProductionRuntimeContext.Provider value={value}>\n <GeneratedCopyProvider translate={translateGenerated}>{children}</GeneratedCopyProvider>\n </ProductionRuntimeContext.Provider>\n )\n}\n\nexport function useProductionFormRuntime(): ProductionRuntimeContextValue {\n const value = React.useContext(ProductionRuntimeContext)\n if (!value) {\n throw new Error('Production form runtime requires ProductionFormRuntimeProvider.')\n }\n return value\n}\n\nexport function useProductionLocale(): AppLocale {\n return useProductionFormRuntime().locale\n}\n\nexport function useProductionTranslations(_namespace?: string): (key: 'lookingUp' | 'searchRecords', values?: { field?: string }) => string {\n const { labels } = useProductionFormRuntime()\n return (key, values) => key === 'lookingUp'\n ? labels.lookingUp\n : labels.searchRecords({ field: values?.field ?? 'records' })\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export type ProductionSectionTone = 'neutral' | 'info' | 'accent' | 'primary' | 'warning' | 'success' | 'danger' | 'teal' | 'blue' | 'purple' | 'amber' | 'indigo' | 'emerald' | 'rose' | 'slate';
|
|
3
|
+
export type ProductionSectionProps = {
|
|
4
|
+
title: string;
|
|
5
|
+
subtitle?: string;
|
|
6
|
+
actions?: React.ReactNode;
|
|
7
|
+
defaultOpen?: boolean;
|
|
8
|
+
children: React.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
/** Tokenized extraction of the production collapsible record section. */
|
|
11
|
+
export declare function ProductionSection({ title, subtitle, actions, defaultOpen, children, }: ProductionSectionProps): React.JSX.Element;
|
|
12
|
+
export type ProductionPremiumSectionProps = ProductionSectionProps & {
|
|
13
|
+
icon?: React.ReactNode;
|
|
14
|
+
tone?: ProductionSectionTone;
|
|
15
|
+
count?: number;
|
|
16
|
+
done?: boolean;
|
|
17
|
+
doneLabel?: string;
|
|
18
|
+
};
|
|
19
|
+
/** Tokenized extraction of the production premium single-page section card. */
|
|
20
|
+
export declare function ProductionPremiumSection({ title, subtitle, actions, icon, tone, count, done, doneLabel, defaultOpen, children, }: ProductionPremiumSectionProps): React.JSX.Element;
|
|
21
|
+
//# sourceMappingURL=production-runtime-layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-layout.d.ts","sourceRoot":"","sources":["../src/production-runtime-layout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,qBAAqB,GAC7B,SAAS,GACT,MAAM,GACN,QAAQ,GACR,SAAS,GACT,SAAS,GACT,SAAS,GACT,QAAQ,GACR,MAAM,GACN,MAAM,GACN,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,MAAM,GACN,OAAO,CAAA;AAoBX,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,CAAA;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAkB,EAClB,QAAQ,GACT,EAAE,sBAAsB,qBA2BxB;AAED,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG;IACnE,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,IAAI,CAAC,EAAE,qBAAqB,CAAA;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,+EAA+E;AAC/E,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,IAAgB,EAChB,KAAK,EACL,IAAI,EACJ,SAAkB,EAClB,WAAkB,EAClB,QAAQ,GACT,EAAE,6BAA6B,qBA0C/B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Check, ChevronDown } from 'lucide-react';
|
|
5
|
+
import { cn } from '@braedonsaunders/appkit-ui';
|
|
6
|
+
const TONE = {
|
|
7
|
+
neutral: 'bg-bg-subtle text-fg-muted',
|
|
8
|
+
info: 'bg-info-subtle text-info',
|
|
9
|
+
accent: 'bg-accent-subtle text-accent',
|
|
10
|
+
primary: 'bg-primary-subtle text-primary',
|
|
11
|
+
warning: 'bg-warning-subtle text-warning',
|
|
12
|
+
success: 'bg-success-subtle text-success',
|
|
13
|
+
danger: 'bg-danger-subtle text-danger',
|
|
14
|
+
teal: 'bg-primary-subtle text-primary',
|
|
15
|
+
blue: 'bg-info-subtle text-info',
|
|
16
|
+
purple: 'bg-accent-subtle text-accent',
|
|
17
|
+
amber: 'bg-warning-subtle text-warning',
|
|
18
|
+
indigo: 'bg-accent-subtle text-accent',
|
|
19
|
+
emerald: 'bg-success-subtle text-success',
|
|
20
|
+
rose: 'bg-danger-subtle text-danger',
|
|
21
|
+
slate: 'bg-bg-subtle text-fg-muted',
|
|
22
|
+
};
|
|
23
|
+
/** Tokenized extraction of the production collapsible record section. */
|
|
24
|
+
export function ProductionSection({ title, subtitle, actions, defaultOpen = true, children, }) {
|
|
25
|
+
const [open, setOpen] = React.useState(defaultOpen);
|
|
26
|
+
return (_jsxs("section", { className: "overflow-hidden rounded-lg border border-border bg-surface", children: [_jsxs("div", { className: "flex items-center gap-3 pr-5", children: [_jsx("button", { type: "button", onClick: () => setOpen((value) => !value), className: "flex min-w-0 flex-1 items-center gap-3 px-5 py-3 text-left hover:bg-surface-hover", "aria-expanded": open, children: _jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 text-base font-semibold text-fg", children: [_jsx(ChevronDown, { size: 16, className: cn('text-fg-subtle transition-transform', !open && '-rotate-90') }), title] }), subtitle ? _jsx("div", { className: "ml-6 text-xs text-fg-muted", children: subtitle }) : null] }) }), actions ? _jsx("div", { className: "shrink-0", children: actions }) : null] }), open ? _jsx("div", { className: "border-t border-border-subtle px-5 py-4", children: children }) : null] }));
|
|
27
|
+
}
|
|
28
|
+
/** Tokenized extraction of the production premium single-page section card. */
|
|
29
|
+
export function ProductionPremiumSection({ title, subtitle, actions, icon, tone = 'neutral', count, done, doneLabel = 'Done', defaultOpen = true, children, }) {
|
|
30
|
+
const [open, setOpen] = React.useState(defaultOpen);
|
|
31
|
+
return (_jsxs("section", { className: "overflow-hidden rounded-2xl border border-border bg-surface shadow-sm transition-shadow hover:shadow-md", children: [_jsxs("div", { className: "flex items-center gap-3 p-4 sm:gap-4 sm:p-5", children: [icon ? (_jsx("span", { className: cn('flex size-11 shrink-0 items-center justify-center rounded-xl', TONE[tone]), children: icon })) : null, _jsxs("button", { type: "button", onClick: () => setOpen((value) => !value), className: "flex min-w-0 flex-1 items-center justify-between gap-3 text-left", "aria-expanded": open, children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("h2", { className: "truncate text-base font-semibold text-fg sm:text-[17px]", children: title }), typeof count === 'number' ? (_jsx("span", { className: "rounded-full bg-bg-subtle px-2 py-0.5 text-xs font-medium text-fg-muted", children: count })) : null, done ? (_jsxs("span", { className: "inline-flex items-center gap-1 rounded-full bg-success-subtle px-2 py-0.5 text-xs font-medium text-success", children: [_jsx(Check, { size: 11 }), " ", doneLabel] })) : null] }), subtitle ? _jsx("p", { className: "mt-0.5 truncate text-sm text-fg-muted", children: subtitle }) : null] }), _jsx(ChevronDown, { size: 18, className: cn('shrink-0 text-fg-subtle transition-transform', !open && '-rotate-90') })] }), actions ? _jsx("div", { className: "shrink-0", children: actions }) : null] }), open ? _jsx("div", { className: "border-t border-border-subtle p-4 sm:p-5", children: children }) : null] }));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=production-runtime-layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"production-runtime-layout.js","sourceRoot":"","sources":["../src/production-runtime-layout.tsx"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { Check, ChevronDown } from 'lucide-react'\nimport { cn } from '@braedonsaunders/appkit-ui'\n\nexport type ProductionSectionTone =\n | 'neutral'\n | 'info'\n | 'accent'\n | 'primary'\n | 'warning'\n | 'success'\n | 'danger'\n | 'teal'\n | 'blue'\n | 'purple'\n | 'amber'\n | 'indigo'\n | 'emerald'\n | 'rose'\n | 'slate'\n\nconst TONE: Record<ProductionSectionTone, string> = {\n neutral: 'bg-bg-subtle text-fg-muted',\n info: 'bg-info-subtle text-info',\n accent: 'bg-accent-subtle text-accent',\n primary: 'bg-primary-subtle text-primary',\n warning: 'bg-warning-subtle text-warning',\n success: 'bg-success-subtle text-success',\n danger: 'bg-danger-subtle text-danger',\n teal: 'bg-primary-subtle text-primary',\n blue: 'bg-info-subtle text-info',\n purple: 'bg-accent-subtle text-accent',\n amber: 'bg-warning-subtle text-warning',\n indigo: 'bg-accent-subtle text-accent',\n emerald: 'bg-success-subtle text-success',\n rose: 'bg-danger-subtle text-danger',\n slate: 'bg-bg-subtle text-fg-muted',\n}\n\nexport type ProductionSectionProps = {\n title: string\n subtitle?: string\n actions?: React.ReactNode\n defaultOpen?: boolean\n children: React.ReactNode\n}\n\n/** Tokenized extraction of the production collapsible record section. */\nexport function ProductionSection({\n title,\n subtitle,\n actions,\n defaultOpen = true,\n children,\n}: ProductionSectionProps) {\n const [open, setOpen] = React.useState(defaultOpen)\n return (\n <section className=\"overflow-hidden rounded-lg border border-border bg-surface\">\n <div className=\"flex items-center gap-3 pr-5\">\n <button\n type=\"button\"\n onClick={() => setOpen((value) => !value)}\n className=\"flex min-w-0 flex-1 items-center gap-3 px-5 py-3 text-left hover:bg-surface-hover\"\n aria-expanded={open}\n >\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 text-base font-semibold text-fg\">\n <ChevronDown\n size={16}\n className={cn('text-fg-subtle transition-transform', !open && '-rotate-90')}\n />\n {title}\n </div>\n {subtitle ? <div className=\"ml-6 text-xs text-fg-muted\">{subtitle}</div> : null}\n </div>\n </button>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {open ? <div className=\"border-t border-border-subtle px-5 py-4\">{children}</div> : null}\n </section>\n )\n}\n\nexport type ProductionPremiumSectionProps = ProductionSectionProps & {\n icon?: React.ReactNode\n tone?: ProductionSectionTone\n count?: number\n done?: boolean\n doneLabel?: string\n}\n\n/** Tokenized extraction of the production premium single-page section card. */\nexport function ProductionPremiumSection({\n title,\n subtitle,\n actions,\n icon,\n tone = 'neutral',\n count,\n done,\n doneLabel = 'Done',\n defaultOpen = true,\n children,\n}: ProductionPremiumSectionProps) {\n const [open, setOpen] = React.useState(defaultOpen)\n return (\n <section className=\"overflow-hidden rounded-2xl border border-border bg-surface shadow-sm transition-shadow hover:shadow-md\">\n <div className=\"flex items-center gap-3 p-4 sm:gap-4 sm:p-5\">\n {icon ? (\n <span className={cn('flex size-11 shrink-0 items-center justify-center rounded-xl', TONE[tone])}>\n {icon}\n </span>\n ) : null}\n <button\n type=\"button\"\n onClick={() => setOpen((value) => !value)}\n className=\"flex min-w-0 flex-1 items-center justify-between gap-3 text-left\"\n aria-expanded={open}\n >\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2\">\n <h2 className=\"truncate text-base font-semibold text-fg sm:text-[17px]\">{title}</h2>\n {typeof count === 'number' ? (\n <span className=\"rounded-full bg-bg-subtle px-2 py-0.5 text-xs font-medium text-fg-muted\">\n {count}\n </span>\n ) : null}\n {done ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-success-subtle px-2 py-0.5 text-xs font-medium text-success\">\n <Check size={11} /> {doneLabel}\n </span>\n ) : null}\n </div>\n {subtitle ? <p className=\"mt-0.5 truncate text-sm text-fg-muted\">{subtitle}</p> : null}\n </div>\n <ChevronDown\n size={18}\n className={cn('shrink-0 text-fg-subtle transition-transform', !open && '-rotate-90')}\n />\n </button>\n {actions ? <div className=\"shrink-0\">{actions}</div> : null}\n </div>\n {open ? <div className=\"border-t border-border-subtle p-4 sm:p-5\">{children}</div> : null}\n </section>\n )\n}\n"]}
|
package/properties.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type FormField, type FormSchemaV1, type FormSection } from '@braedonsaunders/appkit-forms-core';
|
|
3
|
+
import { type AppLocale } from '@braedonsaunders/appkit-i18n';
|
|
4
|
+
export type FormDataSourceColumn = {
|
|
5
|
+
key: string;
|
|
6
|
+
label: string;
|
|
7
|
+
type: 'text' | 'number' | 'date' | 'boolean';
|
|
8
|
+
};
|
|
9
|
+
export type FormDataSource = {
|
|
10
|
+
id: string;
|
|
11
|
+
key: string;
|
|
12
|
+
name: string;
|
|
13
|
+
kind?: string;
|
|
14
|
+
columns: FormDataSourceColumn[];
|
|
15
|
+
};
|
|
16
|
+
export type FieldPropertiesProps = {
|
|
17
|
+
sectionId: string;
|
|
18
|
+
field: FormField;
|
|
19
|
+
schema: FormSchemaV1;
|
|
20
|
+
locale: AppLocale;
|
|
21
|
+
defaultLocale?: AppLocale;
|
|
22
|
+
dataSources?: readonly FormDataSource[];
|
|
23
|
+
dataSourcesLoading?: boolean;
|
|
24
|
+
onRefreshDataSources?: () => void | Promise<void>;
|
|
25
|
+
readOnly?: boolean;
|
|
26
|
+
onChange: (patch: Partial<FormField>) => void;
|
|
27
|
+
};
|
|
28
|
+
export declare function FieldProperties({ sectionId, field, schema, locale, defaultLocale, dataSources, dataSourcesLoading, onRefreshDataSources, readOnly, onChange }: FieldPropertiesProps): React.JSX.Element;
|
|
29
|
+
export declare function SectionProperties({ section, schema, locale, readOnly, onChange }: {
|
|
30
|
+
section: FormSection;
|
|
31
|
+
schema: FormSchemaV1;
|
|
32
|
+
locale: AppLocale;
|
|
33
|
+
readOnly?: boolean;
|
|
34
|
+
onChange: (patch: Partial<FormSection>) => void;
|
|
35
|
+
}): React.JSX.Element;
|
|
36
|
+
//# sourceMappingURL=properties.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"properties.d.ts","sourceRoot":"","sources":["../src/properties.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,WAAW,EAGjB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAO7D,MAAM,MAAM,oBAAoB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAA;CAAE,CAAA;AAC/G,MAAM,MAAM,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,oBAAoB,EAAE,CAAA;CAAE,CAAA;AAEtH,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,SAAS,CAAA;IAChB,MAAM,EAAE,YAAY,CAAA;IACpB,MAAM,EAAE,SAAS,CAAA;IACjB,aAAa,CAAC,EAAE,SAAS,CAAA;IACzB,WAAW,CAAC,EAAE,SAAS,cAAc,EAAE,CAAA;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,oBAAoB,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA;CAC9C,CAAA;AAID,wBAAgB,eAAe,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,aAAsB,EAAE,WAAgB,EAAE,kBAA0B,EAAE,oBAAoB,EAAE,QAAgB,EAAE,QAAQ,EAAE,EAAE,oBAAoB,qBA8BjN;AAqGD,wBAAgB,iBAAiB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAgB,EAAE,QAAQ,EAAE,EAAE;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAA;CAAE,qBAGhO"}
|
package/properties.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Plus, RefreshCw, Trash2 } from 'lucide-react';
|
|
5
|
+
import { CHOICE_FIELD_TYPES, FIELD_TYPES, entityKindForPicker, storesResponseValue, } from '@braedonsaunders/appkit-forms-core';
|
|
6
|
+
import {} from '@braedonsaunders/appkit-i18n';
|
|
7
|
+
import { Button, Checkbox, Input, Label, Select, Textarea, cn } from '@braedonsaunders/appkit-ui';
|
|
8
|
+
import { defaultBox } from './canvas-editor.js';
|
|
9
|
+
import { FormulaBuilder } from './formula-builder.js';
|
|
10
|
+
import { LogicBuilder } from './logic-builder.js';
|
|
11
|
+
import { readText, writeText } from './text.js';
|
|
12
|
+
export function FieldProperties({ sectionId, field, schema, locale, defaultLocale = locale, dataSources = [], dataSourcesLoading = false, onRefreshDataSources, readOnly = false, onChange }) {
|
|
13
|
+
const [tab, setTab] = React.useState('basic');
|
|
14
|
+
const ownerSection = schema.sections.find((section) => section.id === sectionId);
|
|
15
|
+
const otherFields = schema.sections.flatMap((section) => {
|
|
16
|
+
if (section.repeating && section.id !== sectionId)
|
|
17
|
+
return [];
|
|
18
|
+
if (!ownerSection?.repeating && section.repeating)
|
|
19
|
+
return [];
|
|
20
|
+
return section.fields;
|
|
21
|
+
}).filter((candidate) => candidate.id !== field.id && storesResponseValue(candidate)).map((candidate) => ({ id: candidate.id, label: readText(candidate.label, locale, candidate.id) }));
|
|
22
|
+
const repeatingSections = schema.sections.filter((section) => section.repeating).map((section) => ({ id: section.id, label: readText(section.title, locale, section.id), fields: section.fields.filter((candidate) => storesResponseValue(candidate) || (!ownerSection?.repeating && candidate.type === 'formula' && candidate.formula !== undefined)).map((candidate) => ({ id: candidate.id, label: readText(candidate.label, locale, candidate.id) })) }));
|
|
23
|
+
const pickerFields = schema.sections.filter((section) => !section.repeating).flatMap((section) => section.fields).map((candidate) => ({ candidate, kind: entityKindForPicker(candidate.type) })).filter((entry) => entry.kind !== null).map(({ candidate, kind }) => ({ id: candidate.id, label: readText(candidate.label, locale, candidate.id), kind }));
|
|
24
|
+
const storesValue = storesResponseValue(field);
|
|
25
|
+
const tabs = [
|
|
26
|
+
['basic', 'Basic', true],
|
|
27
|
+
['validation', 'Validation', storesValue],
|
|
28
|
+
['logic', 'Logic', true],
|
|
29
|
+
['default', 'Default', storesValue],
|
|
30
|
+
['formula', 'Formula', field.type === 'formula'],
|
|
31
|
+
].filter((entry) => entry[2]);
|
|
32
|
+
return _jsxs("div", { className: "space-y-3 text-sm", children: [_jsx("h3", { className: "text-sm font-semibold text-fg", children: FIELD_TYPES[field.type]?.label ?? field.type }), _jsx("div", { className: "app-scroll flex overflow-x-auto border-b border-border", children: tabs.map(([value, label]) => _jsx("button", { type: "button", onClick: () => setTab(value), className: cn('-mb-px shrink-0 border-b-2 px-2 py-1 text-xs', tab === value ? 'border-primary font-semibold text-primary' : 'border-transparent text-fg-muted hover:text-fg'), children: label }, value)) }), tab === 'basic' ? _jsx(FieldBasic, { field: field, schema: schema, sectionId: sectionId, locale: locale, defaultLocale: defaultLocale, dataSources: dataSources, dataSourcesLoading: dataSourcesLoading, onRefreshDataSources: onRefreshDataSources, readOnly: readOnly, onChange: onChange }) : null, tab === 'validation' && storesValue ? _jsx(FieldValidation, { field: field, readOnly: readOnly, onChange: onChange }) : null, tab === 'logic' ? _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Show this field when" }), _jsx("p", { className: "text-[10px] text-fg-subtle", children: "Leave empty to always show the field." }), _jsx(LogicBuilder, { rule: field.showIf, availableFields: otherFields, onChange: (showIf) => onChange({ showIf }), disabled: readOnly })] }) : null, tab === 'default' && storesValue ? _jsx(FieldDefault, { field: field, readOnly: readOnly, onChange: onChange }) : null, tab === 'formula' && field.type === 'formula' ? _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: "Formula" }), _jsx("p", { className: "text-[10px] text-fg-subtle", children: "Build a typed expression from fields, repeating sections, and selected entity attributes." }), _jsx(FormulaBuilder, { value: field.formula, allFields: otherFields, repeatingSections: repeatingSections, pickerFields: pickerFields, onChange: (formula) => onChange({ formula }) })] }) : null] });
|
|
33
|
+
}
|
|
34
|
+
function FieldBasic({ field, schema, sectionId, locale, dataSources, dataSourcesLoading, onRefreshDataSources, readOnly = false, onChange }) {
|
|
35
|
+
const ownerSection = schema.sections.find((section) => section.id === sectionId);
|
|
36
|
+
const otherFields = schema.sections.flatMap((section) => ownerSection?.repeating ? section.id === sectionId ? section.fields : [] : section.repeating ? [] : section.fields).filter((candidate) => candidate.id !== field.id && storesResponseValue(candidate)).map((candidate) => ({ id: candidate.id, label: readText(candidate.label, locale, candidate.id) }));
|
|
37
|
+
return _jsxs("div", { className: "space-y-3", children: [_jsx(Labeled, { label: "Field key", children: _jsx(Input, { value: field.id, disabled: true, className: "font-mono text-xs" }) }), _jsx(Labeled, { label: `Label · ${locale.toUpperCase()}`, children: _jsx(Input, { value: readText(field.label, locale), disabled: readOnly, onChange: (event) => onChange({ label: writeText(field.label, event.target.value, locale) }) }) }), _jsx(Labeled, { label: "Help text", children: _jsx(Textarea, { rows: 2, value: readText(field.helpText, locale), disabled: readOnly, onChange: (event) => onChange({ helpText: writeText(field.helpText, event.target.value, locale) }) }) }), storesResponseValue(field) ? _jsxs("label", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { checked: field.required ?? false, disabled: readOnly, onChange: (event) => onChange({ required: event.currentTarget.checked }) }), "Required"] }) : null, _jsxs(Labeled, { label: "Width", children: [_jsxs(Select, { value: String(field.colSpan ?? ''), disabled: readOnly, onChange: (event) => onChange({ colSpan: event.target.value ? Number(event.target.value) : undefined }), children: [_jsx("option", { value: "", children: "Full width" }), [1, 2, 3, 4].map((value) => _jsxs("option", { value: value, children: [value, " column", value === 1 ? '' : 's'] }, value))] }), _jsx("p", { className: "text-[10px] text-fg-subtle", children: "Width is clamped to the section column count." })] }), CHOICE_FIELD_TYPES.has(field.type) ? _jsx(ChoiceOptions, { field: field, locale: locale, readOnly: readOnly, onChange: onChange }) : null, field.type === 'table' ? _jsx(TableEditor, { field: field, readOnly: readOnly, onChange: onChange }) : null, field.type === 'slider' ? _jsx(SliderEditor, { field: field, readOnly: readOnly, onChange: onChange }) : null, field.type === 'matrix' ? _jsx(MatrixEditor, { field: field, readOnly: readOnly, onChange: onChange }) : null, field.type === 'lookup' || field.type === 'data_table' || field.type === 'metric' ? _jsx(DataBindingEditor, { field: field, sources: dataSources, loading: Boolean(dataSourcesLoading), otherFields: otherFields, autofillFields: otherFields, onRefresh: onRefreshDataSources, readOnly: readOnly, onChange: onChange }) : null] });
|
|
38
|
+
}
|
|
39
|
+
function FieldValidation({ field, readOnly, onChange }) {
|
|
40
|
+
const value = field.validation ?? {};
|
|
41
|
+
const set = (patch) => {
|
|
42
|
+
const next = { ...value, ...patch };
|
|
43
|
+
for (const key of Object.keys(next))
|
|
44
|
+
if (next[key] === undefined || next[key] === '')
|
|
45
|
+
delete next[key];
|
|
46
|
+
onChange({ validation: Object.keys(next).length ? next : undefined });
|
|
47
|
+
};
|
|
48
|
+
const numeric = ['number', 'currency', 'percentage', 'rating', 'slider'].includes(field.type);
|
|
49
|
+
const text = ['text', 'long_text', 'email', 'phone', 'url'].includes(field.type);
|
|
50
|
+
return _jsxs("div", { className: "space-y-3", children: [_jsxs("label", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { checked: value.required ?? field.required ?? false, disabled: readOnly, onChange: (event) => set({ required: event.currentTarget.checked }) }), "Required"] }), numeric ? _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(NumberSetting, { label: "Minimum", value: value.min, disabled: readOnly, onChange: (min) => set({ min }) }), _jsx(NumberSetting, { label: "Maximum", value: value.max, disabled: readOnly, onChange: (max) => set({ max }) })] }) : null, text ? _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(NumberSetting, { label: "Minimum length", value: value.minLength, disabled: readOnly, onChange: (minLength) => set({ minLength }) }), _jsx(NumberSetting, { label: "Maximum length", value: value.maxLength, disabled: readOnly, onChange: (maxLength) => set({ maxLength }) })] }) : null, text ? _jsxs(Labeled, { label: "Pattern", children: [_jsx(Input, { value: value.pattern ?? '', disabled: readOnly, onChange: (event) => set({ pattern: event.target.value || undefined }), placeholder: "Regular expression" }), _jsx("p", { className: "text-[11px] text-fg-subtle", children: "The pattern is validated before the schema can be published." })] }) : null, _jsx(Labeled, { label: "Validation message", children: _jsx(Input, { value: value.message ?? '', disabled: readOnly, onChange: (event) => set({ message: event.target.value || undefined }), placeholder: "Use the default message" }) })] });
|
|
51
|
+
}
|
|
52
|
+
function FieldDefault({ field, readOnly, onChange }) {
|
|
53
|
+
const value = field.defaultValue;
|
|
54
|
+
function setKind(kind) {
|
|
55
|
+
const next = kind === 'literal' ? { kind: 'literal', value: '' } : kind === 'today' ? { kind: 'today' } : kind === 'now' ? { kind: 'now' } : kind === 'current_user_person_id' ? { kind: 'current_user_person_id' } : kind === 'current_user_name' ? { kind: 'current_user_name' } : undefined;
|
|
56
|
+
onChange({ defaultValue: next });
|
|
57
|
+
}
|
|
58
|
+
return _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-xs text-fg-muted", children: "Defaults apply once when a new response begins." }), _jsxs(Select, { value: value?.kind ?? '', disabled: readOnly, onChange: (event) => setKind(event.target.value), children: [_jsx("option", { value: "", children: "No default" }), _jsx("option", { value: "literal", children: "Literal value" }), _jsx("option", { value: "today", children: "Today's date" }), _jsx("option", { value: "now", children: "Right now" }), _jsx("option", { value: "current_user_person_id", children: "Current user's person ID" }), _jsx("option", { value: "current_user_name", children: "Current user's name" })] }), value?.kind === 'literal' ? _jsx(Input, { value: String(value.value ?? ''), disabled: readOnly, onChange: (event) => onChange({ defaultValue: { kind: 'literal', value: event.target.value } }) }) : null] });
|
|
59
|
+
}
|
|
60
|
+
function ChoiceOptions({ field, locale, readOnly, onChange }) {
|
|
61
|
+
const options = field.validation?.options ?? [];
|
|
62
|
+
const update = (next) => onChange({ validation: { ...field.validation, options: next } });
|
|
63
|
+
return _jsxs(ConfigBox, { title: "Options", children: [_jsx("div", { className: "space-y-1", children: options.map((option, index) => _jsxs("div", { className: "flex gap-1", children: [_jsx(Input, { className: "font-mono text-xs", value: option.value, disabled: readOnly, onChange: (event) => { const next = [...options]; next[index] = { ...option, value: event.target.value }; update(next); } }), _jsx(Input, { value: readText(option.label, locale), disabled: readOnly, onChange: (event) => { const next = [...options]; next[index] = { ...option, label: writeText(option.label, event.target.value, locale) }; update(next); } }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => update(options.filter((_, candidate) => candidate !== index)) })] }, `${option.value}-${index}`)) }), _jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly, onClick: () => update([...options, { value: `opt_${options.length + 1}`, label: writeText(undefined, 'New option', locale) }]), children: [_jsx(Plus, { size: 12 }), "Add option"] }), _jsxs("label", { className: "flex items-center gap-2 text-xs", children: [_jsx(Checkbox, { checked: field.validation?.allowOther ?? false, disabled: readOnly, onChange: (event) => onChange({ validation: { ...field.validation, allowOther: event.currentTarget.checked } }) }), "Allow another value"] })] });
|
|
64
|
+
}
|
|
65
|
+
function SliderEditor({ field, readOnly, onChange }) {
|
|
66
|
+
const config = field.config ?? {};
|
|
67
|
+
const set = (patch) => onChange({ config: { ...config, ...patch } });
|
|
68
|
+
return _jsxs(ConfigBox, { title: "Slider", children: [_jsxs("div", { className: "grid grid-cols-3 gap-2", children: [_jsx(NumberSetting, { label: "Minimum", value: Number(config.min ?? 0), disabled: readOnly, onChange: (min) => set({ min }) }), _jsx(NumberSetting, { label: "Maximum", value: Number(config.max ?? 10), disabled: readOnly, onChange: (max) => set({ max }) }), _jsx(NumberSetting, { label: "Step", value: Number(config.step ?? 1), disabled: readOnly, onChange: (step) => set({ step }) })] }), _jsx(Labeled, { label: "Unit", children: _jsx(Input, { value: String(config.unit ?? ''), disabled: readOnly, onChange: (event) => set({ unit: event.target.value }), placeholder: "hours" }) })] });
|
|
69
|
+
}
|
|
70
|
+
function MatrixEditor({ field, readOnly, onChange }) {
|
|
71
|
+
const config = field.config ?? {};
|
|
72
|
+
const rows = Array.isArray(config.rows) ? config.rows : [];
|
|
73
|
+
const scale = Array.isArray(config.scale) ? config.scale : [];
|
|
74
|
+
const patch = (next) => onChange({ config: { ...config, ...next } });
|
|
75
|
+
return _jsxs(ConfigBox, { title: "Matrix", children: [_jsx(ListEditor, { title: "Rows", values: rows, readOnly: readOnly, keyName: "key", valueName: "label", onChange: (next) => patch({ rows: next }) }), _jsx(ListEditor, { title: "Scale", values: scale, readOnly: readOnly, keyName: "value", valueName: "label", onChange: (next) => patch({ scale: next }) })] });
|
|
76
|
+
}
|
|
77
|
+
function TableEditor({ field, readOnly, onChange }) {
|
|
78
|
+
const config = field.config ?? {};
|
|
79
|
+
const columns = config.columns ?? [];
|
|
80
|
+
const rows = config.rows ?? [];
|
|
81
|
+
const rowMode = config.rowMode === 'fixed' ? 'fixed' : 'addable';
|
|
82
|
+
const set = (patch) => onChange({ config: { ...config, ...patch } });
|
|
83
|
+
return _jsxs(ConfigBox, { title: "Table", children: [_jsx(Labeled, { label: "Rows", children: _jsxs(Select, { value: rowMode, disabled: readOnly, onChange: (event) => set(event.target.value === 'fixed' ? { rowMode: 'fixed', minRows: undefined, maxRows: undefined } : { rowMode: 'addable', rows: undefined }), children: [_jsx("option", { value: "addable", children: "User adds and removes rows" }), _jsx("option", { value: "fixed", children: "Predefined rows" })] }) }), rowMode === 'addable' ? _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(NumberSetting, { label: "Minimum rows", value: config.minRows, disabled: readOnly, onChange: (minRows) => set({ minRows }) }), _jsx(NumberSetting, { label: "Maximum rows", value: config.maxRows, disabled: readOnly, onChange: (maxRows) => set({ maxRows }) })] }) : null, _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { className: "text-xs", children: "Columns" }), columns.map((column, index) => _jsxs("div", { className: "space-y-1 rounded border border-border bg-surface p-2", children: [_jsxs("div", { className: "flex gap-1", children: [_jsx(Input, { value: column.label, disabled: readOnly, onChange: (event) => set({ columns: replace(columns, index, { ...column, label: event.target.value }) }) }), _jsxs(Select, { value: column.type, disabled: readOnly, onChange: (event) => { const type = event.target.value; set({ columns: replace(columns, index, { ...column, type, options: type === 'select' ? column.options ?? [] : undefined }) }); }, children: [_jsx("option", { value: "text", children: "Text" }), _jsx("option", { value: "number", children: "Number" }), _jsx("option", { value: "select", children: "Dropdown" }), _jsx("option", { value: "checkbox", children: "Checkbox" }), _jsx("option", { value: "date", children: "Date" })] }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => set({ columns: columns.filter((_, candidate) => candidate !== index) }) })] }), _jsx(Input, { className: "font-mono text-xs", value: column.key, disabled: readOnly, onChange: (event) => set({ columns: replace(columns, index, { ...column, key: event.target.value.replace(/\s+/g, '_') }) }) }), column.type === 'select' ? _jsx(TableOptions, { options: column.options ?? [], readOnly: readOnly, onChange: (options) => set({ columns: replace(columns, index, { ...column, options }) }) }) : null] }, `${column.key}-${index}`)), _jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly, onClick: () => set({ columns: [...columns, { key: `col_${columns.length + 1}`, label: `Column ${columns.length + 1}`, type: 'text' }] }), children: [_jsx(Plus, { size: 12 }), "Add column"] })] }), rowMode === 'fixed' ? _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { className: "text-xs", children: "Predefined rows" }), rows.map((row, index) => _jsxs("div", { className: "flex gap-1", children: [_jsx(Input, { value: row.label, disabled: readOnly, onChange: (event) => set({ rows: replace(rows, index, { label: event.target.value }) }) }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => set({ rows: rows.filter((_, candidate) => candidate !== index) }) })] }, index)), _jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly, onClick: () => set({ rows: [...rows, { label: `Row ${rows.length + 1}` }] }), children: [_jsx(Plus, { size: 12 }), "Add row"] })] }) : null] });
|
|
84
|
+
}
|
|
85
|
+
function TableOptions({ options, readOnly, onChange }) {
|
|
86
|
+
return _jsxs("div", { className: "space-y-1 rounded border border-border-subtle bg-bg-subtle p-1.5", children: [_jsx(Label, { className: "text-[10px]", children: "Dropdown options" }), options.map((option, index) => _jsxs("div", { className: "flex gap-1", children: [_jsx(Input, { className: "h-7 text-xs", value: option.label, disabled: readOnly, onChange: (event) => onChange(replace(options, index, { value: option.value || slug(event.target.value), label: event.target.value })) }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => onChange(options.filter((_, candidate) => candidate !== index)) })] }, index)), _jsxs(Button, { size: "sm", variant: "outline", disabled: readOnly, onClick: () => onChange([...options, { value: `opt_${options.length + 1}`, label: `Option ${options.length + 1}` }]), children: [_jsx(Plus, { size: 11 }), "Add"] })] });
|
|
87
|
+
}
|
|
88
|
+
function DataBindingEditor({ field, sources, loading, otherFields, autofillFields, onRefresh, readOnly, onChange }) {
|
|
89
|
+
const binding = field.binding;
|
|
90
|
+
const source = sources.find((candidate) => candidate.key === binding?.sourceKey);
|
|
91
|
+
const columns = source?.columns ?? [];
|
|
92
|
+
const patch = (next) => { const merged = { ...binding, ...next }; if (!merged.sourceKey)
|
|
93
|
+
onChange({ binding: undefined });
|
|
94
|
+
else
|
|
95
|
+
onChange({ binding: merged, ...(field.type === 'data_table' && next.selectable === 'none' ? { required: undefined, validation: undefined, defaultValue: undefined } : {}) }); };
|
|
96
|
+
return _jsxs(ConfigBox, { title: "Data source", action: onRefresh ? _jsxs("button", { type: "button", disabled: readOnly, onClick: () => void onRefresh(), className: "inline-flex items-center gap-1 text-[11px] text-primary hover:underline", children: [_jsx(RefreshCw, { size: 11 }), "Refresh"] }) : null, children: [_jsx(Labeled, { label: "Source", children: _jsxs(Select, { value: binding?.sourceKey ?? '', disabled: readOnly, onChange: (event) => onChange({ binding: event.target.value ? { sourceKey: event.target.value } : undefined }), children: [_jsx("option", { value: "", children: loading ? 'Loading…' : 'Choose a data source' }), sources.map((item) => _jsx("option", { value: item.key, children: item.name }, item.id))] }) }), source ? _jsxs(_Fragment, { children: [field.type === 'lookup' ? _jsx(LookupBinding, { binding: binding, columns: columns, otherFields: otherFields, autofillFields: autofillFields, readOnly: readOnly, patch: patch }) : null, field.type === 'data_table' ? _jsx(DataTableBinding, { binding: binding, columns: columns, readOnly: readOnly, patch: patch }) : null, field.type === 'metric' ? _jsx(MetricBinding, { binding: binding, columns: columns, readOnly: readOnly, patch: patch }) : null] }) : null] });
|
|
97
|
+
}
|
|
98
|
+
function LookupBinding({ binding, columns, otherFields, autofillFields, readOnly, patch }) {
|
|
99
|
+
const autofill = binding?.autofill ?? [];
|
|
100
|
+
return _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(ColumnSelect, { label: "Label column", value: binding?.labelColumn, columns: columns, readOnly: readOnly, onChange: (labelColumn) => patch({ labelColumn }) }), _jsx(ColumnSelect, { label: "Value column", value: binding?.valueColumn, columns: columns, readOnly: readOnly, onChange: (valueColumn) => patch({ valueColumn }) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(Labeled, { label: "Parent field", children: _jsxs(Select, { value: binding?.filterByField ?? '', disabled: readOnly, onChange: (event) => patch({ filterByField: event.target.value || undefined }), children: [_jsx("option", { value: "", children: "No cascade" }), otherFields.map((item) => _jsx("option", { value: item.id, children: item.label }, item.id))] }) }), _jsx(ColumnSelect, { label: "Match column", value: binding?.filterColumn, columns: columns, readOnly: readOnly, onChange: (filterColumn) => patch({ filterColumn }) })] }), _jsx(Labeled, { label: "Results per search", children: _jsx(Input, { type: "number", min: 1, max: 1000, value: binding?.limit ?? '', disabled: readOnly, onChange: (event) => patch({ limit: event.target.value ? Number(event.target.value) : undefined }) }) }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs", children: "Auto-fill" }), _jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly, onClick: () => patch({ autofill: [...autofill, { column: columns[0]?.key ?? '', targetFieldId: autofillFields[0]?.id ?? '' }] }), children: [_jsx(Plus, { size: 11 }), "Add"] })] }), autofill.map((entry, index) => _jsxs("div", { className: "flex gap-1", children: [_jsx(Select, { value: entry.column, disabled: readOnly, onChange: (event) => patch({ autofill: replace(autofill, index, { ...entry, column: event.target.value }) }), children: columns.map((column) => _jsx("option", { value: column.key, children: column.label }, column.key)) }), _jsx(Select, { value: entry.targetFieldId, disabled: readOnly, onChange: (event) => patch({ autofill: replace(autofill, index, { ...entry, targetFieldId: event.target.value }) }), children: autofillFields.map((item) => _jsx("option", { value: item.id, children: item.label }, item.id)) }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => patch({ autofill: autofill.filter((_, candidate) => candidate !== index) }) })] }, index))] })] });
|
|
101
|
+
}
|
|
102
|
+
function DataTableBinding({ binding, columns, readOnly, patch }) {
|
|
103
|
+
const selected = new Set(binding?.columns ?? columns.map((column) => column.key));
|
|
104
|
+
return _jsxs("div", { className: "space-y-2", children: [_jsx(Labeled, { label: "Selection", children: _jsxs(Select, { value: binding?.selectable ?? 'none', disabled: readOnly, onChange: (event) => patch({ selectable: event.target.value }), children: [_jsx("option", { value: "none", children: "Display only" }), _jsx("option", { value: "single", children: "Select one row" }), _jsx("option", { value: "multi", children: "Select multiple rows" })] }) }), _jsx(Labeled, { label: "Visible columns", children: _jsx("div", { className: "space-y-1", children: columns.map((column) => _jsxs("label", { className: "flex items-center gap-2 text-xs", children: [_jsx(Checkbox, { checked: selected.has(column.key), disabled: readOnly, onChange: () => { const next = new Set(selected); if (next.has(column.key))
|
|
105
|
+
next.delete(column.key);
|
|
106
|
+
else
|
|
107
|
+
next.add(column.key); patch({ columns: [...next] }); } }), column.label] }, column.key)) }) }), _jsx(Labeled, { label: "Rows per page", children: _jsx(Input, { type: "number", min: 1, max: 1000, value: binding?.limit ?? '', disabled: readOnly, onChange: (event) => patch({ limit: event.target.value ? Number(event.target.value) : undefined }) }) })] });
|
|
108
|
+
}
|
|
109
|
+
function MetricBinding({ binding, columns, readOnly, patch }) {
|
|
110
|
+
const aggregate = binding?.aggregate ?? { fn: 'count' };
|
|
111
|
+
const needsColumn = aggregate.fn !== 'count';
|
|
112
|
+
const set = (next) => patch({ aggregate: { ...aggregate, ...next } });
|
|
113
|
+
return _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(Labeled, { label: "Aggregate", children: _jsxs(Select, { value: aggregate.fn, disabled: readOnly, onChange: (event) => { const fn = event.target.value; patch({ aggregate: fn === 'count' ? { fn } : { fn, column: columns.find((column) => column.type === 'number')?.key } }); }, children: [_jsx("option", { value: "count", children: "Count" }), _jsx("option", { value: "sum", children: "Sum" }), _jsx("option", { value: "avg", children: "Average" }), _jsx("option", { value: "min", children: "Minimum" }), _jsx("option", { value: "max", children: "Maximum" })] }) }), _jsx(ColumnSelect, { label: "Value column", value: aggregate.column, columns: columns, readOnly: readOnly || !needsColumn, onChange: (column) => set({ column }) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(ColumnSelect, { label: "Group by", value: aggregate.groupBy, columns: columns, readOnly: readOnly, onChange: (groupBy) => patch({ aggregate: { ...aggregate, groupBy }, display: groupBy ? binding?.display === 'pie' ? 'pie' : 'bar' : 'number' }) }), _jsx(Labeled, { label: "Display", children: _jsx(Select, { value: binding?.display ?? (aggregate.groupBy ? 'bar' : 'number'), disabled: readOnly, onChange: (event) => patch({ display: event.target.value }), children: aggregate.groupBy ? _jsxs(_Fragment, { children: [_jsx("option", { value: "bar", children: "Bar chart" }), _jsx("option", { value: "pie", children: "Pie chart" })] }) : _jsx("option", { value: "number", children: "Number" }) }) })] }), _jsx(Labeled, { label: "Group limit", children: _jsx(Input, { type: "number", min: 1, max: 1000, value: binding?.limit ?? '', disabled: readOnly, onChange: (event) => patch({ limit: event.target.value ? Number(event.target.value) : undefined }) }) })] });
|
|
114
|
+
}
|
|
115
|
+
function ColumnSelect({ label, value, columns, readOnly, onChange }) { return _jsx(Labeled, { label: label, children: _jsxs(Select, { value: value ?? '', disabled: readOnly, onChange: (event) => onChange(event.target.value || undefined), children: [_jsx("option", { value: "", children: "Automatic" }), columns.map((column) => _jsx("option", { value: column.key, children: column.label }, column.key))] }) }); }
|
|
116
|
+
function ListEditor({ title, values, keyName, valueName, readOnly, onChange }) {
|
|
117
|
+
return _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs", children: title }), _jsxs(Button, { size: "sm", variant: "ghost", disabled: readOnly, onClick: () => onChange([...values, { [keyName]: `${String(keyName)}_${values.length + 1}`, [valueName]: `${title.slice(0, -1)} ${values.length + 1}` }]), children: [_jsx(Plus, { size: 11 }), "Add"] })] }), values.map((value, index) => _jsxs("div", { className: "flex gap-1", children: [_jsx(Input, { className: "w-20 font-mono text-xs", value: value[keyName], disabled: readOnly, onChange: (event) => onChange(replace(values, index, { ...value, [keyName]: event.target.value })) }), _jsx(Input, { value: value[valueName], disabled: readOnly, onChange: (event) => onChange(replace(values, index, { ...value, [valueName]: event.target.value })) }), _jsx(DeleteButton, { disabled: readOnly, onClick: () => onChange(values.filter((_, candidate) => candidate !== index)) })] }, index))] });
|
|
118
|
+
}
|
|
119
|
+
export function SectionProperties({ section, schema, locale, readOnly = false, onChange }) {
|
|
120
|
+
const fields = schema.sections.filter((candidate) => !candidate.repeating).flatMap((candidate) => candidate.fields).filter(storesResponseValue).map((field) => ({ id: field.id, label: readText(field.label, locale, field.id) }));
|
|
121
|
+
return _jsxs("div", { className: "space-y-3 text-sm", children: [_jsx("h3", { className: "text-sm font-semibold text-fg", children: "Section settings" }), _jsx(Labeled, { label: "Section key", children: _jsx(Input, { value: section.id, disabled: true, className: "font-mono text-xs" }) }), _jsx(Labeled, { label: `Title · ${locale.toUpperCase()}`, children: _jsx(Input, { value: readText(section.title, locale), disabled: readOnly, onChange: (event) => onChange({ title: writeText(section.title, event.target.value, locale) }) }) }), schema.tabs?.length ? _jsx(Labeled, { label: "Tab", children: _jsx(Select, { value: section.tabId ?? schema.tabs[0]?.id, disabled: readOnly, onChange: (event) => onChange({ tabId: event.target.value }), children: schema.tabs.map((tab) => _jsx("option", { value: tab.id, children: readText(tab.title, locale, tab.id) }, tab.id)) }) }) : null, _jsx(Labeled, { label: "Description", children: _jsx(Textarea, { rows: 2, value: readText(section.description, locale), disabled: readOnly, onChange: (event) => onChange({ description: writeText(section.description, event.target.value, locale) }) }) }), _jsx(Labeled, { label: "Workflow step", children: _jsxs(Select, { value: section.step ?? '', disabled: readOnly, onChange: (event) => onChange({ step: event.target.value || undefined }), children: [_jsx("option", { value: "", children: "First step" }), (schema.workflow?.steps ?? []).map((step) => _jsx("option", { value: step.key, children: readText(step.title, locale, step.key) }, step.key))] }) }), _jsx(Labeled, { label: "Columns", children: _jsx(Select, { value: String(section.layout?.columns ?? 1), disabled: readOnly, onChange: (event) => { const columns = Number(event.target.value); onChange({ layout: columns > 1 ? { columns, gap: section.layout?.gap } : undefined }); }, children: [1, 2, 3, 4].map((columns) => _jsxs("option", { value: columns, children: [columns, " column", columns === 1 ? '' : 's'] }, columns)) }) }), _jsxs("label", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { checked: section.repeating ?? false, disabled: readOnly, onChange: (event) => onChange({ repeating: event.currentTarget.checked }) }), "Repeating section"] }), section.repeating ? _jsxs(ConfigBox, { title: "Repeating rows", children: [_jsxs("div", { className: "grid grid-cols-2 gap-2", children: [_jsx(NumberSetting, { label: "Minimum rows", value: section.minRows, disabled: readOnly, onChange: (minRows) => onChange({ minRows }) }), _jsx(NumberSetting, { label: "Maximum rows", value: section.maxRows, disabled: readOnly, onChange: (maxRows) => onChange({ maxRows }) })] }), _jsx(Labeled, { label: "Row label", children: _jsx(Input, { value: section.rowLabelTemplate ?? '', disabled: readOnly, onChange: (event) => onChange({ rowLabelTemplate: event.target.value || undefined }), placeholder: "Item {{index}}" }) })] }) : null, _jsx(Labeled, { label: "Show this section when", children: _jsx(LogicBuilder, { rule: section.showIf, availableFields: fields, onChange: (showIf) => onChange({ showIf }), disabled: readOnly }) }), _jsxs("label", { className: "flex items-center gap-2", children: [_jsx(Checkbox, { checked: Boolean(section.canvas), disabled: readOnly, onChange: (event) => onChange({ canvas: event.currentTarget.checked ? createSectionCanvas(section) : undefined }) }), "Free-form canvas layout"] })] });
|
|
122
|
+
}
|
|
123
|
+
function ConfigBox({ title, action, children }) { return _jsxs("div", { className: "space-y-2 rounded-md border border-border bg-bg-subtle p-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2 text-[10px] font-semibold uppercase tracking-wider text-fg-subtle", children: [_jsx("span", { children: title }), action] }), children] }); }
|
|
124
|
+
function Labeled({ label, children }) { return _jsxs("div", { className: "space-y-1", children: [_jsx(Label, { className: "text-xs", children: label }), children] }); }
|
|
125
|
+
function NumberSetting({ label, value, disabled, onChange }) { return _jsx(Labeled, { label: label, children: _jsx(Input, { type: "number", value: value ?? '', disabled: disabled, onChange: (event) => onChange(event.target.value === '' ? undefined : Number(event.target.value)) }) }); }
|
|
126
|
+
function DeleteButton({ disabled, onClick }) { return _jsx("button", { type: "button", "aria-label": "Delete", disabled: disabled, onClick: onClick, className: "grid size-9 shrink-0 place-items-center rounded text-fg-subtle hover:bg-danger-subtle hover:text-danger disabled:opacity-40", children: _jsx(Trash2, { size: 13 }) }); }
|
|
127
|
+
function replace(values, index, value) { return values.map((candidate, candidateIndex) => candidateIndex === index ? value : candidate); }
|
|
128
|
+
function slug(value) { return value.toLowerCase().trim().replace(/[^a-z0-9]+/g, '_').replace(/^_|_$/g, ''); }
|
|
129
|
+
function createSectionCanvas(section) {
|
|
130
|
+
let y = 0;
|
|
131
|
+
return { cols: 12, rowHeight: 40, items: section.fields.map((field) => { const box = defaultBox(field.type); const item = { i: field.id, x: 0, y, ...box }; y += box.h; return item; }) };
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=properties.js.map
|