@progressive-development/pd-content 1.0.3 → 1.1.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 (84) hide show
  1. package/dist/index.d.ts +2 -4
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +0 -4
  4. package/dist/node_modules/.pnpm/@codemirror_autocomplete@6.20.1/node_modules/@codemirror/autocomplete/dist/index.js +550 -0
  5. package/dist/node_modules/.pnpm/@codemirror_lang-css@6.3.1/node_modules/@codemirror/lang-css/dist/index.js +264 -0
  6. package/dist/node_modules/.pnpm/@codemirror_lang-html@6.4.11/node_modules/@codemirror/lang-html/dist/index.js +661 -0
  7. package/dist/node_modules/.pnpm/@codemirror_lang-java@6.0.2/node_modules/@codemirror/lang-java/dist/index.js +44 -0
  8. package/dist/node_modules/.pnpm/@codemirror_lang-javascript@6.2.5/node_modules/@codemirror/lang-javascript/dist/index.js +346 -0
  9. package/dist/node_modules/.pnpm/@codemirror_lang-json@6.0.2/node_modules/@codemirror/lang-json/dist/index.js +32 -0
  10. package/dist/node_modules/.pnpm/@codemirror_lang-markdown@6.5.0/node_modules/@codemirror/lang-markdown/dist/index.js +492 -0
  11. package/dist/node_modules/.pnpm/@codemirror_lang-python@6.2.1/node_modules/@codemirror/lang-python/dist/index.js +308 -0
  12. package/dist/node_modules/.pnpm/@codemirror_language@6.12.3/node_modules/@codemirror/language/dist/index.js +1572 -0
  13. package/dist/node_modules/.pnpm/@codemirror_state@6.6.0/node_modules/@codemirror/state/dist/index.js +3881 -0
  14. package/dist/node_modules/.pnpm/@codemirror_view@6.40.0/node_modules/@codemirror/view/dist/index.js +9657 -0
  15. package/dist/node_modules/.pnpm/@lezer_common@1.5.1/node_modules/@lezer/common/dist/index.js +2196 -0
  16. package/dist/node_modules/.pnpm/@lezer_css@1.3.3/node_modules/@lezer/css/dist/index.js +147 -0
  17. package/dist/node_modules/.pnpm/@lezer_highlight@1.2.3/node_modules/@lezer/highlight/dist/index.js +898 -0
  18. package/dist/node_modules/.pnpm/@lezer_html@1.3.13/node_modules/@lezer/html/dist/index.js +349 -0
  19. package/dist/node_modules/.pnpm/@lezer_java@1.1.3/node_modules/@lezer/java/dist/index.js +67 -0
  20. package/dist/node_modules/.pnpm/@lezer_javascript@1.5.4/node_modules/@lezer/javascript/dist/index.js +192 -0
  21. package/dist/node_modules/.pnpm/@lezer_json@1.0.3/node_modules/@lezer/json/dist/index.js +37 -0
  22. package/dist/node_modules/.pnpm/@lezer_lr@1.4.8/node_modules/@lezer/lr/dist/index.js +1884 -0
  23. package/dist/node_modules/.pnpm/@lezer_markdown@1.6.3/node_modules/@lezer/markdown/dist/index.js +2335 -0
  24. package/dist/node_modules/.pnpm/@lezer_python@1.1.18/node_modules/@lezer/python/dist/index.js +326 -0
  25. package/dist/node_modules/.pnpm/@marijn_find-cluster-break@1.0.2/node_modules/@marijn/find-cluster-break/src/index.js +82 -0
  26. package/dist/node_modules/.pnpm/style-mod@4.1.3/node_modules/style-mod/src/style-mod.js +174 -0
  27. package/dist/node_modules/.pnpm/w3c-keyname@2.2.8/node_modules/w3c-keyname/index.js +121 -0
  28. package/dist/pd-badge-order/PdBadgeItem.d.ts +11 -0
  29. package/dist/pd-badge-order/PdBadgeItem.d.ts.map +1 -1
  30. package/dist/pd-badge-order/PdBadgeItem.js +162 -10
  31. package/dist/pd-badge-order/PdBadgeOrder.d.ts +56 -17
  32. package/dist/pd-badge-order/PdBadgeOrder.d.ts.map +1 -1
  33. package/dist/pd-badge-order/PdBadgeOrder.js +308 -153
  34. package/dist/pd-badge-order/types.js +3 -1
  35. package/dist/pd-code-snippet/PdCodeSnippet.d.ts +29 -0
  36. package/dist/pd-code-snippet/PdCodeSnippet.d.ts.map +1 -1
  37. package/dist/pd-code-snippet/PdCodeSnippet.js +117 -67
  38. package/dist/pd-code-snippet/codemirror-setup.d.ts +10 -0
  39. package/dist/pd-code-snippet/codemirror-setup.d.ts.map +1 -0
  40. package/dist/pd-code-snippet/codemirror-setup.js +101 -0
  41. package/dist/pd-loading-state/PdLoadingState.d.ts +4 -1
  42. package/dist/pd-loading-state/PdLoadingState.d.ts.map +1 -1
  43. package/dist/pd-loading-state/pd-loading-state.d.ts +1 -1
  44. package/dist/pd-loading-state/pd-loading-state.d.ts.map +1 -1
  45. package/dist/pd-loading-state/pd-logo-loader.js +2 -2
  46. package/dist/pd-more-info/PdMoreInfo.d.ts +52 -4
  47. package/dist/pd-more-info/PdMoreInfo.d.ts.map +1 -1
  48. package/dist/pd-more-info/PdMoreInfo.js +146 -24
  49. package/dist/pd-notice-box/PdNoticeBox.d.ts +8 -1
  50. package/dist/pd-notice-box/PdNoticeBox.d.ts.map +1 -1
  51. package/dist/pd-notice-box/PdNoticeBox.js +41 -2
  52. package/dist/pd-panel-viewer/PdPanel.d.ts +3 -0
  53. package/dist/pd-panel-viewer/PdPanel.d.ts.map +1 -1
  54. package/dist/pd-panel-viewer/PdPanel.js +8 -1
  55. package/dist/pd-panel-viewer/PdPanelViewer.d.ts +3 -0
  56. package/dist/pd-panel-viewer/PdPanelViewer.d.ts.map +1 -1
  57. package/dist/pd-panel-viewer/PdPanelViewer.js +59 -26
  58. package/dist/pd-tab/PdTab.d.ts +8 -5
  59. package/dist/pd-tab/PdTab.d.ts.map +1 -1
  60. package/dist/pd-tab/PdTab.js +110 -56
  61. package/dist/pd-timeline/PdTimeline.d.ts +2 -0
  62. package/dist/pd-timeline/PdTimeline.d.ts.map +1 -1
  63. package/dist/pd-timeline/PdTimeline.js +50 -19
  64. package/dist/types.d.ts +2 -2
  65. package/dist/types.d.ts.map +1 -1
  66. package/package.json +16 -8
  67. package/dist/pd-gallery/PdGallery.d.ts +0 -72
  68. package/dist/pd-gallery/PdGallery.d.ts.map +0 -1
  69. package/dist/pd-gallery/PdGallery.js +0 -660
  70. package/dist/pd-gallery/PdGalleryLightbox.d.ts +0 -53
  71. package/dist/pd-gallery/PdGalleryLightbox.d.ts.map +0 -1
  72. package/dist/pd-gallery/PdGalleryLightbox.js +0 -530
  73. package/dist/pd-gallery/index.d.ts +0 -4
  74. package/dist/pd-gallery/index.d.ts.map +0 -1
  75. package/dist/pd-gallery/pd-gallery-lightbox.d.ts +0 -3
  76. package/dist/pd-gallery/pd-gallery-lightbox.d.ts.map +0 -1
  77. package/dist/pd-gallery/pd-gallery.d.ts +0 -3
  78. package/dist/pd-gallery/pd-gallery.d.ts.map +0 -1
  79. package/dist/pd-gallery/types.d.ts +0 -23
  80. package/dist/pd-gallery/types.d.ts.map +0 -1
  81. package/dist/pd-gallery-lightbox.d.ts +0 -2
  82. package/dist/pd-gallery-lightbox.js +0 -8
  83. package/dist/pd-gallery.d.ts +0 -2
  84. package/dist/pd-gallery.js +0 -8
