cedro 0.1.9 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +7 -4
  2. package/dist/cedro-logo.png +0 -0
  3. package/dist/fangio.jpg +0 -0
  4. package/package.json +4 -2
  5. package/src/core/application.builder.tsx +121 -60
  6. package/src/core/application.core.tsx +110 -11
  7. package/src/core/themes.core.ts +160 -1
  8. package/src/core/uid.ts +3 -3
  9. package/src/interfaces/application.interface.ts +3 -2
  10. package/src/interfaces/widget.interface.ts +3 -0
  11. package/src/types/select.item.type.ts +11 -0
  12. package/src/ui/Icon.ui.tsx +158 -0
  13. package/src/ui/IconButton.ui.tsx +51 -9
  14. package/src/ui/{textbox.ui.tsx → Textbox.ui.tsx} +23 -15
  15. package/src/ui/accordion.ui.tsx +152 -0
  16. package/src/ui/button.ui.tsx +56 -14
  17. package/src/ui/buttonColor.ui.tsx +87 -0
  18. package/src/ui/buttonmenu.ui.tsx +134 -0
  19. package/src/ui/{buttonstack.ui.ts → buttonstack.ui.tsx} +67 -1
  20. package/src/ui/checkbox.ui.tsx +9 -13
  21. package/src/ui/container.ui.tsx +141 -76
  22. package/src/ui/datagrid.ui.tsx +518 -0
  23. package/src/ui/dialog.tsx +143 -56
  24. package/src/ui/hpanel.ui.tsx +37 -11
  25. package/src/ui/iconButtonMenu.ui.tsx +176 -0
  26. package/src/ui/image.ui.tsx +123 -112
  27. package/src/ui/index.ts +8 -8
  28. package/src/ui/label.ui.tsx +61 -3
  29. package/src/ui/loading.ui.ts +10 -10
  30. package/src/ui/menu.ui.ts +2 -2
  31. package/src/ui/progressbar.ui.tsx +9 -8
  32. package/src/ui/{radiobutton.tsx → radiobutton.ui.tsx} +9 -13
  33. package/src/ui/scroll.ui.ts +13 -12
  34. package/src/ui/select.ui.tsx +143 -0
  35. package/src/ui/styles/button.css +114 -32
  36. package/src/ui/styles/buttoncolor.css +8 -8
  37. package/src/ui/styles/container.css +29 -0
  38. package/src/ui/styles/icon.css +29 -0
  39. package/src/ui/styles/image.css +19 -19
  40. package/src/ui/styles/label.css +63 -0
  41. package/src/ui/styles/loading.css +12 -12
  42. package/src/ui/styles/main.css +5 -0
  43. package/src/ui/styles/progressbar.css +2 -1
  44. package/src/ui/styles/select.css +13 -0
  45. package/src/ui/styles/stackbutton.css +36 -0
  46. package/src/ui/styles/tabs.css +5 -7
  47. package/src/ui/styles/textarea.css +13 -13
  48. package/src/ui/switch.ui.tsx +9 -13
  49. package/src/ui/tabs.ui.tsx +43 -22
  50. package/src/ui/textarea.ui.tsx +48 -0
  51. package/src/ui/toolbar.ui.tsx +17 -12
  52. package/src/ui/valuebar.ui.tsx +11 -13
  53. package/src/ui/vpanel.ui.tsx +19 -13
  54. package/src/ui/widget.builder.ts +243 -159
  55. package/src/ui/widget.collection.ts +24 -2
  56. package/src/ui/widget.ui.ts +79 -19
  57. package/src/ui/Icon.ui.ts +0 -64
  58. package/src/ui/accordion.ui.ts +0 -71
  59. package/src/ui/buttonColor.ui.ts +0 -24
  60. package/src/ui/buttonmenu.ui.ts +0 -59
  61. package/src/ui/datagrid.ui.ts +0 -231
  62. package/src/ui/iconButtonMenu.ui.ts +0 -59
  63. package/src/ui/select.ui.ts +0 -73
  64. package/src/ui/textarea.ui.ts +0 -20
  65. /package/src/ui/{toggle.ui.ts → toggle.ui.tsx} +0 -0
package/src/core/uid.ts CHANGED
@@ -1,3 +1,3 @@
1
- export function UID(): string {
2
- return "w-uid-" + Date.now().toString(36) + "-" + Math.random().toString(36);
3
- }
1
+ export function UID(): string {
2
+ return "w-uid-" + Date.now().toString(36) + "-" + Math.random().toString(36);
3
+ }
@@ -4,7 +4,6 @@ import { IWidget, WUICallback, WUIEvent } from "./widget.interface";
4
4
  import { Dialog } from "../ui/dialog";
