juxscript 1.0.2 → 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.
Files changed (71) 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/button.ts +188 -53
  7. package/lib/components/card.ts +75 -61
  8. package/lib/components/chart.ts +17 -15
  9. package/lib/components/checkbox.ts +228 -0
  10. package/lib/components/code.ts +66 -152
  11. package/lib/components/container.ts +104 -208
  12. package/lib/components/data.ts +1 -3
  13. package/lib/components/datepicker.ts +226 -0
  14. package/lib/components/dialog.ts +258 -0
  15. package/lib/components/docs-data.json +1697 -388
  16. package/lib/components/dropdown.ts +244 -0
  17. package/lib/components/element.ts +271 -0
  18. package/lib/components/fileupload.ts +319 -0
  19. package/lib/components/footer.ts +37 -18
  20. package/lib/components/header.ts +53 -33
  21. package/lib/components/heading.ts +119 -0
  22. package/lib/components/helpers.ts +34 -0
  23. package/lib/components/hero.ts +57 -31
  24. package/lib/components/include.ts +292 -0
  25. package/lib/components/input.ts +166 -78
  26. package/lib/components/layout.ts +144 -18
  27. package/lib/components/list.ts +83 -74
  28. package/lib/components/loading.ts +263 -0
  29. package/lib/components/main.ts +43 -17
  30. package/lib/components/menu.ts +108 -24
  31. package/lib/components/modal.ts +50 -21
  32. package/lib/components/nav.ts +60 -18
  33. package/lib/components/paragraph.ts +111 -0
  34. package/lib/components/progress.ts +276 -0
  35. package/lib/components/radio.ts +236 -0
  36. package/lib/components/req.ts +300 -0
  37. package/lib/components/script.ts +33 -74
  38. package/lib/components/select.ts +247 -0
  39. package/lib/components/sidebar.ts +86 -36
  40. package/lib/components/style.ts +47 -70
  41. package/lib/components/switch.ts +261 -0
  42. package/lib/components/table.ts +47 -24
  43. package/lib/components/tabs.ts +105 -63
  44. package/lib/components/theme-toggle.ts +361 -0
  45. package/lib/components/token-calculator.ts +380 -0
  46. package/lib/components/tooltip.ts +244 -0
  47. package/lib/components/view.ts +36 -20
  48. package/lib/components/write.ts +284 -0
  49. package/lib/globals.d.ts +21 -0
  50. package/lib/jux.ts +172 -68
  51. package/lib/presets/notion.css +521 -0
  52. package/lib/presets/notion.jux +27 -0
  53. package/lib/reactivity/state.ts +364 -0
  54. package/machinery/compiler.js +126 -38
  55. package/machinery/generators/html.js +2 -3
  56. package/machinery/server.js +2 -2
  57. package/package.json +29 -3
  58. package/lib/components/import.ts +0 -430
  59. package/lib/components/node.ts +0 -200
  60. package/lib/components/reactivity.js +0 -104
  61. package/lib/components/theme.ts +0 -97
  62. package/lib/layouts/notion.css +0 -258
  63. package/lib/styles/base-theme.css +0 -186
  64. package/lib/styles/dark-theme.css +0 -144
  65. package/lib/styles/light-theme.css +0 -144
  66. package/lib/styles/tokens/dark.css +0 -86
  67. package/lib/styles/tokens/light.css +0 -86
  68. package/lib/templates/index.juxt +0 -33
  69. package/lib/themes/dark.css +0 -86
  70. package/lib/themes/light.css +0 -86
  71. /package/lib/{styles → presets}/global.css +0 -0
