@designbasekorea/ui-wc 0.5.6 → 0.6.1

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 (193) hide show
  1. package/dist/chunks/lottie-35a9b0f5.js +1 -0
  2. package/dist/esm/components/animation-background/canvas-controller.js +1 -121
  3. package/dist/esm/components/animation-background/controls.js +1 -180
  4. package/dist/esm/components/animation-background/graphite-controller.js +1 -196
  5. package/dist/esm/components/animation-background/graphite-presets.js +1 -42
  6. package/dist/esm/components/animation-background/graphite-shader.js +1 -111
  7. package/dist/esm/components/animation-background/layers.js +1 -369
  8. package/dist/esm/components/animation-background/lumina-presets.js +1 -53
  9. package/dist/esm/components/animation-background/lumina-shaders.js +1 -181
  10. package/dist/esm/components/animation-background/lumina-utils.js +1 -60
  11. package/dist/esm/components/animation-background/particle-defaults.js +1 -36
  12. package/dist/esm/components/animation-background/renderers.js +1 -167
  13. package/dist/esm/components/animation-background/shader-controller.js +1 -154
  14. package/dist/esm/components/color-picker-utils.js +1 -134
  15. package/dist/esm/components/date-picker-utils.js +1 -140
  16. package/dist/esm/components/db-accordion.js +1 -304
  17. package/dist/esm/components/db-ad-banner.js +1 -455
  18. package/dist/esm/components/db-ai-chat-list.d.ts +43 -0
  19. package/dist/esm/components/db-ai-chat-list.js +1 -0
  20. package/dist/esm/components/db-ai-chat.d.ts +159 -0
  21. package/dist/esm/components/db-ai-chat.js +1 -0
  22. package/dist/esm/components/db-alert.js +1 -149
  23. package/dist/esm/components/db-animation-background.js +1 -486
  24. package/dist/esm/components/db-animation-text.js +1 -601
  25. package/dist/esm/components/db-app-badge.js +1 -88
  26. package/dist/esm/components/db-audio-player.js +1 -752
  27. package/dist/esm/components/db-avatar.js +1 -188
  28. package/dist/esm/components/db-backdrop.js +1 -139
  29. package/dist/esm/components/db-badge.js +1 -91
  30. package/dist/esm/components/db-banner.js +1 -188
  31. package/dist/esm/components/db-bottom-navigation.js +1 -146
  32. package/dist/esm/components/db-bottom-sheet.js +1 -481
  33. package/dist/esm/components/db-breadcrumbs.js +1 -329
  34. package/dist/esm/components/db-button.js +1 -316
  35. package/dist/esm/components/db-calendar.js +1 -675
  36. package/dist/esm/components/db-card.js +1 -265
  37. package/dist/esm/components/db-carousel.js +1 -264
  38. package/dist/esm/components/db-chat-composer.d.ts +134 -0
  39. package/dist/esm/components/db-chat-composer.js +1 -0
  40. package/dist/esm/components/db-chat-list.d.ts +47 -0
  41. package/dist/esm/components/db-chat-list.js +1 -0
  42. package/dist/esm/components/db-chat-message.d.ts +39 -0
  43. package/dist/esm/components/db-chat-message.js +1 -0
  44. package/dist/esm/components/db-chat-orb.d.ts +99 -0
  45. package/dist/esm/components/db-chat-orb.js +1 -0
  46. package/dist/esm/components/db-chat-room.d.ts +71 -0
  47. package/dist/esm/components/db-chat-room.js +1 -0
  48. package/dist/esm/components/db-chat-suggestions.d.ts +44 -0
  49. package/dist/esm/components/db-chat-suggestions.js +1 -0
  50. package/dist/esm/components/db-chat-typing.d.ts +22 -0
  51. package/dist/esm/components/db-chat-typing.js +1 -0
  52. package/dist/esm/components/db-chat-welcome.d.ts +32 -0
  53. package/dist/esm/components/db-chat-welcome.js +1 -0
  54. package/dist/esm/components/db-chat-widget.d.ts +146 -0
  55. package/dist/esm/components/db-chat-widget.js +1 -0
  56. package/dist/esm/components/db-checkbox.js +1 -202
  57. package/dist/esm/components/db-chip.js +1 -104
  58. package/dist/esm/components/db-code-block.js +1 -304
  59. package/dist/esm/components/db-color-picker.js +1 -746
  60. package/dist/esm/components/db-confirm.js +1 -191
  61. package/dist/esm/components/db-container.js +1 -39
  62. package/dist/esm/components/db-context-menu.js +1 -265
  63. package/dist/esm/components/db-countdown.js +1 -146
  64. package/dist/esm/components/db-cursor-follower.js +1 -173
  65. package/dist/esm/components/db-date-picker.js +1 -837
  66. package/dist/esm/components/db-divider.js +1 -66
  67. package/dist/esm/components/db-download-progress.d.ts +89 -0
  68. package/dist/esm/components/db-download-progress.js +1 -0
  69. package/dist/esm/components/db-drawer.js +1 -245
  70. package/dist/esm/components/db-dropdown.js +1 -493
  71. package/dist/esm/components/db-dropzone.js +1 -266
  72. package/dist/esm/components/db-email-verify.d.ts +64 -0
  73. package/dist/esm/components/db-email-verify.js +1 -0
  74. package/dist/esm/components/db-empty-state.js +1 -97
  75. package/dist/esm/components/db-file-uploader.js +1 -256
  76. package/dist/esm/components/db-floating-action-button.js +1 -139
  77. package/dist/esm/components/db-footer.js +1 -385
  78. package/dist/esm/components/db-form.js +1 -566
  79. package/dist/esm/components/db-gantt.js +1 -882
  80. package/dist/esm/components/db-gradient.js +1 -133
  81. package/dist/esm/components/db-grid-background.js +1 -909
  82. package/dist/esm/components/db-grid.js +1 -73
  83. package/dist/esm/components/db-icons.d.ts +3 -0
  84. package/dist/esm/components/db-icons.js +1 -82
  85. package/dist/esm/components/db-image-list.js +1 -214
  86. package/dist/esm/components/db-image-placeholder.js +1 -96
  87. package/dist/esm/components/db-image.js +1 -289
  88. package/dist/esm/components/db-indicator.js +1 -517
  89. package/dist/esm/components/db-input.js +1 -420
  90. package/dist/esm/components/db-kanban.js +1 -538
  91. package/dist/esm/components/db-label.js +1 -66
  92. package/dist/esm/components/db-lightbox.js +1 -372
  93. package/dist/esm/components/db-list.js +1 -340
  94. package/dist/esm/components/db-logo-svg.js +1 -72
  95. package/dist/esm/components/db-logo.js +1 -106
  96. package/dist/esm/components/db-lottie.js +1 -109
  97. package/dist/esm/components/db-markdown-editor.js +1 -458
  98. package/dist/esm/components/db-marquee.js +1 -402
  99. package/dist/esm/components/db-masonry.js +1 -94
  100. package/dist/esm/components/db-menu-item.js +1 -211
  101. package/dist/esm/components/db-modal.js +1 -522
  102. package/dist/esm/components/db-navbar.js +1 -680
  103. package/dist/esm/components/db-onboarding-modal.js +1 -322
  104. package/dist/esm/components/db-otp-input.d.ts +53 -0
  105. package/dist/esm/components/db-otp-input.js +1 -0
  106. package/dist/esm/components/db-page-header.js +1 -312
  107. package/dist/esm/components/db-pagination.js +1 -271
  108. package/dist/esm/components/db-phone-verify.d.ts +63 -0
  109. package/dist/esm/components/db-phone-verify.js +1 -0
  110. package/dist/esm/components/db-popover.js +1 -580
  111. package/dist/esm/components/db-progress-step.js +1 -166
  112. package/dist/esm/components/db-progress.js +1 -171
  113. package/dist/esm/components/db-progressbar.js +1 -72
  114. package/dist/esm/components/db-radio.js +1 -172
  115. package/dist/esm/components/db-random-gradient.js +1 -121
  116. package/dist/esm/components/db-range-slider.js +1 -811
  117. package/dist/esm/components/db-rating.js +1 -325
  118. package/dist/esm/components/db-reorder.js +1 -286
  119. package/dist/esm/components/db-resizable-panels.js +1 -282
  120. package/dist/esm/components/db-scroll-area.js +1 -126
  121. package/dist/esm/components/db-search-bar.js +1 -668
  122. package/dist/esm/components/db-section-app-download.js +1 -101
  123. package/dist/esm/components/db-section-contact.js +1 -102
  124. package/dist/esm/components/db-section-cta.js +1 -150
  125. package/dist/esm/components/db-section-faq.js +1 -120
  126. package/dist/esm/components/db-section-feature-grid.js +1 -137
  127. package/dist/esm/components/db-section-feature.js +1 -179
  128. package/dist/esm/components/db-section-hero.js +1 -243
  129. package/dist/esm/components/db-section-logo-cloud.js +1 -138
  130. package/dist/esm/components/db-section-pricing.js +1 -166
  131. package/dist/esm/components/db-section-stats.js +1 -129
  132. package/dist/esm/components/db-section-testimonials.js +1 -252
  133. package/dist/esm/components/db-section.js +1 -385
  134. package/dist/esm/components/db-segment-control.js +1 -231
  135. package/dist/esm/components/db-select.js +1 -571
  136. package/dist/esm/components/db-share-icons.js +1 -40
  137. package/dist/esm/components/db-share.js +1 -489
  138. package/dist/esm/components/db-sidebar.d.ts +20 -0
  139. package/dist/esm/components/db-sidebar.js +1 -1068
  140. package/dist/esm/components/db-skeleton.js +1 -94
  141. package/dist/esm/components/db-spinner.js +1 -102
  142. package/dist/esm/components/db-split-view.js +1 -297
  143. package/dist/esm/components/db-stack.js +1 -46
  144. package/dist/esm/components/db-stat.js +1 -218
  145. package/dist/esm/components/db-stepper.js +1 -398
  146. package/dist/esm/components/db-table.js +1 -412
  147. package/dist/esm/components/db-tabs.js +1 -335
  148. package/dist/esm/components/db-testimonial.d.ts +2 -0
  149. package/dist/esm/components/db-testimonial.js +1 -162
  150. package/dist/esm/components/db-textarea.js +1 -233
  151. package/dist/esm/components/db-time-picker.js +1 -523
  152. package/dist/esm/components/db-timeline.js +1 -174
  153. package/dist/esm/components/db-toast.js +1 -158
  154. package/dist/esm/components/db-toggle.js +1 -162
  155. package/dist/esm/components/db-toolbar.js +1 -94
  156. package/dist/esm/components/db-tooltip.js +1 -440
  157. package/dist/esm/components/db-top-banner.js +1 -121
  158. package/dist/esm/components/db-tutorial.js +1 -324
  159. package/dist/esm/components/db-two-factor.d.ts +71 -0
  160. package/dist/esm/components/db-two-factor.js +1 -0
  161. package/dist/esm/components/db-video-player.js +1 -503
  162. package/dist/esm/components/db-youtube-player.js +1 -194
  163. package/dist/esm/components/highlight-code.js +1 -65
  164. package/dist/esm/components/input-validation.js +1 -50
  165. package/dist/esm/components/marketing-block-host-utils.js +1 -9
  166. package/dist/esm/components/number-scrub.js +1 -117
  167. package/dist/esm/components/random-gradient-palettes.js +1 -67
  168. package/dist/esm/components/section-block-header-utils.js +1 -48
  169. package/dist/esm/helpers/confirm.js +1 -52
  170. package/dist/esm/helpers/toast.js +1 -73
  171. package/dist/esm/index.d.ts +16 -0
  172. package/dist/esm/index.js +1 -111
  173. package/dist/esm/node_modules/prismjs/components/prism-bash.js +1 -235
  174. package/dist/esm/node_modules/prismjs/components/prism-clike.js +1 -31
  175. package/dist/esm/node_modules/prismjs/components/prism-css.js +1 -64
  176. package/dist/esm/node_modules/prismjs/components/prism-javascript.js +1 -172
  177. package/dist/esm/node_modules/prismjs/components/prism-json.js +1 -27
  178. package/dist/esm/node_modules/prismjs/components/prism-jsx.js +1 -143
  179. package/dist/esm/node_modules/prismjs/components/prism-markup.js +1 -186
  180. package/dist/esm/node_modules/prismjs/components/prism-scss.js +1 -81
  181. package/dist/esm/node_modules/prismjs/components/prism-tsx.js +1 -15
  182. package/dist/esm/node_modules/prismjs/components/prism-typescript.js +1 -60
  183. package/dist/index.cjs +1 -55414
  184. package/dist/index.css +1 -1
  185. package/dist/index.d.ts +1125 -2
  186. package/dist/index.esm.js +1 -38284
  187. package/dist/react/chunks/lottie-14e7addb.js +1 -0
  188. package/dist/react/index.cjs +1 -56503
  189. package/dist/react/index.d.ts +1637 -21
  190. package/dist/react/index.esm.js +1 -39373
  191. package/package.json +2 -2
  192. package/dist/chunks/lottie-e273b936.js +0 -17032
  193. package/dist/react/chunks/lottie-72a4c6d4.js +0 -17032
