@qwickapps/react-framework 1.3.2 → 1.3.4

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 (66) hide show
  1. package/README.md +326 -0
  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/forms/FormBlock.d.ts +1 -1
  10. package/dist/components/forms/FormBlock.d.ts.map +1 -1
  11. package/dist/components/index.d.ts +3 -0
  12. package/dist/components/index.d.ts.map +1 -1
  13. package/dist/components/input/SwitchInputField.d.ts +28 -0
  14. package/dist/components/input/SwitchInputField.d.ts.map +1 -0
  15. package/dist/components/input/index.d.ts +2 -0
  16. package/dist/components/input/index.d.ts.map +1 -1
  17. package/dist/components/layout/CollapsibleLayout/CollapsibleLayout.d.ts +34 -0
  18. package/dist/components/layout/CollapsibleLayout/CollapsibleLayout.d.ts.map +1 -0
  19. package/dist/components/layout/CollapsibleLayout/index.d.ts +9 -0
  20. package/dist/components/layout/CollapsibleLayout/index.d.ts.map +1 -0
  21. package/dist/components/layout/index.d.ts +2 -0
  22. package/dist/components/layout/index.d.ts.map +1 -1
  23. package/dist/index.bundled.css +12 -0
  24. package/dist/index.esm.js +1678 -25
  25. package/dist/index.js +1689 -21
  26. package/dist/schemas/CollapsibleLayoutSchema.d.ts +31 -0
  27. package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -0
  28. package/dist/schemas/SwitchInputFieldSchema.d.ts +18 -0
  29. package/dist/schemas/SwitchInputFieldSchema.d.ts.map +1 -0
  30. package/dist/types/CollapsibleLayout.d.ts +142 -0
  31. package/dist/types/CollapsibleLayout.d.ts.map +1 -0
  32. package/dist/types/index.d.ts +1 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/AccessibilityProvider.tsx +466 -0
  36. package/src/components/Breadcrumbs.tsx +223 -0
  37. package/src/components/ErrorBoundary.tsx +216 -0
  38. package/src/components/QwickApp.tsx +17 -11
  39. package/src/components/__tests__/AccessibilityProvider.test.tsx +330 -0
  40. package/src/components/__tests__/Breadcrumbs.test.tsx +268 -0
  41. package/src/components/__tests__/ErrorBoundary.test.tsx +163 -0
  42. package/src/components/forms/FormBlock.tsx +2 -2
  43. package/src/components/index.ts +3 -0
  44. package/src/components/input/SwitchInputField.tsx +165 -0
  45. package/src/components/input/index.ts +2 -0
  46. package/src/components/layout/CollapsibleLayout/CollapsibleLayout.tsx +554 -0
  47. package/src/components/layout/CollapsibleLayout/__tests__/CollapsibleLayout.test.tsx +1469 -0
  48. package/src/components/layout/CollapsibleLayout/index.tsx +17 -0
  49. package/src/components/layout/index.ts +4 -1
  50. package/src/components/pages/FormPage.tsx +1 -1
  51. package/src/schemas/CollapsibleLayoutSchema.ts +276 -0
  52. package/src/schemas/SwitchInputFieldSchema.ts +99 -0
  53. package/src/stories/AccessibilityProvider.stories.tsx +284 -0
  54. package/src/stories/Breadcrumbs.stories.tsx +304 -0
  55. package/src/stories/CollapsibleLayout.stories.tsx +1566 -0
  56. package/src/stories/ErrorBoundary.stories.tsx +159 -0
  57. package/src/types/CollapsibleLayout.ts +231 -0
  58. package/src/types/index.ts +1 -0
  59. package/dist/schemas/Builders.d.ts +0 -7
  60. package/dist/schemas/Builders.d.ts.map +0 -1
  61. package/dist/schemas/types.d.ts +0 -7
  62. package/dist/schemas/types.d.ts.map +0 -1
  63. package/dist/types/DataBinding.d.ts +0 -7
  64. package/dist/types/DataBinding.d.ts.map +0 -1
  65. package/dist/types/DataProvider.d.ts +0 -7
  66. package/dist/types/DataProvider.d.ts.map +0 -1
package/dist/index.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
- import { CircularProgress, Button as Button$1, Paper, Typography, useTheme as useTheme$1, Box, Container as Container$8, Stack, Tooltip, IconButton, Snackbar, Alert, useMediaQuery, Avatar, Chip, Menu, MenuItem, Grid, Divider, Link, ListItemIcon, ListItemText, Card, CardContent, ButtonGroup, Collapse, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText } from '@mui/material';
3
- import React, { useMemo, useContext, useState, useEffect, createContext, useRef, useCallback, cloneElement } from 'react';
2
+ import { CircularProgress, Button as Button$1, Paper, Typography, useTheme as useTheme$1, Box, Container as Container$8, Stack, Tooltip, IconButton, Snackbar, Alert, useMediaQuery, Avatar, Chip, Menu, MenuItem, Grid, Divider, Collapse, Link, ListItemIcon, ListItemText, Card, CardContent, ButtonGroup, TextField as TextField$1, FormControl, InputLabel, Select, FormHelperText, FormControlLabel, Switch } from '@mui/material';
3
+ import React, { useMemo, useContext, useState, useEffect, createContext, useId, useCallback, useRef, Component, useReducer, cloneElement } from 'react';
4
4
  import { MustacheTemplateProvider, MemoryCacheProvider, CachedDataProvider, Field, Editor, FieldType, Schema, Model, DataType } from '@qwickapps/schema';
5
5
  import { IsOptional, IsString, IsIn, IsUrl, IsArray, ValidateNested, IsNumber, Min, Max, IsBoolean, IsNotEmpty, IsObject } from 'class-validator';
6
6
  import { Type } from 'class-transformer';
7
7
  import 'reflect-metadata';
8
- import { Check, ContentCopy, MoreVert, Schedule, Visibility, Launch, LightMode, DarkMode, SettingsSystemDaydream, Palette, Circle, VisibilityOff, Help, FormatBold, FormatItalic, FormatUnderlined, Code as Code$1, Add, RadioButtonUnchecked } from '@mui/icons-material';
8
+ import { Check, ContentCopy, MoreVert, ExpandMore, ExpandLess, Schedule, Visibility, Launch, LightMode, DarkMode, SettingsSystemDaydream, Palette, Circle, VisibilityOff, Help, FormatBold, FormatItalic, FormatUnderlined, Code as Code$1, Add, RadioButtonUnchecked } from '@mui/icons-material';
9
9
  import { createTheme, ThemeProvider as ThemeProvider$1 } from '@mui/material/styles';
10
10
  import { useLocation, useNavigate } from 'react-router-dom';
11
11
 
@@ -15334,6 +15334,689 @@ const GridCell = props => {
15334
15334
  };
15335
15335
  GridCell.displayName = 'GridCell';
15336
15336
 
