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,111 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Main component options
5
+ */
6
+ export interface MainOptions {
7
+ content?: string;
8
+ padding?: string;
9
+ }
10
+
11
+ /**
12
+ * Main component state
13
+ */
14
+ type MainState = {
15
+ content: string;
16
+ padding: string;
17
+ };
18
+
19
+ /**
20
+ * Main component - represents the main content area
21
+ *
22
+ * Usage:
23
+ * const main = jux.main('myMain', {
24
+ * content: 'Main content here',
25
+ * padding: '2rem'
26
+ * });
27
+ * main.render('#appmain');
28
+ */
29
+ export class Main extends Reactive {
30
+ state!: MainState;
31
+ container: HTMLElement | null = null;
32
+
33
+ constructor(componentId: string, options: MainOptions = {}) {
34
+ super();
35
+ this._setComponentId(componentId);
36
+
37
+ this.state = this._createReactiveState({
38
+ content: options.content ?? '',
39
+ padding: options.padding ?? 'var(--space-xl)'
40
+ }) as MainState;
41
+ }
42
+
43
+ /* -------------------------
44
+ * Fluent API
45
+ * ------------------------- */
46
+
47
+ content(value: string): this {
48
+ this.state.content = value;
49
+ return this;
50
+ }
51
+
52
+ padding(value: string): this {
53
+ this.state.padding = value;
54
+ return this;
55
+ }
56
+
57
+ /* -------------------------
58
+ * Render
59
+ * ------------------------- */
60
+
61
+ render(targetId?: string): this {
62
+ let container: HTMLElement;
63
+
64
+ if (targetId) {
65
+ const target = document.querySelector(targetId);
66
+ if (!target || !(target instanceof HTMLElement)) {
67
+ throw new Error(`Main: Target element "${targetId}" not found`);
68
+ }
69
+ container = target;
70
+ } else {
71
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
72
+ }
73
+
74
+ this.container = container;
75
+ const { content, padding } = this.state;
76
+
77
+ const main = document.createElement('main');
78
+ main.className = 'jux-main';
79
+ main.id = this._componentId;
80
+ main.style.padding = padding;
81
+
82
+ if (content) {
83
+ main.innerHTML = content;
84
+ }
85
+
86
+ container.appendChild(main);
87
+ return this;
88
+ }
89
+
90
+ /**
91
+ * Render to another Jux component's container
92
+ */
93
+ renderTo(juxComponent: any): this {
94
+ if (!juxComponent || typeof juxComponent !== 'object') {
95
+ throw new Error('Main.renderTo: Invalid component - not an object');
96
+ }
97
+
98
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
99
+ throw new Error('Main.renderTo: Invalid component - missing _componentId (not a Jux component)');
100
+ }
101
+
102
+ return this.render(`#${juxComponent._componentId}`);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Factory helper
108
+ */
109
+ export function main(componentId: string, options: MainOptions = {}): Main {
110
+ return new Main(componentId, options);
111
+ }
@@ -0,0 +1,170 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Menu item configuration
5
+ */
6
+ export interface MenuItem {
7
+ label: string;
8
+ href?: string;
9
+ onClick?: () => void;
10
+ icon?: string;
11
+ items?: MenuItem[];
12
+ }
13
+
14
+ /**
15
+ * Menu component options
16
+ */
17
+ export interface MenuOptions {
18
+ items?: MenuItem[];
19
+ orientation?: 'vertical' | 'horizontal';
20
+ }
21
+
22
+ /**
23
+ * Menu component state
24
+ */
25
+ type MenuState = {
26
+ items: MenuItem[];
27
+ orientation: string;
28
+ };
29
+
30
+ /**
31
+ * Menu component
32
+ *
33
+ * Usage:
34
+ * const menu = jux.menu('myMenu', {
35
+ * orientation: 'vertical',
36
+ * items: [
37
+ * { label: 'Home', href: '/' },
38
+ * { label: 'About', href: '/about' }
39
+ * ]
40
+ * });
41
+ * menu.render();
42
+ */
43
+ export class Menu extends Reactive {
44
+ state!: MenuState;
45
+ container: HTMLElement | null = null;
46
+
47
+ constructor(componentId: string, options: MenuOptions = {}) {
48
+ super();
49
+ this._setComponentId(componentId);
50
+
51
+ this.state = this._createReactiveState({
52
+ items: options.items ?? [],
53
+ orientation: options.orientation ?? 'vertical'
54
+ }) as MenuState;
55
+ }
56
+
57
+ /* -------------------------
58
+ * Fluent API
59
+ * ------------------------- */
60
+
61
+ items(value: MenuItem[]): this {
62
+ this.state.items = value;
63
+ return this;
64
+ }
65
+
66
+ addItem(item: MenuItem): this {
67
+ this.state.items.push(item);
68
+ return this;
69
+ }
70
+
71
+ orientation(value: 'vertical' | 'horizontal'): this {
72
+ this.state.orientation = value;
73
+ return this;
74
+ }
75
+
76
+ /* -------------------------
77
+ * Helpers
78
+ * ------------------------- */
79
+
80
+ private _renderMenuItem(item: MenuItem): HTMLElement {
81
+ const menuItem = document.createElement('div');
82
+ menuItem.className = 'jux-menu-item';
83
+
84
+ if (item.href) {
85
+ const link = document.createElement('a');
86
+ link.className = 'jux-menu-link';
87
+ link.href = item.href;
88
+ link.textContent = item.label;
89
+ menuItem.appendChild(link);
90
+ } else {
91
+ const button = document.createElement('button');
92
+ button.className = 'jux-menu-button';
93
+ button.textContent = item.label;
94
+ menuItem.appendChild(button);
95
+
96
+ // Event binding - onClick
97
+ if (item.onClick) {
98
+ button.addEventListener('click', item.onClick);
99
+ }
100
+ }
101
+
102
+ // Nested items (submenu)
103
+ if (item.items && item.items.length > 0) {
104
+ const submenu = document.createElement('div');
105
+ submenu.className = 'jux-menu-submenu';
106
+
107
+ item.items.forEach(subItem => {
108
+ submenu.appendChild(this._renderMenuItem(subItem));
109
+ });
110
+
111
+ menuItem.appendChild(submenu);
112
+ }
113
+
114
+ return menuItem;
115
+ }
116
+
117
+ /* -------------------------
118
+ * Render
119
+ * ------------------------- */
120
+
121
+ render(targetId?: string): this {
122
+ let container: HTMLElement;
123
+
124
+ if (targetId) {
125
+ const target = document.querySelector(targetId);
126
+ if (!target || !(target instanceof HTMLElement)) {
127
+ throw new Error(`Menu: Target element "${targetId}" not found`);
128
+ }
129
+ container = target;
130
+ } else {
131
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
132
+ }
133
+
134
+ this.container = container;
135
+ const { items, orientation } = this.state;
136
+
137
+ const menu = document.createElement('nav');
138
+ menu.className = `jux-menu jux-menu-${orientation}`;
139
+ menu.id = this._componentId;
140
+
141
+ items.forEach(item => {
142
+ menu.appendChild(this._renderMenuItem(item));
143
+ });
144
+
145
+ container.appendChild(menu);
146
+ return this;
147
+ }
148
+
149
+ /**
150
+ * Render to another Jux component's container
151
+ */
152
+ renderTo(juxComponent: any): this {
153
+ if (!juxComponent || typeof juxComponent !== 'object') {
154
+ throw new Error('Menu.renderTo: Invalid component - not an object');
155
+ }
156
+
157
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
158
+ throw new Error('Menu.renderTo: Invalid component - missing _componentId (not a Jux component)');
159
+ }
160
+
161
+ return this.render(`#${juxComponent._componentId}`);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Factory helper
167
+ */
168
+ export function menu(componentId: string, options: MenuOptions = {}): Menu {
169
+ return new Menu(componentId, options);
170
+ }
@@ -0,0 +1,216 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Modal component options
5
+ */
6
+ export interface ModalOptions {
7
+ title?: string;
8
+ content?: string;
9
+ showCloseButton?: boolean;
10
+ closeOnBackdropClick?: boolean;
11
+ size?: 'small' | 'medium' | 'large';
12
+ }
13
+
14
+ /**
15
+ * Modal component state
16
+ */
17
+ type ModalState = {
18
+ title: string;
19
+ content: string;
20
+ showCloseButton: boolean;
21
+ closeOnBackdropClick: boolean;
22
+ size: string;
23
+ isOpen: boolean;
24
+ };
25
+
26
+ /**
27
+ * Modal component
28
+ *
29
+ * Usage:
30
+ * const modal = jux.modal('myModal', {
31
+ * title: 'Confirmation',
32
+ * content: 'Are you sure?',
33
+ * size: 'medium'
34
+ * });
35
+ * modal.render();
36
+ * modal.open();
37
+ */
38
+ export class Modal extends Reactive {
39
+ state!: ModalState;
40
+ container: HTMLElement | null = null;
41
+
42
+ constructor(componentId: string, options: ModalOptions = {}) {
43
+ super();
44
+ this._setComponentId(componentId);
45
+
46
+ this.state = this._createReactiveState({
47
+ title: options.title ?? '',
48
+ content: options.content ?? '',
49
+ showCloseButton: options.showCloseButton ?? true,
50
+ closeOnBackdropClick: options.closeOnBackdropClick ?? true,
51
+ size: options.size ?? 'medium',
52
+ isOpen: false
53
+ }) as ModalState;
54
+ }
55
+
56
+ /* -------------------------
57
+ * Fluent API
58
+ * ------------------------- */
59
+
60
+ title(value: string): this {
61
+ this.state.title = value;
62
+ return this;
63
+ }
64
+
65
+ content(value: string): this {
66
+ this.state.content = value;
67
+ return this;
68
+ }
69
+
70
+ showCloseButton(value: boolean): this {
71
+ this.state.showCloseButton = value;
72
+ return this;
73
+ }
74
+
75
+ closeOnBackdropClick(value: boolean): this {
76
+ this.state.closeOnBackdropClick = value;
77
+ return this;
78
+ }
79
+
80
+ size(value: 'small' | 'medium' | 'large'): this {
81
+ this.state.size = value;
82
+ return this;
83
+ }
84
+
85
+ open(): this {
86
+ this.state.isOpen = true;
87
+ if (this.container) {
88
+ const modalEl = this.container.querySelector('.jux-modal');
89
+ if (modalEl) {
90
+ modalEl.classList.add('jux-modal-open');
91
+ }
92
+ }
93
+ this.emit('open');
94
+ return this;
95
+ }
96
+
97
+ close(): this {
98
+ this.state.isOpen = false;
99
+ if (this.container) {
100
+ const modalEl = this.container.querySelector('.jux-modal');
101
+ if (modalEl) {
102
+ modalEl.classList.remove('jux-modal-open');
103
+ }
104
+ }
105
+ this.emit('close');
106
+ return this;
107
+ }
108
+
109
+ /* -------------------------
110
+ * Render
111
+ * ------------------------- */
112
+
113
+ render(targetId?: string): this {
114
+ let container: HTMLElement;
115
+
116
+ if (targetId) {
117
+ const target = document.querySelector(targetId);
118
+ if (!target || !(target instanceof HTMLElement)) {
119
+ throw new Error(`Modal: Target element "${targetId}" not found`);
120
+ }
121
+ container = target;
122
+ } else {
123
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
124
+ }
125
+
126
+ this.container = container;
127
+ const { title, content, showCloseButton, closeOnBackdropClick, size, isOpen } = this.state;
128
+
129
+ // Modal backdrop
130
+ const modal = document.createElement('div');
131
+ modal.className = `jux-modal jux-modal-${size}`;
132
+ modal.id = this._componentId;
133
+
134
+ if (isOpen) {
135
+ modal.classList.add('jux-modal-open');
136
+ }
137
+
138
+ // Modal dialog
139
+ const dialog = document.createElement('div');
140
+ dialog.className = 'jux-modal-dialog';
141
+
142
+ // Modal header
143
+ if (title || showCloseButton) {
144
+ const header = document.createElement('div');
145
+ header.className = 'jux-modal-header';
146
+
147
+ if (title) {
148
+ const titleEl = document.createElement('h3');
149
+ titleEl.className = 'jux-modal-title';
150
+ titleEl.textContent = title;
151
+ header.appendChild(titleEl);
152
+ }
153
+
154
+ if (showCloseButton) {
155
+ const closeBtn = document.createElement('button');
156
+ closeBtn.className = 'jux-modal-close';
157
+ closeBtn.innerHTML = '×';
158
+ header.appendChild(closeBtn);
159
+
160
+ // Event binding - close button
161
+ closeBtn.addEventListener('click', () => this.close());
162
+ }
163
+
164
+ dialog.appendChild(header);
165
+ }
166
+
167
+ // Modal body
168
+ const body = document.createElement('div');
169
+ body.className = 'jux-modal-body';
170
+ body.innerHTML = content;
171
+ dialog.appendChild(body);
172
+
173
+ modal.appendChild(dialog);
174
+ container.appendChild(modal);
175
+
176
+ // Event binding - backdrop click
177
+ if (closeOnBackdropClick) {
178
+ modal.addEventListener('click', (e) => {
179
+ if (e.target === modal) {
180
+ this.close();
181
+ }
182
+ });
183
+ }
184
+
185
+ // Event binding - escape key
186
+ document.addEventListener('keydown', (e) => {
187
+ if (e.key === 'Escape' && this.state.isOpen) {
188
+ this.close();
189
+ }
190
+ });
191
+
192
+ return this;
193
+ }
194
+
195
+ /**
196
+ * Render to another Jux component's container
197
+ */
198
+ renderTo(juxComponent: any): this {
199
+ if (!juxComponent || typeof juxComponent !== 'object') {
200
+ throw new Error('Modal.renderTo: Invalid component - not an object');
201
+ }
202
+
203
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
204
+ throw new Error('Modal.renderTo: Invalid component - missing _componentId (not a Jux component)');
205
+ }
206
+
207
+ return this.render(`#${juxComponent._componentId}`);
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Factory helper
213
+ */
214
+ export function modal(componentId: string, options: ModalOptions = {}): Modal {
215
+ return new Modal(componentId, options);
216
+ }
@@ -0,0 +1,136 @@
1
+ import { Reactive, getOrCreateContainer } from './reactivity.js';
2
+
3
+ /**
4
+ * Nav item configuration
5
+ */
6
+ export interface NavItem {
7
+ label: string;
8
+ href: string;
9
+ active?: boolean;
10
+ }
11
+
12
+ /**
13
+ * Nav component options
14
+ */
15
+ export interface NavOptions {
16
+ items?: NavItem[];
17
+ variant?: 'default' | 'pills' | 'tabs';
18
+ }
19
+
20
+ /**
21
+ * Nav component state
22
+ */
23
+ type NavState = {
24
+ items: NavItem[];
25
+ variant: string;
26
+ };
27
+
28
+ /**
29
+ * Nav component
30
+ *
31
+ * Usage:
32
+ * const nav = jux.nav('myNav', {
33
+ * variant: 'pills',
34
+ * items: [
35
+ * { label: 'Home', href: '/', active: true },
36
+ * { label: 'About', href: '/about' }
37
+ * ]
38
+ * });
39
+ * nav.render();
40
+ */
41
+ export class Nav extends Reactive {
42
+ state!: NavState;
43
+ container: HTMLElement | null = null;
44
+
45
+ constructor(componentId: string, options: NavOptions = {}) {
46
+ super();
47
+ this._setComponentId(componentId);
48
+
49
+ this.state = this._createReactiveState({
50
+ items: options.items ?? [],
51
+ variant: options.variant ?? 'default'
52
+ }) as NavState;
53
+ }
54
+
55
+ /* -------------------------
56
+ * Fluent API
57
+ * ------------------------- */
58
+
59
+ items(value: NavItem[]): this {
60
+ this.state.items = value;
61
+ return this;
62
+ }
63
+
64
+ addItem(item: NavItem): this {
65
+ this.state.items.push(item);
66
+ return this;
67
+ }
68
+
69
+ variant(value: string): this {
70
+ this.state.variant = value;
71
+ return this;
72
+ }
73
+
74
+ /* -------------------------
75
+ * Render
76
+ * ------------------------- */
77
+
78
+ render(targetId?: string): this {
79
+ let container: HTMLElement;
80
+
81
+ if (targetId) {
82
+ const target = document.querySelector(targetId);
83
+ if (!target || !(target instanceof HTMLElement)) {
84
+ throw new Error(`Nav: Target element "${targetId}" not found`);
85
+ }
86
+ container = target;
87
+ } else {
88
+ container = getOrCreateContainer(this._componentId) as HTMLElement;
89
+ }
90
+
91
+ this.container = container;
92
+ const { items, variant } = this.state;
93
+
94
+ const nav = document.createElement('nav');
95
+ nav.className = `jux-nav jux-nav-${variant}`;
96
+ nav.id = this._componentId;
97
+
98
+ items.forEach(item => {
99
+ const link = document.createElement('a');
100
+ link.className = 'jux-nav-item';
101
+ link.href = item.href;
102
+ link.textContent = item.label;
103
+
104
+ if (item.active) {
105
+ link.classList.add('jux-nav-item-active');
106
+ }
107
+
108
+ nav.appendChild(link);
109
+ });
110
+
111
+ container.appendChild(nav);
112
+ return this;
113
+ }
114
+
115
+ /**
116
+ * Render to another Jux component's container
117
+ */
118
+ renderTo(juxComponent: any): this {
119
+ if (!juxComponent || typeof juxComponent !== 'object') {
120
+ throw new Error('Nav.renderTo: Invalid component - not an object');
121
+ }
122
+
123
+ if (!juxComponent._componentId || typeof juxComponent._componentId !== 'string') {
124
+ throw new Error('Nav.renderTo: Invalid component - missing _componentId (not a Jux component)');
125
+ }
126
+
127
+ return this.render(`#${juxComponent._componentId}`);
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Factory helper
133
+ */
134
+ export function nav(componentId: string, options: NavOptions = {}): Nav {
135
+ return new Nav(componentId, options);
136
+ }