lightview 2.0.9 → 2.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 (115) hide show
  1. package/build-bundles.mjs +105 -0
  2. package/build.js +236 -46
  3. package/components/actions/button.js +16 -3
  4. package/components/actions/swap.js +26 -3
  5. package/components/daisyui.js +1 -1
  6. package/components/data-display/alert.js +13 -3
  7. package/components/data-display/avatar.js +25 -1
  8. package/components/data-display/badge.js +11 -3
  9. package/components/data-display/chart.js +22 -5
  10. package/components/data-display/countdown.js +3 -2
  11. package/components/data-display/kbd.js +9 -3
  12. package/components/data-display/loading.js +11 -3
  13. package/components/data-display/progress.js +11 -3
  14. package/components/data-display/radial-progress.js +12 -3
  15. package/components/data-display/tooltip.js +17 -0
  16. package/components/data-input/checkbox.js +23 -1
  17. package/components/data-input/input.js +24 -1
  18. package/components/data-input/radio.js +37 -2
  19. package/components/data-input/select.js +24 -1
  20. package/components/data-input/toggle.js +21 -1
  21. package/components/layout/divider.js +21 -1
  22. package/components/layout/indicator.js +14 -0
  23. package/components/navigation/breadcrumbs.js +42 -2
  24. package/components/navigation/tabs.js +291 -16
  25. package/docs/api/elements.html +125 -49
  26. package/docs/api/hypermedia.html +29 -2
  27. package/docs/api/index.html +6 -2
  28. package/docs/api/nav.html +18 -4
  29. package/docs/assets/js/examplify.js +1 -1
  30. package/docs/cdom-nav.html +55 -0
  31. package/docs/cdom.html +792 -0
  32. package/docs/components/alert.html +8 -8
  33. package/docs/components/avatar.html +24 -54
  34. package/docs/components/badge.html +69 -14
  35. package/docs/components/breadcrumbs.html +95 -29
  36. package/docs/components/button.html +78 -92
  37. package/docs/components/chart-area.html +3 -3
  38. package/docs/components/chart-bar.html +4 -181
  39. package/docs/components/chart-column.html +4 -189
  40. package/docs/components/chart-line.html +3 -3
  41. package/docs/components/chart-pie.html +112 -166
  42. package/docs/components/chart.html +11 -13
  43. package/docs/components/checkbox.html +48 -28
  44. package/docs/components/collapse.html +6 -6
  45. package/docs/components/component-nav.html +1 -1
  46. package/docs/components/countdown.html +12 -12
  47. package/docs/components/divider.html +65 -21
  48. package/docs/components/dropdown.html +1 -1
  49. package/docs/components/file-input.html +4 -4
  50. package/docs/components/footer.html +11 -11
  51. package/docs/components/indicator.html +85 -31
  52. package/docs/components/input.html +45 -29
  53. package/docs/components/join.html +4 -4
  54. package/docs/components/kbd.html +67 -28
  55. package/docs/components/loading.html +96 -92
  56. package/docs/components/pagination.html +4 -4
  57. package/docs/components/progress.html +50 -7
  58. package/docs/components/radial-progress.html +32 -12
  59. package/docs/components/radio.html +42 -31
  60. package/docs/components/select.html +48 -59
  61. package/docs/components/swap.html +183 -100
  62. package/docs/components/tabs.html +146 -278
  63. package/docs/components/toggle.html +44 -25
  64. package/docs/components/tooltip.html +71 -31
  65. package/docs/getting-started/index.html +8 -6
  66. package/docs/index.html +1 -1
  67. package/docs/syntax-nav.html +10 -0
  68. package/docs/syntax.html +8 -6
  69. package/index.html +2 -2
  70. package/jprx/LICENSE +21 -0
  71. package/jprx/README.md +130 -0
  72. package/jprx/helpers/array.js +75 -0
  73. package/jprx/helpers/compare.js +26 -0
  74. package/jprx/helpers/conditional.js +34 -0
  75. package/jprx/helpers/datetime.js +54 -0
  76. package/jprx/helpers/format.js +20 -0
  77. package/jprx/helpers/logic.js +24 -0
  78. package/jprx/helpers/lookup.js +25 -0
  79. package/jprx/helpers/math.js +34 -0
  80. package/jprx/helpers/network.js +41 -0
  81. package/jprx/helpers/state.js +80 -0
  82. package/jprx/helpers/stats.js +39 -0
  83. package/jprx/helpers/string.js +49 -0
  84. package/jprx/index.js +69 -0
  85. package/jprx/package.json +24 -0
  86. package/jprx/parser.js +1517 -0
  87. package/lightview-all.js +3785 -0
  88. package/lightview-cdom.js +2128 -0
  89. package/lightview-router.js +179 -208
  90. package/lightview-x.js +1435 -1608
  91. package/lightview.js +613 -766
  92. package/lightview.js.bak +1 -0
  93. package/package.json +10 -3
  94. package/src/lightview-all.js +10 -0
  95. package/src/lightview-cdom.js +457 -0
  96. package/src/lightview-router.js +210 -0
  97. package/src/lightview-x.js +1630 -0
  98. package/src/lightview.js +705 -0
  99. package/src/reactivity/signal.js +133 -0
  100. package/src/reactivity/state.js +217 -0
  101. package/{watch.js → start-dev.js} +2 -1
  102. package/tests/cdom/fixtures/helpers.cdomc +62 -0
  103. package/tests/cdom/fixtures/user.cdom +14 -0
  104. package/tests/cdom/fixtures/user.cdomc +12 -0
  105. package/tests/cdom/fixtures/user.odom +18 -0
  106. package/tests/cdom/fixtures/user.vdom +11 -0
  107. package/tests/cdom/helpers.test.js +121 -0
  108. package/tests/cdom/loader.test.js +125 -0
  109. package/tests/cdom/parser.test.js +179 -0
  110. package/tests/cdom/reactivity.test.js +186 -0
  111. package/tests/text-tag.test.js +77 -0
  112. package/vite.config.mjs +52 -0
  113. package/wrangler.toml +0 -3
  114. package/components/data-display/skeleton.js +0 -66
  115. package/docs/components/skeleton.html +0 -447
