@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,402 +1 @@
1
- const CLASS = 'designbase-wc-marquee';
2
- function isImageItem(item) {
3
- return typeof item === 'object' && item !== null && typeof item.src === 'string';
4
- }
5
- class DbMarquee extends HTMLElement {
6
- constructor() {
7
- super(...arguments);
8
- this.built = false;
9
- this.rows = [];
10
- this.rowCount = 0;
11
- this.containerWidth = 0;
12
- this.gap = 24;
13
- // scroll-velocity 상태
14
- this.scrollVelocityEnabled = false;
15
- this.rafId = 0;
16
- this.lastFrameTime = 0;
17
- this.lastScrollY = 0;
18
- this.smoothedScrollV = 0;
19
- this.baseDurationSec = 12;
20
- this.reduceMotion = false;
21
- this.boundMeasure = () => this.measure();
22
- this.boundFrame = (t) => this.frame(t);
23
- }
24
- static get observedAttributes() {
25
- return [
26
- 'items',
27
- 'direction',
28
- 'duration',
29
- 'speed',
30
- 'size',
31
- 'variant',
32
- 'bordered',
33
- 'pause-on-hover',
34
- 'fade-edges',
35
- 'fade-width',
36
- 'edge-padding',
37
- 'gap',
38
- 'align-y',
39
- 'row-count',
40
- 'row-gap',
41
- 'scroll-velocity',
42
- 'scroll-boost',
43
- 'aria-label',
44
- ];
45
- }
46
- connectedCallback() {
47
- this.style.display = 'block';
48
- if (!this.built) {
49
- this.built = true;
50
- this.reduceMotion =
51
- typeof window !== 'undefined' &&
52
- typeof window.matchMedia === 'function' &&
53
- window.matchMedia('(prefers-reduced-motion: reduce)').matches;
54
- this.build();
55
- this.bindResize();
56
- }
57
- this.updateUI();
58
- }
59
- disconnectedCallback() {
60
- this.resizeObserver?.disconnect();
61
- this.stopScrollEngine();
62
- this.unbindImageListeners();
63
- }
64
- attributeChangedCallback() {
65
- if (!this.built)
66
- return;
67
- this.updateUI();
68
- }
69
- getBool(name, fallback = false) {
70
- if (!this.hasAttribute(name))
71
- return fallback;
72
- const value = this.getAttribute(name);
73
- return value === '' || value === 'true';
74
- }
75
- parseItems() {
76
- try {
77
- const raw = this.getAttribute('items');
78
- const parsed = raw ? JSON.parse(raw) : [];
79
- if (Array.isArray(parsed) && parsed.length > 0) {
80
- return parsed.filter((item) => typeof item === 'string' || isImageItem(item));
81
- }
82
- }
83
- catch {
84
- /* fallback to slot */
85
- }
86
- const slotted = Array.from(this.children).filter((child) => !child.hasAttribute('data-wc-internal'));
87
- if (slotted.length > 0)
88
- return slotted.map((node) => node.textContent?.trim() || '');
89
- return [];
90
- }
91
- itemToText(item) {
92
- return isImageItem(item) ? item.alt || '' : item;
93
- }
94
- build() {
95
- this.containerEl = document.createElement('div');
96
- this.srOnlyEl = document.createElement('span');
97
- this.srOnlyEl.className = `${CLASS}__sr-only`;
98
- this.rowsEl = document.createElement('div');
99
- this.rowsEl.className = `${CLASS}__rows`;
100
- this.containerEl.append(this.srOnlyEl, this.rowsEl);
101
- this.append(this.containerEl);
102
- }
103
- bindResize() {
104
- this.resizeObserver = new ResizeObserver(() => this.measure());
105
- if (this.containerEl)
106
- this.resizeObserver.observe(this.containerEl);
107
- }
108
- /** rows 개수에 맞춰 행 DOM을 만들거나 제거한다. */
109
- reconcileRows(count, baseDir) {
110
- if (!this.rowsEl)
111
- return;
112
- this.rowCount = count;
113
- while (this.rows.length < count) {
114
- const rowEl = document.createElement('div');
115
- rowEl.className = `${CLASS}__row`;
116
- const trackEl = document.createElement('div');
117
- trackEl.className = `${CLASS}__track`;
118
- const baseGroupEl = document.createElement('div');
119
- baseGroupEl.className = `${CLASS}__group`;
120
- baseGroupEl.setAttribute('aria-hidden', 'true');
121
- trackEl.append(baseGroupEl);
122
- rowEl.append(trackEl);
123
- this.rowsEl.append(rowEl);
124
- this.rows.push({
125
- rowEl,
126
- trackEl,
127
- baseGroupEl,
128
- baseGroupWidth: 0,
129
- duplicateCount: 0,
130
- baseDir: 1,
131
- x: 0,
132
- dirState: 1,
133
- });
134
- }
135
- while (this.rows.length > count) {
136
- const removed = this.rows.pop();
137
- removed?.rowEl.remove();
138
- }
139
- this.rows.forEach((row, index) => {
140
- // 홀수 행은 반대 방향으로 흘려 좌/우 교차 효과를 만든다.
141
- row.baseDir = index % 2 === 0 ? baseDir : -baseDir;
142
- const goesRight = row.baseDir < 0;
143
- row.rowEl.classList.toggle(`${CLASS}__row--right`, goesRight);
144
- row.rowEl.style.setProperty('--db-marquee-row-index', String(index));
145
- });
146
- if (this.resizeObserver) {
147
- this.rows.forEach((row) => this.resizeObserver?.observe(row.baseGroupEl));
148
- }
149
- }
150
- measure() {
151
- this.containerWidth = Math.ceil(this.containerEl?.clientWidth ?? 0);
152
- this.rows.forEach((row) => {
153
- row.baseGroupWidth = Math.ceil(row.baseGroupEl.scrollWidth ?? 0);
154
- row.rowEl.style.setProperty('--db-marquee-shift', `${row.baseGroupWidth + this.gap}px`);
155
- this.reconcileDuplicates(row);
156
- });
157
- this.syncReadyState();
158
- }
159
- unbindImageListeners() {
160
- this.rows.forEach((row) => {
161
- row.baseGroupEl.querySelectorAll('img').forEach((img) => {
162
- img.removeEventListener('load', this.boundMeasure);
163
- img.removeEventListener('error', this.boundMeasure);
164
- });
165
- });
166
- }
167
- bindImageListeners() {
168
- this.rows.forEach((row) => {
169
- row.baseGroupEl.querySelectorAll('img').forEach((img) => {
170
- if (img.complete)
171
- return;
172
- img.addEventListener('load', this.boundMeasure);
173
- img.addEventListener('error', this.boundMeasure);
174
- });
175
- });
176
- }
177
- renderItem(entry) {
178
- const item = document.createElement('div');
179
- item.className = `${CLASS}__item`;
180
- if (isImageItem(entry)) {
181
- item.classList.add(`${CLASS}__item--image`);
182
- const img = document.createElement('img');
183
- img.className = `${CLASS}__image`;
184
- img.src = entry.src;
185
- img.alt = entry.alt || '';
186
- img.loading = 'lazy';
187
- img.decoding = 'async';
188
- if (entry.height)
189
- img.style.height = `${entry.height}px`;
190
- if (entry.href) {
191
- const link = document.createElement('a');
192
- link.className = `${CLASS}__link`;
193
- link.href = entry.href;
194
- link.setAttribute('tabindex', '-1');
195
- link.append(img);
196
- item.append(link);
197
- }
198
- else {
199
- item.append(img);
200
- }
201
- return item;
202
- }
203
- item.textContent = entry;
204
- return item;
205
- }
206
- renderGroup(items, ref) {
207
- const group = ref ?? document.createElement('div');
208
- group.className = `${CLASS}__group`;
209
- group.setAttribute('aria-hidden', 'true');
210
- group.replaceChildren(...items.map((text) => this.renderItem(text)));
211
- return group;
212
- }
213
- /**
214
- * 각 행의 base 그룹을 items로 다시 만든다 — items/attributes 변경 시에만 실행.
215
- * 이미지 노드 재생성으로 인한 재로딩을 막기 위해 measure() 중에는 건드리지 않는다.
216
- */
217
- buildBase(items) {
218
- this.rows.forEach((row) => {
219
- this.renderGroup(items, row.baseGroupEl);
220
- while (row.trackEl.children.length > 1) {
221
- row.trackEl.lastElementChild?.remove();
222
- }
223
- row.duplicateCount = 0;
224
- });
225
- }
226
- baseImagesReady(row) {
227
- return Array.from(row.baseGroupEl.querySelectorAll('img')).every((img) => img.complete);
228
- }
229
- /** 트랙을 채울 만큼의 복제 그룹 개수를 델타만 조정한다. */
230
- reconcileDuplicates(row) {
231
- const desired = row.baseGroupWidth > 0 && this.baseImagesReady(row)
232
- ? Math.max(1, Math.ceil((this.containerWidth * 2) / row.baseGroupWidth))
233
- : 1;
234
- let current = row.trackEl.children.length - 1;
235
- if (current === desired) {
236
- row.duplicateCount = desired;
237
- return;
238
- }
239
- const items = this.parseItems();
240
- while (current < desired) {
241
- row.trackEl.append(this.renderGroup(items));
242
- current += 1;
243
- }
244
- while (current > desired) {
245
- row.trackEl.lastElementChild?.remove();
246
- current -= 1;
247
- }
248
- row.duplicateCount = desired;
249
- }
250
- syncReadyState() {
251
- if (!this.containerEl)
252
- return;
253
- const ready = this.rows.length > 0 && this.rows.every((row) => row.baseGroupWidth > 0);
254
- this.containerEl.classList.toggle(`${CLASS}--ready`, ready);
255
- }
256
- // ── scroll-velocity 엔진 ──────────────────────────────────────────────
257
- startScrollEngine() {
258
- if (this.rafId || this.reduceMotion)
259
- return;
260
- this.lastScrollY = typeof window !== 'undefined' ? window.scrollY : 0;
261
- this.lastFrameTime = 0;
262
- this.smoothedScrollV = 0;
263
- this.rows.forEach((row) => {
264
- row.x = 0;
265
- row.dirState = 1;
266
- });
267
- this.rafId = requestAnimationFrame(this.boundFrame);
268
- }
269
- stopScrollEngine() {
270
- if (this.rafId) {
271
- cancelAnimationFrame(this.rafId);
272
- this.rafId = 0;
273
- }
274
- // CSS 애니메이션으로 복귀할 수 있도록 인라인 transform 제거
275
- this.rows.forEach((row) => {
276
- row.trackEl.style.transform = '';
277
- });
278
- }
279
- frame(now) {
280
- if (!this.scrollVelocityEnabled) {
281
- this.rafId = 0;
282
- return;
283
- }
284
- if (!this.lastFrameTime)
285
- this.lastFrameTime = now;
286
- const dt = Math.min((now - this.lastFrameTime) / 1000, 0.05);
287
- this.lastFrameTime = now;
288
- // 스크롤 속도(px/s)를 측정하고 지수 감쇠로 부드럽게 만든다.
289
- const scrollY = typeof window !== 'undefined' ? window.scrollY : 0;
290
- const rawV = dt > 0 ? (scrollY - this.lastScrollY) / dt : 0;
291
- this.lastScrollY = scrollY;
292
- const smoothing = 1 - Math.exp(-dt / 0.12);
293
- this.smoothedScrollV += (rawV - this.smoothedScrollV) * smoothing;
294
- const boost = Math.max(Number(this.getAttribute('scroll-boost') || 6), 0);
295
- // 스크롤 속도를 배율로 환산(부호 유지). 800px/s ≈ 1.0
296
- const velocityFactor = (this.smoothedScrollV / 800) * (boost / 6);
297
- this.rows.forEach((row) => {
298
- const shift = row.baseGroupWidth + this.gap;
299
- if (shift <= 0)
300
- return;
301
- const pxPerSec = shift / this.baseDurationSec;
302
- // 기본 진행: baseDir(+1=왼쪽) → x 감소
303
- let moveBy = -row.baseDir * pxPerSec * dt;
304
- // 아래로 스크롤(velocityFactor>0)은 기본 방향 유지·가속,
305
- // 위로 스크롤(velocityFactor<0)은 진행 방향 반전.
306
- if (velocityFactor < 0)
307
- row.dirState = -1;
308
- else if (velocityFactor > 0)
309
- row.dirState = 1;
310
- moveBy *= row.dirState;
311
- moveBy += moveBy * Math.abs(velocityFactor);
312
- // 이음새 없는 루프를 위해 위치를 (-shift, 0] 범위로 정규화한다.
313
- let x = (row.x + moveBy) % shift;
314
- if (x > 0)
315
- x -= shift;
316
- row.x = x;
317
- row.trackEl.style.transform = `translate3d(${x}px, 0, 0)`;
318
- });
319
- this.rafId = requestAnimationFrame(this.boundFrame);
320
- }
321
- updateUI() {
322
- const items = this.parseItems();
323
- if (items.length === 0) {
324
- this.stopScrollEngine();
325
- this.hidden = true;
326
- return;
327
- }
328
- this.hidden = false;
329
- const direction = this.getAttribute('direction') || 'left';
330
- const baseDir = direction === 'right' ? -1 : 1;
331
- const duration = Math.max(Number(this.getAttribute('duration') || 12), 1);
332
- const speed = Number(this.getAttribute('speed') || 1);
333
- const resolvedSpeed = Number.isFinite(speed) && speed > 0 ? speed : 1;
334
- const resolvedDuration = duration / resolvedSpeed;
335
- this.baseDurationSec = resolvedDuration;
336
- const size = this.getAttribute('size') || 'm';
337
- const variant = this.getAttribute('variant') || 'default';
338
- const alignY = this.getAttribute('align-y') || 'center';
339
- const fadeEdges = this.getBool('fade-edges');
340
- const fadeWidth = Math.max(Number(this.getAttribute('fade-width') || 48), 0);
341
- const edgePaddingRaw = this.getAttribute('edge-padding');
342
- const edgePadding = edgePaddingRaw !== null && edgePaddingRaw !== ''
343
- ? Math.max(Number(edgePaddingRaw), 0)
344
- : fadeEdges
345
- ? fadeWidth
346
- : 0;
347
- const gap = Math.max(Number(this.getAttribute('gap') || 24), 0);
348
- this.gap = gap;
349
- const rowCountRaw = Math.round(Number(this.getAttribute('row-count') || 1));
350
- const rows = Number.isFinite(rowCountRaw) ? Math.min(Math.max(rowCountRaw, 1), 8) : 1;
351
- const rowGap = Math.max(Number(this.getAttribute('row-gap') || 12), 0);
352
- const scrollVelocity = this.getBool('scroll-velocity');
353
- this.scrollVelocityEnabled = scrollVelocity;
354
- const pauseOnHover = this.getBool('pause-on-hover', true);
355
- const bordered = this.hasAttribute('bordered') ? this.getBool('bordered') : variant === 'outlined';
356
- const ariaLabel = this.getAttribute('aria-label') || 'Scrolling content';
357
- if (this.containerEl) {
358
- this.containerEl.className = [
359
- CLASS,
360
- `${CLASS}--size-${size}`,
361
- `${CLASS}--variant-${variant}`,
362
- `${CLASS}--align-${alignY}`,
363
- pauseOnHover && !scrollVelocity && `${CLASS}--pause-on-hover`,
364
- fadeEdges && `${CLASS}--fade-edges`,
365
- direction === 'right' && `${CLASS}--right`,
366
- rows > 1 && `${CLASS}--multi-row`,
367
- scrollVelocity && `${CLASS}--scroll-velocity`,
368
- bordered && `${CLASS}--bordered`,
369
- ]
370
- .filter(Boolean)
371
- .join(' ');
372
- this.containerEl.style.setProperty('--db-marquee-duration', `${resolvedDuration}s`);
373
- this.containerEl.style.setProperty('--db-marquee-gap', `${gap}px`);
374
- this.containerEl.style.setProperty('--db-marquee-row-gap', `${rowGap}px`);
375
- this.containerEl.style.setProperty('--db-marquee-fade-width', `${fadeWidth}px`);
376
- this.containerEl.style.setProperty('--db-marquee-edge-padding', `${edgePadding}px`);
377
- this.containerEl.setAttribute('role', 'region');
378
- this.containerEl.setAttribute('aria-label', ariaLabel);
379
- }
380
- if (this.srOnlyEl) {
381
- const srText = items
382
- .map((item) => this.itemToText(item))
383
- .filter(Boolean)
384
- .join(' • ');
385
- this.srOnlyEl.textContent = srText || ariaLabel;
386
- }
387
- this.reconcileRows(rows, baseDir);
388
- this.buildBase(items);
389
- this.bindImageListeners();
390
- this.measure();
391
- if (scrollVelocity) {
392
- this.startScrollEngine();
393
- }
394
- else {
395
- this.stopScrollEngine();
396
- }
397
- }
398
- }
399
- if (!customElements.get('db-marquee'))
400
- customElements.define('db-marquee', DbMarquee);
401
-
402
- export { DbMarquee };
1
+ const t="designbase-wc-marquee";function isImageItem(t){return"object"==typeof t&&null!==t&&"string"==typeof t.src}class DbMarquee extends HTMLElement{constructor(){super(...arguments),this.built=!1,this.rows=[],this.rowCount=0,this.containerWidth=0,this.gap=24,this.scrollVelocityEnabled=!1,this.rafId=0,this.lastFrameTime=0,this.lastScrollY=0,this.smoothedScrollV=0,this.baseDurationSec=12,this.reduceMotion=!1,this.boundMeasure=()=>this.measure(),this.boundFrame=t=>this.frame(t)}static get observedAttributes(){return["items","direction","duration","speed","size","variant","bordered","pause-on-hover","fade-edges","fade-width","edge-padding","gap","align-y","row-count","row-gap","scroll-velocity","scroll-boost","aria-label"]}connectedCallback(){this.style.display="block",this.built||(this.built=!0,this.reduceMotion="undefined"!=typeof window&&"function"==typeof window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,this.build(),this.bindResize()),this.updateUI()}disconnectedCallback(){this.resizeObserver?.disconnect(),this.stopScrollEngine(),this.unbindImageListeners()}attributeChangedCallback(){this.built&&this.updateUI()}getBool(t,e=!1){if(!this.hasAttribute(t))return e;const r=this.getAttribute(t);return""===r||"true"===r}parseItems(){try{const t=this.getAttribute("items"),e=t?JSON.parse(t):[];if(Array.isArray(e)&&e.length>0)return e.filter(t=>"string"==typeof t||isImageItem(t))}catch{}const t=Array.from(this.children).filter(t=>!t.hasAttribute("data-wc-internal"));return t.length>0?t.map(t=>t.textContent?.trim()||""):[]}itemToText(t){return isImageItem(t)?t.alt||"":t}build(){this.containerEl=document.createElement("div"),this.srOnlyEl=document.createElement("span"),this.srOnlyEl.className=`${t}__sr-only`,this.rowsEl=document.createElement("div"),this.rowsEl.className=`${t}__rows`,this.containerEl.append(this.srOnlyEl,this.rowsEl),this.append(this.containerEl)}bindResize(){this.resizeObserver=new ResizeObserver(()=>this.measure()),this.containerEl&&this.resizeObserver.observe(this.containerEl)}reconcileRows(e,r){if(this.rowsEl){for(this.rowCount=e;this.rows.length<e;){const e=document.createElement("div");e.className=`${t}__row`;const r=document.createElement("div");r.className=`${t}__track`;const s=document.createElement("div");s.className=`${t}__group`,s.setAttribute("aria-hidden","true"),r.append(s),e.append(r),this.rowsEl.append(e),this.rows.push({rowEl:e,trackEl:r,baseGroupEl:s,baseGroupWidth:0,duplicateCount:0,baseDir:1,x:0,dirState:1})}for(;this.rows.length>e;){const t=this.rows.pop();t?.rowEl.remove()}this.rows.forEach((e,s)=>{e.baseDir=s%2==0?r:-r;const i=e.baseDir<0;e.rowEl.classList.toggle(`${t}__row--right`,i),e.rowEl.style.setProperty("--db-marquee-row-index",String(s))}),this.resizeObserver&&this.rows.forEach(t=>this.resizeObserver?.observe(t.baseGroupEl))}}measure(){this.containerWidth=Math.ceil(this.containerEl?.clientWidth??0),this.rows.forEach(t=>{t.baseGroupWidth=Math.ceil(t.baseGroupEl.scrollWidth??0),t.rowEl.style.setProperty("--db-marquee-shift",`${t.baseGroupWidth+this.gap}px`),this.reconcileDuplicates(t)}),this.syncReadyState()}unbindImageListeners(){this.rows.forEach(t=>{t.baseGroupEl.querySelectorAll("img").forEach(t=>{t.removeEventListener("load",this.boundMeasure),t.removeEventListener("error",this.boundMeasure)})})}bindImageListeners(){this.rows.forEach(t=>{t.baseGroupEl.querySelectorAll("img").forEach(t=>{t.complete||(t.addEventListener("load",this.boundMeasure),t.addEventListener("error",this.boundMeasure))})})}renderItem(e){const r=document.createElement("div");if(r.className=`${t}__item`,isImageItem(e)){r.classList.add(`${t}__item--image`);const s=document.createElement("img");if(s.className=`${t}__image`,s.src=e.src,s.alt=e.alt||"",s.loading="lazy",s.decoding="async",e.height&&(s.style.height=`${e.height}px`),e.href){const i=document.createElement("a");i.className=`${t}__link`,i.href=e.href,i.setAttribute("tabindex","-1"),i.append(s),r.append(i)}else r.append(s);return r}return r.textContent=e,r}renderGroup(e,r){const s=r??document.createElement("div");return s.className=`${t}__group`,s.setAttribute("aria-hidden","true"),s.replaceChildren(...e.map(t=>this.renderItem(t))),s}buildBase(t){this.rows.forEach(e=>{for(this.renderGroup(t,e.baseGroupEl);e.trackEl.children.length>1;)e.trackEl.lastElementChild?.remove();e.duplicateCount=0})}baseImagesReady(t){return Array.from(t.baseGroupEl.querySelectorAll("img")).every(t=>t.complete)}reconcileDuplicates(t){const e=t.baseGroupWidth>0&&this.baseImagesReady(t)?Math.max(1,Math.ceil(2*this.containerWidth/t.baseGroupWidth)):1;let r=t.trackEl.children.length-1;if(r===e)return void(t.duplicateCount=e);const s=this.parseItems();for(;r<e;)t.trackEl.append(this.renderGroup(s)),r+=1;for(;r>e;)t.trackEl.lastElementChild?.remove(),r-=1;t.duplicateCount=e}syncReadyState(){if(!this.containerEl)return;const e=this.rows.length>0&&this.rows.every(t=>t.baseGroupWidth>0);this.containerEl.classList.toggle(`${t}--ready`,e)}startScrollEngine(){this.rafId||this.reduceMotion||(this.lastScrollY="undefined"!=typeof window?window.scrollY:0,this.lastFrameTime=0,this.smoothedScrollV=0,this.rows.forEach(t=>{t.x=0,t.dirState=1}),this.rafId=requestAnimationFrame(this.boundFrame))}stopScrollEngine(){this.rafId&&(cancelAnimationFrame(this.rafId),this.rafId=0),this.rows.forEach(t=>{t.trackEl.style.transform=""})}frame(t){if(!this.scrollVelocityEnabled)return void(this.rafId=0);this.lastFrameTime||(this.lastFrameTime=t);const e=Math.min((t-this.lastFrameTime)/1e3,.05);this.lastFrameTime=t;const r="undefined"!=typeof window?window.scrollY:0,s=e>0?(r-this.lastScrollY)/e:0;this.lastScrollY=r;const i=1-Math.exp(-e/.12);this.smoothedScrollV+=(s-this.smoothedScrollV)*i;const a=Math.max(Number(this.getAttribute("scroll-boost")||6),0),o=this.smoothedScrollV/800*(a/6);this.rows.forEach(t=>{const r=t.baseGroupWidth+this.gap;if(r<=0)return;const s=r/this.baseDurationSec;let i=-t.baseDir*s*e;o<0?t.dirState=-1:o>0&&(t.dirState=1),i*=t.dirState,i+=i*Math.abs(o);let a=(t.x+i)%r;a>0&&(a-=r),t.x=a,t.trackEl.style.transform=`translate3d(${a}px, 0, 0)`}),this.rafId=requestAnimationFrame(this.boundFrame)}updateUI(){const e=this.parseItems();if(0===e.length)return this.stopScrollEngine(),void(this.hidden=!0);this.hidden=!1;const r=this.getAttribute("direction")||"left",s="right"===r?-1:1,i=Math.max(Number(this.getAttribute("duration")||12),1),a=Number(this.getAttribute("speed")||1),o=i/(Number.isFinite(a)&&a>0?a:1);this.baseDurationSec=o;const n=this.getAttribute("size")||"m",l=this.getAttribute("variant")||"default",h=this.getAttribute("align-y")||"center",c=this.getBool("fade-edges"),d=Math.max(Number(this.getAttribute("fade-width")||48),0),u=this.getAttribute("edge-padding"),m=null!==u&&""!==u?Math.max(Number(u),0):c?d:0,b=Math.max(Number(this.getAttribute("gap")||24),0);this.gap=b;const p=Math.round(Number(this.getAttribute("row-count")||1)),g=Number.isFinite(p)?Math.min(Math.max(p,1),8):1,E=Math.max(Number(this.getAttribute("row-gap")||12),0),f=this.getBool("scroll-velocity");this.scrollVelocityEnabled=f;const w=this.getBool("pause-on-hover",!0),y=this.hasAttribute("bordered")?this.getBool("bordered"):"outlined"===l,v=this.getAttribute("aria-label")||"Scrolling content";if(this.containerEl&&(this.containerEl.className=[t,`${t}--size-${n}`,`${t}--variant-${l}`,`${t}--align-${h}`,w&&!f&&`${t}--pause-on-hover`,c&&`${t}--fade-edges`,"right"===r&&`${t}--right`,g>1&&`${t}--multi-row`,f&&`${t}--scroll-velocity`,y&&`${t}--bordered`].filter(Boolean).join(" "),this.containerEl.style.setProperty("--db-marquee-duration",`${o}s`),this.containerEl.style.setProperty("--db-marquee-gap",`${b}px`),this.containerEl.style.setProperty("--db-marquee-row-gap",`${E}px`),this.containerEl.style.setProperty("--db-marquee-fade-width",`${d}px`),this.containerEl.style.setProperty("--db-marquee-edge-padding",`${m}px`),this.containerEl.setAttribute("role","region"),this.containerEl.setAttribute("aria-label",v)),this.srOnlyEl){const t=e.map(t=>this.itemToText(t)).filter(Boolean).join(" • ");this.srOnlyEl.textContent=t||v}this.reconcileRows(g,s),this.buildBase(e),this.bindImageListeners(),this.measure(),f?this.startScrollEngine():this.stopScrollEngine()}}customElements.get("db-marquee")||customElements.define("db-marquee",DbMarquee);export{DbMarquee};
@@ -1,94 +1 @@
1
- const COLUMNS = [1, 2, 3, 4, 5, 6];
2
- const SPACINGS = ['xs', 's', 'm', 'l', 'xl'];
3
- class DbMasonry extends HTMLElement {
4
- static get observedAttributes() {
5
- return ['images', 'columns', 'spacing', 'hover', 'clickable'];
6
- }
7
- connectedCallback() {
8
- this.render();
9
- }
10
- attributeChangedCallback() {
11
- this.render();
12
- }
13
- get images() {
14
- try {
15
- const parsed = JSON.parse(this.getAttribute('images') || '[]');
16
- return Array.isArray(parsed) ? parsed.filter((item) => item && typeof item.src === 'string') : [];
17
- }
18
- catch {
19
- return [];
20
- }
21
- }
22
- set images(value) {
23
- this.setAttribute('images', typeof value === 'string' ? value : JSON.stringify(value));
24
- }
25
- boolAttr(name, fallback = true) {
26
- if (!this.hasAttribute(name))
27
- return fallback;
28
- const value = this.getAttribute(name);
29
- return value === '' || value === 'true';
30
- }
31
- render() {
32
- const columnsRaw = Number(this.getAttribute('columns') || 3);
33
- const columns = COLUMNS.includes(columnsRaw) ? columnsRaw : 3;
34
- const spacing = this.getAttribute('spacing') || 'm';
35
- const normalizedSpacing = SPACINGS.includes(spacing) ? spacing : 'm';
36
- const hover = this.boolAttr('hover', true);
37
- const clickable = this.boolAttr('clickable', true);
38
- this.className = [
39
- 'designbase-wc-masonry',
40
- `designbase-wc-masonry--columns-${columns}`,
41
- `designbase-wc-masonry--spacing-${normalizedSpacing}`,
42
- hover && 'designbase-wc-masonry--hover',
43
- clickable && 'designbase-wc-masonry--clickable',
44
- ]
45
- .filter(Boolean)
46
- .join(' ');
47
- const fragment = document.createDocumentFragment();
48
- this.images.forEach((item, index) => {
49
- const el = document.createElement('figure');
50
- el.className = 'designbase-wc-masonry__item';
51
- const img = document.createElement('img');
52
- img.className = 'designbase-wc-masonry__image';
53
- img.src = item.thumbnail || item.src;
54
- img.alt = item.alt || item.title || `image-${index + 1}`;
55
- img.loading = 'lazy';
56
- img.addEventListener('load', () => {
57
- this.dispatchEvent(new CustomEvent('db-image-load', { detail: { image: item, index }, bubbles: true, composed: true }));
58
- });
59
- img.addEventListener('error', () => {
60
- this.dispatchEvent(new CustomEvent('db-image-error', { detail: { image: item, index }, bubbles: true, composed: true }));
61
- });
62
- el.append(img);
63
- if (item.title || item.description) {
64
- const overlay = document.createElement('figcaption');
65
- overlay.className = 'designbase-wc-masonry__overlay';
66
- if (item.title) {
67
- const title = document.createElement('h3');
68
- title.className = 'designbase-wc-masonry__title';
69
- title.textContent = item.title;
70
- overlay.append(title);
71
- }
72
- if (item.description) {
73
- const desc = document.createElement('p');
74
- desc.className = 'designbase-wc-masonry__description';
75
- desc.textContent = item.description;
76
- overlay.append(desc);
77
- }
78
- el.append(overlay);
79
- }
80
- if (clickable) {
81
- el.tabIndex = 0;
82
- el.addEventListener('click', () => {
83
- this.dispatchEvent(new CustomEvent('db-image-click', { detail: { image: item, index }, bubbles: true, composed: true }));
84
- });
85
- }
86
- fragment.append(el);
87
- });
88
- this.replaceChildren(fragment);
89
- }
90
- }
91
- if (!customElements.get('db-masonry'))
92
- customElements.define('db-masonry', DbMasonry);
93
-
94
- export { DbMasonry };
1
+ const e=[1,2,3,4,5,6],t=["xs","s","m","l","xl"];class DbMasonry extends HTMLElement{static get observedAttributes(){return["images","columns","spacing","hover","clickable"]}connectedCallback(){this.render()}attributeChangedCallback(){this.render()}get images(){try{const e=JSON.parse(this.getAttribute("images")||"[]");return Array.isArray(e)?e.filter(e=>e&&"string"==typeof e.src):[]}catch{return[]}}set images(e){this.setAttribute("images","string"==typeof e?e:JSON.stringify(e))}boolAttr(e,t=!0){if(!this.hasAttribute(e))return t;const s=this.getAttribute(e);return""===s||"true"===s}render(){const s=Number(this.getAttribute("columns")||3),n=e.includes(s)?s:3,i=this.getAttribute("spacing")||"m",a=t.includes(i)?i:"m",r=this.boolAttr("hover",!0),c=this.boolAttr("clickable",!0);this.className=["designbase-wc-masonry",`designbase-wc-masonry--columns-${n}`,`designbase-wc-masonry--spacing-${a}`,r&&"designbase-wc-masonry--hover",c&&"designbase-wc-masonry--clickable"].filter(Boolean).join(" ");const o=document.createDocumentFragment();this.images.forEach((e,t)=>{const s=document.createElement("figure");s.className="designbase-wc-masonry__item";const n=document.createElement("img");if(n.className="designbase-wc-masonry__image",n.src=e.thumbnail||e.src,n.alt=e.alt||e.title||`image-${t+1}`,n.loading="lazy",n.addEventListener("load",()=>{this.dispatchEvent(new CustomEvent("db-image-load",{detail:{image:e,index:t},bubbles:!0,composed:!0}))}),n.addEventListener("error",()=>{this.dispatchEvent(new CustomEvent("db-image-error",{detail:{image:e,index:t},bubbles:!0,composed:!0}))}),s.append(n),e.title||e.description){const t=document.createElement("figcaption");if(t.className="designbase-wc-masonry__overlay",e.title){const s=document.createElement("h3");s.className="designbase-wc-masonry__title",s.textContent=e.title,t.append(s)}if(e.description){const s=document.createElement("p");s.className="designbase-wc-masonry__description",s.textContent=e.description,t.append(s)}s.append(t)}c&&(s.tabIndex=0,s.addEventListener("click",()=>{this.dispatchEvent(new CustomEvent("db-image-click",{detail:{image:e,index:t},bubbles:!0,composed:!0}))})),o.append(s)}),this.replaceChildren(o)}}customElements.get("db-masonry")||customElements.define("db-masonry",DbMasonry);export{DbMasonry};