juxscript 1.0.0

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 (61) hide show
  1. package/README.md +292 -0
  2. package/bin/cli.js +149 -0
  3. package/lib/adapters/base-adapter.js +35 -0
  4. package/lib/adapters/index.js +33 -0
  5. package/lib/adapters/mysql-adapter.js +65 -0
  6. package/lib/adapters/postgres-adapter.js +70 -0
  7. package/lib/adapters/sqlite-adapter.js +56 -0
  8. package/lib/components/app.ts +124 -0
  9. package/lib/components/button.ts +136 -0
  10. package/lib/components/card.ts +205 -0
  11. package/lib/components/chart.ts +125 -0
  12. package/lib/components/code.ts +242 -0
  13. package/lib/components/container.ts +282 -0
  14. package/lib/components/data.ts +105 -0
  15. package/lib/components/docs-data.json +1211 -0
  16. package/lib/components/error-handler.ts +285 -0
  17. package/lib/components/footer.ts +146 -0
  18. package/lib/components/header.ts +167 -0
  19. package/lib/components/hero.ts +170 -0
  20. package/lib/components/import.ts +430 -0
  21. package/lib/components/input.ts +175 -0
  22. package/lib/components/layout.ts +113 -0
  23. package/lib/components/list.ts +392 -0
  24. package/lib/components/main.ts +111 -0
  25. package/lib/components/menu.ts +170 -0
  26. package/lib/components/modal.ts +216 -0
  27. package/lib/components/nav.ts +136 -0
  28. package/lib/components/node.ts +200 -0
  29. package/lib/components/reactivity.js +104 -0
  30. package/lib/components/script.ts +152 -0
  31. package/lib/components/sidebar.ts +168 -0
  32. package/lib/components/style.ts +129 -0
  33. package/lib/components/table.ts +279 -0
  34. package/lib/components/tabs.ts +191 -0
  35. package/lib/components/theme.ts +97 -0
  36. package/lib/components/view.ts +174 -0
  37. package/lib/jux.ts +203 -0
  38. package/lib/layouts/default.css +260 -0
  39. package/lib/layouts/default.jux +8 -0
  40. package/lib/layouts/figma.css +334 -0
  41. package/lib/layouts/figma.jux +0 -0
  42. package/lib/layouts/notion.css +258 -0
  43. package/lib/styles/base-theme.css +186 -0
  44. package/lib/styles/dark-theme.css +144 -0
  45. package/lib/styles/global.css +1131 -0
  46. package/lib/styles/light-theme.css +144 -0
  47. package/lib/styles/tokens/dark.css +86 -0
  48. package/lib/styles/tokens/light.css +86 -0
  49. package/lib/themes/dark.css +86 -0
  50. package/lib/themes/light.css +86 -0
  51. package/lib/utils/path-resolver.js +23 -0
  52. package/machinery/compiler.js +262 -0
  53. package/machinery/doc-generator.js +160 -0
  54. package/machinery/generators/css.js +128 -0
  55. package/machinery/generators/html.js +108 -0
  56. package/machinery/imports.js +155 -0
  57. package/machinery/server.js +185 -0
  58. package/machinery/validators/file-validator.js +123 -0
  59. package/machinery/watcher.js +148 -0
  60. package/package.json +58 -0
  61. package/types/globals.d.ts +16 -0
