@qwickapps/react-framework 1.3.3 → 1.3.5
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 +227 -0
- package/dist/components/blocks/Content.d.ts.map +1 -1
- package/dist/components/blocks/ProductCard.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/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/contexts/ThemeContext.d.ts.map +1 -1
- package/dist/index.esm.js +963 -105
- package/dist/index.js +967 -101
- 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/blocks/Content.tsx +25 -77
- package/src/components/blocks/ProductCard.tsx +50 -51
- package/src/components/forms/FormBlock.tsx +2 -2
- 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/contexts/ThemeContext.tsx +1 -2
- package/src/schemas/CollapsibleLayoutSchema.ts +276 -0
- package/src/schemas/SwitchInputFieldSchema.ts +99 -0
- package/src/stories/CollapsibleLayout.stories.tsx +1566 -0
- package/src/types/CollapsibleLayout.ts +231 -0
- package/src/types/index.ts +1 -0
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
|
|
|
@@ -13760,72 +13760,62 @@ function ContentView({
|
|
|
13760
13760
|
return 3;
|
|
13761
13761
|
}
|
|
13762
13762
|
};
|
|
13763
|
-
//
|
|
13764
|
-
const
|
|
13765
|
-
|
|
13766
|
-
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
|
|
13778
|
-
|
|
13779
|
-
|
|
13780
|
-
|
|
13781
|
-
return jsx(Paper, {
|
|
13782
|
-
elevation: 4,
|
|
13783
|
-
...htmlProps,
|
|
13784
|
-
...otherProps,
|
|
13785
|
-
sx: {
|
|
13786
|
-
...commonSx,
|
|
13787
|
-
backgroundColor: theme.palette.background.paper
|
|
13788
|
-
},
|
|
13789
|
-
children: children
|
|
13790
|
-
});
|
|
13791
|
-
case 'outlined':
|
|
13792
|
-
return jsx(Paper, {
|
|
13793
|
-
variant: "outlined",
|
|
13794
|
-
elevation: 0,
|
|
13795
|
-
...htmlProps,
|
|
13796
|
-
...otherProps,
|
|
13797
|
-
sx: {
|
|
13798
|
-
...commonSx,
|
|
13799
|
-
backgroundColor: 'var(--theme-surface)',
|
|
13800
|
-
borderColor: 'var(--theme-border-main)',
|
|
13801
|
-
// Use theme border color
|
|
13802
|
-
borderWidth: 1,
|
|
13803
|
-
borderStyle: 'solid'
|
|
13804
|
-
},
|
|
13805
|
-
children: children
|
|
13806
|
-
});
|
|
13807
|
-
case 'filled':
|
|
13808
|
-
return jsx(Box, {
|
|
13809
|
-
...htmlProps,
|
|
13810
|
-
...otherProps,
|
|
13811
|
-
sx: {
|
|
13812
|
-
...commonSx,
|
|
13813
|
-
backgroundColor: 'var(--theme-surface-variant)',
|
|
13814
|
-
// Use theme surface variant
|
|
13815
|
-
borderRadius: 1
|
|
13816
|
-
},
|
|
13817
|
-
children: children
|
|
13818
|
-
});
|
|
13819
|
-
default:
|
|
13820
|
-
return jsx(Box, {
|
|
13821
|
-
...htmlProps,
|
|
13822
|
-
...otherProps,
|
|
13823
|
-
sx: commonSx,
|
|
13824
|
-
children: children
|
|
13825
|
-
});
|
|
13826
|
-
}
|
|
13763
|
+
// Compute stable wrapper element (avoid recreating component type each render which caused remount & focus loss)
|
|
13764
|
+
const paddingValue = getPadding();
|
|
13765
|
+
const mappedMaxWidth = mapToMUIBreakpoint(contentMaxWidth === 'false' ? false : contentMaxWidth);
|
|
13766
|
+
const commonSx = {
|
|
13767
|
+
textAlign: centered ? 'center' : 'left',
|
|
13768
|
+
maxWidth: mappedMaxWidth !== false ? theme.breakpoints.values[mappedMaxWidth] : '100%',
|
|
13769
|
+
width: '100%',
|
|
13770
|
+
...(centered && contentMaxWidth && {
|
|
13771
|
+
mx: 'auto'
|
|
13772
|
+
}),
|
|
13773
|
+
p: paddingValue,
|
|
13774
|
+
...styleProps.sx
|
|
13775
|
+
};
|
|
13776
|
+
let Wrapper = Box;
|
|
13777
|
+
let wrapperProps = {
|
|
13778
|
+
...htmlProps,
|
|
13779
|
+
...otherProps,
|
|
13780
|
+
sx: commonSx
|
|
13827
13781
|
};
|
|
13828
|
-
|
|
13782
|
+
if (variant === 'elevated') {
|
|
13783
|
+
Wrapper = Paper;
|
|
13784
|
+
wrapperProps = {
|
|
13785
|
+
...wrapperProps,
|
|
13786
|
+
elevation: 4,
|
|
13787
|
+
sx: {
|
|
13788
|
+
...commonSx,
|
|
13789
|
+
backgroundColor: theme.palette.background.paper
|
|
13790
|
+
}
|
|
13791
|
+
};
|
|
13792
|
+
} else if (variant === 'outlined') {
|
|
13793
|
+
Wrapper = Paper;
|
|
13794
|
+
wrapperProps = {
|
|
13795
|
+
...wrapperProps,
|
|
13796
|
+
variant: 'outlined',
|
|
13797
|
+
elevation: 0,
|
|
13798
|
+
sx: {
|
|
13799
|
+
...commonSx,
|
|
13800
|
+
backgroundColor: 'var(--theme-surface)',
|
|
13801
|
+
borderColor: 'var(--theme-border-main)',
|
|
13802
|
+
borderWidth: 1,
|
|
13803
|
+
borderStyle: 'solid'
|
|
13804
|
+
}
|
|
13805
|
+
};
|
|
13806
|
+
} else if (variant === 'filled') {
|
|
13807
|
+
Wrapper = Box;
|
|
13808
|
+
wrapperProps = {
|
|
13809
|
+
...wrapperProps,
|
|
13810
|
+
sx: {
|
|
13811
|
+
...commonSx,
|
|
13812
|
+
backgroundColor: 'var(--theme-surface-variant)',
|
|
13813
|
+
borderRadius: 1
|
|
13814
|
+
}
|
|
13815
|
+
};
|
|
13816
|
+
}
|
|
13817
|
+
return jsx(Wrapper, {
|
|
13818
|
+
...wrapperProps,
|
|
13829
13819
|
children: jsxs(Stack, {
|
|
13830
13820
|
spacing: 2,
|
|
13831
13821
|
children: [(title || subtitle) && jsxs(Box, {
|
|
@@ -15334,6 +15324,689 @@ const GridCell = props => {
|
|
|
15334
15324
|
};
|
|
15335
15325
|
GridCell.displayName = 'GridCell';
|
|
15336
15326
|
|
|
15327
|
+
/**
|
|
15328
|
+
* CollapsibleLayout Schema - Data model for collapsible layout component
|
|
15329
|
+
*
|
|
15330
|
+
* Advanced expandable/collapsible container with header controls, animations,
|
|
15331
|
+
* content management, and state persistence capabilities.
|
|
15332
|
+
*
|
|
15333
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
15334
|
+
*/
|
|
15335
|
+
let CollapsibleLayoutModel = class CollapsibleLayoutModel extends Model {};
|
|
15336
|
+
__decorate([Field({
|
|
15337
|
+
defaultValue: false
|
|
15338
|
+
}), Editor({
|
|
15339
|
+
field_type: FieldType.BOOLEAN,
|
|
15340
|
+
label: 'Collapsed',
|
|
15341
|
+
description: 'Whether the layout is currently collapsed'
|
|
15342
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "collapsed", void 0);
|
|
15343
|
+
__decorate([Field({
|
|
15344
|
+
defaultValue: false
|
|
15345
|
+
}), Editor({
|
|
15346
|
+
field_type: FieldType.BOOLEAN,
|
|
15347
|
+
label: 'Default Collapsed',
|
|
15348
|
+
description: 'Initial collapsed state for uncontrolled usage'
|
|
15349
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "defaultCollapsed", void 0);
|
|
15350
|
+
__decorate([Field(), Editor({
|
|
15351
|
+
field_type: FieldType.TEXT,
|
|
15352
|
+
label: 'Title',
|
|
15353
|
+
description: 'Main title displayed in the header',
|
|
15354
|
+
placeholder: 'Enter title...'
|
|
15355
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "title", void 0);
|
|
15356
|
+
__decorate([Field(), Editor({
|
|
15357
|
+
field_type: FieldType.TEXT,
|
|
15358
|
+
label: 'Subtitle',
|
|
15359
|
+
description: 'Secondary text displayed below the title',
|
|
15360
|
+
placeholder: 'Enter subtitle...'
|
|
15361
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "subtitle", void 0);
|
|
15362
|
+
__decorate([Field(), Editor({
|
|
15363
|
+
field_type: FieldType.TEXT,
|
|
15364
|
+
label: 'Lead Icon',
|
|
15365
|
+
description: 'Icon displayed before the title (icon identifier or HTML)',
|
|
15366
|
+
placeholder: 'Icon identifier...'
|
|
15367
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "leadIcon", void 0);
|
|
15368
|
+
__decorate([Field(), Editor({
|
|
15369
|
+
field_type: FieldType.TEXTAREA,
|
|
15370
|
+
label: 'Header Actions',
|
|
15371
|
+
description: 'Additional controls displayed in header (HTML/React content)',
|
|
15372
|
+
placeholder: 'Enter header actions HTML...'
|
|
15373
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "headerActions", void 0);
|
|
15374
|
+
__decorate([Field(), Editor({
|
|
15375
|
+
field_type: FieldType.TEXTAREA,
|
|
15376
|
+
label: 'Collapsed View',
|
|
15377
|
+
description: 'Summary content shown when collapsed (HTML supported)',
|
|
15378
|
+
placeholder: 'Enter collapsed view content...'
|
|
15379
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "collapsedView", void 0);
|
|
15380
|
+
__decorate([Field(), Editor({
|
|
15381
|
+
field_type: FieldType.TEXTAREA,
|
|
15382
|
+
label: 'Content',
|
|
15383
|
+
description: 'Main content shown when expanded (HTML supported)',
|
|
15384
|
+
placeholder: 'Enter main content...'
|
|
15385
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "children", void 0);
|
|
15386
|
+
__decorate([Field(), Editor({
|
|
15387
|
+
field_type: FieldType.TEXTAREA,
|
|
15388
|
+
label: 'Footer View',
|
|
15389
|
+
description: 'Always visible footer content (HTML supported)',
|
|
15390
|
+
placeholder: 'Enter footer content...'
|
|
15391
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "footerView", void 0);
|
|
15392
|
+
__decorate([Field({
|
|
15393
|
+
defaultValue: 'header'
|
|
15394
|
+
}), Editor({
|
|
15395
|
+
field_type: FieldType.SELECT,
|
|
15396
|
+
label: 'Trigger Area',
|
|
15397
|
+
description: 'Area that responds to clicks for toggle functionality',
|
|
15398
|
+
validation: {
|
|
15399
|
+
options: [{
|
|
15400
|
+
label: 'Button Only',
|
|
15401
|
+
value: 'button'
|
|
15402
|
+
}, {
|
|
15403
|
+
label: 'Header Area',
|
|
15404
|
+
value: 'header'
|
|
15405
|
+
}, {
|
|
15406
|
+
label: 'Button and Header',
|
|
15407
|
+
value: 'both'
|
|
15408
|
+
}]
|
|
15409
|
+
}
|
|
15410
|
+
}), IsOptional(), IsIn(['button', 'header', 'both']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "triggerArea", void 0);
|
|
15411
|
+
__decorate([Field({
|
|
15412
|
+
defaultValue: 'slide'
|
|
15413
|
+
}), Editor({
|
|
15414
|
+
field_type: FieldType.SELECT,
|
|
15415
|
+
label: 'Animation Style',
|
|
15416
|
+
description: 'Animation variant for expand/collapse transitions',
|
|
15417
|
+
validation: {
|
|
15418
|
+
options: [{
|
|
15419
|
+
label: 'Fade',
|
|
15420
|
+
value: 'fade'
|
|
15421
|
+
}, {
|
|
15422
|
+
label: 'Slide',
|
|
15423
|
+
value: 'slide'
|
|
15424
|
+
}, {
|
|
15425
|
+
label: 'Scale',
|
|
15426
|
+
value: 'scale'
|
|
15427
|
+
}]
|
|
15428
|
+
}
|
|
15429
|
+
}), IsOptional(), IsIn(['fade', 'slide', 'scale']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "animationStyle", void 0);
|
|
15430
|
+
__decorate([Field({
|
|
15431
|
+
defaultValue: false
|
|
15432
|
+
}), Editor({
|
|
15433
|
+
field_type: FieldType.BOOLEAN,
|
|
15434
|
+
label: 'Persist State',
|
|
15435
|
+
description: 'Save collapse state in local storage'
|
|
15436
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "persistState", void 0);
|
|
15437
|
+
__decorate([Field(), Editor({
|
|
15438
|
+
field_type: FieldType.TEXT,
|
|
15439
|
+
label: 'Collapsed Icon',
|
|
15440
|
+
description: 'Icon shown when content is collapsed (default: VisibilityIcon)',
|
|
15441
|
+
placeholder: 'Icon identifier...'
|
|
15442
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "collapsedIcon", void 0);
|
|
15443
|
+
__decorate([Field(), Editor({
|
|
15444
|
+
field_type: FieldType.TEXT,
|
|
15445
|
+
label: 'Expanded Icon',
|
|
15446
|
+
description: 'Icon shown when content is expanded (default: VisibilityOffIcon)',
|
|
15447
|
+
placeholder: 'Icon identifier...'
|
|
15448
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "expandedIcon", void 0);
|
|
15449
|
+
__decorate([Field({
|
|
15450
|
+
defaultValue: true
|
|
15451
|
+
}), Editor({
|
|
15452
|
+
field_type: FieldType.BOOLEAN,
|
|
15453
|
+
label: 'Show Divider',
|
|
15454
|
+
description: 'Show divider lines between header, content, and footer sections'
|
|
15455
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], CollapsibleLayoutModel.prototype, "showDivider", void 0);
|
|
15456
|
+
__decorate([Field({
|
|
15457
|
+
defaultValue: 'default'
|
|
15458
|
+
}), Editor({
|
|
15459
|
+
field_type: FieldType.SELECT,
|
|
15460
|
+
label: 'Variant',
|
|
15461
|
+
description: 'Visual style variant for the layout container',
|
|
15462
|
+
validation: {
|
|
15463
|
+
options: [{
|
|
15464
|
+
label: 'Default',
|
|
15465
|
+
value: 'default'
|
|
15466
|
+
}, {
|
|
15467
|
+
label: 'Outlined',
|
|
15468
|
+
value: 'outlined'
|
|
15469
|
+
}, {
|
|
15470
|
+
label: 'Elevated',
|
|
15471
|
+
value: 'elevated'
|
|
15472
|
+
}, {
|
|
15473
|
+
label: 'Filled',
|
|
15474
|
+
value: 'filled'
|
|
15475
|
+
}]
|
|
15476
|
+
}
|
|
15477
|
+
}), IsOptional(), IsIn(['default', 'outlined', 'elevated', 'filled']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "variant", void 0);
|
|
15478
|
+
__decorate([Field({
|
|
15479
|
+
defaultValue: 'comfortable'
|
|
15480
|
+
}), Editor({
|
|
15481
|
+
field_type: FieldType.SELECT,
|
|
15482
|
+
label: 'Header Spacing',
|
|
15483
|
+
description: 'Padding/spacing within the header area',
|
|
15484
|
+
validation: {
|
|
15485
|
+
options: [{
|
|
15486
|
+
label: 'Compact',
|
|
15487
|
+
value: 'compact'
|
|
15488
|
+
}, {
|
|
15489
|
+
label: 'Comfortable',
|
|
15490
|
+
value: 'comfortable'
|
|
15491
|
+
}, {
|
|
15492
|
+
label: 'Spacious',
|
|
15493
|
+
value: 'spacious'
|
|
15494
|
+
}]
|
|
15495
|
+
}
|
|
15496
|
+
}), IsOptional(), IsIn(['compact', 'comfortable', 'spacious']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "headerSpacing", void 0);
|
|
15497
|
+
__decorate([Field({
|
|
15498
|
+
defaultValue: 'comfortable'
|
|
15499
|
+
}), Editor({
|
|
15500
|
+
field_type: FieldType.SELECT,
|
|
15501
|
+
label: 'Content Spacing',
|
|
15502
|
+
description: 'Padding/spacing within the content area',
|
|
15503
|
+
validation: {
|
|
15504
|
+
options: [{
|
|
15505
|
+
label: 'Compact',
|
|
15506
|
+
value: 'compact'
|
|
15507
|
+
}, {
|
|
15508
|
+
label: 'Comfortable',
|
|
15509
|
+
value: 'comfortable'
|
|
15510
|
+
}, {
|
|
15511
|
+
label: 'Spacious',
|
|
15512
|
+
value: 'spacious'
|
|
15513
|
+
}]
|
|
15514
|
+
}
|
|
15515
|
+
}), IsOptional(), IsIn(['compact', 'comfortable', 'spacious']), __metadata("design:type", String)], CollapsibleLayoutModel.prototype, "contentSpacing", void 0);
|
|
15516
|
+
CollapsibleLayoutModel = __decorate([Schema('CollapsibleLayout', '1.0.0')], CollapsibleLayoutModel);
|
|
15517
|
+
var CollapsibleLayoutModel$1 = CollapsibleLayoutModel;
|
|
15518
|
+
|
|
15519
|
+
/**
|
|
15520
|
+
* TypeScript type definitions for CollapsibleLayout component
|
|
15521
|
+
*
|
|
15522
|
+
* Provides TypeScript interfaces that extend the schema model with React-specific types
|
|
15523
|
+
* and component-level functionality for the CollapsibleLayout component.
|
|
15524
|
+
*
|
|
15525
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
15526
|
+
*/
|
|
15527
|
+
/**
|
|
15528
|
+
* Type guard to check if a component has CollapsibleLayout props
|
|
15529
|
+
*/
|
|
15530
|
+
function isCollapsibleLayoutProps(props) {
|
|
15531
|
+
return props && typeof props === 'object' && ('collapsed' in props || 'defaultCollapsed' in props);
|
|
15532
|
+
}
|
|
15533
|
+
/**
|
|
15534
|
+
* Default props for CollapsibleLayout component
|
|
15535
|
+
*/
|
|
15536
|
+
const defaultCollapsibleLayoutProps = {
|
|
15537
|
+
// Note: collapsed is intentionally omitted so components can be uncontrolled
|
|
15538
|
+
defaultCollapsed: false,
|
|
15539
|
+
triggerArea: 'both',
|
|
15540
|
+
animationStyle: 'slide',
|
|
15541
|
+
persistState: false,
|
|
15542
|
+
showDivider: true,
|
|
15543
|
+
variant: 'default',
|
|
15544
|
+
headerSpacing: 'comfortable',
|
|
15545
|
+
contentSpacing: 'comfortable',
|
|
15546
|
+
animationDuration: 300,
|
|
15547
|
+
disableAnimations: false,
|
|
15548
|
+
toggleAriaLabel: 'Toggle content visibility'
|
|
15549
|
+
};
|
|
15550
|
+
const animationConfigs = {
|
|
15551
|
+
fade: {
|
|
15552
|
+
duration: 300,
|
|
15553
|
+
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
15554
|
+
opacity: [0, 1]
|
|
15555
|
+
},
|
|
15556
|
+
slide: {
|
|
15557
|
+
duration: 300,
|
|
15558
|
+
easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
15559
|
+
transform: 'translateY(-10px)'
|
|
15560
|
+
},
|
|
15561
|
+
scale: {
|
|
15562
|
+
duration: 200,
|
|
15563
|
+
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
|
|
15564
|
+
transform: 'scale(0.95)',
|
|
15565
|
+
opacity: [0, 1]
|
|
15566
|
+
}
|
|
15567
|
+
};
|
|
15568
|
+
const spacingConfigs = {
|
|
15569
|
+
compact: {
|
|
15570
|
+
padding: '8px 12px',
|
|
15571
|
+
gap: '4px'
|
|
15572
|
+
},
|
|
15573
|
+
comfortable: {
|
|
15574
|
+
padding: '16px 20px',
|
|
15575
|
+
gap: '8px'
|
|
15576
|
+
},
|
|
15577
|
+
spacious: {
|
|
15578
|
+
padding: '24px 32px',
|
|
15579
|
+
gap: '16px'
|
|
15580
|
+
}
|
|
15581
|
+
};
|
|
15582
|
+
|
|
15583
|
+
/**
|
|
15584
|
+
* Custom hook for managing collapsible state - simplified approach
|
|
15585
|
+
*/
|
|
15586
|
+
function useCollapsibleState(controlled, collapsedProp, defaultCollapsedProp, onToggleProp, persistState, storageKey) {
|
|
15587
|
+
const id = useId();
|
|
15588
|
+
const finalStorageKey = storageKey || `collapsible-${id}`;
|
|
15589
|
+
// For controlled components, use the prop; for uncontrolled, use internal state
|
|
15590
|
+
const [internalCollapsed, setInternalCollapsed] = useState(() => {
|
|
15591
|
+
if (controlled) {
|
|
15592
|
+
return collapsedProp ?? false;
|
|
15593
|
+
}
|
|
15594
|
+
// Try localStorage first if persistence is enabled
|
|
15595
|
+
if (persistState && typeof window !== 'undefined') {
|
|
15596
|
+
const stored = localStorage.getItem(finalStorageKey);
|
|
15597
|
+
if (stored !== null) {
|
|
15598
|
+
return JSON.parse(stored);
|
|
15599
|
+
}
|
|
15600
|
+
}
|
|
15601
|
+
return defaultCollapsedProp ?? false;
|
|
15602
|
+
});
|
|
15603
|
+
// Sync with controlled prop changes
|
|
15604
|
+
useEffect(() => {
|
|
15605
|
+
if (controlled && collapsedProp !== undefined) {
|
|
15606
|
+
setInternalCollapsed(collapsedProp);
|
|
15607
|
+
}
|
|
15608
|
+
}, [controlled, collapsedProp]);
|
|
15609
|
+
// Persist to localStorage for uncontrolled components
|
|
15610
|
+
useEffect(() => {
|
|
15611
|
+
if (!controlled && persistState && typeof window !== 'undefined') {
|
|
15612
|
+
localStorage.setItem(finalStorageKey, JSON.stringify(internalCollapsed));
|
|
15613
|
+
}
|
|
15614
|
+
}, [controlled, internalCollapsed, persistState, finalStorageKey]);
|
|
15615
|
+
const toggle = useCallback(() => {
|
|
15616
|
+
const currentState = controlled ? collapsedProp ?? false : internalCollapsed;
|
|
15617
|
+
const newCollapsed = !currentState;
|
|
15618
|
+
// Always update internal state for visual updates
|
|
15619
|
+
setInternalCollapsed(newCollapsed);
|
|
15620
|
+
// Call callback to notify parent
|
|
15621
|
+
onToggleProp?.(newCollapsed);
|
|
15622
|
+
}, [controlled, collapsedProp, internalCollapsed, onToggleProp]);
|
|
15623
|
+
const setCollapsed = useCallback(collapsed => {
|
|
15624
|
+
setInternalCollapsed(collapsed);
|
|
15625
|
+
onToggleProp?.(collapsed);
|
|
15626
|
+
}, [onToggleProp]);
|
|
15627
|
+
// Return the appropriate state
|
|
15628
|
+
const finalCollapsed = controlled ? collapsedProp ?? false : internalCollapsed;
|
|
15629
|
+
return {
|
|
15630
|
+
collapsed: finalCollapsed,
|
|
15631
|
+
toggle,
|
|
15632
|
+
setCollapsed,
|
|
15633
|
+
isControlled: controlled
|
|
15634
|
+
};
|
|
15635
|
+
}
|
|
15636
|
+
/**
|
|
15637
|
+
* Core CollapsibleLayout View component
|
|
15638
|
+
*/
|
|
15639
|
+
function CollapsibleLayoutView({
|
|
15640
|
+
// State props
|
|
15641
|
+
collapsed: collapsedProp,
|
|
15642
|
+
defaultCollapsed = false,
|
|
15643
|
+
onToggle,
|
|
15644
|
+
// Content props
|
|
15645
|
+
title,
|
|
15646
|
+
subtitle,
|
|
15647
|
+
leadIcon,
|
|
15648
|
+
headerActions,
|
|
15649
|
+
collapsedView,
|
|
15650
|
+
children,
|
|
15651
|
+
footerView,
|
|
15652
|
+
// Behavior props
|
|
15653
|
+
triggerArea = 'both',
|
|
15654
|
+
animationStyle = 'slide',
|
|
15655
|
+
persistState = false,
|
|
15656
|
+
storageKey,
|
|
15657
|
+
animationDuration = 300,
|
|
15658
|
+
disableAnimations = false,
|
|
15659
|
+
// Icons
|
|
15660
|
+
collapsedIcon,
|
|
15661
|
+
expandedIcon,
|
|
15662
|
+
// Layout props
|
|
15663
|
+
showDivider = true,
|
|
15664
|
+
variant = 'default',
|
|
15665
|
+
headerSpacing = 'comfortable',
|
|
15666
|
+
contentSpacing = 'comfortable',
|
|
15667
|
+
// Accessibility
|
|
15668
|
+
toggleAriaLabel = 'Toggle content visibility',
|
|
15669
|
+
'aria-describedby': ariaDescribedBy,
|
|
15670
|
+
contentAriaProps = {},
|
|
15671
|
+
// CSS classes
|
|
15672
|
+
containerClassName,
|
|
15673
|
+
headerClassName,
|
|
15674
|
+
contentClassName,
|
|
15675
|
+
footerClassName,
|
|
15676
|
+
...restProps
|
|
15677
|
+
}) {
|
|
15678
|
+
const theme = useTheme$1();
|
|
15679
|
+
const {
|
|
15680
|
+
styleProps,
|
|
15681
|
+
htmlProps,
|
|
15682
|
+
restProps: otherProps
|
|
15683
|
+
} = useBaseProps(restProps);
|
|
15684
|
+
// Mark as QwickApp component
|
|
15685
|
+
CollapsibleLayoutView[QWICKAPP_COMPONENT] = true;
|
|
15686
|
+
// Determine controlled vs uncontrolled usage
|
|
15687
|
+
const controlled = collapsedProp !== undefined;
|
|
15688
|
+
// State management
|
|
15689
|
+
const {
|
|
15690
|
+
collapsed,
|
|
15691
|
+
toggle,
|
|
15692
|
+
setCollapsed
|
|
15693
|
+
} = useCollapsibleState(controlled, collapsedProp, defaultCollapsed, onToggle, persistState, storageKey);
|
|
15694
|
+
// Get spacing configurations
|
|
15695
|
+
const headerSpacingConfig = spacingConfigs[headerSpacing];
|
|
15696
|
+
const contentSpacingConfig = spacingConfigs[contentSpacing];
|
|
15697
|
+
// Get animation configuration
|
|
15698
|
+
const animationConfig = animationConfigs[animationStyle];
|
|
15699
|
+
// Generate unique IDs for accessibility
|
|
15700
|
+
const headerId = useId();
|
|
15701
|
+
const contentId = useId();
|
|
15702
|
+
// Handle click events
|
|
15703
|
+
const handleHeaderClick = useCallback(event => {
|
|
15704
|
+
if (triggerArea === 'header' || triggerArea === 'both') {
|
|
15705
|
+
event.preventDefault();
|
|
15706
|
+
toggle();
|
|
15707
|
+
}
|
|
15708
|
+
}, [triggerArea, toggle]);
|
|
15709
|
+
const handleButtonClick = useCallback(event => {
|
|
15710
|
+
event.stopPropagation();
|
|
15711
|
+
toggle();
|
|
15712
|
+
}, [toggle]);
|
|
15713
|
+
// Render icons
|
|
15714
|
+
const renderIcon = useCallback((icon, defaultIcon) => {
|
|
15715
|
+
if (/*#__PURE__*/React.isValidElement(icon)) {
|
|
15716
|
+
return icon;
|
|
15717
|
+
}
|
|
15718
|
+
if (typeof icon === 'string') {
|
|
15719
|
+
return jsx(Html, {
|
|
15720
|
+
children: icon
|
|
15721
|
+
});
|
|
15722
|
+
}
|
|
15723
|
+
return defaultIcon;
|
|
15724
|
+
}, []);
|
|
15725
|
+
const toggleIcon = renderIcon(collapsed ? collapsedIcon : expandedIcon, collapsed ? jsx(ExpandMore, {}) : jsx(ExpandLess, {}));
|
|
15726
|
+
// Container styles based on variant
|
|
15727
|
+
const containerSx = useMemo(() => {
|
|
15728
|
+
const baseSx = {
|
|
15729
|
+
width: '100%',
|
|
15730
|
+
position: 'relative',
|
|
15731
|
+
...styleProps.sx
|
|
15732
|
+
};
|
|
15733
|
+
switch (variant) {
|
|
15734
|
+
case 'outlined':
|
|
15735
|
+
return {
|
|
15736
|
+
...baseSx,
|
|
15737
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
15738
|
+
borderRadius: 1,
|
|
15739
|
+
backgroundColor: 'var(--theme-surface)'
|
|
15740
|
+
};
|
|
15741
|
+
case 'elevated':
|
|
15742
|
+
return {
|
|
15743
|
+
...baseSx,
|
|
15744
|
+
boxShadow: theme.shadows[2],
|
|
15745
|
+
borderRadius: 1,
|
|
15746
|
+
backgroundColor: theme.palette.background.paper
|
|
15747
|
+
};
|
|
15748
|
+
case 'filled':
|
|
15749
|
+
return {
|
|
15750
|
+
...baseSx,
|
|
15751
|
+
backgroundColor: 'var(--theme-surface-variant)',
|
|
15752
|
+
borderRadius: 1
|
|
15753
|
+
};
|
|
15754
|
+
default:
|
|
15755
|
+
return baseSx;
|
|
15756
|
+
}
|
|
15757
|
+
}, [variant, theme, styleProps.sx]);
|
|
15758
|
+
// Header styles
|
|
15759
|
+
const headerSx = useMemo(() => ({
|
|
15760
|
+
...headerSpacingConfig,
|
|
15761
|
+
cursor: triggerArea === 'header' || triggerArea === 'both' ? 'pointer' : 'default',
|
|
15762
|
+
userSelect: 'none',
|
|
15763
|
+
display: 'flex',
|
|
15764
|
+
alignItems: 'center',
|
|
15765
|
+
justifyContent: 'space-between',
|
|
15766
|
+
'&:hover': triggerArea === 'header' || triggerArea === 'both' ? {
|
|
15767
|
+
backgroundColor: 'rgba(0, 0, 0, 0.04)'
|
|
15768
|
+
} : {}
|
|
15769
|
+
}), [headerSpacingConfig, triggerArea]);
|
|
15770
|
+
// Content styles
|
|
15771
|
+
const contentSx = useMemo(() => ({
|
|
15772
|
+
...contentSpacingConfig
|
|
15773
|
+
}), [contentSpacingConfig]);
|
|
15774
|
+
// Animation props for Collapse component
|
|
15775
|
+
const collapseProps = useMemo(() => {
|
|
15776
|
+
if (disableAnimations) {
|
|
15777
|
+
return {
|
|
15778
|
+
timeout: 0
|
|
15779
|
+
};
|
|
15780
|
+
}
|
|
15781
|
+
const baseProps = {
|
|
15782
|
+
timeout: animationDuration
|
|
15783
|
+
};
|
|
15784
|
+
switch (animationStyle) {
|
|
15785
|
+
case 'fade':
|
|
15786
|
+
return {
|
|
15787
|
+
...baseProps,
|
|
15788
|
+
sx: {
|
|
15789
|
+
'& .MuiCollapse-wrapper': {
|
|
15790
|
+
opacity: collapsed ? 0 : 1,
|
|
15791
|
+
transition: `opacity ${animationDuration}ms ${animationConfig.easing}`
|
|
15792
|
+
}
|
|
15793
|
+
}
|
|
15794
|
+
};
|
|
15795
|
+
case 'scale':
|
|
15796
|
+
return {
|
|
15797
|
+
...baseProps,
|
|
15798
|
+
sx: {
|
|
15799
|
+
'& .MuiCollapse-wrapper': {
|
|
15800
|
+
transform: collapsed ? 'scale(0.95)' : 'scale(1)',
|
|
15801
|
+
opacity: collapsed ? 0 : 1,
|
|
15802
|
+
transition: `all ${animationDuration}ms ${animationConfig.easing}`
|
|
15803
|
+
}
|
|
15804
|
+
}
|
|
15805
|
+
};
|
|
15806
|
+
default:
|
|
15807
|
+
// slide
|
|
15808
|
+
return baseProps;
|
|
15809
|
+
}
|
|
15810
|
+
}, [disableAnimations, animationDuration, animationStyle, animationConfig, collapsed]);
|
|
15811
|
+
// Render content based on type
|
|
15812
|
+
const renderContent = useCallback(content => {
|
|
15813
|
+
if (!content) return null;
|
|
15814
|
+
if (typeof content === 'string') {
|
|
15815
|
+
return jsx(Html, {
|
|
15816
|
+
children: content
|
|
15817
|
+
});
|
|
15818
|
+
}
|
|
15819
|
+
return content;
|
|
15820
|
+
}, []);
|
|
15821
|
+
// Container content that will be wrapped
|
|
15822
|
+
const containerContent = jsxs(Fragment, {
|
|
15823
|
+
children: [(title || subtitle || leadIcon || headerActions || triggerArea === 'button' || triggerArea === 'both') && jsxs(Fragment, {
|
|
15824
|
+
children: [jsxs(Box, {
|
|
15825
|
+
id: headerId,
|
|
15826
|
+
className: headerClassName,
|
|
15827
|
+
sx: headerSx,
|
|
15828
|
+
onClick: handleHeaderClick,
|
|
15829
|
+
role: triggerArea === 'header' || triggerArea === 'both' ? 'button' : undefined,
|
|
15830
|
+
tabIndex: triggerArea === 'header' || triggerArea === 'both' ? 0 : undefined,
|
|
15831
|
+
"aria-expanded": !collapsed,
|
|
15832
|
+
"aria-controls": contentId,
|
|
15833
|
+
"aria-describedby": ariaDescribedBy,
|
|
15834
|
+
onKeyDown: e => {
|
|
15835
|
+
if ((triggerArea === 'header' || triggerArea === 'both') && (e.key === 'Enter' || e.key === ' ')) {
|
|
15836
|
+
e.preventDefault();
|
|
15837
|
+
toggle();
|
|
15838
|
+
}
|
|
15839
|
+
},
|
|
15840
|
+
children: [jsxs(Stack, {
|
|
15841
|
+
direction: "row",
|
|
15842
|
+
spacing: 2,
|
|
15843
|
+
alignItems: "center",
|
|
15844
|
+
sx: {
|
|
15845
|
+
minWidth: 0,
|
|
15846
|
+
flex: 1
|
|
15847
|
+
},
|
|
15848
|
+
children: [leadIcon && jsx(Box, {
|
|
15849
|
+
sx: {
|
|
15850
|
+
flexShrink: 0
|
|
15851
|
+
},
|
|
15852
|
+
children: renderContent(leadIcon)
|
|
15853
|
+
}), (title || subtitle) && jsxs(Box, {
|
|
15854
|
+
sx: {
|
|
15855
|
+
minWidth: 0,
|
|
15856
|
+
flex: 1
|
|
15857
|
+
},
|
|
15858
|
+
children: [title && jsx(Typography, {
|
|
15859
|
+
variant: "h6",
|
|
15860
|
+
component: "h3",
|
|
15861
|
+
sx: {
|
|
15862
|
+
fontWeight: 600,
|
|
15863
|
+
lineHeight: 1.2,
|
|
15864
|
+
...(subtitle && {
|
|
15865
|
+
mb: 0.5
|
|
15866
|
+
})
|
|
15867
|
+
},
|
|
15868
|
+
children: title
|
|
15869
|
+
}), subtitle && jsx(Typography, {
|
|
15870
|
+
variant: "body2",
|
|
15871
|
+
color: "text.secondary",
|
|
15872
|
+
sx: {
|
|
15873
|
+
lineHeight: 1.3
|
|
15874
|
+
},
|
|
15875
|
+
children: subtitle
|
|
15876
|
+
})]
|
|
15877
|
+
})]
|
|
15878
|
+
}), jsxs(Stack, {
|
|
15879
|
+
direction: "row",
|
|
15880
|
+
spacing: 1,
|
|
15881
|
+
alignItems: "center",
|
|
15882
|
+
sx: {
|
|
15883
|
+
flexShrink: 0
|
|
15884
|
+
},
|
|
15885
|
+
children: [headerActions && jsx(Box, {
|
|
15886
|
+
children: renderContent(headerActions)
|
|
15887
|
+
}), jsx(IconButton, {
|
|
15888
|
+
onClick: handleButtonClick,
|
|
15889
|
+
size: "small",
|
|
15890
|
+
"aria-label": toggleAriaLabel,
|
|
15891
|
+
"aria-expanded": !collapsed,
|
|
15892
|
+
"aria-controls": contentId,
|
|
15893
|
+
children: toggleIcon
|
|
15894
|
+
})]
|
|
15895
|
+
})]
|
|
15896
|
+
}), showDivider && jsx(Divider, {})]
|
|
15897
|
+
}), collapsed && collapsedView && jsxs(Fragment, {
|
|
15898
|
+
children: [jsx(Box, {
|
|
15899
|
+
className: contentClassName,
|
|
15900
|
+
sx: contentSx,
|
|
15901
|
+
children: renderContent(collapsedView)
|
|
15902
|
+
}), showDivider && footerView && jsx(Divider, {})]
|
|
15903
|
+
}), jsxs(Collapse, {
|
|
15904
|
+
in: !collapsed,
|
|
15905
|
+
...collapseProps,
|
|
15906
|
+
children: [jsx(Box, {
|
|
15907
|
+
id: contentId,
|
|
15908
|
+
className: contentClassName,
|
|
15909
|
+
sx: contentSx,
|
|
15910
|
+
role: "region",
|
|
15911
|
+
"aria-labelledby": title ? headerId : undefined,
|
|
15912
|
+
...contentAriaProps,
|
|
15913
|
+
children: renderContent(children)
|
|
15914
|
+
}), showDivider && footerView && jsx(Divider, {})]
|
|
15915
|
+
}), footerView && jsx(Box, {
|
|
15916
|
+
className: footerClassName,
|
|
15917
|
+
sx: contentSx,
|
|
15918
|
+
children: renderContent(footerView)
|
|
15919
|
+
})]
|
|
15920
|
+
});
|
|
15921
|
+
// Return appropriate container based on variant
|
|
15922
|
+
if (variant === 'outlined') {
|
|
15923
|
+
return jsx(Paper, {
|
|
15924
|
+
variant: "outlined",
|
|
15925
|
+
elevation: 0,
|
|
15926
|
+
...htmlProps,
|
|
15927
|
+
...otherProps,
|
|
15928
|
+
className: containerClassName,
|
|
15929
|
+
sx: containerSx,
|
|
15930
|
+
children: containerContent
|
|
15931
|
+
});
|
|
15932
|
+
}
|
|
15933
|
+
if (variant === 'elevated') {
|
|
15934
|
+
return jsx(Paper, {
|
|
15935
|
+
elevation: 2,
|
|
15936
|
+
...htmlProps,
|
|
15937
|
+
...otherProps,
|
|
15938
|
+
className: containerClassName,
|
|
15939
|
+
sx: containerSx,
|
|
15940
|
+
children: containerContent
|
|
15941
|
+
});
|
|
15942
|
+
}
|
|
15943
|
+
// Default variant (default, filled)
|
|
15944
|
+
return jsx(Box, {
|
|
15945
|
+
...htmlProps,
|
|
15946
|
+
...otherProps,
|
|
15947
|
+
className: containerClassName,
|
|
15948
|
+
sx: containerSx,
|
|
15949
|
+
children: containerContent
|
|
15950
|
+
});
|
|
15951
|
+
}
|
|
15952
|
+
/**
|
|
15953
|
+
* Main CollapsibleLayout component with data binding support
|
|
15954
|
+
*/
|
|
15955
|
+
function CollapsibleLayout(props) {
|
|
15956
|
+
const {
|
|
15957
|
+
dataSource,
|
|
15958
|
+
bindingOptions,
|
|
15959
|
+
...restProps
|
|
15960
|
+
} = props;
|
|
15961
|
+
// If no dataSource, use traditional props
|
|
15962
|
+
if (!dataSource) {
|
|
15963
|
+
return jsx(CollapsibleLayoutView, {
|
|
15964
|
+
...restProps
|
|
15965
|
+
});
|
|
15966
|
+
}
|
|
15967
|
+
// Use data binding
|
|
15968
|
+
const {
|
|
15969
|
+
dataSource: _source,
|
|
15970
|
+
loading,
|
|
15971
|
+
error,
|
|
15972
|
+
cached,
|
|
15973
|
+
...collapsibleProps
|
|
15974
|
+
} = useDataBinding(dataSource, restProps, CollapsibleLayoutModel$1.getSchema(), {
|
|
15975
|
+
cache: true,
|
|
15976
|
+
cacheTTL: 300000,
|
|
15977
|
+
strict: false,
|
|
15978
|
+
...bindingOptions
|
|
15979
|
+
});
|
|
15980
|
+
// Show loading state
|
|
15981
|
+
if (loading) {
|
|
15982
|
+
return jsx(CollapsibleLayoutView, {
|
|
15983
|
+
...restProps,
|
|
15984
|
+
title: "Loading...",
|
|
15985
|
+
variant: "default",
|
|
15986
|
+
headerSpacing: "comfortable",
|
|
15987
|
+
contentSpacing: "comfortable"
|
|
15988
|
+
});
|
|
15989
|
+
}
|
|
15990
|
+
if (error) {
|
|
15991
|
+
console.error('Error loading collapsible layout:', error);
|
|
15992
|
+
{
|
|
15993
|
+
return jsx(CollapsibleLayoutView, {
|
|
15994
|
+
...restProps,
|
|
15995
|
+
title: "Error Loading Layout",
|
|
15996
|
+
subtitle: error.message,
|
|
15997
|
+
variant: "outlined",
|
|
15998
|
+
headerSpacing: "comfortable",
|
|
15999
|
+
contentSpacing: "comfortable"
|
|
16000
|
+
});
|
|
16001
|
+
}
|
|
16002
|
+
}
|
|
16003
|
+
return jsx(CollapsibleLayoutView, {
|
|
16004
|
+
...collapsibleProps
|
|
16005
|
+
});
|
|
16006
|
+
}
|
|
16007
|
+
// Set default props
|
|
16008
|
+
CollapsibleLayout.defaultProps = defaultCollapsibleLayoutProps;
|
|
16009
|
+
|
|
15337
16010
|
/**
|
|
15338
16011
|
* FeatureCard Schema - Schema definition for FeatureCard component
|
|
15339
16012
|
*
|
|
@@ -16454,7 +17127,9 @@ function ProductCardView({
|
|
|
16454
17127
|
return actions;
|
|
16455
17128
|
};
|
|
16456
17129
|
const displayActions = actions || getDefaultActions();
|
|
16457
|
-
|
|
17130
|
+
// INLINE WRAPPERS REFACTORED: Instead of inline component declarations (which cause remounts),
|
|
17131
|
+
// compute JSX fragments via plain variables/functions and inject directly.
|
|
17132
|
+
const featuresListElement = (() => {
|
|
16458
17133
|
const featuresToShow = variant === 'compact' ? (product.features || []).slice(0, maxFeaturesCompact) : product.features || [];
|
|
16459
17134
|
return jsxs(Box, {
|
|
16460
17135
|
sx: {
|
|
@@ -16514,40 +17189,37 @@ function ProductCardView({
|
|
|
16514
17189
|
})]
|
|
16515
17190
|
})]
|
|
16516
17191
|
});
|
|
16517
|
-
};
|
|
16518
|
-
const
|
|
16519
|
-
|
|
16520
|
-
|
|
17192
|
+
})();
|
|
17193
|
+
const technologiesSectionElement = !showTechnologies || variant === 'compact' ? null : jsxs(Box, {
|
|
17194
|
+
sx: {
|
|
17195
|
+
mb: 3
|
|
17196
|
+
},
|
|
17197
|
+
children: [jsx(Typography, {
|
|
17198
|
+
variant: "h6",
|
|
17199
|
+
component: "h4",
|
|
16521
17200
|
sx: {
|
|
16522
|
-
mb:
|
|
17201
|
+
mb: 1.5,
|
|
17202
|
+
fontSize: '1rem',
|
|
17203
|
+
fontWeight: 600
|
|
16523
17204
|
},
|
|
16524
|
-
children:
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
17205
|
+
children: "Technologies:"
|
|
17206
|
+
}), jsx(Box, {
|
|
17207
|
+
sx: {
|
|
17208
|
+
display: 'flex',
|
|
17209
|
+
flexWrap: 'wrap',
|
|
17210
|
+
gap: 1
|
|
17211
|
+
},
|
|
17212
|
+
children: product.technologies.map((tech, index) => jsx(Chip, {
|
|
17213
|
+
label: tech,
|
|
17214
|
+
variant: "outlined",
|
|
17215
|
+
size: "small",
|
|
16534
17216
|
sx: {
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16540
|
-
|
|
16541
|
-
variant: "outlined",
|
|
16542
|
-
size: "small",
|
|
16543
|
-
sx: {
|
|
16544
|
-
fontSize: '0.8rem',
|
|
16545
|
-
fontWeight: 500
|
|
16546
|
-
}
|
|
16547
|
-
}, index))
|
|
16548
|
-
})]
|
|
16549
|
-
});
|
|
16550
|
-
};
|
|
17217
|
+
fontSize: '0.8rem',
|
|
17218
|
+
fontWeight: 500
|
|
17219
|
+
}
|
|
17220
|
+
}, index))
|
|
17221
|
+
})]
|
|
17222
|
+
});
|
|
16551
17223
|
return jsxs(Box, {
|
|
16552
17224
|
className: styleProps.className || "product-card",
|
|
16553
17225
|
onClick: htmlProps.onClick || (variant === 'compact' ? handleProductClick : undefined),
|
|
@@ -16653,7 +17325,7 @@ function ProductCardView({
|
|
|
16653
17325
|
},
|
|
16654
17326
|
children: variant === 'detailed' ? product.description : product.shortDescription || product.description
|
|
16655
17327
|
})]
|
|
16656
|
-
}),
|
|
17328
|
+
}), featuresListElement, technologiesSectionElement, jsx(Box, {
|
|
16657
17329
|
sx: {
|
|
16658
17330
|
display: 'flex',
|
|
16659
17331
|
gap: 1.5,
|
|
@@ -17514,7 +18186,6 @@ const ThemeProvider = ({
|
|
|
17514
18186
|
}
|
|
17515
18187
|
}
|
|
17516
18188
|
});
|
|
17517
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
17518
18189
|
}, [actualThemeMode, paletteChangeCounter]); // paletteChangeCounter is needed to force theme rebuild // Re-create theme when palette changes
|
|
17519
18190
|
// Theme preference management methods
|
|
17520
18191
|
const setPreferredTheme = theme => {
|
|
@@ -18726,7 +19397,7 @@ function FormBlockView({
|
|
|
18726
19397
|
title,
|
|
18727
19398
|
description,
|
|
18728
19399
|
coverImage,
|
|
18729
|
-
form,
|
|
19400
|
+
children: form,
|
|
18730
19401
|
footer,
|
|
18731
19402
|
status,
|
|
18732
19403
|
message,
|
|
@@ -19727,6 +20398,193 @@ function SelectInputField(props) {
|
|
|
19727
20398
|
// Mark as QwickApp component
|
|
19728
20399
|
SelectInputField[QWICKAPP_COMPONENT] = true;
|
|
19729
20400
|
|
|
20401
|
+
/**
|
|
20402
|
+
* SwitchInputField Schema - Data model for switch input field component
|
|
20403
|
+
*
|
|
20404
|
+
* Copyright (c) 2025 QwickApps.com. All rights reserved.
|
|
20405
|
+
*/
|
|
20406
|
+
let SwitchInputFieldModel = class SwitchInputFieldModel extends Model {};
|
|
20407
|
+
__decorate([Field(), Editor({
|
|
20408
|
+
field_type: FieldType.TEXT,
|
|
20409
|
+
label: 'Label',
|
|
20410
|
+
description: 'The label text for the switch'
|
|
20411
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "label", void 0);
|
|
20412
|
+
__decorate([Field({
|
|
20413
|
+
defaultValue: false
|
|
20414
|
+
}), Editor({
|
|
20415
|
+
field_type: FieldType.BOOLEAN,
|
|
20416
|
+
label: 'Checked',
|
|
20417
|
+
description: 'Whether the switch is checked'
|
|
20418
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "checked", void 0);
|
|
20419
|
+
__decorate([Field({
|
|
20420
|
+
defaultValue: false
|
|
20421
|
+
}), Editor({
|
|
20422
|
+
field_type: FieldType.BOOLEAN,
|
|
20423
|
+
label: 'Required',
|
|
20424
|
+
description: 'Whether the field is required'
|
|
20425
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "required", void 0);
|
|
20426
|
+
__decorate([Field({
|
|
20427
|
+
defaultValue: false
|
|
20428
|
+
}), Editor({
|
|
20429
|
+
field_type: FieldType.BOOLEAN,
|
|
20430
|
+
label: 'Disabled',
|
|
20431
|
+
description: 'Whether the field is disabled'
|
|
20432
|
+
}), IsOptional(), IsBoolean(), __metadata("design:type", Boolean)], SwitchInputFieldModel.prototype, "disabled", void 0);
|
|
20433
|
+
__decorate([Field(), Editor({
|
|
20434
|
+
field_type: FieldType.TEXT,
|
|
20435
|
+
label: 'Error',
|
|
20436
|
+
description: 'Error message to display'
|
|
20437
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "error", void 0);
|
|
20438
|
+
__decorate([Field(), Editor({
|
|
20439
|
+
field_type: FieldType.TEXT,
|
|
20440
|
+
label: 'Helper Text',
|
|
20441
|
+
description: 'Helper text to display below the switch'
|
|
20442
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "helperText", void 0);
|
|
20443
|
+
__decorate([Field({
|
|
20444
|
+
defaultValue: 'medium'
|
|
20445
|
+
}), Editor({
|
|
20446
|
+
field_type: FieldType.SELECT,
|
|
20447
|
+
label: 'Size',
|
|
20448
|
+
description: 'Size of the switch'
|
|
20449
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "size", void 0);
|
|
20450
|
+
__decorate([Field({
|
|
20451
|
+
defaultValue: 'primary'
|
|
20452
|
+
}), Editor({
|
|
20453
|
+
field_type: FieldType.SELECT,
|
|
20454
|
+
label: 'Color',
|
|
20455
|
+
description: 'Color theme of the switch'
|
|
20456
|
+
}), IsOptional(), IsString(), __metadata("design:type", String)], SwitchInputFieldModel.prototype, "color", void 0);
|
|
20457
|
+
SwitchInputFieldModel = __decorate([Schema('SwitchInputField', '1.0.0')], SwitchInputFieldModel);
|
|
20458
|
+
var SwitchInputFieldModel$1 = SwitchInputFieldModel;
|
|
20459
|
+
|
|
20460
|
+
// View component - handles the actual rendering
|
|
20461
|
+
function SwitchInputFieldView({
|
|
20462
|
+
label,
|
|
20463
|
+
checked = false,
|
|
20464
|
+
onChange,
|
|
20465
|
+
onFocus,
|
|
20466
|
+
required = false,
|
|
20467
|
+
disabled = false,
|
|
20468
|
+
error,
|
|
20469
|
+
helperText,
|
|
20470
|
+
size = 'medium',
|
|
20471
|
+
color = 'primary',
|
|
20472
|
+
...restProps
|
|
20473
|
+
}) {
|
|
20474
|
+
const {
|
|
20475
|
+
styleProps,
|
|
20476
|
+
htmlProps
|
|
20477
|
+
} = useBaseProps(restProps);
|
|
20478
|
+
const handleChange = event => {
|
|
20479
|
+
if (onChange) {
|
|
20480
|
+
onChange(event.target.checked);
|
|
20481
|
+
}
|
|
20482
|
+
};
|
|
20483
|
+
return jsxs(FormControl, {
|
|
20484
|
+
...htmlProps,
|
|
20485
|
+
...styleProps,
|
|
20486
|
+
error: !!error,
|
|
20487
|
+
required: required,
|
|
20488
|
+
disabled: disabled,
|
|
20489
|
+
sx: {
|
|
20490
|
+
display: 'block',
|
|
20491
|
+
...styleProps.sx
|
|
20492
|
+
},
|
|
20493
|
+
children: [jsx(FormControlLabel, {
|
|
20494
|
+
control: jsx(Switch, {
|
|
20495
|
+
checked: checked,
|
|
20496
|
+
onChange: handleChange,
|
|
20497
|
+
onFocus: onFocus,
|
|
20498
|
+
size: size,
|
|
20499
|
+
color: color,
|
|
20500
|
+
disabled: disabled
|
|
20501
|
+
}),
|
|
20502
|
+
label: label,
|
|
20503
|
+
disabled: disabled
|
|
20504
|
+
}), (error || helperText) && jsx(FormHelperText, {
|
|
20505
|
+
children: error || helperText
|
|
20506
|
+
})]
|
|
20507
|
+
});
|
|
20508
|
+
}
|
|
20509
|
+
/**
|
|
20510
|
+
* SwitchInputField component with data binding support
|
|
20511
|
+
* Supports both traditional props and dataSource-driven rendering
|
|
20512
|
+
*/
|
|
20513
|
+
function SwitchInputField(props) {
|
|
20514
|
+
const {
|
|
20515
|
+
dataSource,
|
|
20516
|
+
bindingOptions,
|
|
20517
|
+
...restProps
|
|
20518
|
+
} = props;
|
|
20519
|
+
// If no dataSource, use traditional props
|
|
20520
|
+
if (!dataSource) {
|
|
20521
|
+
return jsx(SwitchInputFieldView, {
|
|
20522
|
+
...restProps
|
|
20523
|
+
});
|
|
20524
|
+
}
|
|
20525
|
+
// Use data binding
|
|
20526
|
+
const bindingResult = useDataBinding(dataSource, restProps, SwitchInputFieldModel$1.getSchema(), {
|
|
20527
|
+
cache: true,
|
|
20528
|
+
cacheTTL: 300000,
|
|
20529
|
+
strict: false,
|
|
20530
|
+
...bindingOptions
|
|
20531
|
+
});
|
|
20532
|
+
// Check if we're still loading data using the metadata properties
|
|
20533
|
+
const bindingLoading = bindingResult.$loading;
|
|
20534
|
+
// Extract all the actual switch properties (excluding metadata)
|
|
20535
|
+
const {
|
|
20536
|
+
dataSource: _source,
|
|
20537
|
+
$loading,
|
|
20538
|
+
$error,
|
|
20539
|
+
$dataSource,
|
|
20540
|
+
$cached,
|
|
20541
|
+
cached,
|
|
20542
|
+
...switchInputFieldProps
|
|
20543
|
+
} = bindingResult;
|
|
20544
|
+
const error = bindingResult.$error;
|
|
20545
|
+
// Show loading state while fetching data
|
|
20546
|
+
if (bindingLoading) {
|
|
20547
|
+
return jsxs(Paper, {
|
|
20548
|
+
variant: "outlined",
|
|
20549
|
+
sx: {
|
|
20550
|
+
p: 2,
|
|
20551
|
+
textAlign: 'center'
|
|
20552
|
+
},
|
|
20553
|
+
children: [jsx(Typography, {
|
|
20554
|
+
variant: "body2",
|
|
20555
|
+
children: "Loading SwitchInputField..."
|
|
20556
|
+
}), jsx(Typography, {
|
|
20557
|
+
variant: "caption",
|
|
20558
|
+
color: "text.secondary",
|
|
20559
|
+
children: "Loading switch field configuration from data source..."
|
|
20560
|
+
})]
|
|
20561
|
+
});
|
|
20562
|
+
}
|
|
20563
|
+
if (error) {
|
|
20564
|
+
console.error('Error loading switch input field:', error);
|
|
20565
|
+
{
|
|
20566
|
+
return jsx(Paper, {
|
|
20567
|
+
variant: "outlined",
|
|
20568
|
+
sx: {
|
|
20569
|
+
p: 2,
|
|
20570
|
+
textAlign: 'center',
|
|
20571
|
+
borderColor: 'error.main'
|
|
20572
|
+
},
|
|
20573
|
+
children: jsxs(Typography, {
|
|
20574
|
+
variant: "body2",
|
|
20575
|
+
color: "error",
|
|
20576
|
+
children: ["Error loading switch field: ", error.message]
|
|
20577
|
+
})
|
|
20578
|
+
});
|
|
20579
|
+
}
|
|
20580
|
+
}
|
|
20581
|
+
return jsx(SwitchInputFieldView, {
|
|
20582
|
+
...switchInputFieldProps
|
|
20583
|
+
});
|
|
20584
|
+
}
|
|
20585
|
+
// Mark as QwickApp component
|
|
20586
|
+
SwitchInputField[QWICKAPP_COMPONENT] = true;
|
|
20587
|
+
|
|
19730
20588
|
const TextField = /*#__PURE__*/React.forwardRef((props, ref) => {
|
|
19731
20589
|
const {
|
|
19732
20590
|
gridProps,
|
|
@@ -20223,7 +21081,7 @@ const FormPage = ({
|
|
|
20223
21081
|
title: title,
|
|
20224
21082
|
description: description,
|
|
20225
21083
|
coverImage: coverImage,
|
|
20226
|
-
|
|
21084
|
+
children: form,
|
|
20227
21085
|
footer: footer,
|
|
20228
21086
|
status: status,
|
|
20229
21087
|
message: message,
|
|
@@ -25006,4 +25864,4 @@ var ActionType;
|
|
|
25006
25864
|
ActionType["CANCEL"] = "cancel";
|
|
25007
25865
|
})(ActionType || (ActionType = {}));
|
|
25008
25866
|
|
|
25009
|
-
export { AVAILABLE_PALETTES, AccessibilityProvider, ActionModel, ActionType, AllPalettes, Article, ArticleModel, BasePage, Breadcrumbs, Button, CardListGrid, CardListGridModel, ChoiceInputField, ChoiceInputFieldModel, Code, CodeModel, 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, 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, useAccessibility, useBaseProps, useBreadcrumbs, useData, useDataBinding, useDataContext, useDataProvider, useDimensions, usePalette, useQwickApp, useResolveTemplate, useSafeLocation, useSafeNavigate, useTemplate, useTheme, withAccessibility, withErrorBoundary };
|
|
25867
|
+
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 };
|