@lateralus-ai/shipping-ui 1.1.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/DocumentEditor/DocumentEditor.d.ts +4 -0
- package/dist/components/DocumentEditor/index.d.ts +1 -0
- package/dist/components/ModalPanel.d.ts +4 -0
- package/dist/components/PdfViewer/ImageViewer.d.ts +1 -1
- package/dist/components/PdfViewer/PdfViewer.d.ts +1 -1
- package/dist/components/PdfViewer/usePageManagement.d.ts +5 -1
- package/dist/components/SearchModal.d.ts +24 -0
- package/dist/components/Tabs.d.ts +13 -0
- package/dist/components/icons/SettingsIcon.d.ts +3 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/defect-report.pdf +0 -0
- package/dist/example.pdf +0 -0
- package/dist/index.cjs +272 -10
- package/dist/index.esm.js +35960 -1124
- package/dist/material-theme.d.ts +26 -0
- package/dist/sample-document.docx +0 -0
- package/dist/stories/SearchModal.d.ts +1 -0
- package/dist/style.css +1 -0
- package/dist/tailwind-theme.d.ts +12 -0
- package/dist/types/documentEditor.d.ts +47 -0
- package/dist/utils/checkboxModule.d.ts +54 -0
- package/package.json +5 -1
- package/src/components/DocumentEditor/DocumentEditor.tsx +872 -0
- package/src/components/DocumentEditor/index.ts +1 -0
- package/src/components/ModalPanel.tsx +13 -0
- package/src/components/PdfViewer/ImageViewer.tsx +8 -3
- package/src/components/PdfViewer/PdfViewer.tsx +138 -17
- package/src/components/PdfViewer/usePageManagement.ts +22 -7
- package/src/components/SearchModal.tsx +320 -0
- package/src/components/Tabs.tsx +43 -0
- package/src/components/icons/SettingsIcon.tsx +33 -0
- package/src/components/index.ts +2 -0
- package/src/material-theme.ts +30 -0
- package/src/stories/DocumentEditor.stories.tsx +287 -0
- package/src/stories/ModalHeader.stories.tsx +36 -0
- package/src/stories/PDFViewer.stories.tsx +1 -1
- package/src/stories/SearchModal.stories.tsx +132 -0
- package/src/stories/SearchModal.tsx +82 -0
- package/src/stories/Tabs.stories.tsx +51 -0
- package/src/styles/tabs.css +55 -0
- package/src/tailwind-theme.ts +12 -0
- package/src/types/documentEditor.ts +56 -0
- package/src/utils/checkboxModule.ts +242 -0
package/src/tailwind-theme.ts
CHANGED
|
@@ -93,6 +93,18 @@ export const theme = {
|
|
|
93
93
|
"accordion-up": "accordion-up 0.2s ease-out",
|
|
94
94
|
},
|
|
95
95
|
colors: {
|
|
96
|
+
brand: {
|
|
97
|
+
50: "#e0fff2",
|
|
98
|
+
100: "#adf0d3",
|
|
99
|
+
200: "#8aeac1",
|
|
100
|
+
300: "#67e4ae",
|
|
101
|
+
400: "#45de9c",
|
|
102
|
+
500: "#26d489",
|
|
103
|
+
600: "#1da56a",
|
|
104
|
+
700: "#15754c",
|
|
105
|
+
800: "#0c452d",
|
|
106
|
+
900: "#04160e",
|
|
107
|
+
},
|
|
96
108
|
gray: {
|
|
97
109
|
50: "#fafafa",
|
|
98
110
|
100: "#f0f0f0",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Type definitions for Document Editor components
|
|
2
|
+
|
|
3
|
+
export interface SchemaProperty {
|
|
4
|
+
type: "string" | "boolean" | "number" | "integer";
|
|
5
|
+
enum?: string[];
|
|
6
|
+
format?: "date" | "date-time" | string;
|
|
7
|
+
description?: string;
|
|
8
|
+
title?: string;
|
|
9
|
+
"ui:widget"?: string;
|
|
10
|
+
"ui:rows"?: number;
|
|
11
|
+
docx_mapping?: DocxMapping;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DocxMapping {
|
|
15
|
+
type: "checkbox" | "radio" | "text";
|
|
16
|
+
name?: string;
|
|
17
|
+
true_name?: string;
|
|
18
|
+
false_name?: string;
|
|
19
|
+
mapping?: RadioMapping[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface RadioMapping {
|
|
23
|
+
name: string;
|
|
24
|
+
value: string | boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface Schema {
|
|
28
|
+
type: string;
|
|
29
|
+
properties: Record<string, SchemaProperty>;
|
|
30
|
+
required?: string[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface CheckboxModuleOptions {
|
|
34
|
+
checkboxData?: Record<string, boolean>;
|
|
35
|
+
schema?: Schema;
|
|
36
|
+
finalGeneration?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface DocumentEditorProps {
|
|
40
|
+
docxUrl: string;
|
|
41
|
+
schema: Schema;
|
|
42
|
+
onDataChange?: (data: Record<string, any>) => void;
|
|
43
|
+
initialData?: Record<string, any>;
|
|
44
|
+
onSaveRef?: React.MutableRefObject<(() => void) | null>;
|
|
45
|
+
readonly?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface DocxtemplaterPart {
|
|
49
|
+
value?: string;
|
|
50
|
+
[key: string]: any;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface DocxtemplaterOptions {
|
|
54
|
+
contentType?: string;
|
|
55
|
+
[key: string]: any;
|
|
56
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CheckboxModuleOptions,
|
|
3
|
+
Schema,
|
|
4
|
+
DocxtemplaterPart,
|
|
5
|
+
DocxtemplaterOptions,
|
|
6
|
+
} from "../types/documentEditor";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* CheckboxModule for docxtemplater
|
|
10
|
+
*
|
|
11
|
+
* This module handles three distinct checkbox patterns in DOCX documents:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Single Checkbox Pattern**: A field maps to a single checkbox
|
|
14
|
+
* - Schema: `docx_mapping: { type: "checkbox", name: "Check1" }`
|
|
15
|
+
* - Maps boolean field value directly to checkbox state
|
|
16
|
+
*
|
|
17
|
+
* 2. **Dual Checkbox Pattern**: Yes/No checkboxes for a single field
|
|
18
|
+
* - Schema: `docx_mapping: { type: "checkbox", true_name: "Check1", false_name: "Check2" }`
|
|
19
|
+
* - true_name checkbox checked when field is true
|
|
20
|
+
* - false_name checkbox checked when field is false
|
|
21
|
+
* - Used for Yes/No questions where both options have checkboxes
|
|
22
|
+
*
|
|
23
|
+
* 3. **Radio Button Pattern**: Multiple checkboxes acting as radio buttons
|
|
24
|
+
* - Schema: `docx_mapping: { type: "radio", mapping: [{ name: "Check1", value: "option1" }, ...] }`
|
|
25
|
+
* - Only the checkbox corresponding to the field's value is checked
|
|
26
|
+
* - Used for multiple choice questions
|
|
27
|
+
*
|
|
28
|
+
* The module operates in two modes:
|
|
29
|
+
* - **Preview Mode** (finalGeneration: false): Creates visual markers for inline editing
|
|
30
|
+
* - **Final Generation Mode** (finalGeneration: true): Updates actual Word form fields
|
|
31
|
+
*/
|
|
32
|
+
class CheckboxModule {
|
|
33
|
+
private checkboxData: Record<string, boolean>;
|
|
34
|
+
private schema?: Schema;
|
|
35
|
+
private finalGeneration: boolean;
|
|
36
|
+
|
|
37
|
+
constructor(options: CheckboxModuleOptions = {}) {
|
|
38
|
+
this.checkboxData = options.checkboxData || {};
|
|
39
|
+
this.schema = options.schema;
|
|
40
|
+
this.finalGeneration = options.finalGeneration || false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Required docxtemplater module interface
|
|
44
|
+
name = "CheckboxModule";
|
|
45
|
+
|
|
46
|
+
parse(placeHolderContent: string) {
|
|
47
|
+
// Return null to indicate this module doesn't handle this placeholder
|
|
48
|
+
// This allows other modules/default processing to handle it
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
postparse(parsed: any) {
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
render(part: any, options: any) {
|
|
57
|
+
return part;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
postrender(parts: DocxtemplaterPart[], options: DocxtemplaterOptions) {
|
|
61
|
+
const hasValidOptions = !!(
|
|
62
|
+
options &&
|
|
63
|
+
options.contentType &&
|
|
64
|
+
options.contentType ===
|
|
65
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
return !hasValidOptions ? parts : (() => {
|
|
69
|
+
try {
|
|
70
|
+
// Convert parts to string for processing
|
|
71
|
+
const xmlContent = parts
|
|
72
|
+
.map((part) => {
|
|
73
|
+
const isString = typeof part === "string";
|
|
74
|
+
const hasValue = part && typeof part === "object" && part.value;
|
|
75
|
+
|
|
76
|
+
const getString = () => isString && part;
|
|
77
|
+
const getValue = () => !isString && hasValue && part.value;
|
|
78
|
+
const getStringified = () => !isString && !hasValue && String(part);
|
|
79
|
+
|
|
80
|
+
return getString() || getValue() || getStringified();
|
|
81
|
+
})
|
|
82
|
+
.join("");
|
|
83
|
+
|
|
84
|
+
// Process checkbox patterns
|
|
85
|
+
const processedContent = this.processCheckboxPatterns(xmlContent);
|
|
86
|
+
|
|
87
|
+
// Return the processed content maintaining the same structure as input
|
|
88
|
+
return [processedContent];
|
|
89
|
+
} catch (error) {
|
|
90
|
+
// Return original parts if processing fails
|
|
91
|
+
return parts;
|
|
92
|
+
}
|
|
93
|
+
})();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Process checkbox patterns in the document XML
|
|
98
|
+
* Identifies Word form field checkboxes by their bookmark names (Check1, Check2, etc.)
|
|
99
|
+
* and either updates their values or replaces them with visual markers
|
|
100
|
+
*/
|
|
101
|
+
private processCheckboxPatterns(xmlContent: string): string {
|
|
102
|
+
try {
|
|
103
|
+
// Pattern 1: Simple checkbox bookmarks (most conservative approach)
|
|
104
|
+
// Matches: <w:bookmarkStart w:name="Check1" w:id="0"/>
|
|
105
|
+
const simpleBookmarkRegex =
|
|
106
|
+
/<w:bookmarkStart[^>]*w:name="(Check\d+)"[^>]*\/>/gi;
|
|
107
|
+
|
|
108
|
+
// Reset regex
|
|
109
|
+
simpleBookmarkRegex.lastIndex = 0;
|
|
110
|
+
|
|
111
|
+
const checkboxMatches: string[] = [];
|
|
112
|
+
let match;
|
|
113
|
+
while ((match = simpleBookmarkRegex.exec(xmlContent)) !== null) {
|
|
114
|
+
checkboxMatches.push(match[1]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Only process if we found actual checkbox bookmarks
|
|
118
|
+
const hasCheckboxMatches = checkboxMatches.length > 0;
|
|
119
|
+
|
|
120
|
+
return !hasCheckboxMatches ? xmlContent : (() => {
|
|
121
|
+
const processForFinalGeneration = () => {
|
|
122
|
+
// For final generation, update the checkbox default values directly in the XML
|
|
123
|
+
checkboxMatches.forEach((checkboxName) => {
|
|
124
|
+
const isChecked = this.getCheckboxState(checkboxName);
|
|
125
|
+
const checkedValue = isChecked ? "1" : "0";
|
|
126
|
+
|
|
127
|
+
// Update the default value in the checkbox XML
|
|
128
|
+
const checkboxRegex = new RegExp(
|
|
129
|
+
`(<w:fldChar w:fldCharType="begin">.*?<w:name w:val="${checkboxName}".*?<w:default w:val=")([01])(".*?</w:fldChar>)`,
|
|
130
|
+
"gs",
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
xmlContent = xmlContent.replace(checkboxRegex, `$1${checkedValue}$3`);
|
|
134
|
+
});
|
|
135
|
+
return xmlContent;
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
const processForPreview = () => {
|
|
139
|
+
// For preview mode, create visual markers
|
|
140
|
+
// Reset regex for replacement
|
|
141
|
+
simpleBookmarkRegex.lastIndex = 0;
|
|
142
|
+
|
|
143
|
+
return xmlContent.replace(
|
|
144
|
+
simpleBookmarkRegex,
|
|
145
|
+
(match, checkboxName) => {
|
|
146
|
+
try {
|
|
147
|
+
const isChecked = this.getCheckboxState(checkboxName);
|
|
148
|
+
const symbol = isChecked ? "☑" : "☐";
|
|
149
|
+
const marker = `|||${symbol}|||checkbox:${checkboxName}|||`;
|
|
150
|
+
|
|
151
|
+
// Replace just the bookmark start with our marker in a text run
|
|
152
|
+
return `<w:r><w:t>${marker}</w:t></w:r><w:bookmarkStart w:name="${checkboxName}" w:id="0"/>`;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
// Return original if processing fails
|
|
155
|
+
return match;
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const renderFinalGeneration = () => this.finalGeneration && processForFinalGeneration();
|
|
162
|
+
const renderPreview = () => !this.finalGeneration && processForPreview();
|
|
163
|
+
|
|
164
|
+
return renderFinalGeneration() || renderPreview();
|
|
165
|
+
})();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
// Return original content if processing fails
|
|
168
|
+
return xmlContent;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Determine the state of a checkbox based on field mappings and data
|
|
174
|
+
* @param checkboxName - The name of the checkbox (e.g., "Check1")
|
|
175
|
+
* @returns true if checkbox should be checked, false otherwise
|
|
176
|
+
*/
|
|
177
|
+
private getCheckboxState(checkboxName: string): boolean {
|
|
178
|
+
const hasSchema = !!this.schema;
|
|
179
|
+
|
|
180
|
+
const getSimpleLookup = () => !hasSchema && (this.checkboxData[checkboxName] || false);
|
|
181
|
+
const getSchemaBasedLookup = () => hasSchema && (() => {
|
|
182
|
+
// Check all fields in the schema for checkbox mappings
|
|
183
|
+
const matchedField = Object.entries(
|
|
184
|
+
this.schema!.properties || {},
|
|
185
|
+
).find(([fieldName, fieldConfig]) => {
|
|
186
|
+
const config = fieldConfig as any;
|
|
187
|
+
const docxMapping = config.docx_mapping;
|
|
188
|
+
const hasCheckboxMapping = docxMapping && docxMapping.type === "checkbox";
|
|
189
|
+
const hasRadioMapping = docxMapping && docxMapping.type === "radio" && docxMapping.mapping;
|
|
190
|
+
|
|
191
|
+
// Pattern 1: Single checkbox with "name" property
|
|
192
|
+
const isSingleCheckbox = hasCheckboxMapping && docxMapping.name === checkboxName;
|
|
193
|
+
|
|
194
|
+
// Pattern 2: Dual checkbox with "true_name" and "false_name" properties
|
|
195
|
+
const isTrueCheckbox = hasCheckboxMapping && docxMapping.true_name === checkboxName;
|
|
196
|
+
const isFalseCheckbox = hasCheckboxMapping && docxMapping.false_name === checkboxName;
|
|
197
|
+
|
|
198
|
+
// Pattern 3: Radio button mapping
|
|
199
|
+
const radioMapping = hasRadioMapping && docxMapping.mapping.find(
|
|
200
|
+
(m: any) => m.name === checkboxName,
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return isSingleCheckbox || isTrueCheckbox || isFalseCheckbox || !!radioMapping;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return matchedField ? (() => {
|
|
207
|
+
const [fieldName, fieldConfig] = matchedField;
|
|
208
|
+
const config = fieldConfig as any;
|
|
209
|
+
const docxMapping = config.docx_mapping;
|
|
210
|
+
|
|
211
|
+
// Pattern 1: Single checkbox with "name" property
|
|
212
|
+
const isSingleCheckbox = docxMapping && docxMapping.type === "checkbox" && docxMapping.name === checkboxName;
|
|
213
|
+
|
|
214
|
+
// Pattern 2: Dual checkbox with "true_name" and "false_name" properties
|
|
215
|
+
const isTrueCheckbox = docxMapping && docxMapping.type === "checkbox" && docxMapping.true_name === checkboxName;
|
|
216
|
+
const isFalseCheckbox = docxMapping && docxMapping.type === "checkbox" && docxMapping.false_name === checkboxName;
|
|
217
|
+
|
|
218
|
+
// Pattern 3: Radio button mapping
|
|
219
|
+
const radioMapping = docxMapping && docxMapping.type === "radio" && docxMapping.mapping &&
|
|
220
|
+
docxMapping.mapping.find((m: any) => m.name === checkboxName);
|
|
221
|
+
|
|
222
|
+
const checkSingleOrTrue = () => (isSingleCheckbox || isTrueCheckbox) && this.checkboxData[fieldName] === true;
|
|
223
|
+
const checkFalse = () => isFalseCheckbox && this.checkboxData[fieldName] === false;
|
|
224
|
+
const checkRadio = () => radioMapping && this.checkboxData[fieldName] === radioMapping.value;
|
|
225
|
+
|
|
226
|
+
return checkSingleOrTrue() || checkFalse() || checkRadio() || false;
|
|
227
|
+
})() : (this.checkboxData[checkboxName] || false);
|
|
228
|
+
})();
|
|
229
|
+
|
|
230
|
+
return getSimpleLookup() || getSchemaBasedLookup() || false;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Update checkbox data (can be called to change checkbox states)
|
|
235
|
+
* @param checkboxData - New checkbox data to merge with existing data
|
|
236
|
+
*/
|
|
237
|
+
updateCheckboxData(checkboxData: Record<string, boolean>) {
|
|
238
|
+
this.checkboxData = { ...this.checkboxData, ...checkboxData };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export default CheckboxModule;
|