flet-box 0.0.0-stage → 1.0.2

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 (178) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +190 -2
  3. package/bin/cli.js +394 -0
  4. package/bin/commands/buildAndroid.js +200 -0
  5. package/bin/commands/buildIOS.js +237 -0
  6. package/bin/commands/create.js +406 -0
  7. package/bin/commands/createBundle.js +375 -0
  8. package/bin/commands/createComponent.js +115 -0
  9. package/bin/commands/createScreen.js +161 -0
  10. package/bin/commands/killServer.js +107 -0
  11. package/bin/commands/package.js +131 -0
  12. package/bin/commands/release.js +189 -0
  13. package/bin/commands/runBundle.js +62 -0
  14. package/bin/commands/runCloudflare.js +89 -0
  15. package/bin/commands/runNative.js +109 -0
  16. package/bin/commands/runServer.js +390 -0
  17. package/bin/ota/loader.js +361 -0
  18. package/bin/utils/bundleConfig.js +178 -0
  19. package/bin/utils/capacitor.js +137 -0
  20. package/bin/utils/colors.js +215 -0
  21. package/bin/utils/helpers.js +80 -0
  22. package/bin/utils/spinner.js +96 -0
  23. package/bin/utils/templates.js +1824 -0
  24. package/bin/utils/version.js +108 -0
  25. package/package.json +58 -4
  26. package/src/animations/AnimatedBox.js +607 -0
  27. package/src/animations/AnimatedText.js +105 -0
  28. package/src/animations/MatrixRain.js +220 -0
  29. package/src/animations/ParallaxBox.js +369 -0
  30. package/src/animations/animate.js +332 -0
  31. package/src/animations/index.js +25 -0
  32. package/src/app.js +41 -0
  33. package/src/assets/icon-1024-maskable.png +0 -0
  34. package/src/assets/icon-192-maskable.png +0 -0
  35. package/src/assets/icon-192.png +0 -0
  36. package/src/assets/icon-512-maskable.png +0 -0
  37. package/src/assets/icon-512.png +0 -0
  38. package/src/assets/logo.png +0 -0
  39. package/src/core/App.js +44 -0
  40. package/src/core/hmr-client.js +142 -0
  41. package/src/core/index.js +34 -0
  42. package/src/core/pwa.js +100 -0
  43. package/src/core/runApp.js +430 -0
  44. package/src/create-index.sh +237 -0
  45. package/src/fonts/MaterialIcons-Regular.woff2 +0 -0
  46. package/src/fonts/icons.css +23 -0
  47. package/src/index.d.ts +1930 -0
  48. package/src/index.js +288 -0
  49. package/src/navigations/AdaptiveScaffold.js +149 -0
  50. package/src/navigations/AppBar.js +331 -0
  51. package/src/navigations/BottomNavigation.js +298 -0
  52. package/src/navigations/CollapsibleSideBar.js +139 -0
  53. package/src/navigations/Drawer.js +333 -0
  54. package/src/navigations/DrawerItem.js +260 -0
  55. package/src/navigations/Router.js +475 -0
  56. package/src/navigations/Scaffold.js +537 -0
  57. package/src/navigations/Tabs.js +384 -0
  58. package/src/navigations/index.js +57 -0
  59. package/src/services/RamStore.js +213 -0
  60. package/src/services/Session.js +310 -0
  61. package/src/services/Storage.js +309 -0
  62. package/src/services/http.js +350 -0
  63. package/src/services/index.js +57 -0
  64. package/src/tools/animation.js +42 -0
  65. package/src/tools/array.js +95 -0
  66. package/src/tools/border.js +28 -0
  67. package/src/tools/clipboard.js +104 -0
  68. package/src/tools/color.js +329 -0
  69. package/src/tools/createList.js +215 -0
  70. package/src/tools/delay.js +55 -0
  71. package/src/tools/device.js +138 -0
  72. package/src/tools/dict.js +297 -0
  73. package/src/tools/dimensions.js +118 -0
  74. package/src/tools/filter.js +41 -0
  75. package/src/tools/flex.js +26 -0
  76. package/src/tools/gradient.js +34 -0
  77. package/src/tools/grid.js +57 -0
  78. package/src/tools/index.js +38 -0
  79. package/src/tools/mapList.js +107 -0
  80. package/src/tools/margin.js +93 -0
  81. package/src/tools/memo.js +60 -0
  82. package/src/tools/os.js +104 -0
  83. package/src/tools/padding.js +93 -0
  84. package/src/tools/print.js +69 -0
  85. package/src/tools/random.js +299 -0
  86. package/src/tools/ref.js +70 -0
  87. package/src/tools/rgba.js +4 -0
  88. package/src/tools/shadow.js +23 -0
  89. package/src/tools/string.js +85 -0
  90. package/src/tools/time.js +674 -0
  91. package/src/tools/transform.js +68 -0
  92. package/src/tools/transition.js +48 -0
  93. package/src/tools/useState.js +268 -0
  94. package/src/tools/uuid.js +42 -0
  95. package/src/utils/TextInputValidator.js +256 -0
  96. package/src/utils/composeUpdate.js +65 -0
  97. package/src/utils/getWidgetProps.js +35 -0
  98. package/src/utils/index.js +76 -0
  99. package/src/utils/markdownParser.js +368 -0
  100. package/src/utils/mediaTime.js +79 -0
  101. package/src/utils/navigation.js +263 -0
  102. package/src/utils/scriptInjector.js +73 -0
  103. package/src/utils/stackPosition.js +31 -0
  104. package/src/utils/stopWebRefresh.js +77 -0
  105. package/src/utils/styleInjector.js +38 -0
  106. package/src/utils/syntaxHighlight.js +339 -0
  107. package/src/utils/themes.js +347 -0
  108. package/src/utils/units.js +87 -0
  109. package/src/utils/visualEffects.js +169 -0
  110. package/src/widget-factory/addChildren.js +114 -0
  111. package/src/widget-factory/assignProps.js +256 -0
  112. package/src/widget-factory/createWidget.js +28 -0
  113. package/src/widget-factory/effects.js +132 -0
  114. package/src/widget-factory/index.js +7 -0
  115. package/src/widget-factory/lifecycle.js +210 -0
  116. package/src/widget-factory/makeParentable.js +89 -0
  117. package/src/widget-factory/pixTool.js +40 -0
  118. package/src/widget-factory/processProps.js +122 -0
  119. package/src/widget-factory/reactivity.js +98 -0
  120. package/src/widget-factory/remTool.js +34 -0
  121. package/src/widget-factory/stackPosition.js +87 -0
  122. package/src/widget-factory/stringTool.js +26 -0
  123. package/src/widget-factory/tools.js +249 -0
  124. package/src/widget-factory/translateProps.js +1049 -0
  125. package/src/widget-factory/warnings.js +284 -0
  126. package/src/widget-factory/widgetFactory.js +200 -0
  127. package/src/widgets/Accordion.js +562 -0
  128. package/src/widgets/AdMob.js +315 -0
  129. package/src/widgets/AdSense.js +268 -0
  130. package/src/widgets/AlertDialog.js +162 -0
  131. package/src/widgets/Audio.js +311 -0
  132. package/src/widgets/Avatar.js +210 -0
  133. package/src/widgets/Badge.js +189 -0
  134. package/src/widgets/BottomSheet.js +287 -0
  135. package/src/widgets/Button.js +247 -0
  136. package/src/widgets/Card.js +33 -0
  137. package/src/widgets/Carousel.js +301 -0
  138. package/src/widgets/Chart.js +632 -0
  139. package/src/widgets/Checkbox.js +106 -0
  140. package/src/widgets/Chip.js +153 -0
  141. package/src/widgets/CircularBar.js +352 -0
  142. package/src/widgets/CircularChart.js +549 -0
  143. package/src/widgets/CodeViewer.js +236 -0
  144. package/src/widgets/Column.js +29 -0
  145. package/src/widgets/Container.js +31 -0
  146. package/src/widgets/DataTable.js +257 -0
  147. package/src/widgets/Divider.js +93 -0
  148. package/src/widgets/DraggBox.js +115 -0
  149. package/src/widgets/Dropdown.js +505 -0
  150. package/src/widgets/DroppBox.js +180 -0
  151. package/src/widgets/FloatingActionButton.js +91 -0
  152. package/src/widgets/GridView.js +20 -0
  153. package/src/widgets/Icon.js +33 -0
  154. package/src/widgets/Image.js +15 -0
  155. package/src/widgets/Input.js +565 -0
  156. package/src/widgets/Inspector.js +254 -0
  157. package/src/widgets/InstallButton.js +110 -0
  158. package/src/widgets/ListTile.js +224 -0
  159. package/src/widgets/ListView.js +503 -0
  160. package/src/widgets/Markdown.js +1236 -0
  161. package/src/widgets/Modal.js +496 -0
  162. package/src/widgets/Pagination.js +195 -0
  163. package/src/widgets/ProgressBar.js +178 -0
  164. package/src/widgets/QRCode.js +467 -0
  165. package/src/widgets/Radio.js +132 -0
  166. package/src/widgets/Rating.js +261 -0
  167. package/src/widgets/Row.js +29 -0
  168. package/src/widgets/Skeleton.js +243 -0
  169. package/src/widgets/Slider.js +527 -0
  170. package/src/widgets/SnackBar.js +227 -0
  171. package/src/widgets/Stack.js +29 -0
  172. package/src/widgets/Stepper.js +296 -0
  173. package/src/widgets/Switch.js +102 -0
  174. package/src/widgets/Text.js +98 -0
  175. package/src/widgets/Tooltip.js +267 -0
  176. package/src/widgets/TreeView.js +370 -0
  177. package/src/widgets/Video.js +92 -0
  178. package/src/widgets/index.js +52 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * @file CodeViewer.js
