juxscript 1.0.3 → 1.0.5

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 (73) hide show
  1. package/README.md +37 -92
  2. package/bin/cli.js +57 -56
  3. package/lib/components/alert.ts +240 -0
  4. package/lib/components/app.ts +216 -82
  5. package/lib/components/badge.ts +164 -0
  6. package/lib/components/barchart.ts +1248 -0
  7. package/lib/components/button.ts +188 -53
  8. package/lib/components/card.ts +75 -61
  9. package/lib/components/chart.ts +17 -15
  10. package/lib/components/checkbox.ts +199 -0
  11. package/lib/components/code.ts +66 -152
  12. package/lib/components/container.ts +104 -208
  13. package/lib/components/data.ts +1 -3
  14. package/lib/components/datepicker.ts +226 -0
  15. package/lib/components/dialog.ts +258 -0
  16. package/lib/components/docs-data.json +1969 -423
  17. package/lib/components/dropdown.ts +244 -0
  18. package/lib/components/element.ts +271 -0
  19. package/lib/components/fileupload.ts +319 -0
  20. package/lib/components/footer.ts +37 -18
  21. package/lib/components/header.ts +53 -33
  22. package/lib/components/heading.ts +119 -0
  23. package/lib/components/helpers.ts +34 -0
  24. package/lib/components/hero.ts +57 -31
  25. package/lib/components/include.ts +292 -0
  26. package/lib/components/input.ts +508 -77
  27. package/lib/components/layout.ts +144 -18
  28. package/lib/components/list.ts +83 -74
  29. package/lib/components/loading.ts +263 -0
  30. package/lib/components/main.ts +43 -17
  31. package/lib/components/menu.ts +108 -24
  32. package/lib/components/modal.ts +50 -21
  33. package/lib/components/nav.ts +60 -18
  34. package/lib/components/paragraph.ts +111 -0
  35. package/lib/components/progress.ts +276 -0
  36. package/lib/components/radio.ts +236 -0
  37. package/lib/components/req.ts +300 -0
  38. package/lib/components/script.ts +33 -74
  39. package/lib/components/select.ts +280 -0
  40. package/lib/components/sidebar.ts +87 -37
  41. package/lib/components/style.ts +47 -70
  42. package/lib/components/switch.ts +261 -0
  43. package/lib/components/table.ts +47 -24
  44. package/lib/components/tabs.ts +105 -63
  45. package/lib/components/theme-toggle.ts +361 -0
  46. package/lib/components/token-calculator.ts +380 -0
  47. package/lib/components/tooltip.ts +244 -0
  48. package/lib/components/view.ts +36 -20
  49. package/lib/components/write.ts +284 -0
  50. package/lib/globals.d.ts +21 -0
  51. package/lib/jux.ts +178 -68
  52. package/lib/presets/notion.css +521 -0
  53. package/lib/presets/notion.jux +27 -0
  54. package/lib/reactivity/state.ts +364 -0
  55. package/lib/themes/charts.js +126 -0
  56. package/machinery/compiler.js +126 -38
  57. package/machinery/generators/html.js +2 -3
  58. package/machinery/server.js +2 -2
  59. package/package.json +29 -3
  60. package/lib/components/import.ts +0 -430
  61. package/lib/components/node.ts +0 -200
  62. package/lib/components/reactivity.js +0 -104
  63. package/lib/components/theme.ts +0 -97
  64. package/lib/layouts/notion.css +0 -258
  65. package/lib/styles/base-theme.css +0 -186
  66. package/lib/styles/dark-theme.css +0 -144
  67. package/lib/styles/light-theme.css +0 -144
  68. package/lib/styles/tokens/dark.css +0 -86
  69. package/lib/styles/tokens/light.css +0 -86
  70. package/lib/templates/index.juxt +0 -33
  71. package/lib/themes/dark.css +0 -86
  72. package/lib/themes/light.css +0 -86
  73. /package/lib/{styles → presets}/global.css +0 -0
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Reactive state container
3
+ * Notifies subscribers when value changes
4
+ */
5
+ export class State<T> {
6
+ private _value: T;
7
+ private _subscribers: Set<(value: T) => void> = new Set();
8
+ private _effects: Set<Effect> = new Set();
9
+
10
+ constructor(initialValue: T) {
11
+ this._value = initialValue;
12
+ }
13
+
14
+ /**
15
+ * Get current value
16
+ */
17
+ get value(): T {
18
+ return this._value;
19
+ }
20
+
21
+ /**
22
+ * Set new value and notify subscribers
23
+ */
24
+ 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));
37
+ }
38
+
39
+ /**
40
+ * Subscribe to value changes
41
+ * Returns unsubscribe function
42
+ */
43
+ subscribe(callback: (value: T) => void): () => void {
44
+ this._subscribers.add(callback);
45
+ callback(this._value); // Call immediately with current value
46
+ return () => this._subscribers.delete(callback);
47
+ }
48
+
49
+ /**
50
+ * Notify all subscribers of value change
51
+ */
52
+ private _notify(): void {
53
+ this._subscribers.forEach(callback => callback(this._value));
54
+ }
55
+
56
+ /**
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
102
+ */
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 => {
160
+ if (typeof this._value === 'number') {
161
+ this.set((this._value + 1) as T);
162
+ }
163
+ }
164
+
165
+ /**
166
+ * Decrement (numbers only)
167
+ */
168
+ decrement = (): void => {
169
+ if (typeof this._value === 'number') {
170
+ this.set((this._value - 1) as T);
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Add amount (returns function for event handlers)
176
+ */
177
+ add = (amount: number) => (): void => {
178
+ if (typeof this._value === 'number') {
179
+ this.set((this._value + amount) as T);
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Subtract amount
185
+ */
186
+ subtract = (amount: number) => (): void => {
187
+ if (typeof this._value === 'number') {
188
+ this.set((this._value - amount) as T);
189
+ }
190
+ }
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
+ }
358
+
359
+ /**
360
+ * Create reactive state
361
+ */
362
+ export function state<T>(initialValue: T): State<T> {
363
+ return new State(initialValue);
364
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Chart themes for Jux
3
+ * Each theme defines colors and optional font customization
4
+ */
5
+
6
+ export const googleTheme = {
7
+ name: 'Google',
8
+ colors: [
9
+ '#4285F4', // Google Blue
10
+ '#EA4335', // Google Red
11
+ '#FBBC04', // Google Yellow
12
+ '#34A853', // Google Green
13
+ '#FF6D01', // Orange
14
+ '#46BDC6', // Cyan
15
+ ],
16
+ variables: {
17
+ '--chart-font-family': "'Roboto', sans-serif",
18
+ },
19
+ font: 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'
20
+ };
21
+
22
+ export const seriesaTheme = {
23
+ name: 'Series A',
24
+ colors: [
25
+ '#667eea', // Purple
26
+ '#764ba2', // Dark Purple
27
+ '#f093fb', // Pink
28
+ '#4facfe', // Blue
29
+ '#00f2fe', // Cyan
30
+ '#43e97b', // Green
31
+ ],
32
+ variables: {
33
+ '--chart-font-family': "'Inter', sans-serif",
34
+ },
35
+ font: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'
36
+ };
37
+
38
+ export const hrTheme = {
39
+ name: 'HR',
40
+ colors: [
41
+ '#FF6B6B', // Coral Red
42
+ '#4ECDC4', // Turquoise
43
+ '#45B7D1', // Sky Blue
44
+ '#FFA07A', // Light Salmon
45
+ '#98D8C8', // Mint
46
+ '#F7DC6F', // Pale Yellow
47
+ ],
48
+ variables: {
49
+ '--chart-font-family': "'Work Sans', sans-serif",
50
+ },
51
+ font: 'https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600&display=swap'
52
+ };
53
+
54
+ export const figmaTheme = {
55
+ name: 'Figma',
56
+ colors: [
57
+ '#0ACF83', // Figma Green
58
+ '#FF7262', // Figma Red/Orange
59
+ '#1ABCFE', // Figma Blue
60
+ '#A259FF', // Figma Purple
61
+ '#F24E1E', // Figma Orange
62
+ '#FFC700', // Figma Yellow
63
+ ],
64
+ variables: {
65
+ '--chart-font-family': "'Inter', sans-serif",
66
+ },
67
+ font: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'
68
+ };
69
+
70
+ export const notionTheme = {
71
+ name: 'Notion',
72
+ colors: [
73
+ '#2EAADC', // Notion Blue
74
+ '#9B59B6', // Purple
75
+ '#E67E22', // Orange
76
+ '#E74C3C', // Red
77
+ '#F39C12', // Yellow
78
+ '#16A085', // Teal
79
+ ],
80
+ variables: {
81
+ '--chart-font-family': "'Inter', sans-serif",
82
+ },
83
+ font: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'
84
+ };
85
+
86
+ export const chalkTheme = {
87
+ name: 'Chalk',
88
+ colors: [
89
+ '#96CEB4', // Soft Green
90
+ '#FFEAA7', // Soft Yellow
91
+ '#DFE6E9', // Light Gray
92
+ '#74B9FF', // Soft Blue
93
+ '#FD79A8', // Soft Pink
94
+ '#A29BFE', // Soft Purple
95
+ ],
96
+ variables: {
97
+ '--chart-font-family': "'Courier New', monospace",
98
+ }
99
+ };
100
+
101
+ export const mintTheme = {
102
+ name: 'Mint',
103
+ colors: [
104
+ '#26de81', // Mint Green
105
+ '#20bf6b', // Green
106
+ '#0fb9b1', // Teal
107
+ '#2bcbba', // Light Teal
108
+ '#45aaf2', // Blue
109
+ '#4b7bec', // Dark Blue
110
+ ],
111
+ variables: {
112
+ '--chart-font-family': "'Poppins', sans-serif",
113
+ },
114
+ font: 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'
115
+ };
116
+
117
+ // Export all themes as a collection for easy iteration
118
+ export const chartThemes = {
119
+ google: googleTheme,
120
+ seriesa: seriesaTheme,
121
+ hr: hrTheme,
122
+ figma: figmaTheme,
123
+ notion: notionTheme,
124
+ chalk: chalkTheme,
125
+ mint: mintTheme
126
+ };