@@ -1,9 +1,11 @@
1
- import { css, nothing, html } from 'lit';
1
+ import { LitElement, css, nothing, html } from 'lit';
2
2
  import { property, state, query } from 'lit/decorators.js';
3
3
  import { classMap } from 'lit/directives/class-map.js';
4
- import { PdBaseUIInput } from '@progressive-development/pd-forms';
4
+ import '@progressive-development/pd-forms/pd-button';
5
+ import { pdIcons } from '@progressive-development/pd-icon';
6
+ import '@progressive-development/pd-icon/pd-icon';
5
7
  import './pd-badge-item.js';
6
- import { capturePositions, animateFlip } from './flip-animator.js';
8
+ import { animateFlip, capturePositions } from './flip-animator.js';
7
9
  import { DragController } from './DragController.js';
8
10
 
9
11
  var __defProp = Object.defineProperty;
@@ -16,21 +18,32 @@ var __decorateClass = (decorators, target, key, kind) => {
16
18
  return result;
17
19
  };
18
20
  const BADGE_SELECTOR = "pd-badge-item";
19
- class PdBadgeOrder extends PdBaseUIInput {
21
+ class PdBadgeOrder extends LitElement {
20
22
  constructor() {
21
23
  super(...arguments);
22
- this.badges = [];
24
+ this.label = "";
25
+ this.valueName = "";
23
26
  this.numbered = true;
24
27
  this.activeLabel = "Ausgewählt";
25
28
  this.availableLabel = "Verfügbar";
26
29
  this.emptyActiveText = "Badges hierher ziehen";
27
30
  this.emptyAvailableText = "Keine weiteren Badges";
31
+ this.editable = "";
32
+ this.creatable = "";
33
+ this.required = false;
34
+ this.disabled = false;
35
+ this.readonly = false;
36
+ this._badges = [];
37
+ this._activeIds = [];
38
+ /** Whether initial data has been applied. */
39
+ this._initialized = false;
40
+ this._error = "";
28
41
  this._dragController = new DragController(this);
42
+ /** Badge ID that should auto-enter edit mode after next render. */
43
+ this._autoEditBadgeId = "";
29
44
  /** Positions captured before DOM change for FLIP animation */
30
45
  this._oldPositions = null;
31
- // ---------------------------------------------------------------------------
32
- // Event handlers
33
- // ---------------------------------------------------------------------------
46
+ // ── Event handlers ────────────────────────────────────────────────────────
34
47
  this._onBadgeAction = (e) => {
35
48
  const { action, badgeId } = e.detail;
36
49
  switch (action) {
@@ -43,18 +56,95 @@ class PdBadgeOrder extends PdBaseUIInput {
43
56
  case "delete":
44
57
  this._deleteBadge(badgeId);
45
58
  break;
59
+ case "edit-save":
60
+ this._editBadge(
61
+ badgeId,
62
+ e.detail.title,
63
+ e.detail.description
64
+ );
65
+ break;
46
66
  }
47
67
  };
48
68
  }
69
+ // ── Public API ────────────────────────────────────────────────────────────
70
+ /** Current active IDs (read-only). */
71
+ get value() {
72
+ return this._activeIds;
73
+ }
74
+ /** Current badges (read-only). */
75
+ get badges() {
76
+ return this._badges;
77
+ }
78
+ /** Set badges and active IDs from outside. Marks as initialized. */
79
+ setBadges(badges, activeIds) {
80
+ this._badges = [...badges];
81
+ this._activeIds = [...activeIds];
82
+ this._initialized = true;
83
+ }
84
+ /** Reset to empty state. Allows initialBadges/initialValue to re-apply on next render. */
85
+ reset() {
86
+ this._badges = [];
87
+ this._activeIds = [];
88
+ this._initialized = false;
89
+ this._error = "";
90
+ }
91
+ /** Validate current state. Sets error message visible if invalid. Returns true if valid. */
92
+ validate() {
93
+ const count = this._activeIds.length;
94
+ if (this.required && count === 0) {
95
+ this._error = "Mindestens eine Badge auswählen";
96
+ return false;
97
+ }
98
+ if (this.min !== void 0 && count < this.min) {
99
+ this._error = `Mindestens ${this.min} Badges auswählen`;
100
+ return false;
101
+ }
102
+ if (this.max !== void 0 && count > this.max) {
103
+ this._error = `Maximal ${this.max} Badges erlaubt`;
104
+ return false;
105
+ }
106
+ this._error = "";
107
+ return true;
108
+ }
49
109
  static {
110
+ // ── Styles ────────────────────────────────────────────────────────────────
50
111
  this.styles = [
51
- PdBaseUIInput.styles,
52
112
  css`
53
113
  :host {
54
114
  display: block;
55
115
  --pd-input-field-width: 100%;
56
116
  }
57
117
 
118
+ .label-header {
119
+ display: flex;
120
+ align-items: end;
121
+ justify-content: space-between;
122
+ width: 100%;
123
+ box-sizing: border-box;
124
+ }
125
+
126
+ .label-header label {
127
+ font-size: var(--pd-input-label-font-size, 0.9em);
128
+ color: var(--pd-input-label-col, inherit);
129
+ }
130
+
131
+ .label-icons {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 4px;
135
+ }
136
+
137
+ .ai-trigger {
138
+ --pd-icon-size: 22px;
139
+ cursor: pointer;
140
+ opacity: 0.7;
141
+ transition: opacity 0.2s;
142
+ }
143
+ .ai-trigger:hover,
144
+ .ai-trigger:focus-visible {
145
+ opacity: 1;
146
+ }
147
+
58
148
  .badge-order-container {
59
149
  display: grid;
60
150
  grid-template-columns: 1fr 1fr;
@@ -73,7 +163,8 @@ class PdBadgeOrder extends PdBaseUIInput {
73
163
  display: flex;
74
164
  align-items: center;
75
165
  justify-content: space-between;
76
- padding: 0.5rem 0;
166
+ min-height: 2rem;
167
+ padding: 0.25rem 0;
77
168
  font-family: var(--pd-default-font-title-family, sans-serif);
78
169
  font-size: 0.8rem;
79
170
  font-weight: 600;
@@ -132,7 +223,6 @@ class PdBadgeOrder extends PdBaseUIInput {
132
223
  flex-shrink: 0;
133
224
  }
134
225
 
135
- /* Ghost element for drag */
136
226
  .drag-ghost {
137
227
  position: fixed;
138
228
  pointer-events: none;
@@ -144,7 +234,6 @@ class PdBadgeOrder extends PdBaseUIInput {
144
234
  width: var(--_ghost-width, 300px);
145
235
  }
146
236
 
147
- /* Disabled state */
148
237
  :host([disabled]) .badge-order-container {
149
238
  opacity: 0.5;
150
239
  pointer-events: none;
@@ -154,12 +243,27 @@ class PdBadgeOrder extends PdBaseUIInput {
154
243
  pointer-events: none;
155
244
  }
156
245
 
157
- /* Mobile: stacked layout, available on top */
246
+ .error-box {
247
+ display: block;
248
+ color: var(--pd-default-error-col, #dc2626);
249
+ background: var(--pd-default-error-light-col, #fef2f2);
250
+ border: 1px solid var(--pd-default-error-col, #dc2626);
251
+ border-radius: var(--pd-radius-md, 6px);
252
+ width: 100%;
253
+ box-sizing: border-box;
254
+ margin-top: 0.35rem;
255
+ }
256
+ .error-box p {
257
+ margin: 0;
258
+ padding: var(--pd-spacing-xs, 0.25rem) var(--pd-spacing-xs, 0.25rem)
259
+ var(--pd-spacing-xs, 0.25rem) var(--pd-spacing-sm, 0.5rem);
260
+ font-size: 0.8rem;
261
+ }
262
+
158
263
  @media (max-width: 767px) {
159
264
  .badge-order-container {
160
265
  grid-template-columns: 1fr;
161
266
  }
162
-
163
267
  .list-section.available-section {
164
268
  order: -1;
165
269
  }
@@ -167,107 +271,53 @@ class PdBadgeOrder extends PdBaseUIInput {
167
271
  `
168
272
  ];
169
273
  }
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;
274
+ // ── Lifecycle ─────────────────────────────────────────────────────────────
275
+ update(changedProps) {
276
+ if (!this._initialized) {
277
+ const hasBadges = changedProps.has("initialBadges") && this.initialBadges?.length;
278
+ const hasValue = changedProps.has("initialValue") && this.initialValue?.length;
279
+ if (hasBadges || hasValue) {
280
+ this._badges = [...this.initialBadges ?? []];
281
+ this._activeIds = [...this.initialValue ?? []];
282
+ this._initialized = true;
187
283
  }
188
- } catch {
189
284
  }
190
- super.aiAdopt(value);
285
+ super.update(changedProps);
191
286
  }
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 [];
287
+ updated(changedProps) {
288
+ super.updated(changedProps);
289
+ if (this._oldPositions) {
290
+ const oldPos = this._oldPositions;
291
+ this._oldPositions = null;
292
+ requestAnimationFrame(() => {
293
+ if (this._activeListEl) {
294
+ animateFlip(this._activeListEl, BADGE_SELECTOR, oldPos);
295
+ }
296
+ if (this._availableListEl) {
297
+ animateFlip(this._availableListEl, BADGE_SELECTOR, oldPos);
298
+ }
299
+ });
202
300
  }
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);
301
+ if (this._autoEditBadgeId) {
302
+ const id = this._autoEditBadgeId;
303
+ this._autoEditBadgeId = "";
304
+ requestAnimationFrame(() => {
305
+ const selector = `pd-badge-item[data-badge-id="${id}"]`;
306
+ const item = this._activeListEl?.querySelector(selector) || this._availableListEl?.querySelector(selector);
307
+ item?.startEditing();
308
+ });
210
309
  }
211
310
  }
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
- // ---------------------------------------------------------------------------
311
+ // ── Computed ──────────────────────────────────────────────────────────────
259
312
  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);
313
+ const badgeMap = new Map(this._badges.map((b) => [b.id, b]));
314
+ return this._activeIds.map((id) => badgeMap.get(id)).filter((b) => !!b);
263
315
  }
