juxscript 1.0.18 → 1.0.20

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 (44) hide show
  1. package/lib/components/alert.ts +124 -128
  2. package/lib/components/areachart.ts +169 -287
  3. package/lib/components/areachartsmooth.ts +2 -2
  4. package/lib/components/badge.ts +63 -72
  5. package/lib/components/barchart.ts +120 -48
  6. package/lib/components/button.ts +99 -101
  7. package/lib/components/card.ts +97 -121
  8. package/lib/components/chart-types.ts +159 -0
  9. package/lib/components/chart-utils.ts +160 -0
  10. package/lib/components/chart.ts +628 -48
  11. package/lib/components/checkbox.ts +137 -51
  12. package/lib/components/code.ts +89 -75
  13. package/lib/components/container.ts +1 -1
  14. package/lib/components/datepicker.ts +93 -78
  15. package/lib/components/dialog.ts +163 -130
  16. package/lib/components/divider.ts +111 -193
  17. package/lib/components/docs-data.json +711 -264
  18. package/lib/components/doughnutchart.ts +125 -57
  19. package/lib/components/dropdown.ts +172 -85
  20. package/lib/components/element.ts +66 -61
  21. package/lib/components/fileupload.ts +142 -171
  22. package/lib/components/heading.ts +64 -21
  23. package/lib/components/hero.ts +109 -34
  24. package/lib/components/icon.ts +247 -0
  25. package/lib/components/icons.ts +174 -0
  26. package/lib/components/include.ts +77 -2
  27. package/lib/components/input.ts +174 -125
  28. package/lib/components/list.ts +120 -79
  29. package/lib/components/menu.ts +97 -2
  30. package/lib/components/modal.ts +144 -63
  31. package/lib/components/nav.ts +153 -52
  32. package/lib/components/paragraph.ts +78 -28
  33. package/lib/components/progress.ts +83 -107
  34. package/lib/components/radio.ts +151 -52
  35. package/lib/components/select.ts +110 -102
  36. package/lib/components/sidebar.ts +148 -105
  37. package/lib/components/switch.ts +124 -125
  38. package/lib/components/table.ts +214 -137
  39. package/lib/components/tabs.ts +194 -113
  40. package/lib/components/theme-toggle.ts +38 -7
  41. package/lib/components/tooltip.ts +207 -47
  42. package/lib/jux.ts +24 -5
  43. package/lib/reactivity/state.ts +13 -299
  44. package/package.json +1 -2
@@ -1,233 +1,151 @@
1
- /**
2
- * Divider - Simple horizontal or vertical divider line
3
- */
1
+ import { getOrCreateContainer } from './helpers.js';
2
+ import { State } from '../reactivity/state.js';
4
3
 
5
4
  export interface DividerOptions {
5
+ text?: string;
6
6
  orientation?: 'horizontal' | 'vertical';
7
- thickness?: number;
8
- color?: string;
9
- margin?: string;
10
7
  style?: string;
11
- className?: string;
8
+ class?: string;
12
9
  }
13
10
 
