juxscript 1.1.14 → 1.1.16

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.
@@ -1,4 +1,4 @@
1
- import { BaseComponent } from './base/BaseComponent.js';
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
2
2
 
3
3
  // Event definitions - Hero is display-only, but CTA button can trigger actions
4
4
  const TRIGGER_EVENTS = [] as const;
@@ -18,7 +18,7 @@ export interface HeroOptions {
18
18
  class?: string;
19
19
  }
20
20
 
21
- type HeroState = {
21
+ type HeroState = BaseState & {
22
22
  title: string;
23
23
  subtitle: string;
24
24
  content: string;
@@ -28,8 +28,6 @@ type HeroState = {
28
28
  backgroundOverlay: boolean;
29
29
  variant: string;
30
30
  centered: boolean;
31
- style: string;
32
- class: string;
33
31
  };
34
32
 
35
33
  export class Hero extends BaseComponent<HeroState> {
@@ -71,7 +69,7 @@ export class Hero extends BaseComponent<HeroState> {
71
69
  */
72
70
  update(prop: string, value: any): void {
73
71
  const hero = document.getElementById(this._id);
74
- if (!hero) return; // Component not mounted/rendered yet
72
+ if (!hero) return;
75
73
 
76
74
  switch (prop) {
77
75
  case 'title':
@@ -85,17 +83,17 @@ export class Hero extends BaseComponent<HeroState> {
85
83
  break;
86
84
 
87
85
  case 'content':
88
- const contentEl = hero.querySelector('.jux-hero-body');
86
+ const contentEl = hero.querySelector('.jux-hero-body'); // ✅ BEM naming
89
87
  if (contentEl) contentEl.innerHTML = value;
90
88
  break;
91
89
 
92
90
  case 'cta':
93
- const ctaEl = hero.querySelector('.jux-hero-cta') as HTMLElement;
91
+ const ctaEl = hero.querySelector('.jux-hero-cta') as HTMLElement; // ✅ BEM naming
94
92
  if (ctaEl) ctaEl.textContent = value;
95
93
  break;
96
94
 
97
95
  case 'ctaLink':
98
- const ctaLinkEl = hero.querySelector('.jux-hero-cta') as HTMLAnchorElement;
96
+ const ctaLinkEl = hero.querySelector('.jux-hero-cta') as HTMLAnchorElement; // ✅ BEM naming
99
97
  if (ctaLinkEl) ctaLinkEl.href = value;
100
98
  break;
101
99
 
@@ -106,8 +104,7 @@ export class Hero extends BaseComponent<HeroState> {
106
104
  break;
107
105
 
108
106
  case 'centered':
109
- if (value) hero.classList.add('jux-hero-centered');
110
- else hero.classList.remove('jux-hero-centered');
107
+ hero.classList.toggle('jux-hero-centered', value); // ✅ BEM modifier
111
108
  break;
112
109
  }
113
110
  }
@@ -228,7 +225,6 @@ export class Hero extends BaseComponent<HeroState> {
228
225
  ctaButton.href = this.state.ctaLink;
229
226
  ctaButton.textContent = this.state.cta;
230
227
 
231
- // ✅ Fire callback when CTA is clicked
232
228
  ctaButton.addEventListener('click', (e) => {
233
229
  this._triggerCallback('ctaClick', e);
234
230
  });
@@ -239,7 +235,7 @@ export class Hero extends BaseComponent<HeroState> {
239
235
  hero.appendChild(contentContainer);
240
236
 
241
237
  this._wireStandardEvents(hero);
242
- this._wireAllSyncs(); // Use base method
238
+ this._wireAllSyncs();
243
239
 
244
240
  container.appendChild(hero);
245
241
  return this;
@@ -1,5 +1,13 @@
1
- import { BaseComponent } from './base/BaseComponent.js';
2
- import { MenuOptions } from './menu.js';
1
+ import { BaseComponent, BaseState } from './base/BaseComponent.js';
2
+ export interface SidebarItem {
3
+ label: string;
4
+ href?: string;
5
+ click?: () => void;
6
+ icon?: string;
7
+ items?: SidebarItem[];
8
+ active?: boolean;
9
+ itemClass?: string;
10
+ }
3
11
  export interface SidebarOptions {
4
12
  position?: 'left' | 'right';
5
13
  width?: string;
@@ -7,42 +15,44 @@ export interface SidebarOptions {
7
15
  showToggle?: boolean;
8
16
  expandOnHover?: boolean;
9
17
  collapsed?: boolean;
10
- menu?: MenuOptions;
18
+ items?: SidebarItem[];
19
+ header?: string;
20
+ footer?: string;
11
21
  style?: string;
12
22
  class?: string;
13
23
  }
14
- type SidebarState = {
24
+ type SidebarState = BaseState & {
15
25
  position: 'left' | 'right';
16
26
  width: string;
17
27
  collapsible: boolean;
18
28
  showToggle: boolean;
19
29
  expandOnHover: boolean;
20
30
  collapsed: boolean;
21
- menu: MenuOptions | null;
22
- style: string;
23
- class: string;
31
+ items: SidebarItem[];
32
+ header: string;
33
+ footer: string;
24
34
  };
25
35
  export declare class Sidebar extends BaseComponent<SidebarState> {
26
36
  private _sidebar;
27
- private _menu;
28
37
  constructor(id: string, options?: SidebarOptions);
29
38
  protected getTriggerEvents(): readonly string[];
30
39
  protected getCallbackEvents(): readonly string[];
40
+ private _setActiveStates;
41
+ private _renderItem;
42
+ update(prop: string, value: any): void;
31
43
  width(value: string): this;
32
44
  position(value: 'left' | 'right'): this;
33
45
  collapsible(value: boolean): this;
34
46
  showToggle(value: boolean): this;
35
47
  expandOnHover(value: boolean): this;
36
48
  collapsed(value: boolean): this;
37
- menu(value: MenuOptions): this;
49
+ items(value: SidebarItem[]): this;
50
+ addItem(item: SidebarItem): this;
51
+ header(value: string): this;
52
+ footer(value: string): this;
38
53
  toggle(): void;
39
- /**
40
- * Refresh menu active states (called automatically on URL changes)
41
- */
42
- refreshMenu(): this;
43
- private _updateCollapsedState;
54
+ refreshActiveStates(): this;
44
55
  render(targetId?: string): this;
45
- update(prop: string, value: any): void;
46
56
  }
47
57
  export declare function sidebar(id: string, options?: SidebarOptions): Sidebar;
48
58
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,OAAO,EAAQ,WAAW,EAAE,MAAM,WAAW,CAAC;AAO9C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,YAAY,GAAG;IAClB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,qBAAa,OAAQ,SAAQ,aAAa,CAAC,YAAY,CAAC;IACtD,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,KAAK,CAAqB;gBAEtB,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;IAwBpD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAiBhD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAKvC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKjC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKhC,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKnC,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAM/B,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAK9B,MAAM,IAAI,IAAI;IAYd;;OAEG;IACH,WAAW,IAAI,IAAI;IAQnB,OAAO,CAAC,qBAAqB;IAU7B,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;IAwH/B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;CAGvC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAEzE"}
1
+ {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["sidebar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAQnE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,KAAK,YAAY,GAAG,SAAS,GAAG;IAC9B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,qBAAa,OAAQ,SAAQ,aAAa,CAAC,YAAY,CAAC;IACtD,OAAO,CAAC,QAAQ,CAA4B;gBAEhC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB;IA4BpD,SAAS,CAAC,gBAAgB,IAAI,SAAS,MAAM,EAAE;IAI/C,SAAS,CAAC,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAQhD,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,WAAW;IA+FnB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,IAAI;IAsCtC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAKvC,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKjC,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKhC,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAKnC,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI;IAK/B,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI;IAKjC,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAKhC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK3B,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK3B,MAAM,IAAI,IAAI;IAKd,mBAAmB,IAAI,IAAI;IAU3B,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI;CA2FhC;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAEzE"}
@@ -1,9 +1,9 @@
1
1
  import { BaseComponent } from './base/BaseComponent.js';
2
2
  import { renderIcon } from './icons.js';
3
- import { Menu } from './menu.js';
3
+ import { req } from './req.js';
4
4
  // Event definitions
5
5
  const TRIGGER_EVENTS = [];
6
- const CALLBACK_EVENTS = ['toggle'];
6
+ const CALLBACK_EVENTS = ['toggle', 'itemClick'];
7
7
  export class Sidebar extends BaseComponent {
8
8
  constructor(id, options = {}) {
9
9
  // Restore collapsed state from localStorage if available
@@ -17,15 +17,17 @@ export class Sidebar extends BaseComponent {
17
17
  showToggle: options.showToggle ?? false,
18
18
  expandOnHover: options.expandOnHover ?? false,
19
19
  collapsed: initialCollapsed,
20
- menu: options.menu ?? null,
20
+ items: options.items ?? [],
21
+ header: options.header ?? '',
22
+ footer: options.footer ?? '',
21
23
  style: options.style ?? '',
22
24
  class: options.class ?? ''
23
25
  });
24
26
  this._sidebar = null;
25
- this._menu = null;
26
- // Listen for URL changes to update menu active states
27
+ this._setActiveStates();
28
+ // Listen for URL changes to update active states
27
29
  if (typeof window !== 'undefined') {
28
- window.addEventListener('popstate', () => this.refreshMenu());
30
+ window.addEventListener('popstate', () => this.refreshActiveStates());
29
31
  }
30
32
  }
31
33
  getTriggerEvents() {
@@ -34,19 +36,138 @@ export class Sidebar extends BaseComponent {
34
36
  getCallbackEvents() {
35
37
  return CALLBACK_EVENTS;
36
38
  }
39
+ /* ═════════════════════════════════════════════════════════════════
40
+ * PRIVATE HELPERS
41
+ * ═════════════════════════════════════════════════════════════════ */
42
+ _setActiveStates() {
43
+ this.state.items = this.state.items.map(item => ({
44
+ ...item,
45
+ active: item.href ? req.isActiveNavItem(item.href) : false,
46
+ items: item.items?.map(subItem => ({
47
+ ...subItem,
48
+ active: subItem.href ? req.isActiveNavItem(subItem.href) : false
49
+ }))
50
+ }));
51
+ }
52
+ _renderItem(item) {
53
+ const itemEl = document.createElement('div');
54
+ itemEl.className = 'jux-sidebar-item';
55
+ if (item.itemClass) {
56
+ itemEl.className += ` ${item.itemClass}`;
57
+ }
58
+ if (item.active) {
59
+ itemEl.classList.add('jux-sidebar-item-active');
60
+ }
61
+ if (item.href) {
62
+ const link = document.createElement('a');
63
+ link.className = 'jux-sidebar-link';
64
+ link.href = item.href;
65
+ if (item.active) {
66
+ link.classList.add('jux-sidebar-link-active');
67
+ }
68
+ if (item.icon) {
69
+ const icon = document.createElement('span');
70
+ icon.className = 'jux-sidebar-icon';
71
+ icon.appendChild(renderIcon(item.icon));
72
+ link.appendChild(icon);
73
+ }
74
+ const label = document.createElement('span');
75
+ label.className = 'jux-sidebar-label';
76
+ label.textContent = item.label;
77
+ link.appendChild(label);
78
+ link.addEventListener('click', (e) => {
79
+ this._triggerCallback('itemClick', { item, event: e });
80
+ });
81
+ itemEl.appendChild(link);
82
+ }
83
+ else {
84
+ const button = document.createElement('button');
85
+ button.className = 'jux-sidebar-button';
86
+ button.type = 'button';
87
+ if (item.icon) {
88
+ const icon = document.createElement('span');
89
+ icon.className = 'jux-sidebar-icon';
90
+ icon.appendChild(renderIcon(item.icon));
91
+ button.appendChild(icon);
92
+ }
93
+ const label = document.createElement('span');
94
+ label.className = 'jux-sidebar-label';
95
+ label.textContent = item.label;
96
+ button.appendChild(label);
97
+ button.addEventListener('click', (e) => {
98
+ if (item.click) {
99
+ item.click();
100
+ }
101
+ this._triggerCallback('itemClick', { item, event: e });
102
+ });
103
+ itemEl.appendChild(button);
104
+ }
105
+ if (item.items && item.items.length > 0) {
106
+ itemEl.classList.add('jux-sidebar-item-has-submenu');
107
+ const submenu = document.createElement('div');
108
+ submenu.className = 'jux-sidebar-submenu';
109
+ item.items.forEach(subItem => {
110
+ submenu.appendChild(this._renderItem(subItem));
111
+ });
112
+ itemEl.appendChild(submenu);
113
+ const clickTarget = itemEl.querySelector('a, button');
114
+ if (clickTarget) {
115
+ clickTarget.addEventListener('click', (e) => {
116
+ if (!item.href) {
117
+ e.preventDefault();
118
+ }
119
+ itemEl.classList.toggle('jux-sidebar-item-expanded');
120
+ });
121
+ }
122
+ }
123
+ return itemEl;
124
+ }
125
+ /* ═════════════════════════════════════════════════════════════════
126
+ * REACTIVE UPDATE
127
+ * ═════════════════════════════════════════════════════════════════ */
128
+ update(prop, value) {
129
+ if (!this._sidebar)
130
+ return;
131
+ if (prop === 'collapsed') {
132
+ this._sidebar.classList.toggle('jux-sidebar-collapsed', value);
133
+ // Update toggle button state
134
+ const toggleBtn = this._sidebar.querySelector('.jux-sidebar-toggle');
135
+ if (toggleBtn) {
136
+ toggleBtn.classList.toggle('jux-sidebar-toggle-collapsed', value);
137
+ }
138
+ // Save to localStorage
139
+ const storageKey = `jux-sidebar-${this._id}-collapsed`;
140
+ localStorage.setItem(storageKey, String(value));
141
+ }
142
+ else if (prop === 'items') {
143
+ this._setActiveStates();
144
+ const nav = this._sidebar.querySelector('.jux-sidebar-nav');
145
+ if (nav) {
146
+ nav.innerHTML = '';
147
+ this.state.items.forEach(item => {
148
+ nav.appendChild(this._renderItem(item));
149
+ });
150
+ }
151
+ }
152
+ else if (prop === 'header') {
153
+ const header = this._sidebar.querySelector('.jux-sidebar-header');
154
+ if (header)
155
+ header.textContent = value;
156
+ }
157
+ else if (prop === 'footer') {
158
+ const footer = this._sidebar.querySelector('.jux-sidebar-footer');
159
+ if (footer)
160
+ footer.textContent = value;
161
+ }
162
+ }
37
163
  /* ═════════════════════════════════════════════════════════════════
38
164
  * FLUENT API
39
165
  * ═════════════════════════════════════════════════════════════════ */
40
- // ✅ Inherited from BaseComponent:
41
- // - style(), class()
42
- // - bind(), sync(), renderTo()
43
- // - addClass(), removeClass(), toggleClass()
44
- // - visible(), show(), hide()
45
- // - attr(), attrs(), removeAttr()
46
- // - disabled(), enable(), disable()
47
- // - loading(), focus(), blur(), remove()
48
166
  width(value) {
49
167
  this.state.width = value;
168
+ if (this._sidebar) {
169
+ this._sidebar.style.width = value;
170
+ }
50
171
  return this;
51
172
  }
52
173
  position(value) {
@@ -67,64 +188,74 @@ export class Sidebar extends BaseComponent {
67
188
  }
68
189
  collapsed(value) {
69
190
  this.state.collapsed = value;
70
- this._updateCollapsedState();
71
191
  return this;
72
192
  }
73
- menu(value) {
74
- this.state.menu = value;
193
+ items(value) {
194
+ this.state.items = value;
195
+ return this;
196
+ }
197
+ addItem(item) {
198
+ this.state.items = [...this.state.items, item];
199
+ return this;
200
+ }
201
+ header(value) {
202
+ this.state.header = value;
203
+ return this;
204
+ }
205
+ footer(value) {
206
+ this.state.footer = value;
75
207
  return this;
76
208
  }
77
209
  toggle() {
78
210
  this.state.collapsed = !this.state.collapsed;
79
- this._updateCollapsedState();
80
- // Save to localStorage
81
- const storageKey = `jux-sidebar-${this._id}-collapsed`;
82
- localStorage.setItem(storageKey, String(this.state.collapsed));
83
- // 🎯 Fire the toggle callback event
84
211
  this._triggerCallback('toggle', this.state.collapsed);
85
212
  }
86
- /**
87
- * Refresh menu active states (called automatically on URL changes)
88
- */
89
- refreshMenu() {
90
- if (this._menu && this.state.menu) {
91
- // Re-evaluate and update menu items with current active states
92
- this._menu.items(this.state.menu.items || []);
93
- }
213
+ refreshActiveStates() {
214
+ this._setActiveStates();
215
+ this.state.items = [...this.state.items]; // Trigger update
94
216
  return this;
95
217
  }
96
- _updateCollapsedState() {
97
- if (this._sidebar) {
98
- this._sidebar.classList.toggle('jux-sidebar-collapsed', this.state.collapsed);
99
- }
100
- }
101
218
  /* ═════════════════════════════════════════════════════════════════
102
219
  * RENDER
103
220
  * ═════════════════════════════════════════════════════════════════ */
104
221
  render(targetId) {
105
222
  const container = this._setupContainer(targetId);
106
- const { position, collapsed, expandOnHover, menu, style, class: className } = this.state;
107
- // Build sidebar element
223
+ const { position, collapsed, expandOnHover, items, header, footer, width, style, class: className } = this.state;
108
224
  const sidebar = document.createElement('aside');
225
+ sidebar.className = `jux-sidebar jux-sidebar-${position}`;
109
226
  sidebar.id = this._id;
227
+ if (collapsed) {
228
+ sidebar.classList.add('jux-sidebar-collapsed');
229
+ }
110
230
  if (className)
111
- sidebar.className = className;
231
+ sidebar.className += ` ${className}`;
112
232
  if (style)
113
233
  sidebar.setAttribute('style', style);
114
- // Apply initial collapsed state
115
- if (collapsed) {
116
- sidebar.classList.add('jux-sidebar-collapsed');
234
+ if (width)
235
+ sidebar.style.width = width;
236
+ if (header) {
237
+ const headerEl = document.createElement('div');
238
+ headerEl.className = 'jux-sidebar-header';
239
+ headerEl.textContent = header;
240
+ sidebar.appendChild(headerEl);
241
+ }
242
+ const nav = document.createElement('nav');
243
+ nav.className = 'jux-sidebar-nav';
244
+ items.forEach(item => {
245
+ nav.appendChild(this._renderItem(item));
246
+ });
247
+ sidebar.appendChild(nav);
248
+ if (footer) {
249
+ const footerEl = document.createElement('div');
250
+ footerEl.className = 'jux-sidebar-footer';
251
+ footerEl.textContent = footer;
252
+ sidebar.appendChild(footerEl);
117
253
  }
118
- // Menu container (append first so toggle appears at bottom)
119
- const menuContainer = document.createElement('div');
120
- menuContainer.className = 'jux-sidebar-menu';
121
- menuContainer.id = `${this._id}-menu`;
122
- sidebar.appendChild(menuContainer);
123
- // Toggle button (append last so it appears at bottom)
124
254
  if (this.state.collapsible || this.state.showToggle) {
125
255
  const toggleBtn = document.createElement('button');
126
256
  toggleBtn.className = 'jux-sidebar-toggle';
127
257
  toggleBtn.type = 'button';
258
+ toggleBtn.setAttribute('aria-label', 'Toggle sidebar');
128
259
  const toggleIcon = document.createElement('span');
129
260
  toggleIcon.className = 'jux-sidebar-toggle-icon';
130
261
  const chevronIcon = renderIcon(position === 'left' ? '➡️' : '⬅️');
@@ -135,11 +266,9 @@ export class Sidebar extends BaseComponent {
135
266
  }
136
267
  toggleBtn.addEventListener('click', () => {
137
268
  this.toggle();
138
- toggleBtn.classList.toggle('jux-sidebar-toggle-collapsed', this.state.collapsed);
139
269
  });
140
270
  sidebar.appendChild(toggleBtn);
141
271
  }
142
- // Handle expand on hover
143
272
  if (expandOnHover) {
144
273
  sidebar.addEventListener('mouseenter', () => {
145
274
  if (this.state.collapsed) {
@@ -152,48 +281,10 @@ export class Sidebar extends BaseComponent {
152
281
  }
153
282
  });
154
283
  }
155
- // Wire events using inherited method
156
284
  this._wireStandardEvents(sidebar);
157
- // Wire sync bindings for 'collapsed' property
158
- this._syncBindings.forEach(({ property, stateObj, toState, toComponent }) => {
159
- if (property === 'collapsed') {
160
- const transform = toComponent || ((v) => v);
161
- stateObj.subscribe((val) => {
162
- const transformed = transform(val);
163
- const isCollapsed = Boolean(transformed);
164
- this.state.collapsed = isCollapsed;
165
- this._updateCollapsedState();
166
- });
167
- }
168
- else if (property === 'menu') {
169
- const transform = toComponent || ((v) => v);
170
- stateObj.subscribe((val) => {
171
- const transformed = transform(val);
172
- this.state.menu = transformed;
173
- // Update menu items if menu instance exists
174
- if (this._menu) {
175
- this._menu.items(transformed.items || []);
176
- // Re-render the menu
177
- const menuEl = menuContainer.querySelector(`#${this._id}-menu-instance`);
178
- if (menuEl) {
179
- menuEl.remove();
180
- }
181
- this._menu.render(`#${menuContainer.id}`);
182
- }
183
- });
184
- }
185
- });
285
+ this._wireAllSyncs();
186
286
  container.appendChild(sidebar);
187
287
  this._sidebar = sidebar;
188
- // Create and render menu (after sidebar is in DOM)
189
- if (menu) {
190
- this._menu = new Menu(`${this._id}-menu-instance`, {
191
- ...menu,
192
- orientation: 'vertical'
193
- });
194
- this._menu.render(`#${menuContainer.id}`);
195
- }
196
- // Trigger Iconify icon rendering
197
288
  requestAnimationFrame(() => {
198
289
  if (window.Iconify) {
199
290
  window.Iconify.scan();
@@ -201,9 +292,6 @@ export class Sidebar extends BaseComponent {
201
292
  });
202
293
  return this;
203
294
  }
204
- update(prop, value) {
205
- // No reactive updates needed
206
- }
207
295
  }
208
296
  export function sidebar(id, options = {}) {
209
297
  return new Sidebar(id, options);