juxscript 1.1.2 → 1.1.4

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 (67) hide show
  1. package/machinery/build3.js +7 -91
  2. package/machinery/compiler3.js +3 -209
  3. package/machinery/config.js +93 -6
  4. package/machinery/serve.js +255 -0
  5. package/machinery/watcher.js +49 -161
  6. package/package.json +19 -5
  7. package/lib/components/alert.ts +0 -200
  8. package/lib/components/app.ts +0 -247
  9. package/lib/components/badge.ts +0 -101
  10. package/lib/components/base/BaseComponent.ts +0 -421
  11. package/lib/components/base/FormInput.ts +0 -227
  12. package/lib/components/button.ts +0 -178
  13. package/lib/components/card.ts +0 -173
  14. package/lib/components/chart.ts +0 -231
  15. package/lib/components/checkbox.ts +0 -242
  16. package/lib/components/code.ts +0 -123
  17. package/lib/components/container.ts +0 -140
  18. package/lib/components/data.ts +0 -135
  19. package/lib/components/datepicker.ts +0 -234
  20. package/lib/components/dialog.ts +0 -172
  21. package/lib/components/divider.ts +0 -100
  22. package/lib/components/dropdown.ts +0 -186
  23. package/lib/components/element.ts +0 -267
  24. package/lib/components/fileupload.ts +0 -309
  25. package/lib/components/grid.ts +0 -291
  26. package/lib/components/guard.ts +0 -92
  27. package/lib/components/heading.ts +0 -96
  28. package/lib/components/helpers.ts +0 -41
  29. package/lib/components/hero.ts +0 -224
  30. package/lib/components/icon.ts +0 -178
  31. package/lib/components/icons.ts +0 -464
  32. package/lib/components/include.ts +0 -410
  33. package/lib/components/input.ts +0 -457
  34. package/lib/components/list.ts +0 -419
  35. package/lib/components/loading.ts +0 -100
  36. package/lib/components/menu.ts +0 -275
  37. package/lib/components/modal.ts +0 -284
  38. package/lib/components/nav.ts +0 -257
  39. package/lib/components/paragraph.ts +0 -97
  40. package/lib/components/progress.ts +0 -159
  41. package/lib/components/radio.ts +0 -278
  42. package/lib/components/req.ts +0 -303
  43. package/lib/components/script.ts +0 -41
  44. package/lib/components/select.ts +0 -252
  45. package/lib/components/sidebar.ts +0 -275
  46. package/lib/components/style.ts +0 -41
  47. package/lib/components/switch.ts +0 -246
  48. package/lib/components/table.ts +0 -1249
  49. package/lib/components/tabs.ts +0 -250
  50. package/lib/components/theme-toggle.ts +0 -293
  51. package/lib/components/tooltip.ts +0 -144
  52. package/lib/components/view.ts +0 -190
  53. package/lib/components/write.ts +0 -272
  54. package/lib/layouts/default.css +0 -260
  55. package/lib/layouts/figma.css +0 -334
  56. package/lib/reactivity/state.ts +0 -78
  57. package/lib/utils/fetch.ts +0 -553
  58. package/machinery/ast.js +0 -347
  59. package/machinery/build.js +0 -466
  60. package/machinery/bundleAssets.js +0 -0
  61. package/machinery/bundleJux.js +0 -0
  62. package/machinery/bundleVendors.js +0 -0
  63. package/machinery/doc-generator.js +0 -136
  64. package/machinery/imports.js +0 -155
  65. package/machinery/server.js +0 -166
  66. package/machinery/ts-shim.js +0 -46
  67. package/machinery/validators/file-validator.js +0 -123
