@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.
Files changed (43) hide show
  1. package/README.md +123 -1
  2. package/dist/components/AccessibilityProvider.d.ts +64 -0
  3. package/dist/components/AccessibilityProvider.d.ts.map +1 -0
  4. package/dist/components/Breadcrumbs.d.ts +39 -0
  5. package/dist/components/Breadcrumbs.d.ts.map +1 -0
  6. package/dist/components/ErrorBoundary.d.ts +39 -0
  7. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  8. package/dist/components/QwickApp.d.ts.map +1 -1
  9. package/dist/components/index.d.ts +3 -0
  10. package/dist/components/index.d.ts.map +1 -1
  11. package/dist/index.bundled.css +12 -0
  12. package/dist/index.esm.js +910 -44
  13. package/dist/index.js +916 -47
  14. package/dist/templates/TemplateResolver.d.ts.map +1 -1
  15. package/dist/utils/htmlTransform.d.ts.map +1 -1
  16. package/dist/utils/logger.d.ts +15 -3
  17. package/dist/utils/logger.d.ts.map +1 -1
  18. package/package.json +4 -2
  19. package/src/components/AccessibilityProvider.tsx +466 -0
  20. package/src/components/Breadcrumbs.tsx +223 -0
  21. package/src/components/ErrorBoundary.tsx +216 -0
  22. package/src/components/QwickApp.tsx +17 -11
  23. package/src/components/__tests__/AccessibilityProvider.test.tsx +330 -0
  24. package/src/components/__tests__/Breadcrumbs.test.tsx +268 -0
  25. package/src/components/__tests__/ErrorBoundary.test.tsx +163 -0
  26. package/src/components/index.ts +3 -0
  27. package/src/stories/AccessibilityProvider.stories.tsx +284 -0
  28. package/src/stories/Breadcrumbs.stories.tsx +304 -0
  29. package/src/stories/ErrorBoundary.stories.tsx +159 -0
  30. package/src/stories/{form/FormComponents.stories.tsx → FormComponents.stories.tsx} +8 -8
  31. package/src/templates/TemplateResolver.ts +2 -6
  32. package/src/utils/__tests__/nested-dom-fix.test.tsx +53 -0
  33. package/src/utils/__tests__/optional-logging.test.ts +83 -0
  34. package/src/utils/htmlTransform.tsx +69 -3
  35. package/src/utils/logger.ts +60 -5
  36. package/dist/schemas/Builders.d.ts +0 -7
  37. package/dist/schemas/Builders.d.ts.map +0 -1
  38. package/dist/schemas/types.d.ts +0 -7
  39. package/dist/schemas/types.d.ts.map +0 -1
  40. package/dist/types/DataBinding.d.ts +0 -7
  41. package/dist/types/DataBinding.d.ts.map +0 -1
  42. package/dist/types/DataProvider.d.ts +0 -7
  43. 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(html, 'text/html');
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)
@@ -1,16 +1,71 @@
1
1
  /**
2
2
  * QwickApps React Framework - Logger Utility
3
3
  *
4
- * Re-exports from @qwickapps/logging with framework-specific loggers
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
- // Re-export everything from the logging package
10
- export * from '@qwickapps/logging';
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
- // Import createLogger and Logger type to create framework-specific loggers
13
- import { createLogger, Logger } from '@qwickapps/logging';
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"}
@@ -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"}