264
316
  get _availableBadges() {
265
- const activeIds = new Set(this.value);
266
- return this.badges.filter((b) => !activeIds.has(b.id));
317
+ const activeIds = new Set(this._activeIds);
318
+ return this._badges.filter((b) => !activeIds.has(b.id));
267
319
  }
268
- // ---------------------------------------------------------------------------
269
- // Actions
270
- // ---------------------------------------------------------------------------
320
+ // ── Actions ───────────────────────────────────────────────────────────────
271
321
  _captureBeforeChange() {
272
322
  if (this._activeListEl) {
273
323
  this._oldPositions = capturePositions(this._activeListEl, BADGE_SELECTOR);
@@ -286,32 +336,42 @@ class PdBadgeOrder extends PdBaseUIInput {
286
336
  }
287
337
  }
288
338
  }
339
+ _createBadge(area = "active") {
340
+ if (this.disabled || this.readonly) return;
341
+ const id = `custom-${Date.now()}`;
342
+ const badge = { id, title: "", custom: true };
343
+ this._captureBeforeChange();
344
+ this._badges = [...this._badges, badge];
345
+ if (area === "active") {
346
+ if (this.max !== void 0 && this._activeIds.length >= this.max) return;
347
+ this._activeIds = [...this._activeIds, id];
348
+ }
349
+ this._autoEditBadgeId = id;
350
+ this._fireChangeEvents();
351
+ }
289
352
  _addBadge(badgeId) {
290
353
  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;
354
+ if (this._activeIds.includes(badgeId)) return;
355
+ if (this.max !== void 0 && this._activeIds.length >= this.max) return;
294
356
  this._captureBeforeChange();
295
- this.value = [...ids, badgeId];
357
+ this._activeIds = [...this._activeIds, badgeId];
296
358
  this._fireChangeEvents();
297
359
  }