@@ -1,242 +0,0 @@
1
- import { FormInput, FormInputState } from './base/FormInput.js';
2
- import { renderIcon } from './icons.js';
3
-
4
- // Event definitions
5
- const TRIGGER_EVENTS = [] as const;
6
- const CALLBACK_EVENTS = ['change'] as const;
7
-
8
- export interface CheckboxOptions {
9
- checked?: boolean;
10
- label?: string;
11
- required?: boolean;
12
- disabled?: boolean;
13
- name?: string;
14
- value?: string;
15
- style?: string;
16
- class?: string;
17
- onValidate?: (checked: boolean) => boolean | string;
18
- }
19
-
20
- interface CheckboxState extends FormInputState {
21
- checked: boolean;
22
- value: string;
23
- }
24
-
25
- export class Checkbox extends FormInput<CheckboxState> {
26
- constructor(id: string, options: CheckboxOptions = {}) {
27
- super(id, {
28
- checked: options.checked ?? false,
29
- value: options.value ?? 'on',
30
- label: options.label ?? '',
31
- required: options.required ?? false,
32
- disabled: options.disabled ?? false,
33
- name: options.name ?? id,
34
- style: options.style ?? '',
35
- class: options.class ?? '',
36
- errorMessage: undefined
37
- });
38
-
39
- if (options.onValidate) {
40
- this._onValidate = options.onValidate;
41
- }
42
- }
43
-
44
- protected getTriggerEvents(): readonly string[] {
45
- return TRIGGER_EVENTS;
46
- }
47
-
48
- protected getCallbackEvents(): readonly string[] {
49
- return CALLBACK_EVENTS;
50
- }
51
-
52
- /* ═════════════════════════════════════════════════════════════════
53
- * FLUENT API
54
- * ═════════════════════════════════════════════════════════════════ */
55
-
56
- // ✅ Inherited from FormInput/BaseComponent:
57
- // - label(), required(), name(), onValidate()
58
- // - validate(), isValid()
59
- // - style(), class()
60
- // - bind(), sync(), renderTo()
61
- // - disabled(), enable(), disable()
62
-
63
- checked(value: boolean): this {
64
- return this.setValue(value);
65
- }
66
-
67
- value(value: string): this {
68
- this.state.value = value;
69
- return this;
70
- }
71
-
72
- /* ═════════════════════════════════════════════════════════════════
73
- * FORM INPUT IMPLEMENTATION
74
- * ═════════════════════════════════════════════════════════════════ */
75
-
76
- getValue(): boolean {
77
- return this.state.checked;
78
- }
79
-
80
- setValue(value: boolean): this {
81
- this.state.checked = value;
82
- if (this._inputElement) {
83
- (this._inputElement as HTMLInputElement).checked = value;
84
- }
85
- return this;
86
- }
87
-
88
- protected _validateValue(checked: boolean): boolean | string {
89
- const { required } = this.state;
90
-
91
- if (required && !checked) {
92
- return 'This field must be checked';
93
- }
94
-
95
- if (this._onValidate) {
96
- const result = this._onValidate(checked);
97
- if (result !== true) {
98
- return result || 'Invalid value';
99
- }
100
- }
101
-
102
- return true;
103
- }
104
-
105
- protected _buildInputElement(): HTMLElement {
106
- const { checked, value, required, disabled, name } = this.state;
107
-
108
- const input = document.createElement('input');
109
- input.type = 'checkbox';
110
- input.className = 'jux-checkbox-input';
111
- input.id = `${this._id}-input`;
112
- input.name = name;
113
- input.value = value;
114
- input.checked = checked;
115
- input.required = required;
116
- input.disabled = disabled;
117
-
118
- return input;
119
- }
120
-
121
- /* ═════════════════════════════════════════════════════════════════
122
- * RENDER
123
- * ═════════════════════════════════════════════════════════════════ */
124
-
125
- render(targetId?: string): this {
126
- const container = this._setupContainer(targetId);
127
-
128
- const { style, class: className } = this.state;
129
-
130
- // Build wrapper
131
- const wrapper = document.createElement('div');
132
- wrapper.className = 'jux-checkbox';
133
- wrapper.id = this._id;
134
- if (className) wrapper.className += ` ${className}`;
135
- if (style) wrapper.setAttribute('style', style);
136
-
137
- // Checkbox container
138
- const checkboxContainer = document.createElement('label');
139
- checkboxContainer.className = 'jux-checkbox-container';
140
- checkboxContainer.htmlFor = `${this._id}-input`;
141
-
142
- // Input element
143
- const inputEl = this._buildInputElement() as HTMLInputElement;
144
- this._inputElement = inputEl;
145
- checkboxContainer.appendChild(inputEl);
146
-
147
- // Checkmark (custom styled)
148
- const checkmark = document.createElement('span');
149
- checkmark.className = 'jux-checkbox-checkmark';
150
- checkmark.appendChild(renderIcon('check'));
151
- checkboxContainer.appendChild(checkmark);
152
-
153
- // Label text
154
- if (this.state.label) {
155
- const labelText = document.createElement('span');
156
- labelText.className = 'jux-checkbox-label-text';
157
- labelText.textContent = this.state.label;
158
- if (this.state.required) {
159
- const requiredSpan = document.createElement('span');
160
- requiredSpan.className = 'jux-input-required';
161
- requiredSpan.textContent = ' *';
162
- labelText.appendChild(requiredSpan);
163
- }
164
- checkboxContainer.appendChild(labelText);
165
- }
166
-
167
- wrapper.appendChild(checkboxContainer);
168
-
169
- // Error element
170
- wrapper.appendChild(this._renderError());
171
-
172
- // Wire events
173
- this._wireStandardEvents(wrapper);
174
-
175
- // Wire checkbox-specific sync (maps 'checked' to 'value' property for consistency)
176
- const valueSync = this._syncBindings.find(b => b.property === 'value' || b.property === 'checked');
177
-
178
- if (valueSync) {
179
- const { stateObj, toState, toComponent } = valueSync;
180
-
181
- const transformToState = toState || ((v: boolean) => v);
182
- const transformToComponent = toComponent || ((v: any) => Boolean(v));
183
-
184
- let isUpdating = false;
185
-
186
- // State → Component
187
- stateObj.subscribe((val: any) => {
188
- if (isUpdating) return;
189
- const transformed = transformToComponent(val);
190
- this.setValue(transformed);
191
- });
192
-
193
- // Component → State
194
- inputEl.addEventListener('change', () => {
195
- if (isUpdating) return;
196
- isUpdating = true;
197
-
198
- const checked = inputEl.checked;
199
- this.state.checked = checked;
200
- this._clearError();
201
-
202
- const transformed = transformToState(checked);
203
- stateObj.set(transformed);
204
-
205
- // 🎯 Fire the change callback event
206
- this._triggerCallback('change', checked);
207
-
208
- setTimeout(() => { isUpdating = false; }, 0);
209
- });
210
- } else {
211
- // Default behavior without sync
212
- inputEl.addEventListener('change', () => {
213
- this.state.checked = inputEl.checked;
214
- this._clearError();
215
-
216
- // 🎯 Fire the change callback event
217
- this._triggerCallback('change', inputEl.checked);
218
- });
219
- }
220
-
221
- // Always add blur validation
222
- inputEl.addEventListener('blur', () => {
223
- this.validate();
224
- });
225
-
226
- // Sync label changes
227
- const labelSync = this._syncBindings.find(b => b.property === 'label');
228
- if (labelSync) {
229
- const transform = labelSync.toComponent || ((v: any) => String(v));
230
- labelSync.stateObj.subscribe((val: any) => {
231
- this.label(transform(val));
232
- });
233
- }
234
-
235
- container.appendChild(wrapper);
236
- return this;
237
- }
238
- }
239
-
240
- export function checkbox(id: string, options: CheckboxOptions = {}): Checkbox {
241
- return new Checkbox(id, options);
242
- }
@@ -1,123 +0,0 @@
1
- import { BaseComponent } from './base/BaseComponent.js';
2
-
3
- // Event definitions
4
- const TRIGGER_EVENTS = [] as const;
5
- const CALLBACK_EVENTS = [] as const;
6
-
7
- export interface CodeOptions {
8
- code?: string;
9
- language?: string;
10
- style?: string;
11
- class?: string;
12
- }
13
-
14
- type CodeState = {
15
- code: string;
16
- language: string;
17
- style: string;
18
- class: string;
19
- };
20
-
21
- export class Code extends BaseComponent<CodeState> {
22
- constructor(id: string, options: CodeOptions = {}) {
23
- super(id, {
24
- code: options.code ?? '',
25
- language: options.language ?? 'javascript',
26
- style: options.style ?? '',
27
- class: options.class ?? ''
28
- });
29
- }
30
-
31
- protected getTriggerEvents(): readonly string[] {
32
- return TRIGGER_EVENTS;
33
- }
34
-
35
- protected getCallbackEvents(): readonly string[] {
36
- return CALLBACK_EVENTS;
37
- }
38
-
39
- /* ═════════════════════════════════════════════════════════════════
40
- * FLUENT API
41
- * ═════════════════════════════════════════════════════════════════ */
42
-
43
- // ✅ Inherited from BaseComponent
44
-
45
- code(value: string): this {
46
- this.state.code = value;
47
- return this;
48
- }
49
-
50
- language(value: string): this {
51
- this.state.language = value;
52
- return this;
53
- }
54
-
55
- /* ═════════════════════════════════════════════════════════════════
56
- * RENDER
57
- * ═════════════════════════════════════════════════════════════════ */
58
-
59
- render(targetId?: string): this {
60
- const container = this._setupContainer(targetId);
61
-
62
- const { code, language, style, class: className } = this.state;
63
-
64
- const wrapper = document.createElement('div');
65
- wrapper.className = 'jux-code';
66
- wrapper.id = this._id;
67
- if (className) wrapper.className += ` ${className}`;
68
- if (style) wrapper.setAttribute('style', style);
69
-
70
- const pre = document.createElement('pre');
71
- const codeEl = document.createElement('code');
72
- codeEl.className = `language-${language}`;
73
- codeEl.textContent = code;
74
- pre.appendChild(codeEl);
75
- wrapper.appendChild(pre);
76
-
77
- this._wireStandardEvents(wrapper);
78
-
79
- // Wire sync bindings
80
- this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
81
- if (property === 'code') {
82
- const transform = toComponent || ((v: any) => String(v));
83
-
84
- stateObj.subscribe((val: any) => {
85
- const transformed = transform(val);
86
- codeEl.textContent = transformed;
87
- this.state.code = transformed;
88
-
89
- if ((window as any).Prism) {
90
- (window as any).Prism.highlightElement(codeEl);
91
- }
92
- });
93
- }
94
- else if (property === 'language') {
95
- const transform = toComponent || ((v: any) => String(v));
96
-
97
- stateObj.subscribe((val: any) => {
98
- const transformed = transform(val);
99
- codeEl.className = `language-${transformed}`;
100
- this.state.language = transformed;
101
-
102
- if ((window as any).Prism) {
103
- (window as any).Prism.highlightElement(codeEl);
104
- }
105
- });
106
- }
107
- });
108
-
109
- container.appendChild(wrapper);
110
-
111
- requestAnimationFrame(() => {
112
- if ((window as any).Prism) {
113
- (window as any).Prism.highlightElement(codeEl);
114
- }
115
- });
116
-
117
- return this;
118
- }
119
- }
120
-
121
- export function code(id: string, options: CodeOptions = {}): Code {
122
- return new Code(id, options);
123
- }
@@ -1,140 +0,0 @@
1
- import { BaseComponent } from './base/BaseComponent.js';
2
-
3
- // Event definitions - Container is a layout wrapper that can be clicked
4
- const TRIGGER_EVENTS = [] as const;
5
- const CALLBACK_EVENTS = ['click'] as const;
6
-
7
- /**
8
- * Container options
9
- */
10
- export interface ContainerOptions {
11
- class?: string;
12
- style?: string;
13
- direction?: 'row' | 'column';
14
- gap?: string | number;
15
- align?: 'start' | 'center' | 'end' | 'stretch';
16
- justify?: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly';
17
- }
18
-
19
- /**
20
- * Container state
21
- */
22
- type ContainerState = {
23
- class: string;
24
- style: string;
25
- direction?: 'row' | 'column';
26
- gap?: string | number;
27
- align?: string;
28
- justify?: string;
29
- };
30
-
31
- /**
32
- * Container component - a simple div container for grouping elements
33
- */
34
- export class Container extends BaseComponent<ContainerState> {
35
- constructor(id: string, options: ContainerOptions = {}) {
36
- super(id, {
37
- class: options.class ?? '',
38
- style: options.style ?? '',
39
- direction: options.direction,
40
- gap: options.gap,
41
- align: options.align,
42
- justify: options.justify
43
- });
44
- }
45
-
46
- protected getTriggerEvents(): readonly string[] {
47
- return TRIGGER_EVENTS;
48
- }
49
-
50
- protected getCallbackEvents(): readonly string[] {
51
- return CALLBACK_EVENTS;
52
- }
53
-
54
- /* -------------------------
55
- * Fluent API
56
- * ------------------------- */
57
-
58
- // ✅ Inherited from BaseComponent:
59
- // - style(), class()
60
- // - bind(), sync(), renderTo()
61
- // - addClass(), removeClass(), toggleClass()
62
- // - visible(), show(), hide()
63
- // - attr(), attrs(), removeAttr()
64
- // - disabled(), enable(), disable()
65
-
66
- direction(value: 'row' | 'column'): this {
67
- this.state.direction = value;
68
- return this;
69
- }
70
-
71
- gap(value: string | number): this {
72
- this.state.gap = value;
73
- return this;
74
- }
75
-
76
- align(value: 'start' | 'center' | 'end' | 'stretch'): this {
77
- this.state.align = value;
78
- return this;
79
- }
80
-
81
- justify(value: 'start' | 'center' | 'end' | 'space-between' | 'space-around' | 'space-evenly'): this {
82
- this.state.justify = value;
83
- return this;
84
- }
85
-
86
- /* -------------------------
87
- * Render
88
- * ------------------------- */
89
-
90
- render(targetId?: string): this {
91
- const container = this._setupContainer(targetId);
92
-
93
- const { class: className, style, direction, gap, align, justify } = this.state;
94
-
95
- const div = document.createElement('div');
96
- div.id = this._id;
97
-
98
- // Always include jux-container class, append custom classes
99
- div.className = className ? `jux-container ${className}` : 'jux-container';
100
-
101
- // Only apply flex styles if any flex properties are set
102
- const usesFlexbox = direction || gap !== undefined || align || justify;
103
-
104
- let computedStyle = style;
105
-
106
- if (usesFlexbox) {
107
- const flexStyles: string[] = ['display: flex', 'width: auto'];
108
-
109
- if (direction) flexStyles.push(`flex-direction: ${direction}`);
110
-
111
- if (gap !== undefined) {
112
- const gapValue = typeof gap === 'number' ? `${gap}px` : gap;
113
- flexStyles.push(`gap: ${gapValue}`);
114
- }
115
- // Only set align-items if explicitly specified
116
- if (align) flexStyles.push(`align-items: ${align}`);
117
- // Only set justify-content if explicitly specified
118
- if (justify) flexStyles.push(`justify-content: ${justify}`);
119
-
120
- computedStyle = `${flexStyles.join('; ')}; ${style}`.trim();
121
- }
122
-
123
- if (computedStyle) {
124
- div.setAttribute('style', computedStyle);
125
- }
126
-
127
- this._wireStandardEvents(div);
128
-
129
- container.appendChild(div);
130
-
131
- return this;
132
- }
133
- }
134
-
135
- /**
136
- * Factory helper
137
- */
138
- export function container(id: string, options: ContainerOptions = {}): Container {
139
- return new Container(id, options);
140
- }
@@ -1,135 +0,0 @@
1
- /**
2
- * Data component - SQL query execution
3
- * Note: No id needed - this is a data-only component
4
- *
5
- * Usage:
6
- * const posts = jux.data('SELECT * FROM posts WHERE id = ?', [1]);
7
- * await posts.execute();
8
- * console.log(posts.data);
9
- */
10
-
11
- export interface DataOptions {
12
- sql: string;
13
- params?: any[];
14
- apiUrl?: string;
15
- }
16
-
17
- export class Data {
18
- private _data: any[] = [];
19
- private _executed: boolean = false;
20
- private _loading: boolean = false;
21
- private _sql: string;
22
- private _params: any[];
23
- private _apiUrl: string;
24
-
25
- constructor(sql: string, params: any[] = [], apiUrl: string = '/api/query') {
26
- this._sql = sql;
27
- this._params = params;
28
- this._apiUrl = apiUrl;
29
- }
30
-
31
- /* -------------------------
32
- * Getters
33
- * ------------------------- */
34
-
35
- get data(): any[] {
36
- return this._data;
37
- }
38
-
39
- get executed(): boolean {
40
- return this._executed;
41
- }
42
-
43
- get loading(): boolean {
44
- return this._loading;
45
- }
46
-
47
- get sql(): string {
48
- return this._sql;
49
- }
50
-
51
- set sql(value: string) {
52
- this._sql = value;
53
- }
54
-
55
- /* -------------------------
56
- * Methods
57
- * ------------------------- */
58
-
59
- async execute(): Promise<void> {
60
- if (this._executed) return;
61
- this._loading = true;
62
-
63
- try {
64
- const response = await fetch(this._apiUrl, {
65
- method: 'POST',
66
- headers: {
67
- 'Content-Type': 'application/json'
68
- },
69
- body: JSON.stringify({
70
- sql: this._sql,
71
- params: this._params
72
- })
73
- });
74
-
75
- if (!response.ok) {
76
- throw new Error(`API error: ${response.statusText}`);
77
- }
78
-
79
- const result = await response.json();
80
- this._data = result.data || [];
81
- this._executed = true;
82
- } catch (error) {
83
- console.error('Data execution error:', error);
84
- this._data = [];
85
- throw error;
86
- } finally {
87
- this._loading = false;
88
- }
89
- }
90
-
91
- reset(): void {
92
- this._executed = false;
93
- this._data = [];
94
- this._loading = false;
95
- }
96
-
97
- // Remove id requirement, make it optional for caching
98
- static async fetch<T = any>(url: string, options?: RequestInit): Promise<T> {
99
- const response = await fetch(url, options);
100
- if (!response.ok) {
101
- throw new Error(`API error: ${response.statusText}`);
102
- }
103
- return response.json();
104
- }
105
-
106
- // ✅ Static methods - no ID needed
107
- static async post<T = any>(url: string, body: any, options?: RequestInit): Promise<T> {
108
- const response = await fetch(url, options);
109
- if (!response.ok) {
110
- throw new Error(`API error: ${response.statusText}`);
111
- }
112
- return response.json();
113
- }
114
-
115
- static async put<T = any>(url: string, body: any, options?: RequestInit): Promise<T> {
116
- const response = await fetch(url, options);
117
- if (!response.ok) {
118
- throw new Error(`API error: ${response.statusText}`);
119
- }
120
- return response.json();
121
- }
122
-
123
- static async delete<T = any>(url: string, options?: RequestInit): Promise<T> {
124
- const response = await fetch(url, options);
125
- if (!response.ok) {
126
- throw new Error(`API error: ${response.statusText}`);
127
- }
128
- return response.json();
129
- }
130
- }
131
-
132
- // ✅ No ID needed - pure data fetching
133
- export function data<T = any>(url: string, options?: RequestInit): Promise<T> {
134
- return Data.fetch<T>(url, options);
135
- }