@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.
- package/README.md +326 -0
- 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/forms/FormBlock.d.ts +1 -1
- package/dist/components/forms/FormBlock.d.ts.map +1 -1
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/input/SwitchInputField.d.ts +28 -0
- package/dist/components/input/SwitchInputField.d.ts.map +1 -0
- package/dist/components/input/index.d.ts +2 -0
- package/dist/components/input/index.d.ts.map +1 -1
- package/dist/components/layout/CollapsibleLayout/CollapsibleLayout.d.ts +34 -0
- package/dist/components/layout/CollapsibleLayout/CollapsibleLayout.d.ts.map +1 -0
- package/dist/components/layout/CollapsibleLayout/index.d.ts +9 -0
- package/dist/components/layout/CollapsibleLayout/index.d.ts.map +1 -0
- package/dist/components/layout/index.d.ts +2 -0
- package/dist/components/layout/index.d.ts.map +1 -1
- package/dist/index.bundled.css +12 -0
- package/dist/index.esm.js +1678 -25
- package/dist/index.js +1689 -21
- package/dist/schemas/CollapsibleLayoutSchema.d.ts +31 -0
- package/dist/schemas/CollapsibleLayoutSchema.d.ts.map +1 -0
- package/dist/schemas/SwitchInputFieldSchema.d.ts +18 -0
- package/dist/schemas/SwitchInputFieldSchema.d.ts.map +1 -0
- package/dist/types/CollapsibleLayout.d.ts +142 -0
- package/dist/types/CollapsibleLayout.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- 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/forms/FormBlock.tsx +2 -2
- package/src/components/index.ts +3 -0
- package/src/components/input/SwitchInputField.tsx +165 -0
- package/src/components/input/index.ts +2 -0
- package/src/components/layout/CollapsibleLayout/CollapsibleLayout.tsx +554 -0
- package/src/components/layout/CollapsibleLayout/__tests__/CollapsibleLayout.test.tsx +1469 -0
- package/src/components/layout/CollapsibleLayout/index.tsx +17 -0
- package/src/components/layout/index.ts +4 -1
- package/src/components/pages/FormPage.tsx +1 -1
- package/src/schemas/CollapsibleLayoutSchema.ts +276 -0
- package/src/schemas/SwitchInputFieldSchema.ts +99 -0
- package/src/stories/AccessibilityProvider.stories.tsx +284 -0
- package/src/stories/Breadcrumbs.stories.tsx +304 -0
- package/src/stories/CollapsibleLayout.stories.tsx +1566 -0
- package/src/stories/ErrorBoundary.stories.tsx +159 -0
- package/src/types/CollapsibleLayout.ts +231 -0
- package/src/types/index.ts +1 -0
- 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
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,
|
|
3
|
-
import React, { useMemo, useContext, useState, useEffect, createContext,
|
|
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
|
|
20567
|
+
children: "Loading SwitchInputField..."
|
|
19698
20568
|
}), jsx(Typography, {
|
|
19699
20569
|
variant: "caption",
|
|
19700
20570
|
color: "text.secondary",
|
|
19701
|
-
children: "Loading
|
|
20571
|
+
children: "Loading switch field configuration from data source..."
|
|
19702
20572
|
})]
|
|
19703
20573
|
});
|
|
19704
20574
|
}
|
|
19705
20575
|
if (error) {
|
|
19706
|
-
console.error('Error loading
|
|
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
|
|
20588
|
+
children: ["Error loading switch field: ", error.message]
|
|
19719
20589
|
})
|
|
19720
20590
|
});
|
|
19721
20591
|
}
|
|
19722
20592
|
}
|
|
19723
|
-
return jsx(
|
|
19724
|
-
...
|
|
20593
|
+
return jsx(SwitchInputFieldView, {
|
|
20594
|
+
...switchInputFieldProps
|
|
19725
20595
|
});
|
|
19726
20596
|
}
|
|
19727
20597
|
// Mark as QwickApp component
|
|
19728
|
-
|
|
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
|
-
|
|
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(
|
|
20644
|
-
|
|
20645
|
-
|
|
20646
|
-
|
|
20647
|
-
|
|
20648
|
-
|
|
20649
|
-
|
|
20650
|
-
|
|
20651
|
-
|
|
20652
|
-
|
|
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 };
|