juxscript 1.0.19 → 1.0.21

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 (77) hide show
  1. package/bin/cli.js +121 -72
  2. package/lib/components/alert.ts +212 -165
  3. package/lib/components/badge.ts +93 -103
  4. package/lib/components/base/BaseComponent.ts +397 -0
  5. package/lib/components/base/FormInput.ts +322 -0
  6. package/lib/components/button.ts +63 -122
  7. package/lib/components/card.ts +109 -155
  8. package/lib/components/charts/areachart.ts +315 -0
  9. package/lib/components/charts/barchart.ts +421 -0
  10. package/lib/components/charts/doughnutchart.ts +263 -0
  11. package/lib/components/charts/lib/BaseChart.ts +402 -0
  12. package/lib/components/charts/lib/chart-types.ts +159 -0
  13. package/lib/components/charts/lib/chart-utils.ts +160 -0
  14. package/lib/components/charts/lib/chart.ts +707 -0
  15. package/lib/components/checkbox.ts +264 -127
  16. package/lib/components/code.ts +75 -108
  17. package/lib/components/container.ts +113 -130
  18. package/lib/components/data.ts +37 -5
  19. package/lib/components/datepicker.ts +195 -147
  20. package/lib/components/dialog.ts +187 -157
  21. package/lib/components/divider.ts +85 -191
  22. package/lib/components/docs-data.json +544 -2027
  23. package/lib/components/dropdown.ts +178 -136
  24. package/lib/components/element.ts +227 -171
  25. package/lib/components/fileupload.ts +285 -228
  26. package/lib/components/guard.ts +92 -0
  27. package/lib/components/heading.ts +46 -69
  28. package/lib/components/helpers.ts +13 -6
  29. package/lib/components/hero.ts +107 -95
  30. package/lib/components/icon.ts +160 -0
  31. package/lib/components/icons.ts +175 -0
  32. package/lib/components/include.ts +153 -5
  33. package/lib/components/input.ts +174 -374
  34. package/lib/components/kpicard.ts +16 -16
  35. package/lib/components/list.ts +378 -240
  36. package/lib/components/loading.ts +142 -211
  37. package/lib/components/menu.ts +103 -97
  38. package/lib/components/modal.ts +138 -144
  39. package/lib/components/nav.ts +169 -90
  40. package/lib/components/paragraph.ts +49 -150
  41. package/lib/components/progress.ts +118 -200
  42. package/lib/components/radio.ts +297 -149
  43. package/lib/components/script.ts +19 -87
  44. package/lib/components/select.ts +184 -186
  45. package/lib/components/sidebar.ts +152 -140
  46. package/lib/components/style.ts +19 -82
  47. package/lib/components/switch.ts +258 -188
  48. package/lib/components/table.ts +1117 -170
  49. package/lib/components/tabs.ts +162 -145
  50. package/lib/components/theme-toggle.ts +108 -169
  51. package/lib/components/tooltip.ts +86 -157
  52. package/lib/components/write.ts +108 -127
  53. package/lib/jux.ts +86 -41
  54. package/machinery/build.js +466 -0
  55. package/machinery/compiler.js +354 -105
  56. package/machinery/server.js +23 -100
  57. package/machinery/watcher.js +153 -130
  58. package/package.json +1 -2
  59. package/presets/base.css +1166 -0
  60. package/presets/notion.css +2 -1975
  61. package/lib/adapters/base-adapter.js +0 -35
  62. package/lib/adapters/index.js +0 -33
  63. package/lib/adapters/mysql-adapter.js +0 -65
  64. package/lib/adapters/postgres-adapter.js +0 -70
  65. package/lib/adapters/sqlite-adapter.js +0 -56
  66. package/lib/components/areachart.ts +0 -1246
  67. package/lib/components/areachartsmooth.ts +0 -1380
  68. package/lib/components/barchart.ts +0 -1250
  69. package/lib/components/chart.ts +0 -127
  70. package/lib/components/doughnutchart.ts +0 -1191
  71. package/lib/components/footer.ts +0 -165
  72. package/lib/components/header.ts +0 -187
  73. package/lib/components/layout.ts +0 -239
  74. package/lib/components/main.ts +0 -137
  75. package/lib/layouts/default.jux +0 -8
  76. package/lib/layouts/figma.jux +0 -0
  77. /package/lib/{themes → components/charts/lib}/charts.js +0 -0