@@ -0,0 +1,105 @@
1
+ import { build } from 'vite';
2
+ import { resolve } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { copyFileSync, rmSync, existsSync } from 'fs';
5
+
6
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
7
+ const isWatch = process.argv.includes('--watch');
8
+
9
+ const builds = [
10
+ { entry: 'src/lightview.js', name: 'lightview', globalName: 'Lightview' },
11
+ { entry: 'src/lightview-x.js', name: 'lightview-x', globalName: 'LightviewX' },
12
+ { entry: 'src/lightview-cdom.js', name: 'lightview-cdom', globalName: 'LightviewCDOM' },
13
+ { entry: 'src/lightview-router.js', name: 'lightview-router', globalName: 'LightviewRouter' },
14
+ { entry: 'src/lightview-all.js', name: 'lightview-all', globalName: 'LightviewAll' }
15
+ ];
16
+
17
+ let building = false;
18
+ let queued = false;
19
+
20
+ async function runBuilds() {
21
+ if (building) {
22
+ queued = true;
23
+ return;
24
+ }
25
+ building = true;
26
+
27
+ console.log(isWatch ? 'Change detected. Rebuilding bundled files...' : 'Building bundles...');
28
+
29
+ try {
30
+ for (const b of builds) {
31
+ // console.log(`Building ${b.name}...`);
32
+ await build({
33
+ configFile: false,
34
+ logLevel: 'silent', // Reduce noise
35
+ build: {
36
+ lib: {
37
+ entry: resolve(__dirname, b.entry),
38
+ name: b.globalName,
39
+ formats: ['iife'],
40
+ fileName: () => `${b.name}.js`
41
+ },
42
+ outDir: 'build_tmp',
43
+ // Don't clean here, clean manually
44
+ emptyOutDir: false,
45
+ rollupOptions: {
46
+ external: (id) => id.includes('/components/') || id.includes('/docs/')
47
+ },
48
+ minify: false // No minification for easier debugging
49
+ }
50
+ });
51
+ }
52
+
53
+ // Copy files
54
+ for (const b of builds) {
55
+ try {
56
+ const src = resolve(__dirname, `build_tmp/${b.name}.js`);
57
+ const dest = resolve(__dirname, `${b.name}.js`);
58
+ if (existsSync(src)) {
59
+ copyFileSync(src, dest);
60
+ console.log(`Updated ${b.name}.js`);
61
+ } else {
62
+ console.error(`Missing built file: ${src}`);
63
+ }
64
+ } catch (e) {
65
+ console.error(`Failed to copy ${b.name}.js`, e);
66
+ }
67
+ }
68
+
69
+ // Cleanup
70
+ if (existsSync(resolve(__dirname, 'build_tmp'))) {
71
+ rmSync(resolve(__dirname, 'build_tmp'), { recursive: true, force: true });
72
+ }
73
+ } catch (e) {
74
+ console.error('Build error:', e);
75
+ }
76
+
77
+ building = false;
78
+ if (queued) {
79
+ queued = false;
80
+ runBuilds();
81
+ } else {
82
+ if (isWatch) console.log('Waiting for changes...');
83
+ }
84
+ }
85
+
86
+ // Initial run
87
+ runBuilds();
88
+
89
+ if (isWatch) {
90
+ console.log('Watching src/ for changes...');
91
+ // Dynamic import to avoid errors if run in environment without fs (unlikely here but good practice)
92
+ const { watch } = await import('fs');
93
+ let debounceTimer;
94
+
95
+ // Watch src directory
96
+ // Note: recursive option for Linux requires Node 20+, Windows/macOS supported earlier.
97
+ watch(resolve(__dirname, 'src'), { recursive: true }, (event, filename) => {
98
+ if (filename && !filename.includes('~')) {
99
+ clearTimeout(debounceTimer);
100
+ debounceTimer = setTimeout(() => {
101
+ runBuilds();
102
+ }, 300); // 300ms debounce
103
+ }
104
+ });
105
+ }
package/build.js CHANGED
@@ -1,70 +1,260 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
+ const { minify } = require('terser');
4
+
5
+ // Parse command line arguments
6
+ const args = process.argv.slice(2);
7
+ const envArg = args.find(arg => arg.startsWith('--env='));
8
+ const env = envArg ? envArg.split('=')[1] : 'prod';
9
+
10
+ // Validate env
11
+ const validEnvs = ['prod', 'test', 'dev'];
12
+ if (!validEnvs.includes(env)) {
13
+ console.error(`Invalid env "${env}". Allowed values: ${validEnvs.join(', ')}`);
14
+ process.exit(1);
15
+ }
16
+
17
+ const shouldMinify = env === 'prod';
3
18
 