@@ -1,1068 +1 @@
1
- import { createDbIcon, isDbIconName } from './db-icons.js';
2
-
3
- const SIZES = ['s', 'm', 'l'];
4
- const VARIANTS = ['default', 'dark', 'light'];
5
- const POSITIONS = ['left', 'right'];
6
- const FLYOUT_CLOSE_DELAY_MS = 120;
7
- class DbSidebar extends HTMLElement {
8
- constructor() {
9
- super(...arguments);
10
- this.expandedItems = new Set();
11
- this.userMenuOpen = false;
12
- this.projectMenuOpen = false;
13
- this.flyoutItemId = null;
14
- this.flyoutCloseTimer = null;
15
- this.outsideHandler = null;
16
- }
17
- static get observedAttributes() {
18
- return [
19
- 'items',
20
- 'sections',
21
- 'user-menu-items',
22
- 'user-profile',
23
- 'default-expanded-ids',
24
- 'projects',
25
- 'selected-project-id',
26
- 'project-manage-label',
27
- 'project-manage-href',
28
- 'project-section-label',
29
- 'project-empty-label',
30
- 'project-empty-trigger-label',
31
- 'bottom-items',
32
- 'bottom-sections',
33
- 'promo-banner',
34
- 'size',
35
- 'variant',
36
- 'position',
37
- 'collapsed',
38
- 'collapsible',
39
- 'show-logo',
40
- 'full-height',
41
- 'shadow',
42
- ];
43
- }
44
- connectedCallback() {
45
- this.seedExpanded();
46
- this.render();
47
- this.bindOutsideClick();
48
- }
49
- disconnectedCallback() {
50
- this.unbindOutsideClick();
51
- this.cancelFlyoutClose();
52
- }
53
- attributeChangedCallback(name) {
54
- if (!this.isConnected)
55
- return;
56
- if (name === 'default-expanded-ids')
57
- this.seedExpanded();
58
- if (name === 'collapsed' && this.hasAttribute('collapsed')) {
59
- this.userMenuOpen = false;
60
- this.projectMenuOpen = false;
61
- this.flyoutItemId = null;
62
- this.cancelFlyoutClose();
63
- }
64
- this.render();
65
- }
66
- seedExpanded() {
67
- try {
68
- const ids = JSON.parse(this.getAttribute('default-expanded-ids') || '[]');
69
- if (Array.isArray(ids))
70
- this.expandedItems = new Set(ids);
71
- }
72
- catch {
73
- this.expandedItems = new Set();
74
- }
75
- }
76
- get items() {
77
- try {
78
- const parsed = JSON.parse(this.getAttribute('items') || '[]');
79
- return Array.isArray(parsed) ? parsed : [];
80
- }
81
- catch {
82
- return [];
83
- }
84
- }
85
- set items(value) {
86
- this.setAttribute('items', typeof value === 'string' ? value : JSON.stringify(value));
87
- }
88
- get sections() {
89
- return this.parseSections();
90
- }
91
- set sections(value) {
92
- this.setAttribute('sections', typeof value === 'string' ? value : JSON.stringify(value));
93
- }
94
- get userMenuItems() {
95
- return this.parseUserMenuItems();
96
- }
97
- set userMenuItems(value) {
98
- this.setAttribute('user-menu-items', typeof value === 'string' ? value : JSON.stringify(value));
99
- }
100
- get userProfile() {
101
- return this.parseUserProfile();
102
- }
103
- set userProfile(value) {
104
- if (value === null || value === undefined)
105
- this.removeAttribute('user-profile');
106
- else
107
- this.setAttribute('user-profile', typeof value === 'string' ? value : JSON.stringify(value));
108
- }
109
- get projects() {
110
- return this.parseProjects();
111
- }
112
- set projects(value) {
113
- this.setAttribute('projects', typeof value === 'string' ? value : JSON.stringify(value));
114
- }
115
- get selectedProjectId() {
116
- return this.getAttribute('selected-project-id') || '';
117
- }
118
- set selectedProjectId(value) {
119
- if (value)
120
- this.setAttribute('selected-project-id', value);
121
- else
122
- this.removeAttribute('selected-project-id');
123
- }
124
- get projectManageLabel() {
125
- return this.getAttribute('project-manage-label') || '프로젝트 관리';
126
- }
127
- set projectManageLabel(value) {
128
- this.setAttribute('project-manage-label', value);
129
- }
130
- get projectManageHref() {
131
- return this.getAttribute('project-manage-href') || '';
132
- }
133
- set projectManageHref(value) {
134
- if (value)
135
- this.setAttribute('project-manage-href', value);
136
- else
137
- this.removeAttribute('project-manage-href');
138
- }
139
- get projectSectionLabel() {
140
- return this.getAttribute('project-section-label') || '프로젝트';
141
- }
142
- set projectSectionLabel(value) {
143
- this.setAttribute('project-section-label', value);
144
- }
145
- get projectEmptyLabel() {
146
- return this.getAttribute('project-empty-label') || '프로젝트를 추가해 주세요';
147
- }
148
- set projectEmptyLabel(value) {
149
- this.setAttribute('project-empty-label', value);
150
- }
151
- get projectEmptyTriggerLabel() {
152
- return this.getAttribute('project-empty-trigger-label') || '프로젝트 추가';
153
- }
154
- set projectEmptyTriggerLabel(value) {
155
- this.setAttribute('project-empty-trigger-label', value);
156
- }
157
- get bottomItems() {
158
- return this.parseBottomItems();
159
- }
160
- set bottomItems(value) {
161
- this.setAttribute('bottom-items', typeof value === 'string' ? value : JSON.stringify(value));
162
- }
163
- get bottomSections() {
164
- return this.parseBottomSections();
165
- }
166
- set bottomSections(value) {
167
- this.setAttribute('bottom-sections', typeof value === 'string' ? value : JSON.stringify(value));
168
- }
169
- get promoBanner() {
170
- return this.parsePromoBanner();
171
- }
172
- set promoBanner(value) {
173
- if (value === null || value === undefined)
174
- this.removeAttribute('promo-banner');
175
- else
176
- this.setAttribute('promo-banner', typeof value === 'string' ? value : JSON.stringify(value));
177
- }
178
- parseSections() {
179
- const sectionsRaw = this.getAttribute('sections');
180
- if (sectionsRaw) {
181
- try {
182
- const parsed = JSON.parse(sectionsRaw);
183
- if (Array.isArray(parsed) && parsed.length)
184
- return parsed;
185
- }
186
- catch {
187
- /* fall through */
188
- }
189
- }
190
- try {
191
- const items = JSON.parse(this.getAttribute('items') || '[]');
192
- return [{ id: 'main', items: Array.isArray(items) ? items : [] }];
193
- }
194
- catch {
195
- return [{ id: 'main', items: [] }];
196
- }
197
- }
198
- parseUserMenuItems() {
199
- try {
200
- const parsed = JSON.parse(this.getAttribute('user-menu-items') || '[]');
201
- return Array.isArray(parsed) ? parsed : [];
202
- }
203
- catch {
204
- return [];
205
- }
206
- }
207
- parseUserProfile() {
208
- const raw = this.getAttribute('user-profile');
209
- if (!raw)
210
- return null;
211
- try {
212
- return JSON.parse(raw);
213
- }
214
- catch {
215
- return null;
216
- }
217
- }
218
- parseProjects() {
219
- try {
220
- const parsed = JSON.parse(this.getAttribute('projects') || '[]');
221
- return Array.isArray(parsed) ? parsed : [];
222
- }
223
- catch {
224
- return [];
225
- }
226
- }
227
- parseBottomItems() {
228
- try {
229
- const parsed = JSON.parse(this.getAttribute('bottom-items') || '[]');
230
- return Array.isArray(parsed) ? parsed : [];
231
- }
232
- catch {
233
- return [];
234
- }
235
- }
236
- parseBottomSections() {
237
- const sectionsRaw = this.getAttribute('bottom-sections');
238
- if (sectionsRaw) {
239
- try {
240
- const parsed = JSON.parse(sectionsRaw);
241
- if (Array.isArray(parsed) && parsed.length)
242
- return parsed;
243
- }
244
- catch {
245
- /* fall through */
246
- }
247
- }
248
- const items = this.parseBottomItems();
249
- return items.length ? [{ id: 'bottom', items }] : [];
250
- }
251
- parsePromoBanner() {
252
- const raw = this.getAttribute('promo-banner');
253
- if (!raw)
254
- return null;
255
- try {
256
- return JSON.parse(raw);
257
- }
258
- catch {
259
- return null;
260
- }
261
- }
262
- getSelectedProject() {
263
- const projects = this.parseProjects();
264
- if (!projects.length)
265
- return null;
266
- const selectedId = this.selectedProjectId;
267
- return projects.find((project) => project.id === selectedId) || projects[0];
268
- }
269
- bindOutsideClick() {
270
- if (this.outsideHandler)
271
- return;
272
- this.outsideHandler = (event) => {
273
- const target = event.target;
274
- // 사이드바 내부 클릭은 각 핸들러가 exclusive open을 처리 — mousedown에서 remount하면 클릭이 씹힘
275
- if (this.contains(target))
276
- return;
277
- let changed = false;
278
- if (this.userMenuOpen) {
279
- this.userMenuOpen = false;
280
- changed = true;
281
- }
282
- if (this.projectMenuOpen) {
283
- this.projectMenuOpen = false;
284
- changed = true;
285
- }
286
- if (changed)
287
- this.render();
288
- };
289
- document.addEventListener('mousedown', this.outsideHandler);
290
- }
291
- closeOverlayMenus() {
292
- const projectOpen = this.projectMenuOpen;
293
- const userOpen = this.userMenuOpen;
294
- if (!projectOpen && !userOpen)
295
- return false;
296
- this.projectMenuOpen = false;
297
- this.userMenuOpen = false;
298
- this.querySelector('.designbase-wc-sidebar__project-dropdown')?.remove();
299
- this.querySelector('.designbase-wc-sidebar__project-selector')?.classList.remove('designbase-wc-sidebar__project-selector--open');
300
- const projectTrigger = this.querySelector('.designbase-wc-sidebar__project-trigger');
301
- projectTrigger?.setAttribute('aria-expanded', 'false');
302
- const userDropdown = this.querySelector('.designbase-wc-sidebar__user-dropdown');
303
- if (userDropdown)
304
- userDropdown.hidden = true;
305
- this.querySelector('.designbase-wc-sidebar__user-info')?.setAttribute('aria-expanded', 'false');
306
- this.querySelector('.designbase-wc-sidebar__user-collapsed')?.setAttribute('aria-expanded', 'false');
307
- this.querySelector('.designbase-wc-sidebar__user-collapsed')?.classList.remove('designbase-wc-sidebar__user-collapsed--open');
308
- return true;
309
- }
310
- syncExclusiveAccordion(openId) {
311
- const roots = [
312
- ...Array.from(this.querySelectorAll('.designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item')),
313
- ...Array.from(this.querySelectorAll('.designbase-wc-sidebar__bottom-nav .designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item')),
314
- ];
315
- roots.forEach((el) => {
316
- const id = el.getAttribute('data-item-id');
317
- if (!id)
318
- return;
319
- if (openId && id === openId)
320
- el.setAttribute('expanded', '');
321
- else
322
- el.removeAttribute('expanded');
323
- });
324
- }
325
- unbindOutsideClick() {
326
- if (!this.outsideHandler)
327
- return;
328
- document.removeEventListener('mousedown', this.outsideHandler);
329
- this.outsideHandler = null;
330
- }
331
- cancelFlyoutClose() {
332
- if (this.flyoutCloseTimer) {
333
- clearTimeout(this.flyoutCloseTimer);
334
- this.flyoutCloseTimer = null;
335
- }
336
- }
337
- showFlyout(itemId) {
338
- this.cancelFlyoutClose();
339
- if (this.flyoutItemId === itemId)
340
- return;
341
- this.flyoutItemId = itemId;
342
- this.renderNav();
343
- this.renderBottomNav();
344
- }
345
- scheduleFlyoutClose() {
346
- this.cancelFlyoutClose();
347
- this.flyoutCloseTimer = setTimeout(() => {
348
- this.flyoutCloseTimer = null;
349
- this.flyoutItemId = null;
350
- this.renderNav();
351
- this.renderBottomNav();
352
- }, FLYOUT_CLOSE_DELAY_MS);
353
- }
354
- syncHostClasses() {
355
- const size = this.getAttribute('size') || 'm';
356
- const variant = this.getAttribute('variant') || 'default';
357
- const position = this.getAttribute('position') || 'left';
358
- this.className = [
359
- 'designbase-wc-sidebar',
360
- `designbase-wc-sidebar--${SIZES.includes(size) ? size : 'm'}`,
361
- `designbase-wc-sidebar--${VARIANTS.includes(variant) ? variant : 'default'}`,
362
- `designbase-wc-sidebar--${POSITIONS.includes(position) ? position : 'left'}`,
363
- this.hasAttribute('collapsed') && 'designbase-wc-sidebar--collapsed',
364
- this.hasAttribute('full-height') && 'designbase-wc-sidebar--full-height',
365
- this.hasAttribute('shadow') && 'designbase-wc-sidebar--shadow',
366
- ]
367
- .filter(Boolean)
368
- .join(' ');
369
- }
370
- dispatchItemClick(item) {
371
- this.dispatchEvent(new CustomEvent('db-item-click', {
372
- bubbles: true,
373
- composed: true,
374
- detail: { item },
375
- }));
376
- }
377
- dispatchUserMenuItemClick(item) {
378
- this.dispatchEvent(new CustomEvent('db-user-menu-item-click', {
379
- bubbles: true,
380
- composed: true,
381
- detail: { item },
382
- }));
383
- }
384
- dispatchProjectChange(project) {
385
- this.dispatchEvent(new CustomEvent('db-project-change', {
386
- bubbles: true,
387
- composed: true,
388
- detail: { project },
389
- }));
390
- }
391
- dispatchProjectManage() {
392
- this.dispatchEvent(new CustomEvent('db-project-manage', {
393
- bubbles: true,
394
- composed: true,
395
- detail: {},
396
- }));
397
- }
398
- dispatchPromoCtaClick(banner) {
399
- this.dispatchEvent(new CustomEvent('db-promo-cta-click', {
400
- bubbles: true,
401
- composed: true,
402
- detail: { banner },
403
- }));
404
- }
405
- createProjectAvatar(project, size = 's') {
406
- const avatar = document.createElement('db-avatar');
407
- avatar.className = 'designbase-wc-sidebar__project-avatar';
408
- avatar.setAttribute('size', size);
409
- avatar.setAttribute('initials', (project.label || '?').trim());
410
- avatar.setAttribute('alt', project.label);
411
- if (project.color) {
412
- const applyColor = () => {
413
- const initials = avatar.querySelector('.designbase-wc-avatar__initials');
414
- if (!initials)
415
- return false;
416
- initials.style.backgroundColor = project.color;
417
- initials.style.color = '#fff';
418
- return true;
419
- };
420
- const observer = new MutationObserver(() => {
421
- if (applyColor())
422
- observer.disconnect();
423
- });
424
- observer.observe(avatar, { childList: true, subtree: true });
425
- queueMicrotask(() => {
426
- if (applyColor())
427
- observer.disconnect();
428
- });
429
- }
430
- return avatar;
431
- }
432
- createProjectEmptyMark(size = 's') {
433
- const mark = document.createElement('span');
434
- mark.className = [
435
- 'designbase-wc-sidebar__project-mark',
436
- `designbase-wc-sidebar__project-mark--${size}`,
437
- 'designbase-wc-sidebar__project-mark--empty',
438
- ].join(' ');
439
- mark.setAttribute('aria-hidden', 'true');
440
- mark.append(createDbIcon('plus', size === 'm' ? 16 : 14));
441
- return mark;
442
- }
443
- createProjectBadge(project) {
444
- if (!project.badge)
445
- return null;
446
- const badge = document.createElement('db-badge');
447
- badge.className = 'designbase-wc-sidebar__project-badge';
448
- badge.setAttribute('size', 's');
449
- badge.setAttribute('variant', project.badgeColor || 'warning');
450
- badge.setAttribute('badge-style', 'text');
451
- badge.textContent = project.badge;
452
- return badge;
453
- }
454
- createProjectSelector(collapsed) {
455
- if (!this.hasAttribute('projects'))
456
- return null;
457
- const projects = this.parseProjects();
458
- const isEmpty = projects.length === 0;
459
- const selected = this.getSelectedProject();
460
- const wrap = document.createElement('div');
461
- wrap.className = [
462
- 'designbase-wc-sidebar__project-selector',
463
- collapsed && 'designbase-wc-sidebar__project-selector--collapsed',
464
- this.projectMenuOpen && 'designbase-wc-sidebar__project-selector--open',
465
- isEmpty && 'designbase-wc-sidebar__project-selector--empty',
466
- ]
467
- .filter(Boolean)
468
- .join(' ');
469
- const sectionLabelAttr = this.getAttribute('project-section-label');
470
- if (!collapsed && sectionLabelAttr && sectionLabelAttr.trim()) {
471
- const sectionLabel = document.createElement('div');
472
- sectionLabel.className = 'designbase-wc-sidebar__project-section-label';
473
- sectionLabel.textContent = sectionLabelAttr.trim();
474
- wrap.append(sectionLabel);
475
- }
476
- const trigger = document.createElement('button');
477
- trigger.type = 'button';
478
- trigger.className = 'designbase-wc-sidebar__project-trigger';
479
- trigger.setAttribute('aria-haspopup', 'menu');
480
- trigger.setAttribute('aria-expanded', String(this.projectMenuOpen));
481
- if (isEmpty || !selected) {
482
- trigger.setAttribute('aria-label', this.projectEmptyTriggerLabel);
483
- trigger.append(this.createProjectEmptyMark(collapsed ? 'm' : 's'));
484
- if (!collapsed) {
485
- const label = document.createElement('span');
486
- label.className = 'designbase-wc-sidebar__project-label';
487
- label.textContent = this.projectEmptyTriggerLabel;
488
- trigger.append(label);
489
- }
490
- }
491
- else {
492
- trigger.setAttribute('aria-label', selected.label);
493
- trigger.append(this.createProjectAvatar(selected, collapsed ? 'm' : 's'));
494
- if (!collapsed) {
495
- const label = document.createElement('span');
496
- label.className = 'designbase-wc-sidebar__project-label';
497
- label.textContent = selected.label;
498
- trigger.append(label);
499
- }
500
- }
501
- const chevron = document.createElement('span');
502
- chevron.className = 'designbase-wc-sidebar__project-chevron';
503
- chevron.setAttribute('aria-hidden', 'true');
504
- chevron.append(createDbIcon('chevron-down', 14));
505
- trigger.append(chevron);
506
- trigger.addEventListener('click', () => {
507
- this.projectMenuOpen = !this.projectMenuOpen;
508
- this.userMenuOpen = false;
509
- this.render();
510
- });
511
- wrap.append(trigger);
512
- if (this.projectMenuOpen) {
513
- const dropdown = document.createElement('div');
514
- dropdown.className = 'designbase-wc-sidebar__project-dropdown';
515
- dropdown.setAttribute('role', 'menu');
516
- dropdown.setAttribute('aria-label', this.projectSectionLabel);
517
- if (isEmpty) {
518
- const empty = document.createElement('div');
519
- empty.className = 'designbase-wc-sidebar__project-empty';
520
- empty.setAttribute('role', 'presentation');
521
- const emptyText = document.createElement('p');
522
- emptyText.className = 'designbase-wc-sidebar__project-empty-text';
523
- emptyText.textContent = this.projectEmptyLabel;
524
- empty.append(emptyText);
525
- dropdown.append(empty);
526
- }
527
- else {
528
- const list = document.createElement('ul');
529
- list.className = 'designbase-wc-sidebar__project-list';
530
- projects.forEach((project) => {
531
- const li = document.createElement('li');
532
- li.className = 'designbase-wc-sidebar__project-option';
533
- const button = document.createElement('button');
534
- button.type = 'button';
535
- button.className = [
536
- 'designbase-wc-sidebar__project-option-btn',
537
- selected && project.id === selected.id && 'designbase-wc-sidebar__project-option-btn--active',
538
- ]
539
- .filter(Boolean)
540
- .join(' ');
541
- button.setAttribute('role', 'menuitem');
542
- button.append(this.createProjectAvatar(project, 's'));
543
- const optionLabel = document.createElement('span');
544
- optionLabel.className = 'designbase-wc-sidebar__project-option-label';
545
- optionLabel.textContent = project.label;
546
- button.append(optionLabel);
547
- const badge = this.createProjectBadge(project);
548
- if (badge)
549
- button.append(badge);
550
- button.addEventListener('click', () => {
551
- this.projectMenuOpen = false;
552
- this.setAttribute('selected-project-id', project.id);
553
- this.dispatchProjectChange(project);
554
- this.render();
555
- });
556
- li.append(button);
557
- list.append(li);
558
- });
559
- dropdown.append(list);
560
- }
561
- const manage = document.createElement('button');
562
- manage.type = 'button';
563
- manage.className = 'designbase-wc-sidebar__project-manage';
564
- manage.setAttribute('role', 'menuitem');
565
- manage.append(createDbIcon('plus', 14));
566
- const manageLabel = document.createElement('span');
567
- manageLabel.textContent = this.projectManageLabel;
568
- manage.append(manageLabel);
569
- manage.addEventListener('click', () => {
570
- this.projectMenuOpen = false;
571
- const href = this.projectManageHref;
572
- if (href) {
573
- window.location.assign(href);
574
- }
575
- this.dispatchProjectManage();
576
- this.render();
577
- });
578
- dropdown.append(manage);
579
- wrap.append(dropdown);
580
- }
581
- return wrap;
582
- }
583
- createFlyout(item, size) {
584
- const position = this.getAttribute('position') || 'left';
585
- const flyout = document.createElement('div');
586
- flyout.className = [
587
- 'designbase-wc-sidebar__flyout',
588
- position === 'right' && 'designbase-wc-sidebar__flyout--align-left',
589
- ]
590
- .filter(Boolean)
591
- .join(' ');
592
- flyout.setAttribute('role', 'menu');
593
- flyout.setAttribute('aria-label', `${item.label} 하위 메뉴`);
594
- flyout.addEventListener('mouseenter', () => this.cancelFlyoutClose());
595
- flyout.addEventListener('mouseleave', () => this.scheduleFlyoutClose());
596
- const title = document.createElement('div');
597
- title.className = 'designbase-wc-sidebar__flyout-title';
598
- title.textContent = item.label;
599
- flyout.append(title);
600
- const list = document.createElement('ul');
601
- list.className = 'designbase-wc-sidebar__flyout-list';
602
- (item.children || []).forEach((child) => {
603
- const li = document.createElement('li');
604
- li.className = 'designbase-wc-sidebar__flyout-item';
605
- const menuItem = document.createElement('db-menu-item');
606
- menuItem.setAttribute('label', child.label);
607
- menuItem.setAttribute('type', 'block');
608
- menuItem.setAttribute('menu-style', 'dropdown');
609
- menuItem.setAttribute('size', size);
610
- if (child.href)
611
- menuItem.setAttribute('href', child.href);
612
- if (child.active)
613
- menuItem.setAttribute('active', '');
614
- if (child.disabled)
615
- menuItem.setAttribute('disabled', '');
616
- if (child.badge !== undefined)
617
- menuItem.setAttribute('badge', String(child.badge));
618
- if (child.badgeColor)
619
- menuItem.setAttribute('badge-color', child.badgeColor);
620
- menuItem.addEventListener('db-click', () => {
621
- if (child.disabled)
622
- return;
623
- this.flyoutItemId = null;
624
- this.dispatchItemClick(child);
625
- this.renderNav();
626
- this.renderBottomNav();
627
- });
628
- li.append(menuItem);
629
- list.append(li);
630
- });
631
- flyout.append(list);
632
- return flyout;
633
- }
634
- createSidebarMenuItem(item, size, depth = 0) {
635
- const hasChildren = Boolean(item.children?.length);
636
- const expanded = this.expandedItems.has(item.id);
637
- const collapsed = this.hasAttribute('collapsed');
638
- const useFlyout = collapsed && hasChildren;
639
- const li = document.createElement('li');
640
- li.className = [
641
- 'designbase-wc-sidebar__item',
642
- useFlyout && this.flyoutItemId === item.id && 'designbase-wc-sidebar__item--flyout-active',
643
- ]
644
- .filter(Boolean)
645
- .join(' ');
646
- if (useFlyout) {
647
- li.addEventListener('mouseenter', () => this.showFlyout(item.id));
648
- li.addEventListener('mouseleave', () => this.scheduleFlyoutClose());
649
- }
650
- const menuItem = document.createElement('db-menu-item');
651
- menuItem.setAttribute('data-item-id', item.id);
652
- menuItem.setAttribute('label', item.label);
653
- menuItem.setAttribute('type', 'block');
654
- menuItem.setAttribute('menu-style', 'accordion');
655
- menuItem.setAttribute('size', size);
656
- menuItem.setAttribute('depth', String(depth));
657
- if (item.href)
658
- menuItem.setAttribute('href', item.href);
659
- if (item.icon)
660
- menuItem.setAttribute('icon', item.icon);
661
- if (item.active)
662
- menuItem.setAttribute('active', '');
663
- if (item.disabled)
664
- menuItem.setAttribute('disabled', '');
665
- if (item.badge !== undefined)
666
- menuItem.setAttribute('badge', String(item.badge));
667
- if (item.badgeColor)
668
- menuItem.setAttribute('badge-color', item.badgeColor);
669
- if (hasChildren && !useFlyout) {
670
- menuItem.setAttribute('expandable', '');
671
- menuItem.subItems = (item.children || []).map((child) => ({
672
- id: child.id,
673
- label: child.label,
674
- href: child.href,
675
- active: child.active,
676
- disabled: child.disabled,
677
- badge: child.badge,
678
- badgeColor: child.badgeColor,
679
- }));
680
- if (expanded && !collapsed)
681
- menuItem.setAttribute('expanded', '');
682
- }
683
- menuItem.addEventListener('db-click', (event) => {
684
- if (item.disabled)
685
- return;
686
- if (hasChildren && !collapsed) {
687
- const willOpen = event.detail?.expanded
688
- ?? !this.expandedItems.has(item.id);
689
- this.closeOverlayMenus();
690
- if (willOpen) {
691
- this.expandedItems.clear();
692
- this.expandedItems.add(item.id);
693
- this.syncExclusiveAccordion(item.id);
694
- }
695
- else {
696
- this.expandedItems.delete(item.id);
697
- this.syncExclusiveAccordion(null);
698
- }
699
- return;
700
- }
701
- if (useFlyout) {
702
- this.closeOverlayMenus();
703
- this.showFlyout(item.id);
704
- return;
705
- }
706
- this.closeOverlayMenus();
707
- this.dispatchItemClick(item);
708
- });
709
- menuItem.addEventListener('db-child-click', (event) => {
710
- const detail = event.detail;
711
- this.dispatchItemClick(detail.child);
712
- });
713
- li.append(menuItem);
714
- if (collapsed && item.badge !== undefined && item.badge !== null && item.badge !== '') {
715
- const badgeColor = item.badgeColor || 'primary';
716
- const dot = document.createElement('span');
717
- dot.className = [
718
- 'designbase-wc-sidebar__collapsed-badge-dot',
719
- `designbase-wc-sidebar__collapsed-badge-dot--${badgeColor}`,
720
- ].join(' ');
721
- dot.setAttribute('aria-hidden', 'true');
722
- li.append(dot);
723
- }
724
- if (collapsed && !hasChildren) {
725
- const tooltip = document.createElement('span');
726
- tooltip.className = 'designbase-wc-sidebar__item-tooltip';
727
- tooltip.textContent = item.label;
728
- tooltip.setAttribute('role', 'tooltip');
729
- li.append(tooltip);
730
- }
731
- if (useFlyout && this.flyoutItemId === item.id) {
732
- li.append(this.createFlyout(item, size));
733
- }
734
- return li;
735
- }
736
- renderSectionList(sections, size, collapsed) {
737
- const fragment = document.createDocumentFragment();
738
- sections.forEach((section) => {
739
- const sectionEl = document.createElement('div');
740
- sectionEl.className = 'designbase-wc-sidebar__section';
741
- if (!collapsed && section.title) {
742
- const title = document.createElement('div');
743
- title.className = 'designbase-wc-sidebar__section-title';
744
- title.textContent = section.title;
745
- sectionEl.append(title);
746
- }
747
- const list = document.createElement('ul');
748
- list.className = 'designbase-wc-sidebar__nav-list';
749
- section.items.forEach((item) => list.append(this.createSidebarMenuItem(item, size)));
750
- sectionEl.append(list);
751
- fragment.append(sectionEl);
752
- });
753
- return fragment;
754
- }
755
- renderNav() {
756
- const nav = this.querySelector('.designbase-wc-sidebar__nav');
757
- if (!nav)
758
- return;
759
- const size = this.getAttribute('size') || 'm';
760
- const collapsed = this.hasAttribute('collapsed');
761
- nav.replaceChildren(this.renderSectionList(this.parseSections(), size, collapsed));
762
- }
763
- renderBottomNav() {
764
- const bottomNav = this.querySelector('.designbase-wc-sidebar__bottom-nav');
765
- if (!bottomNav)
766
- return;
767
- const size = this.getAttribute('size') || 'm';
768
- const collapsed = this.hasAttribute('collapsed');
769
- bottomNav.replaceChildren(this.renderSectionList(this.parseBottomSections(), size, collapsed));
770
- }
771
- createUserDropdown(userMenuItems, collapsed = false) {
772
- if (!userMenuItems.length)
773
- return null;
774
- const size = this.getAttribute('size') || 'm';
775
- const dropdown = document.createElement('div');
776
- dropdown.className = [
777
- 'designbase-wc-sidebar__user-dropdown',
778
- collapsed && 'designbase-wc-sidebar__user-dropdown--collapsed',
779
- ]
780
- .filter(Boolean)
781
- .join(' ');
782
- dropdown.setAttribute('role', 'menu');
783
- dropdown.setAttribute('aria-label', '사용자 메뉴');
784
- dropdown.hidden = !this.userMenuOpen;
785
- const menu = document.createElement('ul');
786
- menu.className = 'designbase-wc-sidebar__user-menu';
787
- userMenuItems.forEach((item) => {
788
- const li = document.createElement('li');
789
- li.className = 'designbase-wc-sidebar__user-menu-item';
790
- const menuItem = document.createElement('db-menu-item');
791
- menuItem.setAttribute('label', item.label);
792
- menuItem.setAttribute('type', 'block');
793
- menuItem.setAttribute('menu-style', 'accordion');
794
- menuItem.setAttribute('size', size);
795
- if (item.icon)
796
- menuItem.setAttribute('icon', item.icon);
797
- if (item.href)
798
- menuItem.setAttribute('href', item.href);
799
- menuItem.addEventListener('db-click', () => {
800
- this.userMenuOpen = false;
801
- this.dispatchUserMenuItemClick(item);
802
- this.render();
803
- });
804
- li.append(menuItem);
805
- menu.append(li);
806
- });
807
- dropdown.append(menu);
808
- return dropdown;
809
- }
810
- createPromoBanner(collapsed) {
811
- const banner = this.parsePromoBanner();
812
- if (!banner)
813
- return null;
814
- if (collapsed) {
815
- const collapsedPromo = document.createElement('button');
816
- collapsedPromo.type = 'button';
817
- collapsedPromo.className = 'designbase-wc-sidebar__promo-collapsed';
818
- collapsedPromo.setAttribute('aria-label', banner.ctaLabel || banner.title);
819
- const animBg = document.createElement('db-animation-background');
820
- animBg.className = 'designbase-wc-sidebar__promo-bg';
821
- animBg.setAttribute('type', 'aurora');
822
- animBg.setAttribute('theme', 'light');
823
- animBg.setAttribute('intensity', 'subtle');
824
- animBg.setAttribute('blur', '40');
825
- animBg.setAttribute('speed', '4000');
826
- animBg.setAttribute('colors', JSON.stringify(['#c7d2fe', '#ddd6fe', '#fbcfe8']));
827
- collapsedPromo.append(animBg);
828
- collapsedPromo.append(createDbIcon(banner.icon && isDbIconName(banner.icon) ? banner.icon : 'sparkle', 18));
829
- collapsedPromo.addEventListener('click', () => this.dispatchPromoCtaClick(banner));
830
- const tooltip = document.createElement('span');
831
- tooltip.className = 'designbase-wc-sidebar__item-tooltip';
832
- tooltip.textContent = banner.title;
833
- tooltip.setAttribute('role', 'tooltip');
834
- const wrap = document.createElement('div');
835
- wrap.className = 'designbase-wc-sidebar__promo-collapsed-wrap';
836
- wrap.append(collapsedPromo, tooltip);
837
- return wrap;
838
- }
839
- const promo = document.createElement('div');
840
- promo.className = 'designbase-wc-sidebar__promo';
841
- const animBg = document.createElement('db-animation-background');
842
- animBg.className = 'designbase-wc-sidebar__promo-bg';
843
- animBg.setAttribute('type', 'aurora');
844
- animBg.setAttribute('theme', 'light');
845
- animBg.setAttribute('intensity', 'subtle');
846
- animBg.setAttribute('blur', '60');
847
- animBg.setAttribute('speed', '5000');
848
- animBg.setAttribute('colors', JSON.stringify(['#c7d2fe', '#ddd6fe', '#fbcfe8', '#bfdbfe']));
849
- promo.append(animBg);
850
- const content = document.createElement('div');
851
- content.className = 'designbase-wc-sidebar__promo-content';
852
- const titleRow = document.createElement('div');
853
- titleRow.className = 'designbase-wc-sidebar__promo-title-row';
854
- const iconWrap = document.createElement('span');
855
- iconWrap.className = 'designbase-wc-sidebar__promo-icon';
856
- iconWrap.setAttribute('aria-hidden', 'true');
857
- iconWrap.append(createDbIcon(banner.icon && isDbIconName(banner.icon) ? banner.icon : 'sparkle', 16));
858
- const title = document.createElement('div');
859
- title.className = 'designbase-wc-sidebar__promo-title';
860
- title.textContent = banner.title;
861
- titleRow.append(iconWrap, title);
862
- content.append(titleRow);
863
- if (banner.description) {
864
- const desc = document.createElement('div');
865
- desc.className = 'designbase-wc-sidebar__promo-desc';
866
- desc.textContent = banner.description;
867
- content.append(desc);
868
- }
869
- if (banner.ctaLabel) {
870
- const cta = document.createElement('db-button');
871
- cta.className = 'designbase-wc-sidebar__promo-action';
872
- cta.setAttribute('variant', 'secondary');
873
- cta.setAttribute('size', 's');
874
- cta.setAttribute('full-width', '');
875
- cta.textContent = banner.ctaLabel;
876
- cta.addEventListener('db-click', () => {
877
- if (banner.ctaHref)
878
- window.location.assign(banner.ctaHref);
879
- this.dispatchPromoCtaClick(banner);
880
- });
881
- content.append(cta);
882
- }
883
- promo.append(content);
884
- return promo;
885
- }
886
- render() {
887
- this.syncHostClasses();
888
- this.setAttribute('role', 'complementary');
889
- this.setAttribute('aria-label', '사이드바 네비게이션');
890
- const size = this.getAttribute('size') || 'm';
891
- const collapsible = this.getAttribute('collapsible') !== 'false';
892
- const showLogo = this.getAttribute('show-logo') !== 'false';
893
- const collapsed = this.hasAttribute('collapsed');
894
- const userProfile = this.parseUserProfile();
895
- const userMenuItems = this.parseUserMenuItems();
896
- const bottomSections = this.parseBottomSections();
897
- const logoSize = size === 'l' ? 'm' : size === 's' ? 'xs' : 's';
898
- this.replaceChildren();
899
- const container = document.createElement('div');
900
- container.className = 'designbase-wc-sidebar__container';
901
- if (collapsible || (showLogo && !collapsed)) {
902
- const header = document.createElement('div');
903
- header.className = [
904
- 'designbase-wc-sidebar__header',
905
- (collapsed || !showLogo) && 'designbase-wc-sidebar__header--collapsed-only',
906
- ]
907
- .filter(Boolean)
908
- .join(' ');
909
- if (!collapsed && showLogo) {
910
- const logoWrap = document.createElement('div');
911
- logoWrap.className = 'designbase-wc-sidebar__logo';
912
- const logo = document.createElement('db-logo');
913
- logo.setAttribute('type', 'designbase');
914
- logo.setAttribute('size', logoSize);
915
- logoWrap.append(logo);
916
- logoWrap.addEventListener('click', () => {
917
- this.dispatchEvent(new CustomEvent('db-logo-click', { bubbles: true, composed: true }));
918
- });
919
- header.append(logoWrap);
920
- }
921
- if (collapsible) {
922
- const toggle = document.createElement('db-button');
923
- toggle.className = 'designbase-wc-sidebar__toggle';
924
- toggle.setAttribute('variant', 'tertiary');
925
- toggle.setAttribute('size', 's');
926
- toggle.setAttribute('icon-only', '');
927
- toggle.setAttribute('start-icon', collapsed ? 'arrow-bar-right' : 'arrow-bar-left');
928
- toggle.setAttribute('aria-label', collapsed ? '사이드바 펼치기' : '사이드바 접기');
929
- toggle.addEventListener('db-click', () => {
930
- const next = !this.hasAttribute('collapsed');
931
- if (next)
932
- this.setAttribute('collapsed', '');
933
- else
934
- this.removeAttribute('collapsed');
935
- this.dispatchEvent(new CustomEvent('db-toggle', {
936
- bubbles: true,
937
- composed: true,
938
- detail: { collapsed: next },
939
- }));
940
- });
941
- header.append(toggle);
942
- }
943
- container.append(header);
944
- }
945
- const navWrapper = document.createElement('div');
946
- navWrapper.className = 'designbase-wc-sidebar__nav-wrapper';
947
- const projectSelector = this.createProjectSelector(collapsed);
948
- if (projectSelector)
949
- navWrapper.append(projectSelector);
950
- const nav = document.createElement('nav');
951
- nav.className = 'designbase-wc-sidebar__nav';
952
- nav.setAttribute('aria-label', '주 메뉴');
953
- navWrapper.append(nav);
954
- if (bottomSections.length > 0) {
955
- const bottomNav = document.createElement('nav');
956
- bottomNav.className = 'designbase-wc-sidebar__bottom-nav';
957
- bottomNav.setAttribute('aria-label', '하단 메뉴');
958
- navWrapper.append(bottomNav);
959
- }
960
- container.append(navWrapper);
961
- const footer = document.createElement('div');
962
- footer.className = 'designbase-wc-sidebar__footer';
963
- const promo = this.createPromoBanner(collapsed);
964
- if (promo)
965
- footer.append(promo);
966
- if (userProfile && !collapsed) {
967
- const user = document.createElement('div');
968
- user.className = 'designbase-wc-sidebar__user';
969
- const dropdown = this.createUserDropdown(userMenuItems);
970
- if (dropdown)
971
- user.append(dropdown);
972
- const info = document.createElement('div');
973
- info.className = 'designbase-wc-sidebar__user-info';
974
- info.setAttribute('role', 'button');
975
- info.setAttribute('tabindex', '0');
976
- info.setAttribute('aria-expanded', String(this.userMenuOpen));
977
- const avatar = document.createElement('db-avatar');
978
- avatar.className = 'designbase-wc-sidebar__user-avatar';
979
- avatar.setAttribute('size', 's');
980
- avatar.setAttribute('initials', userProfile.name);
981
- avatar.setAttribute('alt', userProfile.name);
982
- if (userProfile.avatar)
983
- avatar.setAttribute('src', userProfile.avatar);
984
- const details = document.createElement('div');
985
- details.className = 'designbase-wc-sidebar__user-details';
986
- const name = document.createElement('div');
987
- name.className = 'designbase-wc-sidebar__user-name';
988
- name.textContent = userProfile.name;
989
- details.append(name);
990
- if (userProfile.email) {
991
- const email = document.createElement('div');
992
- email.className = 'designbase-wc-sidebar__user-email';
993
- email.textContent = userProfile.email;
994
- details.append(email);
995
- }
996
- info.append(avatar, details);
997
- if (userMenuItems.length) {
998
- const moreIcon = document.createElement('span');
999
- moreIcon.className = 'designbase-wc-sidebar__user-more';
1000
- moreIcon.setAttribute('aria-hidden', 'true');
1001
- moreIcon.append(createDbIcon('more-vertical', 16));
1002
- info.append(moreIcon);
1003
- info.setAttribute('aria-haspopup', 'menu');
1004
- }
1005
- info.addEventListener('click', () => {
1006
- if (!userMenuItems.length)
1007
- return;
1008
- this.userMenuOpen = !this.userMenuOpen;
1009
- this.projectMenuOpen = false;
1010
- this.render();
1011
- });
1012
- user.append(info);
1013
- footer.append(user);
1014
- }
1015
- else if (userProfile && collapsed) {
1016
- const collapsedUser = document.createElement('div');
1017
- collapsedUser.className = [
1018
- 'designbase-wc-sidebar__user-collapsed',
1019
- this.userMenuOpen && 'designbase-wc-sidebar__user-collapsed--open',
1020
- ]
1021
- .filter(Boolean)
1022
- .join(' ');
1023
- collapsedUser.setAttribute('role', 'button');
1024
- collapsedUser.setAttribute('tabindex', '0');
1025
- collapsedUser.setAttribute('aria-label', userProfile.name);
1026
- collapsedUser.setAttribute('aria-expanded', String(this.userMenuOpen));
1027
- if (userMenuItems.length)
1028
- collapsedUser.setAttribute('aria-haspopup', 'menu');
1029
- const avatar = document.createElement('db-avatar');
1030
- avatar.className = 'designbase-wc-sidebar__user-avatar-collapsed';
1031
- avatar.setAttribute('size', 's');
1032
- avatar.setAttribute('initials', userProfile.name);
1033
- avatar.setAttribute('alt', userProfile.name);
1034
- if (userProfile.avatar)
1035
- avatar.setAttribute('src', userProfile.avatar);
1036
- collapsedUser.append(avatar);
1037
- if (!this.userMenuOpen) {
1038
- const tooltip = document.createElement('span');
1039
- tooltip.className = 'designbase-wc-sidebar__item-tooltip';
1040
- tooltip.textContent = userProfile.name;
1041
- tooltip.setAttribute('role', 'tooltip');
1042
- collapsedUser.append(tooltip);
1043
- }
1044
- const dropdown = this.createUserDropdown(userMenuItems, true);
1045
- if (dropdown)
1046
- collapsedUser.append(dropdown);
1047
- collapsedUser.addEventListener('click', (event) => {
1048
- if (!userMenuItems.length)
1049
- return;
1050
- if (event.target.closest('.designbase-wc-sidebar__user-dropdown'))
1051
- return;
1052
- this.userMenuOpen = !this.userMenuOpen;
1053
- this.projectMenuOpen = false;
1054
- this.render();
1055
- });
1056
- footer.append(collapsedUser);
1057
- }
1058
- container.append(footer);
1059
- this.append(container);
1060
- this.renderNav();
1061
- this.renderBottomNav();
1062
- }
1063
- }
1064
- if (!customElements.get('db-sidebar')) {
1065
- customElements.define('db-sidebar', DbSidebar);
1066
- }
1067
-
1068
- export { DbSidebar };
1
+ import{createDbIcon as e,isDbIconName as t}from"./db-icons.js";const s=["s","m","l"],i=["default","dark","light"],r=["left","right"];class DbSidebar extends HTMLElement{constructor(){super(...arguments),this.expandedItems=new Set,this.userMenuOpen=!1,this.projectMenuOpen=!1,this.flyoutItemId=null,this.userFlyoutItemId=null,this.flyoutCloseTimer=null,this.userFlyoutCloseTimer=null,this.outsideHandler=null}static get observedAttributes(){return["items","sections","user-menu-items","user-profile","default-expanded-ids","projects","selected-project-id","project-manage-label","project-manage-href","project-section-label","project-empty-label","project-empty-trigger-label","bottom-items","bottom-sections","promo-banner","header-type","back-label","back-href","size","variant","position","collapsed","collapsible","show-logo","full-height","shadow"]}connectedCallback(){this.seedExpanded(),this.render(),this.bindOutsideClick()}disconnectedCallback(){this.unbindOutsideClick(),this.cancelFlyoutClose(),this.cancelUserFlyoutClose()}attributeChangedCallback(e){this.isConnected&&("default-expanded-ids"===e&&this.seedExpanded(),"collapsed"===e&&this.hasAttribute("collapsed")&&(this.userMenuOpen=!1,this.projectMenuOpen=!1,this.flyoutItemId=null,this.userFlyoutItemId=null,this.cancelFlyoutClose(),this.cancelUserFlyoutClose()),this.render())}seedExpanded(){try{const e=JSON.parse(this.getAttribute("default-expanded-ids")||"[]");Array.isArray(e)&&(this.expandedItems=new Set(e))}catch{this.expandedItems=new Set}}get items(){try{const e=JSON.parse(this.getAttribute("items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}set items(e){this.setAttribute("items","string"==typeof e?e:JSON.stringify(e))}get sections(){return this.parseSections()}set sections(e){this.setAttribute("sections","string"==typeof e?e:JSON.stringify(e))}get userMenuItems(){return this.parseUserMenuItems()}set userMenuItems(e){this.setAttribute("user-menu-items","string"==typeof e?e:JSON.stringify(e))}get userProfile(){return this.parseUserProfile()}set userProfile(e){null==e?this.removeAttribute("user-profile"):this.setAttribute("user-profile","string"==typeof e?e:JSON.stringify(e))}get projects(){return this.parseProjects()}set projects(e){this.setAttribute("projects","string"==typeof e?e:JSON.stringify(e))}get selectedProjectId(){return this.getAttribute("selected-project-id")||""}set selectedProjectId(e){e?this.setAttribute("selected-project-id",e):this.removeAttribute("selected-project-id")}get projectManageLabel(){return this.getAttribute("project-manage-label")||"프로젝트 관리"}set projectManageLabel(e){this.setAttribute("project-manage-label",e)}get projectManageHref(){return this.getAttribute("project-manage-href")||""}set projectManageHref(e){e?this.setAttribute("project-manage-href",e):this.removeAttribute("project-manage-href")}get projectSectionLabel(){return this.getAttribute("project-section-label")||"프로젝트"}set projectSectionLabel(e){this.setAttribute("project-section-label",e)}get projectEmptyLabel(){return this.getAttribute("project-empty-label")||"프로젝트를 추가해 주세요"}set projectEmptyLabel(e){this.setAttribute("project-empty-label",e)}get projectEmptyTriggerLabel(){return this.getAttribute("project-empty-trigger-label")||"프로젝트 추가"}set projectEmptyTriggerLabel(e){this.setAttribute("project-empty-trigger-label",e)}get bottomItems(){return this.parseBottomItems()}set bottomItems(e){this.setAttribute("bottom-items","string"==typeof e?e:JSON.stringify(e))}get bottomSections(){return this.parseBottomSections()}set bottomSections(e){this.setAttribute("bottom-sections","string"==typeof e?e:JSON.stringify(e))}get promoBanner(){return this.parsePromoBanner()}set promoBanner(e){null==e?this.removeAttribute("promo-banner"):this.setAttribute("promo-banner","string"==typeof e?e:JSON.stringify(e))}get headerType(){return"back"===this.getAttribute("header-type")?"back":"default"}set headerType(e){this.setAttribute("header-type",e)}get backLabel(){return this.getAttribute("back-label")||"뒤로가기"}set backLabel(e){this.setAttribute("back-label",e)}get backHref(){return this.getAttribute("back-href")||""}set backHref(e){e?this.setAttribute("back-href",e):this.removeAttribute("back-href")}parseSections(){const e=this.getAttribute("sections");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length)return t}catch{}try{const e=JSON.parse(this.getAttribute("items")||"[]");return[{id:"main",items:Array.isArray(e)?e:[]}]}catch{return[{id:"main",items:[]}]}}parseUserMenuItems(){try{const e=JSON.parse(this.getAttribute("user-menu-items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseUserProfile(){const e=this.getAttribute("user-profile");if(!e)return null;try{return JSON.parse(e)}catch{return null}}parseProjects(){try{const e=JSON.parse(this.getAttribute("projects")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseBottomItems(){try{const e=JSON.parse(this.getAttribute("bottom-items")||"[]");return Array.isArray(e)?e:[]}catch{return[]}}parseBottomSections(){const e=this.getAttribute("bottom-sections");if(e)try{const t=JSON.parse(e);if(Array.isArray(t)&&t.length)return t}catch{}const t=this.parseBottomItems();return t.length?[{id:"bottom",items:t}]:[]}parsePromoBanner(){const e=this.getAttribute("promo-banner");if(!e)return null;try{return JSON.parse(e)}catch{return null}}getSelectedProject(){const e=this.parseProjects();if(!e.length)return null;const t=this.selectedProjectId;return e.find(e=>e.id===t)||e[0]}bindOutsideClick(){this.outsideHandler||(this.outsideHandler=e=>{const t=e.target;if(this.contains(t))return;let s=!1;this.userMenuOpen&&(this.userMenuOpen=!1,this.userFlyoutItemId=null,s=!0),this.projectMenuOpen&&(this.projectMenuOpen=!1,s=!0),s&&this.render()},document.addEventListener("mousedown",this.outsideHandler))}closeOverlayMenus(){const e=this.projectMenuOpen,t=this.userMenuOpen;if(!e&&!t)return!1;this.projectMenuOpen=!1,this.userMenuOpen=!1,this.userFlyoutItemId=null,this.cancelUserFlyoutClose(),this.classList.remove("designbase-wc-sidebar--user-menu-open"),this.querySelector(".designbase-wc-sidebar__project-dropdown")?.remove(),this.querySelector(".designbase-wc-sidebar__project-selector")?.classList.remove("designbase-wc-sidebar__project-selector--open");const s=this.querySelector(".designbase-wc-sidebar__project-trigger");s?.setAttribute("aria-expanded","false");const i=this.querySelector(".designbase-wc-sidebar__user-dropdown");return i&&(i.hidden=!0),this.querySelector(".designbase-wc-sidebar__user-info")?.setAttribute("aria-expanded","false"),this.querySelector(".designbase-wc-sidebar__user-collapsed")?.setAttribute("aria-expanded","false"),this.querySelector(".designbase-wc-sidebar__user-collapsed")?.classList.remove("designbase-wc-sidebar__user-collapsed--open"),!0}syncExclusiveAccordion(e){[...Array.from(this.querySelectorAll(".designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item")),...Array.from(this.querySelectorAll(".designbase-wc-sidebar__bottom-nav .designbase-wc-sidebar__nav-list > .designbase-wc-sidebar__item > db-menu-item"))].forEach(t=>{const s=t.getAttribute("data-item-id");s&&(e&&s===e?t.setAttribute("expanded",""):t.removeAttribute("expanded"))})}unbindOutsideClick(){this.outsideHandler&&(document.removeEventListener("mousedown",this.outsideHandler),this.outsideHandler=null)}cancelFlyoutClose(){this.flyoutCloseTimer&&(clearTimeout(this.flyoutCloseTimer),this.flyoutCloseTimer=null)}showFlyout(e){this.cancelFlyoutClose(),this.flyoutItemId!==e&&(this.flyoutItemId=e,this.renderNav(),this.renderBottomNav())}scheduleFlyoutClose(){this.cancelFlyoutClose(),this.flyoutCloseTimer=setTimeout(()=>{this.flyoutCloseTimer=null,this.flyoutItemId=null,this.renderNav(),this.renderBottomNav()},120)}cancelUserFlyoutClose(){this.userFlyoutCloseTimer&&(clearTimeout(this.userFlyoutCloseTimer),this.userFlyoutCloseTimer=null)}setUserFlyout(e){this.cancelUserFlyoutClose(),this.userFlyoutItemId=e,this.querySelectorAll(".designbase-wc-sidebar__user-menu-item").forEach(t=>{const s=Boolean(e&&t.dataset.itemId===e);t.classList.toggle("designbase-wc-sidebar__user-menu-item--flyout-active",s),t.querySelector(".designbase-wc-sidebar__user-menu-trigger")?.setAttribute("aria-expanded",String(s));const i=t.querySelector(".designbase-wc-sidebar__user-flyout");i&&(i.hidden=!s)})}scheduleUserFlyoutClose(){this.cancelUserFlyoutClose(),this.userFlyoutCloseTimer=setTimeout(()=>{this.userFlyoutCloseTimer=null,this.setUserFlyout(null)},120)}syncHostClasses(){const e=this.getAttribute("size")||"m",t=this.getAttribute("variant")||"default",a=this.getAttribute("position")||"left";this.className=["designbase-wc-sidebar",`designbase-wc-sidebar--${s.includes(e)?e:"m"}`,`designbase-wc-sidebar--${i.includes(t)?t:"default"}`,`designbase-wc-sidebar--${r.includes(a)?a:"left"}`,this.hasAttribute("collapsed")&&"designbase-wc-sidebar--collapsed",this.hasAttribute("full-height")&&"designbase-wc-sidebar--full-height",this.hasAttribute("shadow")&&"designbase-wc-sidebar--shadow",this.userMenuOpen&&"designbase-wc-sidebar--user-menu-open","back"===this.headerType&&"designbase-wc-sidebar--header-back"].filter(Boolean).join(" ")}dispatchItemClick(e){this.dispatchEvent(new CustomEvent("db-item-click",{bubbles:!0,composed:!0,detail:{item:e}}))}dispatchUserMenuItemClick(e){this.dispatchEvent(new CustomEvent("db-user-menu-item-click",{bubbles:!0,composed:!0,detail:{item:e}}))}dispatchBackClick(){const e=new CustomEvent("db-back-click",{bubbles:!0,composed:!0,cancelable:!0,detail:{label:this.backLabel,href:this.backHref}});this.dispatchEvent(e),!e.defaultPrevented&&this.backHref&&window.location.assign(this.backHref)}dispatchProjectChange(e){this.dispatchEvent(new CustomEvent("db-project-change",{bubbles:!0,composed:!0,detail:{project:e}}))}dispatchProjectManage(){this.dispatchEvent(new CustomEvent("db-project-manage",{bubbles:!0,composed:!0,detail:{}}))}dispatchPromoCtaClick(e){this.dispatchEvent(new CustomEvent("db-promo-cta-click",{bubbles:!0,composed:!0,detail:{banner:e}}))}createProjectAvatar(e,t="s"){const s=document.createElement("db-avatar");if(s.className="designbase-wc-sidebar__project-avatar",s.setAttribute("size",t),s.setAttribute("initials",(e.label||"?").trim()),s.setAttribute("alt",e.label),e.color){const applyColor=()=>{const t=s.querySelector(".designbase-wc-avatar__initials");return!!t&&(t.style.backgroundColor=e.color,t.style.color="#fff",!0)},t=new MutationObserver(()=>{applyColor()&&t.disconnect()});t.observe(s,{childList:!0,subtree:!0}),queueMicrotask(()=>{applyColor()&&t.disconnect()})}return s}createProjectEmptyMark(t="s"){const s=document.createElement("span");return s.className=["designbase-wc-sidebar__project-mark",`designbase-wc-sidebar__project-mark--${t}`,"designbase-wc-sidebar__project-mark--empty"].join(" "),s.setAttribute("aria-hidden","true"),s.append(e("plus","m"===t?16:14)),s}createProjectBadge(e){if(!e.badge)return null;const t=document.createElement("db-badge");return t.className="designbase-wc-sidebar__project-badge",t.setAttribute("size","s"),t.setAttribute("variant",e.badgeColor||"warning"),t.setAttribute("badge-style","text"),t.textContent=e.badge,t}createProjectSelector(t){if(!this.hasAttribute("projects"))return null;const s=this.parseProjects(),i=0===s.length,r=this.getSelectedProject(),a=document.createElement("div");a.className=["designbase-wc-sidebar__project-selector",t&&"designbase-wc-sidebar__project-selector--collapsed",this.projectMenuOpen&&"designbase-wc-sidebar__project-selector--open",i&&"designbase-wc-sidebar__project-selector--empty"].filter(Boolean).join(" ");const n=this.getAttribute("project-section-label");if(!t&&n&&n.trim()){const e=document.createElement("div");e.className="designbase-wc-sidebar__project-section-label",e.textContent=n.trim(),a.append(e)}const c=document.createElement("button");if(c.type="button",c.className="designbase-wc-sidebar__project-trigger",c.setAttribute("aria-haspopup","menu"),c.setAttribute("aria-expanded",String(this.projectMenuOpen)),i||!r){if(c.setAttribute("aria-label",this.projectEmptyTriggerLabel),c.append(this.createProjectEmptyMark(t?"m":"s")),!t){const e=document.createElement("span");e.className="designbase-wc-sidebar__project-label",e.textContent=this.projectEmptyTriggerLabel,c.append(e)}}else if(c.setAttribute("aria-label",r.label),c.append(this.createProjectAvatar(r,t?"m":"s")),!t){const e=document.createElement("span");e.className="designbase-wc-sidebar__project-label",e.textContent=r.label,c.append(e)}const o=document.createElement("span");if(o.className="designbase-wc-sidebar__project-chevron",o.setAttribute("aria-hidden","true"),o.append(e("chevron-down",14)),c.append(o),c.addEventListener("click",()=>{this.projectMenuOpen=!this.projectMenuOpen,this.userMenuOpen=!1,this.render()}),a.append(c),this.projectMenuOpen){const t=document.createElement("div");if(t.className="designbase-wc-sidebar__project-dropdown",t.setAttribute("role","menu"),t.setAttribute("aria-label",this.projectSectionLabel),i){const e=document.createElement("div");e.className="designbase-wc-sidebar__project-empty",e.setAttribute("role","presentation");const s=document.createElement("p");s.className="designbase-wc-sidebar__project-empty-text",s.textContent=this.projectEmptyLabel,e.append(s),t.append(e)}else{const e=document.createElement("ul");e.className="designbase-wc-sidebar__project-list",s.forEach(t=>{const s=document.createElement("li");s.className="designbase-wc-sidebar__project-option";const i=document.createElement("button");i.type="button",i.className=["designbase-wc-sidebar__project-option-btn",r&&t.id===r.id&&"designbase-wc-sidebar__project-option-btn--active"].filter(Boolean).join(" "),i.setAttribute("role","menuitem"),i.append(this.createProjectAvatar(t,"s"));const a=document.createElement("span");a.className="designbase-wc-sidebar__project-option-label",a.textContent=t.label,i.append(a);const n=this.createProjectBadge(t);n&&i.append(n),i.addEventListener("click",()=>{this.projectMenuOpen=!1,this.setAttribute("selected-project-id",t.id),this.dispatchProjectChange(t),this.render()}),s.append(i),e.append(s)}),t.append(e)}const n=document.createElement("button");n.type="button",n.className="designbase-wc-sidebar__project-manage",n.setAttribute("role","menuitem"),n.append(e("plus",14));const c=document.createElement("span");c.textContent=this.projectManageLabel,n.append(c),n.addEventListener("click",()=>{this.projectMenuOpen=!1;const e=this.projectManageHref;e&&window.location.assign(e),this.dispatchProjectManage(),this.render()}),t.append(n),a.append(t)}return a}createFlyout(e,t){const s=this.getAttribute("position")||"left",i=document.createElement("div");i.className=["designbase-wc-sidebar__flyout","right"===s&&"designbase-wc-sidebar__flyout--align-left"].filter(Boolean).join(" "),i.setAttribute("role","menu"),i.setAttribute("aria-label",`${e.label} 하위 메뉴`),i.addEventListener("mouseenter",()=>this.cancelFlyoutClose()),i.addEventListener("mouseleave",()=>this.scheduleFlyoutClose());const r=document.createElement("div");r.className="designbase-wc-sidebar__flyout-title",r.textContent=e.label,i.append(r);const a=document.createElement("ul");return a.className="designbase-wc-sidebar__flyout-list",(e.children||[]).forEach(e=>{const s=document.createElement("li");s.className="designbase-wc-sidebar__flyout-item";const i=document.createElement("db-menu-item");i.setAttribute("label",e.label),i.setAttribute("type","block"),i.setAttribute("menu-style","dropdown"),i.setAttribute("size",t),e.href&&i.setAttribute("href",e.href),e.active&&i.setAttribute("active",""),e.disabled&&i.setAttribute("disabled",""),void 0!==e.badge&&i.setAttribute("badge",String(e.badge)),e.badgeColor&&i.setAttribute("badge-color",e.badgeColor),i.addEventListener("db-click",()=>{e.disabled||(this.flyoutItemId=null,this.dispatchItemClick(e),this.renderNav(),this.renderBottomNav())}),s.append(i),a.append(s)}),i.append(a),i}createSidebarMenuItem(e,t,s=0){const i=Boolean(e.children?.length),r=this.expandedItems.has(e.id),a=this.hasAttribute("collapsed"),n=a&&i,c=document.createElement("li");c.className=["designbase-wc-sidebar__item",n&&this.flyoutItemId===e.id&&"designbase-wc-sidebar__item--flyout-active"].filter(Boolean).join(" "),n&&(c.addEventListener("mouseenter",()=>this.showFlyout(e.id)),c.addEventListener("mouseleave",()=>this.scheduleFlyoutClose()));const o=document.createElement("db-menu-item");if(o.setAttribute("data-item-id",e.id),o.setAttribute("label",e.label),o.setAttribute("type","block"),o.setAttribute("menu-style","accordion"),o.setAttribute("size",t),o.setAttribute("depth",String(s)),e.href&&o.setAttribute("href",e.href),e.icon&&o.setAttribute("icon",e.icon),e.active&&o.setAttribute("active",""),e.disabled&&o.setAttribute("disabled",""),void 0!==e.badge&&o.setAttribute("badge",String(e.badge)),e.badgeColor&&o.setAttribute("badge-color",e.badgeColor),i&&!n&&(o.setAttribute("expandable",""),o.subItems=(e.children||[]).map(e=>({id:e.id,label:e.label,href:e.href,active:e.active,disabled:e.disabled,badge:e.badge,badgeColor:e.badgeColor})),r&&!a&&o.setAttribute("expanded","")),o.addEventListener("db-click",t=>{if(!e.disabled){if(i&&!a){const s=t.detail?.expanded??!this.expandedItems.has(e.id);return this.closeOverlayMenus(),void(s?(this.expandedItems.clear(),this.expandedItems.add(e.id),this.syncExclusiveAccordion(e.id)):(this.expandedItems.delete(e.id),this.syncExclusiveAccordion(null)))}if(n)return this.closeOverlayMenus(),void this.showFlyout(e.id);this.closeOverlayMenus(),this.dispatchItemClick(e)}}),o.addEventListener("db-child-click",e=>{const t=e.detail;this.dispatchItemClick(t.child)}),c.append(o),a&&void 0!==e.badge&&null!==e.badge&&""!==e.badge){const t=e.badgeColor||"primary",s=document.createElement("span");s.className=["designbase-wc-sidebar__collapsed-badge-dot",`designbase-wc-sidebar__collapsed-badge-dot--${t}`].join(" "),s.setAttribute("aria-hidden","true"),c.append(s)}if(a&&!i){const t=document.createElement("span");t.className="designbase-wc-sidebar__item-tooltip",t.textContent=e.label,t.setAttribute("role","tooltip"),c.append(t)}return n&&this.flyoutItemId===e.id&&c.append(this.createFlyout(e,t)),c}renderSectionList(e,t,s){const i=document.createDocumentFragment();return e.forEach(e=>{const r=document.createElement("div");if(r.className=["designbase-wc-sidebar__section",e.gap&&`designbase-wc-sidebar__section--gap-${e.gap}`].filter(Boolean).join(" "),!s&&e.title){const t=document.createElement("div");t.className="designbase-wc-sidebar__section-title",t.textContent=e.title,r.append(t)}const a=document.createElement("ul");a.className="designbase-wc-sidebar__nav-list",e.items.forEach(e=>a.append(this.createSidebarMenuItem(e,t))),r.append(a),i.append(r)}),i}renderNav(){const e=this.querySelector(".designbase-wc-sidebar__nav");if(!e)return;const t=this.getAttribute("size")||"m",s=this.hasAttribute("collapsed");e.replaceChildren(this.renderSectionList(this.parseSections(),t,s))}renderBottomNav(){const e=this.querySelector(".designbase-wc-sidebar__bottom-nav");if(!e)return;const t=this.getAttribute("size")||"m",s=this.hasAttribute("collapsed");e.replaceChildren(this.renderSectionList(this.parseBottomSections(),t,s))}createUserDropdown(s,i=!1){if(!s.length)return null;const r=this.getAttribute("position")||"left",a=document.createElement("div");a.className=["designbase-wc-sidebar__user-dropdown",i&&"designbase-wc-sidebar__user-dropdown--collapsed"].filter(Boolean).join(" "),a.setAttribute("role","menu"),a.setAttribute("aria-label","사용자 메뉴"),a.hidden=!this.userMenuOpen,a.addEventListener("keydown",e=>{"Escape"===e.key&&(e.stopPropagation(),this.userFlyoutItemId?this.setUserFlyout(null):(this.userMenuOpen=!1,this.render()))});const n=document.createElement("ul");return n.className="designbase-wc-sidebar__user-menu",s.forEach(s=>{const i=Boolean(s.children?.length),a=document.createElement("li");a.dataset.itemId=s.id,a.className=["designbase-wc-sidebar__user-menu-item",s.dividerBefore&&"designbase-wc-sidebar__user-menu-item--divider",s.disabled&&"designbase-wc-sidebar__user-menu-item--disabled",i&&"designbase-wc-sidebar__user-menu-item--has-children"].filter(Boolean).join(" ");const c=document.createElement("button");if(c.type="button",c.className="designbase-wc-sidebar__user-menu-trigger",c.setAttribute("role","menuitem"),c.disabled=Boolean(s.disabled),s.icon&&t(s.icon)){const t=document.createElement("span");t.className="designbase-wc-sidebar__user-menu-icon",t.setAttribute("aria-hidden","true"),t.append(e(s.icon,16)),c.append(t)}const o=document.createElement("span");if(o.className="designbase-wc-sidebar__user-menu-label",o.textContent=s.label,c.append(o),s.value){const e=document.createElement("span");e.className="designbase-wc-sidebar__user-menu-value",e.textContent=s.value,c.append(e)}if(i){const i=document.createElement("span");i.className="designbase-wc-sidebar__user-menu-chevron",i.setAttribute("aria-hidden","true"),i.append(e("right"===r?"chevron-left":"chevron-right",16)),c.append(i),c.setAttribute("aria-haspopup","menu"),c.setAttribute("aria-expanded",String(this.userFlyoutItemId===s.id));const openFlyout=()=>this.setUserFlyout(s.id);a.addEventListener("mouseenter",openFlyout),a.addEventListener("mouseleave",()=>this.scheduleUserFlyoutClose()),a.addEventListener("focusin",openFlyout),a.addEventListener("focusout",e=>{const t=e.relatedTarget;t&&a.contains(t)||this.scheduleUserFlyoutClose()}),c.addEventListener("click",openFlyout);const n=document.createElement("div");n.className=["designbase-wc-sidebar__user-flyout","right"===r&&"designbase-wc-sidebar__user-flyout--align-left"].filter(Boolean).join(" "),n.setAttribute("role","menu"),n.setAttribute("aria-label",`${s.label} 하위 메뉴`),n.hidden=this.userFlyoutItemId!==s.id,n.addEventListener("mouseenter",()=>this.cancelUserFlyoutClose()),n.addEventListener("mouseleave",()=>this.scheduleUserFlyoutClose());const o=document.createElement("ul");o.className="designbase-wc-sidebar__user-flyout-list",(s.children||[]).forEach(s=>{const i=document.createElement("li");i.className="designbase-wc-sidebar__user-flyout-item";const r=document.createElement("button");if(r.type="button",r.className=["designbase-wc-sidebar__user-menu-trigger","designbase-wc-sidebar__user-flyout-trigger",s.selected&&"designbase-wc-sidebar__user-flyout-trigger--selected"].filter(Boolean).join(" "),r.setAttribute("role","menuitemradio"),r.setAttribute("aria-checked",String(Boolean(s.selected))),r.disabled=Boolean(s.disabled),s.icon&&t(s.icon)){const t=document.createElement("span");t.className="designbase-wc-sidebar__user-menu-icon",t.setAttribute("aria-hidden","true"),t.append(e(s.icon,16)),r.append(t)}const a=document.createElement("span");if(a.className="designbase-wc-sidebar__user-menu-label",a.textContent=s.label,r.append(a),s.selected){const t=document.createElement("span");t.className="designbase-wc-sidebar__user-menu-check",t.setAttribute("aria-hidden","true"),t.append(e("done",16)),r.append(t)}r.addEventListener("click",()=>{s.disabled||(this.userFlyoutItemId=null,this.userMenuOpen=!1,this.dispatchUserMenuItemClick(s),s.href&&window.location.assign(s.href),this.render())}),i.append(r),o.append(i)}),n.append(o),a.append(c,n)}else c.addEventListener("click",()=>{s.disabled||(this.userFlyoutItemId=null,this.userMenuOpen=!1,this.dispatchUserMenuItemClick(s),s.href&&window.location.assign(s.href),this.render())}),a.append(c);n.append(a)}),a.append(n),a}createPromoBanner(s){if("back"===this.headerType)return null;const i=this.parsePromoBanner();if(!i)return null;if(s){const s=document.createElement("button");s.type="button",s.className="designbase-wc-sidebar__promo-collapsed",s.setAttribute("aria-label",i.ctaLabel||i.title);const r=document.createElement("db-animation-background");r.className="designbase-wc-sidebar__promo-bg",r.setAttribute("type","aurora"),r.setAttribute("theme","light"),r.setAttribute("intensity","subtle"),r.setAttribute("blur","40"),r.setAttribute("speed","4000"),r.setAttribute("colors",JSON.stringify(["#c7d2fe","#ddd6fe","#fbcfe8"])),s.append(r),s.append(e(i.icon&&t(i.icon)?i.icon:"sparkle",18)),s.addEventListener("click",()=>this.dispatchPromoCtaClick(i));const a=document.createElement("span");a.className="designbase-wc-sidebar__item-tooltip",a.textContent=i.title,a.setAttribute("role","tooltip");const n=document.createElement("div");return n.className="designbase-wc-sidebar__promo-collapsed-wrap",n.append(s,a),n}const r=document.createElement("div");r.className="designbase-wc-sidebar__promo";const a=document.createElement("db-animation-background");a.className="designbase-wc-sidebar__promo-bg",a.setAttribute("type","aurora"),a.setAttribute("theme","light"),a.setAttribute("intensity","subtle"),a.setAttribute("blur","60"),a.setAttribute("speed","5000"),a.setAttribute("colors",JSON.stringify(["#c7d2fe","#ddd6fe","#fbcfe8","#bfdbfe"])),r.append(a);const n=document.createElement("div");n.className="designbase-wc-sidebar__promo-content";const c=document.createElement("div");c.className="designbase-wc-sidebar__promo-title-row";const o=document.createElement("span");o.className="designbase-wc-sidebar__promo-icon",o.setAttribute("aria-hidden","true"),o.append(e(i.icon&&t(i.icon)?i.icon:"sparkle",16));const d=document.createElement("div");if(d.className="designbase-wc-sidebar__promo-title",d.textContent=i.title,c.append(o,d),n.append(c),i.description){const e=document.createElement("div");e.className="designbase-wc-sidebar__promo-desc",e.textContent=i.description,n.append(e)}if(i.ctaLabel){const e=document.createElement("db-button");e.className="designbase-wc-sidebar__promo-action",e.setAttribute("variant","secondary"),e.setAttribute("size","s"),e.setAttribute("full-width",""),e.textContent=i.ctaLabel,e.addEventListener("db-click",()=>{i.ctaHref&&window.location.assign(i.ctaHref),this.dispatchPromoCtaClick(i)}),n.append(e)}return r.append(n),r}render(){this.syncHostClasses(),this.setAttribute("role","complementary"),this.setAttribute("aria-label","사이드바 네비게이션");const t=this.getAttribute("size")||"m",s="false"!==this.getAttribute("collapsible"),i="false"!==this.getAttribute("show-logo"),r=this.hasAttribute("collapsed"),a=this.parseUserProfile(),n=this.parseUserMenuItems(),c=this.parseBottomSections(),o="l"===t?"m":"s"===t?"xs":"s";this.replaceChildren();const d=document.createElement("div");if(d.className="designbase-wc-sidebar__container","back"===this.headerType||s||i&&!r){const t=document.createElement("div");if(t.className=["designbase-wc-sidebar__header",(r||!i)&&"designbase-wc-sidebar__header--collapsed-only","back"===this.headerType&&"designbase-wc-sidebar__header--back"].filter(Boolean).join(" "),"back"===this.headerType){const s=document.createElement("button");if(s.type="button",s.className=["designbase-wc-sidebar__back",r&&"designbase-wc-sidebar__back--collapsed"].filter(Boolean).join(" "),s.setAttribute("aria-label",this.backLabel),s.append(e("chevron-left",18)),!r){const e=document.createElement("span");e.textContent=this.backLabel,s.append(e)}s.addEventListener("click",()=>this.dispatchBackClick()),t.append(s)}else if(!r&&i){const e=document.createElement("div");e.className="designbase-wc-sidebar__logo";const s=document.createElement("db-logo");s.setAttribute("type","designbase"),s.setAttribute("size",o),e.append(s),e.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-logo-click",{bubbles:!0,composed:!0}))}),t.append(e)}if(s){const e=document.createElement("db-button");e.className="designbase-wc-sidebar__toggle",e.setAttribute("variant","tertiary"),e.setAttribute("size","s"),e.setAttribute("icon-only",""),e.setAttribute("start-icon",r?"arrow-bar-right":"arrow-bar-left"),e.setAttribute("aria-label",r?"사이드바 펼치기":"사이드바 접기"),e.addEventListener("db-click",()=>{const e=!this.hasAttribute("collapsed");e?this.setAttribute("collapsed",""):this.removeAttribute("collapsed"),this.dispatchEvent(new CustomEvent("db-toggle",{bubbles:!0,composed:!0,detail:{collapsed:e}}))}),t.append(e)}d.append(t)}const l=document.createElement("div");l.className="designbase-wc-sidebar__nav-wrapper";const u=this.createProjectSelector(r);u&&l.append(u);const b=document.createElement("nav");if(b.className="designbase-wc-sidebar__nav",b.setAttribute("aria-label","주 메뉴"),l.append(b),c.length>0){const e=document.createElement("nav");e.className="designbase-wc-sidebar__bottom-nav",e.setAttribute("aria-label","하단 메뉴"),l.append(e)}d.append(l);const p=document.createElement("div");p.className="designbase-wc-sidebar__footer";const m=this.createPromoBanner(r);if(m&&p.append(m),a&&!r){const t=document.createElement("div");t.className="designbase-wc-sidebar__user";const s=this.createUserDropdown(n);s&&t.append(s);const i=document.createElement("div");i.className="designbase-wc-sidebar__user-info",i.setAttribute("role","button"),i.setAttribute("tabindex","0"),i.setAttribute("aria-expanded",String(this.userMenuOpen));const r=document.createElement("db-avatar");r.className="designbase-wc-sidebar__user-avatar",r.setAttribute("size","s"),r.setAttribute("initials",a.name),r.setAttribute("alt",a.name),a.avatar&&r.setAttribute("src",a.avatar);const c=document.createElement("div");c.className="designbase-wc-sidebar__user-details";const o=document.createElement("div");if(o.className="designbase-wc-sidebar__user-name",o.textContent=a.name,c.append(o),a.email){const e=document.createElement("div");e.className="designbase-wc-sidebar__user-email",e.textContent=a.email,c.append(e)}if(i.append(r,c),n.length){const t=document.createElement("span");t.className="designbase-wc-sidebar__user-more",t.setAttribute("aria-hidden","true"),t.append(e("more-vertical",16)),i.append(t),i.setAttribute("aria-haspopup","menu")}i.addEventListener("click",()=>{n.length&&(this.userMenuOpen=!this.userMenuOpen,this.userFlyoutItemId=null,this.cancelUserFlyoutClose(),this.projectMenuOpen=!1,this.render())}),i.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key||(e.preventDefault(),i.click())}),t.append(i),p.append(t)}else if(a&&r){const e=document.createElement("div");e.className=["designbase-wc-sidebar__user-collapsed",this.userMenuOpen&&"designbase-wc-sidebar__user-collapsed--open"].filter(Boolean).join(" "),e.setAttribute("role","button"),e.setAttribute("tabindex","0"),e.setAttribute("aria-label",a.name),e.setAttribute("aria-expanded",String(this.userMenuOpen)),n.length&&e.setAttribute("aria-haspopup","menu");const t=document.createElement("db-avatar");if(t.className="designbase-wc-sidebar__user-avatar-collapsed",t.setAttribute("size","s"),t.setAttribute("initials",a.name),t.setAttribute("alt",a.name),a.avatar&&t.setAttribute("src",a.avatar),e.append(t),!this.userMenuOpen){const t=document.createElement("span");t.className="designbase-wc-sidebar__item-tooltip",t.textContent=a.name,t.setAttribute("role","tooltip"),e.append(t)}const s=this.createUserDropdown(n,!0);s&&e.append(s),e.addEventListener("click",e=>{n.length&&(e.target.closest(".designbase-wc-sidebar__user-dropdown")||(this.userMenuOpen=!this.userMenuOpen,this.userFlyoutItemId=null,this.cancelUserFlyoutClose(),this.projectMenuOpen=!1,this.render()))}),e.addEventListener("keydown",t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),e.click())}),p.append(e)}d.append(p),this.append(d),this.renderNav(),this.renderBottomNav()}}customElements.get("db-sidebar")||customElements.define("db-sidebar",DbSidebar);export{DbSidebar};