@@ -1,4 +1,4 @@
1
- import { Reactive, getOrCreateContainer } from './reactivity.js';
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 extends Reactive {
30
- state!: MainState;
33
+ export class Main {
34
+ state: MainState;
31
35
  container: HTMLElement | null = null;
36
+ _id: string;
37
+ id: string;
32
38
 
33
- constructor(componentId: string, options: MainOptions = {}) {
34
- super();
35
- this._setComponentId(componentId);
39
+ constructor(id: string, options: MainOptions = {}) {
40
+ this._id = id;
41
+ this.id = id;
36
42
 
37
- this.state = this._createReactiveState({
43
+ this.state = {
38
44
  content: options.content ?? '',
39
- padding: options.padding ?? 'var(--space-xl)'
40
- }) as MainState;
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._componentId) as HTMLElement;
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._componentId;
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._componentId || typeof juxComponent._componentId !== 'string') {
99
- throw new Error('Main.renderTo: Invalid component - missing _componentId (not a Jux component)');
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._componentId}`);
128
+ return this.render(`#${juxComponent._id}`);
103
129
  }
104
130
  }
105
131
 
106
132
  /**
107
133
  * Factory helper
108
134
  */
109
- export function main(componentId: string, options: MainOptions = {}): Main {
110
- return new Main(componentId, options);
135
+ export function main(id: string, options: MainOptions = {}): Main {
136
+ return new Main(id, options);
111
137
  }
@@ -1,4 +1,5 @@
1
- import { Reactive, getOrCreateContainer } from './reactivity.js';
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
- onClick?: () => void;
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 extends Reactive {
44
- state!: MenuState;
51
+ export class Menu {
52
+ state: MenuState;
45
53
  container: HTMLElement | null = null;
54
+ _id: string;
55
+ id: string;
46
56
 
47
- constructor(componentId: string, options: MenuOptions = {}) {
48
- super();
49
- this._setComponentId(componentId);
57
+ constructor(id: string, options: MenuOptions = {}) {
58
+ this._id = id;
59
+ this.id = id;
50
60
 
51
- this.state = this._createReactiveState({
61
+ this.state = {
52
62
  items: options.items ?? [],
53
- orientation: options.orientation ?? 'vertical'
54
- }) as MenuState;
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.push(item);
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
- link.textContent = item.label;
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
- button.textContent = item.label;
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 - onClick
97
- if (item.onClick) {
98
- button.addEventListener('click', item.onClick);
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._componentId) as HTMLElement;
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._componentId;
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._componentId || typeof juxComponent._componentId !== 'string') {
158
- throw new Error('Menu.renderTo: Invalid component - missing _componentId (not a Jux component)');
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._componentId}`);
245
+ return this.render(`#${juxComponent._id}`);
162
246
  }
163
247
  }
164
248
 
165
249
  /**
166
250
  * Factory helper
167
251
  */
168
- export function menu(componentId: string, options: MenuOptions = {}): Menu {
169
- return new Menu(componentId, options);
252
+ export function menu(id: string, options: MenuOptions = {}): Menu {
253
+ return new Menu(id, options);
170
254
  }
@@ -1,4 +1,4 @@
1
- import { Reactive, getOrCreateContainer } from './reactivity.js';
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 extends Reactive {
39
- state!: ModalState;
42
+ export class Modal {
43
+ state: ModalState;
40
44
  container: HTMLElement | null = null;
45
+ _id: string;
46
+ id: string;
41
47
 
42
- constructor(componentId: string, options: ModalOptions = {}) {
43
- super();
44
- this._setComponentId(componentId);
48
+ constructor(id: string, options: ModalOptions = {}) {
49
+ this._id = id;
50
+ this.id = id;
45
51
 
46
- this.state = this._createReactiveState({
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
- }) as ModalState;
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._componentId) as HTMLElement;
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._componentId;
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
- document.addEventListener('keydown', (e) => {
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._componentId || typeof juxComponent._componentId !== 'string') {
204
- throw new Error('Modal.renderTo: Invalid component - missing _componentId (not a Jux component)');
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._componentId}`);
236
+ return this.render(`#${juxComponent._id}`);
208
237
  }
209
238
  }
210
239
 
211
240
  /**
212
241
  * Factory helper
213
242
  */
214
- export function modal(componentId: string, options: ModalOptions = {}): Modal {
215
- return new Modal(componentId, options);
243
+ export function modal(id: string, options: ModalOptions = {}): Modal {
244
+ return new Modal(id, options);
216
245
  }
@@ -1,4 +1,5 @@
1
- import { Reactive, getOrCreateContainer } from './reactivity.js';
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 extends Reactive {
42
- state!: NavState;
46
+ export class Nav {
47
+ state: NavState;
43
48
  container: HTMLElement | null = null;
49
+ _id: string;
50
+ id: string;
44
51
 
45
- constructor(componentId: string, options: NavOptions = {}) {
46
- super();
47
- this._setComponentId(componentId);
52
+ constructor(id: string, options: NavOptions = {}) {
53
+ this._id = id;
54
+ this.id = id;
48
55
 
49
- this.state = this._createReactiveState({
56
+ this.state = {
50
57
  items: options.items ?? [],
51
- variant: options.variant ?? 'default'
52
- }) as NavState;
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.push(item);
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._componentId) as HTMLElement;
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._componentId;
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._componentId || typeof juxComponent._componentId !== 'string') {
124
- throw new Error('Nav.renderTo: Invalid component - missing _componentId (not a Jux component)');
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._componentId}`);
169
+ return this.render(`#${juxComponent._id}`);
128
170
  }
129
171
  }
130
172
 
131
173
  /**
132
174
  * Factory helper
133
175
  */
134
- export function nav(componentId: string, options: NavOptions = {}): Nav {
135
- return new Nav(componentId, options);
176
+ export function nav(id: string, options: NavOptions = {}): Nav {
177
+ return new Nav(id, options);
136
178
  }