@progressive-development/pd-content 1.0.1 → 1.0.3

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 (85) hide show
  1. package/dist/index.d.ts +5 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +14 -5
  4. package/dist/pd-badge-order/DragController.d.ts +41 -0
  5. package/dist/pd-badge-order/DragController.d.ts.map +1 -0
  6. package/dist/pd-badge-order/DragController.js +239 -0
  7. package/dist/pd-badge-order/PdBadgeItem.d.ts +31 -0
  8. package/dist/pd-badge-order/PdBadgeItem.d.ts.map +1 -0
  9. package/dist/pd-badge-order/PdBadgeItem.js +320 -0
  10. package/dist/pd-badge-order/PdBadgeOrder.d.ts +68 -0
  11. package/dist/pd-badge-order/PdBadgeOrder.d.ts.map +1 -0
  12. package/dist/pd-badge-order/PdBadgeOrder.js +550 -0
  13. package/dist/pd-badge-order/flip-animator.d.ts +30 -0
  14. package/dist/pd-badge-order/flip-animator.d.ts.map +1 -0
  15. package/dist/pd-badge-order/flip-animator.js +39 -0
  16. package/dist/pd-badge-order/pd-badge-item.d.ts +3 -0
  17. package/dist/pd-badge-order/pd-badge-item.d.ts.map +1 -0
  18. package/dist/pd-badge-order/pd-badge-item.js +8 -0
  19. package/dist/pd-badge-order/pd-badge-order.d.ts +3 -0
  20. package/dist/pd-badge-order/pd-badge-order.d.ts.map +1 -0
  21. package/dist/pd-badge-order/types.d.ts +25 -0
  22. package/dist/pd-badge-order/types.d.ts.map +1 -0
  23. package/dist/pd-badge-order/types.js +3 -0
  24. package/dist/pd-badge-order.d.ts +2 -0
  25. package/dist/pd-badge-order.js +8 -0
  26. package/dist/pd-gallery/PdGallery.d.ts +72 -0
  27. package/dist/pd-gallery/PdGallery.d.ts.map +1 -0
  28. package/dist/pd-gallery/PdGallery.js +660 -0
  29. package/dist/pd-gallery/PdGalleryLightbox.d.ts +53 -0
  30. package/dist/pd-gallery/PdGalleryLightbox.d.ts.map +1 -0
  31. package/dist/pd-gallery/PdGalleryLightbox.js +530 -0
  32. package/dist/pd-gallery/index.d.ts +4 -0
  33. package/dist/pd-gallery/index.d.ts.map +1 -0
  34. package/dist/pd-gallery/pd-gallery-lightbox.d.ts +3 -0
  35. package/dist/pd-gallery/pd-gallery-lightbox.d.ts.map +1 -0
  36. package/dist/pd-gallery/pd-gallery.d.ts +3 -0
  37. package/dist/pd-gallery/pd-gallery.d.ts.map +1 -0
  38. package/dist/pd-gallery/types.d.ts +23 -0
  39. package/dist/pd-gallery/types.d.ts.map +1 -0
  40. package/dist/pd-gallery-lightbox.d.ts +2 -0
  41. package/dist/pd-gallery-lightbox.js +8 -0
  42. package/dist/pd-gallery.d.ts +2 -0
  43. package/dist/pd-gallery.js +8 -0
  44. package/dist/pd-loading-state/PdLoadingState.d.ts +25 -9
  45. package/dist/pd-loading-state/PdLoadingState.d.ts.map +1 -1
  46. package/dist/pd-loading-state/PdLoadingState.js +228 -83
  47. package/dist/pd-loading-state/pd-loading-state.d.ts.map +1 -1
  48. package/dist/pd-loading-state/pd-logo-loader.d.ts +25 -0
  49. package/dist/pd-loading-state/pd-logo-loader.d.ts.map +1 -0
  50. package/dist/pd-loading-state/pd-logo-loader.js +63 -0
  51. package/dist/pd-loading-state/register-pd-logo-loader.d.ts +6 -0
  52. package/dist/pd-loading-state/register-pd-logo-loader.d.ts.map +1 -0
  53. package/dist/pd-loading-state/register-pd-logo-loader.js +6 -0
  54. package/dist/pd-loading-state.js +8 -1
  55. package/dist/pd-panel-viewer/PdPanelViewer.d.ts.map +1 -1
  56. package/dist/pd-panel-viewer/PdPanelViewer.js +1 -1
  57. package/dist/types.d.ts +3 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/package.json +8 -3
  60. package/dist/pd-box-view/pd-box-view.stories.d.ts +0 -43
  61. package/dist/pd-box-view/pd-box-view.stories.d.ts.map +0 -1
  62. package/dist/pd-code-snippet/pd-code-snippet.stories.d.ts +0 -55
  63. package/dist/pd-code-snippet/pd-code-snippet.stories.d.ts.map +0 -1
  64. package/dist/pd-collapse/pd-collapse.stories.d.ts +0 -51
  65. package/dist/pd-collapse/pd-collapse.stories.d.ts.map +0 -1
  66. package/dist/pd-collapse-group/pd-collapse-group.stories.d.ts +0 -40
  67. package/dist/pd-collapse-group/pd-collapse-group.stories.d.ts.map +0 -1
  68. package/dist/pd-edit-content/pd-edit-content.stories.d.ts +0 -55
  69. package/dist/pd-edit-content/pd-edit-content.stories.d.ts.map +0 -1
  70. package/dist/pd-loading-state/pd-loading-state.stories.d.ts +0 -48
  71. package/dist/pd-loading-state/pd-loading-state.stories.d.ts.map +0 -1
  72. package/dist/pd-more-info/pd-more-info.stories.d.ts +0 -42
  73. package/dist/pd-more-info/pd-more-info.stories.d.ts.map +0 -1
  74. package/dist/pd-notice-box/pd-notice-box.stories.d.ts +0 -58
  75. package/dist/pd-notice-box/pd-notice-box.stories.d.ts.map +0 -1
  76. package/dist/pd-panel-viewer/pd-panel-viewer.stories.d.ts +0 -46
  77. package/dist/pd-panel-viewer/pd-panel-viewer.stories.d.ts.map +0 -1
  78. package/dist/pd-resize-content/pd-resize-content.stories.d.ts +0 -37
  79. package/dist/pd-resize-content/pd-resize-content.stories.d.ts.map +0 -1
  80. package/dist/pd-tab/pd-tab.stories.d.ts +0 -53
  81. package/dist/pd-tab/pd-tab.stories.d.ts.map +0 -1
  82. package/dist/pd-timeline/pd-timeline.stories.d.ts +0 -56
  83. package/dist/pd-timeline/pd-timeline.stories.d.ts.map +0 -1
  84. package/dist/pd-timeline-wizard/pd-timeline-wizard.stories.d.ts +0 -54
  85. package/dist/pd-timeline-wizard/pd-timeline-wizard.stories.d.ts.map +0 -1
