lexgui 8.1.2 → 8.2.1

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/build/components/AlertDialog.d.ts +7 -7
  2. package/build/components/Avatar.d.ts +15 -0
  3. package/build/components/Counter.d.ts +9 -9
  4. package/build/components/Dialog.d.ts +20 -20
  5. package/build/components/Footer.d.ts +14 -14
  6. package/build/components/Menubar.d.ts +59 -59
  7. package/build/components/NodeTree.d.ts +26 -1
  8. package/build/components/Vector.d.ts +1 -0
  9. package/build/core/Area.d.ts +143 -143
  10. package/build/core/Event.d.ts +0 -20
  11. package/build/core/Namespace.js +1 -1
  12. package/build/core/Namespace.js.map +1 -1
  13. package/build/core/Panel.d.ts +538 -538
  14. package/build/extensions/AssetView.d.ts +137 -136
  15. package/build/extensions/AssetView.js +193 -155
  16. package/build/extensions/AssetView.js.map +1 -1
  17. package/build/extensions/Audio.js +163 -163
  18. package/build/extensions/Audio.js.map +1 -1
  19. package/build/extensions/CodeEditor.d.ts +358 -350
  20. package/build/extensions/CodeEditor.js +302 -270
  21. package/build/extensions/CodeEditor.js.map +1 -1
  22. package/build/extensions/DocMaker.d.ts +27 -27
  23. package/build/extensions/DocMaker.js +15 -11
  24. package/build/extensions/DocMaker.js.map +1 -1
  25. package/build/extensions/GraphEditor.js +2754 -2760
  26. package/build/extensions/GraphEditor.js.map +1 -1
  27. package/build/extensions/ImUi.js +227 -227
  28. package/build/extensions/Timeline.d.ts +668 -670
  29. package/build/extensions/Timeline.js +71 -79
  30. package/build/extensions/Timeline.js.map +1 -1
  31. package/build/extensions/VideoEditor.d.ts +38 -16
  32. package/build/extensions/VideoEditor.js +294 -180
  33. package/build/extensions/VideoEditor.js.map +1 -1
  34. package/build/extensions/index.d.ts +8 -8
  35. package/build/extensions/index.js +10 -10
  36. package/build/index.all.d.ts +2 -2
  37. package/build/index.css.d.ts +3 -4
  38. package/build/index.d.ts +57 -56
  39. package/build/lexgui.all.js +1877 -1520
  40. package/build/lexgui.all.js.map +1 -1
  41. package/build/lexgui.all.min.js +1 -1
  42. package/build/lexgui.all.module.js +1875 -1516
  43. package/build/lexgui.all.module.js.map +1 -1
  44. package/build/lexgui.all.module.min.js +1 -1
  45. package/build/lexgui.css +6123 -5556
  46. package/build/lexgui.js +997 -814
  47. package/build/lexgui.js.map +1 -1
  48. package/build/lexgui.min.css +2 -3
  49. package/build/lexgui.min.js +1 -1
  50. package/build/lexgui.module.js +995 -810
  51. package/build/lexgui.module.js.map +1 -1
  52. package/build/lexgui.module.min.js +1 -1
  53. package/changelog.md +65 -2
  54. package/demo.js +167 -65
  55. package/examples/all-components.html +40 -55
  56. package/examples/asset-view.html +27 -0
  57. package/examples/code-editor.html +12 -1
  58. package/examples/dialogs.html +13 -2
  59. package/examples/editor.html +9 -49
  60. package/examples/index.html +2 -2
  61. package/examples/side-bar.html +1 -1
  62. package/examples/timeline.html +2 -2
  63. package/examples/video-editor.html +1 -1
  64. package/examples/video-editor2.html +2 -2
  65. package/package.json +7 -4
@@ -1,4 +1,6 @@
1
1
  // This is a generated file. Do not edit.
2
+ import { extendTailwindMerge } from 'https://cdn.jsdelivr.net/npm/tailwind-merge@3.4.0/+esm';
3
+
2
4
  // Namespace.ts @jxarco