4
19
  const rootDir = __dirname;
5
20
  const distDir = path.join(rootDir, 'dist');
6
21
  const docsDir = path.join(rootDir, 'docs');
7
22
  const componentsDir = path.join(rootDir, 'components');
8
23
  const middlewareDir = path.join(rootDir, 'middleware');
24
+ const jprxDir = path.join(rootDir, 'jprx');
9
25
 
10
26
  // Configuration
11
27
  // Files in root that should be copied
12
28
  const allowedExtensions = ['.html', '.js', '.css', '.txt', '.xml', '.ico', '.png', '.svg', '.jpg', '.jpeg', '.md'];
13
29
  const includeFiles = ['_headers']; // specific files to always include
14
- const excludeFiles = ['build.js', 'package.json', 'package-lock.json', 'wrangler.toml'];
30
+ const excludeFiles = ['build.js', 'build-bundles.mjs', 'package.json', 'package-lock.json', 'wrangler.toml'];
15
31
 
16
- console.log('Building for deployment...');
32
+ /**
33
+ * Minify a JavaScript file using terser
34
+ * @param {string} code - The JavaScript source code
35
+ * @returns {Promise<string>} - The minified code
36
+ */
37
+ async function minifyJS(code) {
38
+ if (!shouldMinify) {
39
+ return code; // Skip minification in dev mode
40
+ }
41
+ try {
42
+ const result = await minify(code, {
43
+ module: true, // Handle ES6 module syntax
44
+ compress: {
45
+ drop_console: false
46
+ },
47
+ mangle: {
48
+ reserved: ['examplify', 'examplifyIdCounter'] // Preserve global function names called from HTML
49
+ }
50
+ });
51
+ return result.code;
52
+ } catch (e) {
53
+ console.error('Minification error:', e);
54
+ return code; // Return original on error
55
+ }
56
+ }
17
57
 