5
5
  import { Seo } from "../core/seo";
6
6
  import { ThemeManager } from "../core/themes.core";
7
- import { Vector2D } from "src/types/vector2d.type";
8
7
 
9
8
  export interface IScreenSize {
10
9
  minWidth: number;
@@ -30,6 +29,8 @@ export interface IApplication {
30
29
 
31
30
  theme: ThemeManager;
32
31
 
32
+ loadedModule: any;
33
+
33
34
  attachWidget(guest: IWidget, host: IWidget): void;
34
35
 
35
36
  subscribe: (cb: WUICallback) => void;
@@ -48,7 +49,7 @@ export interface IApplication {
48
49
  getRoot(): IWidget;
49
50
 
50
51
  confirm(msg: string): void;
51
- alert(msg: string): void;
52
+ alert(title: string, msg: string): void;
52
53
 
53
54
  showLoading(): void;
54
55
  hideLoading(): void;
@@ -13,6 +13,8 @@ export type WUIEvent =
13
13
  | "mouseleave"
14
14
  | "option-clicked"
15
15
  | "wheel"
16
+ | "render"
17
+ | "scroll"
16
18
  | "drag";
17
19
 
18
20
  export type WUICallback = {
@@ -111,6 +113,7 @@ export interface IWidget {
111
113
  getOverflow(): boolean;
112
114
 
113
115
  addChild(child: IWidget | null): void;
116
+ populate(): void;
114
117
  disableSelection(): void;
115
118
  display(): void;
116
119
  enableSelection(): void;
@@ -0,0 +1,11 @@
1
+ export class SelectItem {
2
+ id: string;
3
+ label: string;
4
+ icon: string;
5
+
6
+ constructor(id: string, label: string, icon: string) {
7
+ this.id = id;
8
+ this.label = label;
9
+ this.icon = icon;
10
+ }
11
+ }
@@ -0,0 +1,158 @@
1
+ import "./styles/icon.css";
2
+ import { Colors } from "./colors.ui";
3
+ import { normalizeWidget, WidgetProps } from "./widget.builder";
4
+ import { connectWidgetCallback, getOnlyEventProps, Widget } from "./widget.ui";
5
+ import { UID } from "../core/uid";
6
+
7
+ export type IconVariants = "Filled" | "Outlined" | "Round" | "Sharp" | "Two Tone";
8
+ export type IconSizes = "small" | "medium" | "large" | "xlarge";
9
+
10
+ const iconSizesMap = {
11
+ small: "md-18",
12
+ medium: "md-24",
13
+ large: "md-36",
14
+ xlarge: "md-48",
15
+ };
16
+
17
+ const iconPixelSizesMap = {
18
+ small: "18px",
19
+ medium: "24px",
20
+ large: "36px",
21
+ xlarge: "48px",
22
+ };
23
+
24
+ export class Icon extends Widget {
25
+ variant: IconVariants;
26
+ color: Colors | null = null;
27
+ iconSize: IconSizes = "medium";
28
+ icon: string;
29
+
30
+ constructor(
31
+ id: string,
32
+ icon: string,
33
+ variant: IconVariants = "Filled",
34
+ parent: Widget | null = null
35
+ ) {
36
+ super(id, "span", parent);
37
+
38
+ this.variant = variant;
39
+ this.setColor("primary");
40
+ this.icon = icon;
41
+
42
+ this.setIconSize("medium");
43
+
44
+ if (this.variant === "Filled") {
45
+ this.addClass("material-icons");
46
+ } else {
47
+ this.addClass(
48
+ "material-icons-" + this.variant.toString().replace(" ", "-").toLowerCase()
49
+ );
50
+ }
51
+
52
+ this.setIcon(icon);
53
+
54
+ this.init();
55
+ }
56
+
57
+ public init(): void {
58
+ super.init();
59
+ }
60
+
61
+ public setIconSize(size: IconSizes = "medium"): void {
62
+ if (this.iconSize !== size) {
63
+ this.deleteClass(iconSizesMap[this.iconSize]);
64
+ }
65
+
66
+ this.iconSize = size;
67
+ this.addClass(iconSizesMap[size]);
68
+
69
+ this.body.style.fontSize = iconPixelSizesMap[size];
70
+ }
71
+
72
+ public setIcon(icon: string): void {
73
+ this.icon = icon;
74
+ this.body.innerHTML = icon;
75
+ }
76
+
77
+ public setVariant(variant: IconVariants = "Filled"): void {
78
+ this.variant = variant;
79
+ }
80
+
81
+ public setColor(color: Colors = "primary"): void {
82
+ if (this.color !== color) {
83
+ this.deleteClass("WUI-icon-color-" + this.color);
84
+ }
85
+
86
+ this.addClass("WUI-icon-color-" + color);
87
+
88
+ this.color = color;
89
+ }
90
+
91
+ public getVariant(): IconVariants {
92
+ return this.variant;
93
+ }
94
+
95
+ public getColor(): Colors {
96
+ return this.color || "primary";
97
+ }
98
+
99
+ public getIcon(): string {
100
+ return this.icon;
101
+ }
102
+
103
+ public getIconSize(): IconSizes {
104
+ return this.iconSize;
105
+ }
106
+
107
+ public getRequiredWidth(): number {
108
+ const sizeString = iconPixelSizesMap[this.iconSize];
109
+ const size = parseInt(sizeString.split("px")[0]);
110
+ return size;
111
+ }
112
+ }
113
+
114
+ export type wIconProps = WidgetProps & {
115
+ icon: string;
116
+ variant?: IconVariants | null;
117
+ color?: Colors | null;
118
+ size?: IconSizes | null;
119
+ };
120
+
121
+ export const WIcon = (props: wIconProps) => {
122
+ if (!props.id) {
123
+ props.id = "Icon." + UID();
124
+ }
125
+
126
+ connectWidgetCallback(props.id, getOnlyEventProps(props));
127
+
128
+ return normalizeWidget(
129
+ <div
130
+ id={props.id}
131
+ w-icon
132
+ w-icon-name={props.icon}
133
+ w-variant={props.variant}
134
+ w-color={props.color}
135
+ w-size={props.size}
136
+ ></div>,
137
+ props
138
+ );
139
+ };
140
+
141
+ export function createIcon(id: string, content: any, parent: Widget | null = null): Icon {
142
+ const dataIcon = content.getAttribute("w-icon-name");
143
+ const dataVariant = content.getAttribute("w-variant") || "Filled";
144
+ const dataColor = content.getAttribute("w-color") || "primary";
145
+ const dataSize = content.getAttribute("w-size") || "medium";
146
+
147
+ let newIcon = new Icon(id, dataIcon, dataVariant, parent);
148
+
149
+ if (dataColor) {
150
+ newIcon.setColor(dataColor);
151
+ }
152
+
153
+ if (dataSize) {
154
+ newIcon.setIconSize(dataSize);
155
+ }
156
+
157
+ return newIcon;
158
+ }
@@ -9,6 +9,8 @@ import {
9
9
  import { Button, wButtonProps } from "./button.ui";
10
10
  import { Icon } from "./Icon.ui";
11
11
  import { Label } from "./label.ui";
12
+ import { normalizeWidget } from "./widget.builder";
13
+ import { UID } from "../core/uid";
12
14
 
13
15
  export class IconButton extends Button {
14
16
  icon: Icon;
@@ -16,10 +18,13 @@ export class IconButton extends Button {
16
18
 
17
19
  showIcon: boolean;
18
20
  showText: boolean;
21
+ centerX: boolean;
19
22
 
20
23
  constructor(id: string, icon: string = "dark_mode", parent: Widget | null = null) {
21
24
  super(id, parent);
22
25
 
26
+ this.centerX = false;
27
+
23
28
  this.setAlign(WidgetAlignTypes.HORIZONTAL);
24
29
  this.icon = new Icon(id + ".icon", icon, undefined, this);
25
30
  this.label = new Label(id + ".label", undefined, this);
@@ -30,6 +35,16 @@ export class IconButton extends Button {
30
35
  this.init();
31
36
  }
32
37
 
38
+ protected updateRequiredWidth(): void {
39
+ if (!this.label) return;
40
+ if (!this.icon) return;
41
+
42
+ const labelWidth = this.label.getRequiredWidth();
43
+ const iconWith = this.icon.getRequiredWidth();
44
+
45
+ this.requiredWidth = labelWidth + iconWith + 70;
46
+ }
47
+
33
48
  public displayIcon(): void {
34
49
  this.showIcon = true;
35
50
  this.icon.setVisible(true);
@@ -66,7 +81,8 @@ export class IconButton extends Button {
66
81
  public render(): void {
67
82
  super.render();
68
83
 
69
- const iconWidth = 24;
84
+ const labelWidth = this.label.getRequiredWidth();
85
+ const iconWidth = this.icon.getRequiredWidth();
70
86
  const padding = 5;
71
87
 
72
88
  if (this.onlyIcon()) {
@@ -81,10 +97,23 @@ export class IconButton extends Button {
81
97
  this.label.getBody().style.position = "absolute";
82
98
  this.icon.getBody().style.position = "absolute";
83
99
 
100
+ const availableWidth = this.getW() - padding * 5; //Doble padding a la derecha e izquierda y uno de separacion entre label y icon.
101
+ const requiredWidth = labelWidth + iconWidth + padding * 5;
102
+
84
103
  const labelHeight = this.label.getBody().clientHeight;
85
104
 
86
- const startX = padding; //this.getBody().clientWidth / 2 - (iconWidth + labelWidth) / 2;
105
+ let startX = availableWidth / 2 - (iconWidth + padding + labelWidth) / 2;
106
+
107
+ if (availableWidth < requiredWidth) {
108
+ startX = padding * 2;
109
+ }
110
+
111
+ if (!this.centerX) {
112
+ startX = padding * 2;
113
+ }
114
+
87
115
  const startLabelX = startX + iconWidth + padding;
116
+
88
117
  let startY = this.getH() / 2 - iconWidth / 2;
89
118
  let startLabelY = this.getH() / 2 - labelHeight / 2;
90
119
 
@@ -112,10 +141,16 @@ export class IconButton extends Button {
112
141
  public setText(text: string): void {
113
142
  //super.setText(text);
114
143
  this.label.setText(text);
144
+ this.updateRequiredWidth();
115
145
  }
116
146
 
117
147
  public setIcon(icon: string): void {
118
148
  this.icon.setIcon(icon);
149
+ this.updateRequiredWidth();
150
+ }
151
+
152
+ public setCenterX(centerX: boolean): void {
153
+ this.centerX = centerX;
119
154
  }
120
155
  }
121
156
 
@@ -123,12 +158,17 @@ export type wIconButtonProps = Omit<wButtonProps, "text"> & {
123
158
  icon?: string | null;
124
159
  text?: string | null;
125
160
  onlyIcon?: boolean | null;
161
+ centerX?: boolean | null;
126
162
  };
127
163
 
128
164
  export const WIconButton = (props: wIconButtonProps) => {
165
+ if (!props.id) {
166
+ props.id = "IconButton." + UID();
167
+ }
168
+
129
169
  connectWidgetCallback(props.id, getOnlyEventProps(props));
130
170
 
131
- return (
171
+ return normalizeWidget(
132
172
  <button
133
173
  id={props.id}
134
174
  w-icon-button
@@ -139,12 +179,9 @@ export const WIconButton = (props: wIconButtonProps) => {
139
179
  w-color={props.color}
140
180
  w-width={props.width}
141
181
  w-height={props.height}
142
- w-class={props.classNames}
143
- w-orientation={props.orientation}
144
- w-fixed-size={props.fixedSize}
145
- w-padding={props.padding}
146
- w-type={props.type}
147
- />
182
+ w-center-x={props.centerX}
183
+ />,
184
+ props
148
185
  );
149
186
  };
150
187
 
@@ -160,6 +197,7 @@ export function createIconButton(
160
197
  const dataWidth = content.getAttribute("w-width");
161
198
  const dataHeight = content.getAttribute("w-height");
162
199
  const dataOnlyIcon = content.getAttribute("w-only-icon");
200
+ const dataCenterX = content.getAttribute("w-center-x");
163
201
 
164
202
  let newIconButton = new IconButton(id, dataIcon, parent);
165
203
 
@@ -187,5 +225,9 @@ export function createIconButton(
187
225
  newIconButton.onlyIcon();
188
226
  }
189
227
 
228
+ if (dataCenterX) {
229
+ newIconButton.setCenterX(true);
230
+ }
231
+
190
232
  return newIconButton;
191
233
  }
@@ -1,6 +1,7 @@
1
- import { WidgetProps } from "./widget.builder";
1
+ import { normalizeWidget, WidgetProps } from "./widget.builder";
2
2
  import "./styles/textbox.css";
3
3
  import { Widget, WidgetTypes, connectWidgetCallback, getOnlyEventProps } from "./widget.ui";
4
+ import { UID } from "../core/uid";
4
5
 
5
6
  export type InputTypes =
6
7
  | "text"
@@ -53,7 +54,7 @@ export class Textbox extends Widget {
53
54
  this.getBody().style.overflow = "";
54
55
  }
55
56
 
56
- getValue(): string {
57
+ public getValue(): string {
57
58
  const value = (this.input.getBody() as HTMLInputElement).value;
58
59
 
59
60
  if (value) return value;
@@ -61,7 +62,7 @@ export class Textbox extends Widget {
61
62
  return "";
62
63
  }
63
64
 
64
- setValue(value: string): void {
65
+ public setValue(value: string): void {
65
66
  (this.input.getBody() as HTMLInputElement).value = value;
66
67
  this.positionLabel();
67
68
  }
@@ -114,17 +115,17 @@ export class Textbox extends Widget {
114
115
  super.render();
115
116
  }
116
117
 
117
- setTitle(title: string): void {
118
+ public setTitle(title: string): void {
118
119
  this.title = title;
119
120
  this.label.getBody().innerHTML = this.title;
120
121
  }
121
122
 
122
- setInputType(type: InputTypes): void {
123
+ public setInputType(type: InputTypes): void {
123
124
  this.inputType = type;
124
125
  this.input.getBody().setAttribute("type", this.inputType);
125
126
  }
126
127
 
127
- getTitle(): string {
128
+ public getTitle(): string {
128
129
  return this.title;
129
130
  }
130
131
 
@@ -132,11 +133,11 @@ export class Textbox extends Widget {
132
133
  return this.label;
133
134
  }*/
134
135
 
135
- getInput(): Widget {
136
+ public getInput(): Widget {
136
137
  return this.input;
137
138
  }
138
139
 
139
- getInputType(): string {
140
+ public getInputType(): string {
140
141
  return this.inputType;
141
142
  }
142
143
  }
@@ -146,25 +147,27 @@ export type wTextBoxProps = WidgetProps & {
146
147
  inputType?: InputTypes | null;
147
148
  width?: number | null;
148
149
  height?: number | null;
150
+ value?: string | null;
149
151
  };
150
152
 
151
153
  export const WTextbox = (props: wTextBoxProps) => {
154
+ if (!props.id) {
155
+ props.id = "Textbox." + UID();
156
+ }
157
+
152
158
  connectWidgetCallback(props.id, getOnlyEventProps(props));
153
159
 
154
- return (
160
+ return normalizeWidget(
155
161
  <input
156
162
  id={props.id}
157
163
  w-textbox
158
164
  w-title={props.title}
165
+ w-value={props.value}
159
166
  w-input-type={props.inputType}
160
167
  w-width={props.width}
161
168
  w-height={props.height}
162
- w-class={props.classNames}
163
- w-orientation={props.orientation}
164
- w-fixed-size={props.fixedSize}
165
- w-padding={props.padding}
166
- w-type={props.type}
167
- />
169
+ />,
170
+ props
168
171
  );
169
172
  };
170
173
 
@@ -172,6 +175,7 @@ export function createTextbox(id: string, content: any, parent: Widget | null =
172
175
  let newTextbox = new Textbox(id, parent);
173
176
 
174
177
  const dataTitle = content.getAttribute("w-title");
178
+ const dataValue = content.getAttribute("w-value");
175
179
  const dataInputType = content.getAttribute("w-input-type");
176
180
  const dataWidth = content.getAttribute("w-width");
177
181
  const dataHeight = content.getAttribute("w-height");
@@ -188,6 +192,10 @@ export function createTextbox(id: string, content: any, parent: Widget | null =
188
192
  newTextbox.setInitialH(dataHeight);
189
193
  }
190
194
 
195
+ if (dataValue) {
196
+ newTextbox.setValue(dataValue);
197
+ }
198
+
191
199
  newTextbox.setTitle(dataTitle);
192
200
 
193
201
  return newTextbox;
@@ -0,0 +1,152 @@
1
+ import "./styles/accordion.css";
2
+ import { IconButton } from "./IconButton.ui";
3
+ import { Label } from "./label.ui";
4
+ import { Widget, WidgetTypes } from "./widget.ui";
5
+ import { createWidget, normalizeWidget, WidgetProps } from "./widget.builder";
6
+ import { UID } from "../core/uid";
7
+
8
+ const ACCORDION_HEADER_HEIGHT = 40;
9
+
10
+ type AccordionItem = {
11
+ header: Widget;
12
+ content: Widget;
13
+ };
14
+
15
+ export class Accordion extends Widget {
16
+ items: Map<string, AccordionItem>;
17
+ selectedItemId: string | null;
18
+ constructor(id: string, parent: Widget | null = null) {
19
+ super(id, "div", parent);
20
+
21
+ this.items = new Map<string, AccordionItem>();
22
+
23
+ this.selectedItemId = null;
24
+
25
+ this.addClass("WUIAccordion");
26
+ }
27
+
28
+ public selectItem(id: string): void {
29
+ this.fixItemsType();
30
+
31
+ const selected = this.items.get(id);
32
+
33
+ if (this.selectedItemId !== null) {
34
+ //deseleccionamos
35
+ const previous = this.items.get(this.selectedItemId);
36
+
37
+ if (previous) {
38
+ previous.content.setFixedSize(0);
39
+ }
40
+ }
41
+
42
+ if (selected) {
43
+ this.selectedItemId = id;
44
+ selected.content.setFixedSize(null);
45
+ }
46
+
47
+ this.render();
48
+ }
49
+
50
+ private fixItemsType(): void {
51
+ this.items.forEach((item) => {
52
+ item.header.deleteClass("WUIFixPosition");
53
+ item.header.addClass("WUINonFreePosition");
54
+ item.content.deleteClass("WUIFixPosition");
55
+ item.content.addClass("WUINonFreePosition");
56
+ });
57
+ }
58
+
59
+ public addItem(title: string, icon: string, content: Widget): string {
60
+ const headerId = this.id + ".item." + Array.from(this.items.entries()).length + ".header";
61
+ const header = icon !== "" ? new IconButton(headerId, icon) : new Label(headerId);
62
+
63
+ header.setType(WidgetTypes.FILL);
64
+ header.setFixedSize(ACCORDION_HEADER_HEIGHT);
65
+ header.setText(title);
66
+
67
+ header.deleteClass("WUIFixPosition");
68
+ header.addClass("WUINonFreePosition");
69
+
70
+ header.subscribe({
71
+ event: "click",
72
+ then: (_e, _w) => {
73
+ this.selectItem(headerId);
74
+ },
75
+ });
76
+
77
+ content.setType(WidgetTypes.FILL);
78
+ content.setFixedSize(0);
79
+
80
+ this.items.set(headerId, { header, content });
81
+
82
+ this.addChild(header);
83
+ this.addChild(content);
84
+
85
+ return headerId;
86
+ }
87
+ }
88
+
89
+ export type WAccordionProps = WidgetProps & {
90
+ children: any;
91
+ };
92
+
93
+ export type WAccordionItemProps = {
94
+ title?: string | null;
95
+ icon?: string | null;
96
+ children: any;
97
+ };
98
+
99
+ export const WAccordion = (props: WAccordionProps) => {
100
+ if (!props.id) {
101
+ props.id = "Accordion." + UID();
102
+ }
103
+
104
+ return normalizeWidget(
105
+ <div id={props.id} w-accordion>
106
+ {props.children}
107
+ </div>,
108
+ props
109
+ );
110
+ };
111
+
112
+ export const WAccordionItem = (props: WAccordionItemProps) => {
113
+ return (
114
+ <div w-accordion-item w-title={props.title} w-icon={props.icon}>
115
+ {props.children}
116
+ </div>
117
+ );
118
+ };
119
+
120
+ export function createAccordion(id: string, content: any, parent: Widget | null = null): Accordion {
121
+ let newAccordion = new Accordion(id, parent);
122
+ let firstWidgetId = "";
123
+
124
+ content.childNodes.forEach((accordionItem: HTMLElement, _index: number) => {
125
+ if (accordionItem.getAttribute("w-accordion-item") !== null) {
126
+ const accordionTitle = accordionItem.getAttribute("w-title");
127
+ const accordionIcon = accordionItem.getAttribute("w-icon");
128
+
129
+ if (!accordionItem.firstChild) {
130
+ throw new Error("Accordion Item must have a content");
131
+ }
132
+
133
+ const widget = createWidget(accordionItem.firstChild);
134
+
135
+ if (widget !== null) {
136
+ const itemId = newAccordion.addItem(
137
+ accordionTitle || "Untitled",
138
+ accordionIcon || "",
139
+ widget
140
+ );
141
+
142
+ if (firstWidgetId === "") {
143
+ firstWidgetId = itemId;
144
+ }
145
+ }
146
+ }
147
+ });
148
+
149
+ newAccordion.selectItem(firstWidgetId);
150
+
151
+ return newAccordion;
152
+ }