juxscript 1.0.3 → 1.0.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.
- package/README.md +37 -92
- package/bin/cli.js +57 -56
- package/lib/components/alert.ts +240 -0
- package/lib/components/app.ts +216 -82
- package/lib/components/badge.ts +164 -0
- package/lib/components/button.ts +188 -53
- package/lib/components/card.ts +75 -61
- package/lib/components/chart.ts +17 -15
- package/lib/components/checkbox.ts +228 -0
- package/lib/components/code.ts +66 -152
- package/lib/components/container.ts +104 -208
- package/lib/components/data.ts +1 -3
- package/lib/components/datepicker.ts +226 -0
- package/lib/components/dialog.ts +258 -0
- package/lib/components/docs-data.json +1697 -388
- package/lib/components/dropdown.ts +244 -0
- package/lib/components/element.ts +271 -0
- package/lib/components/fileupload.ts +319 -0
- package/lib/components/footer.ts +37 -18
- package/lib/components/header.ts +53 -33
- package/lib/components/heading.ts +119 -0
- package/lib/components/helpers.ts +34 -0
- package/lib/components/hero.ts +57 -31
- package/lib/components/include.ts +292 -0
- package/lib/components/input.ts +166 -78
- package/lib/components/layout.ts +144 -18
- package/lib/components/list.ts +83 -74
- package/lib/components/loading.ts +263 -0
- package/lib/components/main.ts +43 -17
- package/lib/components/menu.ts +108 -24
- package/lib/components/modal.ts +50 -21
- package/lib/components/nav.ts +60 -18
- package/lib/components/paragraph.ts +111 -0
- package/lib/components/progress.ts +276 -0
- package/lib/components/radio.ts +236 -0
- package/lib/components/req.ts +300 -0
- package/lib/components/script.ts +33 -74
- package/lib/components/select.ts +247 -0
- package/lib/components/sidebar.ts +86 -36
- package/lib/components/style.ts +47 -70
- package/lib/components/switch.ts +261 -0
- package/lib/components/table.ts +47 -24
- package/lib/components/tabs.ts +105 -63
- package/lib/components/theme-toggle.ts +361 -0
- package/lib/components/token-calculator.ts +380 -0
- package/lib/components/tooltip.ts +244 -0
- package/lib/components/view.ts +36 -20
- package/lib/components/write.ts +284 -0
- package/lib/globals.d.ts +21 -0
- package/lib/jux.ts +172 -68
- package/lib/presets/notion.css +521 -0
- package/lib/presets/notion.jux +27 -0
- package/lib/reactivity/state.ts +364 -0
- package/machinery/compiler.js +126 -38
- package/machinery/generators/html.js +2 -3
- package/machinery/server.js +2 -2
- package/package.json +29 -3
- package/lib/components/import.ts +0 -430
- package/lib/components/node.ts +0 -200
- package/lib/components/reactivity.js +0 -104
- package/lib/components/theme.ts +0 -97
- package/lib/layouts/notion.css +0 -258
- package/lib/styles/base-theme.css +0 -186
- package/lib/styles/dark-theme.css +0 -144
- package/lib/styles/light-theme.css +0 -144
- package/lib/styles/tokens/dark.css +0 -86
- package/lib/styles/tokens/light.css +0 -86
- package/lib/templates/index.juxt +0 -33
- package/lib/themes/dark.css +0 -86
- package/lib/themes/light.css +0 -86
- /package/lib/{styles → presets}/global.css +0 -0
package/lib/components/main.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOrCreateContainer } from './helpers.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Main component options
|
|
@@ -6,6 +6,8 @@ import { Reactive, getOrCreateContainer } from './reactivity.js';
|
|
|
6
6
|
export interface MainOptions {
|
|
7
7
|
content?: string;
|
|
8
8
|
padding?: string;
|
|
9
|
+
style?: string;
|
|
10
|
+
class?: string;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/**
|
|
@@ -14,6 +16,8 @@ export interface MainOptions {
|
|
|
14
16
|
type MainState = {
|
|
15
17
|
content: string;
|
|
16
18
|
padding: string;
|
|
19
|
+
style: string;
|
|
20
|
+
class: string;
|
|
17
21
|
};
|
|
18
22
|
|
|
19
23
|
/**
|
|
@@ -26,18 +30,22 @@ type MainState = {
|
|
|
26
30
|
* });
|
|
27
31
|
* main.render('#appmain');
|
|
28
32
|
*/
|
|
29
|
-
export class Main
|
|
30
|
-
state
|
|
33
|
+
export class Main {
|
|
34
|
+
state: MainState;
|
|
31
35
|
container: HTMLElement | null = null;
|
|
36
|
+
_id: string;
|
|
37
|
+
id: string;
|
|
32
38
|
|
|
33
|
-
constructor(
|
|
34
|
-
|
|
35
|
-
this.
|
|
39
|
+
constructor(id: string, options: MainOptions = {}) {
|
|
40
|
+
this._id = id;
|
|
41
|
+
this.id = id;
|
|
36
42
|
|
|
37
|
-
this.state =
|
|
43
|
+
this.state = {
|
|
38
44
|
content: options.content ?? '',
|
|
39
|
-
padding: options.padding ?? 'var(--space-xl)'
|
|
40
|
-
|
|
45
|
+
padding: options.padding ?? 'var(--space-xl)',
|
|
46
|
+
style: options.style ?? '',
|
|
47
|
+
class: options.class ?? ''
|
|
48
|
+
};
|
|
41
49
|
}
|
|
42
50
|
|
|
43
51
|
/* -------------------------
|
|
@@ -54,6 +62,16 @@ export class Main extends Reactive {
|
|
|
54
62
|
return this;
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
style(value: string): this {
|
|
66
|
+
this.state.style = value;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class(value: string): this {
|
|
71
|
+
this.state.class = value;
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
57
75
|
/* -------------------------
|
|
58
76
|
* Render
|
|
59
77
|
* ------------------------- */
|
|
@@ -68,17 +86,25 @@ export class Main extends Reactive {
|
|
|
68
86
|
}
|
|
69
87
|
container = target;
|
|
70
88
|
} else {
|
|
71
|
-
container = getOrCreateContainer(this.
|
|
89
|
+
container = getOrCreateContainer(this._id);
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
this.container = container;
|
|
75
|
-
const { content, padding } = this.state;
|
|
93
|
+
const { content, padding, style, class: className } = this.state;
|
|
76
94
|
|
|
77
95
|
const main = document.createElement('main');
|
|
78
96
|
main.className = 'jux-main';
|
|
79
|
-
main.id = this.
|
|
97
|
+
main.id = this._id;
|
|
80
98
|
main.style.padding = padding;
|
|
81
99
|
|
|
100
|
+
if (style) {
|
|
101
|
+
main.setAttribute('style', style);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (className) {
|
|
105
|
+
main.className += ` ${className}`;
|
|
106
|
+
}
|
|
107
|
+
|
|
82
108
|
if (content) {
|
|
83
109
|
main.innerHTML = content;
|
|
84
110
|
}
|
|
@@ -95,17 +121,17 @@ export class Main extends Reactive {
|
|
|
95
121
|
throw new Error('Main.renderTo: Invalid component - not an object');
|
|
96
122
|
}
|
|
97
123
|
|
|
98
|
-
if (!juxComponent.
|
|
99
|
-
throw new Error('Main.renderTo: Invalid component - missing
|
|
124
|
+
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
125
|
+
throw new Error('Main.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
100
126
|
}
|
|
101
127
|
|
|
102
|
-
return this.render(`#${juxComponent.
|
|
128
|
+
return this.render(`#${juxComponent._id}`);
|
|
103
129
|
}
|
|
104
130
|
}
|
|
105
131
|
|
|
106
132
|
/**
|
|
107
133
|
* Factory helper
|
|
108
134
|
*/
|
|
109
|
-
export function main(
|
|
110
|
-
return new Main(
|
|
135
|
+
export function main(id: string, options: MainOptions = {}): Main {
|
|
136
|
+
return new Main(id, options);
|
|
111
137
|
}
|
package/lib/components/menu.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOrCreateContainer } from './helpers.js';
|
|
2
|
+
import { req } from './req.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Menu item configuration
|
|
@@ -6,9 +7,10 @@ import { Reactive, getOrCreateContainer } from './reactivity.js';
|
|
|
6
7
|
export interface MenuItem {
|
|
7
8
|
label: string;
|
|
8
9
|
href?: string;
|
|
9
|
-
|
|
10
|
+
click?: () => void;
|
|
10
11
|
icon?: string;
|
|
11
12
|
items?: MenuItem[];
|
|
13
|
+
active?: boolean;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -17,6 +19,8 @@ export interface MenuItem {
|
|
|
17
19
|
export interface MenuOptions {
|
|
18
20
|
items?: MenuItem[];
|
|
19
21
|
orientation?: 'vertical' | 'horizontal';
|
|
22
|
+
style?: string;
|
|
23
|
+
class?: string;
|
|
20
24
|
}
|
|
21
25
|
|
|
22
26
|
/**
|
|
@@ -25,6 +29,8 @@ export interface MenuOptions {
|
|
|
25
29
|
type MenuState = {
|
|
26
30
|
items: MenuItem[];
|
|
27
31
|
orientation: string;
|
|
32
|
+
style: string;
|
|
33
|
+
class: string;
|
|
28
34
|
};
|
|
29
35
|
|
|
30
36
|
/**
|
|
@@ -39,19 +45,43 @@ type MenuState = {
|
|
|
39
45
|
* ]
|
|
40
46
|
* });
|
|
41
47
|
* menu.render();
|
|
48
|
+
*
|
|
49
|
+
* Active states are automatically set based on current URL
|
|
42
50
|
*/
|
|
43
|
-
export class Menu
|
|
44
|
-
state
|
|
51
|
+
export class Menu {
|
|
52
|
+
state: MenuState;
|
|
45
53
|
container: HTMLElement | null = null;
|
|
54
|
+
_id: string;
|
|
55
|
+
id: string;
|
|
46
56
|
|
|
47
|
-
constructor(
|
|
48
|
-
|
|
49
|
-
this.
|
|
57
|
+
constructor(id: string, options: MenuOptions = {}) {
|
|
58
|
+
this._id = id;
|
|
59
|
+
this.id = id;
|
|
50
60
|
|
|
51
|
-
this.state =
|
|
61
|
+
this.state = {
|
|
52
62
|
items: options.items ?? [],
|
|
53
|
-
orientation: options.orientation ?? 'vertical'
|
|
54
|
-
|
|
63
|
+
orientation: options.orientation ?? 'vertical',
|
|
64
|
+
style: options.style ?? '',
|
|
65
|
+
class: options.class ?? ''
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// Auto-set active state based on current path
|
|
69
|
+
this._setActiveStates();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Set active state on items based on current request path
|
|
74
|
+
*/
|
|
75
|
+
private _setActiveStates(): void {
|
|
76
|
+
this.state.items = this.state.items.map(item => ({
|
|
77
|
+
...item,
|
|
78
|
+
active: item.href ? req.isActiveNavItem(item.href) : false,
|
|
79
|
+
// Recursively set active for subitems
|
|
80
|
+
items: item.items?.map(subItem => ({
|
|
81
|
+
...subItem,
|
|
82
|
+
active: subItem.href ? req.isActiveNavItem(subItem.href) : false
|
|
83
|
+
}))
|
|
84
|
+
}));
|
|
55
85
|
}
|
|
56
86
|
|
|
57
87
|
/* -------------------------
|
|
@@ -60,11 +90,13 @@ export class Menu extends Reactive {
|
|
|
60
90
|
|
|
61
91
|
items(value: MenuItem[]): this {
|
|
62
92
|
this.state.items = value;
|
|
93
|
+
this._setActiveStates();
|
|
63
94
|
return this;
|
|
64
95
|
}
|
|
65
96
|
|
|
66
97
|
addItem(item: MenuItem): this {
|
|
67
|
-
this.state.items.
|
|
98
|
+
this.state.items = [...this.state.items, item];
|
|
99
|
+
this._setActiveStates();
|
|
68
100
|
return this;
|
|
69
101
|
}
|
|
70
102
|
|
|
@@ -73,6 +105,16 @@ export class Menu extends Reactive {
|
|
|
73
105
|
return this;
|
|
74
106
|
}
|
|
75
107
|
|
|
108
|
+
style(value: string): this {
|
|
109
|
+
this.state.style = value;
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class(value: string): this {
|
|
114
|
+
this.state.class = value;
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
|
|
76
118
|
/* -------------------------
|
|
77
119
|
* Helpers
|
|
78
120
|
* ------------------------- */
|
|
@@ -81,21 +123,55 @@ export class Menu extends Reactive {
|
|
|
81
123
|
const menuItem = document.createElement('div');
|
|
82
124
|
menuItem.className = 'jux-menu-item';
|
|
83
125
|
|
|
126
|
+
// Add active class if item is active
|
|
127
|
+
if (item.active) {
|
|
128
|
+
menuItem.classList.add('jux-menu-item-active');
|
|
129
|
+
}
|
|
130
|
+
|
|
84
131
|
if (item.href) {
|
|
85
132
|
const link = document.createElement('a');
|
|
86
133
|
link.className = 'jux-menu-link';
|
|
87
134
|
link.href = item.href;
|
|
88
|
-
|
|
135
|
+
|
|
136
|
+
// Add active class to link if item is active
|
|
137
|
+
if (item.active) {
|
|
138
|
+
link.classList.add('jux-menu-link-active');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (item.icon) {
|
|
142
|
+
const icon = document.createElement('span');
|
|
143
|
+
icon.className = 'jux-menu-icon';
|
|
144
|
+
icon.textContent = item.icon;
|
|
145
|
+
link.appendChild(icon);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const label = document.createElement('span');
|
|
149
|
+
label.className = 'jux-menu-label';
|
|
150
|
+
label.textContent = item.label;
|
|
151
|
+
link.appendChild(label);
|
|
152
|
+
|
|
89
153
|
menuItem.appendChild(link);
|
|
90
154
|
} else {
|
|
91
155
|
const button = document.createElement('button');
|
|
92
156
|
button.className = 'jux-menu-button';
|
|
93
|
-
|
|
157
|
+
|
|
158
|
+
if (item.icon) {
|
|
159
|
+
const icon = document.createElement('span');
|
|
160
|
+
icon.className = 'jux-menu-icon';
|
|
161
|
+
icon.textContent = item.icon;
|
|
162
|
+
button.appendChild(icon);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const label = document.createElement('span');
|
|
166
|
+
label.className = 'jux-menu-label';
|
|
167
|
+
label.textContent = item.label;
|
|
168
|
+
button.appendChild(label);
|
|
169
|
+
|
|
94
170
|
menuItem.appendChild(button);
|
|
95
171
|
|
|
96
|
-
// Event binding -
|
|
97
|
-
if (item.
|
|
98
|
-
button.addEventListener('click', item.
|
|
172
|
+
// Event binding - click
|
|
173
|
+
if (item.click) {
|
|
174
|
+
button.addEventListener('click', item.click);
|
|
99
175
|
}
|
|
100
176
|
}
|
|
101
177
|
|
|
@@ -128,15 +204,23 @@ export class Menu extends Reactive {
|
|
|
128
204
|
}
|
|
129
205
|
container = target;
|
|
130
206
|
} else {
|
|
131
|
-
container = getOrCreateContainer(this.
|
|
207
|
+
container = getOrCreateContainer(this._id);
|
|
132
208
|
}
|
|
133
209
|
|
|
134
210
|
this.container = container;
|
|
135
|
-
const { items, orientation } = this.state;
|
|
211
|
+
const { items, orientation, style, class: className } = this.state;
|
|
136
212
|
|
|
137
213
|
const menu = document.createElement('nav');
|
|
138
214
|
menu.className = `jux-menu jux-menu-${orientation}`;
|
|
139
|
-
menu.id = this.
|
|
215
|
+
menu.id = this._id;
|
|
216
|
+
|
|
217
|
+
if (className) {
|
|
218
|
+
menu.className += ` ${className}`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (style) {
|
|
222
|
+
menu.setAttribute('style', style);
|
|
223
|
+
}
|
|
140
224
|
|
|
141
225
|
items.forEach(item => {
|
|
142
226
|
menu.appendChild(this._renderMenuItem(item));
|
|
@@ -154,17 +238,17 @@ export class Menu extends Reactive {
|
|
|
154
238
|
throw new Error('Menu.renderTo: Invalid component - not an object');
|
|
155
239
|
}
|
|
156
240
|
|
|
157
|
-
if (!juxComponent.
|
|
158
|
-
throw new Error('Menu.renderTo: Invalid component - missing
|
|
241
|
+
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
242
|
+
throw new Error('Menu.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
159
243
|
}
|
|
160
244
|
|
|
161
|
-
return this.render(`#${juxComponent.
|
|
245
|
+
return this.render(`#${juxComponent._id}`);
|
|
162
246
|
}
|
|
163
247
|
}
|
|
164
248
|
|
|
165
249
|
/**
|
|
166
250
|
* Factory helper
|
|
167
251
|
*/
|
|
168
|
-
export function menu(
|
|
169
|
-
return new Menu(
|
|
252
|
+
export function menu(id: string, options: MenuOptions = {}): Menu {
|
|
253
|
+
return new Menu(id, options);
|
|
170
254
|
}
|
package/lib/components/modal.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOrCreateContainer } from './helpers.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Modal component options
|
|
@@ -9,6 +9,8 @@ export interface ModalOptions {
|
|
|
9
9
|
showCloseButton?: boolean;
|
|
10
10
|
closeOnBackdropClick?: boolean;
|
|
11
11
|
size?: 'small' | 'medium' | 'large';
|
|
12
|
+
style?: string;
|
|
13
|
+
class?: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -21,6 +23,8 @@ type ModalState = {
|
|
|
21
23
|
closeOnBackdropClick: boolean;
|
|
22
24
|
size: string;
|
|
23
25
|
isOpen: boolean;
|
|
26
|
+
style: string;
|
|
27
|
+
class: string;
|
|
24
28
|
};
|
|
25
29
|
|
|
26
30
|
/**
|
|
@@ -35,22 +39,26 @@ type ModalState = {
|
|
|
35
39
|
* modal.render();
|
|
36
40
|
* modal.open();
|
|
37
41
|
*/
|
|
38
|
-
export class Modal
|
|
39
|
-
state
|
|
42
|
+
export class Modal {
|
|
43
|
+
state: ModalState;
|
|
40
44
|
container: HTMLElement | null = null;
|
|
45
|
+
_id: string;
|
|
46
|
+
id: string;
|
|
41
47
|
|
|
42
|
-
constructor(
|
|
43
|
-
|
|
44
|
-
this.
|
|
48
|
+
constructor(id: string, options: ModalOptions = {}) {
|
|
49
|
+
this._id = id;
|
|
50
|
+
this.id = id;
|
|
45
51
|
|
|
46
|
-
this.state =
|
|
52
|
+
this.state = {
|
|
47
53
|
title: options.title ?? '',
|
|
48
54
|
content: options.content ?? '',
|
|
49
55
|
showCloseButton: options.showCloseButton ?? true,
|
|
50
56
|
closeOnBackdropClick: options.closeOnBackdropClick ?? true,
|
|
51
57
|
size: options.size ?? 'medium',
|
|
52
|
-
isOpen: false
|
|
53
|
-
|
|
58
|
+
isOpen: false,
|
|
59
|
+
style: options.style ?? '',
|
|
60
|
+
class: options.class ?? ''
|
|
61
|
+
};
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/* -------------------------
|
|
@@ -82,6 +90,20 @@ export class Modal extends Reactive {
|
|
|
82
90
|
return this;
|
|
83
91
|
}
|
|
84
92
|
|
|
93
|
+
style(value: string): this {
|
|
94
|
+
this.state.style = value;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
class(value: string): this {
|
|
99
|
+
this.state.class = value;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* -------------------------
|
|
104
|
+
* Modal controls
|
|
105
|
+
* ------------------------- */
|
|
106
|
+
|
|
85
107
|
open(): this {
|
|
86
108
|
this.state.isOpen = true;
|
|
87
109
|
if (this.container) {
|
|
@@ -90,7 +112,6 @@ export class Modal extends Reactive {
|
|
|
90
112
|
modalEl.classList.add('jux-modal-open');
|
|
91
113
|
}
|
|
92
114
|
}
|
|
93
|
-
this.emit('open');
|
|
94
115
|
return this;
|
|
95
116
|
}
|
|
96
117
|
|
|
@@ -102,7 +123,6 @@ export class Modal extends Reactive {
|
|
|
102
123
|
modalEl.classList.remove('jux-modal-open');
|
|
103
124
|
}
|
|
104
125
|
}
|
|
105
|
-
this.emit('close');
|
|
106
126
|
return this;
|
|
107
127
|
}
|
|
108
128
|
|
|
@@ -120,16 +140,24 @@ export class Modal extends Reactive {
|
|
|
120
140
|
}
|
|
121
141
|
container = target;
|
|
122
142
|
} else {
|
|
123
|
-
container = getOrCreateContainer(this.
|
|
143
|
+
container = getOrCreateContainer(this._id);
|
|
124
144
|
}
|
|
125
145
|
|
|
126
146
|
this.container = container;
|
|
127
|
-
const { title, content, showCloseButton, closeOnBackdropClick, size, isOpen } = this.state;
|
|
147
|
+
const { title, content, showCloseButton, closeOnBackdropClick, size, isOpen, style, class: className } = this.state;
|
|
128
148
|
|
|
129
149
|
// Modal backdrop
|
|
130
150
|
const modal = document.createElement('div');
|
|
131
151
|
modal.className = `jux-modal jux-modal-${size}`;
|
|
132
|
-
modal.id = this.
|
|
152
|
+
modal.id = this._id;
|
|
153
|
+
|
|
154
|
+
if (className) {
|
|
155
|
+
modal.className += ` ${className}`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (style) {
|
|
159
|
+
modal.setAttribute('style', style);
|
|
160
|
+
}
|
|
133
161
|
|
|
134
162
|
if (isOpen) {
|
|
135
163
|
modal.classList.add('jux-modal-open');
|
|
@@ -183,11 +211,12 @@ export class Modal extends Reactive {
|
|
|
183
211
|
}
|
|
184
212
|
|
|
185
213
|
// Event binding - escape key
|
|
186
|
-
|
|
214
|
+
const escapeHandler = (e: KeyboardEvent) => {
|
|
187
215
|
if (e.key === 'Escape' && this.state.isOpen) {
|
|
188
216
|
this.close();
|
|
189
217
|
}
|
|
190
|
-
}
|
|
218
|
+
};
|
|
219
|
+
document.addEventListener('keydown', escapeHandler);
|
|
191
220
|
|
|
192
221
|
return this;
|
|
193
222
|
}
|
|
@@ -200,17 +229,17 @@ export class Modal extends Reactive {
|
|
|
200
229
|
throw new Error('Modal.renderTo: Invalid component - not an object');
|
|
201
230
|
}
|
|
202
231
|
|
|
203
|
-
if (!juxComponent.
|
|
204
|
-
throw new Error('Modal.renderTo: Invalid component - missing
|
|
232
|
+
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
233
|
+
throw new Error('Modal.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
205
234
|
}
|
|
206
235
|
|
|
207
|
-
return this.render(`#${juxComponent.
|
|
236
|
+
return this.render(`#${juxComponent._id}`);
|
|
208
237
|
}
|
|
209
238
|
}
|
|
210
239
|
|
|
211
240
|
/**
|
|
212
241
|
* Factory helper
|
|
213
242
|
*/
|
|
214
|
-
export function modal(
|
|
215
|
-
return new Modal(
|
|
243
|
+
export function modal(id: string, options: ModalOptions = {}): Modal {
|
|
244
|
+
return new Modal(id, options);
|
|
216
245
|
}
|
package/lib/components/nav.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getOrCreateContainer } from './helpers.js';
|
|
2
|
+
import { req } from './req.js';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Nav item configuration
|
|
@@ -15,6 +16,8 @@ export interface NavItem {
|
|
|
15
16
|
export interface NavOptions {
|
|
16
17
|
items?: NavItem[];
|
|
17
18
|
variant?: 'default' | 'pills' | 'tabs';
|
|
19
|
+
style?: string;
|
|
20
|
+
class?: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
/**
|
|
@@ -23,6 +26,8 @@ export interface NavOptions {
|
|
|
23
26
|
type NavState = {
|
|
24
27
|
items: NavItem[];
|
|
25
28
|
variant: string;
|
|
29
|
+
style: string;
|
|
30
|
+
class: string;
|
|
26
31
|
};
|
|
27
32
|
|
|
28
33
|
/**
|
|
@@ -38,18 +43,35 @@ type NavState = {
|
|
|
38
43
|
* });
|
|
39
44
|
* nav.render();
|
|
40
45
|
*/
|
|
41
|
-
export class Nav
|
|
42
|
-
state
|
|
46
|
+
export class Nav {
|
|
47
|
+
state: NavState;
|
|
43
48
|
container: HTMLElement | null = null;
|
|
49
|
+
_id: string;
|
|
50
|
+
id: string;
|
|
44
51
|
|
|
45
|
-
constructor(
|
|
46
|
-
|
|
47
|
-
this.
|
|
52
|
+
constructor(id: string, options: NavOptions = {}) {
|
|
53
|
+
this._id = id;
|
|
54
|
+
this.id = id;
|
|
48
55
|
|
|
49
|
-
this.state =
|
|
56
|
+
this.state = {
|
|
50
57
|
items: options.items ?? [],
|
|
51
|
-
variant: options.variant ?? 'default'
|
|
52
|
-
|
|
58
|
+
variant: options.variant ?? 'default',
|
|
59
|
+
style: options.style ?? '',
|
|
60
|
+
class: options.class ?? ''
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Auto-set active state based on current path
|
|
64
|
+
this._setActiveStates();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set active state on items based on current request path
|
|
69
|
+
*/
|
|
70
|
+
private _setActiveStates(): void {
|
|
71
|
+
this.state.items = this.state.items.map(item => ({
|
|
72
|
+
...item,
|
|
73
|
+
active: req.isActiveNavItem(item.href)
|
|
74
|
+
}));
|
|
53
75
|
}
|
|
54
76
|
|
|
55
77
|
/* -------------------------
|
|
@@ -58,11 +80,13 @@ export class Nav extends Reactive {
|
|
|
58
80
|
|
|
59
81
|
items(value: NavItem[]): this {
|
|
60
82
|
this.state.items = value;
|
|
83
|
+
this._setActiveStates();
|
|
61
84
|
return this;
|
|
62
85
|
}
|
|
63
86
|
|
|
64
87
|
addItem(item: NavItem): this {
|
|
65
|
-
this.state.items.
|
|
88
|
+
this.state.items = [...this.state.items, item];
|
|
89
|
+
this._setActiveStates();
|
|
66
90
|
return this;
|
|
67
91
|
}
|
|
68
92
|
|
|
@@ -71,6 +95,16 @@ export class Nav extends Reactive {
|
|
|
71
95
|
return this;
|
|
72
96
|
}
|
|
73
97
|
|
|
98
|
+
style(value: string): this {
|
|
99
|
+
this.state.style = value;
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
class(value: string): this {
|
|
104
|
+
this.state.class = value;
|
|
105
|
+
return this;
|
|
106
|
+
}
|
|
107
|
+
|
|
74
108
|
/* -------------------------
|
|
75
109
|
* Render
|
|
76
110
|
* ------------------------- */
|
|
@@ -85,15 +119,23 @@ export class Nav extends Reactive {
|
|
|
85
119
|
}
|
|
86
120
|
container = target;
|
|
87
121
|
} else {
|
|
88
|
-
container = getOrCreateContainer(this.
|
|
122
|
+
container = getOrCreateContainer(this._id);
|
|
89
123
|
}
|
|
90
124
|
|
|
91
125
|
this.container = container;
|
|
92
|
-
const { items, variant } = this.state;
|
|
126
|
+
const { items, variant, style, class: className } = this.state;
|
|
93
127
|
|
|
94
128
|
const nav = document.createElement('nav');
|
|
95
129
|
nav.className = `jux-nav jux-nav-${variant}`;
|
|
96
|
-
nav.id = this.
|
|
130
|
+
nav.id = this._id;
|
|
131
|
+
|
|
132
|
+
if (className) {
|
|
133
|
+
nav.className += ` ${className}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (style) {
|
|
137
|
+
nav.setAttribute('style', style);
|
|
138
|
+
}
|
|
97
139
|
|
|
98
140
|
items.forEach(item => {
|
|
99
141
|
const link = document.createElement('a');
|
|
@@ -120,17 +162,17 @@ export class Nav extends Reactive {
|
|
|
120
162
|
throw new Error('Nav.renderTo: Invalid component - not an object');
|
|
121
163
|
}
|
|
122
164
|
|
|
123
|
-
if (!juxComponent.
|
|
124
|
-
throw new Error('Nav.renderTo: Invalid component - missing
|
|
165
|
+
if (!juxComponent._id || typeof juxComponent._id !== 'string') {
|
|
166
|
+
throw new Error('Nav.renderTo: Invalid component - missing _id (not a Jux component)');
|
|
125
167
|
}
|
|
126
168
|
|
|
127
|
-
return this.render(`#${juxComponent.
|
|
169
|
+
return this.render(`#${juxComponent._id}`);
|
|
128
170
|
}
|
|
129
171
|
}
|
|
130
172
|
|
|
131
173
|
/**
|
|
132
174
|
* Factory helper
|
|
133
175
|
*/
|
|
134
|
-
export function nav(
|
|
135
|
-
return new Nav(
|
|
176
|
+
export function nav(id: string, options: NavOptions = {}): Nav {
|
|
177
|
+
return new Nav(id, options);
|
|
136
178
|
}
|