3
5
  /**
4
6
  * Main namespace
@@ -10,7 +12,7 @@ const g = globalThis;
10
12
  let LX = g.LX;
11
13
  if (!LX) {
12
14
  LX = {
13
- version: '8.1.2',
15
+ version: '8.2.1',
14
16
  ready: false,
15
17
  extensions: [], // Store extensions used
16
18
  extraCommandbarEntries: [], // User specific entries for command bar
@@ -121,8 +123,7 @@ const RAW_ICONS = {
121
123
  'M432 48L208 48c-17.7 0-32 14.3-32 32l0 16-48 0 0-16c0-44.2 35.8-80 80-80L432 0c44.2 0 80 35.8 80 80l0 224c0 44.2-35.8 80-80 80l-16 0 0-48 16 0c17.7 0 32-14.3 32-32l0-224c0-17.7-14.3-32-32-32zM48 448c0 8.8 7.2 16 16 16l256 0c8.8 0 16-7.2 16-16l0-192L48 256l0 192zM64 128l256 0c35.3 0 64 28.7 64 64l0 256c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 192c0-35.3 28.7-64 64-64z'],
122
124
  'WindowMaximize': [512, 512, [], 'solid',
123
125
  'M.3 89.5C.1 91.6 0 93.8 0 96L0 224 0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-192 0-128c0-35.3-28.7-64-64-64L64 32c-2.2 0-4.4 .1-6.5 .3c-9.2 .9-17.8 3.8-25.5 8.2C21.8 46.5 13.4 55.1 7.7 65.5c-3.9 7.3-6.5 15.4-7.4 24zM48 224l416 0 0 192c0 8.8-7.2 16-16 16L64 432c-8.8 0-16-7.2-16-16l0-192z'],
124
- 'WindowMinimize': [512, 512, [], 'solid',
125
- 'M24 432c-13.3 0-24 10.7-24 24s10.7 24 24 24l464 0c13.3 0 24-10.7 24-24s-10.7-24-24-24L24 432z'],
126
+ 'WindowMinimize': [512, 512, [], 'solid', 'M24 432c-13.3 0-24 10.7-24 24s10.7 24 24 24l464 0c13.3 0 24-10.7 24-24s-10.7-24-24-24L24 432z'],
126
127
  'VrCardboard': [640, 512, ['VR'], 'solid',
127
128
  'M576 64L64 64C28.7 64 0 92.7 0 128L0 384c0 35.3 28.7 64 64 64l120.4 0c24.2 0 46.4-13.7 57.2-35.4l32-64c8.8-17.5 26.7-28.6 46.3-28.6s37.5 11.1 46.3 28.6l32 64c10.8 21.7 33 35.4 57.2 35.4L576 448c35.3 0 64-28.7 64-64l0-256c0-35.3-28.7-64-64-64zM96 240a64 64 0 1 1 128 0A64 64 0 1 1 96 240zm384-64a64 64 0 1 1 0 128 64 64 0 1 1 0-128z'],
128
129
  'C': [32, 32, [], 'solid',
@@ -168,8 +169,7 @@ const RAW_ICONS = {
168
169
  'M0 256C0 114.6 114.6 0 256 0S512 114.6 512 256s-114.6 256-256 256L37.1 512c-13.7 0-20.5-16.5-10.9-26.2L75 437C28.7 390.7 0 326.7 0 256zM349.6 153.6c23.6 0 42.7-19.1 42.7-42.7s-19.1-42.7-42.7-42.7c-20.6 0-37.8 14.6-41.8 34c-34.5 3.7-61.4 33-61.4 68.4l0 .2c-37.5 1.6-71.8 12.3-99 29.1c-10.1-7.8-22.8-12.5-36.5-12.5c-33 0-59.8 26.8-59.8 59.8c0 24 14.1 44.6 34.4 54.1c2 69.4 77.6 125.2 170.6 125.2s168.7-55.9 170.6-125.3c20.2-9.6 34.1-30.2 34.1-54c0-33-26.8-59.8-59.8-59.8c-13.7 0-26.3 4.6-36.4 12.4c-27.4-17-62.1-27.7-100-29.1l0-.2c0-25.4 18.9-46.5 43.4-49.9l0 0c4.4 18.8 21.3 32.8 41.5 32.8zM177.1 246.9c16.7 0 29.5 17.6 28.5 39.3s-13.5 29.6-30.3 29.6s-31.4-8.8-30.4-30.5s15.4-38.3 32.1-38.3zm190.1 38.3c1 21.7-13.7 30.5-30.4 30.5s-29.3-7.9-30.3-29.6c-1-21.7 11.8-39.3 28.5-39.3s31.2 16.6 32.1 38.3zm-48.1 56.7c-10.3 24.6-34.6 41.9-63 41.9s-52.7-17.3-63-41.9c-1.2-2.9 .8-6.2 3.9-6.5c18.4-1.9 38.3-2.9 59.1-2.9s40.7 1 59.1 2.9c3.1 .3 5.1 3.6 3.9 6.5z'],
169
170
  'Rust': [512, 512, [], 'solid',
170
171
  'M508.52,249.75,486.7,236.24c-.17-2-.34-3.93-.55-5.88l18.72-17.5a7.35,7.35,0,0,0-2.44-12.25l-24-9c-.54-1.88-1.08-3.78-1.67-5.64l15-20.83a7.35,7.35,0,0,0-4.79-11.54l-25.42-4.15c-.9-1.73-1.79-3.45-2.73-5.15l10.68-23.42a7.35,7.35,0,0,0-6.95-10.39l-25.82.91q-1.79-2.22-3.61-4.4L439,81.84A7.36,7.36,0,0,0,430.16,73L405,78.93q-2.17-1.83-4.4-3.61l.91-25.82a7.35,7.35,0,0,0-10.39-7L367.7,53.23c-1.7-.94-3.43-1.84-5.15-2.73L358.4,25.08a7.35,7.35,0,0,0-11.54-4.79L326,35.26c-1.86-.59-3.75-1.13-5.64-1.67l-9-24a7.35,7.35,0,0,0-12.25-2.44l-17.5,18.72c-1.95-.21-3.91-.38-5.88-.55L262.25,3.48a7.35,7.35,0,0,0-12.5,0L236.24,25.3c-2,.17-3.93.34-5.88.55L212.86,7.13a7.35,7.35,0,0,0-12.25,2.44l-9,24c-1.89.55-3.79,1.08-5.66,1.68l-20.82-15a7.35,7.35,0,0,0-11.54,4.79l-4.15,25.41c-1.73.9-3.45,1.79-5.16,2.73L120.88,42.55a7.35,7.35,0,0,0-10.39,7l.92,25.81c-1.49,1.19-3,2.39-4.42,3.61L81.84,73A7.36,7.36,0,0,0,73,81.84L78.93,107c-1.23,1.45-2.43,2.93-3.62,4.41l-25.81-.91a7.42,7.42,0,0,0-6.37,3.26,7.35,7.35,0,0,0-.57,7.13l10.66,23.41c-.94,1.7-1.83,3.43-2.73,5.16L25.08,153.6a7.35,7.35,0,0,0-4.79,11.54l15,20.82c-.59,1.87-1.13,3.77-1.68,5.66l-24,9a7.35,7.35,0,0,0-2.44,12.25l18.72,17.5c-.21,1.95-.38,3.91-.55,5.88L3.48,249.75a7.35,7.35,0,0,0,0,12.5L25.3,275.76c.17,2,.34,3.92.55,5.87L7.13,299.13a7.35,7.35,0,0,0,2.44,12.25l24,9c.55,1.89,1.08,3.78,1.68,5.65l-15,20.83a7.35,7.35,0,0,0,4.79,11.54l25.42,4.15c.9,1.72,1.79,3.45,2.73,5.14L42.56,391.12a7.35,7.35,0,0,0,.57,7.13,7.13,7.13,0,0,0,6.37,3.26l25.83-.91q1.77,2.22,3.6,4.4L73,430.16A7.36,7.36,0,0,0,81.84,439L107,433.07q2.18,1.83,4.41,3.61l-.92,25.82a7.35,7.35,0,0,0,10.39,6.95l23.43-10.68c1.69.94,3.42,1.83,5.14,2.73l4.15,25.42a7.34,7.34,0,0,0,11.54,4.78l20.83-15c1.86.6,3.76,1.13,5.65,1.68l9,24a7.36,7.36,0,0,0,12.25,2.44l17.5-18.72c1.95.21,3.92.38,5.88.55l13.51,21.82a7.35,7.35,0,0,0,12.5,0l13.51-21.82c2-.17,3.93-.34,5.88-.56l17.5,18.73a7.36,7.36,0,0,0,12.25-2.44l9-24c1.89-.55,3.78-1.08,5.65-1.68l20.82,15a7.34,7.34,0,0,0,11.54-4.78l4.15-25.42c1.72-.9,3.45-1.79,5.15-2.73l23.42,10.68a7.35,7.35,0,0,0,10.39-6.95l-.91-25.82q2.22-1.79,4.4-3.61L430.16,439a7.36,7.36,0,0,0,8.84-8.84L433.07,405q1.83-2.17,3.61-4.4l25.82.91a7.23,7.23,0,0,0,6.37-3.26,7.35,7.35,0,0,0,.58-7.13L458.77,367.7c.94-1.7,1.83-3.43,2.73-5.15l25.42-4.15a7.35,7.35,0,0,0,4.79-11.54l-15-20.83c.59-1.87,1.13-3.76,1.67-5.65l24-9a7.35,7.35,0,0,0,2.44-12.25l-18.72-17.5c.21-1.95.38-3.91.55-5.87l21.82-13.51a7.35,7.35,0,0,0,0-12.5Zm-151,129.08A13.91,13.91,0,0,0,341,389.51l-7.64,35.67A187.51,187.51,0,0,1,177,424.44l-7.64-35.66a13.87,13.87,0,0,0-16.46-10.68l-31.51,6.76a187.38,187.38,0,0,1-16.26-19.21H258.3c1.72,0,2.89-.29,2.89-1.91V309.55c0-1.57-1.17-1.91-2.89-1.91H213.47l.05-34.35H262c4.41,0,23.66,1.28,29.79,25.87,1.91,7.55,6.17,32.14,9.06,40,2.89,8.82,14.6,26.46,27.1,26.46H407a187.3,187.3,0,0,1-17.34,20.09Zm25.77,34.49A15.24,15.24,0,1,1,368,398.08h.44A15.23,15.23,0,0,1,383.24,413.32Zm-225.62-.68a15.24,15.24,0,1,1-15.25-15.25h.45A15.25,15.25,0,0,1,157.62,412.64ZM69.57,234.15l32.83-14.6a13.88,13.88,0,0,0,7.06-18.33L102.69,186h26.56V305.73H75.65A187.65,187.65,0,0,1,69.57,234.15ZM58.31,198.09a15.24,15.24,0,0,1,15.23-15.25H74a15.24,15.24,0,1,1-15.67,15.24Zm155.16,24.49.05-35.32h63.26c3.28,0,23.07,3.77,23.07,18.62,0,12.29-15.19,16.7-27.68,16.7ZM399,306.71c-9.8,1.13-20.63-4.12-22-10.09-5.78-32.49-15.39-39.4-30.57-51.4,18.86-11.95,38.46-29.64,38.46-53.26,0-25.52-17.49-41.59-29.4-49.48-16.76-11-35.28-13.23-40.27-13.23H116.32A187.49,187.49,0,0,1,221.21,70.06l23.47,24.6a13.82,13.82,0,0,0,19.6.44l26.26-25a187.51,187.51,0,0,1,128.37,91.43l-18,40.57A14,14,0,0,0,408,220.43l34.59,15.33a187.12,187.12,0,0,1,.4,32.54H423.71c-1.91,0-2.69,1.27-2.69,3.13v8.82C421,301,409.31,305.58,399,306.71ZM240,60.21A15.24,15.24,0,0,1,255.21,45h.45A15.24,15.24,0,1,1,240,60.21ZM436.84,214a15.24,15.24,0,1,1,0-30.48h.44a15.24,15.24,0,0,1-.44,30.48Z'],
171
- 'Unity': [16, 16, [], 'solid',
172
- 'M8 6.5L5 5l2-1V2L2 5v5l2-1V6.5L7 8v4.5L4 11l-2 1l6 3l6-3l-2-1l-3 1.5V8l3-1.5V9l2 1V5L9 2v2l2 1Z'],
172
+ 'Unity': [16, 16, [], 'solid', 'M8 6.5L5 5l2-1V2L2 5v5l2-1V6.5L7 8v4.5L4 11l-2 1l6 3l6-3l-2-1l-3 1.5V8l3-1.5V9l2 1V5L9 2v2l2 1Z'],
173
173
  'UnrealEngine': [24, 24, [], 'regular',
174
174
  'M12 0a12 12 0 1 0 12 12A12 12 0 0 0 12 0m0 23.52A11.52 11.52 0 1 1 23.52 12A11.52 11.52 0 0 1 12 23.52m7.13-9.791c-.206.997-1.126 3.557-4.06 4.942l-1.179-1.325l-1.988 2a7.34 7.34 0 0 1-5.804-2.978a3 3 0 0 0 .65.123c.326.006.678-.114.678-.66v-5.394a.89.89 0 0 0-1.116-.89c-.92.212-1.656 2.509-1.656 2.509a7.3 7.3 0 0 1 2.528-5.597a7.4 7.4 0 0 1 3.73-1.721c-1.006.573-1.57 1.507-1.57 2.29c0 1.262.76 1.109.984.923v7.28a1.2 1.2 0 0 0 .148.256a1.08 1.08 0 0 0 .88.445c.76 0 1.747-.868 1.747-.868V9.172c0-.6-.452-1.324-.905-1.572c0 0 .838-.149 1.484.346a6 6 0 0 1 .387-.425c1.508-1.48 2.929-1.902 4.112-2.112c0 0-2.151 1.69-2.151 3.96c0 1.687.043 5.801.043 5.801c.799.771 1.986-.342 3.059-1.441Z'],
175
175
  'UnrealEngine@solid': [24, 24, [], 'solid',
@@ -256,8 +256,7 @@ const RAW_ICONS = {
256
256
  'M448 480L64 480c-35.3 0-64-28.7-64-64L0 192l512 0 0 224c0 35.3-28.7 64-64 64zm64-320L0 160 0 96C0 60.7 28.7 32 64 32l128 0c20.1 0 39.1 9.5 51.2 25.6l19.2 25.6c6 8.1 15.5 12.8 25.6 12.8l160 0c35.3 0 64 28.7 64 64z'],
257
257
  'Function': [384, 512, [], 'solid',
258
258
  'M314.7 32c-38.8 0-73.7 23.3-88.6 59.1L170.7 224 64 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l80 0L98.9 396.3c-5 11.9-16.6 19.7-29.5 19.7L32 416c-17.7 0-32 14.3-32 32s14.3 32 32 32l37.3 0c38.8 0 73.7-23.3 88.6-59.1L213.3 288 320 288c17.7 0 32-14.3 32-32s-14.3-32-32-32l-80 0 45.1-108.3c5-11.9 16.6-19.7 29.5-19.7L352 96c17.7 0 32-14.3 32-32s-14.3-32-32-32l-37.3 0z'],
259
- 'Stop': [384, 512, [], 'solid',
260
- 'M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z'],
259
+ 'Stop': [384, 512, [], 'solid', 'M0 128C0 92.7 28.7 64 64 64H320c35.3 0 64 28.7 64 64V384c0 35.3-28.7 64-64 64H64c-35.3 0-64-28.7-64-64V128z'],
261
260
  'Image': [512, 512, [], 'solid',
262
261
  'M448 80c8.8 0 16 7.2 16 16l0 319.8-5-6.5-136-176c-4.5-5.9-11.6-9.3-19-9.3s-14.4 3.4-19 9.3L202 340.7l-30.5-42.7C167 291.7 159.8 288 152 288s-15 3.7-19.5 10.1l-80 112L48 416.3l0-.3L48 96c0-8.8 7.2-16 16-16l384 0zM64 32C28.7 32 0 60.7 0 96L0 416c0 35.3 28.7 64 64 64l384 0c35.3 0 64-28.7 64-64l0-320c0-35.3-28.7-64-64-64L64 32zm80 192a48 48 0 1 0 0-96 48 48 0 1 0 0 96z'],
263
262
  'Images': [576, 512, [], 'solid',
@@ -388,52 +387,6 @@ class IEvent {
388
387
  }
389
388
  }
390
389
  LX.IEvent = IEvent;
391
- class TreeEvent {
392
- static NONE = 0;
393
- static NODE_SELECTED = 1;
394
- static NODE_DELETED = 2;
395
- static NODE_DBLCLICKED = 3;
396
- static NODE_CONTEXTMENU = 4;
397
- static NODE_DRAGGED = 5;
398
- static NODE_RENAMED = 6;
399
- static NODE_VISIBILITY = 7;
400
- static NODE_CARETCHANGED = 8;
401
- type = TreeEvent.NONE;
402
- node;
403
- value;
404
- event;
405
- multiple = false; // Multiple selection
406
- panel = null;
407
- constructor(type, node, value, event) {
408
- this.type = type || TreeEvent.NONE;
409
- this.node = node;
410
- this.value = value;
411
- this.event = event;
412
- }
413
- string() {
414
- switch (this.type) {
415
- case TreeEvent.NONE:
416
- return 'tree_event_none';
417
- case TreeEvent.NODE_SELECTED:
418
- return 'tree_event_selected';
419
- case TreeEvent.NODE_DELETED:
420
- return 'tree_event_deleted';
421
- case TreeEvent.NODE_DBLCLICKED:
422
- return 'tree_event_dblclick';
423
- case TreeEvent.NODE_CONTEXTMENU:
424
- return 'tree_event_contextmenu';
425
- case TreeEvent.NODE_DRAGGED:
426
- return 'tree_event_dragged';
427
- case TreeEvent.NODE_RENAMED:
428
- return 'tree_event_renamed';
429
- case TreeEvent.NODE_VISIBILITY:
430
- return 'tree_event_visibility';
431
- case TreeEvent.NODE_CARETCHANGED:
432
- return 'tree_event_caretchanged';
433
- }
434
- }
435
- }
436
- LX.TreeEvent = TreeEvent;
437
390
 
438
391
  // BaseComponent.ts @jxarco
439
392
  var ComponentType;
@@ -508,8 +461,7 @@ class BaseComponent {
508
461
  this.name = name;
509
462
  this.options = options;
510
463
  this._initialValue = value;
511
- const root = document.createElement('div');
512
- root.className = 'lexcomponent';
464
+ const root = LX.makeElement('div', LX.mergeClass('lexcomponent flex flex-row outline-none items-center text-foreground text-sm overflow-hidden min-h-8 pad-sm', options.className));
513
465
  this.onResize = () => { };
514
466
  if (options.id) {
515
467
  root.id = options.id;
@@ -517,9 +469,6 @@ class BaseComponent {
517
469
  if (options.title) {
518
470
  root.title = options.title;
519
471
  }
520
- if (options.className) {
521
- root.className += ' ' + options.className;
522
- }
523
472
  if (type != ComponentType.TITLE) {
524
473
  if (options.width) {
525
474
  root.style.width = root.style.minWidth = options.width;
@@ -537,12 +486,10 @@ class BaseComponent {
537
486
  }
538
487
  if (name != undefined) {
539
488
  if (!(options.hideName ?? false)) {
540
- let domName = document.createElement('div');
541
- domName.className = 'lexcomponentname';
489
+ let domName = LX.makeElement('div', 'lexcomponentname flex text-sm text-secondary-foreground justify-between whitespace-nowrap overflow-hidden', name);
542
490
  if (options.justifyName) {
543
491
  domName.classList.add('float-' + options.justifyName);
544
492
  }
545
- domName.innerHTML = name;
546
493
  domName.title = options.title ?? domName.innerHTML;
547
494
  domName.style.width = options.nameWidth || LX.DEFAULT_NAME_WIDTH;
548
495
  domName.style.minWidth = domName.style.width;
@@ -771,7 +718,7 @@ class Button extends BaseComponent {
771
718
  wValue.prepend(img);
772
719
  }
773
720
  else {
774
- wValue.innerHTML = `<span>${(newValue ?? '')}</span>`;
721
+ wValue.innerHTML = `${(newValue ?? '')}`;
775
722
  }
776
723
  };
777
724
  this.onResize = (rect) => {
@@ -798,9 +745,10 @@ class Button extends BaseComponent {
798
745
  this._trigger(new IEvent(name, swapInput ? swapInput.checked : (this.selectable ? v : value), null), callback);
799
746
  }
800
747
  };
801
- var wValue = document.createElement('button');
748
+ var wValue = LX.makeElement('button', LX.mergeClass(['lexbutton', 'inline-flex', 'items-center', 'justify-center', 'whitespace-nowrap', 'transition-all', 'disabled:pointer-events-none',
749
+ 'disabled:opacity-50', '[&_svg]:pointer-events-none', 'shrink-0', '[&_svg]:shrink-0', 'outline-none', 'select-none', 'cursor-pointer',
750
+ 'font-medium', 'text-sm', 'border-1', 'h-9', 'px-2', 'overflow-hidden', 'bg-clip-padding'].join(' '), options.buttonClass ?? 'outline'));
802
751
  wValue.title = options.tooltip ? '' : (options.title ?? '');
803
- wValue.className = 'lexbutton px-3 ' + (options.buttonClass ?? '');
804
752
  this.root.appendChild(wValue);
805
753
  if (options.selected) {
806
754
  wValue.classList.add('selected');
@@ -818,19 +766,19 @@ class Button extends BaseComponent {
818
766
  wValue.prepend(icon);
819
767
  }
820
768
  else {
821
- wValue.innerHTML = `<span>${(value || '')}</span>`;
769
+ wValue.innerHTML = `${(value || '')}`;
822
770
  if (iconPosition == 'start') {
823
- wValue.querySelector('span').prepend(icon);
771
+ wValue.prepend(icon);
824
772
  }
825
773
  // "end"
826
774
  else {
827
- wValue.querySelector('span').appendChild(icon);
775
+ wValue.appendChild(icon);
828
776
  }
829
777
  }
830
778
  wValue.classList.add('justify-center');
831
779
  }
832
780
  else {
833
- wValue.innerHTML = `<span>${(value || '')}</span>`;
781
+ wValue.innerHTML = `${(value || '')}`;
834
782
  }
835
783
  if (options.fileInput) {
836
784
  const fileInput = document.createElement('input');
@@ -955,10 +903,9 @@ class Menubar {
955
903
  focused = false;
956
904
  _currentDropdown;
957
905
  constructor(items, options = {}) {
958
- this.root = document.createElement('div');
959
- this.root.className = 'lexmenubar';
906
+ this.root = LX.makeElement('div', 'lexmenubar size-full bg-background text-foreground inline-flex gap-1 overflow-hidden text-sm font-medium');
960
907
  if (options.float) {
961
- this.root.style.justifyContent = options.float;
908
+ this.root.className = LX.mergeClass(this.root.className, `justify-${options.float}`);
962
909
  }
963
910
  this.items = items ?? [];
964
911
  this.createEntries();
@@ -996,8 +943,7 @@ class Menubar {
996
943
  this._resetMenubar(true);
997
944
  entry.classList.add('selected');
998
945
  entry.dataset['built'] = 'true';
999
- this._currentDropdown = LX.addDropdownMenu(entry, item.submenu ?? [], { side: 'bottom', align: 'start',
1000
- onBlur: () => {
946
+ this._currentDropdown = LX.addDropdownMenu(entry, item.submenu ?? [], { side: 'bottom', align: 'start', onBlur: () => {
1001
947
  this._resetMenubar();
1002
948
  } });
1003
949
  };
@@ -1172,7 +1118,7 @@ class Menubar {
1172
1118
  const title = data.title;
1173
1119
  const button = new Button(title, data.label, data.callback, {
1174
1120
  title,
1175
- buttonClass: 'bg-none',
1121
+ buttonClass: 'ghost',
1176
1122
  disabled: data.disabled,
1177
1123
  icon: data.icon,
1178
1124
  hideName: true,
@@ -1205,7 +1151,7 @@ class Tabs {
1205
1151
  constructor(area, options = {}) {
1206
1152
  this.onclose = options.onclose;
1207
1153
  let container = document.createElement('div');
1208
- container.className = 'lexareatabs ' + (options.fit ? 'fit' : 'row');
1154
+ container.className = 'lexareatabs flex flex-row w-fit ' + (options.fit ? 'fit' : 'row');
1209
1155
  const folding = options.folding ?? false;
1210
1156
  if (folding)
1211
1157
  container.classList.add('folding');
@@ -1267,16 +1213,15 @@ class Tabs {
1267
1213
  that.tabs[tabDom.dataset['name']] = content;
1268
1214
  });
1269
1215
  area.root.classList.add('lexareatabscontainer');
1270
- const [tabButtons, content] = area.split({ type: 'vertical', sizes: options.sizes ?? 'auto', resize: false,
1271
- top: 2 });
1216
+ const [tabButtons, content] = area.split({ type: 'vertical', sizes: options.sizes ?? 'auto', resize: false, top: 2 });
1272
1217
  tabButtons.attach(container);
1273
1218
  if (options.parentClass && container.parentElement) {
1274
- container.parentElement.className += ` ${options.parentClass}`;
1219
+ container.parentElement.className = LX.mergeClass(container.parentElement.className, options.parentClass);
1275
1220
  }
1276
1221
  this.area = content;
1277
1222
  this.area.root.className += ' lexareatabscontent';
1278
1223
  if (options.contentClass) {
1279
- this.area.root.className += ` ${options.contentClass}`;
1224
+ this.area.root.className = LX.mergeClass(this.area.root.className, options.contentClass);
1280
1225
  }
1281
1226
  this.selected = null;
1282
1227
  this.root = container;
@@ -1335,8 +1280,7 @@ class Tabs {
1335
1280
  if (options.icon) {
1336
1281
  if (!options.icon.includes('.')) { // Not a file
1337
1282
  const classes = options.icon.split(' ');
1338
- options.icon =
1339
- LX.makeIcon(classes[0], { svgClass: 'sm ' + classes.slice(0).join(' ') }).innerHTML;
1283
+ options.icon = LX.makeIcon(classes[0], { svgClass: 'sm ' + classes.slice(0).join(' ') }).innerHTML;
1340
1284
  }
1341
1285
  // an image..
1342
1286
  else {
@@ -1371,10 +1315,9 @@ class Tabs {
1371
1315
  e.stopPropagation();
1372
1316
  const scope = tabEl.instance;
1373
1317
  if (!tabEl.fixed) {
1374
- // For folding tabs
1375
1318
  const lastValue = tabEl.selected;
1376
1319
  tabEl.parentElement.querySelectorAll('span').forEach((s) => s.selected = false);
1377
- tabEl.selected = !lastValue || (tabEl._forceSelect ? true : false);
1320
+ tabEl.selected = (scope.folding ? !lastValue : true) || (tabEl._forceSelect ? true : false);
1378
1321
  // Manage selected
1379
1322
  tabEl.parentElement.querySelectorAll('span').forEach((s) => s.classList.remove('selected'));
1380
1323
  tabEl.classList.toggle('selected', tabEl.selected);
@@ -1517,9 +1460,7 @@ class NumberInput extends BaseComponent {
1517
1460
  var container = document.createElement('div');
1518
1461
  container.className = 'lexnumber';
1519
1462
  this.root.appendChild(container);
1520
- let box = document.createElement('div');
1521
- box.className = 'numberbox';
1522
- container.appendChild(box);
1463
+ let box = LX.makeElement('div', 'numberbox relative flex flex-col w-full bg-secondary rounded-lg scrollbar-hidden overflow-x-hidden', '', container);
1523
1464
  let valueBox = LX.makeContainer(['auto', '100%'], 'relative flex flex-row cursor-text', '', box);
1524
1465
  let vecinput = document.createElement('input');
1525
1466
  vecinput.id = 'number_' + LX.guidGenerator();
@@ -1537,7 +1478,7 @@ class NumberInput extends BaseComponent {
1537
1478
  const dragIcon = LX.makeIcon('MoveVertical', { iconClass: 'drag-icon hidden-opacity', svgClass: 'sm' });
1538
1479
  valueBox.appendChild(dragIcon);
1539
1480
  if (options.units) {
1540
- let unitBox = LX.makeContainer(['auto', 'auto'], 'px-2 bg-secondary content-center', options.units, valueBox, { 'word-break': 'keep-all' });
1481
+ let unitBox = LX.makeContainer(['auto', 'auto'], 'px-2 bg-card content-center break-keep', options.units, valueBox);
1541
1482
  vecinput.unitBox = unitBox;
1542
1483
  }
1543
1484
  if (options.disabled) {
@@ -1698,8 +1639,7 @@ class TextInput extends BaseComponent {
1698
1639
  this.disabled = (options.disabled || options.warning) ?? (options.url ? true : false);
1699
1640
  let wValue = null;
1700
1641
  if (!this.disabled) {
1701
- wValue = document.createElement('input');
1702
- wValue.className = 'lextext ' + (options.inputClass ?? '');
1642
+ wValue = LX.makeElement('input', LX.mergeClass('lextext text-sm', options.inputClass));
1703
1643
  wValue.type = options.type || '';
1704
1644
  wValue.value = value || '';
1705
1645
  wValue.style.textAlign = options.float ?? '';
@@ -1751,10 +1691,10 @@ class TextInput extends BaseComponent {
1751
1691
  wValue.disabled = true;
1752
1692
  wValue.value = value;
1753
1693
  wValue.style.textAlign = options.float ?? '';
1754
- wValue.className = 'lextext ellipsis-overflow ' + (options.inputClass ?? '');
1694
+ wValue.className = LX.mergeClass('lextext ellipsis-overflow', options.inputClass);
1755
1695
  }
1756
1696
  if (options.fit) {
1757
- wValue.classList.add('size-content');
1697
+ wValue.classList.add('field-sizing-content');
1758
1698
  }
1759
1699
  Object.assign(wValue.style, options.style ?? {});
1760
1700
  container.appendChild(wValue);
@@ -1778,7 +1718,7 @@ class Select extends BaseComponent {
1778
1718
  this.onSetValue = (newValue, skipCallback, event) => {
1779
1719
  value = newValue;
1780
1720
  let item = null;
1781
- const listOptionsNodes = listOptions.childNodes;
1721
+ const listOptionsNodes = list.childNodes;
1782
1722
  listOptionsNodes.forEach((e) => {
1783
1723
  e.classList.remove('selected');
1784
1724
  if (e.getAttribute('value') == newValue) {
@@ -1879,8 +1819,9 @@ class Select extends BaseComponent {
1879
1819
  const parentRect = overflowContainer.getBoundingClientRect();
1880
1820
  maxX = parentRect.x + parentRect.width;
1881
1821
  }
1882
- const showLeft = (leftPosition + listWidth) > maxX;
1883
- if (showLeft) {
1822
+ // "align" basically forces left-right alignment
1823
+ const showLeft = (options.align === 'end') || (leftPosition + listWidth) > maxX;
1824
+ if (showLeft && (options.align ? options.align !== 'start' : true)) {
1884
1825
  parent.style.left = (leftPosition - (listWidth - rect.width)) + 'px';
1885
1826
  }
1886
1827
  }
@@ -1902,17 +1843,17 @@ class Select extends BaseComponent {
1902
1843
  if (filter) {
1903
1844
  filter.root.querySelector('input').focus();
1904
1845
  }
1905
- }, { buttonClass: 'array', skipInlineCount: true, disabled: options.disabled });
1846
+ }, { buttonClass: 'outline [&_a]:ml-auto', skipInlineCount: true, disabled: options.disabled });
1906
1847
  selectedOption.root.style.width = '100%';
1907
- selectedOption.root.querySelector('span').appendChild(LX.makeIcon('Down', { svgClass: 'sm' }));
1848
+ selectedOption.root.querySelector('button').appendChild(LX.makeIcon('Down', { svgClass: 'sm' }));
1908
1849
  container.appendChild(selectedOption.root);
1909
1850
  selectedOption.refresh = (v) => {
1910
- const buttonSpan = selectedOption.root.querySelector('span');
1911
- if (buttonSpan.innerText == '') {
1912
- buttonSpan.innerText = v;
1851
+ const button = selectedOption.root.querySelector('button');
1852
+ if (button.innerText == '') {
1853
+ button.innerText = v;
1913
1854
  }
1914
1855
  else {
1915
- buttonSpan.innerHTML = buttonSpan.innerHTML.replaceAll(buttonSpan.innerText, v);
1856
+ button.innerHTML = button.innerHTML.replaceAll(button.innerText, v);
1916
1857
  }
1917
1858
  };
1918
1859
  // Add select options container
@@ -1963,14 +1904,12 @@ class Select extends BaseComponent {
1963
1904
  });
1964
1905
  list.appendChild(filter.root);
1965
1906
  }
1966
- // Create option list to empty it easily..
1967
- const listOptions = document.createElement('span');
1968
- listOptions.className = 'lexselectinnerlist';
1969
- list.appendChild(listOptions);
1970
1907
  // Add select options list
1971
1908
  list.refresh = (currentOptions) => {
1972
1909
  // Empty list
1973
- listOptions.innerHTML = '';
1910
+ while (list.childElementCount > (options.filter ?? false ? 1 : 0)) {
1911
+ list.removeChild(list.lastChild);
1912
+ }
1974
1913
  if (!currentOptions.length) {
1975
1914
  let iValue = options.emptyMsg ?? 'No options found.';
1976
1915
  let option = document.createElement('div');
@@ -1979,7 +1918,7 @@ class Select extends BaseComponent {
1979
1918
  let li = document.createElement('li');
1980
1919
  li.className = 'lexselectitem empty';
1981
1920
  li.appendChild(option);
1982
- listOptions.appendChild(li);
1921
+ list.appendChild(li);
1983
1922
  return;
1984
1923
  }
1985
1924
  for (let i = 0; i < currentOptions.length; i++) {
@@ -1997,7 +1936,7 @@ class Select extends BaseComponent {
1997
1936
  if (iValue.constructor != Object) {
1998
1937
  const asLabel = iValue[0] === '@';
1999
1938
  if (!asLabel) {
2000
- option.innerHTML = `<span>${iValue}</span>`;
1939
+ option.innerHTML = `<span class="flex flex-row justify-between">${iValue}</span>`;
2001
1940
  option.appendChild(LX.makeIcon('Check'));
2002
1941
  option.value = iValue;
2003
1942
  li.setAttribute('value', iValue);
@@ -2029,14 +1968,13 @@ class Select extends BaseComponent {
2029
1968
  li.classList.add('selected');
2030
1969
  }
2031
1970
  }
2032
- listOptions.appendChild(li);
1971
+ list.appendChild(li);
2033
1972
  }
2034
1973
  };
2035
1974
  list.refresh(values);
2036
1975
  container.appendChild(listDialog);
2037
1976
  // Element suboptions
2038
- let suboptions = document.createElement('div');
2039
- suboptions.className = 'lexcustomcontainer w-full';
1977
+ let suboptions = LX.makeElement('div', 'lexcustomcontainer w-full');
2040
1978
  const suboptionsFunc = options[`on_${value}`];
2041
1979
  suboptions.toggleAttribute('hidden', !suboptionsFunc);
2042
1980
  if (suboptionsFunc) {
@@ -2079,7 +2017,7 @@ LX.Select = Select;
2079
2017
  class ArrayInput extends BaseComponent {
2080
2018
  _updateItems;
2081
2019
  constructor(name, values = [], callback, options = {}) {
2082
- options.nameWidth = '100%';
2020
+ options.nameWidth = 'auto';
2083
2021
  super(ComponentType.ARRAY, name, null, options);
2084
2022
  this.onGetValue = () => {
2085
2023
  return values;
@@ -2093,16 +2031,16 @@ class ArrayInput extends BaseComponent {
2093
2031
  };
2094
2032
  // Add open array button
2095
2033
  let container = document.createElement('div');
2096
- container.className = 'lexarray';
2097
- container.style.width = '100%';
2034
+ container.className = 'lexarray shrink-1 grow-1 ml-4';
2035
+ container.style.width = 'auto';
2098
2036
  this.root.appendChild(container);
2099
2037
  this.root.dataset['opened'] = false;
2100
2038
  let buttonName = `Array (size ${values.length})`;
2101
2039
  const toggleButton = new Button(null, buttonName, () => {
2102
2040
  this.root.dataset['opened'] = this.root.dataset['opened'] == 'true' ? false : true;
2103
2041
  this.root.querySelector('.lexarrayitems').toggleAttribute('hidden');
2104
- }, { buttonClass: 'array' });
2105
- toggleButton.root.querySelector('span').appendChild(LX.makeIcon('Down', { svgClass: 'sm' }));
2042
+ }, { buttonClass: 'outline [&_a]:ml-auto' });
2043
+ toggleButton.root.querySelector('button').appendChild(LX.makeIcon('Down', { svgClass: 'sm' }));
2106
2044
  container.appendChild(toggleButton.root);
2107
2045
  // Show elements
2108
2046
  let arrayItems = document.createElement('div');
@@ -2111,8 +2049,8 @@ class ArrayInput extends BaseComponent {
2111
2049
  this.root.appendChild(arrayItems);
2112
2050
  this._updateItems = () => {
2113
2051
  // Update num items
2114
- let buttonSpan = this.root.querySelector('.lexbutton.array span');
2115
- for (let node of buttonSpan.childNodes) {
2052
+ let button = this.root.querySelector('button');
2053
+ for (let node of button.childNodes) {
2116
2054
  if (node.nodeType === Node.TEXT_NODE) {
2117
2055
  node.textContent = `Array (size ${values.length})`;
2118
2056
  break;
@@ -2150,14 +2088,14 @@ class ArrayInput extends BaseComponent {
2150
2088
  values.splice(values.indexOf(value), 1);
2151
2089
  this._updateItems();
2152
2090
  this._trigger(new IEvent(name, values, event), callback);
2153
- }, { title: 'Remove item', icon: 'Trash3' });
2091
+ }, { buttonClass: 'ghost xs p-0', title: 'Remove item', icon: 'Trash2' });
2154
2092
  component.root.appendChild(removeComponent.root);
2155
2093
  }
2156
2094
  const addButton = new Button(null, LX.makeIcon('Plus', { svgClass: 'sm' }).innerHTML + 'Add item', (v, event) => {
2157
2095
  values.push(options.innerValues ? options.innerValues[0] : '');
2158
2096
  this._updateItems();
2159
2097
  this._trigger(new IEvent(name, values, event), callback);
2160
- }, { buttonClass: 'array' });
2098
+ }, { buttonClass: 'ghost' });
2161
2099
  arrayItems.appendChild(addButton.root);
2162
2100
  };
2163
2101
  this._updateItems();
@@ -2175,22 +2113,22 @@ class Card extends BaseComponent {
2175
2113
  options.hideName = true;
2176
2114
  super(ComponentType.CARD, name, null, options);
2177
2115
  this.root.classList.add('place-content-center');
2178
- const container = LX.makeContainer(['100%', 'auto'], 'lexcard max-w-sm flex flex-col gap-4 bg-primary border rounded-xl py-6', '', this.root);
2116
+ const container = LX.makeContainer(['100%', 'auto'], 'lexcard max-w-sm flex flex-col gap-4 bg-card border-color rounded-xl py-6', '', this.root);
2179
2117
  if (options.header) {
2180
2118
  const hasAction = options.header.action !== undefined;
2181
2119
  let header = LX.makeContainer(['100%', 'auto'], `flex ${hasAction ? 'flex-row gap-4' : 'flex-col gap-1'} px-6`, '', container);
2182
2120
  if (hasAction) {
2183
- const actionBtn = new Button(null, options.header.action.name, options.header.action.callback);
2121
+ const actionBtn = new Button(null, options.header.action.name, options.header.action.callback, { buttonClass: 'secondary' });
2184
2122
  header.appendChild(actionBtn.root);
2185
2123
  const titleDescBox = LX.makeContainer(['75%', 'auto'], `flex flex-col gap-1`, '');
2186
2124
  header.prepend(titleDescBox);
2187
2125
  header = titleDescBox;
2188
2126
  }
2189
2127
  if (options.header.title) {
2190
- LX.makeElement('div', 'text-md leading-none font-semibold', options.header.title, header);
2128
+ LX.makeElement('div', 'text-sm text-foreground leading-none font-semibold', options.header.title, header);
2191
2129
  }
2192
2130
  if (options.header.description) {
2193
- LX.makeElement('div', 'text-sm fg-tertiary', options.header.description, header);
2131
+ LX.makeElement('div', 'text-xs text-muted-foreground', options.header.description, header);
2194
2132
  }
2195
2133
  }
2196
2134
  if (options.content) {
@@ -2248,24 +2186,19 @@ class Checkbox extends BaseComponent {
2248
2186
  container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
2249
2187
  };
2250
2188
  var container = document.createElement('div');
2251
- container.className = 'lexcheckboxcont';
2189
+ container.className = 'flex items-center gap-2 my-0 mx-auto [&_span]:truncate [&_span]:flex-auto-fill';
2252
2190
  this.root.appendChild(container);
2253
- let checkbox = document.createElement('input');
2191
+ let checkbox = LX.makeElement('input', LX.mergeClass('lexcheckbox rounded-xl', options.className ?? 'primary'));
2254
2192
  checkbox.type = 'checkbox';
2255
- checkbox.className = 'lexcheckbox ' + (options.className ?? 'primary');
2256
2193
  checkbox.checked = value;
2257
2194
  checkbox.disabled = options.disabled ?? false;
2258
2195
  container.appendChild(checkbox);
2259
- let valueName = document.createElement('span');
2260
- valueName.className = 'checkboxtext';
2261
- valueName.innerHTML = options.label ?? 'On';
2262
- container.appendChild(valueName);
2196
+ LX.makeElement('span', 'text-sm', options.label ?? 'On', container);
2263
2197
  checkbox.addEventListener('change', (e) => {
2264
2198
  this.set(checkbox.checked, false, e);
2265
2199
  });
2266
2200
  if (options.suboptions) {
2267
- let suboptions = document.createElement('div');
2268
- suboptions.className = 'lexcheckboxsubmenu';
2201
+ let suboptions = LX.makeElement('div', 'lexcheckboxsubmenu');
2269
2202
  suboptions.toggleAttribute('hidden', !checkbox.checked);
2270
2203
  const suboptionsPanel = new LX.Panel();
2271
2204
  suboptionsPanel.queue(suboptions);
@@ -2376,20 +2309,17 @@ class ColorPicker {
2376
2309
  if (!this.callback) {
2377
2310
  console.warn('Define a callback in _options.onChange_ to allow getting new Color values!');
2378
2311
  }
2379
- this.root = document.createElement('div');
2380
- this.root.className = 'lexcolorpicker';
2312
+ this.root = LX.makeElement('div', 'lexcolorpicker flex flex-col text-sm w-3xs gap-2 p-1');
2381
2313
  this.markerHalfSize = 8;
2382
2314
  this.markerSize = this.markerHalfSize * 2;
2383
2315
  this.currentColor = new Color(hexValue);
2384
2316
  const hueColor = new Color({ h: this.currentColor.hsv.h, s: 1, v: 1 });
2317
+ const colorMarkerClass = 'size-4 rounded-lg bg-transparent absolute pointer-events-none border-3 border-solid border-white';
2385
2318
  // Intensity, Sat
2386
- this.colorPickerBackground = document.createElement('div');
2387
- this.colorPickerBackground.className = 'lexcolorpickerbg';
2388
- this.colorPickerBackground.style.backgroundColor =
2389
- `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2319
+ this.colorPickerBackground = LX.makeElement('div', 'lexcolorpickerbg w-full aspect-square relative rounded-md cursor-pointer');
2320
+ this.colorPickerBackground.style.backgroundColor = `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2390
2321
  this.root.appendChild(this.colorPickerBackground);
2391
- this.intSatMarker = document.createElement('div');
2392
- this.intSatMarker.className = 'lexcolormarker';
2322
+ this.intSatMarker = LX.makeElement('div', colorMarkerClass);
2393
2323
  this.intSatMarker.style.backgroundColor = this.currentColor.hex;
2394
2324
  this.colorPickerBackground.appendChild(this.intSatMarker);
2395
2325
  let pickerRect = null;
@@ -2450,11 +2380,9 @@ class ColorPicker {
2450
2380
  }
2451
2381
  const innerHueAlpha = LX.makeContainer(['100%', '100%'], 'flex flex-col gap-2', '', hueAlphaContainer);
2452
2382
  // Hue
2453
- this.colorPickerTracker = document.createElement('div');
2454
- this.colorPickerTracker.className = 'lexhuetracker';
2383
+ this.colorPickerTracker = LX.makeElement('div', 'lexhuetracker w-full h-4 rounded-lg relative cursor-pointer');
2455
2384
  innerHueAlpha.appendChild(this.colorPickerTracker);
2456
- this.hueMarker = document.createElement('div');
2457
- this.hueMarker.className = 'lexcolormarker';
2385
+ this.hueMarker = LX.makeElement('div', colorMarkerClass);
2458
2386
  this.hueMarker.style.backgroundColor = `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2459
2387
  this.colorPickerTracker.appendChild(this.hueMarker);
2460
2388
  const _fromHueX = (hueX) => {
@@ -2462,8 +2390,7 @@ class ColorPicker {
2462
2390
  this.currentColor.hsv.h = LX.remapRange(hueX, 0, this.colorPickerTracker.offsetWidth - this.markerSize, 0, 360);
2463
2391
  const hueColor = new Color({ h: this.currentColor.hsv.h, s: 1, v: 1 });
2464
2392
  this.hueMarker.style.backgroundColor = `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2465
- this.colorPickerBackground.style.backgroundColor =
2466
- `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2393
+ this.colorPickerBackground.style.backgroundColor = `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2467
2394
  this._updateColorValue();
2468
2395
  };
2469
2396
  let hueTrackerRect = null;
@@ -2498,13 +2425,10 @@ class ColorPicker {
2498
2425
  this.colorPickerTracker.addEventListener('mousedown', innerMouseDownHue);
2499
2426
  // Alpha
2500
2427
  if (this.useAlpha) {
2501
- this.alphaTracker = document.createElement('div');
2502
- this.alphaTracker.className = 'lexalphatracker';
2503
- this.alphaTracker.style.color =
2504
- `rgb(${this.currentColor.css.r}, ${this.currentColor.css.g}, ${this.currentColor.css.b})`;
2428
+ this.alphaTracker = LX.makeElement('div', 'lexalphatracker w-full h-4 rounded-lg relative cursor-pointer');
2429
+ this.alphaTracker.style.color = `rgb(${this.currentColor.css.r}, ${this.currentColor.css.g}, ${this.currentColor.css.b})`;
2505
2430
  innerHueAlpha.appendChild(this.alphaTracker);
2506
- this.alphaMarker = document.createElement('div');
2507
- this.alphaMarker.className = 'lexcolormarker';
2431
+ this.alphaMarker = LX.makeElement('div', colorMarkerClass);
2508
2432
  this.alphaMarker.style.backgroundColor =
2509
2433
  `rgb(${this.currentColor.css.r}, ${this.currentColor.css.g}, ${this.currentColor.css.b},${this.currentColor.css.a})`;
2510
2434
  this.alphaTracker.appendChild(this.alphaMarker);
@@ -2566,7 +2490,7 @@ class ColorPicker {
2566
2490
  copyButtonComponent.root.querySelector("input[type='checkbox']").style.pointerEvents = 'auto';
2567
2491
  }, 3000);
2568
2492
  }, { swap: 'Check', icon: 'Copy', buttonClass: 'bg-none', className: 'ml-auto', title: 'Copy' });
2569
- copyButtonComponent.root.querySelector('.swap-on svg').classList.add('fg-success');
2493
+ copyButtonComponent.root.querySelector('.swap-on svg').classList.add('text-success');
2570
2494
  colorLabel.appendChild(copyButtonComponent.root);
2571
2495
  }
2572
2496
  this._updateColorValue(hexValue, true);
@@ -2598,8 +2522,7 @@ class ColorPicker {
2598
2522
  }
2599
2523
  this.intSatMarker.style.backgroundColor = this.currentColor.hex;
2600
2524
  if (this.useAlpha) {
2601
- this.alphaTracker.style.color =
2602
- `rgb(${this.currentColor.css.r}, ${this.currentColor.css.g}, ${this.currentColor.css.b})`;
2525
+ this.alphaTracker.style.color = `rgb(${this.currentColor.css.r}, ${this.currentColor.css.g}, ${this.currentColor.css.b})`;
2603
2526
  }
2604
2527
  const toFixed = (s, n = 2) => {
2605
2528
  return s.toFixed(n).replace(/([0-9]+(\.[0-9]+[1-9])?)(\.?0+$)/, '$1');
@@ -2636,9 +2559,8 @@ class ColorPicker {
2636
2559
  this.hueMarker.style.backgroundColor =
2637
2560
  this.colorPickerBackground.style.backgroundColor =
2638
2561
  `rgb(${hueColor.css.r}, ${hueColor.css.g}, ${hueColor.css.b})`;
2639
- this.hueMarker.style.left =
2640
- LX.remapRange(h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize)
2641
- + 'px';
2562
+ this.hueMarker.style.left = LX.remapRange(h, 0, 360, -this.markerHalfSize, this.colorPickerTracker.offsetWidth - this.markerHalfSize)
2563
+ + 'px';
2642
2564
  this._updateColorValue(hexColor);
2643
2565
  }
2644
2566
  }
@@ -2677,10 +2599,9 @@ class Popover {
2677
2599
  this.alignOffset = options.alignOffset ?? this.alignOffset;
2678
2600
  this.avoidCollisions = options.avoidCollisions ?? true;
2679
2601
  this.reference = options.reference;
2680
- this.root = document.createElement('div');
2602
+ this.root = LX.makeElement('div', 'lexpopover fixed bg-background rounded-lg border-color p-1 left-0 top-0');
2681
2603
  this.root.dataset['side'] = this.side;
2682
2604
  this.root.tabIndex = '1';
2683
- this.root.className = 'lexpopover';
2684
2605
  const refElement = trigger ?? this.reference;
2685
2606
  const nestedDialog = refElement.closest('dialog');
2686
2607
  if (nestedDialog && nestedDialog.dataset['modal'] == 'true') {
@@ -2813,11 +2734,11 @@ class PopConfirm {
2813
2734
  const popoverContainer = LX.makeContainer(['auto', 'auto'], 'tour-step-container');
2814
2735
  {
2815
2736
  const headerDiv = LX.makeContainer(['100%', 'auto'], 'flex flex-row', '', popoverContainer);
2816
- LX.makeContainer(['100%', 'auto'], 'p-1 font-medium text-md', title, headerDiv);
2737
+ LX.makeContainer(['100%', 'auto'], 'p-1 font-medium text-base', title, headerDiv);
2817
2738
  }
2818
- LX.makeContainer(['100%', 'auto'], 'p-1 text-md', content, popoverContainer, { maxWidth: '400px' });
2819
- const footer = LX.makeContainer(['100%', 'auto'], 'flex flex-row text-md', '', popoverContainer);
2820
- const footerButtons = LX.makeContainer(['100%', 'auto'], 'text-md', '', footer);
2739
+ LX.makeContainer(['100%', 'auto'], 'p-1 text-base', content, popoverContainer, { maxWidth: '400px' });
2740
+ const footer = LX.makeContainer(['100%', 'auto'], 'flex flex-row text-base', '', popoverContainer);
2741
+ const footerButtons = LX.makeContainer(['100%', 'auto'], 'text-base', '', footer);
2821
2742
  const footerPanel = new LX.Panel();
2822
2743
  footerButtons.appendChild(footerPanel.root);
2823
2744
  footerPanel.sameLine(2, 'justify-end');
@@ -2825,7 +2746,7 @@ class PopConfirm {
2825
2746
  if (onCancel)
2826
2747
  onCancel();
2827
2748
  this._popover?.destroy();
2828
- }, { xbuttonClass: 'contrast' });
2749
+ });
2829
2750
  footerPanel.addButton(null, okText, () => {
2830
2751
  if (onConfirm)
2831
2752
  onConfirm();
@@ -2854,12 +2775,15 @@ class ColorInput extends BaseComponent {
2854
2775
  _popover = undefined;
2855
2776
  constructor(name, value, callback, options = {}) {
2856
2777
  value = value ?? '#000000';
2778
+ // Force always hex internally
2779
+ if (value.constructor === String && value.includes('oklch')) {
2780
+ value = LX.oklchToHex(value);
2781
+ }
2857
2782
  const useAlpha = options.useAlpha
2858
2783
  ?? ((value.constructor === Object && 'a' in value)
2859
2784
  || (value.constructor === String && [5, 9].includes(value.length)));
2860
2785
  const componentColor = new Color(value);
2861
- // Force always hex internally
2862
- value = useAlpha ? componentColor.hex : componentColor.hex.substr(0, 7);
2786
+ value = useAlpha ? componentColor.hex : componentColor.hex.substring(0, 7);
2863
2787
  super(ComponentType.COLOR, name, value, options);
2864
2788
  this.onGetValue = () => {
2865
2789
  const currentColor = new Color(value);
@@ -2867,7 +2791,7 @@ class ColorInput extends BaseComponent {
2867
2791
  };
2868
2792
  this.onSetValue = (newValue, skipCallback, event) => {
2869
2793
  const newColor = new Color(newValue);
2870
- colorSampleRGB.style.color = value = newColor.hex.substr(0, 7);
2794
+ colorSampleRGB.style.color = value = newColor.hex.substring(0, 7);
2871
2795
  if (useAlpha) {
2872
2796
  colorSampleAlpha.style.color = value = newColor.hex;
2873
2797
  }
@@ -2899,7 +2823,7 @@ class ColorInput extends BaseComponent {
2899
2823
  this.set(color.hex);
2900
2824
  }
2901
2825
  });
2902
- let sampleContainer = LX.makeContainer(['18px', '18px'], 'flex flex-row bg-contrast rounded overflow-hidden', '', container);
2826
+ let sampleContainer = LX.makeContainer(['18px', '18px'], 'flex flex-row rounded overflow-hidden', '', container);
2903
2827
  sampleContainer.tabIndex = '1';
2904
2828
  sampleContainer.addEventListener('click', (e) => {
2905
2829
  if ((options.disabled ?? false)) {
@@ -2946,42 +2870,18 @@ class ComboButtons extends BaseComponent {
2946
2870
  const shouldSelect = !(options.noSelection ?? false);
2947
2871
  let shouldToggle = shouldSelect && (options.toggle ?? false);
2948
2872
  let container = document.createElement('div');
2949
- container.className = 'lexcombobuttons ';
2873
+ container.className = 'lexcombobuttons flex justify-center';
2950
2874
  options.skipReset = true;
2951
2875
  if (options.float) {
2952
- container.className += options.float;
2876
+ container.className = LX.mergeClass(container.className, `justify-${options.float}`);
2953
2877
  }
2954
2878
  let currentValue = [];
2955
- let buttonsBox = document.createElement('div');
2956
- buttonsBox.className = 'lexcombobuttonsbox ';
2957
- container.appendChild(buttonsBox);
2879
+ let buttonsBox = LX.makeElement('div', 'flex w-max bg-secondary pad-sm rounded-lg gap-1', '', container);
2958
2880
  for (let b of values) {
2959
2881
  if (!b.value) {
2960
2882
  throw ("Set 'value' for each button!");
2961
2883
  }
2962
- let buttonEl = document.createElement('button');
2963
- buttonEl.className = 'lexbutton combo';
2964
- buttonEl.title = b.icon ? b.value : '';
2965
- buttonEl.id = b.id ?? '';
2966
- buttonEl.dataset['value'] = b.value;
2967
- if (options.buttonClass) {
2968
- buttonEl.classList.add(options.buttonClass);
2969
- }
2970
- if (shouldSelect && (b.selected || options.selected?.includes(b.value))) {
2971
- buttonEl.classList.add('selected');
2972
- currentValue = currentValue.concat([b.value]);
2973
- }
2974
- if (b.icon) {
2975
- const icon = LX.makeIcon(b.icon);
2976
- buttonEl.appendChild(icon);
2977
- }
2978
- else {
2979
- buttonEl.innerHTML = `<span>${b.value}</span>`;
2980
- }
2981
- if (b.disabled) {
2982
- buttonEl.setAttribute('disabled', 'true');
2983
- }
2984
- buttonEl.addEventListener('click', (e) => {
2884
+ const onClick = (event) => {
2985
2885
  currentValue = [];
2986
2886
  if (shouldSelect) {
2987
2887
  if (shouldToggle) {
@@ -3003,7 +2903,20 @@ class ComboButtons extends BaseComponent {
3003
2903
  }
3004
2904
  currentValue = currentValue[0];
3005
2905
  this.set(b.value, false, buttonEl.classList.contains('selected'));
2906
+ };
2907
+ const button = new Button(b.name ?? null, b.value, onClick, {
2908
+ title: b.icon ? b.value : '',
2909
+ icon: b.icon,
2910
+ disabled: b.disabled,
2911
+ buttonClass: LX.mergeClass('combo w-auto', options.buttonClass)
3006
2912
  });
2913
+ let buttonEl = button.root.querySelector('button');
2914
+ buttonEl.id = b.id ?? '';
2915
+ buttonEl.dataset['value'] = b.value;
2916
+ if (shouldSelect && (b.selected || options.selected?.includes(b.value))) {
2917
+ buttonEl.classList.add('selected');
2918
+ currentValue = currentValue.concat([b.value]);
2919
+ }
3007
2920
  buttonsBox.appendChild(buttonEl);
3008
2921
  }
3009
2922
  if (currentValue.length > 1) {
@@ -3069,9 +2982,9 @@ class Counter extends BaseComponent {
3069
2982
  const max = options.max ?? 100;
3070
2983
  const step = options.step ?? 1;
3071
2984
  const container = document.createElement('div');
3072
- container.className = 'flex flex-row border bg-primary rounded-lg shadow';
2985
+ container.className = 'flex flex-row border-color bg-card rounded-lg shadow';
3073
2986
  this.root.appendChild(container);
3074
- const input = LX.makeElement('input', 'lexcounter w-12 bg-primary px-2 fg-primary', '', container);
2987
+ const input = LX.makeElement('input', 'lexcounter w-12 bg-card px-2 text-foreground', '', container);
3075
2988
  input.type = 'number';
3076
2989
  input.value = value;
3077
2990
  if (options.disabled) {
@@ -3082,9 +2995,8 @@ class Counter extends BaseComponent {
3082
2995
  if (e.shiftKey)
3083
2996
  mult *= 10;
3084
2997
  this.set(this.count - mult, false, e);
3085
- }, { disabled: options.disabled,
3086
- className: `p-0 ${options.disabled ? '' : 'hover:bg-secondary'} border-left border-right`,
3087
- buttonClass: 'bg-none', icon: 'Minus' });
2998
+ }, { disabled: options.disabled, className: `p-0 ${options.disabled ? '' : 'hover:bg-secondary'} border-l-color border-r-color`,
2999
+ buttonClass: 'px-0 bg-none h-7', icon: 'Minus' });
3088
3000
  container.appendChild(substrButton.root);
3089
3001
  const addButton = new Button(null, '', (value, e) => {
3090
3002
  let mult = step ?? 1;
@@ -3092,7 +3004,7 @@ class Counter extends BaseComponent {
3092
3004
  mult *= 10;
3093
3005
  this.set(this.count + mult, false, e);
3094
3006
  }, { disabled: options.disabled, className: `p-0 ${options.disabled ? '' : 'hover:bg-secondary'} rounded-r-lg`,
3095
- buttonClass: 'bg-none', icon: 'Plus' });
3007
+ buttonClass: 'px-0 bg-none h-7', icon: 'Plus' });
3096
3008
  container.appendChild(addButton.root);
3097
3009
  }
3098
3010
  }
@@ -3108,14 +3020,14 @@ class CanvasCurve {
3108
3020
  canvas;
3109
3021
  constructor(value, options = {}) {
3110
3022
  let element = document.createElement('div');
3111
- element.className = 'curve ' + (options.className ? options.className : '');
3023
+ element.className = LX.mergeClass('curve [&_canvas]:rounded', options.className);
3112
3024
  element.style.minHeight = '50px';
3113
3025
  element.style.width = options.width || '100%';
3114
3026
  element.style.minWidth = '50px';
3115
3027
  element.style.minHeight = '20px';
3116
- element.bgcolor = options.bgColor || LX.getThemeColor('global-background');
3117
- element.pointscolor = options.pointsColor || LX.getThemeColor('global-color-accent');
3118
- element.activepointscolor = options.activePointsColor || LX.getThemeColor('global-color-accent-light');
3028
+ element.bgcolor = options.bgColor || LX.getCSSVariable('background');
3029
+ element.pointscolor = options.pointsColor || LX.getCSSVariable('primary');
3030
+ element.activepointscolor = options.activePointsColor || LX.getCSSVariable('primary/50');
3119
3031
  element.linecolor = options.lineColor || '#555';
3120
3032
  element.value = value || [];
3121
3033
  element.xrange = options.xrange || [0, 1]; // min, max
@@ -3129,9 +3041,9 @@ class CanvasCurve {
3129
3041
  element.smooth = (options.smooth && typeof (options.smooth) == 'number' ? options.smooth : 0.3) || false;
3130
3042
  element.move_out = options.moveOutAction ?? LX.CURVE_MOVEOUT_DELETE;
3131
3043
  LX.addSignal('@on_new_color_scheme', (el, value) => {
3132
- element.bgcolor = options.bgColor || LX.getThemeColor('global-background');
3133
- element.pointscolor = options.pointsColor || LX.getThemeColor('global-color-accent');
3134
- element.activepointscolor = options.activePointsColor || LX.getThemeColor('global-color-accent-light');
3044
+ element.bgcolor = options.bgColor || LX.getCSSVariable('background');
3045
+ element.pointscolor = options.pointsColor || LX.getCSSVariable('primary');
3046
+ element.activepointscolor = options.activePointsColor || LX.getCSSVariable('primary/50');
3135
3047
  this.redraw();
3136
3048
  });
3137
3049
  this.element = element;
@@ -3188,8 +3100,7 @@ class CanvasCurve {
3188
3100
  }
3189
3101
  // Canvas to value
3190
3102
  function unconvert(v) {
3191
- return [v[0] * element.xrange[1] / canvas.width + element.xrange[0],
3192
- v[1] * element.yrange[1] / canvas.height + element.yrange[0]];
3103
+ return [v[0] * element.xrange[1] / canvas.width + element.xrange[0], v[1] * element.yrange[1] / canvas.height + element.yrange[0]];
3193
3104
  }
3194
3105
  let selected = -1;
3195
3106
  element.redraw = function (o = {}) {
@@ -3466,7 +3377,7 @@ class Calendar {
3466
3377
  onPreviousMonth;
3467
3378
  onNextMonth;
3468
3379
  constructor(dateString, options = {}) {
3469
- this.root = LX.makeContainer(['256px', 'auto'], 'p-1 text-md');
3380
+ this.root = LX.makeContainer(['256px', 'auto'], 'p-1 flex flex-col gap-2 text-sm');
3470
3381
  this.onChange = options.onChange;
3471
3382
  this.onPreviousMonth = options.onPreviousMonth;
3472
3383
  this.onNextMonth = options.onNextMonth;
@@ -3521,8 +3432,8 @@ class Calendar {
3521
3432
  {
3522
3433
  const header = LX.makeContainer(['100%', 'auto'], 'flex flex-row p-1', '', this.root);
3523
3434
  if (!this.skipPrevMonth) {
3524
- const prevMonthIcon = LX.makeIcon('Left', { title: 'Previous Month',
3525
- iconClass: 'border p-1 rounded hover:bg-secondary', svgClass: 'sm' });
3435
+ const prevMonthIcon = LX.makeIcon('Left', { title: 'Previous Month', iconClass: 'border-color p-1 rounded hover:bg-secondary',
3436
+ svgClass: 'sm' });
3526
3437
  header.appendChild(prevMonthIcon);
3527
3438
  prevMonthIcon.addEventListener('click', () => {
3528
3439
  this._previousMonth();
@@ -3530,8 +3441,8 @@ class Calendar {
3530
3441
  }
3531
3442
  LX.makeContainer(['100%', 'auto'], 'text-center font-medium select-none', `${this.monthName} ${this.year}`, header);
3532
3443
  if (!this.skipNextMonth) {
3533
- const nextMonthIcon = LX.makeIcon('Right', { title: 'Next Month',
3534
- iconClass: 'border p-1 rounded hover:bg-secondary', svgClass: 'sm' });
3444
+ const nextMonthIcon = LX.makeIcon('Right', { title: 'Next Month', iconClass: 'border-color p-1 rounded hover:bg-secondary',
3445
+ svgClass: 'sm' });
3535
3446
  header.appendChild(nextMonthIcon);
3536
3447
  nextMonthIcon.addEventListener('click', () => {
3537
3448
  this._nextMonth();
@@ -3550,7 +3461,7 @@ class Calendar {
3550
3461
  const hrow = document.createElement('tr');
3551
3462
  for (const headData of ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su']) {
3552
3463
  const th = document.createElement('th');
3553
- th.className = 'fg-tertiary text-sm font-normal select-none';
3464
+ th.className = 'text-muted-foreground text-xs font-normal w-10 select-none';
3554
3465
  th.innerHTML = `<span>${headData}</span>`;
3555
3466
  hrow.appendChild(th);
3556
3467
  }
@@ -3567,7 +3478,7 @@ class Calendar {
3567
3478
  const weekDays = this.calendarDays.slice(week * 7, week * 7 + 7);
3568
3479
  for (const dayData of weekDays) {
3569
3480
  const th = document.createElement('th');
3570
- th.className = 'leading-loose font-normal rounded select-none cursor-pointer';
3481
+ th.className = 'leading-8 text-xs font-normal rounded select-none cursor-pointer shrink-0 grow-0';
3571
3482
  const dayDate = new Date(`${this.month}/${dayData.day}/${this.year}`);
3572
3483
  const date = new Date();
3573
3484
  // today inclusives
@@ -3591,13 +3502,13 @@ class Calendar {
3591
3502
  && (this.month == (toRangeDate.getMonth() + 1))
3592
3503
  && (this.year == toRangeDate.getFullYear());
3593
3504
  if ((!this.range && currentDay) || this.range && (currentFromRange || currentToRange)) {
3594
- th.className += ` bg-contrast fg-contrast`;
3505
+ th.className += ` bg-primary text-primary-foreground`;
3595
3506
  }
3596
3507
  else if (this.range && selectable && (dayDate > fromRangeDate) && (dayDate < toRangeDate)) {
3597
- th.className += ` bg-accent fg-contrast`;
3508
+ th.className += ` bg-accent text-accent-foreground`;
3598
3509
  }
3599
3510
  else {
3600
- th.className += ` ${selectable ? 'fg-primary' : 'fg-tertiary'} hover:bg-secondary`;
3511
+ th.className += ` ${selectable ? 'text-secondary-foreground' : 'text-muted-foreground'} hover:bg-secondary`;
3601
3512
  }
3602
3513
  th.innerHTML = `<span>${dayData.day}</span>`;
3603
3514
  hrow.appendChild(th);
@@ -3841,7 +3752,7 @@ class DatePicker extends BaseComponent {
3841
3752
  const calendarIcon = LX.makeIcon('Calendar');
3842
3753
  const calendarButton = new Button(null, d0, () => {
3843
3754
  this._popover = new Popover(calendarButton.root, [this.calendar]);
3844
- }, { buttonClass: `flex flex-row px-3 ${emptyDate ? '' : 'fg-tertiary'} justify-between` });
3755
+ }, { buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3845
3756
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
3846
3757
  calendarButton.root.style.width = '100%';
3847
3758
  container.appendChild(calendarButton.root);
@@ -3852,7 +3763,7 @@ class DatePicker extends BaseComponent {
3852
3763
  const calendarIcon = LX.makeIcon('Calendar');
3853
3764
  const calendarButton = new Button(null, d1, () => {
3854
3765
  this._popover = new Popover(calendarButton.root, [this.calendar]);
3855
- }, { buttonClass: `flex flex-row px-3 ${emptyDate ? '' : 'fg-tertiary'} justify-between` });
3766
+ }, { buttonClass: `outline flex flex-row px-3 ${emptyDate ? '' : 'text-muted-foreground'} justify-between` });
3856
3767
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
3857
3768
  calendarButton.root.style.width = '100%';
3858
3769
  container.appendChild(calendarButton.root);
@@ -3881,11 +3792,11 @@ class CanvasDial {
3881
3792
  canvas;
3882
3793
  constructor(value, options = {}) {
3883
3794
  let element = document.createElement('div');
3884
- element.className = 'dial ' + (options.className ? options.className : '');
3795
+ element.className = LX.mergeClass('dial', options.className);
3885
3796
  element.style.width = element.style.height = options.size || '100%';
3886
3797
  element.style.minWidth = element.style.minHeight = '50px';
3887
- element.bgcolor = options.bgColor || LX.getThemeColor('global-background');
3888
- element.pointscolor = options.pointsColor || LX.getThemeColor('global-color-accent-light');
3798
+ element.bgcolor = options.bgColor || LX.getCSSVariable('background');
3799
+ element.pointscolor = options.pointsColor || LX.getCSSVariable('primary/50');
3889
3800
  element.linecolor = options.lineColor || '#555';
3890
3801
  element.value = value || [];
3891
3802
  element.xrange = options.xrange || [0, 1]; // min, max
@@ -3899,8 +3810,8 @@ class CanvasDial {
3899
3810
  element.smooth = (options.smooth && typeof (options.smooth) == 'number' ? options.smooth : 0.3) || false;
3900
3811
  element.move_out = options.moveOutAction ?? LX.CURVE_MOVEOUT_DELETE;
3901
3812
  LX.addSignal('@on_new_color_scheme', (el, value) => {
3902
- element.bgcolor = options.bgColor || LX.getThemeColor('global-background');
3903
- element.pointscolor = options.pointsColor || LX.getThemeColor('global-color-accent-light');
3813
+ element.bgcolor = options.bgColor || LX.getCSSVariable('background');
3814
+ element.pointscolor = options.pointsColor || LX.getCSSVariable('primary/50');
3904
3815
  this.redraw();
3905
3816
  });
3906
3817
  this.element = element;
@@ -3956,8 +3867,7 @@ class CanvasDial {
3956
3867
  }
3957
3868
  // Canvas to value
3958
3869
  function unconvert(v) {
3959
- return [v[0] * element.xrange[1] / canvas.width + element.xrange[0],
3960
- v[1] * element.yrange[1] / canvas.height + element.yrange[0]];
3870
+ return [v[0] * element.xrange[1] / canvas.width + element.xrange[0], v[1] * element.yrange[1] / canvas.height + element.yrange[0]];
3961
3871
  }
3962
3872
  var selected = -1;
3963
3873
  element.redraw = function (o = {}) {
@@ -4314,7 +4224,7 @@ class Form extends BaseComponent {
4314
4224
  }
4315
4225
  };
4316
4226
  let container = document.createElement('div');
4317
- container.className = 'lexformdata';
4227
+ container.className = 'flex flex-col gap-1';
4318
4228
  container.style.width = '100%';
4319
4229
  container.formData = {};
4320
4230
  this.root.appendChild(container);
@@ -4330,7 +4240,7 @@ class Form extends BaseComponent {
4330
4240
  entryData.ignoreValidation = true;
4331
4241
  if (!(options.skipLabels ?? false)) {
4332
4242
  const label = new TextInput(null, entryData.label ?? entry, null, { disabled: true,
4333
- inputClass: 'formlabel bg-none' });
4243
+ inputClass: 'formlabel text-xs bg-none text-muted-foreground' });
4334
4244
  container.appendChild(label.root);
4335
4245
  }
4336
4246
  entryData.textComponent = new TextInput(null, entryData.constructor == Object ? entryData.value : entryData, (value, event) => {
@@ -4348,7 +4258,7 @@ class Form extends BaseComponent {
4348
4258
  if (options.secondaryActionCallback) {
4349
4259
  options.secondaryActionCallback(container.formData, event);
4350
4260
  }
4351
- }, { width: '100%', minWidth: '0', buttonClass: options.secondaryButtonClass ?? 'primary' });
4261
+ }, { width: '100%', minWidth: '0', buttonClass: options.secondaryButtonClass ?? 'secondary' });
4352
4262
  buttonContainer.appendChild(secondaryButton.root);
4353
4263
  }
4354
4264
  const primaryButton = new Button(null, options.primaryActionName ?? 'Submit', (value, event) => {
@@ -4368,7 +4278,7 @@ class Form extends BaseComponent {
4368
4278
  if (callback) {
4369
4279
  callback(container.formData, errors, event);
4370
4280
  }
4371
- }, { width: '100%', minWidth: '0', buttonClass: options.primaryButtonClass ?? 'contrast' });
4281
+ }, { width: '100%', minWidth: '0', buttonClass: options.primaryButtonClass ?? 'primary' });
4372
4282
  buttonContainer.appendChild(primaryButton.root);
4373
4283
  }
4374
4284
  }
@@ -4397,9 +4307,7 @@ class Layers extends BaseComponent {
4397
4307
  const realNameWidth = this.root.domName?.style.width ?? '0px';
4398
4308
  container.style.width = `calc( 100% - ${realNameWidth})`;
4399
4309
  };
4400
- const container = document.createElement('div');
4401
- container.className = 'lexlayers';
4402
- this.root.appendChild(container);
4310
+ const container = LX.makeElement('div', 'lexlayers grid', '', this.root);
4403
4311
  const maxBits = options.maxBits ?? 16;
4404
4312
  this.setLayers = (val) => {
4405
4313
  container.innerHTML = '';
@@ -4411,7 +4319,8 @@ class Layers extends BaseComponent {
4411
4319
  }
4412
4320
  for (let bit = 0; bit < maxBits; ++bit) {
4413
4321
  let layer = document.createElement('div');
4414
- layer.className = 'lexlayer';
4322
+ layer.className =
4323
+ 'lexlayer size-6 text-secondary-foreground text-center content-center place-self-center cursor-pointer font-semibold text-xs rounded-lg';
4415
4324
  if (val != undefined) {
4416
4325
  const valueBit = binary[maxBits - bit - 1];
4417
4326
  if (valueBit != undefined && valueBit == '1') {
@@ -4499,7 +4408,7 @@ class List extends BaseComponent {
4499
4408
  };
4500
4409
  // Show list
4501
4410
  let listContainer = document.createElement('div');
4502
- listContainer.className = 'lexlist';
4411
+ listContainer.className = 'bg-background flex flex-col gap-1 rounded-xl border-color p-2';
4503
4412
  this.root.appendChild(listContainer);
4504
4413
  this._updateValues(values);
4505
4414
  LX.doAsync(this.onResize.bind(this));
@@ -4945,7 +4854,7 @@ class Map2D extends BaseComponent {
4945
4854
  const calendarIcon = LX.makeIcon('SquareMousePointer');
4946
4855
  const calendarButton = new Button(null, 'Open Map', () => {
4947
4856
  this._popover = new Popover(calendarButton.root, [this.map2d]);
4948
- }, { buttonClass: `flex flex-row px-3 fg-secondary justify-between` });
4857
+ }, { buttonClass: `outline justify-between` });
4949
4858
  calendarButton.root.querySelector('button').appendChild(calendarIcon);
4950
4859
  container.appendChild(calendarButton.root);
4951
4860
  LX.doAsync(this.onResize.bind(this));
@@ -4960,14 +4869,13 @@ LX.Map2D = Map2D;
4960
4869
  class NodeTree {
4961
4870
  domEl;
4962
4871
  data;
4963
- onevent;
4964
4872
  options;
4965
4873
  selected = [];
4966
4874
  _forceClose = false;
4875
+ _callbacks = {};
4967
4876
  constructor(domEl, data, options = {}) {
4968
4877
  this.domEl = domEl;
4969
4878
  this.data = data;
4970
- this.onevent = options.onevent;
4971
4879
  this.options = options;
4972
4880
  if (data.constructor === Object) {
4973
4881
  this._createItem(null, data);
@@ -5001,8 +4909,8 @@ class NodeTree {
5001
4909
  isParent = !!hasFolders;
5002
4910
  }
5003
4911
  let item = document.createElement('li');
5004
- item.className = 'lextreeitem ' + 'datalevel' + level + (isParent ? ' parent' : '')
5005
- + (isSelected ? ' selected' : '');
4912
+ item.className =
4913
+ `lextreeitem inline-flex outline-none text-sm items-center h-7 cursor-pointer truncate rounded-lg select-none datalevel${level} ${isParent ? 'parent' : ''} ${isSelected ? ' selected' : ''}`;
5006
4914
  item.id = LX.getSupportedDOMName(node.id);
5007
4915
  item.tabIndex = '0';
5008
4916
  item.treeData = node;
@@ -5012,7 +4920,7 @@ class NodeTree {
5012
4920
  icon = node.closed ? 'Right' : 'Down';
5013
4921
  }
5014
4922
  if (icon) {
5015
- item.appendChild(LX.makeIcon(icon, { iconClass: 'hierarchy', svgClass: 'xs' }));
4923
+ item.appendChild(LX.makeIcon(icon, { iconClass: 'hierarchy', svgClass: 'sm' }));
5016
4924
  }
5017
4925
  // Add display icon
5018
4926
  icon = node.icon;
@@ -5027,13 +4935,15 @@ class NodeTree {
5027
4935
  // an image..
5028
4936
  else {
5029
4937
  const rootPath = 'https://raw.githubusercontent.com/jxarco/lexgui.js/master/';
5030
- item.innerHTML += "<img src='" + (rootPath + node.icon) + "'>";
4938
+ item.innerHTML += `<img src="${rootPath + node.icon}">`;
5031
4939
  }
5032
4940
  }
5033
4941
  item.innerHTML += node.rename ? '' : node.id;
5034
- item.setAttribute('draggable', true);
5035
4942
  item.style.paddingLeft = (3 + (level + 1) * 15) + 'px';
5036
4943
  list.appendChild(item);
4944
+ const isDraggable = parent && (node.metadata?.draggable ?? (this.options.defaultDraggable ?? true));
4945
+ if (isDraggable)
4946
+ item.setAttribute('draggable', 'true');
5037
4947
  // Callbacks
5038
4948
  item.addEventListener('click', (e) => {
5039
4949
  if (handled) {
@@ -5048,27 +4958,38 @@ class NodeTree {
5048
4958
  }
5049
4959
  // Add or remove
5050
4960
  const idx = this.selected.indexOf(node);
4961
+ item.classList.toggle('selected', idx == -1);
5051
4962
  if (idx > -1) {
5052
- item.classList.remove('selected');
5053
4963
  this.selected.splice(idx, 1);
5054
4964
  }
5055
4965
  else {
5056
- item.classList.add('selected');
5057
4966
  this.selected.push(node);
5058
4967
  }
5059
4968
  // Only Show children...
5060
4969
  if (isParent && node.id.length > 1 /* Strange case... */) {
5061
4970
  node.closed = false;
5062
- if (that.onevent) {
5063
- const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed, e);
5064
- that.onevent(event);
4971
+ const onCaretChanged = that._callbacks['caretChanged'];
4972
+ if (onCaretChanged !== undefined) {
4973
+ const event = {
4974
+ type: 'caret',
4975
+ items: [node],
4976
+ domEvent: e,
4977
+ userInitiated: true
4978
+ };
4979
+ onCaretChanged(event);
5065
4980
  }
5066
4981
  that.frefresh(node.id);
5067
4982
  }
