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,11 +1,9 @@
1
1
  /**
2
- * Reactive state container
3
- * Notifies subscribers when value changes
2
+ * Simple reactive state container
4
3
  */
5
4
  export class State<T> {
6
5
  private _value: T;
7
6
  private _subscribers: Set<(value: T) => void> = new Set();
8
- private _effects: Set<Effect> = new Set();
9
7
 
10
8
  constructor(initialValue: T) {
11
9
  this._value = initialValue;
@@ -22,342 +20,58 @@ export class State<T> {
22
20
  * Set new value and notify subscribers
23
21
  */
24
22
  set(newValue: T): void {
25
- if (this._value !== newValue) {
26
- this._value = newValue;
27
- this._notify();
28
- this._runEffects();
29
- }
30
- }
31
-
32
- /**
33
- * Update value using a function
34
- */
35
- update(fn: (current: T) => T): void {
36
- this.set(fn(this._value));
23
+ this._value = newValue;
24
+ this._notify();
37
25
  }
38
26
 
39
27
  /**
40
28
  * Subscribe to value changes
41
- * Returns unsubscribe function
42
29
  */
43
30
  subscribe(callback: (value: T) => void): () => void {
44
31
  this._subscribers.add(callback);
45
- callback(this._value); // Call immediately with current value
32
+ // Call immediately with current value
33
+ callback(this._value);
34
+ // Return unsubscribe function
46
35
  return () => this._subscribers.delete(callback);
47
36
  }
48
37
 
49
38
  /**
50
- * Notify all subscribers of value change
39
+ * Notify all subscribers
51
40
  */
52
41
  private _notify(): void {
53
42
  this._subscribers.forEach(callback => callback(this._value));
54
43
  }
55
44
 
56
45
  /**
57
- * Run all registered effects
58
- */
59
- private _runEffects(): void {
60
- this._effects.forEach(effect => effect.run(this._value));
61
- }
62
-
63
- /* -------------------------
64
- * Higher-Order Effects
65
- * ------------------------- */
66
-
67
- /**
68
- * Bind visibility to element (v-show style)
69
- * Toggles display: none on/off
70
- * For animations, use bindClass() instead
71
- */
72
- bindVisibility(elementId: string): () => void {
73
- if (typeof this._value !== 'boolean') {
74
- console.warn(`State.bindVisibility: State value must be boolean, got ${typeof this._value}`);
75
- return () => { };
76
- }
77
-
78
- const effect = new VisibilityEffect(elementId);
79
- this._effects.add(effect);
80
- effect.run(this._value); // Initial run
81
-
82
- return () => this._effects.delete(effect);
83
- }
84
-
85
- /**
86
- * Bind value property to element (for progress, input, range, etc.)
87
- * @param elementId - DOM element ID
88
- * @param transform - Optional transform function
89
- */
90
- bindValue(elementId: string, transform?: (val: T) => number | string): () => void {
91
- const effect = new ValueEffect(elementId, transform);
92
- this._effects.add(effect);
93
- effect.run(this._value);
94
-
95
- return () => this._effects.delete(effect);
96
- }
97
-
98
- /**
99
- * Bind text content to element
100
- * @param elementId - DOM element ID
101
- * @param transform - Optional transform function
46
+ * Helper methods for numeric state
102
47
  */
103
- bindText(elementId: string, transform?: (val: T) => string): () => void {
104
- const effect = new TextEffect(elementId, transform);
105
- this._effects.add(effect);
106
- effect.run(this._value);
107
-
108
- return () => this._effects.delete(effect);
109
- }
110
-
111
- /**
112
- * Bind attribute to element
113
- * @param elementId - DOM element ID
114
- * @param attrName - Attribute name
115
- * @param transform - Optional transform function
116
- */
117
- bindAttr(elementId: string, attrName: string, transform?: (val: T) => string): () => void {
118
- const effect = new AttrEffect(elementId, attrName, transform);
119
- this._effects.add(effect);
120
- effect.run(this._value);
121
-
122
- return () => this._effects.delete(effect);
123
- }
124
-
125
- /**
126
- * Bind CSS class to element
127
- * @param elementId - DOM element ID
128
- * @param className - Class to toggle
129
- * @param condition - Optional condition function
130
- */
131
- bindClass(elementId: string, className: string, condition?: (val: T) => boolean): () => void {
132
- const effect = new ClassEffect(elementId, className, condition);
133
- this._effects.add(effect);
134
- effect.run(this._value);
135
-
136
- return () => this._effects.delete(effect);
137
- }
138
-
139
- /**
140
- * Bind innerHTML to element
141
- * @param elementId - DOM element ID
142
- * @param transform - Optional transform function
143
- */
144
- bindHTML(elementId: string, transform?: (val: T) => string): () => void {
145
- const effect = new HTMLEffect(elementId, transform);
146
- this._effects.add(effect);
147
- effect.run(this._value);
148
-
149
- return () => this._effects.delete(effect);
150
- }
151
-
152
- /* -------------------------
153
- * Number Helpers
154
- * ------------------------- */
155
-
156
- /**
157
- * Increment (numbers only)
158
- */
159
- increment = (): void => {
48
+ increment(): void {
160
49
  if (typeof this._value === 'number') {
161
50
  this.set((this._value + 1) as T);
162
51
  }
163
52
  }
164
53
 
165
- /**
166
- * Decrement (numbers only)
167
- */
168
- decrement = (): void => {
54
+ decrement(): void {
169
55
  if (typeof this._value === 'number') {
170
56
  this.set((this._value - 1) as T);
171
57
  }
172
58
  }
173
59
 
174
- /**
175
- * Add amount (returns function for event handlers)
176
- */
177
- add = (amount: number) => (): void => {
60
+ add(amount: number): void {
178
61
  if (typeof this._value === 'number') {
179
62
  this.set((this._value + amount) as T);
180
63
  }
181
64
  }
182
65
 
183
- /**
184
- * Subtract amount
185
- */
186
- subtract = (amount: number) => (): void => {
66
+ subtract(amount: number): void {
187
67
  if (typeof this._value === 'number') {
188
68
  this.set((this._value - amount) as T);
189
69
  }
190
70
  }
191
-
192
- /**
193
- * Multiply by factor
194
- */
195
- multiply = (factor: number) => (): void => {
196
- if (typeof this._value === 'number') {
197
- this.set((this._value * factor) as T);
198
- }
199
- }
200
-
201
- /* -------------------------
202
- * Boolean Helpers
203
- * ------------------------- */
204
-
205
- /**
206
- * Toggle (booleans only)
207
- */
208
- toggle = (): void => {
209
- if (typeof this._value === 'boolean') {
210
- this.set((!this._value) as T);
211
- }
212
- }
213
-
214
- /* -------------------------
215
- * General Helpers
216
- * ------------------------- */
217
-
218
- /**
219
- * Reset to initial value (returns function)
220
- */
221
- reset = (initialValue: T) => (): void => {
222
- this.set(initialValue);
223
- }
224
- }
225
-
226
- /* -------------------------
227
- * Effect Classes
228
- * ------------------------- */
229
-
230
- interface Effect {
231
- run(value: any): void;
232
- }
233
-
234
- class VisibilityEffect implements Effect {
235
- constructor(
236
- private elementId: string
237
- ) { }
238
-
239
- run(visible: boolean): void {
240
- const el = document.getElementById(this.elementId);
241
- if (!el) return;
242
-
243
- // Simple display toggle (Vue v-show style)
244
- el.style.display = visible ? '' : 'none';
245
- }
246
- }
247
-
248
- interface VisibilityOptions {
249
- mode?: 'display' | 'visibility' | 'opacity' | 'class';
250
- visibleClass?: string;
251
- hiddenClass?: string;
252
- }
253
-
254
- class TextEffect implements Effect {
255
- constructor(
256
- private elementId: string,
257
- private transform?: (val: any) => string
258
- ) { }
259
-
260
- run(value: any): void {
261
- const el = document.getElementById(this.elementId);
262
- if (!el) return;
263
-
264
- const text = this.transform ? this.transform(value) : String(value);
265
- el.textContent = text;
266
- }
267
- }
268
-
269
- class HTMLEffect implements Effect {
270
- constructor(
271
- private elementId: string,
272
- private transform?: (val: any) => string
273
- ) { }
274
-
275
- run(value: any): void {
276
- const el = document.getElementById(this.elementId);
277
- if (!el) return;
278
-
279
- const html = this.transform ? this.transform(value) : String(value);
280
- el.innerHTML = html;
281
- }
282
- }
283
-
284
- class AttrEffect implements Effect {
285
- constructor(
286
- private elementId: string,
287
- private attrName: string,
288
- private transform?: (val: any) => string
289
- ) { }
290
-
291
- run(value: any): void {
292
- const el = document.getElementById(this.elementId);
293
- if (!el) return;
294
-
295
- const attrValue = this.transform ? this.transform(value) : String(value);
296
- el.setAttribute(this.attrName, attrValue);
297
- }
298
- }
299
-
300
- class ClassEffect implements Effect {
301
- constructor(
302
- private elementId: string,
303
- private className: string,
304
- private condition?: (val: any) => boolean
305
- ) { }
306
-
307
- run(value: any): void {
308
- const el = document.getElementById(this.elementId);
309
- if (!el) return;
310
-
311
- const shouldAdd = this.condition ? this.condition(value) : Boolean(value);
312
- if (shouldAdd) {
313
- el.classList.add(this.className);
314
- } else {
315
- el.classList.remove(this.className);
316
- }
317
- }
318
- }
319
-
320
- class ValueEffect implements Effect {
321
- constructor(
322
- private elementId: string,
323
- private transform?: (val: any) => number | string
324
- ) { }
325
-
326
- run(value: any): void {
327
- const el = document.getElementById(this.elementId);
328
- if (!el) return;
329
-
330
- const newValue = this.transform ? this.transform(value) : value;
331
-
332
- // For progress/jux components, set data-value and trigger update
333
- if (el.classList.contains('jux-progress')) {
334
- el.setAttribute('data-value', String(newValue));
335
-
336
- // Find the progress instance and call value() to trigger update
337
- const progressBar = el.querySelector('.jux-progress-bar');
338
- if (progressBar) {
339
- const percentage = typeof newValue === 'number' ? newValue : parseFloat(String(newValue));
340
- const max = parseFloat(progressBar.getAttribute('aria-valuemax') || '100');
341
- const percentageValue = (percentage / max) * 100;
342
- (progressBar as HTMLElement).style.width = `${percentageValue}%`;
343
- progressBar.setAttribute('aria-valuenow', String(percentage));
344
- }
345
- return;
346
- }
347
-
348
- // For native HTML elements (input, progress, meter)
349
- if ('value' in el) {
350
- (el as any).value = String(newValue);
351
- }
352
-
353
- if (el instanceof HTMLProgressElement || el.tagName === 'METER') {
354
- el.setAttribute('value', String(newValue));
355
- }
356
- }
357
71
  }
358
72
 
359
73
  /**
360
- * Create reactive state
74
+ * Factory function to create reactive state
361
75
  */
362
76
  export function state<T>(initialValue: T): State<T> {
363
77
  return new State(initialValue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "juxscript",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "type": "module",
5
5
  "description": "A JavaScript UX authorship platform",
6
6
  "main": "lib/jux.js",
@@ -55,7 +55,6 @@
55
55
  "esbuild": "^0.19.0",
56
56
  "express": "^4.18.2",
57
57
  "glob": "^13.0.0",
58
- "sql.js": "^1.8.0",
59
58
  "ws": "^8.13.0"
60
59
  },
61
60
  "devDependencies": {