15337
+ /**
15338
+ * CollapsibleLayout Schema - Data model for collapsible layout component
15339
+ *
15340
+ * Advanced expandable/collapsible container with header controls, animations,
15341
+ * content management, and state persistence capabilities.
15342
+ *
15343
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15344
+ */
15345
+ let CollapsibleLayoutModel = class CollapsibleLayoutModel extends Model {};
15346
+ __decorate([Field({
15347
+ defaultValue: false
15348
+ }), Editor({
15349
+ field_type: FieldType.BOOLEAN,
15350
+ label: 'Collapsed',
15351
+ description: 'Whether the layout is currently collapsed'
15352
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "collapsed", void 0);
15353
+ __decorate([Field({
15354
+ defaultValue: false
15355
+ }), Editor({
15356
+ field_type: FieldType.BOOLEAN,
15357
+ label: 'Default Collapsed',
15358
+ description: 'Initial collapsed state for uncontrolled usage'
15359
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "defaultCollapsed", void 0);
15360
+ __decorate([Field(), Editor({
15361
+ field_type: FieldType.TEXT,
15362
+ label: 'Title',
15363
+ description: 'Main title displayed in the header',
15364
+ placeholder: 'Enter title...'
15365
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "title", void 0);
15366
+ __decorate([Field(), Editor({
15367
+ field_type: FieldType.TEXT,
15368
+ label: 'Subtitle',
15369
+ description: 'Secondary text displayed below the title',
15370
+ placeholder: 'Enter subtitle...'
15371
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "subtitle", void 0);
15372
+ __decorate([Field(), Editor({
15373
+ field_type: FieldType.TEXT,
15374
+ label: 'Lead Icon',
15375
+ description: 'Icon displayed before the title (icon identifier or HTML)',
15376
+ placeholder: 'Icon identifier...'
15377
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "leadIcon", void 0);
15378
+ __decorate([Field(), Editor({
15379
+ field_type: FieldType.TEXTAREA,
15380
+ label: 'Header Actions',
15381
+ description: 'Additional controls displayed in header (HTML/React content)',
15382
+ placeholder: 'Enter header actions HTML...'
15383
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "headerActions", void 0);
15384
+ __decorate([Field(), Editor({
15385
+ field_type: FieldType.TEXTAREA,
15386
+ label: 'Collapsed View',
15387
+ description: 'Summary content shown when collapsed (HTML supported)',
15388
+ placeholder: 'Enter collapsed view content...'
15389
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "collapsedView", void 0);
15390
+ __decorate([Field(), Editor({
15391
+ field_type: FieldType.TEXTAREA,
15392
+ label: 'Content',
15393
+ description: 'Main content shown when expanded (HTML supported)',
15394
+ placeholder: 'Enter main content...'
15395
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "children", void 0);
15396
+ __decorate([Field(), Editor({
15397
+ field_type: FieldType.TEXTAREA,
15398
+ label: 'Footer View',
15399
+ description: 'Always visible footer content (HTML supported)',
15400
+ placeholder: 'Enter footer content...'
15401
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "footerView", void 0);
15402
+ __decorate([Field({
15403
+ defaultValue: 'header'
15404
+ }), Editor({
15405
+ field_type: FieldType.SELECT,
15406
+ label: 'Trigger Area',
15407
+ description: 'Area that responds to clicks for toggle functionality',
15408
+ validation: {
15409
+ options: [{
15410
+ label: 'Button Only',
15411
+ value: 'button'
15412
+ }, {
15413
+ label: 'Header Area',
15414
+ value: 'header'
15415
+ }, {
15416
+ label: 'Button and Header',
15417
+ value: 'both'
15418
+ }]
15419
+ }
15420
+ }), IsOptional(), IsIn(['button', 'header', 'both']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "triggerArea", void 0);
15421
+ __decorate([Field({
15422
+ defaultValue: 'slide'
15423
+ }), Editor({
15424
+ field_type: FieldType.SELECT,
15425
+ label: 'Animation Style',
15426
+ description: 'Animation variant for expand/collapse transitions',
15427
+ validation: {
15428
+ options: [{
15429
+ label: 'Fade',
15430
+ value: 'fade'
15431
+ }, {
15432
+ label: 'Slide',
15433
+ value: 'slide'
15434
+ }, {
15435
+ label: 'Scale',
15436
+ value: 'scale'
15437
+ }]
15438
+ }
15439
+ }), IsOptional(), IsIn(['fade', 'slide', 'scale']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "animationStyle", void 0);
15440
+ __decorate([Field({
15441
+ defaultValue: false
15442
+ }), Editor({
15443
+ field_type: FieldType.BOOLEAN,
15444
+ label: 'Persist State',
15445
+ description: 'Save collapse state in local storage'
15446
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "persistState", void 0);
15447
+ __decorate([Field(), Editor({
15448
+ field_type: FieldType.TEXT,
15449
+ label: 'Collapsed Icon',
15450
+ description: 'Icon shown when content is collapsed (default: VisibilityIcon)',
15451
+ placeholder: 'Icon identifier...'
15452
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "collapsedIcon", void 0);
15453
+ __decorate([Field(), Editor({
15454
+ field_type: FieldType.TEXT,
15455
+ label: 'Expanded Icon',
15456
+ description: 'Icon shown when content is expanded (default: VisibilityOffIcon)',
15457
+ placeholder: 'Icon identifier...'
15458
+ }), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "expandedIcon", void 0);
15459
+ __decorate([Field({
15460
+ defaultValue: true
15461
+ }), Editor({
15462
+ field_type: FieldType.BOOLEAN,
15463
+ label: 'Show Divider',
15464
+ description: 'Show divider lines between header, content, and footer sections'
15465
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "showDivider", void 0);
15466
+ __decorate([Field({
15467
+ defaultValue: 'default'
15468
+ }), Editor({
15469
+ field_type: FieldType.SELECT,
15470
+ label: 'Variant',
15471
+ description: 'Visual style variant for the layout container',
15472
+ validation: {
15473
+ options: [{
15474
+ label: 'Default',
15475
+ value: 'default'
15476
+ }, {
15477
+ label: 'Outlined',
15478
+ value: 'outlined'
15479
+ }, {
15480
+ label: 'Elevated',
15481
+ value: 'elevated'
15482
+ }, {
15483
+ label: 'Filled',
15484
+ value: 'filled'
15485
+ }]
15486
+ }
15487
+ }), IsOptional(), IsIn(['default', 'outlined', 'elevated', 'filled']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "variant", void 0);
15488
+ __decorate([Field({
15489
+ defaultValue: 'comfortable'
15490
+ }), Editor({
15491
+ field_type: FieldType.SELECT,
15492
+ label: 'Header Spacing',
15493
+ description: 'Padding/spacing within the header area',
15494
+ validation: {
15495
+ options: [{
15496
+ label: 'Compact',
15497
+ value: 'compact'
15498
+ }, {
15499
+ label: 'Comfortable',
15500
+ value: 'comfortable'
15501
+ }, {
15502
+ label: 'Spacious',
15503
+ value: 'spacious'
15504
+ }]
15505
+ }
15506
+ }), IsOptional(), IsIn(['compact', 'comfortable', 'spacious']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "headerSpacing", void 0);
15507
+ __decorate([Field({
15508
+ defaultValue: 'comfortable'
15509
+ }), Editor({
15510
+ field_type: FieldType.SELECT,
15511
+ label: 'Content Spacing',
15512
+ description: 'Padding/spacing within the content area',
15513
+ validation: {
15514
+ options: [{
15515
+ label: 'Compact',
15516
+ value: 'compact'
15517
+ }, {
15518
+ label: 'Comfortable',
15519
+ value: 'comfortable'
15520
+ }, {
15521
+ label: 'Spacious',
15522
+ value: 'spacious'
15523
+ }]
15524
+ }
15525
+ }), IsOptional(), IsIn(['compact', 'comfortable', 'spacious']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "contentSpacing", void 0);
15526
+ CollapsibleLayoutModel = __decorate([Schema('CollapsibleLayout', '1.0.0')], CollapsibleLayoutModel);
15527
+ var CollapsibleLayoutModel$1 = CollapsibleLayoutModel;
15528
+
15529
+ /**
15530
+ * TypeScript type definitions for CollapsibleLayout component
15531
+ *
15532
+ * Provides TypeScript interfaces that extend the schema model with React-specific types
15533
+ * and component-level functionality for the CollapsibleLayout component.
15534
+ *
15535
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
15536
+ */
15537
+ /**
15538
+ * Type guard to check if a component has CollapsibleLayout props
15539
+ */
15540
+ function isCollapsibleLayoutProps(props) {
15541
+ return props && typeof props === 'object' && ('collapsed' in props || 'defaultCollapsed' in props);
15542
+ }
15543
+ /**
15544
+ * Default props for CollapsibleLayout component
15545
+ */
15546
+ const defaultCollapsibleLayoutProps = {
15547
+ // Note: collapsed is intentionally omitted so components can be uncontrolled
15548
+ defaultCollapsed: false,
15549
+ triggerArea: 'both',
15550
+ animationStyle: 'slide',
15551
+ persistState: false,
15552
+ showDivider: true,
15553
+ variant: 'default',
15554
+ headerSpacing: 'comfortable',
15555
+ contentSpacing: 'comfortable',
15556
+ animationDuration: 300,
15557
+ disableAnimations: false,
15558
+ toggleAriaLabel: 'Toggle content visibility'
15559
+ };
15560
+ const animationConfigs = {
15561
+ fade: {
15562
+ duration: 300,
15563
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
15564
+ opacity: [0, 1]
15565
+ },
15566
+ slide: {
15567
+ duration: 300,
15568
+ easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
15569
+ transform: 'translateY(-10px)'
15570
+ },
15571
+ scale: {
15572
+ duration: 200,
15573
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
15574
+ transform: 'scale(0.95)',
15575
+ opacity: [0, 1]
15576
+ }
15577
+ };
15578
+ const spacingConfigs = {
15579
+ compact: {
15580
+ padding: '8px 12px',
15581
+ gap: '4px'
15582
+ },
15583
+ comfortable: {
15584
+ padding: '16px 20px',
15585
+ gap: '8px'
15586
+ },
15587
+ spacious: {
15588
+ padding: '24px 32px',
15589
+ gap: '16px'
15590
+ }
15591
+ };
15592
+
15593
+ /**
15594
+ * Custom hook for managing collapsible state - simplified approach
15595
+ */
15596
+ function useCollapsibleState(controlled, collapsedProp, defaultCollapsedProp, onToggleProp, persistState, storageKey) {
15597
+ const id = useId();
15598
+ const finalStorageKey = storageKey || `collapsible-${id}`;
15599
+ // For controlled components, use the prop; for uncontrolled, use internal state
15600
+ const [internalCollapsed, setInternalCollapsed] = useState(() => {
15601
+ if (controlled) {
15602
+ return collapsedProp ?? false;
15603
+ }
15604
+ // Try localStorage first if persistence is enabled
15605
+ if (persistState && typeof window !== 'undefined') {
15606
+ const stored = localStorage.getItem(finalStorageKey);
15607
+ if (stored !== null) {
15608
+ return JSON.parse(stored);
15609
+ }
15610
+ }
15611
+ return defaultCollapsedProp ?? false;
15612
+ });
15613
+ // Sync with controlled prop changes
15614
+ useEffect(() => {
15615
+ if (controlled && collapsedProp !== undefined) {
15616
+ setInternalCollapsed(collapsedProp);
15617
+ }
15618
+ }, [controlled, collapsedProp]);
15619
+ // Persist to localStorage for uncontrolled components
15620
+ useEffect(() => {
15621
+ if (!controlled && persistState && typeof window !== 'undefined') {
15622
+ localStorage.setItem(finalStorageKey, JSON.stringify(internalCollapsed));
15623
+ }
15624
+ }, [controlled, internalCollapsed, persistState, finalStorageKey]);
15625
+ const toggle = useCallback(() => {
15626
+ const currentState = controlled ? collapsedProp ?? false : internalCollapsed;
15627
+ const newCollapsed = !currentState;
15628
+ // Always update internal state for visual updates
15629
+ setInternalCollapsed(newCollapsed);
15630
+ // Call callback to notify parent
15631
+ onToggleProp?.(newCollapsed);
15632
+ }, [controlled, collapsedProp, internalCollapsed, onToggleProp]);
15633
+ const setCollapsed = useCallback(collapsed => {
15634
+ setInternalCollapsed(collapsed);
15635
+ onToggleProp?.(collapsed);
15636
+ }, [onToggleProp]);
15637
+ // Return the appropriate state
15638
+ const finalCollapsed = controlled ? collapsedProp ?? false : internalCollapsed;
15639
+ return {
15640
+ collapsed: finalCollapsed,
15641
+ toggle,
15642
+ setCollapsed,
15643
+ isControlled: controlled
15644
+ };
15645
+ }
15646
+ /**
15647
+ * Core CollapsibleLayout View component
15648
+ */
15649
+ function CollapsibleLayoutView({
15650
+ // State props
15651
+ collapsed: collapsedProp,
15652
+ defaultCollapsed = false,
15653
+ onToggle,
15654
+ // Content props
15655
+ title,
15656
+ subtitle,
15657
+ leadIcon,
15658
+ headerActions,
15659
+ collapsedView,
15660
+ children,
15661
+ footerView,
15662
+ // Behavior props
15663
+ triggerArea = 'both',
15664
+ animationStyle = 'slide',
15665
+ persistState = false,
15666
+ storageKey,
15667
+ animationDuration = 300,
15668
+ disableAnimations = false,
15669
+ // Icons
15670
+ collapsedIcon,
15671
+ expandedIcon,
15672
+ // Layout props
15673
+ showDivider = true,
15674
+ variant = 'default',
15675
+ headerSpacing = 'comfortable',
15676
+ contentSpacing = 'comfortable',
15677
+ // Accessibility
15678
+ toggleAriaLabel = 'Toggle content visibility',
15679
+ 'aria-describedby': ariaDescribedBy,
15680
+ contentAriaProps = {},
15681
+ // CSS classes
15682
+ containerClassName,
15683
+ headerClassName,
15684
+ contentClassName,
15685
+ footerClassName,
15686
+ ...restProps
15687
+ }) {
15688
+ const theme = useTheme$1();
15689
+ const {
15690
+ styleProps,
15691
+ htmlProps,
15692
+ restProps: otherProps
15693
+ } = useBaseProps(restProps);
15694
+ // Mark as QwickApp component
15695
+ CollapsibleLayoutView[QWICKAPP_COMPONENT] = true;
15696
+ // Determine controlled vs uncontrolled usage
15697
+ const controlled = collapsedProp !== undefined;
15698
+ // State management
15699
+ const {
15700
+ collapsed,
15701
+ toggle,
15702
+ setCollapsed
15703
+ } = useCollapsibleState(controlled, collapsedProp, defaultCollapsed, onToggle, persistState, storageKey);
15704
+ // Get spacing configurations
15705
+ const headerSpacingConfig = spacingConfigs[headerSpacing];
15706
+ const contentSpacingConfig = spacingConfigs[contentSpacing];
15707
+ // Get animation configuration
15708
+ const animationConfig = animationConfigs[animationStyle];
15709
+ // Generate unique IDs for accessibility
15710
+ const headerId = useId();
15711
+ const contentId = useId();
15712
+ // Handle click events
15713
+ const handleHeaderClick = useCallback(event => {
15714
+ if (triggerArea === 'header' || triggerArea === 'both') {
15715
+ event.preventDefault();
15716
+ toggle();
15717
+ }
15718
+ }, [triggerArea, toggle]);
15719
+ const handleButtonClick = useCallback(event => {
15720
+ event.stopPropagation();
15721
+ toggle();
15722
+ }, [toggle]);
15723
+ // Render icons
15724
+ const renderIcon = useCallback((icon, defaultIcon) => {
15725
+ if (/*#__PURE__*/React.isValidElement(icon)) {
15726
+ return icon;
15727
+ }
15728
+ if (typeof icon === 'string') {
15729
+ return jsx(Html, {
15730
+ children: icon
15731
+ });
15732
+ }
15733
+ return defaultIcon;
15734
+ }, []);
15735
+ const toggleIcon = renderIcon(collapsed ? collapsedIcon : expandedIcon, collapsed ? jsx(ExpandMore, {}) : jsx(ExpandLess, {}));
15736
+ // Container styles based on variant
15737
+ const containerSx = useMemo(() => {
15738
+ const baseSx = {
15739
+ width: '100%',
15740
+ position: 'relative',
15741
+ ...styleProps.sx
15742
+ };
15743
+ switch (variant) {
15744
+ case 'outlined':
15745
+ return {
15746
+ ...baseSx,
15747
+ border: `1px solid ${theme.palette.divider}`,
15748
+ borderRadius: 1,
15749
+ backgroundColor: 'var(--theme-surface)'
15750
+ };
15751
+ case 'elevated':
15752
+ return {
15753
+ ...baseSx,
15754
+ boxShadow: theme.shadows[2],
15755
+ borderRadius: 1,
15756
+ backgroundColor: theme.palette.background.paper
15757
+ };
15758
+ case 'filled':
15759
+ return {
15760
+ ...baseSx,
15761
+ backgroundColor: 'var(--theme-surface-variant)',
15762
+ borderRadius: 1
15763
+ };
15764
+ default:
15765
+ return baseSx;
15766
+ }
15767
+ }, [variant, theme, styleProps.sx]);
15768
+ // Header styles
15769
+ const headerSx = useMemo(() => ({
15770
+ ...headerSpacingConfig,
15771
+ cursor: triggerArea === 'header' || triggerArea === 'both' ? 'pointer' : 'default',
15772
+ userSelect: 'none',
15773
+ display: 'flex',
15774
+ alignItems: 'center',
15775
+ justifyContent: 'space-between',
15776
+ '&:hover': triggerArea === 'header' || triggerArea === 'both' ? {
15777
+ backgroundColor: 'rgba(0, 0, 0, 0.04)'
15778
+ } : {}
15779
+ }), [headerSpacingConfig, triggerArea]);
15780
+ // Content styles
15781
+ const contentSx = useMemo(() => ({
15782
+ ...contentSpacingConfig
15783
+ }), [contentSpacingConfig]);
15784
+ // Animation props for Collapse component
15785
+ const collapseProps = useMemo(() => {
15786
+ if (disableAnimations) {
15787
+ return {
15788
+ timeout: 0
15789
+ };
15790
+ }
15791
+ const baseProps = {
15792
+ timeout: animationDuration
15793
+ };
15794
+ switch (animationStyle) {
15795
+ case 'fade':
15796
+ return {
15797
+ ...baseProps,
15798
+ sx: {
15799
+ '& .MuiCollapse-wrapper': {
15800
+ opacity: collapsed ? 0 : 1,
15801
+ transition: `opacity ${animationDuration}ms ${animationConfig.easing}`
15802
+ }
15803
+ }
15804
+ };
15805
+ case 'scale':
15806
+ return {
15807
+ ...baseProps,
15808
+ sx: {
15809
+ '& .MuiCollapse-wrapper': {
15810
+ transform: collapsed ? 'scale(0.95)' : 'scale(1)',
15811
+ opacity: collapsed ? 0 : 1,
15812
+ transition: `all ${animationDuration}ms ${animationConfig.easing}`
15813
+ }
15814
+ }
15815
+ };
15816
+ default:
15817
+ // slide
15818
+ return baseProps;
15819
+ }
15820
+ }, [disableAnimations, animationDuration, animationStyle, animationConfig, collapsed]);
15821
+ // Render content based on type
15822
+ const renderContent = useCallback(content => {
15823
+ if (!content) return null;
15824
+ if (typeof content === 'string') {
15825
+ return jsx(Html, {
15826
+ children: content
15827
+ });
15828
+ }
15829
+ return content;
15830
+ }, []);
15831
+ // Container content that will be wrapped
15832
+ const containerContent = jsxs(Fragment, {
15833
+ children: [(title || subtitle || leadIcon || headerActions || triggerArea === 'button' || triggerArea === 'both') && jsxs(Fragment, {
15834
+ children: [jsxs(Box, {
15835
+ id: headerId,
15836
+ className: headerClassName,
15837
+ sx: headerSx,
15838
+ onClick: handleHeaderClick,
15839
+ role: triggerArea === 'header' || triggerArea === 'both' ? 'button' : undefined,
15840
+ tabIndex: triggerArea === 'header' || triggerArea === 'both' ? 0 : undefined,
15841
+ "aria-expanded": !collapsed,
15842
+ "aria-controls": contentId,
15843
+ "aria-describedby": ariaDescribedBy,
15844
+ onKeyDown: e => {
15845
+ if ((triggerArea === 'header' || triggerArea === 'both') && (e.key === 'Enter' || e.key === ' ')) {
15846
+ e.preventDefault();
15847
+ toggle();
15848
+ }
15849
+ },
15850
+ children: [jsxs(Stack, {
15851
+ direction: "row",
15852
+ spacing: 2,
15853
+ alignItems: "center",
15854
+ sx: {
15855
+ minWidth: 0,
15856
+ flex: 1
15857
+ },
15858
+ children: [leadIcon && jsx(Box, {
15859
+ sx: {
15860
+ flexShrink: 0
15861
+ },
15862
+ children: renderContent(leadIcon)
15863
+ }), (title || subtitle) && jsxs(Box, {
15864
+ sx: {
15865
+ minWidth: 0,
15866
+ flex: 1
15867
+ },
15868
+ children: [title && jsx(Typography, {
15869
+ variant: "h6",
15870
+ component: "h3",
15871
+ sx: {
15872
+ fontWeight: 600,
15873
+ lineHeight: 1.2,
15874
+ ...(subtitle && {
15875
+ mb: 0.5
15876
+ })
15877
+ },
15878
+ children: title
15879
+ }), subtitle && jsx(Typography, {
15880
+ variant: "body2",
15881
+ color: "text.secondary",
15882
+ sx: {
15883
+ lineHeight: 1.3
15884
+ },
15885
+ children: subtitle
15886
+ })]
15887
+ })]
15888
+ }), jsxs(Stack, {
15889
+ direction: "row",
15890
+ spacing: 1,
15891
+ alignItems: "center",
15892
+ sx: {
15893
+ flexShrink: 0
15894
+ },
15895
+ children: [headerActions && jsx(Box, {
15896
+ children: renderContent(headerActions)
15897
+ }), jsx(IconButton, {
15898
+ onClick: handleButtonClick,
15899
+ size: "small",
15900
+ "aria-label": toggleAriaLabel,
15901
+ "aria-expanded": !collapsed,
15902
+ "aria-controls": contentId,
15903
+ children: toggleIcon
15904
+ })]
15905
+ })]
15906
+ }), showDivider && jsx(Divider, {})]
15907
+ }), collapsed && collapsedView && jsxs(Fragment, {
15908
+ children: [jsx(Box, {
15909
+ className: contentClassName,
15910
+ sx: contentSx,
15911
+ children: renderContent(collapsedView)
15912
+ }), showDivider && footerView && jsx(Divider, {})]
15913
+ }), jsxs(Collapse, {
15914
+ in: !collapsed,
15915
+ ...collapseProps,
15916
+ children: [jsx(Box, {
15917
+ id: contentId,
15918
+ className: contentClassName,
15919
+ sx: contentSx,
15920
+ role: "region",
15921
+ "aria-labelledby": title ? headerId : undefined,
15922
+ ...contentAriaProps,
15923
+ children: renderContent(children)
15924
+ }), showDivider && footerView && jsx(Divider, {})]
15925
+ }), footerView && jsx(Box, {
15926
+ className: footerClassName,
15927
+ sx: contentSx,
15928
+ children: renderContent(footerView)
15929
+ })]
15930
+ });
15931
+ // Return appropriate container based on variant
15932
+ if (variant === 'outlined') {
15933
+ return jsx(Paper, {
15934
+ variant: "outlined",
15935
+ elevation: 0,
15936
+ ...htmlProps,
15937
+ ...otherProps,
15938
+ className: containerClassName,
15939
+ sx: containerSx,
15940
+ children: containerContent
15941
+ });
15942
+ }
15943
+ if (variant === 'elevated') {
15944
+ return jsx(Paper, {
15945
+ elevation: 2,
15946
+ ...htmlProps,
15947
+ ...otherProps,
15948
+ className: containerClassName,
15949
+ sx: containerSx,
15950
+ children: containerContent
15951
+ });
15952
+ }
15953
+ // Default variant (default, filled)
15954
+ return jsx(Box, {
15955
+ ...htmlProps,
15956
+ ...otherProps,
15957
+ className: containerClassName,
15958
+ sx: containerSx,
15959
+ children: containerContent
15960
+ });
15961
+ }
15962
+ /**
15963
+ * Main CollapsibleLayout component with data binding support
15964
+ */
15965
+ function CollapsibleLayout(props) {
15966
+ const {
15967
+ dataSource,
15968
+ bindingOptions,
15969
+ ...restProps
15970
+ } = props;
15971
+ // If no dataSource, use traditional props
15972
+ if (!dataSource) {
15973
+ return jsx(CollapsibleLayoutView, {
15974
+ ...restProps
15975
+ });
15976
+ }
15977
+ // Use data binding
15978
+ const {
15979
+ dataSource: _source,
15980
+ loading,
15981
+ error,
15982
+ cached,
15983
+ ...collapsibleProps
15984
+ } = useDataBinding(dataSource, restProps, CollapsibleLayoutModel$1.getSchema(), {
15985
+ cache: true,
15986
+ cacheTTL: 300000,
15987
+ strict: false,
15988
+ ...bindingOptions
15989
+ });
15990
+ // Show loading state
15991
+ if (loading) {
15992
+ return jsx(CollapsibleLayoutView, {
15993
+ ...restProps,
15994
+ title: "Loading...",
15995
+ variant: "default",
15996
+ headerSpacing: "comfortable",
15997
+ contentSpacing: "comfortable"
15998
+ });
15999
+ }
16000
+ if (error) {
16001
+ console.error('Error loading collapsible layout:', error);
16002
+ {
16003
+ return jsx(CollapsibleLayoutView, {
16004
+ ...restProps,
16005
+ title: "Error Loading Layout",
16006
+ subtitle: error.message,
16007
+ variant: "outlined",
16008
+ headerSpacing: "comfortable",
16009
+ contentSpacing: "comfortable"
16010
+ });
16011
+ }
16012
+ }
16013
+ return jsx(CollapsibleLayoutView, {
16014
+ ...collapsibleProps
16015
+ });
16016
+ }
16017
+ // Set default props
16018
+ CollapsibleLayout.defaultProps = defaultCollapsibleLayoutProps;
16019
+
15337
16020
  /**
15338
16021
  * FeatureCard Schema - Schema definition for FeatureCard component
15339
16022
  *
@@ -18726,7 +19409,7 @@ function FormBlockView({
18726
19409
  title,
18727
19410
  description,
18728
19411
  coverImage,
18729
- form,
19412
+ children: form,
18730
19413
  footer,
18731
19414
  status,
18732
19415
  message,
@@ -19684,8 +20367,195 @@ function SelectInputField(props) {
19684
20367
  strict: false,
19685
20368
  ...bindingOptions
19686
20369
  });
19687
- // Show loading state
19688
- if (loading) {
20370
+ // Show loading state
20371
+ if (loading) {
20372
+ return jsxs(Paper, {
20373
+ variant: "outlined",
20374
+ sx: {
20375
+ p: 2,
20376
+ textAlign: 'center'
20377
+ },
20378
+ children: [jsx(Typography, {
20379
+ variant: "body2",
20380
+ children: "Loading SelectInputField..."
20381
+ }), jsx(Typography, {
20382
+ variant: "caption",
20383
+ color: "text.secondary",
20384
+ children: "Loading select field configuration from data source..."
20385
+ })]
20386
+ });
20387
+ }
20388
+ if (error) {
20389
+ console.error('Error loading select input field:', error);
20390
+ {
20391
+ return jsx(Paper, {
20392
+ variant: "outlined",
20393
+ sx: {
20394
+ p: 2,
20395
+ textAlign: 'center',
20396
+ borderColor: 'error.main'
20397
+ },
20398
+ children: jsxs(Typography, {
20399
+ variant: "body2",
20400
+ color: "error",
20401
+ children: ["Error loading select field: ", error.message]
20402
+ })
20403
+ });
20404
+ }
20405
+ }
20406
+ return jsx(SelectInputFieldView, {
20407
+ ...selectInputFieldProps
20408
+ });
20409
+ }
20410
+ // Mark as QwickApp component
20411
+ SelectInputField[QWICKAPP_COMPONENT] = true;
20412
+
20413
+ /**
20414
+ * SwitchInputField Schema - Data model for switch input field component
20415
+ *
20416
+ * Copyright (c) 2025 QwickApps.com. All rights reserved.
20417
+ */
20418
+ let SwitchInputFieldModel = class SwitchInputFieldModel extends Model {};
20419
+ __decorate([Field(), Editor({
20420
+ field_type: FieldType.TEXT,
20421
+ label: 'Label',
20422
+ description: 'The label text for the switch'
20423
+ }), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "label", void 0);
20424
+ __decorate([Field({
20425
+ defaultValue: false
20426
+ }), Editor({
20427
+ field_type: FieldType.BOOLEAN,
20428
+ label: 'Checked',
20429
+ description: 'Whether the switch is checked'
20430
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "checked", void 0);
20431
+ __decorate([Field({
20432
+ defaultValue: false
20433
+ }), Editor({
20434
+ field_type: FieldType.BOOLEAN,
20435
+ label: 'Required',
20436
+ description: 'Whether the field is required'
20437
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "required", void 0);
20438
+ __decorate([Field({
20439
+ defaultValue: false
20440
+ }), Editor({
20441
+ field_type: FieldType.BOOLEAN,
20442
+ label: 'Disabled',
20443
+ description: 'Whether the field is disabled'
20444
+ }), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "disabled", void 0);
20445
+ __decorate([Field(), Editor({
20446
+ field_type: FieldType.TEXT,
20447
+ label: 'Error',
20448
+ description: 'Error message to display'
20449
+ }), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "error", void 0);
20450
+ __decorate([Field(), Editor({
20451
+ field_type: FieldType.TEXT,
20452
+ label: 'Helper Text',
20453
+ description: 'Helper text to display below the switch'
20454
+ }), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "helperText", void 0);
20455
+ __decorate([Field({
20456
+ defaultValue: 'medium'
20457
+ }), Editor({
20458
+ field_type: FieldType.SELECT,
20459
+ label: 'Size',
20460
+ description: 'Size of the switch'
20461
+ }), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "size", void 0);
20462
+ __decorate([Field({
20463
+ defaultValue: 'primary'
20464
+ }), Editor({
20465
+ field_type: FieldType.SELECT,
20466
+ label: 'Color',
20467
+ description: 'Color theme of the switch'
20468
+ }), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "color", void 0);
20469
+ SwitchInputFieldModel = __decorate([Schema('SwitchInputField', '1.0.0')], SwitchInputFieldModel);
20470
+ var SwitchInputFieldModel$1 = SwitchInputFieldModel;
20471
+
20472
+ // View component - handles the actual rendering
20473
+ function SwitchInputFieldView({
20474
+ label,
20475
+ checked = false,
20476
+ onChange,
20477
+ onFocus,
20478
+ required = false,
20479
+ disabled = false,
20480
+ error,
20481
+ helperText,
20482
+ size = 'medium',
20483
+ color = 'primary',
20484
+ ...restProps
20485
+ }) {
20486
+ const {
20487
+ styleProps,
20488
+ htmlProps
20489
+ } = useBaseProps(restProps);
20490
+ const handleChange = event => {
20491
+ if (onChange) {
20492
+ onChange(event.target.checked);
20493
+ }
20494
+ };
20495
+ return jsxs(FormControl, {
20496
+ ...htmlProps,
20497
+ ...styleProps,
20498
+ error: !!error,
20499
+ required: required,
20500
+ disabled: disabled,
20501
+ sx: {
20502
+ display: 'block',
20503
+ ...styleProps.sx
20504
+ },
20505
+ children: [jsx(FormControlLabel, {
20506
+ control: jsx(Switch, {
20507
+ checked: checked,
20508
+ onChange: handleChange,
20509
+ onFocus: onFocus,
20510
+ size: size,
20511
+ color: color,
20512
+ disabled: disabled
20513
+ }),
20514
+ label: label,
20515
+ disabled: disabled
20516
+ }), (error || helperText) && jsx(FormHelperText, {
20517
+ children: error || helperText
20518
+ })]
20519
+ });
20520
+ }
20521
+ /**
20522
+ * SwitchInputField component with data binding support
20523
+ * Supports both traditional props and dataSource-driven rendering
20524
+ */
20525
+ function SwitchInputField(props) {
20526
+ const {
20527
+ dataSource,
20528
+ bindingOptions,
20529
+ ...restProps
20530
+ } = props;
20531
+ // If no dataSource, use traditional props
20532
+ if (!dataSource) {
20533
+ return jsx(SwitchInputFieldView, {
20534
+ ...restProps
20535
+ });
20536
+ }
20537
+ // Use data binding
20538
+ const bindingResult = useDataBinding(dataSource, restProps, SwitchInputFieldModel$1.getSchema(), {
20539
+ cache: true,
20540
+ cacheTTL: 300000,
20541
+ strict: false,
20542
+ ...bindingOptions
20543
+ });
20544
+ // Check if we're still loading data using the metadata properties
20545
+ const bindingLoading = bindingResult.$loading;
20546
+ // Extract all the actual switch properties (excluding metadata)
20547
+ const {
20548
+ dataSource: _source,
20549
+ $loading,
20550
+ $error,
20551
+ $dataSource,
20552
+ $cached,
20553
+ cached,
20554
+ ...switchInputFieldProps
20555
+ } = bindingResult;
20556
+ const error = bindingResult.$error;
20557
+ // Show loading state while fetching data
20558
+ if (bindingLoading) {
19689
20559
  return jsxs(Paper, {
19690
20560
  variant: "outlined",
19691
20561
  sx: {
@@ -19694,16 +20564,16 @@ function SelectInputField(props) {
19694
20564
  },
19695
20565
  children: [jsx(Typography, {
19696
20566
  variant: "body2",
19697
- children: "Loading SelectInputField..."
20567
+ children: "Loading SwitchInputField..."
19698
20568
  }), jsx(Typography, {
19699
20569
  variant: "caption",
19700
20570
  color: "text.secondary",
19701
- children: "Loading select field configuration from data source..."
20571
+ children: "Loading switch field configuration from data source..."
19702
20572
  })]
19703
20573
  });
19704
20574
  }
19705
20575
  if (error) {
19706
- console.error('Error loading select input field:', error);
20576
+ console.error('Error loading switch input field:', error);
19707
20577
  {
19708
20578
  return jsx(Paper, {
19709
20579
  variant: "outlined",
@@ -19715,17 +20585,17 @@ function SelectInputField(props) {
19715
20585
  children: jsxs(Typography, {
19716
20586
  variant: "body2",
19717
20587
  color: "error",
19718
- children: ["Error loading select field: ", error.message]
20588
+ children: ["Error loading switch field: ", error.message]
19719
20589
  })
19720
20590
  });
19721
20591
  }
19722
20592
  }
19723
- return jsx(SelectInputFieldView, {
19724
- ...selectInputFieldProps
20593
+ return jsx(SwitchInputFieldView, {
20594
+ ...switchInputFieldProps
19725
20595
  });
19726
20596
  }
19727
20597
  // Mark as QwickApp component
19728
- SelectInputField[QWICKAPP_COMPONENT] = true;
20598
+ SwitchInputField[QWICKAPP_COMPONENT] = true;
19729
20599
 
19730
20600
  const TextField = /*#__PURE__*/React.forwardRef((props, ref) => {
19731
20601
  const {
@@ -20223,7 +21093,7 @@ const FormPage = ({
20223
21093
  title: title,
20224
21094
  description: description,
20225
21095
  coverImage: coverImage,
20226
- form: form,
21096
+ children: form,
20227
21097
  footer: footer,
20228
21098
  status: status,
20229
21099
  message: message,
@@ -20579,6 +21449,605 @@ const Scaffold = ({
20579
21449
 
20580
21450
  loggers.menu;
20581
21451
 
21452
+ /**
21453
+ * Generic ErrorBoundary component for catching and handling React errors
21454
+ *
21455
+ * Features:
21456
+ * - Catches JavaScript errors anywhere in child component tree
21457
+ * - Displays fallback UI with retry functionality
21458
+ * - Shows error details in development mode
21459
+ * - Customizable error handling and fallback UI
21460
+ * - Automatic error logging
21461
+ */
21462
+ class ErrorBoundary extends Component {
21463
+ constructor(props) {
21464
+ super(props);
21465
+ this.handleRetry = () => {
21466
+ this.setState({
21467
+ hasError: false,
21468
+ error: null,
21469
+ errorInfo: null
21470
+ });
21471
+ };
21472
+ this.handleRefresh = () => {
21473
+ if (typeof window !== 'undefined') {
21474
+ window.location.reload();
21475
+ }
21476
+ };
21477
+ this.state = {
21478
+ hasError: false,
21479
+ error: null,
21480
+ errorInfo: null
21481
+ };
21482
+ }
21483
+ static getDerivedStateFromError(error) {
21484
+ // Update state so the next render will show the fallback UI
21485
+ return {
21486
+ hasError: true,
21487
+ error,
21488
+ errorInfo: null
21489
+ };
21490
+ }
21491
+ componentDidCatch(error, errorInfo) {
21492
+ // Log error details
21493
+ this.setState({
21494
+ error,
21495
+ errorInfo
21496
+ });
21497
+ // Log to console for debugging
21498
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
21499
+ // Custom error handler
21500
+ if (this.props.onError) {
21501
+ this.props.onError(error, errorInfo);
21502
+ }
21503
+ // Send error to logging service if available
21504
+ if (typeof window !== 'undefined') {
21505
+ // @ts-ignore - Global error logging service
21506
+ if (window.qwickapps?.logError) {
21507
+ window.qwickapps.logError(error, errorInfo);
21508
+ }
21509
+ }
21510
+ }
21511
+ render() {
21512
+ if (this.state.hasError) {
21513
+ // Custom fallback UI
21514
+ if (this.props.fallback) {
21515
+ return this.props.fallback;
21516
+ }
21517
+ // Default error UI
21518
+ return jsxs("div", {
21519
+ className: "error-boundary",
21520
+ role: "alert",
21521
+ style: {
21522
+ padding: '2rem',
21523
+ textAlign: 'center',
21524
+ backgroundColor: '#fef2f2',
21525
+ border: '1px solid #fecaca',
21526
+ borderRadius: '8px',
21527
+ margin: '1rem',
21528
+ color: '#991b1b'
21529
+ },
21530
+ children: [jsxs("div", {
21531
+ style: {
21532
+ marginBottom: '1.5rem'
21533
+ },
21534
+ children: [jsx("h2", {
21535
+ style: {
21536
+ fontSize: '1.5rem',
21537
+ fontWeight: 'bold',
21538
+ marginBottom: '0.5rem',
21539
+ color: '#991b1b'
21540
+ },
21541
+ children: "Something went wrong"
21542
+ }), jsx("p", {
21543
+ style: {
21544
+ color: '#7f1d1d',
21545
+ marginBottom: '1rem'
21546
+ },
21547
+ children: "An unexpected error occurred in the application. Please try again or refresh the page."
21548
+ })]
21549
+ }), jsxs("div", {
21550
+ style: {
21551
+ display: 'flex',
21552
+ gap: '0.75rem',
21553
+ justifyContent: 'center',
21554
+ marginBottom: '1rem'
21555
+ },
21556
+ children: [jsx(Button, {
21557
+ variant: "contained",
21558
+ onClick: this.handleRetry,
21559
+ style: {
21560
+ backgroundColor: '#dc2626',
21561
+ color: 'white'
21562
+ },
21563
+ children: "Try Again"
21564
+ }), jsx(Button, {
21565
+ variant: "outlined",
21566
+ onClick: this.handleRefresh,
21567
+ style: {
21568
+ borderColor: '#dc2626',
21569
+ color: '#dc2626'
21570
+ },
21571
+ children: "Refresh Page"
21572
+ })]
21573
+ }), this.state.error && jsxs("details", {
21574
+ style: {
21575
+ textAlign: 'left',
21576
+ marginTop: '1rem',
21577
+ padding: '1rem',
21578
+ backgroundColor: '#f9fafb',
21579
+ border: '1px solid #d1d5db',
21580
+ borderRadius: '6px'
21581
+ },
21582
+ children: [jsx("summary", {
21583
+ style: {
21584
+ cursor: 'pointer',
21585
+ fontWeight: 'bold',
21586
+ marginBottom: '0.5rem',
21587
+ color: '#374151'
21588
+ },
21589
+ children: "Error Details (Development Mode)"
21590
+ }), jsxs("pre", {
21591
+ style: {
21592
+ fontSize: '0.75rem',
21593
+ color: '#374151',
21594
+ whiteSpace: 'pre-wrap',
21595
+ overflow: 'auto'
21596
+ },
21597
+ children: [this.state.error.toString(), this.state.errorInfo?.componentStack && jsxs(Fragment, {
21598
+ children: [jsx("br", {}), jsx("br", {}), "Component Stack:", this.state.errorInfo.componentStack]
21599
+ })]
21600
+ })]
21601
+ })]
21602
+ });
21603
+ }
21604
+ return this.props.children;
21605
+ }
21606
+ }
21607
+ /**
21608
+ * Higher-order component that wraps a component with ErrorBoundary
21609
+ */
21610
+ function withErrorBoundary(WrappedComponent, errorBoundaryProps) {
21611
+ const WithErrorBoundaryComponent = props => jsx(ErrorBoundary, {
21612
+ ...errorBoundaryProps,
21613
+ children: jsx(WrappedComponent, {
21614
+ ...props
21615
+ })
21616
+ });
21617
+ WithErrorBoundaryComponent.displayName = `withErrorBoundary(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
21618
+ return WithErrorBoundaryComponent;
21619
+ }
21620
+
21621
+ const AccessibilityContext = /*#__PURE__*/createContext(null);
21622
+ // Reducer
21623
+ const accessibilityReducer = (state, action) => {
21624
+ switch (action.type) {
21625
+ case 'SET_HIGH_CONTRAST':
21626
+ return {
21627
+ ...state,
21628
+ highContrast: action.payload
21629
+ };
21630
+ case 'SET_REDUCED_MOTION':
21631
+ return {
21632
+ ...state,
21633
+ reducedMotion: action.payload
21634
+ };
21635
+ case 'SET_LARGE_TEXT':
21636
+ return {
21637
+ ...state,
21638
+ largeText: action.payload
21639
+ };
21640
+ case 'SET_FOCUS_VISIBLE':
21641
+ return {
21642
+ ...state,
21643
+ focusVisible: action.payload
21644
+ };
21645
+ case 'SET_KEYBOARD_USER':
21646
+ return {
21647
+ ...state,
21648
+ isKeyboardUser: action.payload
21649
+ };
21650
+ case 'ADD_ISSUE':
21651
+ return {
21652
+ ...state,
21653
+ issues: [...state.issues, action.payload]
21654
+ };
21655
+ case 'CLEAR_ISSUES':
21656
+ return {
21657
+ ...state,
21658
+ issues: []
21659
+ };
21660
+ case 'SET_ANNOUNCEMENT':
21661
+ return {
21662
+ ...state,
21663
+ lastAnnouncement: action.payload
21664
+ };
21665
+ default:
21666
+ return state;
21667
+ }
21668
+ };
21669
+ // Initial state
21670
+ const initialState = {
21671
+ highContrast: false,
21672
+ reducedMotion: false,
21673
+ largeText: false,
21674
+ focusVisible: true,
21675
+ isKeyboardUser: false,
21676
+ issues: [],
21677
+ lastAnnouncement: null,
21678
+ preferences: {}
21679
+ };
21680
+ // ARIA Live Manager
21681
+ class AriaLiveManager {
21682
+ constructor() {
21683
+ this.politeRegion = null;
21684
+ this.assertiveRegion = null;
21685
+ this.createLiveRegions();
21686
+ }
21687
+ createLiveRegions() {
21688
+ if (typeof document === 'undefined') return;
21689
+ // Polite announcements
21690
+ this.politeRegion = document.createElement('div');
21691
+ this.politeRegion.setAttribute('aria-live', 'polite');
21692
+ this.politeRegion.setAttribute('aria-atomic', 'true');
21693
+ this.politeRegion.setAttribute('id', 'qwickapps-aria-live-polite');
21694
+ this.politeRegion.style.cssText = `
21695
+ position: absolute !important;
21696
+ left: -10000px !important;
21697
+ width: 1px !important;
21698
+ height: 1px !important;
21699
+ overflow: hidden !important;
21700
+ `;
21701
+ document.body.appendChild(this.politeRegion);
21702
+ // Assertive announcements
21703
+ this.assertiveRegion = document.createElement('div');
21704
+ this.assertiveRegion.setAttribute('aria-live', 'assertive');
21705
+ this.assertiveRegion.setAttribute('aria-atomic', 'true');
21706
+ this.assertiveRegion.setAttribute('id', 'qwickapps-aria-live-assertive');
21707
+ this.assertiveRegion.style.cssText = `
21708
+ position: absolute !important;
21709
+ left: -10000px !important;
21710
+ width: 1px !important;
21711
+ height: 1px !important;
21712
+ overflow: hidden !important;
21713
+ `;
21714
+ document.body.appendChild(this.assertiveRegion);
21715
+ }
21716
+ announce(message, level = 'polite') {
21717
+ if (level === 'assertive') {
21718
+ this.announceAssertive(message);
21719
+ } else {
21720
+ this.announcePolite(message);
21721
+ }
21722
+ }
21723
+ announcePolite(message) {
21724
+ if (!this.politeRegion) return;
21725
+ this.politeRegion.textContent = '';
21726
+ // Small delay ensures screen readers detect the change
21727
+ setTimeout(() => {
21728
+ if (this.politeRegion) {
21729
+ this.politeRegion.textContent = message;
21730
+ }
21731
+ }, 100);
21732
+ }
21733
+ announceAssertive(message) {
21734
+ if (!this.assertiveRegion) return;
21735
+ this.assertiveRegion.textContent = '';
21736
+ // Small delay ensures screen readers detect the change
21737
+ setTimeout(() => {
21738
+ if (this.assertiveRegion) {
21739
+ this.assertiveRegion.textContent = message;
21740
+ }
21741
+ }, 100);
21742
+ }
21743
+ }
21744
+ const ariaLiveManager = new AriaLiveManager();
21745
+ /**
21746
+ * Accessibility Provider Component
21747
+ * Provides comprehensive accessibility context and utilities
21748
+ *
21749
+ * Features:
21750
+ * - System preference detection (high contrast, reduced motion)
21751
+ * - Keyboard navigation detection
21752
+ * - ARIA live announcements
21753
+ * - Focus management
21754
+ * - Accessibility auditing
21755
+ * - Settings persistence
21756
+ */
21757
+ const AccessibilityProvider = ({
21758
+ children,
21759
+ enableAudit = "development" === 'development'
21760
+ }) => {
21761
+ const [state, dispatch] = useReducer(accessibilityReducer, initialState);
21762
+ useEffect(() => {
21763
+ // Detect user preferences from system
21764
+ detectUserPreferences();
21765
+ // Set up keyboard detection
21766
+ const keyboardCleanup = setupKeyboardDetection();
21767
+ // Initialize focus management
21768
+ initializeFocusManagement();
21769
+ // Run initial accessibility audit
21770
+ if (enableAudit) {
21771
+ runAccessibilityAudit();
21772
+ }
21773
+ // Cleanup
21774
+ return () => {
21775
+ if (keyboardCleanup) keyboardCleanup();
21776
+ };
21777
+ }, [enableAudit]);
21778
+ const detectUserPreferences = () => {
21779
+ if (typeof window === 'undefined') return;
21780
+ // High contrast mode
21781
+ if (window.matchMedia && window.matchMedia('(prefers-contrast: high)').matches) {
21782
+ dispatch({
21783
+ type: 'SET_HIGH_CONTRAST',
21784
+ payload: true
21785
+ });
21786
+ }
21787
+ // Reduced motion
21788
+ if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
21789
+ dispatch({
21790
+ type: 'SET_REDUCED_MOTION',
21791
+ payload: true
21792
+ });
21793
+ }
21794
+ // Listen for changes
21795
+ if (window.matchMedia) {
21796
+ const contrastMedia = window.matchMedia('(prefers-contrast: high)');
21797
+ const motionMedia = window.matchMedia('(prefers-reduced-motion: reduce)');
21798
+ const contrastHandler = e => {
21799
+ dispatch({
21800
+ type: 'SET_HIGH_CONTRAST',
21801
+ payload: e.matches
21802
+ });
21803
+ };
21804
+ const motionHandler = e => {
21805
+ dispatch({
21806
+ type: 'SET_REDUCED_MOTION',
21807
+ payload: e.matches
21808
+ });
21809
+ };
21810
+ contrastMedia.addEventListener('change', contrastHandler);
21811
+ motionMedia.addEventListener('change', motionHandler);
21812
+ // Return cleanup function
21813
+ return () => {
21814
+ contrastMedia.removeEventListener('change', contrastHandler);
21815
+ motionMedia.removeEventListener('change', motionHandler);
21816
+ };
21817
+ }
21818
+ };
21819
+ const setupKeyboardDetection = () => {
21820
+ if (typeof document === 'undefined') return;
21821
+ let keyboardUser = false;
21822
+ const handleKeyDown = e => {
21823
+ if (e.key === 'Tab') {
21824
+ keyboardUser = true;
21825
+ dispatch({
21826
+ type: 'SET_KEYBOARD_USER',
21827
+ payload: true
21828
+ });
21829
+ document.body.classList.add('keyboard-user');
21830
+ }
21831
+ };
21832
+ const handleMouseDown = () => {
21833
+ if (keyboardUser) {
21834
+ keyboardUser = false;
21835
+ dispatch({
21836
+ type: 'SET_KEYBOARD_USER',
21837
+ payload: false
21838
+ });
21839
+ document.body.classList.remove('keyboard-user');
21840
+ }
21841
+ };
21842
+ document.addEventListener('keydown', handleKeyDown);
21843
+ document.addEventListener('mousedown', handleMouseDown);
21844
+ return () => {
21845
+ document.removeEventListener('keydown', handleKeyDown);
21846
+ document.removeEventListener('mousedown', handleMouseDown);
21847
+ };
21848
+ };
21849
+ const initializeFocusManagement = () => {
21850
+ if (typeof document === 'undefined') return;
21851
+ // Enhanced focus indicators for keyboard users
21852
+ const style = document.createElement('style');
21853
+ style.textContent = `
21854
+ .keyboard-user *:focus {
21855
+ outline: 3px solid #005cee !important;
21856
+ outline-offset: 2px !important;
21857
+ }
21858
+
21859
+ .high-contrast *:focus {
21860
+ outline: 3px solid #ffffff !important;
21861
+ outline-offset: 2px !important;
21862
+ box-shadow: 0 0 0 1px #000000 !important;
21863
+ }
21864
+
21865
+ .reduced-motion * {
21866
+ animation-duration: 0.01ms !important;
21867
+ animation-iteration-count: 1 !important;
21868
+ transition-duration: 0.01ms !important;
21869
+ }
21870
+
21871
+ .large-text {
21872
+ font-size: 1.2em !important;
21873
+ }
21874
+ `;
21875
+ document.head.appendChild(style);
21876
+ };
21877
+ const runAccessibilityAudit = () => {
21878
+ if (typeof document === 'undefined') return;
21879
+ setTimeout(() => {
21880
+ const issues = [];
21881
+ // Check for images without alt text
21882
+ const images = document.querySelectorAll('img:not([alt])');
21883
+ images.forEach(img => {
21884
+ issues.push({
21885
+ type: 'missing-alt-text',
21886
+ message: 'Image missing alt attribute',
21887
+ level: 'error',
21888
+ element: img
21889
+ });
21890
+ });
21891
+ // Check for buttons without accessible names
21892
+ const buttons = document.querySelectorAll('button:not([aria-label]):not([title])');
21893
+ buttons.forEach(button => {
21894
+ if (!button.textContent?.trim()) {
21895
+ issues.push({
21896
+ type: 'unnamed-button',
21897
+ message: 'Button missing accessible name',
21898
+ level: 'error',
21899
+ element: button
21900
+ });
21901
+ }
21902
+ });
21903
+ // Check for form inputs without labels
21904
+ const inputs = document.querySelectorAll('input:not([aria-label]):not([title])');
21905
+ inputs.forEach(input => {
21906
+ const id = input.getAttribute('id');
21907
+ if (id) {
21908
+ const label = document.querySelector(`label[for="${id}"]`);
21909
+ if (!label) {
21910
+ issues.push({
21911
+ type: 'unlabeled-input',
21912
+ message: 'Form input missing label',
21913
+ level: 'error',
21914
+ element: input
21915
+ });
21916
+ }
21917
+ } else {
21918
+ issues.push({
21919
+ type: 'unlabeled-input',
21920
+ message: 'Form input missing label',
21921
+ level: 'error',
21922
+ element: input
21923
+ });
21924
+ }
21925
+ });
21926
+ dispatch({
21927
+ type: 'CLEAR_ISSUES'
21928
+ });
21929
+ issues.forEach(issue => {
21930
+ dispatch({
21931
+ type: 'ADD_ISSUE',
21932
+ payload: issue
21933
+ });
21934
+ });
21935
+ if (issues.length > 0) {
21936
+ console.group('🔍 Accessibility Issues Found');
21937
+ issues.forEach(issue => {
21938
+ const logMethod = issue.level === 'error' ? console.error : console.warn;
21939
+ logMethod(`${issue.type}: ${issue.message}`);
21940
+ });
21941
+ console.groupEnd();
21942
+ }
21943
+ }, 1000);
21944
+ };
21945
+ // Context value
21946
+ const contextValue = {
21947
+ ...state,
21948
+ // Actions
21949
+ setHighContrast: enabled => dispatch({
21950
+ type: 'SET_HIGH_CONTRAST',
21951
+ payload: enabled
21952
+ }),
21953
+ setReducedMotion: enabled => dispatch({
21954
+ type: 'SET_REDUCED_MOTION',
21955
+ payload: enabled
21956
+ }),
21957
+ setLargeText: enabled => dispatch({
21958
+ type: 'SET_LARGE_TEXT',
21959
+ payload: enabled
21960
+ }),
21961
+ setFocusVisible: enabled => dispatch({
21962
+ type: 'SET_FOCUS_VISIBLE',
21963
+ payload: enabled
21964
+ }),
21965
+ // Utilities
21966
+ announce: (message, level = 'polite') => {
21967
+ ariaLiveManager.announce(message, level);
21968
+ dispatch({
21969
+ type: 'SET_ANNOUNCEMENT',
21970
+ payload: {
21971
+ message,
21972
+ level,
21973
+ timestamp: Date.now()
21974
+ }
21975
+ });
21976
+ },
21977
+ announcePolite: message => {
21978
+ ariaLiveManager.announcePolite(message);
21979
+ dispatch({
21980
+ type: 'SET_ANNOUNCEMENT',
21981
+ payload: {
21982
+ message,
21983
+ level: 'polite',
21984
+ timestamp: Date.now()
21985
+ }
21986
+ });
21987
+ },
21988
+ announceAssertive: message => {
21989
+ ariaLiveManager.announceAssertive(message);
21990
+ dispatch({
21991
+ type: 'SET_ANNOUNCEMENT',
21992
+ payload: {
21993
+ message,
21994
+ level: 'assertive',
21995
+ timestamp: Date.now()
21996
+ }
21997
+ });
21998
+ },
21999
+ addIssue: issue => dispatch({
22000
+ type: 'ADD_ISSUE',
22001
+ payload: issue
22002
+ }),
22003
+ clearIssues: () => dispatch({
22004
+ type: 'CLEAR_ISSUES'
22005
+ }),
22006
+ // Audit function
22007
+ runAudit: runAccessibilityAudit
22008
+ };
22009
+ // Apply CSS classes based on preferences
22010
+ useEffect(() => {
22011
+ if (typeof document === 'undefined') return;
22012
+ const {
22013
+ highContrast,
22014
+ reducedMotion,
22015
+ largeText
22016
+ } = state;
22017
+ document.body.classList.toggle('high-contrast', highContrast);
22018
+ document.body.classList.toggle('reduced-motion', reducedMotion);
22019
+ document.body.classList.toggle('large-text', largeText);
22020
+ }, [state.highContrast, state.reducedMotion, state.largeText]);
22021
+ return jsx(AccessibilityContext.Provider, {
22022
+ value: contextValue,
22023
+ children: children
22024
+ });
22025
+ };
22026
+ /**
22027
+ * Hook to access accessibility context
22028
+ */
22029
+ const useAccessibility = () => {
22030
+ const context = useContext(AccessibilityContext);
22031
+ if (!context) {
22032
+ throw new Error('useAccessibility must be used within an AccessibilityProvider');
22033
+ }
22034
+ return context;
22035
+ };
22036
+ /**
22037
+ * Higher-Order Component for accessibility enhancements
22038
+ */
22039
+ const withAccessibility = WrappedComponent => {
22040
+ const AccessibilityEnhancedComponent = props => {
22041
+ const accessibility = useAccessibility();
22042
+ return jsx(WrappedComponent, {
22043
+ ...props,
22044
+ accessibility: accessibility
22045
+ });
22046
+ };
22047
+ AccessibilityEnhancedComponent.displayName = `withAccessibility(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
22048
+ return AccessibilityEnhancedComponent;
22049
+ };
22050
+
20582
22051
  const QwickApp = ({
20583
22052
  children,
20584
22053
  className,
@@ -20640,16 +22109,20 @@ const QwickApp = ({
20640
22109
  dataSource: dataSource,
20641
22110
  children: content
20642
22111
  }) : content;
20643
- const appContent = jsx("div", {
20644
- className: `qwick-app ${className || ''}`,
20645
- style: style,
20646
- children: jsx(ThemeProvider, {
20647
- appId: appId,
20648
- defaultTheme: defaultTheme,
20649
- defaultPalette: defaultPalette,
20650
- children: jsx(QwickAppContext.Provider, {
20651
- value: contextValue,
20652
- children: wrappedContent
22112
+ const appContent = jsx(ErrorBoundary, {
22113
+ children: jsx(AccessibilityProvider, {
22114
+ children: jsx("div", {
22115
+ className: `qwick-app ${className || ''}`,
22116
+ style: style,
22117
+ children: jsx(ThemeProvider, {
22118
+ appId: appId,
22119
+ defaultTheme: defaultTheme,
22120
+ defaultPalette: defaultPalette,
22121
+ children: jsx(QwickAppContext.Provider, {
22122
+ value: contextValue,
22123
+ children: wrappedContent
22124
+ })
22125
+ })
20653
22126
  })
20654
22127
  })
20655
22128
  });
@@ -20757,6 +22230,186 @@ const setCSSVariable = (property, value) => {
20757
22230
  document.documentElement.style.setProperty(property, value);
20758
22231
  };
20759
22232
 
22233
+ /**
22234
+ * Generic Breadcrumbs component for navigation hierarchy
22235
+ *
22236
+ * Features:
22237
+ * - Accessible navigation with proper ARIA labels
22238
+ * - Customizable separators and icons
22239
+ * - Responsive design with item truncation
22240
+ * - Support for custom navigation handlers
22241
+ * - Keyboard navigation support
22242
+ * - Screen reader friendly
22243
+ */
22244
+ const Breadcrumbs = ({
22245
+ items,
22246
+ separator = '/',
22247
+ className = '',
22248
+ onNavigate,
22249
+ maxItems,
22250
+ showRoot = true
22251
+ }) => {
22252
+ // Filter and prepare items
22253
+ let displayItems = showRoot ? items : items.slice(1);
22254
+ // Handle max items with ellipsis
22255
+ if (maxItems && displayItems.length > maxItems) {
22256
+ const firstItems = displayItems.slice(0, 1);
22257
+ const lastItems = displayItems.slice(-Math.max(1, maxItems - 2));
22258
+ displayItems = [...firstItems, {
22259
+ label: '...',
22260
+ href: undefined,
22261
+ current: false
22262
+ }, ...lastItems];
22263
+ }
22264
+ const handleItemClick = (e, item, index) => {
22265
+ if (onNavigate) {
22266
+ e.preventDefault();
22267
+ onNavigate(item, index);
22268
+ }
22269
+ };
22270
+ const handleKeyDown = (e, item, index) => {
22271
+ if (e.key === 'Enter' || e.key === ' ') {
22272
+ e.preventDefault();
22273
+ if (onNavigate) {
22274
+ onNavigate(item, index);
22275
+ } else if (item.href) {
22276
+ window.location.href = item.href;
22277
+ }
22278
+ }
22279
+ };
22280
+ if (displayItems.length <= 1) {
22281
+ return null;
22282
+ }
22283
+ return jsx("nav", {
22284
+ className: `breadcrumbs ${className}`,
22285
+ role: "navigation",
22286
+ "aria-label": "Breadcrumb navigation",
22287
+ style: {
22288
+ display: 'flex',
22289
+ alignItems: 'center',
22290
+ fontSize: '14px',
22291
+ color: '#6b7280',
22292
+ ...defaultStyles.nav
22293
+ },
22294
+ children: jsx("ol", {
22295
+ style: {
22296
+ display: 'flex',
22297
+ alignItems: 'center',
22298
+ listStyle: 'none',
22299
+ margin: 0,
22300
+ padding: 0,
22301
+ gap: '8px'
22302
+ },
22303
+ children: displayItems.map((item, index) => {
22304
+ const isLast = index === displayItems.length - 1;
22305
+ const isClickable = (item.href || onNavigate) && !item.current && item.label !== '...';
22306
+ return jsxs("li", {
22307
+ style: {
22308
+ display: 'flex',
22309
+ alignItems: 'center'
22310
+ },
22311
+ children: [isClickable ? jsxs("a", {
22312
+ href: item.href,
22313
+ onClick: e => handleItemClick(e, item, index),
22314
+ onKeyDown: e => handleKeyDown(e, item, index),
22315
+ style: {
22316
+ ...defaultStyles.link,
22317
+ color: isLast ? '#374151' : '#6b7280',
22318
+ textDecoration: 'none',
22319
+ display: 'flex',
22320
+ alignItems: 'center',
22321
+ gap: '4px'
22322
+ },
22323
+ tabIndex: 0,
22324
+ "aria-current": item.current ? 'page' : undefined,
22325
+ children: [item.icon && jsx("span", {
22326
+ style: {
22327
+ display: 'flex',
22328
+ alignItems: 'center'
22329
+ },
22330
+ "aria-hidden": "true",
22331
+ children: item.icon
22332
+ }), jsx("span", {
22333
+ children: item.label
22334
+ })]
22335
+ }) : jsxs("span", {
22336
+ style: {
22337
+ ...defaultStyles.current,
22338
+ color: isLast ? '#111827' : '#6b7280',
22339
+ fontWeight: isLast ? 600 : 400,
22340
+ display: 'flex',
22341
+ alignItems: 'center',
22342
+ gap: '4px'
22343
+ },
22344
+ "aria-current": item.current ? 'page' : undefined,
22345
+ children: [item.icon && jsx("span", {
22346
+ style: {
22347
+ display: 'flex',
22348
+ alignItems: 'center'
22349
+ },
22350
+ "aria-hidden": "true",
22351
+ children: item.icon
22352
+ }), jsx("span", {
22353
+ children: item.label
22354
+ })]
22355
+ }), !isLast && jsx("span", {
22356
+ style: {
22357
+ display: 'flex',
22358
+ alignItems: 'center',
22359
+ marginLeft: '8px',
22360
+ color: '#d1d5db',
22361
+ fontSize: '12px'
22362
+ },
22363
+ "aria-hidden": "true",
22364
+ children: separator
22365
+ })]
22366
+ }, `${item.label}-${index}`);
22367
+ })
22368
+ })
22369
+ });
22370
+ };
22371
+ // Default styles
22372
+ const defaultStyles = {
22373
+ nav: {
22374
+ padding: '8px 0'
22375
+ },
22376
+ link: {
22377
+ transition: 'color 0.2s ease',
22378
+ cursor: 'pointer',
22379
+ borderRadius: '4px',
22380
+ padding: '4px',
22381
+ margin: '-4px'
22382
+ },
22383
+ current: {
22384
+ padding: '4px'
22385
+ }
22386
+ };
22387
+ /**
22388
+ * Hook for managing breadcrumb state
22389
+ */
22390
+ const useBreadcrumbs = () => {
22391
+ const [breadcrumbs, setBreadcrumbs] = React.useState([]);
22392
+ const addBreadcrumb = React.useCallback(item => {
22393
+ setBreadcrumbs(prev => [...prev, item]);
22394
+ }, []);
22395
+ const removeBreadcrumb = React.useCallback(index => {
22396
+ setBreadcrumbs(prev => prev.filter((_, i) => i !== index));
22397
+ }, []);
22398
+ const setBreadcrumbsCurrent = React.useCallback(items => {
22399
+ setBreadcrumbs(items);
22400
+ }, []);
22401
+ const clearBreadcrumbs = React.useCallback(() => {
22402
+ setBreadcrumbs([]);
22403
+ }, []);
22404
+ return {
22405
+ breadcrumbs,
22406
+ addBreadcrumb,
22407
+ removeBreadcrumb,
22408
+ setBreadcrumbs: setBreadcrumbsCurrent,
22409
+ clearBreadcrumbs
22410
+ };
22411
+ };
22412
+
20760
22413
  const QwickAppsLogo = props => {
20761
22414
  const {
20762
22415
  styleProps,
@@ -24223,4 +25876,4 @@ var ActionType;
24223
25876
  ActionType["CANCEL"] = "cancel";
24224
25877
  })(ActionType || (ActionType = {}));
24225
25878
 
24226
- export { AVAILABLE_PALETTES, ActionModel, ActionType, AllPalettes, Article, ArticleModel, BasePage, Button, CardListGrid, CardListGridModel, ChoiceInputField, ChoiceInputFieldModel, Code, CodeModel, Content, ContentModel, CoverImageHeader, CoverImageHeaderModel, DataProvider, DataProxy, DimensionsProvider, FeatureCard, FeatureCardActionModel, FeatureCardModel, FeatureGrid, FeatureGridModel, FeatureItemModel, Footer, FooterItemModel, FooterModel, FooterSectionModel, FormBlock, FormBlockModel, FormMethod, FormPage, GridCell, GridLayout, HeaderActionModel, HeroBlock, HeroBlockModel, Html, HtmlInputField, Logo, Markdown, MetadataItemModel, Page, PageBannerHeader, PageBannerHeaderModel, PaletteAutumn, PaletteCosmic, PaletteDefault, PaletteOcean, PaletteProvider, PaletteSpring, PaletteSwitcher, PaletteSwitcherModel, PaletteWinter, ProductCard, ProductCardActionModel, ProductCardModel, ProductModel, QWICKAPP_COMPONENT, QwickApp, QwickAppsLogo, SafeSpan, SafeSpanModel, Section, SectionModel, SelectInputField, T, TextField, TextInputField, TextInputFieldModel, ThemeProvider, ThemeSwitcher, ThemeSwitcherModel, applyCustomPalette, clearUserPalettePreference, clearUserThemePreference, createLogger, createPaletteFromCurrentTheme, deleteCustomPalette, exportPalette, getCSSVariable, getComputedTheme, getCurrentPalette, getCurrentTheme, getCustomPalettes, getPaletteConfig, getPaletteName, getSystemTheme, getThemePerformanceStats, importPalette, initializePalette, initializeTheme, loadUserPalettePreference, loadUserThemePreference, logThemePerformanceStats, loggers, resetThemePerformanceStats, resolveDimension, resolveDimensions, resolveSpacing, resolveSpacingProps, saveCustomPalette, savePalettePreference, saveThemePreference, saveUserPalettePreference, saveUserThemePreference, setCSSVariable, setPalette, setTheme, t, useBaseProps, useData, useDataBinding, useDataContext, useDataProvider, useDimensions, usePalette, useQwickApp, useResolveTemplate, useSafeLocation, useSafeNavigate, useTemplate, useTheme };
25879
+ export { AVAILABLE_PALETTES, AccessibilityProvider, ActionModel, ActionType, AllPalettes, Article, ArticleModel, BasePage, Breadcrumbs, Button, CardListGrid, CardListGridModel, ChoiceInputField, ChoiceInputFieldModel, Code, CodeModel, CollapsibleLayout, CollapsibleLayoutView, Content, ContentModel, CoverImageHeader, CoverImageHeaderModel, DataProvider, DataProxy, DimensionsProvider, ErrorBoundary, FeatureCard, FeatureCardActionModel, FeatureCardModel, FeatureGrid, FeatureGridModel, FeatureItemModel, Footer, FooterItemModel, FooterModel, FooterSectionModel, FormBlock, FormBlockModel, FormMethod, FormPage, GridCell, GridLayout, HeaderActionModel, HeroBlock, HeroBlockModel, Html, HtmlInputField, Logo, Markdown, MetadataItemModel, Page, PageBannerHeader, PageBannerHeaderModel, PaletteAutumn, PaletteCosmic, PaletteDefault, PaletteOcean, PaletteProvider, PaletteSpring, PaletteSwitcher, PaletteSwitcherModel, PaletteWinter, ProductCard, ProductCardActionModel, ProductCardModel, ProductModel, QWICKAPP_COMPONENT, QwickApp, QwickAppsLogo, SafeSpan, SafeSpanModel, Section, SectionModel, SelectInputField, SwitchInputField, T, TextField, TextInputField, TextInputFieldModel, ThemeProvider, ThemeSwitcher, ThemeSwitcherModel, animationConfigs, applyCustomPalette, clearUserPalettePreference, clearUserThemePreference, createLogger, createPaletteFromCurrentTheme, defaultCollapsibleLayoutProps, deleteCustomPalette, exportPalette, getCSSVariable, getComputedTheme, getCurrentPalette, getCurrentTheme, getCustomPalettes, getPaletteConfig, getPaletteName, getSystemTheme, getThemePerformanceStats, importPalette, initializePalette, initializeTheme, isCollapsibleLayoutProps, loadUserPalettePreference, loadUserThemePreference, logThemePerformanceStats, loggers, resetThemePerformanceStats, resolveDimension, resolveDimensions, resolveSpacing, resolveSpacingProps, saveCustomPalette, savePalettePreference, saveThemePreference, saveUserPalettePreference, saveUserThemePreference, setCSSVariable, setPalette, setTheme, spacingConfigs, t, useAccessibility, useBaseProps, useBreadcrumbs, useCollapsibleState, useData, useDataBinding, useDataContext, useDataProvider, useDimensions, usePalette, useQwickApp, useResolveTemplate, useSafeLocation, useSafeNavigate, useTemplate, useTheme, withAccessibility, withErrorBoundary };