5068
- if (that.onevent) {
5069
- const event = new TreeEvent(TreeEvent.NODE_SELECTED, node, this.selected, e);
5070
- event.multiple = e.shiftKey;
5071
- that.onevent(event);
4983
+ const onSelect = that._callbacks['select'];
4984
+ if (onSelect !== undefined) {
4985
+ const event = {
4986
+ type: 'select',
4987
+ items: [node],
4988
+ result: this.selected,
4989
+ domEvent: e,
4990
+ userInitiated: true
4991
+ };
4992
+ onSelect(event);
5072
4993
  }
5073
4994
  });
5074
4995
  item.addEventListener('dblclick', function (e) {
@@ -5077,27 +4998,40 @@ class NodeTree {
5077
4998
  node.rename = true;
5078
4999
  that.refresh();
5079
5000
  }
5080
- if (that.onevent) {
5081
- const event = new TreeEvent(TreeEvent.NODE_DBLCLICKED, node, null, e);
5082
- that.onevent(event);
5001
+ const onDblClick = that._callbacks['dblClick'];
5002
+ if (onDblClick !== undefined) {
5003
+ const event = {
5004
+ type: 'dbl_click',
5005
+ items: [node],
5006
+ domEvent: e,
5007
+ userInitiated: true
5008
+ };
5009
+ onDblClick(event);
5083
5010
  }
5084
5011
  });
5085
- item.addEventListener('contextmenu', (e) => {
5012
+ item.addEventListener('contextmenu', async (e) => {
5086
5013
  e.preventDefault();
5087
- if (!that.onevent) {
5014
+ const onContextMenu = that._callbacks['contextMenu'];
5015
+ if (!onContextMenu) {
5088
5016
  return;
5089
5017
  }
5090
- const event = new TreeEvent(TreeEvent.NODE_CONTEXTMENU, node, this.selected, e);
5091
- event.multiple = this.selected.length > 1;
5092
- LX.addContextMenu(event.multiple ? 'Selected Nodes' : event.node.id, event.event, (m) => {
5093
- event.panel = m;
5094
- });
5095
- that.onevent(event);
5096
- if (this.options.addDefault ?? false) {
5097
- if (event.panel.items) {
5098
- event.panel.add('');
5018
+ const event = {
5019
+ type: 'context_menu',
5020
+ items: this.selected,
5021
+ from: node,
5022
+ domEvent: e,
5023
+ userInitiated: true
5024
+ };
5025
+ const r = await onContextMenu(event);
5026
+ const multiple = this.selected.length > 1;
5027
+ LX.addContextMenu(multiple ? 'Selected Nodes' : node.id, e, (m) => {
5028
+ if (r?.length) {
5029
+ for (const i of r) {
5030
+ m.add(i.name, { callback: i.callback });
5031
+ }
5032
+ m.add('');
5099
5033
  }
5100
- event.panel.add('Select Children', () => {
5034
+ m.add('Select Children', () => {
5101
5035
  const selectChildren = (n) => {
5102
5036
  if (n.closed) {
5103
5037
  return;
@@ -5116,15 +5050,53 @@ class NodeTree {
5116
5050
  this.selected.length = 0;
5117
5051
  // Add childs of the clicked node
5118
5052
  selectChildren(node);
5053
+ const onSelect = this._callbacks['select'];
5054
+ if (onSelect !== undefined) {
5055
+ const event = {
5056
+ type: 'select',
5057
+ items: [node],
5058
+ result: this.selected,
5059
+ domEvent: e,
5060
+ userInitiated: true
5061
+ };
5062
+ onSelect(event);
5063
+ }
5119
5064
  });
5120
- event.panel.add('Delete', { callback: () => {
5121
- const ok = that.deleteNode(node);
5122
- if (ok && that.onevent) {
5123
- const event = new TreeEvent(TreeEvent.NODE_DELETED, node, [node], null);
5124
- that.onevent(event);
5065
+ m.add('Delete', { callback: () => {
5066
+ const onBeforeDelete = this._callbacks['beforeDelete'];
5067
+ const onDelete = this._callbacks['delete'];
5068
+ const resolve = (...args) => {
5069
+ let deletedNodes = [];
5070
+ if (this.selected.length) {
5071
+ deletedNodes.push(...that.deleteNodes(this.selected));
5072
+ }
5073
+ else if (that.deleteNode(node)) {
5074
+ deletedNodes.push(node);
5075
+ }
5076
+ this.refresh();
5077
+ const event = {
5078
+ type: 'delete',
5079
+ items: deletedNodes,
5080
+ userInitiated: true
5081
+ };
5082
+ if (onDelete)
5083
+ onDelete(event, ...args);
5084
+ };
5085
+ if (onBeforeDelete) {
5086
+ const event = {
5087
+ type: 'delete',
5088
+ items: this.selected.length ? this.selected : [node],
5089
+ userInitiated: true
5090
+ };
5091
+ onBeforeDelete(event, resolve);
5092
+ }
5093
+ else {
5094
+ resolve();
5125
5095
  }
5126
- this.refresh();
5127
5096
  } });
5097
+ });
5098
+ if (!(this.options.addDefault ?? false)) {
5099
+ return;
5128
5100
  }
5129
5101
  });
5130
5102
  item.addEventListener('keydown', (e) => {
@@ -5133,20 +5105,40 @@ class NodeTree {
5133
5105
  }
5134
5106
  e.preventDefault();
5135
5107
  if (e.key == 'Delete') {
5136
- const nodesDeleted = [];
5137
- for (let _node of this.selected) {
5138
- if (that.deleteNode(_node)) {
5139
- nodesDeleted.push(_node);
5108
+ const onBeforeDelete = this._callbacks['beforeDelete'];
5109
+ const onDelete = this._callbacks['delete'];
5110
+ const resolve = (...args) => {
5111
+ const nodesDeleted = [];
5112
+ for (let n of this.selected) {
5113
+ if (that.deleteNode(n)) {
5114
+ nodesDeleted.push(n);
5115
+ }
5116
+ }
5117
+ this.selected.length = 0;
5118
+ this.refresh();
5119
+ if (nodesDeleted.length) {
5120
+ const event = {
5121
+ type: 'delete',
5122
+ items: nodesDeleted,
5123
+ domEvent: e,
5124
+ userInitiated: true
5125
+ };
5126
+ if (onDelete)
5127
+ onDelete(event, ...args);
5140
5128
  }
5129
+ };
5130
+ if (onBeforeDelete) {
5131
+ const event = {
5132
+ type: 'delete',
5133
+ items: this.selected,
5134
+ domEvent: e,
5135
+ userInitiated: true
5136
+ };
5137
+ onBeforeDelete(event, resolve);
5141
5138
  }
5142
- // Send event now so we have the info in selected array..
5143
- if (nodesDeleted.length && that.onevent) {
5144
- const event = new TreeEvent(TreeEvent.NODE_DELETED, node, nodesDeleted, e);
5145
- event.multiple = nodesDeleted.length > 1;
5146
- that.onevent(event);
5139
+ else {
5140
+ resolve();
5147
5141
  }
5148
- this.selected.length = 0;
5149
- this.refresh();
5150
5142
  }
5151
5143
  else if (e.key == 'ArrowUp' || e.key == 'ArrowDown') { // Unique or zero selected
5152
5144
  var selected = this.selected.length > 1
@@ -5162,7 +5154,7 @@ class NodeTree {
5162
5154
  // Node rename
5163
5155
  const nameInput = document.createElement('input');
5164
5156
  nameInput.toggleAttribute('hidden', !node.rename);
5165
- nameInput.className = 'bg-none';
5157
+ nameInput.className = 'text-foreground bg-none text-sm border-none outline-none';
5166
5158
  nameInput.value = node.id;
5167
5159
  item.appendChild(nameInput);
5168
5160
  if (node.rename) {
@@ -5171,15 +5163,38 @@ class NodeTree {
5171
5163
  }
5172
5164
  nameInput.addEventListener('keyup', function (e) {
5173
5165
  if (e.key == 'Enter') {
5166
+ const onBeforeRename = that._callbacks['beforeRename'];
5167
+ const onRename = that._callbacks['rename'];
5168
+ const oldName = node.id;
5174
5169
  this.value = this.value.replace(/\s/g, '_');
5175
- if (that.onevent) {
5176
- const event = new TreeEvent(TreeEvent.NODE_RENAMED, node, this.value, e);
5177
- that.onevent(event);
5170
+ const resolve = (...args) => {
5171
+ node.id = LX.getSupportedDOMName(this.value);
5172
+ delete node.rename;
5173
+ that.frefresh(node.id);
5174
+ list.querySelector(`#${node.id}`).classList.add('selected');
5175
+ const event = {
5176
+ type: 'rename',
5177
+ items: [node],
5178
+ oldName,
5179
+ newName: this.value,
5180
+ userInitiated: true
5181
+ };
5182
+ if (onRename)
5183
+ onRename(event, ...args);
5184
+ };
5185
+ if (onBeforeRename) {
5186
+ const event = {
5187
+ type: 'rename',
5188
+ items: [node],
5189
+ oldName,
5190
+ newName: this.value,
5191
+ userInitiated: true
5192
+ };
5193
+ onBeforeRename(event, resolve);
5194
+ }
5195
+ else {
5196
+ resolve();
5178
5197
  }
5179
- node.id = LX.getSupportedDOMName(this.value);
5180
- delete node.rename;
5181
- that.frefresh(node.id);
5182
- list.querySelector('#' + node.id).classList.add('selected');
5183
5198
  }
5184
5199
  else if (e.key == 'Escape') {
5185
5200
  delete node.rename;
@@ -5190,69 +5205,90 @@ class NodeTree {
5190
5205
  delete node.rename;
5191
5206
  that.refresh();
5192
5207
  });
5193
- if (this.options.draggable ?? true) {
5194
- // Drag nodes
5195
- if (parent) { // Root doesn't move!
5196
- item.addEventListener('dragstart', (e) => {
5197
- window.__tree_node_dragged = node;
5198
- });
5199
- }
5200
- /* Events fired on other node items */
5201
- item.addEventListener('dragover', (e) => {
5202
- e.preventDefault(); // allow drop
5203
- }, false);
5204
- item.addEventListener('dragenter', (e) => {
5205
- e.target.classList.add('draggingover');
5206
- });
5207
- item.addEventListener('dragend', (e) => {
5208
- e.target.classList.remove('draggingover');
5209
- });
5210
- item.addEventListener('dragleave', (e) => {
5211
- e.target.classList.remove('draggingover');
5208
+ if (isDraggable) {
5209
+ item.addEventListener('dragstart', (e) => {
5210
+ window.__tree_node_dragged = node;
5212
5211
  });
5213
- item.addEventListener('drop', (e) => {
5214
- e.preventDefault(); // Prevent default action (open as link for some elements)
5215
- let dragged = window.__tree_node_dragged;
5216
- if (!dragged) {
5217
- // Test if we are moving from AssetView extension
5218
- dragged = window.__av_item_dragged;
5219
- if (dragged) {
5220
- dragged._nodeTarget = node;
5221
- }
5222
- return;
5223
- }
5224
- let target = node;
5225
- // Can't drop to same node
5226
- if (dragged.id == target.id) {
5227
- console.warn('Cannot parent node to itself!');
5228
- return;
5229
- }
5230
- // Can't drop to child node
5231
- const isChild = function (newParent, node) {
5232
- var result = false;
5233
- for (var c of node.children) {
5234
- if (c.id == newParent.id)
5235
- return true;
5236
- result = result || isChild(newParent, c);
5237
- }
5238
- return result;
5239
- };
5240
- if (isChild(target, dragged)) {
5241
- console.warn('Cannot parent node to a current child!');
5242
- return;
5212
+ }
5213
+ /* Events fired on other node items,
5214
+ by now everyone is a drop target, cancel in the event if necessary */
5215
+ item.addEventListener('dragover', (e) => {
5216
+ e.preventDefault(); // allow drop
5217
+ }, false);
5218
+ item.addEventListener('dragenter', (e) => {
5219
+ e.target.classList.add('draggingover');
5220
+ });
5221
+ item.addEventListener('dragend', (e) => {
5222
+ e.target.classList.remove('draggingover');
5223
+ });
5224
+ item.addEventListener('dragleave', (e) => {
5225
+ e.target.classList.remove('draggingover');
5226
+ });
5227
+ item.addEventListener('drop', (e) => {
5228
+ e.preventDefault(); // Prevent default action (open as link for some elements)
5229
+ let dragged = window.__tree_node_dragged;
5230
+ if (!dragged) {
5231
+ // Test if we are moving from AssetView extension
5232
+ dragged = window.__av_item_dragged;
5233
+ if (dragged) {
5234
+ dragged._nodeTarget = node;
5243
5235
  }
5244
- // Trigger node dragger event
5245
- if (that.onevent) {
5246
- const event = new TreeEvent(TreeEvent.NODE_DRAGGED, dragged, target, e);
5247
- that.onevent(event);
5236
+ return;
5237
+ }
5238
+ const domTarget = e.target;
5239
+ domTarget.classList.remove('draggingover');
5240
+ let target = node;
5241
+ // Can't drop to same node
5242
+ if (dragged.id == target.id) {
5243
+ console.warn('Cannot parent node to itself!');
5244
+ return;
5245
+ }
5246
+ // Can't drop to child node
5247
+ const isChild = function (newParent, node) {
5248
+ var result = false;
5249
+ for (var c of node.children) {
5250
+ if (c.id == newParent.id)
5251
+ return true;
5252
+ result = result || isChild(newParent, c);
5248
5253
  }
5254
+ return result;
5255
+ };
5256
+ if (isChild(target, dragged)) {
5257
+ console.warn('Cannot parent node to a current child!');
5258
+ return;
5259
+ }
5260
+ const onBeforeMove = this._callbacks['beforeMove'];
5261
+ const onMove = this._callbacks['move'];
5262
+ const resolve = (...args) => {
5249
5263
  const index = dragged.parent.children.findIndex((n) => n.id == dragged.id);
5250
5264
  const removed = dragged.parent.children.splice(index, 1);
5251
5265
  target.children.push(removed[0]);
5252
5266
  that.refresh();
5253
5267
  delete window.__tree_node_dragged;
5254
- });
5255
- }
5268
+ const event = {
5269
+ type: 'move',
5270
+ items: [dragged],
5271
+ to: target,
5272
+ domEvent: e,
5273
+ userInitiated: true
5274
+ };
5275
+ if (onMove)
5276
+ onMove(event, ...args);
5277
+ };
5278
+ if (onBeforeMove) {
5279
+ const event = {
5280
+ type: 'move',
5281
+ items: [dragged],
5282
+ to: target,
5283
+ domEvent: e,
5284
+ userInitiated: true
5285
+ };
5286
+ onBeforeMove(event, resolve);
5287
+ }
5288
+ else {
5289
+ resolve();
5290
+ }
5291
+ });
5256
5292
  let handled = false;
5257
5293
  // Show/hide children
5258
5294
  if (isParent) {
@@ -5272,15 +5308,21 @@ class NodeTree {
5272
5308
  else {
5273
5309
  node.closed = !node.closed;
5274
5310
  }
5275
- if (that.onevent) {
5276
- const event = new TreeEvent(TreeEvent.NODE_CARETCHANGED, node, node.closed, e);
5277
- that.onevent(event);
5311
+ const onCaretChanged = that._callbacks['caretChanged'];
5312
+ if (onCaretChanged !== undefined) {
5313
+ const event = {
5314
+ type: 'caret',
5315
+ items: [node],
5316
+ domEvent: e,
5317
+ userInitiated: true
5318
+ };
5319
+ onCaretChanged(event);
5278
5320
  }
5279
5321
  that.frefresh(node.id);
5280
5322
  });
5281
5323
  }
5282
5324
  // Add button icons
5283
- const inputContainer = document.createElement('div');
5325
+ const inputContainer = LX.makeElement('div', 'flex flex-row ml-auto mr-2');
5284
5326
  item.appendChild(inputContainer);
5285
5327
  if (node.actions) {
5286
5328
  for (let i = 0; i < node.actions.length; ++i) {
@@ -5290,15 +5332,8 @@ class NodeTree {
5290
5332
  if (action.callback) {
5291
5333
  action.callback(node, swapValue, event);
5292
5334
  }
5293
- }, { icon: action.icon, swap: action.swap, title: action.name, hideName: true, className: 'p-0 m-0',
5294
- buttonClass: 'p-0 m-0 bg-none no-h' });
5295
- actionBtn.root.style.minWidth = 'fit-content';
5296
- actionBtn.root.style.margin = '0'; // adding classes does not work
5297
- actionBtn.root.style.padding = '0'; // adding classes does not work
5298
- const _btn = actionBtn.root.querySelector('button');
5299
- _btn.style.minWidth = 'fit-content';
5300
- _btn.style.margin = '0'; // adding classes does not work
5301
- _btn.style.padding = '0'; // adding classes does not work
5335
+ }, { icon: action.icon, swap: action.swap, title: action.name, hideName: true, className: 'p-0 min-h-fit',
5336
+ buttonClass: 'px-0 h-full bg-none' });
5302
5337
  inputContainer.appendChild(actionBtn.root);
5303
5338
  }
5304
5339
  }
@@ -5306,13 +5341,18 @@ class NodeTree {
5306
5341
  const visibilityBtn = new Button(null, '', (swapValue, e) => {
5307
5342
  e.stopPropagation();
5308
5343
  node.visible = node.visible === undefined ? false : !node.visible;
5309
- // Trigger visibility event
5310
- if (that.onevent) {
5311
- const event = new TreeEvent(TreeEvent.NODE_VISIBILITY, node, node.visible, e);
5312
- that.onevent(event);
5344
+ const onVisibleChanged = this._callbacks['visibleChanged'];
5345
+ if (onVisibleChanged !== undefined) {
5346
+ const event = {
5347
+ type: 'visibility',
5348
+ items: [node],
5349
+ domEvent: e,
5350
+ userInitiated: true
5351
+ };
5352
+ onVisibleChanged(event);
5313
5353
  }
5314
- }, { icon: node.visible ? 'Eye' : 'EyeOff', swap: node.visible ? 'EyeOff' : 'Eye', title: 'Toggle visible',
5315
- className: 'p-0 m-0', buttonClass: 'bg-none' });
5354
+ }, { icon: node.visible ? 'Eye' : 'EyeOff', swap: node.visible ? 'EyeOff' : 'Eye', title: 'Toggle visible', className: 'p-0 min-h-fit',
5355
+ buttonClass: 'px-0 h-full bg-none' });
5316
5356
  inputContainer.appendChild(visibilityBtn.root);
5317
5357
  }
5318
5358
  const _hasChild = function (node, id) {
@@ -5375,6 +5415,15 @@ class NodeTree {
5375
5415
  this.selected = [el.treeData];
5376
5416
  el.focus();
5377
5417
  }
5418
+ deleteNodes(nodes) {
5419
+ const nodesDeleted = [];
5420
+ for (const n of nodes) {
5421
+ if (this.deleteNode(n)) {
5422
+ nodesDeleted.push(n);
5423
+ }
5424
+ }
5425
+ return nodesDeleted;
5426
+ }
5378
5427
  deleteNode(node) {
5379
5428
  const dataAsArray = this.data.constructor === Array;
5380
5429
  // Can be either Array or Object type data
@@ -5407,16 +5456,11 @@ class Tree extends BaseComponent {
5407
5456
  constructor(name, data, options = {}) {
5408
5457
  options.hideName = true;
5409
5458
  super(ComponentType.TREE, name, null, options);
5410
- let container = document.createElement('div');
5411
- container.className = 'lextree';
5412
- this.root.appendChild(container);
5459
+ let container = LX.makeElement('div', 'lextree p-1 rounded-lg w-full my-0 mx-auto font-medium text-sm min-h-3', '', this.root);
5413
5460
  if (name) {
5414
- let title = document.createElement('span');
5415
- title.innerHTML = name;
5416
- container.appendChild(title);
5461
+ LX.makeElement('span', 'block p-1 select-none text-base font-medium whitespace-nowrap', name, container);
5417
5462
  }
5418
- let toolsDiv = document.createElement('div');
5419
- toolsDiv.className = 'lextreetools';
5463
+ let toolsDiv = LX.makeElement('div', 'lextreetools flex items-center bg-secondary px-2 rounded-lg gap-2 my-1');
5420
5464
  if (!name) {
5421
5465
  toolsDiv.className += ' notitle';
5422
5466
  }
@@ -5447,13 +5491,20 @@ class Tree extends BaseComponent {
5447
5491
  container.appendChild(toolsDiv);
5448
5492
  }
5449
5493
  // Tree
5450
- let list = document.createElement('ul');
5494
+ let list = LX.makeElement('ul', 'flex flex-col gap-1 ps-0');
5451
5495
  list.addEventListener('contextmenu', function (e) {
5452
5496
  e.preventDefault();
5453
5497
  });
5454
5498
  container.appendChild(list);
5455
5499
  this.innerTree = new NodeTree(container, data, options);
5456
5500
  }
5501
+ /**
5502
+ * @method on
5503
+ * @description Stores an event callback for the desired action
5504
+ */
5505
+ on(eventName, callback) {
5506
+ this.innerTree._callbacks[eventName] = callback;
5507
+ }
5457
5508
  }
5458
5509
  LX.Tree = Tree;
5459
5510
 
@@ -5478,7 +5529,7 @@ class OTPInput extends BaseComponent {
5478
5529
  value = newValue;
5479
5530
  _refreshInput(value);
5480
5531
  if (!skipCallback) {
5481
- this._trigger(new IEvent(name, +newValue, event), callback);
5532
+ this._trigger(new IEvent(name, newValue, event), callback);
5482
5533
  }
5483
5534
  };
5484
5535
  this.onResize = (rect) => {
@@ -5499,7 +5550,7 @@ class OTPInput extends BaseComponent {
5499
5550
  for (let j = 0; j < g.length; ++j) {
5500
5551
  let number = valueString[itemsCount++];
5501
5552
  number = number == 'x' ? '' : number;
5502
- const slotDom = LX.makeContainer(['36px', '30px'], 'lexotpslot border-top border-bottom border-left px-3 cursor-text select-none font-medium outline-none', number, container);
5553
+ const slotDom = LX.makeContainer(['36px', '30px'], 'lexotpslot border-t-color border-b-color border-l-color px-3 cursor-text select-none font-medium outline-none', number, container);
5503
5554
  slotDom.tabIndex = '1';
5504
5555
  if (this.disabled) {
5505
5556
  slotDom.classList.add('disabled');
@@ -5509,7 +5560,7 @@ class OTPInput extends BaseComponent {
5509
5560
  slotDom.className += ' rounded-l';
5510
5561
  }
5511
5562
  else if (j == (g.length - 1)) {
5512
- slotDom.className += ' rounded-r border-right';
5563
+ slotDom.className += ' rounded-r border-r-color';
5513
5564
  }
5514
5565
  slotDom.addEventListener('click', () => {
5515
5566
  if (this.disabled)
@@ -5691,13 +5742,10 @@ class Progress extends BaseComponent {
5691
5742
  const realNameWidth = this.root.domName?.style.width ?? '0px';
5692
5743
  container.style.width = `calc( 100% - ${realNameWidth})`;
5693
5744
  };
5694
- const container = document.createElement('div');
5695
- container.className = 'lexprogress';
5696
- this.root.appendChild(container);
5745
+ const container = LX.makeElement('div', 'flex justify-center items-center gap-2', '', this.root);
5697
5746
  // add slider (0-1 if not specified different )
5698
- let progress = document.createElement('meter');
5747
+ let progress = LX.makeElement('meter', 'lexprogressbar outline-none rounded-lg select-none');
5699
5748
  progress.id = 'lexprogressbar-' + name;
5700
- progress.className = 'lexprogressbar';
5701
5749
  progress.step = 'any';
5702
5750
  progress.min = options.min ?? 0;
5703
5751
  progress.max = options.max ?? 1;
@@ -5707,12 +5755,12 @@ class Progress extends BaseComponent {
5707
5755
  progress.value = value;
5708
5756
  container.appendChild(progress);
5709
5757
  const _updateColor = () => {
5710
- let backgroundColor = LX.getThemeColor('global-selected');
5758
+ let backgroundColor = LX.getCSSVariable('blue-500');
5711
5759
  if (progress.low != undefined && progress.value < progress.low) {
5712
- backgroundColor = LX.getThemeColor('global-color-error');
5760
+ backgroundColor = LX.getCSSVariable('destructive');
5713
5761
  }
5714
5762
  else if (progress.high != undefined && progress.value < progress.high) {
5715
- backgroundColor = LX.getThemeColor('global-color-warning');
5763
+ backgroundColor = LX.getCSSVariable('warning');
5716
5764
  }
5717
5765
  progress.style.background = `color-mix(in srgb, ${backgroundColor} 20%, transparent)`;
5718
5766
  };
@@ -5721,11 +5769,8 @@ class Progress extends BaseComponent {
5721
5769
  if (oldSpan) {
5722
5770
  oldSpan.remove();
5723
5771
  }
5724
- let span = document.createElement('span');
5772
+ let span = LX.makeElement('span', 'w-12 flex-auto-keep text-center', value, container);
5725
5773
  span.id = 'progressvalue-' + name;
5726
- span.style.padding = '0px 5px';
5727
- span.innerText = value;
5728
- container.appendChild(span);
5729
5774
  }
5730
5775
  if (options.editable ?? false) {
5731
5776
  progress.classList.add('editable');
@@ -5795,14 +5840,13 @@ class RadioGroup extends BaseComponent {
5795
5840
  }
5796
5841
  };
5797
5842
  var container = document.createElement('div');
5798
- container.className = 'lexradiogroup ' + (options.className ?? '');
5843
+ container.className = LX.mergeClass('lexradiogroup flex flex-col', options.className);
5799
5844
  this.root.appendChild(container);
5800
- let labelSpan = document.createElement('span');
5801
- labelSpan.innerHTML = label;
5802
- container.appendChild(labelSpan);
5845
+ // Make label
5846
+ LX.makeElement('span', 'font-medium mb-2', label, container);
5803
5847
  for (let i = 0; i < values.length; ++i) {
5804
5848
  const optionItem = document.createElement('div');
5805
- optionItem.className = 'lexradiogroupitem';
5849
+ optionItem.className = 'lexradiogroupitem flex items-center gap-2 px-6 py-1';
5806
5850
  container.appendChild(optionItem);
5807
5851
  const optionButton = document.createElement('button');
5808
5852
  optionButton.className = 'flex p-0 rounded-lg cursor-pointer';
@@ -5910,11 +5954,10 @@ class RangeInput extends BaseComponent {
5910
5954
  }
5911
5955
  };
5912
5956
  const container = document.createElement('div');
5913
- container.className = 'lexrange relative';
5957
+ container.className = 'lexrange relative py-3';
5914
5958
  this.root.appendChild(container);
5915
5959
  let slider = document.createElement('input');
5916
- slider.className = 'lexrangeslider ' + (isRangeValue ? 'pointer-events-none ' : '')
5917
- + (options.className ?? '');
5960
+ slider.className = LX.mergeClass('lexrangeslider' + (isRangeValue ? ' range pointer-events-none' : ''), options.className);
5918
5961
  slider.min = options.min ?? 0;
5919
5962
  slider.max = options.max ?? 100;
5920
5963
  slider.step = options.step ?? 1;
@@ -5968,15 +6011,12 @@ class RangeInput extends BaseComponent {
5968
6011
  const remapped = LX.remapRange(value, options.min, options.max, 0, 1) * 0.5;
5969
6012
  offsetX = container.offsetWidth * remapped - (container.offsetWidth * 0.5);
5970
6013
  }
5971
- LX.asTooltip(container, `${value}${isRangeValue ? `- ${ogValue[1]}` : ``}`, { offsetX,
5972
- callback: (tpDom) => {
6014
+ LX.asTooltip(container, `${value}${isRangeValue ? `- ${ogValue[1]}` : ``}`, { offsetX, callback: (tpDom) => {
5973
6015
  this._labelTooltip = tpDom;
5974
6016
  } });
5975
6017
  });
5976
- if (ogValue.constructor == Array) { // Its a range value
5977
- let maxSlider = document.createElement('input');
5978
- maxSlider.className = 'lexrangeslider no-fill pointer-events-none overlap absolute top-0 left-0 '
5979
- + (options.className ?? '');
6018
+ if (ogValue.constructor == Array) {
6019
+ let maxSlider = LX.makeElement('input', LX.mergeClass('lexrangeslider no-fill pointer-events-none overlap absolute left-0', options.className));
5980
6020
  maxSlider.min = options.min ?? 0;
5981
6021
  maxSlider.max = options.max ?? 100;
5982
6022
  maxSlider.step = options.step ?? 1;
@@ -6041,7 +6081,7 @@ class Rate extends BaseComponent {
6041
6081
  }, false);
6042
6082
  // Create all layers of stars
6043
6083
  for (let i = 0; i < 5; ++i) {
6044
- const starIcon = LX.makeIcon('Star', { svgClass: `lg fill-current fg-secondary` });
6084
+ const starIcon = LX.makeIcon('Star', { svgClass: `lg fill-current text-accent` });
6045
6085
  starIcon.dataset['idx'] = i + 1;
6046
6086
  starsContainer.appendChild(starIcon);
6047
6087
  starIcon.addEventListener('click', (e) => {
@@ -6050,9 +6090,9 @@ class Rate extends BaseComponent {
6050
6090
  const half = allowHalf && e.offsetX < (rect.width * 0.5);
6051
6091
  this.set(parseFloat(star.dataset['idx']) - (half ? 0.5 : 0.0));
6052
6092
  }, false);
6053
- const filledStarIcon = LX.makeIcon('Star', { svgClass: `lg fill-current fg-yellow-500` });
6093
+ const filledStarIcon = LX.makeIcon('Star', { svgClass: `lg fill-current text-yellow-400` });
6054
6094
  filledStarsContainer.appendChild(filledStarIcon);
6055
- const halfStarIcon = LX.makeIcon('StarHalf', { svgClass: `lg fill-current fg-yellow-500` });
6095
+ const halfStarIcon = LX.makeIcon('StarHalf', { svgClass: `lg fill-current text-yellow-400` });
6056
6096
  halfStarsContainer.appendChild(halfStarIcon);
6057
6097
  }
6058
6098
  const _updateStars = (v) => {
@@ -6101,8 +6141,13 @@ class SizeInput extends BaseComponent {
6101
6141
  this.root.dimensions[i].set(newValue[i], skipCallback);
6102
6142
  }
6103
6143
  };
6144
+ this.onResize = (rect) => {
6145
+ const realNameWidth = this.root.domName?.style.width ?? '0px';
6146
+ container.style.width = `calc( 100% - ${realNameWidth})`;
6147
+ };
6104
6148
  this.root.aspectRatio = value.length == 2 ? value[0] / value[1] : null;
6105
6149
  this.root.dimensions = [];
6150
+ const container = LX.makeElement('div', 'flex', '', this.root);
6106
6151
  for (let i = 0; i < value.length; ++i) {
6107
6152
  const p = new LX.Panel();
6108
6153
  this.root.dimensions[i] = p.addNumber(null, value[i], (v) => {
@@ -6116,18 +6161,15 @@ class SizeInput extends BaseComponent {
6116
6161
  if (callback) {
6117
6162
  callback(value);
6118
6163
  }
6119
- }, { min: 0, disabled: options.disabled, precision: options.precision, className: 'flex-fill' });
6120
- this.root.appendChild(this.root.dimensions[i].root);
6164
+ }, { min: 0, disabled: options.disabled, precision: options.precision, className: 'flex-auto-fill' });
6165
+ container.appendChild(this.root.dimensions[i].root);
6121
6166
  if ((i + 1) != value.length) {
6122
- const xIcon = LX.makeIcon('X', { svgClass: 'fg-accent font-bold' });
6123
- this.root.appendChild(xIcon);
6167
+ const xIcon = LX.makeIcon('X', { svgClass: 'text-foreground font-bold' });
6168
+ container.appendChild(xIcon);
6124
6169
  }
6125
6170
  }
6126
6171
  if (options.units) {
6127
- let unitSpan = document.createElement('span');
6128
- unitSpan.className = 'select-none fg-tertiary font-medium';
6129
- unitSpan.innerText = options.units;
6130
- this.root.appendChild(unitSpan);
6172
+ LX.makeElement('span', 'text-muted-foreground align-center content-center font-medium flex-auto-keep select-none', options.units, container);
6131
6173
  }
6132
6174
  // Lock aspect ratio
6133
6175
  if (this.root.aspectRatio) {
@@ -6138,9 +6180,10 @@ class SizeInput extends BaseComponent {
6138
6180
  const value = this.value();
6139
6181
  this.root.aspectRatio = value[0] / value[1];
6140
6182
  }
6141
- }, { title: 'Lock Aspect Ratio', icon: 'LockOpen', swap: 'Lock', buttonClass: 'bg-none p-0' });
6142
- this.root.appendChild(lockerButton.root);
6183
+ }, { title: 'Lock Aspect Ratio', icon: 'LockOpen', swap: 'Lock', className: 'flex-auto-keep', buttonClass: 'h-auto bg-none p-0' });
6184
+ container.appendChild(lockerButton.root);
6143
6185
  }
6186
+ LX.doAsync(this.onResize.bind(this));
6144
6187
  }
6145
6188
  }
6146
6189
  LX.SizeInput = SizeInput;
@@ -6185,7 +6228,7 @@ class Pagination {
6185
6228
  if (typeof options.onItemsPerPageChange === 'function') {
6186
6229
  this.onItemsPerPageChange = options.onItemsPerPageChange;
6187
6230
  }
6188
- this.root = LX.makeContainer(['auto', 'auto'], 'flex flex-row gap-2 ' + (options.className ?? ''));
6231
+ this.root = LX.makeContainer(['auto', 'auto'], LX.mergeClass('flex flex-row gap-2', options.className));
6189
6232
  if (options.allowChangeItemsPerPage ?? false) {
6190
6233
  const itemsPerPageSelectContainer = LX.makeContainer(['auto', 'auto'], 'flex flex-row items-center', '', this.root);
6191
6234
  const itemsPerPageSelect = new Select(null, Pagination.ITEMS_PER_PAGE_VALUES, this._itemsPerPage, (v) => {
@@ -6222,7 +6265,7 @@ class Pagination {
6222
6265
  refresh() {
6223
6266
  this.pagesRoot.innerHTML = '';
6224
6267
  // Previous page button
6225
- this._makeButton(LX.makeIcon('ChevronLeft').innerHTML, this.page === 1, () => this.prev(), `bg-none ${this.page === 1 ? '' : 'hover:bg-tertiary'}`);
6268
+ this._makeButton(LX.makeIcon('ChevronLeft').innerHTML, this.page === 1, () => this.prev(), `bg-none ${this.page === 1 ? '' : 'hover:bg-secondary'}`);
6226
6269
  const pagesContainer = LX.makeContainer(['auto', 'auto'], 'flex flex-row items-center', '', this.pagesRoot);
6227
6270
  const maxButtons = this._maxButtons + 2; // + next and prev
6228
6271
  if (this.pages <= maxButtons) {
@@ -6272,7 +6315,7 @@ class Pagination {
6272
6315
  }
6273
6316
  }
6274
6317
  // Next page button
6275
- this._makeButton(LX.makeIcon('ChevronRight').innerHTML, this.page === this.pages, () => this.next(), `bg-none ${this.page === this.pages ? '' : 'hover:bg-tertiary'}`);
6318
+ this._makeButton(LX.makeIcon('ChevronRight').innerHTML, this.page === this.pages, () => this.next(), `bg-none ${this.page === this.pages ? '' : 'hover:bg-secondary'}`);
6276
6319
  }
6277
6320
  _emitChange() {
6278
6321
  // Event callback
@@ -6290,7 +6333,7 @@ class Pagination {
6290
6333
  return btn.root;
6291
6334
  }
6292
6335
  _makePageButton(container, i) {
6293
- const buttonClass = i === this.page ? 'bg-secondary border' : 'bg-none';
6336
+ const buttonClass = `h-8 ${i === this.page ? 'primary text-primary-foreground' : 'ghost'}`;
6294
6337
  return this._makeButton(String(i), false, () => this.setPage(i), buttonClass, container);
6295
6338
  }
6296
6339
  }
@@ -6444,10 +6487,10 @@ class Table extends BaseComponent {
6444
6487
  }
6445
6488
  if (this.customFilters !== null) {
6446
6489
  const icon = LX.makeIcon('CirclePlus', { svgClass: 'sm' });
6447
- const separatorHtml = `<div class="lexcontainer border-right self-center mx-1" style="width: 1px; height: 70%;"></div>`;
6490
+ const separatorHtml = `<div class="lexcontainer border-r-color place-self-center mx-1" style="width: 1px; height: 70%;"></div>`;
6448
6491
  for (let f of this.customFilters) {
6449
6492
  f.component = new Button(null, icon.innerHTML + f.name, (v) => {
6450
- const spanName = f.component.root.querySelector('span');
6493
+ const buttonRoot = f.component.root.querySelector('button');
6451
6494
  if (f.options) {
6452
6495
  const menuOptions = f.options.map((colName, idx) => {
6453
6496
  const item = {
@@ -6460,8 +6503,8 @@ class Table extends BaseComponent {
6460
6503
  delete this.activeCustomFilters[key];
6461
6504
  }
6462
6505
  const activeFilters = Object.keys(this.activeCustomFilters).filter((k) => this.activeCustomFilters[k] == f.name);
6463
- const filterBadgesHtml = activeFilters.reduce((acc, key) => acc += LX.badge(key, 'bg-tertiary fg-secondary text-sm border-0'), '');
6464
- spanName.innerHTML = icon.innerHTML + f.name
6506
+ const filterBadgesHtml = activeFilters.reduce((acc, key) => acc += LX.badge(key, 'xs secondary'), '');
6507
+ buttonRoot.innerHTML = icon.innerHTML + f.name
6465
6508
  + (activeFilters.length ? separatorHtml : '') + filterBadgesHtml;
6466
6509
  this.refresh();
6467
6510
  }
@@ -6472,9 +6515,9 @@ class Table extends BaseComponent {
6472
6515
  }
6473
6516
  else if (f.type == 'range') {
6474
6517
  console.assert(f.min != undefined && f.max != undefined, 'Range filter needs min and max values!');
6475
- const container = LX.makeContainer(['240px', 'auto'], 'text-md');
6476
- const panel = new LX.Panel();
6477
- LX.makeContainer(['100%', 'auto'], 'px-3 p-2 pb-0 text-md font-medium', f.name, container);
6518
+ const container = LX.makeContainer(['240px', 'auto'], 'text-base');
6519
+ const panel = new LX.Panel({ className: 'flex flex-col gap-2' });
6520
+ LX.makeContainer(['100%', 'auto'], 'px-3 p-2 pb-0 text-base font-medium', f.name, container);
6478
6521
  f.start = f.start ?? f.min;
6479
6522
  f.end = f.end ?? f.max;
6480
6523
  panel.refresh = () => {
@@ -6483,9 +6526,9 @@ class Table extends BaseComponent {
6483
6526
  panel.addNumber(null, f.start, (v) => {
6484
6527
  f.start = v;
6485
6528
  const inUse = f.start != f.min || f.end != f.max;
6486
- spanName.innerHTML = icon.innerHTML + f.name + (inUse
6529
+ buttonRoot.innerHTML = icon.innerHTML + f.name + (inUse
6487
6530
  ? separatorHtml
6488
- + LX.badge(`${f.start} - ${f.end} ${f.units ?? ''}`, 'bg-tertiary fg-secondary text-sm border-0')
6531
+ + LX.badge(`${f.start} - ${f.end} ${f.units ?? ''}`, 'xs secondary')
6489
6532
  : '');
6490
6533
  if (inUse) {
6491
6534
  this._resetCustomFiltersBtn?.root.classList.remove('hidden');
@@ -6495,10 +6538,10 @@ class Table extends BaseComponent {
6495
6538
  panel.addNumber(null, f.end, (v) => {
6496
6539
  f.end = v;
6497
6540
  const inUse = f.start != f.min || f.end != f.max;
6498
- spanName.innerHTML = icon.innerHTML + f.name
6541
+ buttonRoot.innerHTML = icon.innerHTML + f.name
6499
6542
  + (inUse
6500
6543
  ? separatorHtml
6501
- + LX.badge(`${f.start} - ${f.end} ${f.units ?? ''}`, 'bg-tertiary fg-secondary text-sm border-0')
6544
+ + LX.badge(`${f.start} - ${f.end} ${f.units ?? ''}`, 'xs secondary')
6502
6545
  : '');
6503
6546
  if (inUse) {
6504
6547
  this._resetCustomFiltersBtn?.root.classList.remove('hidden');
@@ -6508,19 +6551,19 @@ class Table extends BaseComponent {
6508
6551
  panel.addButton(null, 'Reset', () => {
6509
6552
  f.start = f.min;
6510
6553
  f.end = f.max;
6511
- spanName.innerHTML = icon.innerHTML + f.name;
6554
+ buttonRoot.innerHTML = icon.innerHTML + f.name;
6512
6555
  panel.refresh();
6513
6556
  this.refresh();
6514
- }, { buttonClass: 'contrast' });
6557
+ }, { buttonClass: 'ghost' });
6515
6558
  };
6516
6559
  panel.refresh();
6517
6560
  container.appendChild(panel.root);
6518
6561
  new Popover(f.component.root, [container], { side: 'bottom' });
6519
6562
  }
6520
6563
  else if (f.type == 'date') {
6521
- const container = LX.makeContainer(['auto', 'auto'], 'text-md');
6564
+ const container = LX.makeContainer(['auto', 'auto'], 'text-base');
6522
6565
  const panel = new LX.Panel();
6523
- LX.makeContainer(['100%', 'auto'], 'px-3 p-2 pb-0 text-md font-medium', f.name, container);
6566
+ LX.makeContainer(['100%', 'auto'], 'px-3 p-2 pb-0 text-base font-medium', f.name, container);
6524
6567
  panel.refresh = () => {
6525
6568
  panel.clear();
6526
6569
  // Generate default value once the filter is used
@@ -6532,9 +6575,9 @@ class Table extends BaseComponent {
6532
6575
  const calendar = new CalendarRange(f.value ?? f.default, {
6533
6576
  onChange: (dateRange) => {
6534
6577
  f.value = dateRange;
6535
- spanName.innerHTML = icon.innerHTML + f.name
6578
+ buttonRoot.innerHTML = icon.innerHTML + f.name
6536
6579
  + (separatorHtml
6537
- + LX.badge(`${calendar.getFullDate()}`, 'bg-tertiary fg-secondary text-sm border-0'));
6580
+ + LX.badge(`${calendar.getFullDate()}`, 'xs secondary'));
6538
6581
  this._resetCustomFiltersBtn?.root.classList.remove('hidden');
6539
6582
  this.refresh();
6540
6583
  }
@@ -6545,14 +6588,14 @@ class Table extends BaseComponent {
6545
6588
  container.appendChild(panel.root);
6546
6589
  new Popover(f.component.root, [container], { side: 'bottom' });
6547
6590
  }
6548
- }, { buttonClass: 'px-2 primary dashed' });
6591
+ }, { buttonClass: 'sm outline dashed' });
6549
6592
  headerContainer.appendChild(f.component.root);
6550
6593
  }
6551
6594
  this._resetCustomFiltersBtn = new Button(null, 'resetButton', () => {
6552
6595
  this.activeCustomFilters = {};
6553
6596
  this._resetCustomFiltersBtn?.root.classList.add('hidden');
6554
6597
  for (let f of this.customFilters ?? []) {
6555
- f.component.root.querySelector('span').innerHTML = icon.innerHTML + f.name;
6598
+ f.component.root.querySelector('button').innerHTML = icon.innerHTML + f.name;
6556
6599
  if (f.type == 'range') {
6557
6600
  f.start = f.min;
6558
6601
  f.end = f.max;
@@ -6562,7 +6605,7 @@ class Table extends BaseComponent {
6562
6605
  }
6563
6606
  }
6564
6607
  this.refresh();
6565
- }, { title: 'Reset filters', tooltip: true, icon: 'X' });
6608
+ }, { title: 'Reset filters', tooltip: true, icon: 'X', buttonClass: 'ghost' });
6566
6609
  headerContainer.appendChild(this._resetCustomFiltersBtn?.root);
6567
6610
  this._resetCustomFiltersBtn?.root.classList.add('hidden');
6568
6611
  }
@@ -6586,15 +6629,13 @@ class Table extends BaseComponent {
6586
6629
  return item;
6587
6630
  });
6588
6631
  LX.addDropdownMenu(e.target, menuOptions, { side: 'bottom', align: 'end' });
6589
- }, { hideName: true });
6632
+ }, { hideName: true, buttonClass: 'outline' });
6590
6633
  headerContainer.appendChild(toggleColumnsBtn.root);
6591
6634
  toggleColumnsBtn.root.style.marginLeft = 'auto';
6592
6635
  }
6593
6636
  container.appendChild(headerContainer);
6594
6637
  }
6595
- const table = document.createElement('table');
6596
- LX.addClass(table, options.tableClass);
6597
- container.appendChild(table);
6638
+ const table = LX.makeElement('table', options.tableClass, '', container);
6598
6639
  this.refresh = () => {
6599
6640
  this._currentFilter = this._currentFilter ?? '';
6600
6641
  table.innerHTML = '';
@@ -6616,7 +6657,7 @@ class Table extends BaseComponent {
6616
6657
  th.style.width = '0px';
6617
6658
  const input = document.createElement('input');
6618
6659
  input.type = 'checkbox';
6619
- input.className = 'lexcheckbox accent';
6660
+ input.className = 'lexcheckbox primary';
6620
6661
  input.checked = data.checkMap[':root'] ?? false;
6621
6662
  th.appendChild(input);
6622
6663
  input.addEventListener('change', function () {
@@ -6651,8 +6692,7 @@ class Table extends BaseComponent {
6651
6692
  console.warn('Invalid column action (missing name):', action);
6652
6693
  continue;
6653
6694
  }
6654
- menuOptions.push({ name: action.name, icon: action.icon, className: action.className,
6655
- callback: () => {
6695
+ menuOptions.push({ name: action.name, icon: action.icon, className: action.className, callback: () => {
6656
6696
  const colRows = this.data.body.map((row) => [row[idx]]);
6657
6697
  const mustRefresh = action.callback(colRows, table);
6658
6698
  if (mustRefresh) {
@@ -6883,7 +6923,7 @@ class Table extends BaseComponent {
6883
6923
  const td = document.createElement('td');
6884
6924
  const input = document.createElement('input');
6885
6925
  input.type = 'checkbox';
6886
- input.className = 'lexcheckbox accent';
6926
+ input.className = 'lexcheckbox primary';
6887
6927
  input.checked = data.checkMap[rowId];
6888
6928
  td.appendChild(input);
6889
6929
  input.addEventListener('change', function () {
@@ -6995,7 +7035,7 @@ class Table extends BaseComponent {
6995
7035
  const footerContainer = LX.makeContainer(['100%', 'auto'], 'flex flex-row px-3 my-1 align-center', '', container);
6996
7036
  // Show num selected rows
6997
7037
  if (showSelected) {
6998
- const selectedRowsLabelContainer = LX.makeContainer(['100%', 'auto'], 'flex justify-start items-center fg-secondary', '0 row(s) selected.', footerContainer);
7038
+ const selectedRowsLabelContainer = LX.makeContainer(['100%', 'auto'], 'flex justify-start items-center', '0 row(s) selected.', footerContainer);
6999
7039
  LX.addSignal('@rows_selected_changed', (target, n) => {
7000
7040
  if (!this._showSelectedNumber)
7001
7041
  return;
@@ -7091,7 +7131,8 @@ class TabSections extends BaseComponent {
7091
7131
  let tabEl = document.createElement('div');
7092
7132
  tabEl.className = 'lextab ' + ((tab.selected ?? false) ? 'selected' : '');
7093
7133
  tabEl.innerHTML = showNames ? tab.name : '';
7094
- tabEl.appendChild(LX.makeIcon(tab.icon ?? 'Hash', { title: tab.name, iconClass: tab.iconClass, svgClass: tab.svgClass }));
7134
+ tabEl.appendChild(LX.makeIcon(tab.icon ?? 'Hash', { title: tab.name, iconClass: tab.iconClass,
7135
+ svgClass: `lg${tab.svgClass ? ' ' + tab.svgClass : ''}` }));
7095
7136
  this.tabDOMs[tab.name] = tabEl;
7096
7137
  let infoContainer = document.createElement('div');
7097
7138
  infoContainer.id = tab.name.replace(/\s/g, '');
@@ -7164,15 +7205,13 @@ class Tags extends BaseComponent {
7164
7205
  };
7165
7206
  // Show tags
7166
7207
  const tagsContainer = document.createElement('div');
7167
- tagsContainer.className = 'lextags';
7208
+ tagsContainer.className = 'inline-flex flex-wrap gap-1 bg-card/50 rounded-lg pad-xs [&_input]:w-2/3';
7168
7209
  this.root.appendChild(tagsContainer);
7169
7210
  this.generateTags = (value) => {
7170
7211
  tagsContainer.innerHTML = '';
7171
7212
  for (let i = 0; i < value.length; ++i) {
7172
7213
  const tagName = value[i];
7173
- const tag = document.createElement('span');
7174
- tag.className = 'lextag';
7175
- tag.innerHTML = tagName;
7214
+ const tag = LX.makeElement('span', 'lextag bg-primary px-2 py-1 rounded-xl min-w-2 justify-center text-primary-foreground gap-1 text-sm select-none', tagName);
7176
7215
  const removeButton = LX.makeIcon('X', { svgClass: 'sm' });
7177
7216
  tag.appendChild(removeButton);
7178
7217
  removeButton.addEventListener('click', (e) => {
@@ -7230,13 +7269,12 @@ class TextArea extends BaseComponent {
7230
7269
  container.className = 'lextextarea';
7231
7270
  container.style.display = 'flex';
7232
7271
  this.root.appendChild(container);
7233
- let wValue = document.createElement('textarea');
7272
+ let wValue = LX.makeElement('textarea', options.inputClass ?? '');
7234
7273
  wValue.value = value ?? '';
7235
- wValue.className = options.inputClass ?? '';
7236
7274
  wValue.style.textAlign = options.float ?? '';
7237
7275
  Object.assign(wValue.style, options.style ?? {});
7238
7276
  if (options.fitHeight ?? false) {
7239
- wValue.classList.add('size-content');
7277
+ wValue.classList.add('field-sizing-content');
7240
7278
  }
7241
7279
  if (!(options.resize ?? true)) {
7242
7280
  wValue.classList.add('resize-none');
@@ -7287,7 +7325,8 @@ class Title extends BaseComponent {
7287
7325
  console.assert(name.length !== 0, "Can't create Title Component without text!");
7288
7326
  // Note: Titles are not registered in Panel.components by now
7289
7327
  super(ComponentType.TITLE, null, null, options);
7290
- this.root.className = `lextitle ${this.root.className}`;
7328
+ const cn = 'lextitle !w-fit bg-muted text-foreground text-sm font-semibold leading-normal m-3 flex content-center rounded-xl select-none';
7329
+ this.root.className = LX.mergeClass(cn, options.className);
7291
7330
  if (options.icon) {
7292
7331
  let icon = LX.makeIcon(options.icon, { iconClass: 'mr-2' });
7293
7332
  icon.querySelector('svg').style.color = options.iconColor || '';
@@ -7296,16 +7335,14 @@ class Title extends BaseComponent {
7296
7335
  let text = document.createElement('span');
7297
7336
  text.innerText = name;
7298
7337
  this.root.appendChild(text);
7299
- Object.assign(this.root.style, options.style ?? {});
7300
7338
  if (options.link != undefined) {
7301
- let linkDom = document.createElement('a');
7302
- linkDom.innerText = name;
7339
+ let linkDom = LX.makeElement('a', `${cn} link`, name);
7303
7340
  linkDom.href = options.link;
7304
7341
  linkDom.target = options.target ?? '';
7305
- linkDom.className = 'lextitle link';
7306
- Object.assign(linkDom.style, options.style ?? {});
7307
7342
  this.root.replaceWith(linkDom);
7343
+ this.root = linkDom;
7308
7344
  }
7345
+ Object.assign(this.root.style, options.style ?? {});
7309
7346
  }
7310
7347
  }
7311
7348
  LX.Title = Title;
@@ -7340,25 +7377,23 @@ class Toggle extends BaseComponent {
7340
7377
  container.style.width = options.inputWidth ?? `calc( 100% - ${realNameWidth})`;
7341
7378
  };
7342
7379
  var container = document.createElement('div');
7343
- container.className = 'lextogglecont';
7380
+ container.className = 'flex flex-row gap-2 items-center';
7344
7381
  this.root.appendChild(container);
7345
- let toggle = document.createElement('input');
7382
+ let toggle = LX.makeElement('input', LX.mergeClass('lextoggle relative inline-grid place-content-center cursor-pointer shrink-0 select-none', options.className));
7346
7383
  toggle.type = 'checkbox';
7347
- toggle.className = 'lextoggle ' + (options.className ?? '');
7348
7384
  toggle.checked = value;
7349
7385
  toggle.iValue = value;
7350
7386
  toggle.disabled = options.disabled ?? false;
7351
7387
  container.appendChild(toggle);
7352
7388
  let valueName = document.createElement('span');
7353
- valueName.className = 'toggletext';
7389
+ valueName.className = 'font-medium w-full overflow-hidden truncate';
7354
7390
  valueName.innerHTML = options.label ?? 'On';
7355
7391
  container.appendChild(valueName);
7356
7392
  toggle.addEventListener('change', (e) => {
7357
7393
  this.set(toggle.checked, false, e);
7358
7394
  });
7359
7395
  if (options.suboptions) {
7360
- let suboptions = document.createElement('div');
7361
- suboptions.className = 'lextogglesubmenu';
7396
+ let suboptions = LX.makeElement('div', 'lextogglesubmenu w-full p-2');
7362
7397
  suboptions.toggleAttribute('hidden', !toggle.checked);
7363
7398
  const suboptionsPanel = new LX.Panel();
7364
7399
  suboptionsPanel.queue(suboptions);
@@ -7377,6 +7412,7 @@ LX.Toggle = Toggle;
7377
7412
  * @description Vector Component
7378
7413
  */
7379
7414
  class Vector extends BaseComponent {
7415
+ locked = false;
7380
7416
  setLimits;
7381
7417
  constructor(numComponents, name, value, callback, options = {}) {
7382
7418
  numComponents = LX.clamp(numComponents, 2, 4);
@@ -7412,7 +7448,7 @@ class Vector extends BaseComponent {
7412
7448
  this.setLimits = (newMin, newMax, newStep) => { };
7413
7449
  const vectorInputs = [];
7414
7450
  var container = document.createElement('div');
7415
- container.className = 'lexvector';
7451
+ container.className = 'lexvector flex';
7416
7452
  this.root.appendChild(container);
7417
7453
  this.disabled = options.disabled ?? false;
7418
7454
  const that = this;
@@ -7451,7 +7487,7 @@ class Vector extends BaseComponent {
7451
7487
  mult = 10;
7452
7488
  else if (e.altKey)
7453
7489
  mult = 0.1;
7454
- if (lockerButton.locked) {
7490
+ if (that.locked) {
7455
7491
  for (let v of vectorInputs) {
7456
7492
  v.value = LX.round(+v.valueAsNumber - mult * (e.deltaY > 0 ? 1 : -1), options.precision);
7457
7493
  BaseComponent._dispatchEvent(v, 'change');
@@ -7468,7 +7504,7 @@ class Vector extends BaseComponent {
7468
7504
  }
7469
7505
  let val = LX.clamp(e.target.value, +vecinput.min, +vecinput.max);
7470
7506
  val = LX.round(val, options.precision);
7471
- if (lockerButton.locked) {
7507
+ if (this.locked) {
7472
7508
  for (let v of vectorInputs) {
7473
7509
  v.value = val;
7474
7510
  value[v.idx] = val;
@@ -7507,7 +7543,7 @@ class Vector extends BaseComponent {
7507
7543
  mult = 10;
7508
7544
  else if (e.altKey)
7509
7545
  mult = 0.1;
7510
- if (lockerButton.locked) {
7546
+ if (that.locked) {
7511
7547
  for (let v of vectorInputs) {
7512
7548
  v.value = LX.round(+v.valueAsNumber + mult * dt, options.precision);
7513
7549
  BaseComponent._dispatchEvent(v, 'change');
@@ -7548,10 +7584,12 @@ class Vector extends BaseComponent {
7548
7584
  this.set(value, true);
7549
7585
  };
7550
7586
  }
7551
- const lockerButton = new Button(null, '', (swapValue) => {
7552
- lockerButton.locked = swapValue;
7553
- }, { title: 'Lock', icon: 'LockOpen', swap: 'Lock', buttonClass: 'no-h bg-none p-0' });
7554
- container.appendChild(lockerButton.root);
7587
+ if (!options.skipLock) {
7588
+ const lockerButton = new Button(null, '', (swapValue) => {
7589
+ this.locked = swapValue;
7590
+ }, { title: 'Lock', icon: 'LockOpen', swap: 'Lock', buttonClass: 'h-auto bg-none p-0' });
7591
+ container.appendChild(lockerButton.root);
7592
+ }
7555
7593
  LX.doAsync(this.onResize.bind(this));
7556
7594
  }
7557
7595
  }
@@ -7574,22 +7612,17 @@ class Branch {
7574
7612
  constructor(name, options = {}) {
7575
7613
  this.name = name;
7576
7614
  var root = document.createElement('div');
7577
- root.className = 'lexbranch';
7578
7615
  if (options.id) {
7579
7616
  root.id = options.id;
7580
7617
  }
7581
- if (options.className) {
7582
- root.className += ' ' + options.className;
7583
- }
7584
- root.style.margin = '0 auto';
7618
+ root.className = LX.mergeClass('lexbranch bg-secondary/50 dark:bg-card text-secondary-foreground dark:text-card-foreground w-full rounded-lg my-0 mx-auto', options.className);
7585
7619
  var that = this;
7586
7620
  this.closed = options.closed ?? false;
7587
7621
  this.root = root;
7588
7622
  this.components = [];
7589
7623
  this.panel = null;
7590
7624
  // Create element
7591
- const title = document.createElement('div');
7592
- title.className = 'lexbranchtitle';
7625
+ const title = LX.makeElement('div', 'lexbranchtitle flex cursor-pointer select-none pad-lg text-lg', '', root);
7593
7626
  if (options.icon) {
7594
7627
  const branchIcon = LX.makeIcon(options.icon, { iconClass: 'mr-2' });
7595
7628
  title.appendChild(branchIcon);
@@ -7597,11 +7630,8 @@ class Branch {
7597
7630
  title.innerHTML += name || 'Branch';
7598
7631
  const collapseIcon = LX.makeIcon('Right', { iconClass: 'switch-branch-button', svgClass: 'sm' });
7599
7632
  title.appendChild(collapseIcon);
7600
- root.appendChild(title);
7601
- var branchContent = document.createElement('div');
7633
+ var branchContent = LX.makeElement('div', 'lexbranchcontent pad-xs', '', root);
7602
7634
  branchContent.id = name.replace(/\s/g, '');
7603
- branchContent.className = 'lexbranchcontent';
7604
- root.appendChild(branchContent);
7605
7635
  this.content = branchContent;
7606
7636
  this._addBranchSeparator();
7607
7637
  if (this.closed) {
@@ -7756,14 +7786,10 @@ class Panel {
7756
7786
  * style: CSS Style object to be applied to the panel
7757
7787
  */
7758
7788
  constructor(options = {}) {
7759
- var root = document.createElement('div');
7760
- root.className = 'lexpanel';
7789
+ const root = LX.makeElement('div', LX.mergeClass('lexpanel m-0 pad-md overflow-hidden overflow-y-scroll text-foreground scrollbar-hidden', options.className));
7761
7790
  if (options.id) {
7762
7791
  root.id = options.id;
7763
7792
  }
7764
- if (options.className) {
7765
- root.className += ' ' + options.className;
7766
- }
7767
7793
  root.style.width = options.width || '100%';
7768
7794
  root.style.height = options.height || '100%';
7769
7795
  Object.assign(root.style, options.style ?? {});
@@ -7817,8 +7843,7 @@ class Panel {
7817
7843
  const signal = this.components[w].options.signal;
7818
7844
  for (let i = 0; i < LX.signals[signal].length; i++) {
7819
7845
  if (LX.signals[signal][i] == this.components[w]) {
7820
- LX.signals[signal] = [...LX.signals[signal].slice(0, i),
7821
- ...LX.signals[signal].slice(i + 1)];
7846
+ LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i + 1)];
7822
7847
  }
7823
7848
  }
7824
7849
  }
@@ -7829,8 +7854,7 @@ class Panel {
7829
7854
  let signal = c.options.signal;
7830
7855
  for (let i = 0; i < LX.signals[signal].length; i++) {
7831
7856
  if (LX.signals[signal][i] == c) {
7832
- LX.signals[signal] = [...LX.signals[signal].slice(0, i),
7833
- ...LX.signals[signal].slice(i + 1)];
7857
+ LX.signals[signal] = [...LX.signals[signal].slice(0, i), ...LX.signals[signal].slice(i + 1)];
7834
7858
  }
7835
7859
  }
7836
7860
  }
@@ -8163,7 +8187,7 @@ class Panel {
8163
8187
  */
8164
8188
  addLabel(value, options = {}) {
8165
8189
  options.disabled = true;
8166
- options.inputClass = (options.inputClass ?? '') + ' bg-none';
8190
+ options.inputClass = LX.mergeClass('bg-none', options.inputClass);
8167
8191
  const component = this.addText(null, value, null, options);
8168
8192
  component.type = ComponentType.LABEL;
8169
8193
  return component;
@@ -8225,7 +8249,7 @@ class Panel {
8225
8249
  * @param {Function} callback Callback function on submit form
8226
8250
  * @param {Object} options:
8227
8251
  * primaryActionName: Text to be shown in the primary action button ['Submit']
8228
- * primaryButtonClass: Button class for primary action button ['contrast']
8252
+ * primaryButtonClass: Button class for primary action button ['primary']
8229
8253
  * secondaryActionName: Text to be shown in the secondary action button ['Cancel']
8230
8254
  * secondaryActionCallback: Callback function on press secondary button
8231
8255
  * secondaryButtonClass: Button class for secondary action button ['primary']
@@ -8700,11 +8724,10 @@ class AreaOverlayButtons {
8700
8724
  this._buildButtons(buttonsArray, options);
8701
8725
  }
8702
8726
  _buildButtons(buttonsArray, options = {}) {
8703
- options.className = 'lexoverlaybuttons';
8727
+ options.className = 'lexoverlaybuttons flex justify-start gap-2 bg-card m-2 p-1 rounded-2xl border-color';
8704
8728
  let overlayPanel = this.area.addPanel(options);
8705
8729
  let overlayGroup = null;
8706
- const container = document.createElement('div');
8707
- container.className = 'lexoverlaybuttonscontainer';
8730
+ const container = LX.makeElement('div', 'lexoverlaybuttonscontainer absolute flex top-0 w-full pointer-events-none');
8708
8731
  container.appendChild(overlayPanel.root);
8709
8732
  this.area.attach(container);
8710
8733
  const float = options.float;
@@ -8746,6 +8769,7 @@ class AreaOverlayButtons {
8746
8769
  icon: b.icon,
8747
8770
  img: b.img,
8748
8771
  className: b.class ?? '',
8772
+ buttonClass: b.buttonClass ?? 'x', // Avoid using default outline
8749
8773
  title: b.name,
8750
8774
  overflowContainerX: overlayPanel.root,
8751
8775
  swap: b.swap
@@ -8753,7 +8777,7 @@ class AreaOverlayButtons {
8753
8777
  if (group) {
8754
8778
  if (!overlayGroup) {
8755
8779
  overlayGroup = document.createElement('div');
8756
- overlayGroup.className = 'lexoverlaygroup';
8780
+ overlayGroup.className = 'lexoverlaygroup flex flex-none bg-secondary rounded-xl';
8757
8781
  overlayPanel.queuedContainer = overlayGroup;
8758
8782
  }
8759
8783
  _options.parent = overlayGroup;
@@ -8862,13 +8886,10 @@ class Area {
8862
8886
  _root;
8863
8887
  constructor(options = {}) {
8864
8888
  var root = document.createElement('div');
8865
- root.className = 'lexarea';
8866
8889
  if (options.id) {
8867
8890
  root.id = options.id;
8868
8891
  }
8869
- if (options.className) {
8870
- root.className += ' ' + options.className;
8871
- }
8892
+ root.className = LX.mergeClass('lexarea m-0 bg-background text-foreground', options.className);
8872
8893
  var width = options.width || '100%';
8873
8894
  var height = options.height || '100%';
8874
8895
  // This has default options..
@@ -9032,8 +9053,7 @@ class Area {
9032
9053
  const type = layout.type ?? 'horizontal';
9033
9054
  const resize = layout.resize ?? true;
9034
9055
  const minimizable = layout.minimizable ?? false;
9035
- const [splitA, splitB] = area.split({ type, resize, minimizable,
9036
- sizes: [layout.splits[0].size, layout.splits[1].size] });
9056
+ const [splitA, splitB] = area.split({ type, resize, minimizable, sizes: [layout.splits[0].size, layout.splits[1].size] });
9037
9057
  _splitArea(splitA, layout.splits[0]);
9038
9058
  _splitArea(splitB, layout.splits[1]);
9039
9059
  };
@@ -9133,8 +9153,7 @@ class Area {
9133
9153
  // Create areas
9134
9154
  let area1 = new Area({ width: primarySize[0], height: primarySize[1], skipAppend: true,
9135
9155
  className: 'split' + (options.menubar || options.sidebar ? '' : ' origin') });
9136
- let area2 = new Area({ width: secondarySize[0], height: secondarySize[1], skipAppend: true,
9137
- className: 'split' });
9156
+ let area2 = new Area({ width: secondarySize[0], height: secondarySize[1], skipAppend: true, className: 'split' });
9138
9157
  /*
9139
9158
  If the parent area is not in the DOM, we need to wait for the resize event to get the its correct size
9140
9159
  and set the sizes of the split areas accordingly.
@@ -9406,16 +9425,15 @@ class Area {
9406
9425
  addMenubar(items, options = {}) {
9407
9426
  let menubar = new Menubar(items, options);
9408
9427
  LX.menubars.push(menubar);
9409
- const [bar, content] = this.split({ type: 'vertical', sizes: ['48px', null], resize: false,
9410
- menubar: true });
9428
+ const [bar, content] = this.split({ type: 'vertical', sizes: ['48px', null], resize: false, menubar: true });
9411
9429
  menubar.siblingArea = content;
9412
9430
  bar.attach(menubar);
9413
9431
  bar.isMenubar = true;
9414
9432
  if (options.sticky ?? true) {
9415
- bar.root.className += ' sticky top-0 z-1000';
9433
+ bar.root.className += ' sticky top-0 z-100';
9416
9434
  }
9417
9435
  if (options.parentClass) {
9418
- bar.root.className += ` ${options.parentClass}`;
9436
+ bar.root.className = LX.mergeClass(bar.root.className, options.parentClass);
9419
9437
  }
9420
9438
  return menubar;
9421
9439
  }
@@ -9445,7 +9463,7 @@ class Area {
9445
9463
  bar.attach(sidebar);
9446
9464
  bar.isSidebar = true;
9447
9465
  if (options.parentClass) {
9448
- bar.root.className += ` ${options.parentClass}`;
9466
+ bar.root.className = LX.mergeClass(bar.root.className, options.parentClass);
9449
9467
  }
9450
9468
  return sidebar;
9451
9469
  }
@@ -9574,6 +9592,17 @@ class Area {
9574
9592
  LX.Area = Area;
9575
9593
 
9576
9594
  // Utils.ts @jxarco
9595
+ // @ts-ignore
9596
+ /* Add Tailwind merge utility to LX namespace EXTENDED with new LX class groups*/
9597
+ LX.twMerge = extendTailwindMerge({
9598
+ extend: {
9599
+ classGroups: {
9600
+ pad: [
9601
+ { pad: ['xs', 'sm', 'md', 'lg', 'xl', '2xl'] }
9602
+ ]
9603
+ }
9604
+ }
9605
+ });
9577
9606
  function clamp(num, min, max) {
9578
9607
  return Math.min(Math.max(num, min), max);
9579
9608
  }
@@ -9664,7 +9693,7 @@ function getSupportedDOMName(text) {
9664
9693
  console.assert(typeof text == 'string', 'getSupportedDOMName: Text is not a string!');
9665
9694
  let name = text.trim();
9666
9695
  // Replace specific known symbols
9667
- name = name.replace(/@/g, '_at_').replace(/\+/g, '_plus_').replace(/\./g, '_dot_');
9696
+ name = name.replace(/\//g, '_slash_').replace(/@/g, '_at_').replace(/\+/g, '_plus_').replace(/\./g, '_dot_');
9668
9697
  name = name.replace(/[^a-zA-Z0-9_-]/g, '_');
9669
9698
  // prefix with an underscore if needed
9670
9699
  if (/^[0-9]/.test(name)) {
@@ -9798,45 +9827,57 @@ function concatTypedArray(arrays, ArrayType) {
9798
9827
  }
9799
9828
  LX.concatTypedArray = concatTypedArray;
9800
9829
  /**
9801
- * @method setTheme
9802
- * @description Set dark or light theme
9830
+ * @method setThemeColor
9831
+ * @description Set colored theme
9832
+ * @param {String} colorThemeName Name of the color
9833
+ */
9834
+ function setThemeColor(colorThemeName) {
9835
+ document.documentElement.className = `theme-${colorThemeName}`;
9836
+ const colorScheme = LX.getMode();
9837
+ document.documentElement.classList.toggle('dark', colorScheme == 'dark');
9838
+ }
9839
+ LX.setThemeColor = setThemeColor;
9840
+ /**
9841
+ * @method setMode
9842
+ * @description Set dark or light scheme mode
9803
9843
  * @param {String} colorScheme Name of the scheme
9804
9844
  * @param {Boolean} storeLocal Store in localStorage
9805
9845
  */
9806
- function setTheme(colorScheme, storeLocal = true) {
9846
+ function setMode(colorScheme, storeLocal = true) {
9807
9847
  colorScheme = (colorScheme == 'light') ? 'light' : 'dark';
9808
- document.documentElement.setAttribute('data-theme', colorScheme);
9848
+ document.documentElement.setAttribute('data-mode', colorScheme);
9849
+ document.documentElement.classList.toggle('dark', colorScheme == 'dark');
9809
9850
  if (storeLocal)
9810
9851
  localStorage.setItem('lxColorScheme', colorScheme);
9811
9852
  LX.emitSignal('@on_new_color_scheme', colorScheme);
9812
9853
  }
9813
- LX.setTheme = setTheme;
9854
+ LX.setMode = setMode;
9814
9855
  /**
9815
- * @method getTheme
9856
+ * @method getMode
9816
9857
  * @description Gets either "dark" or "light" theme value
9817
9858
  */
9818
- function getTheme() {
9819
- return document.documentElement.getAttribute('data-theme') ?? 'dark';
9859
+ function getMode() {
9860
+ return document.documentElement.getAttribute('data-mode') ?? 'dark';
9820
9861
  }
9821
- LX.getTheme = getTheme;
9862
+ LX.getMode = getMode;
9822
9863
  /**
9823
- * @method switchTheme
9864
+ * @method switchMode
9824
9865
  * @description Toggles between "dark" and "light" themes
9825
9866
  */
9826
- function switchTheme() {
9827
- const currentTheme = getTheme();
9828
- setTheme(currentTheme == 'dark' ? 'light' : 'dark');
9867
+ function switchMode() {
9868
+ const currentTheme = getMode();
9869
+ setMode(currentTheme == 'dark' ? 'light' : 'dark');
9829
9870
  }
9830
- LX.switchTheme = switchTheme;
9871
+ LX.switchMode = switchMode;
9831
9872
  /**
9832
- * @method setSystemTheme
9873
+ * @method setSystemMode
9833
9874
  * @description Sets back the system theme
9834
9875
  */
9835
- function setSystemTheme() {
9876
+ function setSystemMode() {
9836
9877
  const currentTheme = (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches)
9837
9878
  ? 'light'
9838
9879
  : 'dark';
9839
- setTheme(currentTheme);
9880
+ setMode(currentTheme);
9840
9881
  localStorage.removeItem('lxColorScheme');
9841
9882
  // Reapply listener
9842
9883
  if (LX._mqlPrefersDarkScheme) {
@@ -9844,39 +9885,55 @@ function setSystemTheme() {
9844
9885
  LX._mqlPrefersDarkScheme.addEventListener('change', LX._onChangeSystemTheme);
9845
9886
  }
9846
9887
  }
9847
- LX.setSystemTheme = setSystemTheme;
9888
+ LX.setSystemMode = setSystemMode;
9848
9889
  /**
9849
- * @method setThemeColor
9850
- * @description Sets a new value for one of the main theme variables
9851
- * @param {String} colorName Name of the theme variable
9852
- * @param {String} color Color in rgba/hex
9890
+ * @method setCSSVariable
9891
+ * @description Sets a new value for one of the CSS root variables
9892
+ * @param {String} varName Name of the CSS variable
9893
+ * @param {String} value
9853
9894
  */
9854
- function setThemeColor(colorName, color) {
9895
+ function setCSSVariable(varName, value) {
9855
9896
  const r = document.querySelector(':root');
9856
- r.style.setProperty('--' + colorName, color);
9897
+ r.style.setProperty('--' + varName, value);
9857
9898
  }
9858
- LX.setThemeColor = setThemeColor;
9899
+ LX.setCSSVariable = setCSSVariable;
9859
9900
  /**
9860
- * @method getThemeColor
9861
- * @description Get the value for one of the main theme variables
9862
- * @param {String} colorName Name of the theme variable
9901
+ * @method getCSSVariable
9902
+ * @description Get the value for one of the CSS root variables
9903
+ * @param {String} varName Name of the CSS variable
9863
9904
  */
9864
- function getThemeColor(colorName) {
9905
+ function getCSSVariable(varName) {
9906
+ const [name, opacity] = varName.split('/');
9865
9907
  const r = document.querySelector(':root');
9866
9908
  const s = getComputedStyle(r);
9867
- const value = s.getPropertyValue('--' + colorName);
9909
+ let value = s.getPropertyValue('--' + name);
9910
+ if (!value)
9911
+ return '';
9868
9912
  if (value.includes('light-dark')) {
9869
9913
  const currentScheme = s.getPropertyValue('color-scheme');
9870
9914
  if (currentScheme == 'light') {
9871
- return value.substring(value.indexOf('(') + 1, value.indexOf(',')).replace(/\s/g, '');
9915
+ value = value.substring(value.indexOf('(') + 1, value.indexOf(',')).replace(/\s/g, '');
9872
9916
  }
9873
9917
  else {
9874
- return value.substring(value.indexOf(',') + 1, value.indexOf(')')).replace(/\s/g, '');
9918
+ value = value.substring(value.indexOf(',') + 1, value.indexOf(')')).replace(/\s/g, '');
9919
+ }
9920
+ }
9921
+ if (opacity) {
9922
+ if (value.includes('/'))
9923
+ return value;
9924
+ if (value.startsWith('rgb(') || value.startsWith('hsl(') || value.startsWith('oklch(')
9925
+ || value.startsWith('lab(') || value.startsWith('lch(')) {
9926
+ return value.replace(/\)$/, ` / ${parseFloat(opacity) / 100.0})`);
9927
+ }
9928
+ // Hex fallback
9929
+ if (value.startsWith('#')) {
9930
+ const rgba = LX.hexToRgb(value, opacity);
9931
+ return LX.rgbToHex(rgba);
9875
9932
  }
9876
9933
  }
9877
9934
  return value;
9878
9935
  }
9879
- LX.getThemeColor = getThemeColor;
9936
+ LX.getCSSVariable = getCSSVariable;
9880
9937
  /**
9881
9938
  * @method switchSpacing
9882
9939
  * @description Toggles between "default" and "compact" spacing layouts
@@ -9906,8 +9963,9 @@ LX.getBase64Image = getBase64Image;
9906
9963
  * @method hexToRgb
9907
9964
  * @description Convert a hexadecimal string to a valid RGB color
9908
9965
  * @param {String} hex Hexadecimal color
9966
+ * @param {Number} hex Opacity alpha value
9909
9967
  */
9910
- function hexToRgb(hex) {
9968
+ function hexToRgb(hex, alpha) {
9911
9969
  const hexPattern = /^#(?:[A-Fa-f0-9]{3,4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/;
9912
9970
  if (!hexPattern.test(hex)) {
9913
9971
  throw (`Invalid Hex Color: ${hex}`);
@@ -9923,7 +9981,7 @@ function hexToRgb(hex) {
9923
9981
  const b = ((bigint >> (hex.length === 8 ? 8 : 0)) & 255) / 255;
9924
9982
  const a = (hex.length === 8 ? (bigint & 255) : (hex.length === 4 ? parseInt(hex.slice(-2), 16) : 255))
9925
9983
  / 255;
9926
- return { r, g, b, a };
9984
+ return { r, g, b, a: (alpha ? alpha / 100 : a) };
9927
9985
  }
9928
9986
  LX.hexToRgb = hexToRgb;
9929
9987
  /**
@@ -9948,12 +10006,48 @@ function rgbToHex(rgb, scale = 255) {
9948
10006
  rgbArray.push(rgb.a);
9949
10007
  return ('#'
9950
10008
  + rgbArray.map((c) => {
9951
- c = Math.floor(c * scale);
10009
+ c = Math.floor(LX.clamp(c * scale, 0.0, scale));
9952
10010
  const hex = c.toString(16);
9953
10011
  return hex.length === 1 ? ('0' + hex) : hex;
9954
10012
  }).join(''));
9955
10013
  }
9956
10014
  LX.rgbToHex = rgbToHex;
10015
+ /**
10016
+ * @method oklchToHex
10017
+ * @description Convert a oklch color to a hexadecimal string
10018
+ * @param {String} oklch String containing oklch color
10019
+ */
10020
+ function oklchToHex(oklch) {
10021
+ const match = oklch.match(/oklch\(\s*([\d.]+)%\s+([\d.]+)\s+([\d.]+)\s*\)/);
10022
+ if (!match) {
10023
+ console.error('Invalid OKLCH format');
10024
+ return '#000';
10025
+ }
10026
+ let [, Lp, C, h] = match;
10027
+ const L = parseFloat(Lp) / 100;
10028
+ const H = (parseFloat(h) * Math.PI) / 180;
10029
+ // OKLCH -> OKLab
10030
+ const a = parseFloat(C) * Math.cos(H);
10031
+ const b = parseFloat(C) * Math.sin(H);
10032
+ // OKLab -> LMS
10033
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
10034
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
10035
+ const s_ = L - 0.0894841775 * a - 1.2914855480 * b;
10036
+ const l = l_ ** 3;
10037
+ const m = m_ ** 3;
10038
+ const s = s_ ** 3;
10039
+ // LMS -> linear RGB
10040
+ let r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
10041
+ let g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
10042
+ let b2 = -0.0041960863 * l - 0.7034186147 * m + 1.7076147010 * s;
10043
+ // linear RGB -> sRGB
10044
+ const toSRGB = (x) => x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
10045
+ r = toSRGB(r);
10046
+ g = toSRGB(g);
10047
+ b2 = toSRGB(b2);
10048
+ return LX.rgbToHex({ r, g, b: b2 });
10049
+ }
10050
+ LX.oklchToHex = oklchToHex;
9957
10051
  /**
9958
10052
  * @method rgbToCss
9959
10053
  * @description Convert a RGB color (0..1) to a CSS color format
@@ -10193,10 +10287,8 @@ function makeDraggable(domEl, options = {}) {
10193
10287
  const fixedOffset = isFixed ? new vec2(parentRect.x, parentRect.y) : new vec2();
10194
10288
  left = left ?? e.clientX - offsetX - parentRect.x;
10195
10289
  top = top ?? e.clientY - offsetY - parentRect.y;
10196
- domEl.style.left =
10197
- LX.clamp(left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin) + 'px';
10198
- domEl.style.top =
10199
- LX.clamp(top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin) + 'px';
10290
+ domEl.style.left = LX.clamp(left, dragMargin + fixedOffset.x, fixedOffset.x + parentRect.width - domEl.offsetWidth - dragMargin) + 'px';
10291
+ domEl.style.top = LX.clamp(top, dragMargin + fixedOffset.y, fixedOffset.y + parentRect.height - domEl.offsetHeight - dragMargin) + 'px';
10200
10292
  domEl.style.translate = 'none'; // Force remove translation
10201
10293
  };
10202
10294
  // Initial adjustment
@@ -10322,7 +10414,7 @@ function makeCodeSnippet(code, size, options = {}) {
10322
10414
  return;
10323
10415
  }
10324
10416
  const snippet = document.createElement('div');
10325
- snippet.className = 'lexcodesnippet ' + (options.className ?? '');
10417
+ snippet.className = LX.mergeClass('lexcodesnippet relative rounded-xl overflow-hidden', options.className);
10326
10418
  snippet.style.width = size ? size[0] : 'auto';
10327
10419
  snippet.style.height = size ? size[1] : 'auto';
10328
10420
  const area = new Area({ xskipAppend: true });
@@ -10331,7 +10423,7 @@ function makeCodeSnippet(code, size, options = {}) {
10331
10423
  disableEdition: true,
10332
10424
  allowAddScripts: false,
10333
10425
  name: options.tabName,
10334
- callback: (instance) => {
10426
+ onReady: (instance) => {
10335
10427
  instance.setText(code, options.language ?? 'Plain Text');
10336
10428
  if (options.linesAdded) {
10337
10429
  const code = instance.root.querySelector('.code');
@@ -10407,9 +10499,10 @@ function makeKbd(keys, useSpecialKeys = true, extraClass = '') {
10407
10499
  'ArrowRight': '→',
10408
10500
  'Space': '␣'
10409
10501
  };
10410
- const kbd = LX.makeContainer(['auto', 'auto'], 'flex flex-row ml-auto');
10502
+ const kbd = LX.makeContainer(['auto', 'auto'], `text-muted-foreground font-sans text-xs inline-flex
10503
+ ml-auto pointer-events-none select-none items-center justify-center gap-1`);
10411
10504
  for (const k of keys) {
10412
- LX.makeContainer(['auto', 'auto'], 'self-center text-xs fg-secondary select-none ' + extraClass, useSpecialKeys ? specialKeys[k] ?? k : k, kbd);
10505
+ LX.makeContainer(['auto', 'auto'], 'bg-muted px-1 rounded-sm ' + extraClass, useSpecialKeys ? specialKeys[k] ?? k : k, kbd);
10413
10506
  }
10414
10507
  return kbd;
10415
10508
  }
@@ -10429,38 +10522,38 @@ function makeBreadcrumb(items, options = {}) {
10429
10522
  const eraseNum = items.length - maxItems;
10430
10523
  if (eraseNum > 0) {
10431
10524
  const erased = items.splice(1, eraseNum + 1);
10432
- const ellipsisItem = { title: '...', ellipsis: erased.map((v) => v.title).join('/') };
10525
+ const ellipsisItem = { name: '...', ellipsis: erased.map((v) => v.name).join('/') };
10433
10526
  items.splice(1, 0, ellipsisItem);
10434
10527
  }
10435
10528
  for (let i = 0; i < items.length; ++i) {
10436
10529
  const item = items[i];
10437
- console.assert(item.title, 'Breadcrumb item must have a title!');
10530
+ console.assert(item.name, 'Breadcrumb item must have a name!');
10438
10531
  if (i != 0) {
10439
- const icon = LX.makeIcon(separatorIcon, { svgClass: 'sm fg-secondary separator' });
10532
+ const icon = LX.makeIcon(separatorIcon, { svgClass: 'sm text-foreground separator' });
10440
10533
  breadcrumb.appendChild(icon);
10441
10534
  }
10442
- const lastElement = i == items.length - 1;
10443
- const breadcrumbItem = LX.makeContainer(['auto', 'auto'], `p-1 flex flex-row gap-1 items-center ${lastElement ? '' : 'fg-secondary'}`);
10535
+ const lastElement = i == (items.length - 1);
10536
+ const breadcrumbItem = LX.makeContainer(['auto', 'auto'], `p-1 flex flex-row gap-1 items-center ${lastElement ? 'text-foreground' : 'text-muted-foreground'}`);
10444
10537
  breadcrumb.appendChild(breadcrumbItem);
10445
- let itemTitle = LX.makeElement('p', '', item.title);
10538
+ let itemName = LX.makeElement('p', '', item.name);
10446
10539
  if (item.icon) {
10447
10540
  breadcrumbItem.appendChild(LX.makeIcon(item.icon, { svgClass: 'sm' }));
10448
10541
  }
10449
10542
  if (item.items !== undefined) {
10450
- const bDropdownTrigger = LX.makeContainer(['auto', 'auto'], `${lastElement ? '' : 'fg-secondary'}`);
10543
+ const bDropdownTrigger = LX.makeContainer(['auto', 'auto'], `${lastElement ? 'text-foreground' : 'text-muted-foreground'}`);
10451
10544
  LX.listen(bDropdownTrigger, 'click', (e) => {
10452
10545
  LX.addDropdownMenu(e.target, item.items, { side: 'bottom', align: 'start' });
10453
10546
  });
10454
- bDropdownTrigger.append(itemTitle);
10547
+ bDropdownTrigger.append(itemName);
10455
10548
  breadcrumbItem.appendChild(bDropdownTrigger);
10456
10549
  }
10457
10550
  else if (item.url !== undefined) {
10458
- let itemUrl = LX.makeElement('a', `decoration-none fg-${lastElement ? 'primary' : 'secondary'}`, '', breadcrumbItem);
10551
+ let itemUrl = LX.makeElement('a', `decoration-none hover:underline underline-offset-4 ${lastElement ? 'text-foreground' : 'text-muted-foreground'}`, '', breadcrumbItem);
10459
10552
  itemUrl.href = item.url;
10460
- itemUrl.appendChild(itemTitle);
10553
+ itemUrl.appendChild(itemName);
10461
10554
  }
10462
10555
  else {
10463
- breadcrumbItem.appendChild(itemTitle);
10556
+ breadcrumbItem.appendChild(itemName);
10464
10557
  }
10465
10558
  if (item.ellipsis) {
10466
10559
  LX.asTooltip(breadcrumbItem, item.ellipsis, { side: 'bottom', offset: 4 });
@@ -10482,13 +10575,15 @@ LX.makeBreadcrumb = makeBreadcrumb;
10482
10575
  */
10483
10576
  function makeIcon(iconName, options = {}) {
10484
10577
  let svg = null;
10485
- const _createIconFromSVG = (svg) => {
10486
- if (options.svgClass && options.svgClass.length) {
10487
- options.svgClass.split(' ').forEach((c) => svg.classList.add(c));
10488
- }
10489
- const icon = document.createElement('a');
10578
+ const _createIconFromSVG = function (svg) {
10579
+ const cn = options.svgClass;
10580
+ if (cn && cn.length) {
10581
+ const mergedCn = LX.twMerge(...svg.classList, ...cn.split(' '));
10582
+ svg.classList.remove(...svg.classList);
10583
+ mergedCn.split(' ').forEach((c) => svg.classList.add(c));
10584
+ }
10585
+ const icon = LX.makeElement('a', LX.mergeClass('lexicon', options.iconClass));
10490
10586
  icon.title = options.title ?? '';
10491
- icon.className = 'lexicon ' + (options.iconClass ?? '');
10492
10587
  icon.appendChild(svg);
10493
10588
  svg.dataset['name'] = iconName;
10494
10589
  return icon;
@@ -10513,6 +10608,7 @@ function makeIcon(iconName, options = {}) {
10513
10608
  // Create internal icon if variant is the same as requested, there's no lucide/fallback data or if variant is "regular" (default)
10514
10609
  if ((requestedVariant == variant) || !lucideData || variant == 'regular') {
10515
10610
  svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
10611
+ svg.classList.add('text-inherit');
10516
10612
  svg.setAttribute('viewBox', `0 0 ${data[0]} ${data[1]}`);
10517
10613
  if (data[5]) {
10518
10614
  const classes = data[5].svgClass;
@@ -10526,6 +10622,7 @@ function makeIcon(iconName, options = {}) {
10526
10622
  });
10527
10623
  }
10528
10624
  const path = document.createElement('path');
10625
+ path.classList.add('text-inherit');
10529
10626
  path.setAttribute('fill', 'currentColor');
10530
10627
  path.setAttribute('d', data[4]);
10531
10628
  svg.appendChild(path);
@@ -10652,7 +10749,6 @@ function popup(text, title, options = {}) {
10652
10749
  throw ('No message to show');
10653
10750
  }
10654
10751
  options.size = options.size ?? ['max-content', 'auto'];
10655
- options.class = 'lexpopup';
10656
10752
  const time = options.timeout || 3000;
10657
10753
  const dialog = new LX.Dialog(title, (p) => {
10658
10754
  p.addTextArea(null, text, null, { disabled: true, fitHeight: true });
@@ -10726,9 +10822,7 @@ function toast(title, description, options = {}) {
10726
10822
  }
10727
10823
  const nots = LX.notifications;
10728
10824
  console.assert(nots);
10729
- const toast = document.createElement('li');
10730
- toast.className = 'lextoast';
10731
- nots.prepend(toast);
10825
+ const toast = LX.makeElement('li', 'lextoast flex flex-row relative w-full border-color overflow-hidden select-none pointer-events-auto touch-none rounded-lg p-3', '', nots);
10732
10826
  const [positionVertical, positionHorizontal] = options.position
10733
10827
  ? options.position.split('-')
10734
10828
  : ['bottom', 'right'];
@@ -10757,6 +10851,7 @@ function toast(title, description, options = {}) {
10757
10851
  break;
10758
10852
  case 'center':
10759
10853
  nots.style.placeSelf = 'center';
10854
+ nots.style.justifySelf = 'anchor-center';
10760
10855
  break;
10761
10856
  case 'right':
10762
10857
  nots.style.right = '1rem';
@@ -10771,18 +10866,10 @@ function toast(title, description, options = {}) {
10771
10866
  }
10772
10867
  toast.dataset['open'] = true;
10773
10868
  }, 10);
10774
- const content = document.createElement('div');
10775
- content.className = 'lextoastcontent';
10776
- toast.appendChild(content);
10777
- const titleContent = document.createElement('div');
10778
- titleContent.className = 'title';
10779
- titleContent.innerHTML = title;
10780
- content.appendChild(titleContent);
10869
+ const content = LX.makeElement('div', 'grid h-fit max-w-lg gap-1 items-center mr-6 [&_div]:truncate [&_svg]:shrink-0', '', toast);
10870
+ LX.makeElement('div', 'flex flex-row gap-2 text-sm text-foreground items-center min-w-0', title, content);
10781
10871
  if (description) {
10782
- const desc = document.createElement('div');
10783
- desc.className = 'desc';
10784
- desc.innerHTML = description;
10785
- content.appendChild(desc);
10872
+ LX.makeElement('div', 'text-secondary-foreground text-xs', description, content);
10786
10873
  }
10787
10874
  if (options.action) {
10788
10875
  const panel = new Panel();
@@ -10790,7 +10877,7 @@ function toast(title, description, options = {}) {
10790
10877
  width: 'auto',
10791
10878
  maxWidth: '150px',
10792
10879
  className: 'right',
10793
- buttonClass: 'border'
10880
+ buttonClass: 'outline sm'
10794
10881
  });
10795
10882
  toast.appendChild(panel.root.childNodes[0]);
10796
10883
  }
@@ -10805,7 +10892,7 @@ function toast(title, description, options = {}) {
10805
10892
  }, 500);
10806
10893
  };
10807
10894
  if (options.closable ?? true) {
10808
- const closeIcon = LX.makeIcon('X', { iconClass: 'closer' });
10895
+ const closeIcon = LX.makeIcon('X', { iconClass: 'absolute top-2 right-2 text-sm' });
10809
10896
  closeIcon.addEventListener('click', () => {
10810
10897
  toast.close();
10811
10898
  });
@@ -10830,13 +10917,12 @@ LX.toast = toast;
10830
10917
  function badge(text, className, options = {}) {
10831
10918
  const container = document.createElement('div');
10832
10919
  container.innerHTML = text;
10833
- container.className = 'lexbadge ' + (className ?? '');
10834
- if (options.chip) {
10835
- container.classList.add('chip');
10836
- }
10920
+ const cn = ['lexbadge', 'inline-flex', 'items-center', 'justify-center', 'rounded-full', 'border', 'px-2', 'py-0.5', 'text-xs', 'font-medium',
10921
+ 'w-fit', 'whitespace-nowrap', 'shrink-0', 'overflow-hidden', 'border-transparent', 'gap-1', 'min-w-5', 'bg-card text-foreground'];
10922
+ container.className = className ? LX.twMerge(...cn, ...className.split(' ')) : cn.join(' ');
10837
10923
  Object.assign(container.style, options.style ?? {});
10838
10924
  if (options.callback) {
10839
- const arrowIcon = LX.makeIcon('ArrowUpRight', { svgClass: 'xs fg-contrast' });
10925
+ const arrowIcon = LX.makeIcon('ArrowUpRight', { svgClass: 'xs' });
10840
10926
  arrowIcon.querySelector('svg').style.marginLeft = '-0.25rem';
10841
10927
  container.innerHTML += arrowIcon.innerHTML;
10842
10928
  container.addEventListener('click', (e) => {
@@ -10915,9 +11001,7 @@ function asTooltip(trigger, content, options = {}) {
10915
11001
  if (trigger.dataset['disableTooltip'] == 'true') {
10916
11002
  return;
10917
11003
  }
10918
- tooltipDom = document.createElement('div');
10919
- tooltipDom.className = 'lextooltip';
10920
- tooltipDom.innerHTML = trigger.dataset['tooltipContent'] ?? content;
11004
+ tooltipDom = LX.makeElement('div', 'lextooltip fixed bg-secondary-foreground text-secondary text-xs px-2 py-1 rounded-lg pointer-events-none data-closed:opacity-0', trigger.dataset['tooltipContent'] ?? content);
10921
11005
  const nestedDialog = trigger.closest('dialog');
10922
11006
  const tooltipParent = nestedDialog ?? LX.root;
10923
11007
  // Remove other first
@@ -11018,13 +11102,17 @@ function hasClass(el, list) {
11018
11102
  }
11019
11103
  LX.hasClass = hasClass;
11020
11104
  function addClass(el, className) {
11021
- if (className)
11022
- el.classList.add(className);
11105
+ if (!className)
11106
+ return;
11107
+ const cn = className.split(' ');
11108
+ el.classList.add(...cn);
11023
11109
  }
11024
11110
  LX.addClass = addClass;
11025
11111
  function removeClass(el, className) {
11026
- if (className)
11027
- el.classList.remove(className);
11112
+ if (!className)
11113
+ return;
11114
+ const cn = className.split(' ');
11115
+ el.classList.remove(...cn);
11028
11116
  }
11029
11117
  LX.removeClass = removeClass;
11030
11118
  function toggleClass(el, className, force) {
@@ -11032,6 +11120,12 @@ function toggleClass(el, className, force) {
11032
11120
  el.classList.toggle(className, force);
11033
11121
  }
11034
11122
  LX.toggleClass = toggleClass;
11123
+ function mergeClass(className, classNameOverride) {
11124
+ if (classNameOverride)
11125
+ className = [className, classNameOverride].join(' ');
11126
+ return LX.twMerge(...className.split(' '));
11127
+ }
11128
+ LX.mergeClass = mergeClass;
11035
11129
  function lastChar(str) {
11036
11130
  return str[str.length - 1];
11037
11131
  }
@@ -11350,6 +11444,32 @@ function drawSpline(ctx, pts, t) {
11350
11444
  }
11351
11445
  LX.drawSpline = drawSpline;
11352
11446
 
11447
+ // Avatar.ts @jxarco
11448
+ class Avatar {
11449
+ root;
11450
+ imageElement = undefined;
11451
+ fallbackElement = undefined;
11452
+ constructor(desc) {
11453
+ let rootCn = 'lexavatar bg-card items-center flex flex-row relative size-8 shrink-0 overflow-hidden rounded-full';
11454
+ this.root = LX.makeElement('div');
11455
+ if (desc.imgSource) {
11456
+ const cn = 'aspect-square size-full object-cover';
11457
+ const img = LX.makeElement('img', desc.imgClass ? LX.twMerge(...cn.split(' '), ...desc.imgClass.split(' ')) : cn, '', this.root);
11458
+ img.src = desc.imgSource;
11459
+ img.alt = desc.imgAlt;
11460
+ this.imageElement = img;
11461
+ }
11462
+ else if (desc.fallback) {
11463
+ const cn = 'size-full text-sm font-semibold place-self-center text-center content-center';
11464
+ const span = LX.makeElement('span', desc.fallbackClass ? LX.twMerge(...cn.split(' '), ...desc.fallbackClass.split(' ')) : cn, desc.fallback, this.root);
11465
+ this.fallbackElement = span;
11466
+ rootCn += ' border-color';
11467
+ }
11468
+ this.root.className = desc.className ? LX.twMerge(...rootCn.split(' '), ...desc.className.split(' ')) : rootCn;
11469
+ }
11470
+ }
11471
+ LX.Avatar = Avatar;
11472
+
11353
11473
  // Spinner.ts @jxarco
11354
11474
  /**
11355
11475
  * @class Spinner
@@ -11359,8 +11479,8 @@ class Spinner {
11359
11479
  constructor(options = {}) {
11360
11480
  const icon = options.icon ?? 'LoaderCircle';
11361
11481
  const size = options.size ?? 'md';
11362
- const iconClass = `flex ${options.iconClass ?? ''}`.trim();
11363
- const svgClass = `animate-spin ${size} ${options.svgClass ?? ''}`.trim();
11482
+ const iconClass = LX.mergeClass('flex', options.iconClass);
11483
+ const svgClass = LX.mergeClass(`animate-spin ${size}`, options.svgClass);
11364
11484
  this.root = LX.makeIcon(icon, { iconClass, svgClass });
11365
11485
  }
11366
11486
  html() {
@@ -11394,7 +11514,7 @@ class Dialog {
11394
11514
  this.id = LX.guidGenerator();
11395
11515
  const size = options.size ?? [], position = options.position ?? [], draggable = options.draggable ?? true, dockable = options.dockable ?? false, modal = options.modal ?? false;
11396
11516
  let root = document.createElement('dialog');
11397
- root.className = 'lexdialog ' + (options.className ?? '');
11517
+ root.className = LX.mergeClass('lexdialog absolute outline-none border-color m-0 p-0 min-w-3xs min-h-max overflow-hidden rounded-xl bg-background', options.className);
11398
11518
  root.id = options.id ?? 'dialog' + Dialog._last_id++;
11399
11519
  root.dataset['modal'] = modal;
11400
11520
  LX.root.appendChild(root);
@@ -11404,7 +11524,8 @@ class Dialog {
11404
11524
  let that = this;
11405
11525
  const titleDiv = document.createElement('div');
11406
11526
  if (title) {
11407
- titleDiv.className = 'lexdialogtitle';
11527
+ titleDiv.className =
11528
+ 'lexdialogtitle flex w-full outline-none items-center justify-between font-semibold text-xl text-secondary-foreground pad-xl select-none';
11408
11529
  titleDiv.innerHTML = title;
11409
11530
  titleDiv.setAttribute('draggable', 'false');
11410
11531
  root.appendChild(titleDiv);
@@ -11425,7 +11546,8 @@ class Dialog {
11425
11546
  options.onclose(this.root);
11426
11547
  }
11427
11548
  };
11428
- const closeButton = LX.makeIcon('X', { title: 'Close', iconClass: 'lexdialogcloser' });
11549
+ const closeButton = LX.makeIcon('X', { title: 'Close',
11550
+ iconClass: 'lexdialogcloser text-lg text-secondary-foreground cursor-pointer z-1 select-none' });
11429
11551
  closeButton.addEventListener('click', this.close);
11430
11552
  const dockButton = LX.makeIcon('Minus', { title: 'Dock', iconClass: 'ml-auto mr-2' });
11431
11553
  dockButton.addEventListener('click', () => {
@@ -11452,8 +11574,7 @@ class Dialog {
11452
11574
  root.appendChild(closeButton);
11453
11575
  }
11454
11576
  }
11455
- const panel = new LX.Panel();
11456
- panel.root.classList.add('lexdialogcontent');
11577
+ const panel = new LX.Panel({ className: 'lexdialogcontent w-full p-1 text-secondary-foreground text-sm ml-0 break-all' });
11457
11578
  if (!title) {
11458
11579
  panel.root.classList.add('notitle');
11459
11580
  }
@@ -11517,19 +11638,18 @@ class AlertDialog extends Dialog {
11517
11638
  options.draggable = false;
11518
11639
  options.modal = true;
11519
11640
  super(undefined, (p) => {
11520
- p.root.classList.add('p-4', 'flex', 'flex-col', 'gap-2');
11521
- LX.makeContainer(['100%', '100%'], 'text-xl font-medium', title, p);
11522
- p.addTextArea(null, message, null, { disabled: true, fitHeight: true,
11523
- inputClass: 'bg-none fg-tertiary' });
11641
+ p.root.className = LX.mergeClass(p.root.className, 'pad-2xl flex flex-col gap-2');
11642
+ LX.makeContainer(['100%', '100%'], 'text-lg font-medium text-foreground', title, p);
11643
+ p.addTextArea(null, message, null, { disabled: true, fitHeight: true, inputClass: 'bg-none text-sm text-muted-foreground' });
11524
11644
  p.sameLine(2, 'justify-end');
11525
11645
  p.addButton(null, options.cancelText ?? 'Cancel', () => this.destroy(), {
11526
- buttonClass: 'border bg-primary'
11646
+ buttonClass: 'outline'
11527
11647
  });
11528
11648
  p.addButton(null, options.continueText ?? 'Continue', () => {
11529
11649
  this.destroy();
11530
11650
  if (callback)
11531
11651
  callback();
11532
- }, { buttonClass: 'contrast' });
11652
+ }, { buttonClass: 'primary' });
11533
11653
  }, options);
11534
11654
  }
11535
11655
  }
@@ -11911,8 +12031,9 @@ class DropdownMenu {
11911
12031
  return;
11912
12032
  }
11913
12033
  const menuItem = document.createElement('div');
11914
- menuItem.className = 'lexdropdownmenuitem' + ((item.name || item.options) ? '' : ' label')
11915
- + (item.disabled ?? false ? ' disabled' : '') + (` ${item.className ?? ''}`);
12034
+ menuItem.className = LX.mergeClass('lexdropdownmenuitem flex flex-row pad-md rounded-lg gap-2 truncate cursor-pointer select-none'
12035
+ + ((item.name || item.options) ? '' : ' label')
12036
+ + (item.disabled ?? false ? ' disabled' : ''), item.className);
11916
12037
  menuItem.dataset['id'] = pKey;
11917
12038
  menuItem.innerHTML = `<span class="ellipsis-overflow">${key}</span>`;
11918
12039
  menuItem.tabIndex = '1';
@@ -11943,14 +12064,14 @@ class DropdownMenu {
11943
12064
  const disabled = item.disabled ?? false;
11944
12065
  if (this._radioGroup !== undefined) {
11945
12066
  if (item.name === this._radioGroup.selected) {
11946
- const icon = LX.makeIcon('Circle', { svgClass: 'xxs fill-current' });
12067
+ const icon = LX.makeIcon('Circle', { svgClass: '2xs fill-current' });
11947
12068
  menuItem.prepend(icon);
11948
12069
  }
11949
12070
  menuItem.setAttribute('data-radioname', this._radioGroup.name);
11950
12071
  }
11951
12072
  else if (item.icon) {
11952
12073
  const icon = item.icon.constructor === String
11953
- ? LX.makeIcon(item.icon, { svgClass: disabled ? 'fg-tertiary' : item.svgClass ?? item.className })
12074
+ ? LX.makeIcon(item.icon, { svgClass: disabled ? 'text-muted-foreground' : item.svgClass ?? item.className })
11954
12075
  : item.icon;
11955
12076
  menuItem.prepend(icon);
11956
12077
  }
@@ -11967,7 +12088,7 @@ class DropdownMenu {
11967
12088
  if (f) {
11968
12089
  f.call(this, key, v, menuItem);
11969
12090
  }
11970
- }, { className: 'accent' });
12091
+ }, { className: 'primary' });
11971
12092
  const input = checkbox.root.querySelector('input');
11972
12093
  input.classList.add('ml-auto');
11973
12094
  menuItem.appendChild(input);
@@ -12130,16 +12251,14 @@ class Footer {
12130
12251
  root;
12131
12252
  constructor(options = {}) {
12132
12253
  const root = document.createElement('footer');
12133
- root.className = 'lexfooter' + ` ${options.className ?? ''}`;
12254
+ root.className = LX.mergeClass('lexfooter bg-background p-2 w-full leading-6 [&_p]:text-xs', options.className);
12134
12255
  const wrapper = document.createElement('div');
12135
12256
  wrapper.style.minHeight = '48px';
12136
12257
  wrapper.className = 'w-full';
12137
12258
  root.appendChild(wrapper);
12138
- // const hr = document.createElement( "hr" );
12139
- // wrapper.appendChild( hr );
12140
12259
  if (options.columns && options.columns.constructor == Array) {
12141
12260
  const cols = document.createElement('div');
12142
- cols.className = 'columns';
12261
+ cols.className = 'grid text-center';
12143
12262
  cols.style.gridTemplateColumns = '1fr '.repeat(options.columns.length);
12144
12263
  wrapper.appendChild(cols);
12145
12264
  for (let col of options.columns) {
@@ -12304,7 +12423,7 @@ class Sheet {
12304
12423
  this.root.dataset['side'] = this.side;
12305
12424
  this.root.tabIndex = '1';
12306
12425
  this.root.role = 'dialog';
12307
- this.root.className = 'lexsheet fixed z-1000 bg-primary';
12426
+ this.root.className = 'lexsheet fixed z-1000 bg-primary overflow-hidden';
12308
12427
  document.body.appendChild(this.root);
12309
12428
  this.root.addEventListener('keydown', (e) => {
12310
12429
  if (e.key == 'Escape') {
@@ -12431,13 +12550,13 @@ class Sidebar {
12431
12550
  constructor(options = {}) {
12432
12551
  const mobile = navigator && /Android|iPhone/i.test(navigator.userAgent);
12433
12552
  this.root = document.createElement('div');
12434
- this.root.className = 'lexsidebar flex flex-col ' + (options.className ?? '');
12553
+ this.root.className = LX.mergeClass('lexsidebar flex flex-col pad-xl size-full scrollbar-hidden', options.className);
12435
12554
  this.callback = options.callback ?? null;
12436
- this._displaySelected = options.displaySelected ?? false;
12437
12555
  this.side = options.side ?? 'left';
12438
12556
  this.collapsable = options.collapsable ?? true;
12439
- this._collapseWidth = (options.collapseToIcons ?? true) ? '58px' : '0px';
12440
12557
  this.collapsed = options.collapsed ?? mobile;
12558
+ this._displaySelected = options.displaySelected ?? false;
12559
+ this._collapseWidth = (options.collapseToIcons ?? true) ? '58px' : '0px';
12441
12560
  this.filterString = '';
12442
12561
  LX.doAsync(() => {
12443
12562
  this.root.parentElement.ogWidth = this.root.parentElement.style.width;
@@ -12464,11 +12583,10 @@ class Sidebar {
12464
12583
  if (!(options.skipHeader ?? false)) {
12465
12584
  this.header = options.header ?? this._generateDefaultHeader(options);
12466
12585
  console.assert(this.header.constructor === HTMLDivElement, 'Use an HTMLDivElement to build your custom header');
12467
- this.header.className = 'lexsidebarheader flex-auto';
12586
+ this.header.className = 'lexsidebarheader w-full h-[48px] flex rounded-lg p-2 mb-2 text-sm cursor-pointer items-center select-none';
12468
12587
  this.root.appendChild(this.header);
12469
12588
  if (this.collapsable) {
12470
- const icon = LX.makeIcon(this.side == 'left' ? 'PanelLeft' : 'PanelRight', { title: 'Toggle Sidebar',
12471
- iconClass: 'toggler' });
12589
+ const icon = LX.makeIcon(this.side == 'left' ? 'PanelLeft' : 'PanelRight', { title: 'Toggle Sidebar', iconClass: 'toggler' });
12472
12590
  this.header.appendChild(icon);
12473
12591
  if (mobile) {
12474
12592
  // create an area and append a sidebar:
@@ -12504,14 +12622,14 @@ class Sidebar {
12504
12622
  // Content
12505
12623
  {
12506
12624
  this.content = document.createElement('div');
12507
- this.content.className = 'lexsidebarcontent flex-auto-fill';
12625
+ this.content.className = 'lexsidebarcontent overflow-mask flex flex-col overflow-x-hidden overflow-y-scroll flex-auto-fill w-full';
12508
12626
  this.root.appendChild(this.content);
12509
12627
  }
12510
12628
  // Footer
12511
12629
  if (!(options.skipFooter ?? false)) {
12512
12630
  this.footer = options.footer ?? this._generateDefaultFooter(options);
12513
12631
  console.assert(this.footer.constructor === HTMLDivElement, 'Use an HTMLDivElement to build your custom footer');
12514
- this.footer.className = 'lexsidebarfooter flex-auto';
12632
+ this.footer.className = 'lexsidebarfooter w-full h-[48px] flex rounded-lg p-2 mt-2 text-sm cursor-pointer items-center select-none';
12515
12633
  this.root.appendChild(this.footer);
12516
12634
  }
12517
12635
  }
@@ -12527,27 +12645,21 @@ class Sidebar {
12527
12645
  options.onHeaderPressed(e);
12528
12646
  }
12529
12647
  });
12530
- const avatar = document.createElement('span');
12531
- avatar.className = 'lexavatar';
12532
- header.appendChild(avatar);
12533
- if (options.headerImage) {
12534
- const avatarImg = document.createElement('img');
12535
- avatarImg.src = options.headerImage;
12536
- avatar.appendChild(avatarImg);
12537
- }
12538
- else if (options.headerIcon) {
12539
- const avatarIcon = LX.makeIcon(options.headerIcon);
12540
- avatar.appendChild(avatarIcon);
12541
- }
12648
+ const avatar = new LX.Avatar({
12649
+ imgSource: options.headerImage,
12650
+ fallback: options.headerIcon ? LX.makeIcon(options.headerIcon, { svgClass: 'xl' }).innerHTML : undefined,
12651
+ className: 'rounded-lg'
12652
+ });
12653
+ header.appendChild(avatar.root);
12542
12654
  // Info
12543
12655
  {
12544
12656
  const info = document.createElement('div');
12545
12657
  info.className = 'infodefault';
12546
12658
  header.appendChild(info);
12547
- const infoText = document.createElement('span');
12659
+ const infoText = LX.makeElement('span', 'truncate text-sm font-semibold');
12548
12660
  infoText.innerHTML = options.headerTitle ?? '';
12549
12661
  info.appendChild(infoText);
12550
- const infoSubtext = document.createElement('span');
12662
+ const infoSubtext = LX.makeElement('span', 'truncate text-xs');
12551
12663
  infoSubtext.innerHTML = options.headerSubtitle ?? '';
12552
12664
  info.appendChild(infoSubtext);
12553
12665
  }
@@ -12565,27 +12677,21 @@ class Sidebar {
12565
12677
  options.onFooterPressed(e, footer);
12566
12678
  }
12567
12679
  });
12568
- const avatar = document.createElement('span');
12569
- avatar.className = 'lexavatar';
12570
- footer.appendChild(avatar);
12571
- if (options.footerImage) {
12572
- const avatarImg = document.createElement('img');
12573
- avatarImg.src = options.footerImage;
12574
- avatar.appendChild(avatarImg);
12575
- }
12576
- else if (options.footerIcon) {
12577
- const avatarIcon = LX.makeIcon(options.footerIcon);
12578
- avatar.appendChild(avatarIcon);
12579
- }
12680
+ const avatar = new LX.Avatar({
12681
+ imgSource: options.footerImage,
12682
+ fallback: options.footerIcon ? LX.makeIcon(options.footerIcon, { svgClass: 'xl' }).innerHTML : undefined,
12683
+ className: 'rounded-lg'
12684
+ });
12685
+ footer.appendChild(avatar.root);
12580
12686
  // Info
12581
12687
  {
12582
12688
  const info = document.createElement('div');
12583
12689
  info.className = 'infodefault';
12584
12690
  footer.appendChild(info);
12585
- const infoText = document.createElement('span');
12691
+ const infoText = LX.makeElement('span', 'truncate text-sm font-semibold');
12586
12692
  infoText.innerHTML = options.footerTitle ?? '';
12587
12693
  info.appendChild(infoText);
12588
- const infoSubtext = document.createElement('span');
12694
+ const infoSubtext = LX.makeElement('span', 'truncate text-xs');
12589
12695
  infoSubtext.innerHTML = options.footerSubtitle ?? '';
12590
12696
  info.appendChild(infoSubtext);
12591
12697
  }
@@ -12720,9 +12826,8 @@ class Sidebar {
12720
12826
  }
12721
12827
  let pKey = LX.getSupportedDOMName(key);
12722
12828
  let currentGroup = null;
12723
- let entry = document.createElement('div');
12829
+ let entry = LX.makeElement('div', LX.mergeClass('lexsidebarentry w-full rounded-lg cursor-pointer select-none', options.className));
12724
12830
  entry.id = pKey;
12725
- entry.className = 'lexsidebarentry ' + (options.className ?? '');
12726
12831
  if (this.displaySelected && options.selected) {
12727
12832
  entry.classList.add('selected');
12728
12833
  }
@@ -12730,16 +12835,13 @@ class Sidebar {
12730
12835
  const pGroupKey = item.group.replace(/\s/g, '').replaceAll('.', '');
12731
12836
  currentGroup = this.content.querySelector('#' + pGroupKey);
12732
12837
  if (!currentGroup) {
12733
- currentGroup = document.createElement('div');
12838
+ currentGroup = LX.makeElement('div', 'lexsidebargroup flex flex-col gap-0.5');
12734
12839
  currentGroup.id = pGroupKey;
12735
- currentGroup.className = 'lexsidebargroup';
12736
12840
  this.content.appendChild(currentGroup);
12737
- let groupEntry = document.createElement('div');
12738
- groupEntry.className = 'lexsidebargrouptitle';
12841
+ let groupEntry = LX.makeElement('div', 'lexsidebargrouptitle');
12739
12842
  currentGroup.appendChild(groupEntry);
12740
- let groupLabel = document.createElement('div');
12741
- groupLabel.innerHTML = item.group;
12742
- groupEntry.appendChild(groupLabel);
12843
+ // Group label
12844
+ LX.makeElement('div', '', item.group, groupEntry);
12743
12845
  if (this.groups[item.group] != null) {
12744
12846
  const groupActionIcon = LX.makeIcon(this.groups[item.group].icon, { svgClass: 'sm' });
12745
12847
  groupEntry.appendChild(groupActionIcon);
@@ -12787,7 +12889,7 @@ class Sidebar {
12787
12889
  item.value = value;
12788
12890
  if (f)
12789
12891
  f.call(this, key, value, event);
12790
- }, { className: 'accent', label: key, signal: ('@checkbox_' + key) });
12892
+ }, { className: 'primary', label: key, signal: ('@checkbox_' + key) });
12791
12893
  itemDom.appendChild(panel.root.childNodes[0]);
12792
12894
  }
12793
12895
  else {
@@ -12864,8 +12966,7 @@ class Sidebar {
12864
12966
  if (!item[key].length) {
12865
12967
  continue;
12866
12968
  }
12867
- let subentryContainer = document.createElement('div');
12868
- subentryContainer.className = 'lexsidebarsubentrycontainer';
12969
+ let subentryContainer = LX.makeElement('div', 'lexsidebarsubentrycontainer flex flex-col self-center w-full ml-4 px-4 select-none');
12869
12970
  if (isCollapsable) {
12870
12971
  this.collapseContainer.appendChild(subentryContainer);
12871
12972
  delete this.collapseContainer;
@@ -12899,7 +13000,7 @@ class Sidebar {
12899
13000
  f.call(this, subkey, e);
12900
13001
  });
12901
13002
  }
12902
- subentry.className = 'lexsidebarentry';
13003
+ subentry.className = 'lexsidebarentry w-full rounded-lg cursor-pointer select-none';
12903
13004
  subentry.id = subkey;
12904
13005
  if (suboptions.content) {
12905
13006
  const parentContainer = LX.makeElement('div');
@@ -13035,7 +13136,7 @@ class Tour {
13035
13136
  // using a fullscreen SVG with "rect" elements
13036
13137
  _generateMask(reference) {
13037
13138
  this.tourContainer.innerHTML = ''; // Clear previous content
13038
- this.tourMask = LX.makeContainer(['100%', '100%'], 'tour-mask');
13139
+ this.tourMask = LX.makeContainer(['100%', '100%'], 'tour-mask absolute inset-0');
13039
13140
  this.tourContainer.appendChild(this.tourMask);
13040
13141
  const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
13041
13142
  svg.style.width = '100%';
@@ -13096,7 +13197,7 @@ class Tour {
13096
13197
  clipPath.appendChild(rect);
13097
13198
  }
13098
13199
  // Reference Highlight
13099
- const refContainer = LX.makeContainer(['0', '0'], 'tour-ref-mask');
13200
+ const refContainer = LX.makeContainer(['0', '0'], 'tour-ref-mask absolute');
13100
13201
  refContainer.style.left = `${boundingX - hOffset - 1}px`;
13101
13202
  refContainer.style.top = `${boundingY - vOffset - 1}px`;
13102
13203
  refContainer.style.width = `${boundingWidth + hOffset * 2 + 2}px`;
@@ -13127,7 +13228,7 @@ class Tour {
13127
13228
  const popoverContainer = LX.makeContainer(['auto', 'auto'], 'tour-step-container');
13128
13229
  {
13129
13230
  const header = LX.makeContainer(['100%', 'auto'], 'flex flex-row', '', popoverContainer);
13130
- LX.makeContainer(['70%', 'auto'], 'p-2 font-medium', step.title, header);
13231
+ LX.makeContainer(['70%', 'auto'], 'p-2 font-medium text-base', step.title, header);
13131
13232
  const closer = LX.makeContainer(['30%', 'auto'], 'flex flex-row p-2 justify-end', '', header);
13132
13233
  const closeIcon = LX.makeIcon('X');
13133
13234
  closer.appendChild(closeIcon);
@@ -13135,22 +13236,22 @@ class Tour {
13135
13236
  this.stop();
13136
13237
  });
13137
13238
  }
13138
- LX.makeContainer(['100%', 'auto'], 'p-2 text-md', step.content, popoverContainer, {
13239
+ LX.makeContainer(['100%', 'auto'], 'p-2 text-sm', step.content, popoverContainer, {
13139
13240
  maxWidth: '400px'
13140
13241
  });
13141
- const footer = LX.makeContainer(['100%', 'auto'], 'flex flex-row text-md', '', popoverContainer);
13242
+ const footer = LX.makeContainer(['100%', 'auto'], 'flex flex-row', '', popoverContainer);
13142
13243
  {
13143
- const footerSteps = LX.makeContainer(['50%', 'auto'], 'p-2 gap-1 self-center flex flex-row text-md', '', footer);
13244
+ const footerSteps = LX.makeContainer(['50%', 'auto'], 'p-2 gap-1 place-self-center flex flex-row', '', footer);
13144
13245
  for (let i = 0; i < this.steps.length; i++) {
13145
- const stepIndicator = document.createElement('span');
13146
- stepIndicator.className = 'tour-step-indicator';
13246
+ const stepIndicator = LX.makeElement('span');
13247
+ stepIndicator.className = 'size-3 rounded-full bg-accent inline-flex data-active:bg-primary';
13147
13248
  if (i === this.currentStep) {
13148
- stepIndicator.classList.add('active');
13249
+ stepIndicator.dataset['active'] = 'true';
13149
13250
  }
13150
13251
  footerSteps.appendChild(stepIndicator);
13151
13252
  }
13152
13253
  }
13153
- const footerButtons = LX.makeContainer(['50%', 'auto'], 'text-md', '', footer);
13254
+ const footerButtons = LX.makeContainer(['50%', 'auto'], 'text-base', '', footer);
13154
13255
  const footerPanel = new Panel();
13155
13256
  let numButtons = 1;
13156
13257
  if (previousStep) {
@@ -13162,7 +13263,7 @@ class Tour {
13162
13263
  if (previousStep) {
13163
13264
  footerPanel.addButton(null, 'Previous', () => {
13164
13265
  this._showStep(-1);
13165
- }, { buttonClass: 'contrast' });
13266
+ }, { buttonClass: 'ghost' });
13166
13267
  }
13167
13268
  if (nextStep) {
13168
13269
  footerPanel.addButton(null, 'Next', () => {
@@ -13172,11 +13273,10 @@ class Tour {
13172
13273
  else {
13173
13274
  footerPanel.addButton(null, 'Finish', () => {
13174
13275
  this.stop();
13175
- });
13276
+ }, { buttonClass: 'primary' });
13176
13277
  }
13177
13278
  footerButtons.appendChild(footerPanel.root);
13178
- const sideOffset = (step.side === 'left' || step.side === 'right' ? this.horizontalOffset : this.verticalOffset)
13179
- ?? this.offset;
13279
+ const sideOffset = (step.side === 'left' || step.side === 'right' ? this.horizontalOffset : this.verticalOffset) ?? this.offset;
13180
13280
  const alignOffset = step.align === 'start' || step.align === 'end' ? sideOffset : 0;
13181
13281
  this._popover?.destroy();
13182
13282
  this._popover = new Popover(null, [popoverContainer], {
@@ -13210,19 +13310,20 @@ LX.init = async function (options = {}) {
13210
13310
  await LX.loadScriptSync('https://unpkg.com/lucide@latest');
13211
13311
  // LexGUI root
13212
13312
  console.log(`LexGUI v${this.version}`);
13213
- var root = document.createElement('div');
13313
+ const root = LX.makeElement('div', LX.mergeClass('lexcontainer', options.rootClass));
13214
13314
  root.id = 'lexroot';
13215
- root.className = 'lexcontainer';
13216
13315
  root.tabIndex = -1;
13217
- if (options.rootClass) {
13218
- root.className += ` ${options.rootClass}`;
13219
- }
13220
- this.modal = document.createElement('div');
13316
+ this.modal = LX.makeElement('div', 'inset-0 hidden-opacity bg-black/50 fixed z-100 transition-opacity duration-100 ease-in');
13221
13317
  this.modal.id = 'modal';
13222
- this.modal.classList.add('hidden-opacity');
13223
13318
  this.modal.toggle = function (force) {
13224
13319
  this.classList.toggle('hidden-opacity', force);
13225
13320
  };
13321
+ function blockScroll(e) {
13322
+ e.preventDefault();
13323
+ e.stopPropagation();
13324
+ }
13325
+ this.modal.addEventListener('wheel', blockScroll, { passive: false });
13326
+ this.modal.addEventListener('touchmove', blockScroll, { passive: false });
13226
13327
  this.root = root;
13227
13328
  this.container = document.body;
13228
13329
  if (options.container) {
@@ -13247,7 +13348,7 @@ LX.init = async function (options = {}) {
13247
13348
  const notifSection = document.createElement('section');
13248
13349
  notifSection.className = 'notifications';
13249
13350
  this.notifications = document.createElement('ol');
13250
- this.notifications.className = '';
13351
+ this.notifications.className = 'fixed flex flex-col-reverse m-0 p-0 gap-1 z-1000';
13251
13352
  this.notifications.iWidth = 0;
13252
13353
  notifSection.appendChild(this.notifications);
13253
13354
  document.body.appendChild(notifSection);
@@ -13290,87 +13391,113 @@ LX.init = async function (options = {}) {
13290
13391
  const storedcolorScheme = localStorage.getItem('lxColorScheme');
13291
13392
  if (storedcolorScheme)
13292
13393
  return;
13293
- LX.setTheme(event.matches ? 'dark' : 'light', false);
13394
+ LX.setMode(event.matches ? 'dark' : 'light', false);
13294
13395
  };
13295
13396
  this._mqlPrefersDarkScheme = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
13296
13397
  const storedcolorScheme = localStorage.getItem('lxColorScheme');
13297
13398
  if (storedcolorScheme) {
13298
- LX.setTheme(storedcolorScheme);
13399
+ LX.setMode(storedcolorScheme);
13299
13400
  }
13300
13401
  else if (this._mqlPrefersDarkScheme && (options.autoTheme ?? true)) {
13301
13402
  if (window.matchMedia('(prefers-color-scheme: light)').matches) {
13302
- LX.setTheme('light', false);
13403
+ LX.setMode('light', false);
13303
13404
  }
13304
13405
  this._mqlPrefersDarkScheme.addEventListener('change', this._onChangeSystemTheme);
13305
13406
  }
13407
+ // LX.setThemeColor( 'rose' );
13306
13408
  return this.mainArea;
13307
- }, /**
13409
+ };
13410
+ /**
13308
13411
  * @method setSpacingMode
13309
13412
  * @param {String} mode: "default" | "compact"
13310
13413
  */
13311
- LX.setSpacingMode = function (mode) {
13312
- this.spacingMode = mode;
13313
- document.documentElement.setAttribute('data-spacing', this.spacingMode);
13314
- }, /**
13414
+ LX.setSpacingMode = function (mode) {
13415
+ this.spacingMode = mode;
13416
+ document.documentElement.setAttribute('data-spacing', this.spacingMode);
13417
+ };
13418
+ /**
13315
13419
  * @method setLayoutMode
13316
13420
  * @param {String} mode: "app" | "document"
13317
13421
  */
13318
- LX.setLayoutMode = function (mode) {
13319
- this.layoutMode = mode;
13320
- document.documentElement.setAttribute('data-layout', this.layoutMode);
13321
- }, /**
13422
+ LX.setLayoutMode = function (mode) {
13423
+ this.layoutMode = mode;
13424
+ document.documentElement.setAttribute('data-layout', this.layoutMode);
13425
+ };
13426
+ /**
13322
13427
  * @method addSignal
13323
13428
  * @param {String} name
13324
13429
  * @param {Object} obj
13325
13430
  * @param {Function} callback
13326
13431
  */
13327
- LX.addSignal = function (name, obj, callback) {
13328
- obj[name] = callback;
13329
- if (!LX.signals[name]) {
13330
- LX.signals[name] = [];
13331
- }
13332
- if (LX.signals[name].indexOf(obj) > -1) {
13333
- return;
13432
+ LX.addSignal = function (name, obj, callback) {
13433
+ obj[name] = callback;
13434
+ if (!LX.signals[name]) {
13435
+ LX.signals[name] = [];
13436
+ }
13437
+ if (LX.signals[name].indexOf(obj) > -1) {
13438
+ return;
13439
+ }
13440
+ LX.signals[name].push(obj);
13441
+ };
13442
+ /**
13443
+ * @method removeSignal
13444
+ * @param {String} name
13445
+ * @param {Object} targetObj
13446
+ */
13447
+ LX.removeSignal = function (name, targetObj) {
13448
+ const data = LX.signals[name];
13449
+ if (!data) {
13450
+ return;
13451
+ }
13452
+ if (!targetObj) {
13453
+ delete LX.signals[name];
13454
+ return;
13455
+ }
13456
+ for (let i = 0; i < data.length; ++i) {
13457
+ if (data[i] == targetObj) {
13458
+ data.splice(i, 1);
13459
+ break;
13334
13460
  }
13335
- LX.signals[name].push(obj);
13336
- }, /**
13461
+ }
13462
+ };
13463
+ /**
13337
13464
  * @method emitSignal
13338
13465
  * @param {String} name
13339
13466
  * @param {*} value
13340
13467
  * @param {Object} options
13341
13468
  */
13342
- LX.emitSignal = function (name, value, options = {}) {
13343
- const data = LX.signals[name];
13344
- if (!data) {
13345
- return;
13469
+ LX.emitSignal = function (name, value, options = {}) {
13470
+ const data = LX.signals[name];
13471
+ if (!data) {
13472
+ return;
13473
+ }
13474
+ const target = options.target;
13475
+ if (target) {
13476
+ if (target[name]) {
13477
+ target[name].call(target, value);
13346
13478
  }
13347
- const target = options.target;
13348
- if (target) {
13349
- if (target[name]) {
13350
- target[name].call(target, value);
13351
- }
13352
- return;
13479
+ return;
13480
+ }
13481
+ for (let obj of data) {
13482
+ if (obj instanceof BaseComponent) {
13483
+ obj.set(value, options.skipCallback ?? true);
13353
13484
  }
13354
- for (let obj of data) {
13355
- if (obj instanceof BaseComponent) {
13356
- obj.set(value, options.skipCallback ?? true);
13357
- }
13358
- else if (obj.constructor === Function) {
13359
- const fn = obj;
13360
- fn(null, value);
13361
- }
13362
- else {
13363
- // This is an element
13364
- const fn = obj[name];
13365
- console.assert(fn, `No callback registered with _${name}_ signal`);
13366
- fn.bind(obj)(value);
13367
- }
13485
+ else if (obj.constructor === Function) {
13486
+ const fn = obj;
13487
+ fn(null, value);
13368
13488
  }
13369
- };
13489
+ else {
13490
+ // This is an element
13491
+ const fn = obj[name];
13492
+ console.assert(fn, `No callback registered with _${name}_ signal`);
13493
+ fn.bind(obj)(value);
13494
+ }
13495
+ }
13496
+ };
13370
13497
  // Command bar creation
13371
13498
  LX._createCommandbar = function (root) {
13372
13499
  let commandbar = document.createElement('dialog');
13373
- commandbar.className = 'commandbar';
13500
+ commandbar.className = 'commandbar absolute border-color rounded-lg m-0';
13374
13501
  commandbar.tabIndex = -1;
13375
13502
  root.appendChild(commandbar);
13376
13503
  let allItems = [];
@@ -13419,7 +13546,7 @@ LX._createCommandbar = function (root) {
13419
13546
  }
13420
13547
  e.stopPropagation();
13421
13548
  e.stopImmediatePropagation();
13422
- commandbar.close();
13549
+ LX.setCommandbarState(false);
13423
13550
  _resetBar(true);
13424
13551
  });
13425
13552
  root.addEventListener('keydown', (e) => {
@@ -13459,8 +13586,7 @@ LX._createCommandbar = function (root) {
13459
13586
  cbTabs.add('All', document.createElement('div'), { selected: true, onSelect: _onSelectTab });
13460
13587
  // cbTabs.add( "Main", document.createElement('div'), { onSelect: _onSelectTab } );
13461
13588
  }
13462
- const itemContainer = document.createElement('div');
13463
- itemContainer.className = 'searchitembox';
13589
+ const itemContainer = LX.makeElement('div', 'searchitembox overflow-y-scroll basis-full scrollbar-hidden');
13464
13590
  let refPrevious = null;
13465
13591
  const _resetBar = (resetInput) => {
13466
13592
  itemContainer.innerHTML = '';
@@ -13470,6 +13596,53 @@ LX._createCommandbar = function (root) {
13470
13596
  filter.set('', true);
13471
13597
  }
13472
13598
  };
13599
+ const _filterEntry = function (entryName, filter) {
13600
+ if (!filter?.length)
13601
+ return false;
13602
+ const cleanName = LX.stripTags(entryName).toLowerCase();
13603
+ return cleanName.includes(filter.toLowerCase());
13604
+ };
13605
+ const _getEntries = function (filter) {
13606
+ const entries = [];
13607
+ for (let m of LX.menubars) {
13608
+ for (let i of m.items) {
13609
+ if (_filterEntry(i.name, filter))
13610
+ entries.push(i);
13611
+ }
13612
+ }
13613
+ for (let m of LX.sidebars) {
13614
+ for (let i of m.items) {
13615
+ if (_filterEntry(i.name, filter))
13616
+ entries.push(i);
13617
+ }
13618
+ }
13619
+ for (let entry of LX.extraCommandbarEntries) {
13620
+ if (_filterEntry(entry.name, filter))
13621
+ entries.push(entry);
13622
+ }
13623
+ if (LX.has('CodeEditor')) {
13624
+ const instances = LX.CodeEditor.getInstances();
13625
+ if (!instances.length || !instances[0].area.root.offsetHeight)
13626
+ return entries;
13627
+ const languages = LX.CodeEditor.languages;
13628
+ for (let l of Object.keys(languages)) {
13629
+ const key = 'Language: ' + l;
13630
+ const icon = instances[0]._getFileIcon(null, languages[l].ext);
13631
+ const classes = icon.split(' ');
13632
+ let value = LX.makeIcon(classes[0], { svgClass: `${classes.slice(0).join(' ')}` }).innerHTML;
13633
+ value += key + " <span class='lang-ext'>(" + languages[l].ext + ')</span>';
13634
+ if (!_filterEntry(key, filter)) {
13635
+ continue;
13636
+ }
13637
+ entries.push({ name: value, callback: () => {
13638
+ for (let i of instances) {
13639
+ i._changeLanguage(l);
13640
+ }
13641
+ } });
13642
+ }
13643
+ }
13644
+ return entries;
13645
+ };
13473
13646
  const _addElement = (t, c, p, i) => {
13474
13647
  if (!t.length) {
13475
13648
  return;
@@ -13507,64 +13680,41 @@ LX._createCommandbar = function (root) {
13507
13680
  itemContainer.appendChild(searchItem);
13508
13681
  refPrevious = searchItem;
13509
13682
  };
13510
- const _propagateAdd = (item, filter, path, skipPropagation) => {
13683
+ const _propagateAdd = (item, path, skipPropagation) => {
13511
13684
  if (!item || (item.constructor != Object)) {
13512
13685
  return;
13513
13686
  }
13514
- let name = item.name;
13515
- if (name.toLowerCase().includes(filter)) {
13516
- if (item.callback) {
13517
- _addElement(name, item.callback, path, item);
13518
- }
13687
+ if (item.callback) {
13688
+ _addElement(item.name, item.callback, path, item);
13519
13689
  }
13520
- const submenu = item.submenu ?? item[name];
13690
+ const submenu = item.submenu ?? item[item.name];
13521
13691
  if (!submenu) {
13522
13692
  return;
13523
13693
  }
13524
- const icon = LX.makeIcon('ChevronRight', { svgClass: 'sm fg-secondary separator' });
13525
- path += name + icon.innerHTML;
13694
+ const icon = LX.makeIcon('ChevronRight', { svgClass: 'sm text-muted-foreground separator' });
13695
+ path += item.name + icon.innerHTML;
13526
13696
  for (let c of submenu) {
13527
- _propagateAdd(c, filter, path);
13697
+ _propagateAdd(c, path);
13528
13698
  }
13529
13699
  };
13530
13700
  commandbar._addElements = (filter) => {
13531
13701
  _resetBar();
13532
- for (let m of LX.menubars) {
13533
- for (let i of m.items) {
13534
- _propagateAdd(i, filter, '');
13535
- }
13536
- }
13537
- for (let m of LX.sidebars) {
13538
- for (let i of m.items) {
13539
- _propagateAdd(i, filter, '');
13540
- }
13541
- }
13542
- for (let entry of LX.extraCommandbarEntries) {
13543
- const name = entry.name;
13544
- if (!name.toLowerCase().includes(filter)) {
13545
- continue;
13546
- }
13547
- _addElement(name, entry.callback, '', {});
13548
- }
13549
- if (LX.has('CodeEditor')) {
13550
- const instances = LX.CodeEditor.getInstances();
13551
- if (!instances.length || !instances[0].area.root.offsetHeight)
13552
- return;
13553
- const languages = LX.CodeEditor.languages;
13554
- for (let l of Object.keys(languages)) {
13555
- const key = 'Language: ' + l;
13556
- const icon = instances[0]._getFileIcon(null, languages[l].ext);
13557
- const classes = icon.split(' ');
13558
- let value = LX.makeIcon(classes[0], { svgClass: `${classes.slice(0).join(' ')}` }).innerHTML;
13559
- value += key + " <span class='lang-ext'>(" + languages[l].ext + ')</span>';
13560
- if (key.toLowerCase().includes(filter)) {
13561
- _addElement(value, () => {
13562
- for (let i of instances) {
13563
- i._changeLanguage(l);
13564
- }
13565
- }, '', {});
13566
- }
13567
- }
13702
+ let entries = _getEntries(filter);
13703
+ // Order...
13704
+ function scoreEntry(s, prefix) {
13705
+ if (s.startsWith(prefix))
13706
+ return 0; // best option
13707
+ if (s.includes(prefix))
13708
+ return 1;
13709
+ return 2; // worst
13710
+ }
13711
+ entries = entries.sort((a, b) => {
13712
+ const nameA = LX.stripTags(a.name), nameB = LX.stripTags(b.name);
13713
+ return (scoreEntry(nameA, filter) - scoreEntry(nameB, filter)) || nameA.localeCompare(nameB);
13714
+ });
13715
+ entries = entries.slice(0, 48); // Get 48 ocurrences max
13716
+ for (let entry of entries) {
13717
+ _propagateAdd(entry, '');
13568
13718
  }
13569
13719
  };
13570
13720
  commandbar.appendChild(header);
@@ -13572,6 +13722,37 @@ LX._createCommandbar = function (root) {
13572
13722
  commandbar.appendChild(itemContainer);
13573
13723
  return commandbar;
13574
13724
  };
13725
+ LX._registerIconsAndColors = function (colorsRootPath = './') {
13726
+ LX.requestJSON(colorsRootPath + 'registry/colors.json', (colors) => {
13727
+ // loop through each color
13728
+ for (const key in colors) {
13729
+ const value = colors[key];
13730
+ if (!Array.isArray(value)) {
13731
+ continue;
13732
+ }
13733
+ value.forEach((entry) => {
13734
+ const color = `${key}-${entry.scale}`;
13735
+ const val = `<span class="flex bg-${color} w-3 h-3 rounded-full mr-2"></span>${color}`;
13736
+ LX.registerCommandbarEntry(val, () => {
13737
+ navigator.clipboard.writeText(color);
13738
+ LX.toast(`${LX.makeIcon('CircleCheck').innerHTML} Copied ${color} to clipboard.`, null, { position: 'top-center',
13739
+ timeout: 3000 });
13740
+ });
13741
+ });
13742
+ }
13743
+ });
13744
+ const lucide = window.lucide;
13745
+ const allIcons = { ...LX.ICONS, ...lucide.icons };
13746
+ for (const iconName in allIcons) {
13747
+ const variant = 'regular';
13748
+ const icon = LX.makeIcon(iconName, { svgClass: 'mr-2 pointer-events-none', variant });
13749
+ const val = `${icon.innerHTML}${iconName}`;
13750
+ LX.registerCommandbarEntry(val, () => {
13751
+ navigator.clipboard.writeText(iconName);
13752
+ LX.toast(`${LX.makeIcon('CircleCheck').innerHTML} Copied ${iconName} to clipboard.`, null, { position: 'top-center', timeout: 3000 });
13753
+ });
13754
+ }
13755
+ };
13575
13756
  /**
13576
13757
  * @method setCommandbarState
13577
13758
  * @param {Boolean} value
@@ -13579,12 +13760,16 @@ LX._createCommandbar = function (root) {
13579
13760
  */
13580
13761
  LX.setCommandbarState = function (value, resetEntries = true) {
13581
13762
  const cb = this.commandbar;
13763
+ LX.modal.toggle(!value);
13582
13764
  if (value) {
13765
+ // Get current position based on main scroll
13766
+ cb.style.top = `calc(15% + ${document.scrollingElement?.scrollTop ?? 0}px)`;
13583
13767
  cb.show();
13584
13768
  cb.querySelector('input').focus();
13585
13769
  if (resetEntries) {
13586
13770
  cb._addElements(undefined);
13587
13771
  }
13772
+ LX.modal.toggle(false);
13588
13773
  }
13589
13774
  else {
13590
13775
  cb.close();
@@ -13630,7 +13815,7 @@ LX.REGISTER_COMPONENT = function (customComponentName, options = {}) {
13630
13815
  const customIcon = LX.makeIcon(options.icon ?? 'Box');
13631
13816
  const menuIcon = LX.makeIcon('Menu');
13632
13817
  let buttonName = customComponentName + (!instance ? ' [empty]' : '');
13633
- let buttonEl = this.addButton(null, buttonName, (value, event) => {
13818
+ let button = this.addButton(null, buttonName, (value, event) => {
13634
13819
  if (instance) {
13635
13820
  element.querySelector('.lexcustomitems').toggleAttribute('hidden');
13636
13821
  element.dataset['opened'] = !element.querySelector('.lexcustomitems').hasAttribute('hidden');
@@ -13645,11 +13830,11 @@ LX.REGISTER_COMPONENT = function (customComponentName, options = {}) {
13645
13830
  });
13646
13831
  });
13647
13832
  }
13648
- }, { buttonClass: 'custom' });
13649
- const buttonSpan = buttonEl.root.querySelector('span');
13650
- buttonSpan.prepend(customIcon);
13651
- buttonSpan.appendChild(menuIcon);
13652
- container.appendChild(buttonEl.root);
13833
+ }, { buttonClass: 'outline custom' });
13834
+ const buttonDom = button.root.querySelector('button');
13835
+ buttonDom.prepend(customIcon);
13836
+ buttonDom.appendChild(menuIcon);
13837
+ container.appendChild(button.root);
13653
13838
  if (instance) {
13654
13839
  menuIcon.addEventListener('click', (e) => {
13655
13840
  e.stopImmediatePropagation();
@@ -13729,5 +13914,5 @@ LX.REGISTER_COMPONENT = function (customComponentName, options = {}) {
13729
13914
  };
13730
13915
  };
13731
13916
 
13732
- export { AlertDialog, Area, AreaOverlayButtons, ArrayInput, BaseComponent, Branch, Button, Checkbox, ColorInput, ComboButtons, ComponentType, ContextMenu, Counter, Curve, DatePicker, Dial, Dialog, DropdownMenu, FileInput, Footer, Form, IEvent, LX, Layers, List, Map2D, NodeTree, NumberInput, OTPInput, Pad, Pagination, Panel, PocketDialog, Popover, Progress, RadioGroup, RangeInput, Rate, Select, Sheet, Sidebar, SizeInput, Skeleton, Spinner, TabSections, Table, Tabs, Tags, TextArea, TextInput, Title, Toggle, Tour, Tree, TreeEvent, Vector, addDropdownMenu, vec2 };
13917
+ export { AlertDialog, Area, AreaOverlayButtons, ArrayInput, Avatar, BaseComponent, Branch, Button, Checkbox, ColorInput, ComboButtons, ComponentType, ContextMenu, Counter, Curve, DatePicker, Dial, Dialog, DropdownMenu, FileInput, Footer, Form, IEvent, LX, Layers, List, Map2D, NodeTree, NumberInput, OTPInput, Pad, Pagination, Panel, PocketDialog, Popover, Progress, RadioGroup, RangeInput, Rate, Select, Sheet, Sidebar, SizeInput, Skeleton, Spinner, TabSections, Table, Tabs, Tags, TextArea, TextInput, Title, Toggle, Tour, Tree, Vector, addDropdownMenu, vec2 };
13733
13918
  //# sourceMappingURL=lexgui.module.js.map