@qwickapps/react-framework 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -1
- package/dist/components/AccessibilityProvider.d.ts +64 -0
- package/dist/components/AccessibilityProvider.d.ts.map +1 -0
- package/dist/components/Breadcrumbs.d.ts +39 -0
- package/dist/components/Breadcrumbs.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +39 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/QwickApp.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.bundled.css +12 -0
- package/dist/index.esm.js +910 -44
- package/dist/index.js +916 -47
- package/dist/templates/TemplateResolver.d.ts.map +1 -1
- package/dist/utils/htmlTransform.d.ts.map +1 -1
- package/dist/utils/logger.d.ts +15 -3
- package/dist/utils/logger.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/components/AccessibilityProvider.tsx +466 -0
- package/src/components/Breadcrumbs.tsx +223 -0
- package/src/components/ErrorBoundary.tsx +216 -0
- package/src/components/QwickApp.tsx +17 -11
- package/src/components/__tests__/AccessibilityProvider.test.tsx +330 -0
- package/src/components/__tests__/Breadcrumbs.test.tsx +268 -0
- package/src/components/__tests__/ErrorBoundary.test.tsx +163 -0
- package/src/components/index.ts +3 -0
- package/src/stories/AccessibilityProvider.stories.tsx +284 -0
- package/src/stories/Breadcrumbs.stories.tsx +304 -0
- package/src/stories/ErrorBoundary.stories.tsx +159 -0
- package/src/stories/{form/FormComponents.stories.tsx → FormComponents.stories.tsx} +8 -8
- package/src/templates/TemplateResolver.ts +2 -6
- package/src/utils/__tests__/nested-dom-fix.test.tsx +53 -0
- package/src/utils/__tests__/optional-logging.test.ts +83 -0
- package/src/utils/htmlTransform.tsx +69 -3
- package/src/utils/logger.ts +60 -5
- package/dist/schemas/Builders.d.ts +0 -7
- package/dist/schemas/Builders.d.ts.map +0 -1
- package/dist/schemas/types.d.ts +0 -7
- package/dist/schemas/types.d.ts.map +0 -1
- package/dist/types/DataBinding.d.ts +0 -7
- package/dist/types/DataBinding.d.ts.map +0 -1
- package/dist/types/DataProvider.d.ts +0 -7
- package/dist/types/DataProvider.d.ts.map +0 -1
|
@@ -179,6 +179,26 @@ export const defaultMarkdownRules: TransformRule[] = [
|
|
|
179
179
|
}
|
|
180
180
|
];
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Parse style string into React style object
|
|
184
|
+
*/
|
|
185
|
+
function parseStyleString(styleStr: string): React.CSSProperties {
|
|
186
|
+
const styles: React.CSSProperties = {};
|
|
187
|
+
|
|
188
|
+
if (!styleStr) return styles;
|
|
189
|
+
|
|
190
|
+
styleStr.split(';').forEach(declaration => {
|
|
191
|
+
const [property, value] = declaration.split(':').map(s => s.trim());
|
|
192
|
+
if (property && value) {
|
|
193
|
+
// Convert kebab-case to camelCase
|
|
194
|
+
const camelProperty = property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
195
|
+
styles[camelProperty as keyof React.CSSProperties] = value;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
return styles;
|
|
200
|
+
}
|
|
201
|
+
|
|
182
202
|
/**
|
|
183
203
|
* Default fallback component - renders element as-is with SafeSpan content
|
|
184
204
|
*/
|
|
@@ -191,13 +211,18 @@ export const defaultFallback = (element: Element, key: string): React.ReactNode
|
|
|
191
211
|
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
|
192
212
|
]);
|
|
193
213
|
|
|
214
|
+
// Handle style attribute separately to convert to object
|
|
215
|
+
const styleAttr = element.getAttribute('style');
|
|
216
|
+
const style = styleAttr ? parseStyleString(styleAttr) : undefined;
|
|
217
|
+
|
|
194
218
|
const props = {
|
|
195
219
|
key,
|
|
196
220
|
...(element.className ? { className: element.className } : {}),
|
|
197
221
|
...(element.id ? { id: element.id } : {}),
|
|
222
|
+
...(style ? { style } : {}),
|
|
198
223
|
...Object.fromEntries(
|
|
199
224
|
Array.from(element.attributes)
|
|
200
|
-
.filter(attr => !['class', 'id'].includes(attr.name))
|
|
225
|
+
.filter(attr => !['class', 'id', 'style'].includes(attr.name))
|
|
201
226
|
.map(attr => [attr.name, attr.value])
|
|
202
227
|
)
|
|
203
228
|
};
|
|
@@ -257,15 +282,20 @@ export function transformElement(
|
|
|
257
282
|
transformElement(child, `${key}-${index}`, config)
|
|
258
283
|
);
|
|
259
284
|
|
|
285
|
+
// Handle style attribute separately to convert to object
|
|
286
|
+
const styleAttr = element.getAttribute('style');
|
|
287
|
+
const style = styleAttr ? parseStyleString(styleAttr) : undefined;
|
|
288
|
+
|
|
260
289
|
return React.createElement(
|
|
261
290
|
tagName,
|
|
262
291
|
{
|
|
263
292
|
key,
|
|
264
293
|
...(element.className ? { className: element.className } : {}),
|
|
265
294
|
...(element.id ? { id: element.id } : {}),
|
|
295
|
+
...(style ? { style } : {}),
|
|
266
296
|
...Object.fromEntries(
|
|
267
297
|
Array.from(element.attributes)
|
|
268
|
-
.filter(attr => !['class', 'id'].includes(attr.name))
|
|
298
|
+
.filter(attr => !['class', 'id', 'style'].includes(attr.name))
|
|
269
299
|
.map(attr => [attr.name, attr.value])
|
|
270
300
|
)
|
|
271
301
|
},
|
|
@@ -277,6 +307,39 @@ export function transformElement(
|
|
|
277
307
|
return fallbackComponent(element, key);
|
|
278
308
|
}
|
|
279
309
|
|
|
310
|
+
/**
|
|
311
|
+
* Clean up invalid DOM nesting that can cause React errors
|
|
312
|
+
*/
|
|
313
|
+
function cleanupInvalidNesting(html: string): string {
|
|
314
|
+
const parser = new DOMParser();
|
|
315
|
+
const doc = parser.parseFromString(html, 'text/html');
|
|
316
|
+
|
|
317
|
+
// Find paragraphs that contain block-level elements (invalid nesting)
|
|
318
|
+
const paragraphs = doc.querySelectorAll('p');
|
|
319
|
+
const blockElements = ['div', 'section', 'article', 'aside', 'header', 'footer', 'nav', 'main', 'figure', 'blockquote', 'pre', 'table', 'form', 'fieldset', 'address'];
|
|
320
|
+
|
|
321
|
+
paragraphs.forEach(p => {
|
|
322
|
+
const hasBlockChildren = Array.from(p.children).some(child =>
|
|
323
|
+
blockElements.includes(child.tagName.toLowerCase())
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
if (hasBlockChildren) {
|
|
327
|
+
// Convert paragraph to div to allow block children
|
|
328
|
+
const div = doc.createElement('div');
|
|
329
|
+
div.innerHTML = p.innerHTML;
|
|
330
|
+
|
|
331
|
+
// Copy attributes
|
|
332
|
+
Array.from(p.attributes).forEach(attr => {
|
|
333
|
+
div.setAttribute(attr.name, attr.value);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
p.parentNode?.replaceChild(div, p);
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
return doc.body.innerHTML;
|
|
341
|
+
}
|
|
342
|
+
|
|
280
343
|
/**
|
|
281
344
|
* Transform HTML string to React components
|
|
282
345
|
*/
|
|
@@ -286,8 +349,11 @@ export function transformHtmlToReact(
|
|
|
286
349
|
): React.ReactNode[] {
|
|
287
350
|
if (!html.trim()) return [];
|
|
288
351
|
|
|
352
|
+
// Clean up invalid DOM nesting first
|
|
353
|
+
const cleanHtml = cleanupInvalidNesting(html);
|
|
354
|
+
|
|
289
355
|
const parser = new DOMParser();
|
|
290
|
-
const doc = parser.parseFromString(
|
|
356
|
+
const doc = parser.parseFromString(cleanHtml, 'text/html');
|
|
291
357
|
|
|
292
358
|
return Array.from(doc.body.children).map((element, index) =>
|
|
293
359
|
transformElement(element, index.toString(), config)
|
package/src/utils/logger.ts
CHANGED
|
@@ -1,16 +1,71 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* QwickApps React Framework - Logger Utility
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Optional logging with fallback to console when @qwickapps/logging is not available
|
|
5
5
|
*
|
|
6
6
|
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
export interface Logger {
|
|
10
|
+
debug(message: string, ...args: any[]): void;
|
|
11
|
+
info(message: string, ...args: any[]): void;
|
|
12
|
+
warn(message: string, ...args: any[]): void;
|
|
13
|
+
error(message: string, ...args: any[]): void;
|
|
14
|
+
}
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Console-based logger fallback
|
|
18
|
+
*/
|
|
19
|
+
class ConsoleLogger implements Logger {
|
|
20
|
+
constructor(private name: string) {}
|
|
21
|
+
|
|
22
|
+
debug(message: string, ...args: any[]): void {
|
|
23
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
24
|
+
console.debug(`[${this.name}] ${message}`, ...args);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
info(message: string, ...args: any[]): void {
|
|
29
|
+
console.info(`[${this.name}] ${message}`, ...args);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
warn(message: string, ...args: any[]): void {
|
|
33
|
+
console.warn(`[${this.name}] ${message}`, ...args);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
error(message: string, ...args: any[]): void {
|
|
37
|
+
console.error(`[${this.name}] ${message}`, ...args);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* No-op logger for when logging should be disabled
|
|
43
|
+
*/
|
|
44
|
+
class NoOpLogger implements Logger {
|
|
45
|
+
debug(): void {}
|
|
46
|
+
info(): void {}
|
|
47
|
+
warn(): void {}
|
|
48
|
+
error(): void {}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create logger with optional @qwickapps/logging dependency
|
|
53
|
+
*/
|
|
54
|
+
function createLogger(name: string): Logger {
|
|
55
|
+
try {
|
|
56
|
+
// Try to use @qwickapps/logging if available
|
|
57
|
+
const logging = require('@qwickapps/logging');
|
|
58
|
+
return logging.createLogger(name);
|
|
59
|
+
} catch {
|
|
60
|
+
// Fallback to console-based logger
|
|
61
|
+
return new ConsoleLogger(name);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Re-export Logger type and createLogger function for compatibility
|
|
67
|
+
*/
|
|
68
|
+
export { createLogger };
|
|
14
69
|
|
|
15
70
|
/**
|
|
16
71
|
* Framework-specific loggers
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema builders - Re-exported from @qwickapps/schema
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Import directly from '@qwickapps/schema' instead
|
|
5
|
-
*/
|
|
6
|
-
export { FieldBuilder, SchemaBuilder, ModelBuilder, createSchema, field, model, Fields } from '@qwickapps/schema';
|
|
7
|
-
//# sourceMappingURL=Builders.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Builders.d.ts","sourceRoot":"","sources":["../../src/schemas/Builders.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,KAAK,EACL,MAAM,EACP,MAAM,mBAAmB,CAAC"}
|
package/dist/schemas/types.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Schema types - Re-exported from @qwickapps/schema
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Import directly from '@qwickapps/schema' instead
|
|
5
|
-
*/
|
|
6
|
-
export { Schema, Model, FieldDefinition, DataType, FieldType, ValidationRules, EditorConfig } from '@qwickapps/schema';
|
|
7
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schemas/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,MAAM,EACN,KAAK,EACL,eAAe,EACf,QAAQ,EACR,SAAS,EACT,eAAe,EACf,YAAY,EACb,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Data binding types - Re-exported from @qwickapps/schema
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Import directly from '@qwickapps/schema' instead
|
|
5
|
-
*/
|
|
6
|
-
export { DataBindingProps, DataBindingMeta, DataBindingOptions, WithDataBinding, DataBindingResult } from '@qwickapps/schema';
|
|
7
|
-
//# sourceMappingURL=DataBinding.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DataBinding.d.ts","sourceRoot":"","sources":["../../src/types/DataBinding.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EAClB,MAAM,mBAAmB,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Data provider interface - Re-exported from @qwickapps/schema
|
|
3
|
-
*
|
|
4
|
-
* @deprecated Import directly from '@qwickapps/schema' instead
|
|
5
|
-
*/
|
|
6
|
-
export { IDataProvider, DataResponse, ModelInstance, SelectOptions } from '@qwickapps/schema';
|
|
7
|
-
//# sourceMappingURL=DataProvider.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DataProvider.d.ts","sourceRoot":"","sources":["../../src/types/DataProvider.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|