juxscript 1.0.20 → 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 (76) hide show
  1. package/bin/cli.js +121 -72
  2. package/lib/components/alert.ts +143 -92
  3. package/lib/components/badge.ts +93 -94
  4. package/lib/components/base/BaseComponent.ts +397 -0
  5. package/lib/components/base/FormInput.ts +322 -0
  6. package/lib/components/button.ts +40 -131
  7. package/lib/components/card.ts +57 -79
  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/{chart-types.ts → charts/lib/chart-types.ts} +1 -1
  13. package/lib/components/{chart-utils.ts → charts/lib/chart-utils.ts} +1 -1
  14. package/lib/components/{chart.ts → charts/lib/chart.ts} +3 -3
  15. package/lib/components/checkbox.ts +255 -204
  16. package/lib/components/code.ts +31 -78
  17. package/lib/components/container.ts +113 -130
  18. package/lib/components/data.ts +37 -5
  19. package/lib/components/datepicker.ts +180 -147
  20. package/lib/components/dialog.ts +218 -221
  21. package/lib/components/divider.ts +63 -87
  22. package/lib/components/docs-data.json +498 -2404
  23. package/lib/components/dropdown.ts +191 -236
  24. package/lib/components/element.ts +196 -145
  25. package/lib/components/fileupload.ts +253 -167
  26. package/lib/components/guard.ts +92 -0
  27. package/lib/components/heading.ts +31 -97
  28. package/lib/components/helpers.ts +13 -6
  29. package/lib/components/hero.ts +51 -114
  30. package/lib/components/icon.ts +33 -120
  31. package/lib/components/icons.ts +2 -1
  32. package/lib/components/include.ts +76 -3
  33. package/lib/components/input.ts +155 -407
  34. package/lib/components/kpicard.ts +16 -16
  35. package/lib/components/list.ts +358 -261
  36. package/lib/components/loading.ts +142 -211
  37. package/lib/components/menu.ts +63 -152
  38. package/lib/components/modal.ts +42 -129
  39. package/lib/components/nav.ts +79 -101
  40. package/lib/components/paragraph.ts +38 -102
  41. package/lib/components/progress.ts +108 -166
  42. package/lib/components/radio.ts +283 -234
  43. package/lib/components/script.ts +19 -87
  44. package/lib/components/select.ts +189 -199
  45. package/lib/components/sidebar.ts +110 -141
  46. package/lib/components/style.ts +19 -82
  47. package/lib/components/switch.ts +254 -183
  48. package/lib/components/table.ts +1078 -208
  49. package/lib/components/tabs.ts +42 -106
  50. package/lib/components/theme-toggle.ts +73 -165
  51. package/lib/components/tooltip.ts +85 -316
  52. package/lib/components/write.ts +108 -127
  53. package/lib/jux.ts +67 -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 -1
  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 -1128
  67. package/lib/components/areachartsmooth.ts +0 -1380
  68. package/lib/components/barchart.ts +0 -1322
  69. package/lib/components/doughnutchart.ts +0 -1259
  70. package/lib/components/footer.ts +0 -165
  71. package/lib/components/header.ts +0 -187
  72. package/lib/components/layout.ts +0 -239
  73. package/lib/components/main.ts +0 -137
  74. package/lib/layouts/default.jux +0 -8
  75. package/lib/layouts/figma.jux +0 -0
  76. /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
- }