14
- /**
15
- * Divider component for visual separation
16
- *
17
- * Usage:
18
- * // Simple horizontal divider
19
- * jux.divider().render('#container');
20
- *
21
- * // Vertical divider
22
- * jux.divider({ orientation: 'vertical' }).render('#container');
23
- *
24
- * // Custom styling
25
- * jux.divider({
26
- * thickness: 2,
27
- * color: '#3b82f6',
28
- * margin: '24px 0'
29
- * }).render('#container');
30
- *
31
- * // With custom class
32
- * jux.divider({ className: 'my-divider' }).render('#container');
33
- */
11
+ type DividerState = {
12
+ text: string;
13
+ orientation: string;
14
+ style: string;
15
+ class: string;
16
+ };
17
+
34
18
  export class Divider {
35
- private options: Required<DividerOptions>;
36
-
37
- constructor(options: DividerOptions = {}) {
38
- this.options = {
39
- orientation: 'horizontal',
40
- thickness: 1,
41
- color: '#e5e7eb',
42
- margin: '16px 0',
43
- style: '',
44
- className: '',
45
- ...options
19
+ state: DividerState;
20
+ container: HTMLElement | null = null;
21
+ _id: string;
22
+ id: string;
23
+
24
+ // CRITICAL: Store bind/sync instructions for deferred wiring
25
+ private _bindings: Array<{ event: string, handler: Function }> = [];
26
+ private _syncBindings: Array<{
27
+ property: string,
28
+ stateObj: State<any>,
29
+ toState?: Function,
30
+ toComponent?: Function
31
+ }> = [];
32
+
33
+ constructor(id: string, options: DividerOptions = {}) {
34
+ this._id = id;
35
+ this.id = id;
36
+
37
+ this.state = {
38
+ text: options.text ?? '',
39
+ orientation: options.orientation ?? 'horizontal',
40
+ style: options.style ?? '',
41
+ class: options.class ?? ''
46
42
  };
47
43
  }
48
44
 
49
- /**
50
- * Set orientation
51
- */
52
- orientation(value: 'horizontal' | 'vertical'): this {
53
- this.options.orientation = value;
45
+ text(value: string): this {
46
+ this.state.text = value;
54
47
  return this;
55
48
  }
56
49
 
57
- /**
58
- * Set thickness in pixels
59
- */
60
- thickness(value: number): this {
61
- this.options.thickness = value;
50
+ orientation(value: 'horizontal' | 'vertical'): this {
51
+ this.state.orientation = value;
62
52
  return this;
63
53
  }
64
54
 
65
- /**
66
- * Set color
67
- */
68
- color(value: string): this {
69
- this.options.color = value;
55
+ style(value: string): this {
56
+ this.state.style = value;
70
57
  return this;
71
58
  }
72
59
 
73
- /**
74
- * Set margin
75
- */
76
- margin(value: string): this {
77
- this.options.margin = value;
60
+ class(value: string): this {
61
+ this.state.class = value;
78
62
  return this;
79
63
  }
80
64
 
81
- /**
82
- * Set custom styles
83
- */
84
- style(value: string): this {
85
- this.options.style = value;
65
+ bind(event: string, handler: Function): this {
66
+ this._bindings.push({ event, handler });
86
67
  return this;
87
68
  }
88
69
 
89
- /**
90
- * Set class name
91
- */
92
- className(value: string): this {
93
- this.options.className = value;
94
- return this;
95
- }
96
-
97
- /**
98
- * Render divider to target element
99
- */
100
- render(targetSelector: string): this {
101
- const target = document.querySelector(targetSelector);
102
-
103
- if (!target || !(target instanceof HTMLElement)) {
104
- console.warn(`Divider: Target element "${targetSelector}" not found`);
105
- return this;
70
+ sync(property: string, stateObj: State<any>, toState?: Function, toComponent?: Function): this {
71
+ if (!stateObj || typeof stateObj.subscribe !== 'function') {
72
+ throw new Error(`Divider.sync: Expected a State object for property "${property}"`);
106
73
  }
107
-
108
- const divider = document.createElement('hr');
109
- divider.className = `jux-divider ${this.options.className}`.trim();
110
-
111
- const isVertical = this.options.orientation === 'vertical';
112
-
113
- const baseStyles = `
114
- border: none;
115
- background-color: ${this.options.color};
116
- margin: ${this.options.margin};
117
- ${isVertical ? `
118
- width: ${this.options.thickness}px;
119
- height: 100%;
120
- display: inline-block;
121
- vertical-align: middle;
122
- ` : `
123
- width: 100%;
124
- height: ${this.options.thickness}px;
125
- `}
126
- ${this.options.style}
127
- `;
128
-
129
- divider.setAttribute('style', baseStyles);
130
-
131
- target.appendChild(divider);
132
-
74
+ this._syncBindings.push({ property, stateObj, toState, toComponent });
133
75
  return this;
134
76
  }
135
77
 
136
- /**
137
- * Replace target content with divider
138
- */
139
- replace(targetSelector: string): this {
140
- const target = document.querySelector(targetSelector);
141
-
142
- if (!target || !(target instanceof HTMLElement)) {
143
- console.warn(`Divider: Target element "${targetSelector}" not found`);
144
- return this;
78
+ render(targetId?: string): this {
79
+ // === 1. SETUP: Get or create container ===
80
+ let container: HTMLElement;
81
+ if (targetId) {
82
+ const target = document.querySelector(targetId);
83
+ if (!target || !(target instanceof HTMLElement)) {
84
+ throw new Error(`Divider: Target "${targetId}" not found`);
85
+ }
86
+ container = target;
87
+ } else {
88
+ container = getOrCreateContainer(this._id);
145
89
  }
146
-
147
- target.innerHTML = '';
148
- return this.render(targetSelector);
149
- }
150
-
151
- /**
152
- * Render before target element
153
- */
154
- before(targetSelector: string): this {
155
- const target = document.querySelector(targetSelector);
156
-
157
- if (!target || !(target instanceof HTMLElement)) {
158
- console.warn(`Divider: Target element "${targetSelector}" not found`);
159
- return this;
90
+ this.container = container;
91
+
92
+ // === 2. PREPARE: Destructure state ===
93
+ const { text, orientation, style, class: className } = this.state;
94
+
95
+ // === 3. BUILD: Create DOM elements ===
96
+ const divider = document.createElement('div');
97
+ divider.className = `jux-divider jux-divider-${orientation}`;
98
+ divider.id = this._id;
99
+ if (className) divider.className += ` ${className}`;
100
+ if (style) divider.setAttribute('style', style);
101
+
102
+ if (text) {
103
+ const textEl = document.createElement('span');
104
+ textEl.className = 'jux-divider-text';
105
+ textEl.textContent = text;
106
+ divider.appendChild(textEl);
107
+ } else {
108
+ const line = document.createElement('hr');
109
+ line.className = 'jux-divider-line';
110
+ divider.appendChild(line);
160
111
  }
161
112
 
162
- const divider = document.createElement('hr');
163
- divider.className = `jux-divider ${this.options.className}`.trim();
164
-
165
- const isVertical = this.options.orientation === 'vertical';
166
-
167
- const baseStyles = `
168
- border: none;
169
- background-color: ${this.options.color};
170
- margin: ${this.options.margin};
171
- ${isVertical ? `
172
- width: ${this.options.thickness}px;
173
- height: 100%;
174
- display: inline-block;
175
- vertical-align: middle;
176
- ` : `
177
- width: 100%;
178
- height: ${this.options.thickness}px;
179
- `}
180
- ${this.options.style}
181
- `;
182
-
183
- divider.setAttribute('style', baseStyles);
184
- target.parentNode?.insertBefore(divider, target);
185
-
113
+ // === 4. WIRE: Attach event listeners and sync bindings ===
114
+
115
+ // Wire custom bindings from .bind() calls
116
+ this._bindings.forEach(({ event, handler }) => {
117
+ divider.addEventListener(event, handler as EventListener);
118
+ });
119
+
120
+ // Wire sync bindings from .sync() calls
121
+ this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
122
+ if (property === 'text') {
123
+ const transformToComponent = toComponent || ((v: any) => String(v));
124
+
125
+ stateObj.subscribe((val: any) => {
126
+ const transformed = transformToComponent(val);
127
+ const textEl = divider.querySelector('.jux-divider-text');
128
+ if (textEl) {
129
+ textEl.textContent = transformed;
130
+ }
131
+ this.state.text = transformed;
132
+ });
133
+ }
134
+ });
135
+
136
+ // === 5. RENDER: Append to DOM and finalize ===
137
+ container.appendChild(divider);
186
138
  return this;
187
139
  }
188
140
 
189
- /**
190
- * Render after target element
191
- */
192
- after(targetSelector: string): this {
193
- const target = document.querySelector(targetSelector);
194
-
195
- if (!target || !(target instanceof HTMLElement)) {
196
- console.warn(`Divider: Target element "${targetSelector}" not found`);
197
- return this;
141
+ renderTo(juxComponent: any): this {
142
+ if (!juxComponent?._id) {
143
+ throw new Error('Divider.renderTo: Invalid component');
198
144
  }
199
-
200
- const divider = document.createElement('hr');
201
- divider.className = `jux-divider ${this.options.className}`.trim();
202
-
203
- const isVertical = this.options.orientation === 'vertical';
204
-
205
- const baseStyles = `
206
- border: none;
207
- background-color: ${this.options.color};
208
- margin: ${this.options.margin};
209
- ${isVertical ? `
210
- width: ${this.options.thickness}px;
211
- height: 100%;
212
- display: inline-block;
213
- vertical-align: middle;
214
- ` : `
215
- width: 100%;
216
- height: ${this.options.thickness}px;
217
- `}
218
- ${this.options.style}
219
- `;
220
-
221
- divider.setAttribute('style', baseStyles);
222
- target.parentNode?.insertBefore(divider, target.nextSibling);
223
-
224
- return this;
145
+ return this.render(`#${juxComponent._id}`);
225
146
  }
226
147
  }
227
148
 
228
- /**
229
- * Factory function for quick divider creation
230
- */
231
- export function divider(options: DividerOptions = {}): Divider {
232
- return new Divider(options);
149
+ export function divider(id: string, options: DividerOptions = {}): Divider {
150
+ return new Divider(id, options);
233
151
  }