3
+ * @description Read-only code block with line numbers and syntax highlighting.
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { colors } from "../utils/themes.js";
7
+ import { generateHighlightedHtml } from "../utils/syntaxHighlight.js";
8
+
9
+ export const CodeViewer = (props) => {
10
+ const {
11
+ code = "",
12
+ title,
13
+ maxHeight = 400,
14
+ fontSize = 12,
15
+ backgroundColor = colors.gray100,
16
+ padding = 12,
17
+ borderRadius = 8,
18
+ showHeader = true,
19
+ showLineNumbers = false,
20
+ startingLineNumber = 1,
21
+ lineNumberWidth = 40,
22
+ lineNumberColor = colors.secondary,
23
+ ...rest
24
+ } = props;
25
+
26
+ let currentCode =
27
+ typeof code === "string" ? code : JSON.stringify(code, null, 2);
28
+ let currentTitle = title;
29
+ let headerRef = null;
30
+ let scrollWrapperRef = null;
31
+ let lineNumbersColRef = null;
32
+ let codeColRef = null;
33
+ let codeWrapperRef = null;
34
+
35
+ const refreshContent = () => {
36
+ const lines = currentCode.split("\n");
37
+ const highlightedLines = lines.map((line) => generateHighlightedHtml(line));
38
+
39
+ if (showLineNumbers) {
40
+ // Update line numbers
41
+ if (lineNumbersColRef) {
42
+ lineNumbersColRef.innerHTML = "";
43
+ for (let i = 0; i < lines.length; i++) {
44
+ const numberDiv = WidgetFactory({
45
+ tag: "div",
46
+ padding: `0 ${padding / 2}px 0 ${padding}px`,
47
+ whiteSpace: "pre",
48
+ textContent: String(startingLineNumber + i),
49
+ });
50
+ lineNumbersColRef.appendChild(numberDiv);
51
+ }
52
+ }
53
+
54
+ // Update code
55
+ if (codeColRef) {
56
+ codeColRef.innerHTML = "";
57
+ for (let i = 0; i < lines.length; i++) {
58
+ const lineDiv = WidgetFactory({
59
+ tag: "div",
60
+ whiteSpace: "pre",
61
+ minHeight: "1.5em",
62
+ });
63
+ lineDiv.innerHTML = highlightedLines[i] || "&nbsp;";
64
+ codeColRef.appendChild(lineDiv);
65
+ }
66
+ }
67
+ } else {
68
+ // Update code without line numbers
69
+ if (codeWrapperRef) {
70
+ codeWrapperRef.innerHTML = highlightedLines.join("\n");
71
+ }
72
+ }
73
+ };
74
+
75
+ const container = WidgetFactory({
76
+ tag: "div",
77
+ widgetName: "CodeViewer",
78
+ width: "100%",
79
+ display: "flex",
80
+ flexDirection: "column",
81
+ ...rest,
82
+ });
83
+
84
+ // Header
85
+ if (currentTitle && showHeader) {
86
+ headerRef = WidgetFactory({
87
+ tag: "div",
88
+ padding: "8px 12px",
89
+ backgroundColor: colors.primary,
90
+ borderRadius: `${borderRadius}px ${borderRadius}px 0 0`,
91
+ color: "#fff",
92
+ fontSize: "14px",
93
+ fontWeight: "bold",
94
+ textContent: currentTitle,
95
+ });
96
+ container.appendChild(headerRef);
97
+ }
98
+
99
+ // Scroll wrapper
100
+ scrollWrapperRef = WidgetFactory({
101
+ tag: "div",
102
+ backgroundColor,
103
+ borderRadius: currentTitle
104
+ ? `0 0 ${borderRadius}px ${borderRadius}px`
105
+ : `${borderRadius}px`,
106
+ overflow: "auto",
107
+ maxHeight: typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight,
108
+ overflowX: "auto",
109
+ overflowY: "auto",
110
+ });
111
+
112
+ // Build content according to showLineNumbers
113
+ if (showLineNumbers) {
114
+ const flexContainer = WidgetFactory({
115
+ tag: "div",
116
+ display: "flex",
117
+ flexDirection: "row",
118
+ minWidth: "100%",
119
+ width: "fit-content",
120
+ });
121
+
122
+ lineNumbersColRef = WidgetFactory({
123
+ tag: "div",
124
+ backgroundColor,
125
+ borderRight: `1px solid ${colors.border}`,
126
+ padding: `${padding}px 0`,
127
+ fontFamily: "monospace",
128
+ fontSize: typeof fontSize === "number" ? `${fontSize}px` : fontSize,
129
+ lineHeight: "1.5",
130
+ textAlign: "right",
131
+ color: lineNumberColor,
132
+ userSelect: "none",
133
+ width: `${lineNumberWidth}px`,
134
+ flexShrink: 0,
135
+ });
136
+
137
+ codeColRef = WidgetFactory({
138
+ tag: "div",
139
+ padding: `${padding}px`,
140
+ fontFamily: "monospace",
141
+ fontSize: typeof fontSize === "number" ? `${fontSize}px` : fontSize,
142
+ lineHeight: "1.5",
143
+ whiteSpace: "pre",
144
+ flex: 1,
145
+ overflowX: "visible",
146
+ });
147
+
148
+ flexContainer.appendChild(lineNumbersColRef);
149
+ flexContainer.appendChild(codeColRef);
150
+ scrollWrapperRef.appendChild(flexContainer);
151
+
152
+ // Sync scroll
153
+ const syncScroll = () => {
154
+ if (lineNumbersColRef) lineNumbersColRef.scrollTop = codeColRef.scrollTop;
155
+ };
156
+ codeColRef.addEventListener("scroll", syncScroll);
157
+
158
+ scrollWrapperRef.onUnmount(() => {
159
+ codeColRef.removeEventListener("scroll", syncScroll);
160
+ });
161
+ } else {
162
+ codeWrapperRef = WidgetFactory({
163
+ tag: "div",
164
+ padding: typeof padding === "number" ? `${padding}px` : padding,
165
+ fontFamily: "monospace",
166
+ fontSize: typeof fontSize === "number" ? `${fontSize}px` : fontSize,
167
+ whiteSpace: "pre",
168
+ lineHeight: "1.5",
169
+ });
170
+ scrollWrapperRef.appendChild(codeWrapperRef);
171
+ }
172
+
173
+ container.appendChild(scrollWrapperRef);
174
+
175
+ // Fill initial content
176
+ const lines = currentCode.split("\n");
177
+ const highlightedLines = lines.map((line) => generateHighlightedHtml(line));
178
+
179
+ if (showLineNumbers) {
180
+ for (let i = 0; i < lines.length; i++) {
181
+ const numberDiv = WidgetFactory({
182
+ tag: "div",
183
+ padding: `0 ${padding / 2}px 0 ${padding}px`,
184
+ whiteSpace: "pre",
185
+ textContent: String(startingLineNumber + i),
186
+ });
187
+ lineNumbersColRef.appendChild(numberDiv);
188
+ }
189
+
190
+ for (let i = 0; i < lines.length; i++) {
191
+ const lineDiv = WidgetFactory({
192
+ tag: "div",
193
+ whiteSpace: "pre",
194
+ minHeight: "1.5em",
195
+ });
196
+ lineDiv.innerHTML = highlightedLines[i] || "&nbsp;";
197
+ codeColRef.appendChild(lineDiv);
198
+ }
199
+ } else {
200
+ codeWrapperRef.innerHTML = highlightedLines.join("\n");
201
+ }
202
+
203
+ // ========== PUBLIC METHODS ==========
204
+ container.updateCode = (newCode) => {
205
+ currentCode =
206
+ typeof newCode === "string" ? newCode : JSON.stringify(newCode, null, 2);
207
+ refreshContent();
208
+ };
209
+
210
+ container.updateTitle = (newTitle) => {
211
+ currentTitle = newTitle;
212
+ if (headerRef) {
213
+ headerRef.textContent = currentTitle;
214
+ }
215
+ };
216
+
217
+ container.scrollTo = (x, y) => {
218
+ if (scrollWrapperRef) {
219
+ scrollWrapperRef.scrollLeft = x;
220
+ scrollWrapperRef.scrollTop = y;
221
+ }
222
+ };
223
+
224
+ container.scrollToStart = () => {
225
+ if (scrollWrapperRef) scrollWrapperRef.scrollLeft = 0;
226
+ };
227
+
228
+ container.scrollToEnd = () => {
229
+ if (scrollWrapperRef)
230
+ scrollWrapperRef.scrollLeft = scrollWrapperRef.scrollWidth;
231
+ };
232
+
233
+ return container;
234
+ };
235
+
236
+ export default CodeViewer;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @file Column.js
3
+ * @description Vertical flex layout container (default `flex-direction: column`).
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+
7
+ export const Column = (props = {}) => {
8
+ const {
9
+ display = "flex",
10
+ flexDirection = "column",
11
+ width = "100%",
12
+ height = "auto",
13
+ boxSizing = "border-box",
14
+ ...rest
15
+ } = props;
16
+
17
+ return WidgetFactory({
18
+ tag: "div",
19
+ widgetName: "Column",
20
+ display: display,
21
+ flexDirection: flexDirection,
22
+ width: width,
23
+ height: height,
24
+ boxSizing: boxSizing,
25
+ ...rest,
26
+ });
27
+ };
28
+
29
+ export default Column;
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @file Container.js
3
+ * @description General-purpose surface container: flex column with overflow and
4
+ * the theme's surface background by default.
5
+ */
6
+ import { WidgetFactory } from "../widget-factory/index.js";
7
+ import { colors } from "../utils/themes.js";
8
+
9
+ export const Container = (props = {}) => {
10
+ const {
11
+ display = "flex",
12
+ flexDirection = "column",
13
+ overflow = "auto",
14
+ boxSizing = "border-box",
15
+ bgColor = colors.surface,
16
+ ...rest
17
+ } = props;
18
+
19
+ return WidgetFactory({
20
+ tag: "div",
21
+ widgetName: "Container",
22
+ display: display,
23
+ flexDirection: flexDirection,
24
+ overflow: overflow,
25
+ boxSizing: boxSizing,
26
+ backgroundColor: bgColor,
27
+ ...rest,
28
+ });
29
+ };
30
+
31
+ export default Container;
@@ -0,0 +1,257 @@
1
+ /**
2
+ * @file DataTable.js
3
+ * @description Table renderer with configurable columns and rows.
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { colors } from "../utils/themes.js";
7
+
8
+ export const DataTable = (props) => {
9
+ const {
10
+ columns,
11
+ rows,
12
+ striped = true,
13
+ hoverable = true,
14
+ bordered = true,
15
+ onRowClick,
16
+
17
+ // ========== COLOR PROPS ==========
18
+ headerBgColor = colors.gray100,
19
+ headerTextColor = colors.text,
20
+ headerFontWeight = "bold",
21
+ headerFontSize = 14,
22
+
23
+ rowBgColor = "transparent",
24
+ rowTextColor = colors.text,
25
+ rowFontSize = 13,
26
+
27
+ stripedRowBgColor = colors.gray50,
28
+
29
+ hoverRowBgColor = `${colors.primary}10`,
30
+
31
+ borderColor = colors.border,
32
+ borderWidth = 1,
33
+
34
+ cellPadding = "10px 12px",
35
+ headerCellPadding = "12px",
36
+
37
+ // ========== OTHER PROPS ==========
38
+ ...rest
39
+ } = props;
40
+
41
+ // Main container with WidgetFactory
42
+ const container = WidgetFactory({
43
+ widgetName: "DataTable",
44
+ width: "100%",
45
+ overflowX: "auto",
46
+ ...rest,
47
+ });
48
+
49
+ // Createste table element
50
+ const table = document.createElement("table");
51
+ table.style.width = "100%";
52
+ table.style.borderCollapse = "collapse";
53
+ table.style.border = bordered
54
+ ? `${borderWidth}px solid ${borderColor}`
55
+ : "none";
56
+
57
+ // ========== HEADER ==========
58
+ const thead = document.createElement("thead");
59
+ const headerRow = document.createElement("tr");
60
+
61
+ for (const col of columns) {
62
+ const th = document.createElement("th");
63
+ th.textContent = typeof col === "string" ? col : col.label;
64
+ th.style.padding = headerCellPadding;
65
+ th.style.textAlign = "left";
66
+ th.style.borderBottom = `2px solid ${borderColor}`;
67
+ th.style.backgroundColor = headerBgColor;
68
+ th.style.color = headerTextColor;
69
+ th.style.fontWeight = headerFontWeight;
70
+ th.style.fontSize =
71
+ typeof headerFontSize === "number"
72
+ ? `${headerFontSize}px`
73
+ : headerFontSize;
74
+
75
+ // Custom alignment per column
76
+ if (typeof col !== "string" && col.align) {
77
+ th.style.textAlign = col.align;
78
+ }
79
+
80
+ headerRow.appendChild(th);
81
+ }
82
+ thead.appendChild(headerRow);
83
+ table.appendChild(thead);
84
+
85
+ // ========== BODY ==========
86
+ const tbody = document.createElement("tbody");
87
+
88
+ rows.forEach((row, index) => {
89
+ const tr = document.createElement("tr");
90
+
91
+ // Row background color (striped or normal)
92
+ if (striped && index % 2 === 1) {
93
+ tr.style.backgroundColor = stripedRowBgColor;
94
+ } else {
95
+ tr.style.backgroundColor = rowBgColor;
96
+ }
97
+
98
+ // Hover effect
99
+ if (hoverable) {
100
+ tr.style.transition = "background-color 0.2s";
101
+ tr.addEventListener("mouseenter", () => {
102
+ tr.style.backgroundColor = hoverRowBgColor;
103
+ });
104
+ tr.addEventListener("mouseleave", () => {
105
+ tr.style.backgroundColor =
106
+ striped && index % 2 === 1 ? stripedRowBgColor : rowBgColor;
107
+ });
108
+ }
109
+
110
+ // Row click handler
111
+ if (onRowClick) {
112
+ tr.style.cursor = "pointer";
113
+ tr.addEventListener("click", () => onRowClick(row, index));
114
+ }
115
+
116
+ // Cells
117
+ for (const col of columns) {
118
+ const td = document.createElement("td");
119
+ const key = typeof col === "string" ? col : col.key;
120
+ const value = row[key];
121
+
122
+ td.textContent = value !== undefined ? String(value) : "";
123
+ td.style.padding = cellPadding;
124
+ td.style.borderBottom = `${borderWidth}px solid ${borderColor}`;
125
+ td.style.color = rowTextColor;
126
+ td.style.fontSize =
127
+ typeof rowFontSize === "number" ? `${rowFontSize}px` : rowFontSize;
128
+
129
+ // Custom alignment per column
130
+ if (typeof col !== "string" && col.align) {
131
+ td.style.textAlign = col.align;
132
+ }
133
+
134
+ // Custom formatter per column
135
+ if (
136
+ typeof col !== "string" &&
137
+ col.format &&
138
+ typeof col.format === "function"
139
+ ) {
140
+ td.textContent = col.format(value, row);
141
+ }
142
+
143
+ tr.appendChild(td);
144
+ }
145
+ tbody.appendChild(tr);
146
+ });
147
+ table.appendChild(tbody);
148
+
149
+ container.appendChild(table);
150
+
151
+ // ========== PUBLIC METHODS ==========
152
+
153
+ // Update table data
154
+ container.updateData = (newRows) => {
155
+ rows.length = 0;
156
+ rows.push(...newRows);
157
+
158
+ // Rebuild body
159
+ const newTbody = document.createElement("tbody");
160
+
161
+ newRows.forEach((row, index) => {
162
+ const tr = document.createElement("tr");
163
+
164
+ if (striped && index % 2 === 1) {
165
+ tr.style.backgroundColor = stripedRowBgColor;
166
+ } else {
167
+ tr.style.backgroundColor = rowBgColor;
168
+ }
169
+
170
+ if (hoverable) {
171
+ tr.style.transition = "background-color 0.2s";
172
+ tr.addEventListener("mouseenter", () => {
173
+ tr.style.backgroundColor = hoverRowBgColor;
174
+ });
175
+ tr.addEventListener("mouseleave", () => {
176
+ tr.style.backgroundColor =
177
+ striped && index % 2 === 1 ? stripedRowBgColor : rowBgColor;
178
+ });
179
+ }
180
+
181
+ if (onRowClick) {
182
+ tr.style.cursor = "pointer";
183
+ tr.addEventListener("click", () => onRowClick(row, index));
184
+ }
185
+
186
+ for (const col of columns) {
187
+ const td = document.createElement("td");
188
+ const key = typeof col === "string" ? col : col.key;
189
+ const value = row[key];
190
+
191
+ td.textContent = value !== undefined ? String(value) : "";
192
+ td.style.padding = cellPadding;
193
+ td.style.borderBottom = `${borderWidth}px solid ${borderColor}`;
194
+ td.style.color = rowTextColor;
195
+ td.style.fontSize =
196
+ typeof rowFontSize === "number" ? `${rowFontSize}px` : rowFontSize;
197
+
198
+ if (typeof col !== "string" && col.align) {
199
+ td.style.textAlign = col.align;
200
+ }
201
+
202
+ if (
203
+ typeof col !== "string" &&
204
+ col.format &&
205
+ typeof col.format === "function"
206
+ ) {
207
+ td.textContent = col.format(value, row);
208
+ }
209
+
210
+ tr.appendChild(td);
211
+ }
212
+ newTbody.appendChild(tr);
213
+ });
214
+
215
+ table.replaceChild(newTbody, tbody);
216
+ };
217
+
218
+ // Update table columns
219
+ container.updateColumns = (newColumns) => {
220
+ columns.length = 0;
221
+ columns.push(...newColumns);
222
+
223
+ // Rebuild header
224
+ const newThead = document.createElement("thead");
225
+ const newHeaderRow = document.createElement("tr");
226
+
227
+ for (const col of newColumns) {
228
+ const th = document.createElement("th");
229
+ th.textContent = typeof col === "string" ? col : col.label;
230
+ th.style.padding = headerCellPadding;
231
+ th.style.textAlign = "left";
232
+ th.style.borderBottom = `2px solid ${borderColor}`;
233
+ th.style.backgroundColor = headerBgColor;
234
+ th.style.color = headerTextColor;
235
+ th.style.fontWeight = headerFontWeight;
236
+ th.style.fontSize =
237
+ typeof headerFontSize === "number"
238
+ ? `${headerFontSize}px`
239
+ : headerFontSize;
240
+
241
+ if (typeof col !== "string" && col.align) {
242
+ th.style.textAlign = col.align;
243
+ }
244
+
245
+ newHeaderRow.appendChild(th);
246
+ }
247
+ newThead.appendChild(newHeaderRow);
248
+ table.replaceChild(newThead, thead);
249
+
250
+ // Rebuild body with existing rows
251
+ container.updateData(rows);
252
+ };
253
+
254
+ return container;
255
+ };
256
+
257
+ export default DataTable;
@@ -0,0 +1,93 @@
1
+ /**
2
+ * @file Divider.js
3
+ * @description Horizontal/vertical rule with configurable thickness and margins.
4
+ */
5
+ import { WidgetFactory } from "../widget-factory/index.js";
6
+ import { colors } from "../utils/themes.js";
7
+
8
+ export const Divider = (props = {}) => {
9
+ const {
10
+ color = colors.surface,
11
+ thickness = 1,
12
+ margin = 16,
13
+ orientation = "horizontal",
14
+ width = "100%",
15
+ height = "100%",
16
+ flexShrink = 0,
17
+ marginTop: propMarginTop,
18
+ marginBottom: propMarginBottom,
19
+ marginLeft: propMarginLeft,
20
+ marginRight: propMarginRight,
21
+ ...rest
22
+ } = props;
23
+
24
+ const isHorizontal = orientation === "horizontal";
25
+
26
+ // Determine margin values with proper priority:
27
+ // 1. Individual props (marginTop, marginBottom, etc.)
28
+ // 2. margin object (margin.top, margin.bottom, etc.)
29
+ // 3. margin number (applied to all sides)
30
+ // 4. Default values
31
+
32
+ let finalMarginTop = propMarginTop ?? 0;
33
+ let finalMarginBottom = propMarginBottom ?? 0;
34
+ let finalMarginLeft = propMarginLeft ?? 0;
35
+ let finalMarginRight = propMarginRight ?? 0;
36
+
37
+ if (typeof margin === "number") {
38
+ if (isHorizontal) {
39
+ finalMarginTop = margin;
40
+ finalMarginBottom = margin;
41
+ } else {
42
+ finalMarginLeft = margin;
43
+ finalMarginRight = margin;
44
+ }
45
+ } else if (margin && typeof margin === "object") {
46
+ if (isHorizontal) {
47
+ finalMarginTop = margin.top ?? finalMarginTop;
48
+ finalMarginBottom = margin.bottom ?? finalMarginBottom;
49
+ } else {
50
+ finalMarginLeft = margin.left ?? finalMarginLeft;
51
+ finalMarginRight = margin.right ?? finalMarginRight;
52
+ }
53
+ }
54
+
55
+ // If margin is a string, use it directly (overrides everything)
56
+ const useMarginString = typeof margin === "string";
57
+
58
+ // Createste widget
59
+ const widget = WidgetFactory({
60
+ tag: "div",
61
+ widgetName: "Divider",
62
+ backgroundColor: color,
63
+ flexShrink: flexShrink,
64
+ ...rest,
65
+ });
66
+
67
+ // Apply divider-specific props
68
+ if (isHorizontal) {
69
+ widget.update({
70
+ height: thickness,
71
+ width: width,
72
+ marginTop: finalMarginTop,
73
+ marginBottom: finalMarginBottom,
74
+ });
75
+ } else {
76
+ widget.update({
77
+ width: thickness,
78
+ height: height,
79
+ minHeight: 1,
80
+ marginLeft: finalMarginLeft,
81
+ marginRight: finalMarginRight,
82
+ });
83
+ }
84
+
85
+ // If margin is a string, apply it directly (overrides individual margins)
86
+ if (useMarginString) {
87
+ widget.update({ margin: margin });
88
+ }
89
+
90
+ return widget;
91
+ };
92
+
93
+ export default Divider;