298
360
  _removeBadge(badgeId) {
299
361
  if (this.disabled || this.readonly) return;
300
- const ids = this.value;
301
362
  this._captureBeforeChange();
302
- this.value = ids.filter((id) => id !== badgeId);
363
+ this._activeIds = this._activeIds.filter((id) => id !== badgeId);
303
364
  this._fireChangeEvents();
304
365
  }
305
366
  _deleteBadge(badgeId) {
306
367
  if (this.disabled || this.readonly) return;
307
- const badge = this.badges.find((b) => b.id === badgeId);
368
+ const badge = this._badges.find((b) => b.id === badgeId);
308
369
  if (!badge?.custom) return;
309
370
  this._captureBeforeChange();
310
- const ids = this.value;
311
- if (ids.includes(badgeId)) {
312
- this.value = ids.filter((id) => id !== badgeId);
371
+ if (this._activeIds.includes(badgeId)) {
372
+ this._activeIds = this._activeIds.filter((id) => id !== badgeId);
313
373
  }
314
- this.badges = this.badges.filter((b) => b.id !== badgeId);
374
+ this._badges = this._badges.filter((b) => b.id !== badgeId);
315
375
  this.dispatchEvent(
316
376
  new CustomEvent("pd-badge-deleted", {
317
377
  detail: { badge },
@@ -321,15 +381,28 @@ class PdBadgeOrder extends PdBaseUIInput {
321
381
  );
322
382
  this._fireChangeEvents();
323
383
  }
384
+ _editBadge(badgeId, title, description) {
385
+ this._badges = this._badges.map(
386
+ (b) => b.id === badgeId ? { ...b, title, description: description || void 0 } : b
387
+ );
388
+ this.dispatchEvent(
389
+ new CustomEvent("pd-badge-edited", {
390
+ detail: { badge: this._badges.find((b) => b.id === badgeId) },
391
+ bubbles: true,
392
+ composed: true
393
+ })
394
+ );
395
+ this._fireChangeEvents();
396
+ }
324
397
  /** Reorder: move badge from oldIndex to newIndex within active list */
325
398
  reorderBadge(oldIndex, newIndex) {
326
- const ids = [...this.value];
399
+ const ids = [...this._activeIds];
327
400
  if (oldIndex < 0 || oldIndex >= ids.length || newIndex < 0 || newIndex >= ids.length)
328
401
  return;
329
402
  this._captureBeforeChange();
330
403
  const [moved] = ids.splice(oldIndex, 1);
331
404
  ids.splice(newIndex, 0, moved);
332
- this.value = ids;
405
+ this._activeIds = ids;
333
406
  this.dispatchEvent(
334
407
  new CustomEvent("pd-reorder", {
335
408
  detail: { value: ids },
@@ -342,14 +415,13 @@ class PdBadgeOrder extends PdBaseUIInput {
342
415
  /** Insert a badge from available into active list at a specific index */
343
416
  insertBadgeAt(badgeId, index) {
344
417
  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;
418
+ if (this._activeIds.includes(badgeId)) return;
419
+ if (this.max !== void 0 && this._activeIds.length >= this.max) return;
348
420
  this._captureBeforeChange();
349
- const newIds = [...ids];
421
+ const newIds = [...this._activeIds];
350
422
  const insertIdx = Math.max(0, Math.min(index, newIds.length));
351
423
  newIds.splice(insertIdx, 0, badgeId);
352
- this.value = newIds;
424
+ this._activeIds = newIds;
353
425
  this._fireChangeEvents();
354
426
  }
355
427
  /** Move a badge from active to available (at drop) */
@@ -357,45 +429,47 @@ class PdBadgeOrder extends PdBaseUIInput {
357
429
  this._removeBadge(badgeId);
358
430
  }
359
431
  _fireChangeEvents() {
432
+ if (this._error) this.validate();
360
433
  const detail = {
361
- value: this.value,
362
- badges: this.badges
434
+ value: this._activeIds,
435
+ badges: this._badges
363
436
  };
364
437
  this.dispatchEvent(
365
- new CustomEvent("pd-change", {
438
+ new CustomEvent("pd-badge-selection-change", {
366
439
  detail,
367
440
  bubbles: true,
368
441
  composed: true
369
442
  })
370
443
  );
371
444
  }
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);
445
+ // ── AI Trigger ────────────────────────────────────────────────────────────
446
+ _onAiTrigger() {
447
+ this.dispatchEvent(
448
+ new CustomEvent("pd-ai-trigger", {
449
+ bubbles: true,
450
+ composed: true,
451
+ detail: {
452
+ value: JSON.stringify(this._activeIds),
453
+ valueName: this.valueName,
454
+ aiOptions: this.aiOptions
386
455
  }
387
- });
456
+ })
457
+ );
458
+ }
459
+ _onAiTriggerKeyDown(e) {
460
+ if (e.key === "Enter" || e.key === " ") {
461
+ e.preventDefault();
462
+ this._onAiTrigger();
388
463
  }
389
464
  }
390
- // ---------------------------------------------------------------------------
391
- // Render
392
- // ---------------------------------------------------------------------------
465
+ // ── Render ────────────────────────────────────────────────────────────────
393
466
  render() {
394
467
  const activeBadges = this._activeBadges;
395
468
  const availableBadges = this._availableBadges;
396
469
  const drag = this._dragController;
470
+ const error = this._error;
397
471
  return html`
398
- ${this._renderLabel("badge-order")}
472
+ ${this._renderLabel()}
399
473
 
400
474
  <div
401
475
  class="badge-order-container"
@@ -409,6 +483,16 @@ class PdBadgeOrder extends PdBaseUIInput {
409
483
  <slot name="active-header">${this.activeLabel}</slot>
410
484
  <span class="section-count">(${activeBadges.length})</span>
411
485
  </span>
486
+ ${(this.creatable === "active" || this.creatable === "all") && !this.disabled && !this.readonly ? html`
487
+ <pd-button
488
+ outline
489
+ size="sm"
490
+ text="Hinzufügen"
491
+ icon=${pdIcons.ICON_ADD}
492
+ @button-clicked=${() => this._createBadge("active")}
493
+ part="create-button"
494
+ ></pd-button>
495
+ ` : nothing}
412
496
  </div>
413
497
  <div
414
498
  id="active-list"
@@ -430,6 +514,7 @@ class PdBadgeOrder extends PdBaseUIInput {
430
514
  .index=${i + 1}
431
515
  ?numbered=${this.numbered}
432
516
  ?active=${true}
517
+ ?editable=${this.editable === "active" || this.editable === "all"}
433
518
  ?disabled=${this.disabled}
434
519
  ?readonly=${this.readonly}
435
520
  ?ghost=${drag.isDragging && drag.draggedId === badge.id}
@@ -454,6 +539,16 @@ class PdBadgeOrder extends PdBaseUIInput {
454
539
  <slot name="available-header">${this.availableLabel}</slot>
455
540
  <span class="section-count">(${availableBadges.length})</span>
456
541
  </span>
542
+ ${(this.creatable === "available" || this.creatable === "all") && !this.disabled && !this.readonly ? html`
543
+ <pd-button
544
+ outline
545
+ size="sm"
546
+ text="Hinzufügen"
547
+ icon=${pdIcons.ICON_ADD}
548
+ @button-clicked=${() => this._createBadge("available")}
549
+ part="create-button"
550
+ ></pd-button>
551
+ ` : nothing}
457
552
  </div>
458
553
  <div
459
554
  id="available-list"
@@ -470,6 +565,7 @@ class PdBadgeOrder extends PdBaseUIInput {
470
565
  (badge) => html`
471
566
  <pd-badge-item
472
567
  .badge=${badge}
568
+ ?editable=${this.editable === "available" || this.editable === "all"}
473
569
  ?disabled=${this.disabled}
474
570
  ?readonly=${this.readonly}
475
571
  data-badge-id=${badge.id}
@@ -488,15 +584,38 @@ class PdBadgeOrder extends PdBaseUIInput {
488
584
  </div>
489
585
  </div>
490
586
 
491
- ${this._renderGhost()} ${this._renderErrorMsg()}
587
+ ${this._renderGhost()}
588
+ ${error ? html`<div class="error-box"><p>${error}</p></div>` : nothing}
589
+ `;
590
+ }
591
+ _renderLabel() {
592
+ if (!this.label && !this.aiOptions) return nothing;
593
+ return html`
594
+ <div class="label-header">
595
+ <label>${this.label}${this.required && this.label ? "*" : ""}</label>
596
+ <div class="label-icons">
597
+ ${this.aiOptions ? html`
598
+ <pd-icon
599
+ icon="${pdIcons.ICON_AI_SPARKLE}"
600
+ activeIcon
601
+ class="ai-trigger"
602
+ tabindex="0"
603
+ role="button"
604
+ aria-label="KI-Assistent öffnen"
605
+ @click="${this._onAiTrigger}"
606
+ @keydown="${this._onAiTriggerKeyDown}"
607
+ ></pd-icon>
608
+ ` : nothing}
609
+ </div>
610
+ </div>
492
611
  `;
493
612
  }
494
613
  _renderGhost() {
495
614
  const drag = this._dragController;
496
615
  if (!drag.isDragging || !drag.draggedId) return nothing;
497
- const badge = this.badges.find((b) => b.id === drag.draggedId);
616
+ const badge = this._badges.find((b) => b.id === drag.draggedId);
498
617
  if (!badge) return nothing;
499
- const idx = this.value.indexOf(drag.draggedId);
618
+ const idx = this._activeIds.indexOf(drag.draggedId);
500
619
  return html`
501
620
  <div
502
621
  class="drag-ghost"
@@ -515,7 +634,16 @@ class PdBadgeOrder extends PdBaseUIInput {
515
634
  }
516
635
  __decorateClass([
517
636
  property({ type: Array, attribute: false })
518
- ], PdBadgeOrder.prototype, "badges");
637
+ ], PdBadgeOrder.prototype, "initialBadges");
638
+ __decorateClass([
639
+ property({ type: Array, attribute: false })
640
+ ], PdBadgeOrder.prototype, "initialValue");
641
+ __decorateClass([
642
+ property({ type: String })
643
+ ], PdBadgeOrder.prototype, "label");
644
+ __decorateClass([
645
+ property({ type: String })
646
+ ], PdBadgeOrder.prototype, "valueName");
519
647
  __decorateClass([
520
648
  property({ type: Number })
521
649
  ], PdBadgeOrder.prototype, "min");
@@ -526,17 +654,44 @@ __decorateClass([
526
654
  property({ type: Boolean })
527
655
  ], PdBadgeOrder.prototype, "numbered");
528
656
  __decorateClass([
529
- property({ type: String })
657
+ property({ type: String, attribute: "active-label" })
530
658
  ], PdBadgeOrder.prototype, "activeLabel");
531
659
  __decorateClass([
532
- property({ type: String })
660
+ property({ type: String, attribute: "available-label" })
533
661
  ], PdBadgeOrder.prototype, "availableLabel");
534
662
  __decorateClass([
535
- property({ type: String })
663
+ property({ type: String, attribute: "empty-active-text" })
536
664
  ], PdBadgeOrder.prototype, "emptyActiveText");
537
665
  __decorateClass([
538
- property({ type: String })
666
+ property({ type: String, attribute: "empty-available-text" })
539
667
  ], PdBadgeOrder.prototype, "emptyAvailableText");
668
+ __decorateClass([
669
+ property({ type: String })
670
+ ], PdBadgeOrder.prototype, "editable");
671
+ __decorateClass([
672
+ property({ type: String })
673
+ ], PdBadgeOrder.prototype, "creatable");
674
+ __decorateClass([
675
+ property({ type: Boolean })
676
+ ], PdBadgeOrder.prototype, "required");
677
+ __decorateClass([
678
+ property({ type: Boolean, reflect: true })
679
+ ], PdBadgeOrder.prototype, "disabled");
680
+ __decorateClass([
681
+ property({ type: Boolean, reflect: true })
682
+ ], PdBadgeOrder.prototype, "readonly");
683
+ __decorateClass([
684
+ property({ type: Object, attribute: false })
685
+ ], PdBadgeOrder.prototype, "aiOptions");
686
+ __decorateClass([
687
+ state()
688
+ ], PdBadgeOrder.prototype, "_badges");
689
+ __decorateClass([
690
+ state()
691
+ ], PdBadgeOrder.prototype, "_activeIds");
692
+ __decorateClass([
693
+ state()
694
+ ], PdBadgeOrder.prototype, "_error");
540
695
  __decorateClass([
541
696
  state()
542
697
  ], PdBadgeOrder.prototype, "_dragController");
@@ -1,3 +1,5 @@
1
+ const TEXT_LIMIT_TITLE = 40;
2
+ const TEXT_LIMIT_DESC = 100;
1
3
  const DEFAULT_BADGE_COLOR = "#9E9E9E";
2
4
 
3
- export { DEFAULT_BADGE_COLOR };
5
+ export { DEFAULT_BADGE_COLOR, TEXT_LIMIT_DESC, TEXT_LIMIT_TITLE };