@@ -0,0 +1,124 @@
1
+ import { ErrorHandler } from './error-handler.js';
2
+
3
+ /**
4
+ * App - Configure application-level settings
5
+ * Manages document metadata, theme, and global configuration
6
+ */
7
+ export class App {
8
+ private _title: string = '';
9
+ private _theme: 'light' | 'dark' | 'auto' = 'auto';
10
+ private _favicon: string = '';
11
+ private _meta: Map<string, string> = new Map();
12
+
13
+ title(title: string): this {
14
+ this._title = title;
15
+ this.applyTitle();
16
+ return this;
17
+ }
18
+
19
+ theme(theme: 'light' | 'dark' | 'auto'): this {
20
+ this._theme = theme;
21
+ this.applyTheme();
22
+ return this;
23
+ }
24
+
25
+ favicon(url: string): this {
26
+ this._favicon = url;
27
+ this.applyFavicon();
28
+ return this;
29
+ }
30
+
31
+ meta(name: string, content: string): this {
32
+ this._meta.set(name, content);
33
+ this.applyMeta(name, content);
34
+ return this;
35
+ }
36
+
37
+ private applyTitle(): void {
38
+ if (typeof document === 'undefined') return;
39
+
40
+ try {
41
+ document.title = this._title;
42
+ } catch (error: any) {
43
+ ErrorHandler.captureError({
44
+ component: 'App',
45
+ method: 'applyTitle',
46
+ message: error.message,
47
+ stack: error.stack,
48
+ timestamp: new Date(),
49
+ context: { title: this._title }
50
+ });
51
+ }
52
+ }
53
+
54
+ private applyTheme(): void {
55
+ if (typeof document === 'undefined') return;
56
+
57
+ try {
58
+ document.body.setAttribute('data-theme', this._theme);
59
+
60
+ // Add theme class for styling
61
+ document.body.classList.remove('theme-light', 'theme-dark', 'theme-auto');
62
+ document.body.classList.add(`theme-${this._theme}`);
63
+ } catch (error: any) {
64
+ ErrorHandler.captureError({
65
+ component: 'App',
66
+ method: 'applyTheme',
67
+ message: error.message,
68
+ stack: error.stack,
69
+ timestamp: new Date(),
70
+ context: { theme: this._theme }
71
+ });
72
+ }
73
+ }
74
+
75
+ private applyFavicon(): void {
76
+ if (typeof document === 'undefined') return;
77
+
78
+ try {
79
+ let link = document.querySelector<HTMLLinkElement>('link[rel="icon"]');
80
+
81
+ if (!link) {
82
+ link = document.createElement('link');
83
+ link.rel = 'icon';
84
+ document.head.appendChild(link);
85
+ }
86
+
87
+ link.href = this._favicon;
88
+ } catch (error: any) {
89
+ ErrorHandler.captureError({
90
+ component: 'App',
91
+ method: 'applyFavicon',
92
+ message: error.message,
93
+ stack: error.stack,
94
+ timestamp: new Date(),
95
+ context: { favicon: this._favicon }
96
+ });
97
+ }
98
+ }
99
+
100
+ private applyMeta(name: string, content: string): void {
101
+ if (typeof document === 'undefined') return;
102
+
103
+ try {
104
+ let meta = document.querySelector<HTMLMetaElement>(`meta[name="${name}"]`);
105
+
106
+ if (!meta) {
107
+ meta = document.createElement('meta');
108
+ meta.name = name;
109
+ document.head.appendChild(meta);
110
+ }
111
+
112
+ meta.content = content;
113
+ } catch (error: any) {
114
+ ErrorHandler.captureError({
115
+ component: 'App',
116
+ method: 'applyMeta',
117
+ message: error.message,
118
+ stack: error.stack,
119
+ timestamp: new Date(),
120
+ context: { name, content }
121
+ });
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,136 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+
4
+ /**
5
+ * Button component options
6
+ */
7
+ export interface ButtonOptions {
8
+ label?: string;
9
+ variant?: 'primary' | 'secondary' | 'danger' | 'success' | string;
10
+ disabled?: boolean;
11
+ onClick?: (e: Event) => void;
12
+ }
13
+
14
+ /**
15
+ * Button component state
16
+ */
17
+ type ButtonState = {
18
+ label: string;
19
+ variant: string;
20
+ disabled: boolean;
21
+ onClick: ((e: Event) => void) | null;
22
+ };
23
+
24
+ /**
25
+ * Button component
26
+ *
27
+ * Usage:
28
+ * const btn = jux.button('myButton', { label: 'Click Me', onClick: () => console.log('clicked') });
29
+ * btn.render();
30
+ */
31
+ export class Button extends Reactive {
32
+ state!: ButtonState;
33
+ container: HTMLElement | null = null;
34
+
35
+ constructor(componentId: string, options: ButtonOptions = {}) {
36
+ super();
37
+ this._setComponentId(componentId);
38
+
39
+ this.state = this._createReactiveState({
40
+ label: options.label ?? 'Button',
41
+ variant: options.variant ?? 'primary',
42
+ disabled: options.disabled ?? false,
43
+ onClick: options.onClick ?? null
44
+ }) as ButtonState;
45
+ }
46
+
47
+ /* -------------------------
48
+ * Fluent API
49
+ * ------------------------- */
50
+
51
+ label(value: string): this {
52
+ this.state.label = value;
53
+ return this;
54
+ }
55
+
56
+ variant(value: string): this {
57
+ this.state.variant = value;
58
+ return this;
59
+ }
60
+
61
+ disabled(value: boolean): this {
62
+ this.state.disabled = value;
63
+ return this;
64
+ }
65
+
66
+ onClick(callback: (e: Event) => void): this {
67
+ this.state.onClick = callback;
68
+ return this;
69
+ }
70
+
71
+ /* -------------------------
72
+ * Render
73
+ * ------------------------- */
74
+
75
+ render(targetId?: string): this {
76
+ let container: HTMLElement;
77
+
78
+ if (targetId) {
79
+ // Use provided targetId - must exist
80
+ const target = document.querySelector(targetId);
81
+ if (!target || !(target instanceof HTMLElement)) {
82
+ throw new Error(`Button: Target element "${targetId}" not found`);
83
+ }
84
+ container = target;
85
+ } else {
86
+ // Create or get container with component ID
87
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
88
+ }
89
+
90
+ this.container = container;
91
+ const { label, variant, disabled, onClick } = this.state;
92
+
93
+ // Create button element
94
+ const button = document.createElement('button');
95
+ button.className = `jux-button jux-button-${variant}`;
96
+ button.id = this._componentId;
97
+ button.textContent = label;
98
+ button.disabled = disabled;
99
+
100
+ // Attach click handler if provided
101
+ if (onClick) {
102
+ button.addEventListener('click', onClick);
103
+ }
104
+
105
+ container.appendChild(button);
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Render to another Jux component's container
111
+ *
112
+ * Usage:
113
+ * const container = jux.node('myContainer');
114
+ * const btn = jux.button('myBtn').renderTo(container);
115
+ */
116
+ renderTo(juxComponent: any): this {
117
+ // Verify it's a Jux component (has _componentId from Reactive base)
118
+ if (!juxComponent || typeof juxComponent !== 'object') {
119
+ throw new Error('Button.renderTo: Invalid component - not an object');
120
+ }
121
+
122
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
123
+ throw new Error('Button.renderTo: Invalid component - missing _componentId (not a Jux component)');
124
+ }
125
+
126
+ // Render to the component's ID as a selector
127
+ return this.render(`#${juxComponent._componentId}`);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Factory helper
133
+ */
134
+ export function button(componentId: string, options: ButtonOptions = {}): Button {
135
+ return new Button(componentId, options);
136
+ }
@@ -0,0 +1,205 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Action configuration for card actions
5
+ */
6
+ export interface CardAction {
7
+ label: string;
8
+ onClick: () => void;
9
+ variant?: 'primary' | 'secondary' | 'danger';
10
+ }
11
+
12
+ /**
13
+ * Card component options
14
+ */
15
+ export interface CardOptions {
16
+ title?: string;
17
+ subtitle?: string;
18
+ content?: string;
19
+ image?: string;
20
+ actions?: CardAction[];
21
+ variant?: 'default' | 'elevated' | 'outlined';
22
+ }
23
+
24
+ /**
25
+ * Card component state
26
+ */
27
+ type CardState = {
28
+ title: string;
29
+ subtitle: string;
30
+ content: string;
31
+ image: string;
32
+ actions: CardAction[];
33
+ variant: string;
34
+ };
35
+
36
+ /**
37
+ * Card component
38
+ *
39
+ * Usage:
40
+ * const card = jux.card('myCard', {
41
+ * title: 'Card Title',
42
+ * content: 'Card content here'
43
+ * });
44
+ * card.render();
45
+ */
46
+ export class Card extends Reactive {
47
+ state!: CardState;
48
+ container: HTMLElement | null = null;
49
+
50
+ constructor(componentId: string, options: CardOptions = {}) {
51
+ super();
52
+ this._setComponentId(componentId);
53
+
54
+ this.state = this._createReactiveState({
55
+ title: options.title ?? '',
56
+ subtitle: options.subtitle ?? '',
57
+ content: options.content ?? '',
58
+ image: options.image ?? '',
59
+ actions: options.actions ?? [],
60
+ variant: options.variant ?? 'default'
61
+ }) as CardState;
62
+ }
63
+
64
+ /* -------------------------
65
+ * Fluent API
66
+ * ------------------------- */
67
+
68
+ title(value: string): this {
69
+ this.state.title = value;
70
+ return this;
71
+ }
72
+
73
+ subtitle(value: string): this {
74
+ this.state.subtitle = value;
75
+ return this;
76
+ }
77
+
78
+ content(value: string): this {
79
+ this.state.content = value;
80
+ return this;
81
+ }
82
+
83
+ image(value: string): this {
84
+ this.state.image = value;
85
+ return this;
86
+ }
87
+
88
+ actions(value: CardAction[]): this {
89
+ this.state.actions = value;
90
+ return this;
91
+ }
92
+
93
+ variant(value: string): this {
94
+ this.state.variant = value;
95
+ return this;
96
+ }
97
+
98
+ /* -------------------------
99
+ * Render
100
+ * ------------------------- */
101
+
102
+ render(targetId?: string): this {
103
+ let container: HTMLElement;
104
+
105
+ if (targetId) {
106
+ const target = document.querySelector(targetId);
107
+ if (!target || !(target instanceof HTMLElement)) {
108
+ throw new Error(`Card: Target element "${targetId}" not found`);
109
+ }
110
+ container = target;
111
+ } else {
112
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
113
+ }
114
+
115
+ this.container = container;
116
+ const { title, subtitle, content, image, actions, variant } = this.state;
117
+
118
+ // Create card element
119
+ const card = document.createElement('div');
120
+ card.className = `jux-card jux-card-${variant}`;
121
+ card.id = this._componentId;
122
+
123
+ // Image
124
+ if (image) {
125
+ const img = document.createElement('img');
126
+ img.className = 'jux-card-image';
127
+ img.src = image;
128
+ img.alt = title || 'Card image';
129
+ card.appendChild(img);
130
+ }
131
+
132
+ // Content wrapper
133
+ const cardBody = document.createElement('div');
134
+ cardBody.className = 'jux-card-body';
135
+
136
+ // Title
137
+ if (title) {
138
+ const titleEl = document.createElement('h3');
139
+ titleEl.className = 'jux-card-title';
140
+ titleEl.textContent = title;
141
+ cardBody.appendChild(titleEl);
142
+ }
143
+
144
+ // Subtitle
145
+ if (subtitle) {
146
+ const subtitleEl = document.createElement('p');
147
+ subtitleEl.className = 'jux-card-subtitle';
148
+ subtitleEl.textContent = subtitle;
149
+ cardBody.appendChild(subtitleEl);
150
+ }
151
+
152
+ // Content
153
+ if (content) {
154
+ const contentEl = document.createElement('p');
155
+ contentEl.className = 'jux-card-content';
156
+ contentEl.textContent = content;
157
+ cardBody.appendChild(contentEl);
158
+ }
159
+
160
+ card.appendChild(cardBody);
161
+
162
+ // Actions
163
+ if (actions.length > 0) {
164
+ const actionsEl = document.createElement('div');
165
+ actionsEl.className = 'jux-card-actions';
166
+
167
+ actions.forEach(action => {
168
+ const btn = document.createElement('button');
169
+ btn.className = `jux-button jux-button-${action.variant || 'primary'}`;
170
+ btn.textContent = action.label;
171
+ actionsEl.appendChild(btn);
172
+
173
+ // Event binding
174
+ btn.addEventListener('click', action.onClick);
175
+ });
176
+
177
+ card.appendChild(actionsEl);
178
+ }
179
+
180
+ container.appendChild(card);
181
+ return this;
182
+ }
183
+
184
+ /**
185
+ * Render to another Jux component's container
186
+ */
187
+ renderTo(juxComponent: any): this {
188
+ if (!juxComponent || typeof juxComponent !== 'object') {
189
+ throw new Error('Card.renderTo: Invalid component - not an object');
190
+ }
191
+
192
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
193
+ throw new Error('Card.renderTo: Invalid component - missing _componentId (not a Jux component)');
194
+ }
195
+
196
+ return this.render(`#${juxComponent._componentId}`);
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Factory helper
202
+ */
203
+ export function card(componentId: string, options: CardOptions = {}): Card {
204
+ return new Card(componentId, options);
205
+ }
@@ -0,0 +1,125 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Chart component options
5
+ */
6
+ export interface ChartOptions {
7
+ type?: 'bar' | 'line' | 'pie' | 'doughnut';
8
+ data?: any;
9
+ options?: any;
10
+ }
11
+
12
+ /**
13
+ * Chart component state
14
+ */
15
+ type ChartState = {
16
+ type: string;
17
+ data: any;
18
+ options: any;
19
+ };
20
+
21
+ /**
22
+ * Chart component - placeholder for chart integration
23
+ *
24
+ * Usage:
25
+ * const chart = jux.chart('myChart', {
26
+ * type: 'bar',
27
+ * data: {
28
+ * labels: ['A', 'B', 'C'],
29
+ * datasets: [{ data: [10, 20, 30] }]
30
+ * }
31
+ * });
32
+ * chart.render();
33
+ */
34
+ export class Chart extends Reactive {
35
+ state!: ChartState;
36
+ container: HTMLElement | null = null;
37
+
38
+ constructor(componentId: string, options: ChartOptions = {}) {
39
+ super();
40
+ this._setComponentId(componentId);
41
+
42
+ this.state = this._createReactiveState({
43
+ type: options.type ?? 'bar',
44
+ data: options.data ?? {},
45
+ options: options.options ?? {}
46
+ }) as ChartState;
47
+ }
48
+
49
+ /* -------------------------
50
+ * Fluent API
51
+ * ------------------------- */
52
+
53
+ type(value: string): this {
54
+ this.state.type = value;
55
+ return this;
56
+ }
57
+
58
+ data(value: any): this {
59
+ this.state.data = value;
60
+ return this;
61
+ }
62
+
63
+ options(value: any): this {
64
+ this.state.options = value;
65
+ return this;
66
+ }
67
+
68
+ /* -------------------------
69
+ * Render
70
+ * ------------------------- */
71
+
72
+ render(targetId?: string): this {
73
+ let container: HTMLElement;
74
+
75
+ if (targetId) {
76
+ const target = document.querySelector(targetId);
77
+ if (!target || !(target instanceof HTMLElement)) {
78
+ throw new Error(`Chart: Target element "${targetId}" not found`);
79
+ }
80
+ container = target;
81
+ } else {
82
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
83
+ }
84
+
85
+ this.container = container;
86
+ const { type, data } = this.state;
87
+
88
+ const canvas = document.createElement('canvas');
89
+ canvas.id = this._componentId;
90
+ canvas.className = 'jux-chart';
91
+
92
+ // Placeholder rendering (would integrate with Chart.js or similar)
93
+ const placeholder = document.createElement('div');
94
+ placeholder.className = 'jux-chart-placeholder';
95
+ placeholder.textContent = `Chart (${type}) - Integration pending`;
96
+ placeholder.style.cssText = 'padding: 2rem; border: 2px dashed var(--border-color); text-align: center;';
97
+
98
+ container.appendChild(placeholder);
99
+ container.appendChild(canvas);
100
+
101
+ return this;
102
+ }
103
+
104
+ /**
105
+ * Render to another Jux component's container
106
+ */
107
+ renderTo(juxComponent: any): this {
108
+ if (!juxComponent || typeof juxComponent !== 'object') {
109
+ throw new Error('Chart.renderTo: Invalid component - not an object');
110
+ }
111
+
112
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
113
+ throw new Error('Chart.renderTo: Invalid component - missing _componentId (not a Jux component)');
114
+ }
115
+
116
+ return this.render(`#${juxComponent._componentId}`);
117
+ }
118
+ }
119
+
120
+ /**
121
+ * Factory helper
122
+ */
123
+ export function chart(componentId: string, options: ChartOptions = {}): Chart {
124
+ return new Chart(componentId, options);
125
+ }