juxscript 1.1.3 → 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 (63) hide show
  1. package/machinery/build3.js +7 -91
  2. package/machinery/compiler3.js +3 -209
  3. package/package.json +19 -5
  4. package/lib/components/alert.ts +0 -200
  5. package/lib/components/app.ts +0 -247
  6. package/lib/components/badge.ts +0 -101
  7. package/lib/components/base/BaseComponent.ts +0 -421
  8. package/lib/components/base/FormInput.ts +0 -227
  9. package/lib/components/button.ts +0 -178
  10. package/lib/components/card.ts +0 -173
  11. package/lib/components/chart.ts +0 -231
  12. package/lib/components/checkbox.ts +0 -242
  13. package/lib/components/code.ts +0 -123
  14. package/lib/components/container.ts +0 -140
  15. package/lib/components/data.ts +0 -135
  16. package/lib/components/datepicker.ts +0 -234
  17. package/lib/components/dialog.ts +0 -172
  18. package/lib/components/divider.ts +0 -100
  19. package/lib/components/dropdown.ts +0 -186
  20. package/lib/components/element.ts +0 -267
  21. package/lib/components/fileupload.ts +0 -309
  22. package/lib/components/grid.ts +0 -291
  23. package/lib/components/guard.ts +0 -92
  24. package/lib/components/heading.ts +0 -96
  25. package/lib/components/helpers.ts +0 -41
  26. package/lib/components/hero.ts +0 -224
  27. package/lib/components/icon.ts +0 -178
  28. package/lib/components/icons.ts +0 -464
  29. package/lib/components/include.ts +0 -410
  30. package/lib/components/input.ts +0 -457
  31. package/lib/components/list.ts +0 -419
  32. package/lib/components/loading.ts +0 -100
  33. package/lib/components/menu.ts +0 -275
  34. package/lib/components/modal.ts +0 -284
  35. package/lib/components/nav.ts +0 -257
  36. package/lib/components/paragraph.ts +0 -97
  37. package/lib/components/progress.ts +0 -159
  38. package/lib/components/radio.ts +0 -278
  39. package/lib/components/req.ts +0 -303
  40. package/lib/components/script.ts +0 -41
  41. package/lib/components/select.ts +0 -252
  42. package/lib/components/sidebar.ts +0 -275
  43. package/lib/components/style.ts +0 -41
  44. package/lib/components/switch.ts +0 -246
  45. package/lib/components/table.ts +0 -1249
  46. package/lib/components/tabs.ts +0 -250
  47. package/lib/components/theme-toggle.ts +0 -293
  48. package/lib/components/tooltip.ts +0 -144
  49. package/lib/components/view.ts +0 -190
  50. package/lib/components/write.ts +0 -272
  51. package/lib/layouts/default.css +0 -260
  52. package/lib/layouts/figma.css +0 -334
  53. package/lib/reactivity/state.ts +0 -78
  54. package/lib/utils/fetch.ts +0 -553
  55. package/machinery/ast.js +0 -347
  56. package/machinery/build.js +0 -466
  57. package/machinery/bundleAssets.js +0 -0
  58. package/machinery/bundleJux.js +0 -0
  59. package/machinery/bundleVendors.js +0 -0
  60. package/machinery/doc-generator.js +0 -136
  61. package/machinery/imports.js +0 -155
  62. package/machinery/ts-shim.js +0 -46
  63. 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
- }