@servicetitan/dte-pdf-editor 1.48.0 → 1.50.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.
Files changed (55) hide show
  1. package/dist/components/field-config-panel/field-sidebar.d.ts.map +1 -1
  2. package/dist/components/field-config-panel/field-sidebar.js +42 -6
  3. package/dist/components/field-config-panel/field-sidebar.js.map +1 -1
  4. package/dist/components/field-config-panel/formula-modal.d.ts.map +1 -1
  5. package/dist/components/field-config-panel/formula-modal.js +55 -2
  6. package/dist/components/field-config-panel/formula-modal.js.map +1 -1
  7. package/dist/components/field-config-panel/formula-workspace.d.ts +1 -0
  8. package/dist/components/field-config-panel/formula-workspace.d.ts.map +1 -1
  9. package/dist/components/field-config-panel/formula-workspace.js +3 -3
  10. package/dist/components/field-config-panel/formula-workspace.js.map +1 -1
  11. package/dist/components/field-sidebar/data-model-field-type-list.d.ts.map +1 -1
  12. package/dist/components/field-sidebar/data-model-field-type-list.js +2 -1
  13. package/dist/components/field-sidebar/data-model-field-type-list.js.map +1 -1
  14. package/dist/components/field-sidebar/field-type.d.ts +1 -0
  15. package/dist/components/field-sidebar/field-type.d.ts.map +1 -1
  16. package/dist/components/field-sidebar/field-type.js +3 -3
  17. package/dist/components/field-sidebar/field-type.js.map +1 -1
  18. package/dist/components/field-sidebar/form-fields-type-list.d.ts.map +1 -1
  19. package/dist/components/field-sidebar/form-fields-type-list.js +2 -1
  20. package/dist/components/field-sidebar/form-fields-type-list.js.map +1 -1
  21. package/dist/components/pdf-view/pdf-view-data-model.d.ts.map +1 -1
  22. package/dist/components/pdf-view/pdf-view-data-model.js +8 -2
  23. package/dist/components/pdf-view/pdf-view-data-model.js.map +1 -1
  24. package/dist/interface/types.d.ts +1 -0
  25. package/dist/interface/types.d.ts.map +1 -1
  26. package/dist/interface/types.js.map +1 -1
  27. package/dist/utils/data-model/extract-fields.utils.d.ts.map +1 -1
  28. package/dist/utils/data-model/extract-fields.utils.js +4 -2
  29. package/dist/utils/data-model/extract-fields.utils.js.map +1 -1
  30. package/dist/utils/shared/index.d.ts +2 -0
  31. package/dist/utils/shared/index.d.ts.map +1 -1
  32. package/dist/utils/shared/index.js +2 -0
  33. package/dist/utils/shared/index.js.map +1 -1
  34. package/dist/utils/shared/sample-data.utils.d.ts +3 -0
  35. package/dist/utils/shared/sample-data.utils.d.ts.map +1 -0
  36. package/dist/utils/shared/sample-data.utils.js +20 -0
  37. package/dist/utils/shared/sample-data.utils.js.map +1 -0
  38. package/dist/utils/shared/schema.utils.d.ts +7 -0
  39. package/dist/utils/shared/schema.utils.d.ts.map +1 -0
  40. package/dist/utils/shared/schema.utils.js +9 -0
  41. package/dist/utils/shared/schema.utils.js.map +1 -0
  42. package/package.json +1 -1
  43. package/src/components/field-config-panel/field-sidebar.tsx +71 -7
  44. package/src/components/field-config-panel/formula-modal.tsx +61 -0
  45. package/src/components/field-config-panel/formula-workspace.tsx +8 -0
  46. package/src/components/field-sidebar/data-model-field-type-list.tsx +6 -1
  47. package/src/components/field-sidebar/field-type.tsx +16 -3
  48. package/src/components/field-sidebar/form-fields-type-list.tsx +5 -0
  49. package/src/components/pdf-view/pdf-view-data-model.tsx +13 -2
  50. package/src/interface/types.ts +1 -0
  51. package/src/styles/formula-modal.css +10 -0
  52. package/src/utils/data-model/extract-fields.utils.ts +2 -0
  53. package/src/utils/shared/index.ts +2 -0
  54. package/src/utils/shared/sample-data.utils.ts +29 -0
  55. package/src/utils/shared/schema.utils.ts +8 -0