@@ -0,0 +1,550 @@
1
+ import { css, nothing, html } from 'lit';
2
+ import { property, state, query } from 'lit/decorators.js';
3
+ import { classMap } from 'lit/directives/class-map.js';
4
+ import { PdBaseUIInput } from '@progressive-development/pd-forms';
5
+ import './pd-badge-item.js';
6
+ import { capturePositions, animateFlip } from './flip-animator.js';
7
+ import { DragController } from './DragController.js';
8
+
9
+ var __defProp = Object.defineProperty;
10
+ var __decorateClass = (decorators, target, key, kind) => {
11
+ var result = void 0 ;
12
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
13
+ if (decorator = decorators[i])
14
+ result = (decorator(target, key, result) ) || result;
15
+ if (result) __defProp(target, key, result);
16
+ return result;
17
+ };
18
+ const BADGE_SELECTOR = "pd-badge-item";
19
+ class PdBadgeOrder extends PdBaseUIInput {
20
+ constructor() {
21
+ super(...arguments);
22
+ this.badges = [];
23
+ this.numbered = true;
24
+ this.activeLabel = "Ausgewählt";
25
+ this.availableLabel = "Verfügbar";
26
+ this.emptyActiveText = "Badges hierher ziehen";
27
+ this.emptyAvailableText = "Keine weiteren Badges";
28
+ this._dragController = new DragController(this);
29
+ /** Positions captured before DOM change for FLIP animation */
30
+ this._oldPositions = null;
31
+ // ---------------------------------------------------------------------------
32
+ // Event handlers
33
+ // ---------------------------------------------------------------------------
34
+ this._onBadgeAction = (e) => {
35
+ const { action, badgeId } = e.detail;
36
+ switch (action) {
37
+ case "add":
38
+ this._addBadge(badgeId);
39
+ break;
40
+ case "remove":
41
+ this._removeBadge(badgeId);
42
+ break;
43
+ case "delete":
44
+ this._deleteBadge(badgeId);
45
+ break;
46
+ }
47
+ };
48
+ }
49
+ static {
50
+ this.styles = [
51
+ PdBaseUIInput.styles,
52
+ css`
53
+ :host {
54
+ display: block;
55
+ --pd-input-field-width: 100%;
56
+ }
57
+
58
+ .badge-order-container {
59
+ display: grid;
60
+ grid-template-columns: 1fr 1fr;
61
+ gap: var(--pd-badge-order-gap, 1rem);
62
+ width: 100%;
63
+ box-sizing: border-box;
64
+ }
65
+
66
+ .list-section {
67
+ display: flex;
68
+ flex-direction: column;
69
+ min-height: var(--pd-badge-order-min-height, 200px);
70
+ }
71
+
72
+ .section-header {
73
+ display: flex;
74
+ align-items: center;
75
+ justify-content: space-between;
76
+ padding: 0.5rem 0;
77
+ font-family: var(--pd-default-font-title-family, sans-serif);
78
+ font-size: 0.8rem;
79
+ font-weight: 600;
80
+ color: var(--pd-default-font-title-col, #374151);
81
+ }
82
+
83
+ .section-count {
84
+ font-weight: 400;
85
+ color: var(--pd-default-disabled-col, #9ca3af);
86
+ font-size: 0.75rem;
87
+ }
88
+
89
+ .badge-list {
90
+ display: flex;
91
+ flex-direction: column;
92
+ gap: 0.4rem;
93
+ flex: 1;
94
+ padding: 0.5rem;
95
+ border: 1px solid var(--pd-default-disabled-light-col, #e5e7eb);
96
+ border-radius: var(--pd-radius-md, 6px);
97
+ background: var(--pd-default-lightest-col, #fafafa);
98
+ overflow-y: auto;
99
+ position: relative;
100
+ transition: background-color 0.2s;
101
+ }
102
+
103
+ .badge-list.drag-over {
104
+ background: color-mix(
105
+ in srgb,
106
+ var(--pd-badge-drop-highlight, var(--pd-default-col, #3b82f6)) 8%,
107
+ var(--pd-default-lightest-col, #fafafa)
108
+ );
109
+ }
110
+
111
+ .empty-placeholder {
112
+ display: flex;
113
+ align-items: center;
114
+ justify-content: center;
115
+ flex: 1;
116
+ min-height: 80px;
117
+ color: var(--pd-default-disabled-col, #9ca3af);
118
+ font-size: 0.8rem;
119
+ font-style: italic;
120
+ text-align: center;
121
+ padding: 1rem;
122
+ }
123
+
124
+ .drop-indicator {
125
+ height: 2px;
126
+ background: var(
127
+ --pd-badge-drop-highlight,
128
+ var(--pd-default-col, #3b82f6)
129
+ );
130
+ border-radius: 1px;
131
+ transition: opacity 0.15s;
132
+ flex-shrink: 0;
133
+ }
134
+
135
+ /* Ghost element for drag */
136
+ .drag-ghost {
137
+ position: fixed;
138
+ pointer-events: none;
139
+ z-index: 9999;
140
+ opacity: 0.9;
141
+ transform: scale(var(--pd-badge-drag-scale, 1.03));
142
+ box-shadow: var(--pd-badge-drag-shadow, 0 8px 24px rgba(0, 0, 0, 0.15));
143
+ will-change: transform;
144
+ width: var(--_ghost-width, 300px);
145
+ }
146
+
147
+ /* Disabled state */
148
+ :host([disabled]) .badge-order-container {
149
+ opacity: 0.5;
150
+ pointer-events: none;
151
+ }
152
+
153
+ :host([readonly]) .badge-order-container {
154
+ pointer-events: none;
155
+ }
156
+
157
+ /* Mobile: stacked layout, available on top */
158
+ @media (max-width: 767px) {
159
+ .badge-order-container {
160
+ grid-template-columns: 1fr;
161
+ }
162
+
163
+ .list-section.available-section {
164
+ order: -1;
165
+ }
166
+ }
167
+ `
168
+ ];
169
+ }
170
+ // ---------------------------------------------------------------------------
171
+ // AI adoption: supports enriched format { value: string[], badges: PdBadge[] }
172
+ // ---------------------------------------------------------------------------
173
+ aiAdopt(value) {
174
+ try {
175
+ const parsed = JSON.parse(value);
176
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && Array.isArray(parsed.value)) {
177
+ if (Array.isArray(parsed.badges) && parsed.badges.length > 0) {
178
+ const existingMap = new Map(this.badges.map((b) => [b.id, b]));
179
+ for (const badge of parsed.badges) {
180
+ existingMap.set(badge.id, badge);
181
+ }
182
+ this.badges = [...existingMap.values()];
183
+ }
184
+ this.value = parsed.value;
185
+ this._fireChangeEvents();
186
+ return;
187
+ }
188
+ } catch {
189
+ }
190
+ super.aiAdopt(value);
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // Value handling: string[] serialized as JSON string
194
+ // ---------------------------------------------------------------------------
195
+ /** @ts-expect-error Widening return type from string to string[] */
196
+ get value() {
197
+ try {
198
+ const parsed = JSON.parse(this._value);
199
+ return Array.isArray(parsed) ? parsed : [];
200
+ } catch {
201
+ return [];
202
+ }
203
+ }
204
+ /** @ts-expect-error Widening param type from string to string[] | string */
205
+ set value(val) {
206
+ const ids = Array.isArray(val) ? val : typeof val === "string" && val.startsWith("[") ? JSON.parse(val) : [];
207
+ const jsonVal = JSON.stringify(ids);
208
+ if (this._value !== jsonVal) {
209
+ this._handleChangedValue(jsonVal, void 0, true);
210
+ }
211
+ }
212
+ _getParsedValue() {
213
+ return this.value;
214
+ }
215
+ _getInitialValue(reset) {
216
+ return reset ? this.initValue || "[]" : this.initValue || this._value || "[]";
217
+ }
218
+ // ---------------------------------------------------------------------------
219
+ // Validators
220
+ // ---------------------------------------------------------------------------
221
+ connectedCallback() {
222
+ super.connectedCallback();
223
+ this._setupValidators();
224
+ }
225
+ _setupValidators() {
226
+ this._validators = [];
227
+ const requiredBadgeValidator = (val) => {
228
+ if (!this.required) return null;
229
+ try {
230
+ const ids = JSON.parse(val);
231
+ return Array.isArray(ids) && ids.length === 0 ? "Mindestens eine Badge auswählen" : null;
232
+ } catch {
233
+ return "Mindestens eine Badge auswählen";
234
+ }
235
+ };
236
+ const minValidator = (val) => {
237
+ if (this.min === void 0) return null;
238
+ try {
239
+ const ids = JSON.parse(val);
240
+ return Array.isArray(ids) && ids.length < this.min ? `Mindestens ${this.min} Badges auswählen` : null;
241
+ } catch {
242
+ return null;
243
+ }
244
+ };
245
+ const maxValidator = (val) => {
246
+ if (this.max === void 0) return null;
247
+ try {
248
+ const ids = JSON.parse(val);
249
+ return Array.isArray(ids) && ids.length > this.max ? `Maximal ${this.max} Badges erlaubt` : null;
250
+ } catch {
251
+ return null;
252
+ }
253
+ };
254
+ this._validators.push(requiredBadgeValidator, minValidator, maxValidator);
255
+ }
256
+ // ---------------------------------------------------------------------------
257
+ // Computed properties
258
+ // ---------------------------------------------------------------------------
259
+ get _activeBadges() {
260
+ const ids = this.value;
261
+ const badgeMap = new Map(this.badges.map((b) => [b.id, b]));
262
+ return ids.map((id) => badgeMap.get(id)).filter((b) => !!b);
263
+ }
264
+ get _availableBadges() {
265
+ const activeIds = new Set(this.value);
266
+ return this.badges.filter((b) => !activeIds.has(b.id));
267
+ }
268
+ // ---------------------------------------------------------------------------
269
+ // Actions
270
+ // ---------------------------------------------------------------------------
271
+ _captureBeforeChange() {
272
+ if (this._activeListEl) {
273
+ this._oldPositions = capturePositions(this._activeListEl, BADGE_SELECTOR);
274
+ }
275
+ if (this._availableListEl) {
276
+ const availPositions = capturePositions(
277
+ this._availableListEl,
278
+ BADGE_SELECTOR
279
+ );
280
+ if (this._oldPositions) {
281
+ availPositions.forEach(
282
+ (rect, key) => this._oldPositions.set(key, rect)
283
+ );
284
+ } else {
285
+ this._oldPositions = availPositions;
286
+ }
287
+ }
288
+ }
289
+ _addBadge(badgeId) {
290
+ if (this.disabled || this.readonly) return;
291
+ const ids = this.value;
292
+ if (ids.includes(badgeId)) return;
293
+ if (this.max !== void 0 && ids.length >= this.max) return;
294
+ this._captureBeforeChange();
295
+ this.value = [...ids, badgeId];
296
+ this._fireChangeEvents();
297
+ }
298
+ _removeBadge(badgeId) {
299
+ if (this.disabled || this.readonly) return;
300
+ const ids = this.value;
301
+ this._captureBeforeChange();
302
+ this.value = ids.filter((id) => id !== badgeId);
303
+ this._fireChangeEvents();
304
+ }
305
+ _deleteBadge(badgeId) {
306
+ if (this.disabled || this.readonly) return;
307
+ const badge = this.badges.find((b) => b.id === badgeId);
308
+ if (!badge?.custom) return;
309
+ this._captureBeforeChange();
310
+ const ids = this.value;
311
+ if (ids.includes(badgeId)) {
312
+ this.value = ids.filter((id) => id !== badgeId);
313
+ }
314
+ this.badges = this.badges.filter((b) => b.id !== badgeId);
315
+ this.dispatchEvent(
316
+ new CustomEvent("pd-badge-deleted", {
317
+ detail: { badge },
318
+ bubbles: true,
319
+ composed: true
320
+ })
321
+ );
322
+ this._fireChangeEvents();
323
+ }
324
+ /** Reorder: move badge from oldIndex to newIndex within active list */
325
+ reorderBadge(oldIndex, newIndex) {
326
+ const ids = [...this.value];
327
+ if (oldIndex < 0 || oldIndex >= ids.length || newIndex < 0 || newIndex >= ids.length)
328
+ return;
329
+ this._captureBeforeChange();
330
+ const [moved] = ids.splice(oldIndex, 1);
331
+ ids.splice(newIndex, 0, moved);
332
+ this.value = ids;
333
+ this.dispatchEvent(
334
+ new CustomEvent("pd-reorder", {
335
+ detail: { value: ids },
336
+ bubbles: true,
337
+ composed: true
338
+ })
339
+ );
340
+ this._fireChangeEvents();
341
+ }
342
+ /** Insert a badge from available into active list at a specific index */
343
+ insertBadgeAt(badgeId, index) {
344
+ if (this.disabled || this.readonly) return;
345
+ const ids = this.value;
346
+ if (ids.includes(badgeId)) return;
347
+ if (this.max !== void 0 && ids.length >= this.max) return;
348
+ this._captureBeforeChange();
349
+ const newIds = [...ids];
350
+ const insertIdx = Math.max(0, Math.min(index, newIds.length));
351
+ newIds.splice(insertIdx, 0, badgeId);
352
+ this.value = newIds;
353
+ this._fireChangeEvents();
354
+ }
355
+ /** Move a badge from active to available (at drop) */
356
+ deactivateBadge(badgeId) {
357
+ this._removeBadge(badgeId);
358
+ }
359
+ _fireChangeEvents() {
360
+ const detail = {
361
+ value: this.value,
362
+ badges: this.badges
363
+ };
364
+ this.dispatchEvent(
365
+ new CustomEvent("pd-change", {
366
+ detail,
367
+ bubbles: true,
368
+ composed: true
369
+ })
370
+ );
371
+ }
372
+ // ---------------------------------------------------------------------------
373
+ // Lifecycle
374
+ // ---------------------------------------------------------------------------
375
+ updated(changedProps) {
376
+ super.updated(changedProps);
377
+ if (this._oldPositions) {
378
+ const oldPos = this._oldPositions;
379
+ this._oldPositions = null;
380
+ requestAnimationFrame(() => {
381
+ if (this._activeListEl) {
382
+ animateFlip(this._activeListEl, BADGE_SELECTOR, oldPos);
383
+ }
384
+ if (this._availableListEl) {
385
+ animateFlip(this._availableListEl, BADGE_SELECTOR, oldPos);
386
+ }
387
+ });
388
+ }
389
+ }
390
+ // ---------------------------------------------------------------------------
391
+ // Render
392
+ // ---------------------------------------------------------------------------
393
+ render() {
394
+ const activeBadges = this._activeBadges;
395
+ const availableBadges = this._availableBadges;
396
+ const drag = this._dragController;
397
+ return html`
398
+ ${this._renderLabel("badge-order")}
399
+
400
+ <div
401
+ class="badge-order-container"
402
+ part="container"
403
+ @badge-action=${this._onBadgeAction}
404
+ >
405
+ <!-- Active list -->
406
+ <div class="list-section active-section">
407
+ <div class="section-header">
408
+ <span>
409
+ <slot name="active-header">${this.activeLabel}</slot>
410
+ <span class="section-count">(${activeBadges.length})</span>
411
+ </span>
412
+ </div>
413
+ <div
414
+ id="active-list"
415
+ class=${classMap({
416
+ "badge-list": true,
417
+ "drag-over": drag.isDragging && drag.dropTarget === "active"
418
+ })}
419
+ part="active-list"
420
+ role="listbox"
421
+ aria-label="${this.activeLabel} (${activeBadges.length})"
422
+ data-area="active"
423
+ @pointerdown=${drag.onPointerDown}
424
+ >
425
+ ${activeBadges.length > 0 ? activeBadges.map(
426
+ (badge, i) => html`
427
+ ${drag.isDragging && drag.dropTarget === "active" && drag.insertIndex === i ? html`<div class="drop-indicator"></div>` : nothing}
428
+ <pd-badge-item
429
+ .badge=${badge}
430
+ .index=${i + 1}
431
+ ?numbered=${this.numbered}
432
+ ?active=${true}
433
+ ?disabled=${this.disabled}
434
+ ?readonly=${this.readonly}
435
+ ?ghost=${drag.isDragging && drag.draggedId === badge.id}
436
+ data-badge-id=${badge.id}
437
+ role="option"
438
+ aria-label="${badge.title}, Position ${i + 1}"
439
+ ></pd-badge-item>
440
+ `
441
+ ) : html`
442
+ <div class="empty-placeholder">
443
+ <slot name="empty-active">${this.emptyActiveText}</slot>
444
+ </div>
445
+ `}
446
+ ${drag.isDragging && drag.dropTarget === "active" && drag.insertIndex === activeBadges.length ? html`<div class="drop-indicator"></div>` : nothing}
447
+ </div>
448
+ </div>
449
+
450
+ <!-- Available list -->
451
+ <div class="list-section available-section">
452
+ <div class="section-header">
453
+ <span>
454
+ <slot name="available-header">${this.availableLabel}</slot>
455
+ <span class="section-count">(${availableBadges.length})</span>
456
+ </span>
457
+ </div>
458
+ <div
459
+ id="available-list"
460
+ class=${classMap({
461
+ "badge-list": true,
462
+ "drag-over": drag.isDragging && drag.dropTarget === "available"
463
+ })}
464
+ part="available-list"
465
+ role="listbox"
466
+ aria-label="${this.availableLabel} (${availableBadges.length})"
467
+ data-area="available"
468
+ >
469
+ ${availableBadges.length > 0 ? availableBadges.map(
470
+ (badge) => html`
471
+ <pd-badge-item
472
+ .badge=${badge}
473
+ ?disabled=${this.disabled}
474
+ ?readonly=${this.readonly}
475
+ data-badge-id=${badge.id}
476
+ role="option"
477
+ aria-label="${badge.title}"
478
+ ></pd-badge-item>
479
+ `
480
+ ) : html`
481
+ <div class="empty-placeholder">
482
+ <slot name="empty-available"
483
+ >${this.emptyAvailableText}</slot
484
+ >
485
+ </div>
486
+ `}
487
+ </div>
488
+ </div>
489
+ </div>
490
+
491
+ ${this._renderGhost()} ${this._renderErrorMsg()}
492
+ `;
493
+ }
494
+ _renderGhost() {
495
+ const drag = this._dragController;
496
+ if (!drag.isDragging || !drag.draggedId) return nothing;
497
+ const badge = this.badges.find((b) => b.id === drag.draggedId);
498
+ if (!badge) return nothing;
499
+ const idx = this.value.indexOf(drag.draggedId);
500
+ return html`
501
+ <div
502
+ class="drag-ghost"
503
+ style="left: ${drag.ghostX}px; top: ${drag.ghostY}px;"
504
+ >
505
+ <pd-badge-item
506
+ .badge=${badge}
507
+ .index=${idx >= 0 ? idx + 1 : 0}
508
+ ?numbered=${this.numbered && idx >= 0}
509
+ ?active=${idx >= 0}
510
+ ?dragging=${true}
511
+ ></pd-badge-item>
512
+ </div>
513
+ `;
514
+ }
515
+ }
516
+ __decorateClass([
517
+ property({ type: Array, attribute: false })
518
+ ], PdBadgeOrder.prototype, "badges");
519
+ __decorateClass([
520
+ property({ type: Number })
521
+ ], PdBadgeOrder.prototype, "min");
522
+ __decorateClass([
523
+ property({ type: Number })
524
+ ], PdBadgeOrder.prototype, "max");
525
+ __decorateClass([
526
+ property({ type: Boolean })
527
+ ], PdBadgeOrder.prototype, "numbered");
528
+ __decorateClass([
529
+ property({ type: String })
530
+ ], PdBadgeOrder.prototype, "activeLabel");
531
+ __decorateClass([
532
+ property({ type: String })
533
+ ], PdBadgeOrder.prototype, "availableLabel");
534
+ __decorateClass([
535
+ property({ type: String })
536
+ ], PdBadgeOrder.prototype, "emptyActiveText");
537
+ __decorateClass([
538
+ property({ type: String })
539
+ ], PdBadgeOrder.prototype, "emptyAvailableText");
540
+ __decorateClass([
541
+ state()
542
+ ], PdBadgeOrder.prototype, "_dragController");
543
+ __decorateClass([
544
+ query("#active-list")
545
+ ], PdBadgeOrder.prototype, "_activeListEl");
546
+ __decorateClass([
547
+ query("#available-list")
548
+ ], PdBadgeOrder.prototype, "_availableListEl");
549
+
550
+ export { PdBadgeOrder };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * FLIP animation utility for smooth badge reordering.
3
+ *
4
+ * FLIP = First, Last, Invert, Play
5
+ * 1. First: Capture positions before DOM change (capturePositions)
6
+ * 2. Last: DOM change happens (Lit re-render)
7
+ * 3. Invert: Calculate deltas, apply inverse transform
8
+ * 4. Play: Animate transform back to none
9
+ */
10
+ /**
11
+ * Capture current positions of all matching elements in a container.
12
+ * Call this BEFORE the DOM change.
13
+ *
14
+ * @returns Map of badge-id → DOMRect
15
+ */
16
+ export declare function capturePositions(container: HTMLElement, selector: string): Map<string, DOMRect>;
17
+ /**
18
+ * Animate elements from their old positions to their new positions using FLIP.
19
+ * Call this AFTER the DOM change (e.g., in updated() or requestAnimationFrame).
20
+ *
21
+ * @param container - The container element holding the badges
22
+ * @param selector - CSS selector for badge elements
23
+ * @param oldPositions - Positions captured before the DOM change
24
+ * @param options - Animation options
25
+ */
26
+ export declare function animateFlip(container: HTMLElement, selector: string, oldPositions: Map<string, DOMRect>, options?: {
27
+ duration?: number;
28
+ easing?: string;
29
+ }): void;
30
+ //# sourceMappingURL=flip-animator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flip-animator.d.ts","sourceRoot":"","sources":["../../src/pd-badge-order/flip-animator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,MAAM,GACf,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAYtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACZ,GACL,IAAI,CAkCN"}
@@ -0,0 +1,39 @@
1
+ function capturePositions(container, selector) {
2
+ const positions = /* @__PURE__ */ new Map();
3
+ const elements = container.querySelectorAll(selector);
4
+ elements.forEach((el) => {
5
+ const id = el.dataset.badgeId;
6
+ if (id) {
7
+ positions.set(id, el.getBoundingClientRect());
8
+ }
9
+ });
10
+ return positions;
11
+ }
12
+ function animateFlip(container, selector, oldPositions, options = {}) {
13
+ const { duration = 200, easing = "ease-in-out" } = options;
14
+ const elements = container.querySelectorAll(selector);
15
+ elements.forEach((el) => {
16
+ const htmlEl = el;
17
+ const id = htmlEl.dataset.badgeId;
18
+ if (!id) return;
19
+ const oldPos = oldPositions.get(id);
20
+ if (!oldPos) return;
21
+ const newPos = htmlEl.getBoundingClientRect();
22
+ const deltaX = oldPos.left - newPos.left;
23
+ const deltaY = oldPos.top - newPos.top;
24
+ if (Math.abs(deltaX) < 1 && Math.abs(deltaY) < 1) return;
25
+ htmlEl.animate(
26
+ [
27
+ { transform: `translate(${deltaX}px, ${deltaY}px)` },
28
+ { transform: "translate(0, 0)" }
29
+ ],
30
+ {
31
+ duration,
32
+ easing,
33
+ fill: "none"
34
+ }
35
+ );
36
+ });
37
+ }
38
+
39
+ export { animateFlip, capturePositions };
@@ -0,0 +1,3 @@
1
+ import { PdBadgeItem } from './PdBadgeItem.js';
2
+ export { PdBadgeItem };
3
+ //# sourceMappingURL=pd-badge-item.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-badge-item.d.ts","sourceRoot":"","sources":["../../src/pd-badge-order/pd-badge-item.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAO/C,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { PdBadgeItem } from './PdBadgeItem.js';
2
+
3
+ const tag = "pd-badge-item";
4
+ if (!customElements.get(tag)) {
5
+ customElements.define(tag, PdBadgeItem);
6
+ }
7
+
8
+ export { PdBadgeItem };
@@ -0,0 +1,3 @@
1
+ import { PdBadgeOrder } from './PdBadgeOrder.js';
2
+ export { PdBadgeOrder };
3
+ //# sourceMappingURL=pd-badge-order.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pd-badge-order.d.ts","sourceRoot":"","sources":["../../src/pd-badge-order/pd-badge-order.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAOjD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface PdBadge {
2
+ /** Unique badge ID */
3
+ id: string;
4
+ /** Display title (max TEXT_LIMIT_TITLE characters) */
5
+ title: string;
6
+ /** Optional description below title (max TEXT_LIMIT_DESC characters) */
7
+ description?: string;
8
+ /** Optional color (hex or CSS color name) */
9
+ color?: string;
10
+ /** Optional icon name from pd-icon library */
11
+ icon?: string;
12
+ /** Marks user-created badges (only these are deletable) */
13
+ custom?: boolean;
14
+ }
15
+ export interface PdBadgeChangeDetail {
16
+ value: string[];
17
+ badges: PdBadge[];
18
+ }
19
+ export interface PdBadgeReorderDetail {
20
+ value: string[];
21
+ }
22
+ export declare const TEXT_LIMIT_TITLE = 40;
23
+ export declare const TEXT_LIMIT_DESC = 100;
24
+ export declare const DEFAULT_BADGE_COLOR = "#9E9E9E";
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/pd-badge-order/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,eAAO,MAAM,mBAAmB,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ const DEFAULT_BADGE_COLOR = "#9E9E9E";
2
+
3
+ export { DEFAULT_BADGE_COLOR };
@@ -0,0 +1,2 @@
1
+ export * from './pd-badge-order/pd-badge-order'
2
+ export {}