@@ -1,165 +0,0 @@
1
- import { getOrCreateContainer } from './helpers.js';
2
-
3
- /**
4
- * Footer component options
5
- */
6
- export interface FooterOptions {
7
- content?: string;
8
- copyright?: string;
9
- links?: Array<{ label: string; href: string }>;
10
- class?: string;
11
- style?: string;
12
- }
13
-
14
- /**
15
- * Footer component state
16
- */
17
- type FooterState = {
18
- content: string;
19
- copyright: string;
20
- links: Array<{ label: string; href: string }>;
21
- class: string;
22
- style: string;
23
- };
24
-
25
- /**
26
- * Footer component
27
- *
28
- * Usage:
29
- * const footer = jux.footer('myFooter', {
30
- * copyright: '© 2025 My Company',
31
- * links: [
32
- * { label: 'Privacy', href: '/privacy' },
33
- * { label: 'Terms', href: '/terms' }
34
- * ]
35
- * });
36
- * footer.render('#appfooter');
37
- */
38
- export class Footer {
39
- state: FooterState;
40
- container: HTMLElement | null = null;
41
- _id: string;
42
- id: string;
43
-
44
- constructor(id: string, options: FooterOptions = {}) {
45
- this._id = id;
46
- this.id = id;
47
-
48
- this.state = {
49
- content: options.content ?? '',
50
- copyright: options.copyright ?? '',
51
- links: options.links ?? [],
52
- class: options.class ?? '',
53
- style: options.style ?? ''
54
- };
55
- }
56
-
57
- /* -------------------------
58
- * Fluent API
59
- * ------------------------- */
60
-
61
- content(value: string): this {
62
- this.state.content = value;
63
- return this;
64
- }
65
-
66
- copyright(value: string): this {
67
- this.state.copyright = value;
68
- return this;
69
- }
70
-
71
- links(value: Array<{ label: string; href: string }>): this {
72
- this.state.links = value;
73
- return this;
74
- }
75
-
76
- class(value: string): this {
77
- this.state.class = value;
78
- return this;
79
- }
80
-
81
- style(value: string): this {
82
- this.state.style = value;
83
- return this;
84
- }
85
-
86
- /* -------------------------
87
- * Render
88
- * ------------------------- */
89
-
90
- render(targetId?: string): this {
91
- let container: HTMLElement;
92
-
93
- if (targetId) {
94
- const target = document.querySelector(targetId);
95
- if (!target || !(target instanceof HTMLElement)) {
96
- throw new Error(`Footer: Target element "${targetId}" not found`);
97
- }
98
- container = target;
99
- } else {
100
- container = getOrCreateContainer(this._id);
101
- }
102
-
103
- this.container = container;
104
- const { content, copyright, links, class: className, style } = this.state;
105
-
106
- const footer = document.createElement('footer');
107
- footer.className = `jux-footer ${className}`.trim();
108
- footer.style.cssText = style;
109
- footer.id = this._id;
110
-
111
- if (content) {
112
- const contentEl = document.createElement('div');
113
- contentEl.className = 'jux-footer-content';
114
- contentEl.textContent = content;
115
- footer.appendChild(contentEl);
116
- }
117
-
118
- if (links.length > 0) {
119
- const linksEl = document.createElement('div');
120
- linksEl.className = 'jux-footer-links';
121
-
122
- links.forEach(link => {
123
- const linkEl = document.createElement('a');
124
- linkEl.className = 'jux-footer-link';
125
- linkEl.href = link.href;
126
- linkEl.textContent = link.label;
127
- linksEl.appendChild(linkEl);
128
- });
129
-
130
- footer.appendChild(linksEl);
131
- }
132
-
133
- if (copyright) {
134
- const copyrightEl = document.createElement('div');
135
- copyrightEl.className = 'jux-footer-copyright';
136
- copyrightEl.textContent = copyright;
137
- footer.appendChild(copyrightEl);
138
- }
139
-
140
- container.appendChild(footer);
141
- return this;
142
- }
143
-
144
- /**
145
- * Render to another Jux component's container
146
- */
147
- renderTo(juxComponent: any): this {
148
- if (!juxComponent || typeof juxComponent !== 'object') {
149
- throw new Error('Footer.renderTo: Invalid component - not an object');
150
- }
151
-
152
- if (!juxComponent._id || typeof juxComponent._id !== 'string') {
153
- throw new Error('Footer.renderTo: Invalid component - missing _id (not a Jux component)');
154
- }
155
-
156
- return this.render(`#${juxComponent._id}`);
157
- }
158
- }
159
-
160
- /**
161
- * Factory helper
162
- */
163
- export function footer(id: string, options: FooterOptions = {}): Footer {
164
- return new Footer(id, options);
165
- }
@@ -1,187 +0,0 @@
1
- import { getOrCreateContainer } from './helpers.js';
2
-
3
- /**
4
- * Header component options
5
- */
6
- export interface HeaderOptions {
7
- title?: string;
8
- logo?: string;
9
- navigation?: Array<{ label: string; href: string }>;
10
- sticky?: boolean;
11
- style?: string;
12
- class?: string;
13
- }
14
-
15
- /**
16
- * Header component state
17
- */
18
- type HeaderState = {
19
- title: string;
20
- logo: string;
21
- navigation: Array<{ label: string; href: string }>;
22
- sticky: boolean;
23
- style: string;
24
- class: string;
25
- };
26
-
27
- /**
28
- * Header component
29
- *
30
- * Usage:
31
- * const header = jux.header('myHeader', {
32
- * title: 'My App',
33
- * navigation: [
34
- * { label: 'Home', href: '/' },
35
- * { label: 'About', href: '/about' }
36
- * ]
37
- * });
38
- * header.render('#appheader');
39
- */
40
- export class Header {
41
- state: HeaderState;
42
- container: HTMLElement | null = null;
43
- _id: string;
44
- id: string;
45
-
46
- constructor(id: string, options: HeaderOptions = {}) {
47
- this._id = id;
48
- this.id = id;
49
-
50
- this.state = {
51
- title: options.title ?? '',
52
- logo: options.logo ?? '',
53
- navigation: options.navigation ?? [],
54
- sticky: options.sticky ?? true,
55
- style: options.style ?? '',
56
- class: options.class ?? ''
57
- };
58
- }
59
-
60
- /* -------------------------
61
- * Fluent API
62
- * ------------------------- */
63
-
64
- title(value: string): this {
65
- this.state.title = value;
66
- return this;
67
- }
68
-
69
- logo(value: string): this {
70
- this.state.logo = value;
71
- return this;
72
- }
73
-
74
- navigation(value: Array<{ label: string; href: string }>): this {
75
- this.state.navigation = value;
76
- return this;
77
- }
78
-
79
- sticky(value: boolean): this {
80
- this.state.sticky = value;
81
- return this;
82
- }
83
-
84
- class(value: string): this {
85
- this.state.class = value;
86
- return this;
87
- }
88
-
89
- style(value: string): this {
90
- this.state.style = value;
91
- return this;
92
- }
93
- /* -------------------------
94
- * Render
95
- * ------------------------- */
96
-
97
- render(targetId?: string): this {
98
- let container: HTMLElement;
99
-
100
- if (targetId) {
101
- const target = document.querySelector(targetId);
102
- if (!target || !(target instanceof HTMLElement)) {
103
- throw new Error(`Header: Target element "${targetId}" not found`);
104
- }
105
- container = target;
106
- } else {
107
- container = getOrCreateContainer(this._id);
108
- }
109
-
110
- this.container = container;
111
- const { title, logo, navigation, sticky, style, class: className } = this.state;
112
-
113
- const header = document.createElement('header');
114
- header.className = 'jux-header';
115
-
116
- header.id = this._id;
117
- header.style.cssText = style;
118
- header.className = `jux-header ${className}`.trim();
119
-
120
- if (sticky) {
121
- header.classList.add('jux-header-sticky');
122
- }
123
-
124
- // Logo section
125
- if (logo || title) {
126
- const logoSection = document.createElement('div');
127
- logoSection.className = 'jux-header-logo';
128
-
129
- if (logo) {
130
- const logoImg = document.createElement('img');
131
- logoImg.src = logo;
132
- logoImg.alt = title || 'Logo';
133
- logoSection.appendChild(logoImg);
134
- }
135
-
136
- if (title) {
137
- const titleEl = document.createElement('span');
138
- titleEl.className = 'jux-header-title';
139
- titleEl.textContent = title;
140
- logoSection.appendChild(titleEl);
141
- }
142
-
143
- header.appendChild(logoSection);
144
- }
145
-
146
- // Navigation
147
- if (navigation.length > 0) {
148
- const nav = document.createElement('nav');
149
- nav.className = 'jux-header-nav';
150
-
151
- navigation.forEach(item => {
152
- const link = document.createElement('a');
153
- link.className = 'jux-header-nav-item';
154
- link.href = item.href;
155
- link.textContent = item.label;
156
- nav.appendChild(link);
157
- });
158
-
159
- header.appendChild(nav);
160
- }
161
-
162
- container.appendChild(header);
163
- return this;
164
- }
165
-
166
- /**
167
- * Render to another Jux component's container
168
- */
169
- renderTo(juxComponent: any): this {
170
- if (!juxComponent || typeof juxComponent !== 'object') {
171
- throw new Error('Header.renderTo: Invalid component - not an object');
172
- }
173
-
174
- if (!juxComponent._id || typeof juxComponent._id !== 'string') {
175
- throw new Error('Header.renderTo: Invalid component - missing _id (not a Jux component)');
176
- }
177
-
178
- return this.render(`#${juxComponent._id}`);
179
- }
180
- }
181
-
182
- /**
183
- * Factory helper
184
- */
185
- export function header(id: string, options: HeaderOptions = {}): Header {
186
- return new Header(id, options);
187
- }
@@ -1,239 +0,0 @@
1
- import { ErrorHandler } from './error-handler.js';
2
-
3
- /**
4
- * Layout component interface
5
- * Represents any Jux component that can be rendered
6
- */
7
- interface LayoutComponent {
8
- render: (target?: string) => any;
9
- _componentId?: string;
10
- _id?: string;
11
- }
12
-
13
- /**
14
- * Layout - Compose and render multiple components
15
- *
16
- * Usage:
17
- * // As a composition function
18
- * jux.layout(
19
- * jux.include('/lib/presets/notion/notion.css'),
20
- * jux.header('appheader').render('#app'),
21
- * jux.sidebar('appsidebar').render('#app'),
22
- * jux.main('appmain').render('#app')
23
- * );
24
- *
25
- * // Or load from a .jux file
26
- * jux.layout('/lib/presets/notion/main.jux');
27
- */
28
- export class Layout {
29
- private _juxFile: string;
30
- private _loaded: boolean = false;
31
- private _components: any[] = [];
32
-
33
- constructor(...args: any[]) {
34
- // If first arg is string, it's a file path
35
- if (args.length === 1 && typeof args[0] === 'string' && args[0].endsWith('.jux')) {
36
- this._juxFile = args[0];
37
- this.load();
38
- } else {
39
- // Otherwise, it's a list of components to compose
40
- this._juxFile = '';
41
- this._components = args;
42
- this._compose();
43
- }
44
- }
45
-
46
- /**
47
- * Set the JUX file to load
48
- */
49
- file(juxFile: string): this {
50
- this._juxFile = juxFile;
51
- this._loaded = false;
52
- this.load();
53
- return this;
54
- }
55
-
56
- /**
57
- * Get the current JUX file path
58
- */
59
- getFile(): string {
60
- return this._juxFile;
61
- }
62
-
63
- /**
64
- * Compose components immediately
65
- * This handles the case where components are passed directly
66
- */
67
- private _compose(): this {
68
- try {
69
- // Components are already rendered via chaining
70
- // This just ensures they're tracked
71
- this._components.forEach((component, index) => {
72
- // Components that return themselves from .render() are already in DOM
73
- // Just log for debugging
74
- if (component && typeof component === 'object') {
75
- const id = component._componentId || component._id || component.id || `component-${index}`;
76
- console.log(`✓ Layout component composed: ${id}`);
77
- }
78
- });
79
-
80
- this._loaded = true;
81
- } catch (error: any) {
82
- ErrorHandler.captureError({
83
- component: 'Layout',
84
- method: '_compose',
85
- message: `Failed to compose layout: ${error.message}`,
86
- stack: error.stack,
87
- timestamp: new Date(),
88
- context: {
89
- componentCount: this._components.length,
90
- error: 'composition_failed'
91
- }
92
- });
93
- }
94
-
95
- return this;
96
- }
97
-
98
- /**
99
- * Normalize path to absolute URL from site root
100
- */
101
- private normalizePath(path: string): string {
102
- // If already a full URL, return as-is
103
- if (path.startsWith('http://') || path.startsWith('https://')) {
104
- return path;
105
- }
106
-
107
- // Convert relative path to absolute
108
- // Remove leading './' if present
109
- let cleanPath = path.replace(/^\.\//, '');
110
-
111
- // Ensure it starts with /
112
- if (!cleanPath.startsWith('/')) {
113
- cleanPath = '/' + cleanPath;
114
- }
115
-
116
- // Return absolute URL with origin
117
- return new URL(cleanPath, window.location.origin).href;
118
- }
119
-
120
- /**
121
- * Load the layout from a .jux file
122
- * This will dynamically import the compiled JS file
123
- */
124
- async load(): Promise<this> {
125
- if (typeof document === 'undefined') {
126
- return this;
127
- }
128
-
129
- if (!this._juxFile) {
130
- console.warn('Layout: No file specified to load');
131
- return this;
132
- }
133
-
134
- try {
135
- // Convert .jux to .js for the compiled output
136
- let jsFile = this._juxFile.replace(/\.jux$/, '.js');
137
-
138
- // Normalize to absolute URL for browser import
139
- jsFile = this.normalizePath(jsFile);
140
-
141
- console.log(`Loading layout: ${jsFile}`);
142
-
143
- // Dynamic import of the layout module
144
- const layoutModule = await import(jsFile);
145
-
146
- // If the module has an init or default export, call it
147
- if (typeof layoutModule.default === 'function') {
148
- await layoutModule.default();
149
- } else if (typeof layoutModule.init === 'function') {
150
- await layoutModule.init();
151
- } else if (layoutModule.default && typeof layoutModule.default === 'object') {
152
- // If default export is the layout object itself
153
- console.log('✓ Layout module loaded (object export)');
154
- }
155
-
156
- this._loaded = true;
157
- console.log(`✓ Layout loaded: ${this._juxFile}`);
158
- } catch (error: any) {
159
- ErrorHandler.captureError({
160
- component: 'Layout',
161
- method: 'load',
162
- message: `Failed to load layout: ${error.message}`,
163
- stack: error.stack,
164
- timestamp: new Date(),
165
- context: {
166
- juxFile: this._juxFile,
167
- jsFile: this._juxFile.replace(/\.jux$/, '.js'),
168
- errorCode: error.code
169
- }
170
- });
171
- }
172
-
173
- return this;
174
- }
175
-
176
- /**
177
- * Check if layout is loaded
178
- */
179
- isLoaded(): boolean {
180
- return this._loaded;
181
- }
182
-
183
- /**
184
- * Get all composed components
185
- */
186
- getComponents(): any[] {
187
- return this._components;
188
- }
189
-
190
- /**
191
- * Add a component to the layout
192
- */
193
- add(component: any): this {
194
- this._components.push(component);
195
- return this;
196
- }
197
-
198
- /**
199
- * Render all components
200
- * Useful if components weren't already rendered
201
- */
202
- render(target?: string): this {
203
- this._components.forEach((component) => {
204
- if (component && typeof component.render === 'function') {
205
- try {
206
- component.render(target);
207
- } catch (error: any) {
208
- ErrorHandler.captureError({
209
- component: 'Layout',
210
- method: 'render',
211
- message: `Failed to render component: ${error.message}`,
212
- stack: error.stack,
213
- timestamp: new Date(),
214
- context: {
215
- componentId: component._componentId || component._id || 'unknown',
216
- target
217
- }
218
- });
219
- }
220
- }
221
- });
222
-
223
- return this;
224
- }
225
- }
226
-
227
- /**
228
- * Factory helper
229
- * Accepts either:
230
- * - A file path: layout('/lib/presets/notion/main.jux')
231
- * - A list of components: layout(header, sidebar, main)
232
- */
233
- export function layout(...args: any[]): Layout {
234
- return new Layout(...args);
235
- }
236
-
237
- /* -------------------------
238
- * Module Exports
239
- * ------------------------- */
@@ -1,137 +0,0 @@
1
- import { getOrCreateContainer } from './helpers.js';
2
-
3
- /**
4
- * Main component options
5
- */
6
- export interface MainOptions {
7
- content?: string;
8
- padding?: string;
9
- style?: string;
10
- class?: string;
11
- }
12
-
13
- /**
14
- * Main component state
15
- */
16
- type MainState = {
17
- content: string;
18
- padding: string;
19
- style: string;
20
- class: string;
21
- };
22
-
23
- /**
24
- * Main component - represents the main content area
25
- *
26
- * Usage:
27
- * const main = jux.main('myMain', {
28
- * content: 'Main content here',
29
- * padding: '2rem'
30
- * });
31
- * main.render('#appmain');
32
- */
33
- export class Main {
34
- state: MainState;
35
- container: HTMLElement | null = null;
36
- _id: string;
37
- id: string;
38
-
39
- constructor(id: string, options: MainOptions = {}) {
40
- this._id = id;
41
- this.id = id;
42
-
43
- this.state = {
44
- content: options.content ?? '',
45
- padding: options.padding ?? 'var(--space-xl)',
46
- style: options.style ?? '',
47
- class: options.class ?? ''
48
- };
49
- }
50
-
51
- /* -------------------------
52
- * Fluent API
53
- * ------------------------- */
54
-
55
- content(value: string): this {
56
- this.state.content = value;
57
- return this;
58
- }
59
-
60
- padding(value: string): this {
61
- this.state.padding = value;
62
- return this;
63
- }
64
-
65
- style(value: string): this {
66
- this.state.style = value;
67
- return this;
68
- }
69
-
70
- class(value: string): this {
71
- this.state.class = value;
72
- return this;
73
- }
74
-
75
- /* -------------------------
76
- * Render
77
- * ------------------------- */
78
-
79
- render(targetId?: string): this {
80
- let container: HTMLElement;
81
-
82
- if (targetId) {
83
- const target = document.querySelector(targetId);
84
- if (!target || !(target instanceof HTMLElement)) {
85
- throw new Error(`Main: Target element "${targetId}" not found`);
86
- }
87
- container = target;
88
- } else {
89
- container = getOrCreateContainer(this._id);
90
- }
91
-
92
- this.container = container;
93
- const { content, padding, style, class: className } = this.state;
94
-
95
- const main = document.createElement('main');
96
- main.className = 'jux-main';
97
- main.id = this._id;
98
- main.style.padding = padding;
99
-
100
- if (style) {
101
- main.setAttribute('style', style);
102
- }
103
-
104
- if (className) {
105
- main.className += ` ${className}`;
106
- }
107
-
108
- if (content) {
109
- main.innerHTML = content;
110
- }
111
-
112
- container.appendChild(main);
113
- return this;
114
- }
115
-
116
- /**
117
- * Render to another Jux component's container
118
- */
119
- renderTo(juxComponent: any): this {
120
- if (!juxComponent || typeof juxComponent !== 'object') {
121
- throw new Error('Main.renderTo: Invalid component - not an object');
122
- }
123
-
124
- if (!juxComponent._id || typeof juxComponent._id !== 'string') {
125
- throw new Error('Main.renderTo: Invalid component - missing _id (not a Jux component)');
126
- }
127
-
128
- return this.render(`#${juxComponent._id}`);
129
- }
130
- }
131
-
132
- /**
133
- * Factory helper
134
- */
135
- export function main(id: string, options: MainOptions = {}): Main {
136
- return new Main(id, options);
137
- }