@@ -1 +1 @@
1
- {"version":3,"file":"extract-fields.utils.js","sourceRoot":"","sources":["../../../src/utils/data-model/extract-fields.utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extract-fields.utils.js","sourceRoot":"","sources":["../../../src/utils/data-model/extract-fields.utils.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,5 @@
1
1
  export * from './date.utils';
2
2
  export * from './number.utils';
3
+ export * from './sample-data.utils';
4
+ export * from './schema.utils';
3
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
@@ -1,3 +1,5 @@
1
1
  export * from './date.utils';
2
2
  export * from './number.utils';
3
+ export * from './sample-data.utils';
4
+ export * from './schema.utils';
3
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/shared/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { PdfFieldSubType } from '../../interface/types';
2
+ export declare const getFieldSampleData: (sampleData: unknown, fieldSubType?: PdfFieldSubType) => string | number | null;
3
+ //# sourceMappingURL=sample-data.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-data.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/sample-data.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAWxD,eAAO,MAAM,kBAAkB,GAC3B,YAAY,OAAO,EACnB,eAAe,eAAe,KAC/B,MAAM,GAAG,MAAM,GAAG,IAcpB,CAAC"}
@@ -0,0 +1,20 @@
1
+ const DEFAULT_NUMBER_SAMPLE = 350;
2
+ const toPrimitiveSample = (value) => {
3
+ if (typeof value === 'string' || typeof value === 'number') {
4
+ return value;
5
+ }
6
+ return undefined;
7
+ };
8
+ export const getFieldSampleData = (sampleData, fieldSubType) => {
9
+ const primitiveSample = toPrimitiveSample(sampleData);
10
+ if (fieldSubType === 'date') {
11
+ const candidate = primitiveSample !== undefined ? new Date(primitiveSample) : new Date();
12
+ const source = Number.isNaN(candidate.getTime()) ? new Date() : candidate;
13
+ return source.toISOString().slice(0, 10);
14
+ }
15
+ if (fieldSubType === 'number') {
16
+ return primitiveSample !== null && primitiveSample !== void 0 ? primitiveSample : DEFAULT_NUMBER_SAMPLE;
17
+ }
18
+ return primitiveSample !== null && primitiveSample !== void 0 ? primitiveSample : null;
19
+ };
20
+ //# sourceMappingURL=sample-data.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample-data.utils.js","sourceRoot":"","sources":["../../../src/utils/shared/sample-data.utils.ts"],"names":[],"mappings":"AAEA,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,MAAM,iBAAiB,GAAG,CAAC,KAAc,EAA+B,EAAE;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAC9B,UAAmB,EACnB,YAA8B,EACR,EAAE;IACxB,MAAM,eAAe,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAEtD,IAAI,YAAY,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;QACzF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1E,OAAO,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,qBAAqB,CAAC;IACpD,CAAC;IAED,OAAO,eAAe,aAAf,eAAe,cAAf,eAAe,GAAI,IAAI,CAAC;AACnC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
3
+ * `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
4
+ * keeping the original newline so the rendered HTML source still wraps in dev tools.
5
+ */
6
+ export declare const nl2br: (value: string) => string;
7
+ //# sourceMappingURL=schema.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/shared/schema.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MAErC,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
3
+ * `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
4
+ * keeping the original newline so the rendered HTML source still wraps in dev tools.
5
+ */
6
+ export const nl2br = (value) => {
7
+ return value.replace(/\r\n|\n/g, '<br />\n');
8
+ };
9
+ //# sourceMappingURL=schema.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.utils.js","sourceRoot":"","sources":["../../../src/utils/shared/schema.utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAU,EAAE;IAC3C,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/dte-pdf-editor",
3
- "version": "1.48.0",
3
+ "version": "1.50.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -1,9 +1,13 @@
1
- import { Button, Flex, Text } from '@servicetitan/anvil2';
1
+ import { Button, Flex, SearchField, Text } from '@servicetitan/anvil2';
2
2
  import IconArrowBack from '@servicetitan/anvil2/assets/icons/material/round/keyboard_arrow_left.svg';
3
3
  import IconArrowForward from '@servicetitan/anvil2/assets/icons/material/round/keyboard_arrow_right.svg';
4
4
  import { FC, Fragment, useMemo, useState } from 'react';
5
5
  import { FieldTypeOption, FormFieldsByFormIdI, FormInfo } from '../../interface/types';
6
- import { formFieldInfosToCalculationOptions, parseFormFieldKey } from '../../utils';
6
+ import {
7
+ formFieldInfosToCalculationOptions,
8
+ getFieldSampleData,
9
+ parseFormFieldKey,
10
+ } from '../../utils';
7
11
 
8
12
  interface FieldSidebarProps {
9
13
  fillableOptions: FieldTypeOption[];
@@ -31,15 +35,23 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
31
35
  selectedPaths,
32
36
  }) => {
33
37
  const [selectedFormId, setSelectedFormId] = useState<number | null>(null);
38
+ const [topSearchValue, setTopSearchValue] = useState('');
39
+ const [formFieldsSearchValue, setFormFieldsSearchValue] = useState('');
34
40
 
35
41
  const onFormClick = (formId: number) => {
36
42
  setSelectedFormId(formId);
43
+ setFormFieldsSearchValue('');
37
44
  const loaded = formFieldsByFormId[formId];
38
45
  if (!loaded?.length) {
39
46
  onRequestFormFields(formId);
40
47
  }
41
48
  };
42
49
 
50
+ const onBackToList = () => {
51
+ setSelectedFormId(null);
52
+ setFormFieldsSearchValue('');
53
+ };
54
+
43
55
  const isFormFieldsLoading = selectedFormId != null && formulaLoadingFormId === selectedFormId;
44
56
 
45
57
  const selectedForm = useMemo(
@@ -57,6 +69,36 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
57
69
  );
58
70
  }, [selectedFormId, formFieldsByFormId, selectedForm?.name]);
59
71
 
72
+ const filteredForms = useMemo(() => {
73
+ const query = topSearchValue.trim().toLowerCase();
74
+ if (!query) {
75
+ return forms;
76
+ }
77
+ return forms.filter(form => form.name.toLowerCase().includes(query));
78
+ }, [forms, topSearchValue]);
79
+
80
+ const filteredMergeTagOptions = useMemo(() => {
81
+ const query = topSearchValue.trim().toLowerCase();
82
+ if (!query) {
83
+ return mergeTagOptions;
84
+ }
85
+ return mergeTagOptions.filter(option => {
86
+ const label = (option.label ?? option.path ?? '').toLowerCase();
87
+ return label.includes(query);
88
+ });
89
+ }, [mergeTagOptions, topSearchValue]);
90
+
91
+ const filteredCalcOptions = useMemo(() => {
92
+ const query = formFieldsSearchValue.trim().toLowerCase();
93
+ if (!query) {
94
+ return calcOptions;
95
+ }
96
+ return calcOptions.filter(option => {
97
+ const label = (option.label ?? option.path ?? '').toLowerCase();
98
+ return label.includes(query);
99
+ });
100
+ }, [calcOptions, formFieldsSearchValue]);
101
+
60
102
  const formIdsReferencedInFormula = useMemo(() => {
61
103
  const ids = new Set<number>();
62
104
  for (const path of selectedPaths) {
@@ -75,7 +117,14 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
75
117
  className={`dte-formula-sidebar-slide-track${selectedFormId ? ' --detail' : ''}`}
76
118
  >
77
119
  <div className="dte-formula-sidebar-slide-panel">
78
- {forms.length > 0 && (
120
+ <SearchField
121
+ placeholder="Search"
122
+ size="small"
123
+ style={{ marginLeft: '4px', marginTop: '18px' }}
124
+ value={topSearchValue}
125
+ onChange={e => setTopSearchValue(e.target.value ?? '')}
126
+ />
127
+ {filteredForms.length > 0 && (
79
128
  <div className="dte-formula-sidebar-forms-heading">
80
129
  <Text variant="headline" el="h6" size="small">
81
130
  Forms
@@ -85,7 +134,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
85
134
  role="listbox"
86
135
  aria-label="Forms"
87
136
  >
88
- {forms.map(form => (
137
+ {filteredForms.map(form => (
89
138
  <li
90
139
  key={form.id}
91
140
  role="option"
@@ -122,7 +171,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
122
171
  />
123
172
  <FieldOptionList
124
173
  title="Merge tags"
125
- options={mergeTagOptions}
174
+ options={filteredMergeTagOptions}
126
175
  highlightElementPath={highlightElementPath}
127
176
  selectedPaths={selectedPaths}
128
177
  onHover={onHover}
@@ -138,7 +187,7 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
138
187
  size="small"
139
188
  icon={IconArrowBack}
140
189
  title={selectedForm?.name ?? 'Form fields'}
141
- onClick={() => setSelectedFormId(null)}
190
+ onClick={onBackToList}
142
191
  >
143
192
  <Text
144
193
  size="medium"
@@ -148,11 +197,18 @@ export const FieldSidebar: FC<FieldSidebarProps> = ({
148
197
  {selectedForm?.name ?? 'Form fields'}
149
198
  </Text>
150
199
  </Button>
200
+ <SearchField
201
+ style={{ margin: '4px' }}
202
+ placeholder="Search"
203
+ size="small"
204
+ value={formFieldsSearchValue}
205
+ onChange={e => setFormFieldsSearchValue(e.target.value ?? '')}
206
+ />
151
207
 
152
208
  <FieldOptionList
153
209
  title=""
154
210
  isLoading={isFormFieldsLoading}
155
- options={calcOptions}
211
+ options={filteredCalcOptions}
156
212
  highlightElementPath={highlightElementPath}
157
213
  selectedPaths={selectedPaths}
158
214
  onHover={onHover}
@@ -228,6 +284,14 @@ const FieldOptionList: FC<FieldOptionListProps> = ({
228
284
  <span className="dte-text-ellipsis" title={opt.label ?? opt.path}>
229
285
  {opt.label ?? opt.path}
230
286
  </span>
287
+ <Text
288
+ size="small"
289
+ subdued
290
+ style={{ fontSize: '12px', marginTop: '-2px' }}
291
+ className="ellipsis"
292
+ >
293
+ e.g. {getFieldSampleData(opt.sampleData, opt.fieldType)}
294
+ </Text>
231
295
  </li>
232
296
  ))}
233
297
  </ul>
@@ -11,13 +11,17 @@ import { useFormulaEditor } from '../../hooks';
11
11
  import {
12
12
  CalculatedFieldFormat,
13
13
  DataModelFieldGroup,
14
+ DataModelValues,
14
15
  FieldTypeOption,
15
16
  FormFieldsByFormIdI,
16
17
  FormInfo,
17
18
  StructuredFormula,
18
19
  } from '../../interface/types';
19
20
  import {
21
+ evaluateFormula,
22
+ formatCalculatedResult,
20
23
  formFieldInfosToCalculationOptions,
24
+ getFieldSampleData,
21
25
  parseExpression,
22
26
  tokenizeExpression,
23
27
  tokensToExpression,
@@ -46,6 +50,20 @@ function getValidPathsSet(groups: DataModelFieldGroup[]): Set<string> {
46
50
  return set;
47
51
  }
48
52
 
53
+ function setSampleValueAtPath(target: DataModelValues, path: string, value: unknown): void {
54
+ const keys = path.split('.');
55
+ let cursor: DataModelValues = target;
56
+ for (let i = 0; i < keys.length - 1; i++) {
57
+ const key = keys[i];
58
+ const next = cursor[key];
59
+ if (next === null || typeof next !== 'object') {
60
+ cursor[key] = {};
61
+ }
62
+ cursor = cursor[key];
63
+ }
64
+ cursor[keys[keys.length - 1]] = value;
65
+ }
66
+
49
67
  export interface FormulaModalProps {
50
68
  initialFormula: StructuredFormula | undefined;
51
69
  initialFormat?: CalculatedFieldFormat;
@@ -197,6 +215,48 @@ export const FormulaModal: FC<FormulaModalProps> = ({
197
215
  return errors;
198
216
  }, [formulaEditor.draftExpression, validPaths]);
199
217
 
218
+ const optionByPath = useMemo(() => {
219
+ const map = new Map<string, FieldTypeOption>();
220
+ for (const opt of allFields) {
221
+ if (opt.path) {
222
+ map.set(opt.path, opt);
223
+ }
224
+ }
225
+ for (const opt of fillableFieldsFromDocument) {
226
+ if (opt.path) {
227
+ map.set(opt.path, opt);
228
+ }
229
+ }
230
+ for (const opt of formCalculationOptions) {
231
+ if (opt.path) {
232
+ map.set(opt.path, opt);
233
+ }
234
+ }
235
+ return map;
236
+ }, [allFields, fillableFieldsFromDocument, formCalculationOptions]);
237
+
238
+ const previewValue = useMemo(() => {
239
+ if (parsedTokens.length === 0 || !formulaValidation.valid) {
240
+ return '';
241
+ }
242
+ const sampleData: DataModelValues = {};
243
+ for (const token of parsedTokens) {
244
+ if (token.type !== 'field') {
245
+ continue;
246
+ }
247
+ const option = optionByPath.get(token.path);
248
+ const sample = getFieldSampleData(option?.sampleData, token.fieldType);
249
+ if (sample !== null) {
250
+ setSampleValueAtPath(sampleData, token.path, sample);
251
+ }
252
+ }
253
+ const computed = evaluateFormula({ tokens: parsedTokens }, sampleData);
254
+ if (computed === null) {
255
+ return '';
256
+ }
257
+ return formatCalculatedResult(computed, format);
258
+ }, [parsedTokens, formulaValidation.valid, optionByPath, format]);
259
+
200
260
  const handleClose = useCallback(() => {
201
261
  onClose();
202
262
  }, [onClose]);
@@ -243,6 +303,7 @@ export const FormulaModal: FC<FormulaModalProps> = ({
243
303
  isInvalid={isInvalid && formulaEditor.isDirty}
244
304
  validationError={validationError}
245
305
  format={format}
306
+ previewValue={previewValue}
246
307
  onResultTypeChange={nextType => {
247
308
  if (nextType === 'date') {
248
309
  setFormat(DEFAULT_DATE_CALCULATED_FORMAT);
@@ -30,6 +30,7 @@ interface FormulaWorkspaceProps {
30
30
  onRemoveField: (fieldIndex: number) => void;
31
31
  onResultTypeChange: (nextType: CalculatedFieldFormat['resultType']) => void;
32
32
  onToggleAdvanced: () => void;
33
+ previewValue: string;
33
34
  setFormat: Dispatch<SetStateAction<CalculatedFieldFormat>>;
34
35
  validationError: string;
35
36
  }
@@ -50,6 +51,7 @@ export const FormulaWorkspace: FC<FormulaWorkspaceProps> = ({
50
51
  onRemoveField,
51
52
  onResultTypeChange,
52
53
  onToggleAdvanced,
54
+ previewValue,
53
55
  setFormat,
54
56
  validationError,
55
57
  }) => {
@@ -74,6 +76,12 @@ export const FormulaWorkspace: FC<FormulaWorkspaceProps> = ({
74
76
 
75
77
  return (
76
78
  <Flex direction="column" flex={1} gap={2} style={{ padding: '12px' }}>
79
+ <Flex direction="column" gap={1}>
80
+ <Text variant="body" size="small">
81
+ Preview (uses demo sample data)
82
+ </Text>
83
+ <div className="dte-formula-preview">{previewValue ?? ' '}</div>
84
+ </Flex>
77
85
  <Text variant="body" size="small">
78
86
  Click a field on the left to add it. Use +, -,{' '}
79
87
  {disabledOperators?.has('*') ? '' : '*, /, and '}parentheses to build formulas.
@@ -1,6 +1,7 @@
1
1
  import { Flex, SearchField, Text } from '@servicetitan/anvil2';
2
2
  import { FC, Fragment, useMemo, useState } from 'react';
3
3
  import { DataModelFieldGroup, FieldTypeOption } from '../../interface/types';
4
+ import { getFieldSampleData } from '../../utils';
4
5
  import { FieldType } from './field-type';
5
6
 
6
7
  interface DataModelFieldTypeListProps {
@@ -51,9 +52,13 @@ export const DataModelFieldTypeList: FC<DataModelFieldTypeListProps> = ({
51
52
  return (
52
53
  <FieldType
53
54
  key={key}
54
- label={fieldOption.label}
55
55
  onDragEnd={onDragEnd}
56
56
  onDragStart={() => onDragStart(fieldOption)}
57
+ label={fieldOption.label}
58
+ sampleData={getFieldSampleData(
59
+ fieldOption.sampleData,
60
+ fieldOption.fieldType,
61
+ )}
57
62
  />
58
63
  );
59
64
  })}
@@ -1,14 +1,15 @@
1
- import { Icon, Text } from '@servicetitan/anvil2';
1
+ import { Flex, Icon, Text } from '@servicetitan/anvil2';
2
2
  import IconDragIndicator from '@servicetitan/anvil2/assets/icons/material/round/drag_indicator.svg';
3
3
  import { FC } from 'react';
4
4
 
5
5
  interface FieldTypeProps {
6
6
  label: string;
7
+ sampleData?: string | number | null;
7
8
  onDragEnd(): void;
8
9
  onDragStart(): void;
9
10
  }
10
11
 
11
- export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart }) => {
12
+ export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart, sampleData }) => {
12
13
  return (
13
14
  <div
14
15
  draggable
@@ -22,7 +23,19 @@ export const FieldType: FC<FieldTypeProps> = ({ label, onDragEnd, onDragStart })
22
23
  className="dte-field-type-item"
23
24
  >
24
25
  <Icon svg={IconDragIndicator} size="medium" />
25
- <Text size="small">{label}</Text>
26
+ <Flex direction="column" style={{ overflow: 'hidden' }}>
27
+ <Text size="small">{label}</Text>
28
+ {sampleData && (
29
+ <Text
30
+ size="small"
31
+ subdued
32
+ style={{ fontSize: '12px', marginTop: '-2px' }}
33
+ className="ellipsis"
34
+ >
35
+ e.g. {sampleData}
36
+ </Text>
37
+ )}
38
+ </Flex>
26
39
  </div>
27
40
  );
28
41
  };
@@ -4,6 +4,7 @@ import IconArrowForward from '@servicetitan/anvil2/assets/icons/material/round/k
4
4
  import { Stack } from '@servicetitan/design-system';
5
5
  import { FC, Fragment } from 'react';
6
6
  import { FieldTypeOption, FormInfo } from '../../interface/types';
7
+ import { getFieldSampleData } from '../../utils';
7
8
  import { FieldType } from './field-type';
8
9
 
9
10
  export interface FormFieldsTypeListProps {
@@ -97,6 +98,10 @@ export const FormFieldsTypeList: FC<FormFieldsTypeListProps> = ({
97
98
  <FieldType
98
99
  key={option.path}
99
100
  label={option.label}
101
+ sampleData={getFieldSampleData(
102
+ option.sampleData,
103
+ option.fieldType,
104
+ )}
100
105
  onDragEnd={onDragEnd}
101
106
  onDragStart={() => onDragStart(option)}
102
107
  />
@@ -1,6 +1,6 @@
1
1
  import { FC } from 'react';
2
2
  import { DataModelValues, PdfField } from '../../interface/types';
3
- import { resolvePdfDataValues } from '../../utils';
3
+ import { nl2br, resolvePdfDataValues } from '../../utils';
4
4
 
5
5
  interface PdfViewDataModelProps {
6
6
  field: PdfField;
@@ -9,5 +9,16 @@ interface PdfViewDataModelProps {
9
9
 
10
10
  export const PdfViewDataModel: FC<PdfViewDataModelProps> = ({ data, field }) => {
11
11
  const resolvedValue = field.path ? resolvePdfDataValues(data, field.path) : '';
12
- return <div className="dte-pdf-field-value">{resolvedValue ?? ''}</div>;
12
+
13
+ /*
14
+ * Mirrors Unlayer's `{{ field | safe | nl2br }}` as
15
+ * conversion. The `__html` key and `dangerouslySetInnerHTML` are mandated by React's API.
16
+ */
17
+ return (
18
+ <div
19
+ className="dte-pdf-field-value"
20
+ // eslint-disable-next-line react/no-danger, @typescript-eslint/naming-convention
21
+ dangerouslySetInnerHTML={{ __html: nl2br(resolvedValue ?? '') }}
22
+ />
23
+ );
13
24
  };
@@ -108,6 +108,7 @@ export interface FieldTypeOption {
108
108
  path?: string;
109
109
  fieldType?: SchemaFieldType;
110
110
  formSnapshot?: FormulaFieldFormSnapshot;
111
+ sampleData?: unknown;
111
112
  }
112
113
 
113
114
  export interface DataModelFieldGroup {
@@ -116,6 +116,16 @@
116
116
  white-space: pre-wrap;
117
117
  }
118
118
 
119
+ .dte-formula-preview {
120
+ padding: var(--spacing-1) var(--spacing-2);
121
+ border: 1px solid var(--border-color);
122
+ border-radius: 4px;
123
+ height: 20px;
124
+ background-color: var(--color-neutral-10, #f5f6f7);
125
+ font-size: var(--typescale-2);
126
+ line-height: var(--base-line-height);
127
+ }
128
+
119
129
  .dte-formula-editor:focus {
120
130
  border-color: var(--border-color-active);
121
131
  box-shadow: 0 0 0 1px var(--border-color-active);
@@ -91,6 +91,7 @@ export const extractGroupedFieldsFromDataModel = (
91
91
  type: FieldTypeEnum.dataModel,
92
92
  path: key,
93
93
  fieldType: getSchemaFieldType(property),
94
+ sampleData: property?.options?.sampleData,
94
95
  });
95
96
  }
96
97
  }
@@ -132,6 +133,7 @@ const extractFieldsRecursive = (
132
133
  type: FieldTypeEnum.dataModel,
133
134
  path: currentPath,
134
135
  fieldType: getSchemaFieldType(fieldProperty),
136
+ sampleData: fieldProperty.options?.sampleData,
135
137
  });
136
138
  } else if (fieldProperty.type === 'object' && fieldProperty.properties) {
137
139
  extractFieldsRecursive(
@@ -1,2 +1,4 @@
1
1
  export * from './date.utils';
2
2
  export * from './number.utils';
3
+ export * from './sample-data.utils';
4
+ export * from './schema.utils';
@@ -0,0 +1,29 @@
1
+ import { PdfFieldSubType } from '../../interface/types';
2
+
3
+ const DEFAULT_NUMBER_SAMPLE = 350;
4
+
5
+ const toPrimitiveSample = (value: unknown): string | number | undefined => {
6
+ if (typeof value === 'string' || typeof value === 'number') {
7
+ return value;
8
+ }
9
+ return undefined;
10
+ };
11
+
12
+ export const getFieldSampleData = (
13
+ sampleData: unknown,
14
+ fieldSubType?: PdfFieldSubType,
15
+ ): string | number | null => {
16
+ const primitiveSample = toPrimitiveSample(sampleData);
17
+
18
+ if (fieldSubType === 'date') {
19
+ const candidate = primitiveSample !== undefined ? new Date(primitiveSample) : new Date();
20
+ const source = Number.isNaN(candidate.getTime()) ? new Date() : candidate;
21
+ return source.toISOString().slice(0, 10);
22
+ }
23
+
24
+ if (fieldSubType === 'number') {
25
+ return primitiveSample ?? DEFAULT_NUMBER_SAMPLE;
26
+ }
27
+
28
+ return primitiveSample ?? null;
29
+ };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * React/HTML equivalent of the Nunjucks `nl2br` filter used by Unlayer's
3
+ * `{{ field | safe | nl2br }}` template. Replaces every `\r\n` or `\n` with `<br />\n`,
4
+ * keeping the original newline so the rendered HTML source still wraps in dev tools.
5
+ */
6
+ export const nl2br = (value: string): string => {
7
+ return value.replace(/\r\n|\n/g, '<br />\n');
8
+ };