18
- // 1. Clean/Create dist
19
- if (fs.existsSync(distDir)) {
20
- fs.rmSync(distDir, { recursive: true, force: true });
58
+ /**
59
+ * Copy a file, minifying if it's a JS file (and minification is enabled)
60
+ * @param {string} srcPath - Source file path
61
+ * @param {string} destPath - Destination file path
62
+ */
63
+ async function copyFile(srcPath, destPath) {
64
+ const ext = path.extname(srcPath).toLowerCase();
65
+
66
+ if (ext === '.js' && shouldMinify) {
67
+ // Read, minify, and write JS files
68
+ const code = fs.readFileSync(srcPath, 'utf8');
69
+ const minified = await minifyJS(code);
70
+ fs.writeFileSync(destPath, minified);
71
+ } else {
72
+ // Copy other files directly
73
+ fs.copyFileSync(srcPath, destPath);
74
+ }
21
75
  }
22
- fs.mkdirSync(distDir);
23
- console.log('Created dist directory.');
24
-
25
- // 2. Copy Root Files
26
- const files = fs.readdirSync(rootDir);
27
- files.forEach(file => {
28
- const srcPath = path.join(rootDir, file);
29
- const stat = fs.statSync(srcPath);
30
-
31
- if (stat.isFile()) {
32
- const ext = path.extname(file).toLowerCase();
33
-
34
- // Check if file should be copied
35
- const isAllowedExt = allowedExtensions.includes(ext);
36
- const isExplicitInclude = includeFiles.includes(file);
37
- const isExcluded = excludeFiles.includes(file) || file.startsWith('.');
38
-
39
- if ((isAllowedExt || isExplicitInclude) && !isExcluded) {
40
- fs.copyFileSync(srcPath, path.join(distDir, file));
41
- console.log(`Copied: ${file}`);
42
- }
76
+
77
+ /**
78
+ * Recursively copy a directory, minifying JS files if enabled
79
+ * @param {string} srcDir - Source directory
80
+ * @param {string} destDir - Destination directory
81
+ */
82
+ async function copyDirWithMinify(srcDir, destDir) {
83
+ if (!fs.existsSync(destDir)) {
84
+ fs.mkdirSync(destDir, { recursive: true });
43
85
  }
44
- });
45
86
 
46
- // 3. Copy Docs Directory
47
- if (fs.existsSync(docsDir)) {
48
- fs.cpSync(docsDir, path.join(distDir, 'docs'), { recursive: true });
49
- console.log('Copied: docs directory');
50
- } else {
51
- console.warn('Warning: docs directory not found.');
87
+ const entries = fs.readdirSync(srcDir, { withFileTypes: true });
88
+
89
+ for (const entry of entries) {
90
+ const srcPath = path.join(srcDir, entry.name);
91
+ const destPath = path.join(destDir, entry.name);
92
+
93
+ if (entry.isDirectory()) {
94
+ await copyDirWithMinify(srcPath, destPath);
95
+ } else {
96
+ await copyFile(srcPath, destPath);
97
+ }
98
+ }
52
99
  }
53
100
 
54
- // 4. Copy Components Directory
55
- if (fs.existsSync(componentsDir)) {
56
- fs.cpSync(componentsDir, path.join(distDir, 'components'), { recursive: true });
57
- console.log('Copied: components directory');
58
- } else {
59
- console.warn('Warning: components directory not found.');
101
+ async function build() {
102
+ console.log(`Building for deployment (env: ${env}, minify: ${shouldMinify})...`);
103
+
104
+ // 1. Clean/Create dist - continue even if deletion fails (e.g., file locks on Windows)
105
+ if (fs.existsSync(distDir)) {
106
+ try {
107
+ fs.rmSync(distDir, { recursive: true, force: true });
108
+ console.log('Cleaned dist directory.');
109
+ } catch (e) {
110
+ console.warn('Warning: Could not delete dist directory (files may be locked). Overwriting files instead.');
111
+ }
112
+ }
113
+
114
+ if (!fs.existsSync(distDir)) {
115
+ fs.mkdirSync(distDir);
116
+ console.log('Created dist directory.');
117
+ }
118
+
119
+ // 2. Copy Root Files (with minification for JS if enabled)
120
+ const files = fs.readdirSync(rootDir);
121
+ for (const file of files) {
122
+ const srcPath = path.join(rootDir, file);
123
+ const stat = fs.statSync(srcPath);
124
+
125
+ if (stat.isFile()) {
126
+ const ext = path.extname(file).toLowerCase();
127
+
128
+ // Check if file should be copied
129
+ const isAllowedExt = allowedExtensions.includes(ext);
130
+ const isExplicitInclude = includeFiles.includes(file);
131
+ const isExcluded = excludeFiles.includes(file) || file.startsWith('.');
132
+
133
+ if ((isAllowedExt || isExplicitInclude) && !isExcluded) {
134
+ await copyFile(srcPath, path.join(distDir, file));
135
+ const suffix = ext === '.js' && shouldMinify ? ' (minified)' : '';
136
+ console.log(`Copied: ${file}${suffix}`);
137
+ }
138
+ }
139
+ }
140
+
141
+ // 3. Copy Docs Directory
142
+ if (fs.existsSync(docsDir)) {
143
+ await copyDirWithMinify(docsDir, path.join(distDir, 'docs'));
144
+ console.log(`Copied: docs directory${shouldMinify ? ' (JS files minified)' : ''}`);
145
+ } else {
146
+ console.warn('Warning: docs directory not found.');
147
+ }
148
+
149
+ // 4. Copy Components Directory
150
+ if (fs.existsSync(componentsDir)) {
151
+ await copyDirWithMinify(componentsDir, path.join(distDir, 'components'));
152
+ console.log(`Copied: components directory${shouldMinify ? ' (JS files minified)' : ''}`);
153
+ } else {
154
+ console.warn('Warning: components directory not found.');
155
+ }
156
+
157
+ // 5. Copy Middleware Directory
158
+ if (fs.existsSync(middlewareDir)) {
159
+ await copyDirWithMinify(middlewareDir, path.join(distDir, 'middleware'));
160
+ console.log(`Copied: middleware directory${shouldMinify ? ' (JS files minified)' : ''}`);
161
+ } else {
162
+ console.warn('Warning: middleware directory not found.');
163
+ }
164
+
165
+
166
+
167
+ // 7. Copy JPRX Directory
168
+ if (fs.existsSync(jprxDir)) {
169
+ await copyDirWithMinify(jprxDir, path.join(distDir, 'jprx'));
170
+ console.log(`Copied: jprx directory${shouldMinify ? ' (JS files minified)' : ''}`);
171
+ } else {
172
+ console.warn('Warning: jprx directory not found.');
173
+ }
174
+
175
+ console.log('Build complete! Assets are ready in ./dist');
60
176
  }
61
177
 
62
- // 5. Copy Middleware Directory
63
- if (fs.existsSync(middlewareDir)) {
64
- fs.cpSync(middlewareDir, path.join(distDir, 'middleware'), { recursive: true });
65
- console.log('Copied: middleware directory');
178
+ // Check for --watch flag
179
+ const isWatch = args.includes('--watch');
180
+
181
+ if (isWatch) {
182
+ // Watch mode
183
+ const { watch } = require('fs');
184
+ const { execSync } = require('child_process');
185
+ let debounceTimer;
186
+ let building = false;
187
+ let queued = false;
188
+ let needsBundleRebuild = false;
189
+
190
+ const runBuildBundles = () => {
191
+ console.log('Rebuilding bundles...');
192
+ try {
193
+ execSync('node build-bundles.mjs', { cwd: rootDir, stdio: 'inherit' });
194
+ console.log('Bundles rebuilt successfully.');
195
+ } catch (e) {
196
+ console.error('Bundle rebuild failed:', e.message);
197
+ }
198
+ };
199
+
200
+ const runBuild = async () => {
201
+ if (building) {
202
+ queued = true;
203
+ return;
204
+ }
205
+ building = true;
206
+ try {
207
+ if (needsBundleRebuild) {
208
+ runBuildBundles();
209
+ needsBundleRebuild = false;
210
+ }
211
+ await build();
212
+ } catch (e) {
213
+ console.error('Build failed:', e);
214
+ }
215
+ building = false;
216
+ if (queued) {
217
+ queued = false;
218
+ runBuild();
219
+ }
220
+ };
221
+
222
+ const watchDir = (dir, name, triggersBundleRebuild = false) => {
223
+ if (fs.existsSync(dir)) {
224
+ watch(dir, { recursive: true }, (event, filename) => {
225
+ if (filename && !filename.includes('~') && !filename.includes('.git')) {
226
+ clearTimeout(debounceTimer);
227
+ if (triggersBundleRebuild) {
228
+ needsBundleRebuild = true;
229
+ }
230
+ debounceTimer = setTimeout(() => {
231
+ console.log(`\nChange detected in ${name}: ${filename}`);
232
+ runBuild();
233
+ }, 300);
234
+ }
235
+ });
236
+ console.log(`Watching: ${name}${triggersBundleRebuild ? ' (triggers bundle rebuild)' : ''}`);
237
+ }
238
+ };
239
+
240
+ console.log('Starting watch mode...\n');
241
+
242
+ // Initial build (bundles already built by npm script)
243
+ runBuild().then(() => {
244
+ // Watch all relevant directories
245
+ // src/ and jprx/ trigger bundle rebuilds
246
+ watchDir(path.join(rootDir, 'src'), 'src/', true);
247
+ watchDir(jprxDir, 'jprx/', true);
248
+ // Other directories just get copied
249
+ watchDir(docsDir, 'docs/');
250
+ watchDir(componentsDir, 'components/');
251
+ watchDir(middlewareDir, 'middleware/');
252
+ console.log('\nWaiting for changes...');
253
+ });
66
254
  } else {
67
- console.warn('Warning: middleware directory not found.');
255
+ // Single build
256
+ build().catch(e => {
257
+ console.error('Build failed:', e);
258
+ process.exit(1);
259
+ });
68
260
  }
69
-
70
- console.log('Build complete! Assets are ready in ./dist');
@@ -139,9 +139,22 @@ const Button = (props = {}, ...children) => {
139
139
 
140
140
  globalThis.Lightview.tags.Button = Button;
141
141
 
142
- // Register as Custom Element
143
- if (globalThis.LightviewX?.createCustomElement) {
144
- const ButtonElement = globalThis.LightviewX.createCustomElement(Button);
142
+ // Register as Custom Element using customElementWrapper
143
+ if (globalThis.LightviewX && typeof customElements !== 'undefined') {
144
+ const ButtonElement = globalThis.LightviewX.customElementWrapper(Button, {
145
+ attributeMap: {
146
+ color: String,
147
+ size: String,
148
+ variant: String,
149
+ disabled: Boolean,
150
+ loading: Boolean,
151
+ active: Boolean,
152
+ glass: Boolean,
153
+ noAnimation: Boolean
154
+ },
155
+ childElements: {} // No child components for Button, uses slot
156
+ });
157
+
145
158
  if (!customElements.get('lv-button')) {
146
159
  customElements.define('lv-button', ButtonElement);
147
160
  }
@@ -34,8 +34,9 @@ const Swap = (props = {}, ...children) => {
34
34
  else if (effect === 'flip') classes.push('swap-flip');
35
35
  if (className) classes.push(className);
36
36
 
37
- // Handle reactive active state
38
- const isActive = typeof active === 'function' ? active : () => active;
37
+ // Handle internal state for non-reactive/uncontrolled usage
38
+ const internalActive = signal(active);
39
+ const isActive = typeof active === 'function' ? active : () => internalActive.value;
39
40
 
40
41
  const swapEl = label({
41
42
  class: () => {
@@ -49,7 +50,11 @@ const Swap = (props = {}, ...children) => {
49
50
  type: 'checkbox',
50
51
  checked: isActive,
51
52
  onchange: (e) => {
52
- if (onChange) onChange(e.target.checked);
53
+ const checked = e.target.checked;
54
+ if (typeof active !== 'function') {
55
+ internalActive.value = checked;
56
+ }
57
+ if (onChange) onChange(checked);
53
58
  }
54
59
  }),
55
60
  ...children
@@ -115,4 +120,22 @@ tags.Swap = Swap;
115
120
  tags['Swap.On'] = Swap.On;
116
121
  tags['Swap.Off'] = Swap.Off;
117
122
 
123
+ // Register as Custom Element using customElementWrapper
124
+ if (globalThis.LightviewX && typeof customElements !== 'undefined') {
125
+ const SwapElement = globalThis.LightviewX.customElementWrapper(Swap, {
126
+ attributeMap: {
127
+ active: Boolean,
128
+ effect: String
129
+ },
130
+ childElements: {
131
+ 'on': Swap.On,
132
+ 'off': Swap.Off
133
+ }
134
+ });
135
+
136
+ if (!customElements.get('lv-swap')) {
137
+ customElements.define('lv-swap', SwapElement);
138
+ }
139
+ }
140
+
118
141
  export default Swap;
@@ -3,7 +3,7 @@
3
3
  * This module ensures DaisyUI CSS is loaded and provides utilities for components
4
4
  */
5
5
 
6
- const DAISYUI_CDN = 'https://cdn.jsdelivr.net/npm/daisyui@4.12.10/dist/full.min.css';
6
+ const DAISYUI_CDN = 'https://cdn.jsdelivr.net/npm/daisyui@5.5.14/daisyui.min.css';
7
7
  const TAILWIND_CDN = 'https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4';
8
8
 
9
9
  let daisyLoaded = false;
@@ -101,9 +101,19 @@ function getAlertIcon(type) {
101
101
 
102
102
  globalThis.Lightview.tags.Alert = Alert;
103
103
 
104
- // Register as Custom Element
105
- if (globalThis.LightviewX?.createCustomElement) {
106
- const AlertElement = globalThis.LightviewX.createCustomElement(Alert);
104
+ // Register as Custom Element using customElementWrapper
105
+ if (globalThis.LightviewX && typeof customElements !== 'undefined') {
106
+ const AlertElement = globalThis.LightviewX.customElementWrapper(Alert, {
107
+ attributeMap: {
108
+ color: String,
109
+ soft: Boolean,
110
+ dash: Boolean,
111
+ outline: Boolean,
112
+ icon: String
113
+ },
114
+ childElements: {} // No child components for Alert
115
+ });
116
+
107
117
  if (!customElements.get('lv-alert')) {
108
118
  customElements.define('lv-alert', AlertElement);
109
119
  }
@@ -158,7 +158,31 @@ tags.Avatar = Avatar;
158
158
  tags['Avatar.Group'] = Avatar.Group;
159
159
 
160
160
  // Register as Custom Elements
161
- if (globalThis.LightviewX?.createCustomElement) {
161
+ if (globalThis.LightviewX?.customElementWrapper) {
162
+ if (!customElements.get('lv-avatar')) {
163
+ customElements.define('lv-avatar', globalThis.LightviewX.customElementWrapper(Avatar, {
164
+ attributeMap: {
165
+ src: String,
166
+ alt: String,
167
+ placeholder: String,
168
+ size: String,
169
+ shape: String,
170
+ ring: Boolean,
171
+ ringColor: String,
172
+ online: Boolean,
173
+ offline: Boolean,
174
+ class: String
175
+ }
176
+ }));
177
+ }
178
+ if (!customElements.get('lv-avatar-group')) {
179
+ customElements.define('lv-avatar-group', globalThis.LightviewX.customElementWrapper(Avatar.Group, {
180
+ attributeMap: {
181
+ class: String
182
+ }
183
+ }));
184
+ }
185
+ } else if (globalThis.LightviewX?.createCustomElement) {
162
186
  if (!customElements.get('lv-avatar')) {
163
187
  customElements.define('lv-avatar', globalThis.LightviewX.createCustomElement(Avatar));
164
188
  }
@@ -71,9 +71,17 @@ const Badge = (props = {}, ...children) => {
71
71
 
72
72
  globalThis.Lightview.tags.Badge = Badge;
73
73
 
74
- // Register as Custom Element
75
- if (globalThis.LightviewX?.createCustomElement) {
76
- const BadgeElement = globalThis.LightviewX.createCustomElement(Badge);
74
+ // Register as Custom Element using customElementWrapper
75
+ if (globalThis.LightviewX && typeof customElements !== 'undefined') {
76
+ const BadgeElement = globalThis.LightviewX.customElementWrapper(Badge, {
77
+ attributeMap: {
78
+ color: String,
79
+ size: String,
80
+ variant: String
81
+ },
82
+ childElements: {} // No child components for Badge, uses slot
83
+ });
84
+
77
85
  if (!customElements.get('lv-badge')) {
78
86
  customElements.define('lv-badge', BadgeElement);
79
87
  }
@@ -24,9 +24,22 @@ import '../daisyui.js';
24
24
  */
25
25
  const CHARTS_CSS_URL = 'https://cdn.jsdelivr.net/npm/charts.css/dist/charts.min.css';
26
26
 
27
+ // Register stylesheet for Shadow DOM usage (Adopted StyleSheets)
28
+ // Using top-level await in module to ensure it's loaded before any component renders
29
+ if (globalThis.LightviewX?.registerStyleSheet) {
30
+ await LightviewX.registerStyleSheet(CHARTS_CSS_URL);
31
+ }
32
+
27
33
  // Auto-load charts.css for Global/Light DOM usage
28
34
  if (typeof document !== 'undefined') {
29
- if (!document.querySelector(`link[href^="https://cdn.jsdelivr.net/npm/charts.css"]`)) {
35
+ if (!document.querySelector(`link[href^="${CHARTS_CSS_URL}"]`)) {
36
+ // Preload for better performance
37
+ const preload = document.createElement('link');
38
+ preload.rel = 'preload';
39
+ preload.as = 'style';
40
+ preload.href = CHARTS_CSS_URL;
41
+ document.head.appendChild(preload);
42
+
30
43
  const link = document.createElement('link');
31
44
  link.rel = 'stylesheet';
32
45
  link.href = CHARTS_CSS_URL;
@@ -48,8 +61,8 @@ const Chart = (props = {}, ...children) => {
48
61
  labels = false,
49
62
  dataOnHover = false,
50
63
  primaryAxis = false,
64
+ secondaryAxesCount,
51
65
  secondaryAxis = false,
52
- spacing,
53
66
  reverse = false,
54
67
  multiple = false,
55
68
  stacked = false,
@@ -65,10 +78,14 @@ const Chart = (props = {}, ...children) => {
65
78
  if (heading) classes.push('show-heading');
66
79
  if (primaryAxis) classes.push('show-primary-axis');
67
80
 
68
- if (secondaryAxis === true) classes.push('show-10-secondary-axes');
69
- else if (typeof secondaryAxis === 'string') classes.push(secondaryAxis);
81
+ if (secondaryAxesCount) {
82
+ classes.push(`show-${secondaryAxesCount}-secondary-axes`);
83
+ } else if (secondaryAxis === true) {
84
+ classes.push('show-10-secondary-axes');
85
+ } else if (typeof secondaryAxis === 'string') {
86
+ classes.push(secondaryAxis);
87
+ }
70
88
 
71
- if (spacing) classes.push(`data-spacing-${spacing}`);
72
89
  if (reverse) classes.push('reverse');
73
90
  if (multiple) classes.push('multiple');
74
91
  if (stacked) classes.push('stacked');
@@ -30,12 +30,13 @@ const Countdown = (props = {}, ...children) => {
30
30
 
31
31
  const countdownEl = span({
32
32
  class: `countdown ${className}`.trim(),
33
+ style: 'line-height: 1.2em; height: 1.2em; vertical-align: middle;',
33
34
  ...rest
34
35
  },
35
36
  span({
36
37
  style: typeof value === 'function'
37
- ? () => `--value:${getValue()};`
38
- : `--value:${value};`
38
+ ? () => `--value:${getValue()}; height: 1.2em;`
39
+ : `--value:${value}; height: 1.2em;`
39
40
  })
40
41
  );
41
42
 
@@ -54,9 +54,15 @@ const Kbd = (props = {}, ...children) => {
54
54
 
55
55
  globalThis.Lightview.tags.Kbd = Kbd;
56
56
 
57
- // Register as Custom Element
58
- if (globalThis.LightviewX?.createCustomElement) {
59
- const KbdElement = globalThis.LightviewX.createCustomElement(Kbd);
57
+ // Register as Custom Element using customElementWrapper
58
+ if (globalThis.LightviewX && typeof customElements !== 'undefined') {
59
+ const KbdElement = globalThis.LightviewX.customElementWrapper(Kbd, {
60
+ attributeMap: {
61
+ size: String
62
+ },
63
+ childElements: {} // No child components, uses slot for key text
64
+ });
65
+
60
66
  if (!customElements.get('lv-kbd')) {
61
67
  customElements.define('lv-kbd', KbdElement);
62
68
  }