@design.estate/dees-catalog 3.73.2 → 3.74.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design.estate/dees-catalog",
3
- "version": "3.73.2",
3
+ "version": "3.74.2",
4
4
  "private": false,
5
5
  "description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
6
6
  "main": "dist_ts_web/index.js",
@@ -18,7 +18,7 @@
18
18
  "dependencies": {
19
19
  "@design.estate/dees-domtools": "^2.5.4",
20
20
  "@design.estate/dees-element": "^2.2.4",
21
- "@design.estate/dees-wcctools": "^3.8.2",
21
+ "@design.estate/dees-wcctools": "^3.8.4",
22
22
  "@fortawesome/fontawesome-svg-core": "^7.2.0",
23
23
  "@fortawesome/free-brands-svg-icons": "^7.2.0",
24
24
  "@fortawesome/free-regular-svg-icons": "^7.2.0",
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@design.estate/dees-catalog',
6
- version: '3.73.2',
6
+ version: '3.74.2',
7
7
  description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
8
8
  }
@@ -50,6 +50,16 @@ export class DeesInputIban extends DeesInputBase<DeesInputIban> {
50
50
  .disabled=${this.disabled}
51
51
  .required=${this.required}
52
52
  .placeholder=${'DE89 3704 0044 0532 0130 00'}
53
+ .validationFunction=${(value: string) => {
54
+ const normalized = value.replace(/ /g, '');
55
+ if (normalized.length === 0) {
56
+ return { valid: true, message: '' };
57
+ }
58
+ const isValid = ibantools.isValidIBAN(normalized);
59
+ return isValid
60
+ ? { valid: true, message: 'IBAN is valid' }
61
+ : { valid: false, message: 'Please enter a valid IBAN' };
62
+ }}
53
63
  @input=${(eventArg: InputEvent) => {
54
64
  this.validateIban(eventArg);
55
65
  }}
@@ -81,10 +91,6 @@ export class DeesInputIban extends DeesInputBase<DeesInputIban> {
81
91
  }
82
92
  }
83
93
  this.enteredIbanIsValid = ibantools.isValidIBAN(this.enteredString.replace(/ /g, ''));
84
- const deesInputText = this.shadowRoot!.querySelector('dees-input-text') as any;
85
- if (deesInputText) {
86
- deesInputText.validationText = `IBAN is valid: ${this.enteredIbanIsValid}`;
87
- }
88
94
  }
89
95
 
90
96
  public getValue(): string {
@@ -210,39 +210,7 @@ export const demoFunc = () => html`
210
210
  </dees-panel>
211
211
  </dees-demowrapper>
212
212
 
213
- <dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
214
- // Demonstrate validation states
215
- const requiredInput = elementArg.querySelector('dees-input-text[required]') as DeesInputText;
216
- const disabledInput = elementArg.querySelector('dees-input-text[disabled]') as DeesInputText;
217
- const errorInput = elementArg.querySelector('dees-input-text[validationState="invalid"]') as DeesInputText;
218
-
219
- if (requiredInput) {
220
- // Show validation on blur for empty required field
221
- requiredInput.addEventListener('blur', () => {
222
- if (!requiredInput.getValue()) {
223
- console.log('Required field is empty!');
224
- }
225
- });
226
- }
227
-
228
- if (disabledInput) {
229
- console.log('Disabled input cannot be edited');
230
- }
231
-
232
- if (errorInput) {
233
- console.log('Error input shows validation message:', errorInput.validationText);
234
-
235
- // Simulate fixing the error
236
- errorInput.addEventListener('changeSubject', () => {
237
- const value = errorInput.getValue();
238
- if (value.includes('@') && value.includes('.')) {
239
- errorInput.validationState = 'valid';
240
- errorInput.validationText = '';
241
- console.log('Email validation passed!');
242
- }
243
- });
244
- }
245
- }}>
213
+ <dees-demowrapper>
246
214
  <dees-panel .title=${'Validation & States'} .subtitle=${'Different validation states and input configurations'}>
247
215
  <div class="input-group">
248
216
  <dees-input-text
@@ -258,10 +226,15 @@ export const demoFunc = () => html`
258
226
  ></dees-input-text>
259
227
 
260
228
  <dees-input-text
261
- .label=${'Field with Error'}
229
+ .label=${'Email with Validation'}
262
230
  .value=${'invalid@'}
263
- .validationText=${'Please enter a valid email address'}
264
- .validationState=${'invalid'}
231
+ .validationFunction=${(value: string) => {
232
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
233
+ if (emailRegex.test(value)) {
234
+ return { valid: true, message: 'Email address is valid' };
235
+ }
236
+ return { valid: false, message: 'Please enter a valid email address' };
237
+ }}
265
238
  ></dees-input-text>
266
239
  </div>
267
240
  </dees-panel>
@@ -311,40 +284,21 @@ export const demoFunc = () => html`
311
284
  </dees-demowrapper>
312
285
 
313
286
  <dees-demowrapper .runAfterRender=${async (elementArg: HTMLElement) => {
314
- // Set up interactive example
315
- const dynamicInput = elementArg.querySelector('dees-input-text');
287
+ const dynamicInput = elementArg.querySelector('dees-input-text') as DeesInputText;
316
288
  const output = elementArg.querySelector('#text-input-output');
317
-
289
+
318
290
  if (dynamicInput && output) {
319
- // Update output on every change
320
- dynamicInput.addEventListener('changeSubject', ((event: CustomEvent) => {
321
- const value = (event.detail as DeesInputText).getValue();
322
- output.textContent = `Current value: "${value}"`;
323
- }) as EventListener);
324
-
325
- // Also track focus/blur events
326
- dynamicInput.addEventListener('focus', () => {
327
- console.log('Input focused');
328
- });
329
-
330
- dynamicInput.addEventListener('blur', () => {
331
- console.log('Input blurred');
332
- });
333
-
334
- // Track keypress events
335
- let keypressCount = 0;
336
- dynamicInput.addEventListener('keydown', () => {
337
- keypressCount++;
338
- console.log(`Keypress count: ${keypressCount}`);
291
+ dynamicInput.changeSubject.subscribe(() => {
292
+ output.textContent = `Current value: "${dynamicInput.getValue()}"`;
339
293
  });
340
294
  }
341
295
  }}>
342
- <dees-panel .title=${'Interactive Example'} .subtitle=${'Try typing in the inputs to see real-time value changes'}>
343
- <dees-input-text
344
- .label=${'Dynamic Input'}
296
+ <dees-panel .title=${'Interactive Example'} .subtitle=${'Try typing in the input to see real-time value changes'}>
297
+ <dees-input-text
298
+ .label=${'Dynamic Input'}
345
299
  .placeholder=${'Type something here...'}
346
300
  ></dees-input-text>
347
-
301
+
348
302
  <div class="interactive-section">
349
303
  <div id="text-input-output" class="output-text">Current value: ""</div>
350
304
  </div>
@@ -7,11 +7,13 @@ import {
7
7
  customElement,
8
8
  type TemplateResult,
9
9
  property,
10
+ state,
10
11
  html,
11
12
  cssManager,
12
13
  css,
13
14
  } from '@design.estate/dees-element';
14
15
  import { themeDefaultStyles } from '../../00theme.js';
16
+ import '../../00group-overlay/dees-contextmenu/dees-contextmenu.js';
15
17
 
16
18
  declare global {
17
19
  interface HTMLElementTagNameMap {
@@ -54,8 +56,8 @@ export class DeesInputText extends DeesInputBase {
54
56
  })
55
57
  accessor validationText: string = '';
56
58
 
57
- @property({})
58
- accessor validationFunction!: (value: string) => boolean;
59
+ @property({ attribute: false })
60
+ accessor validationFunction!: (value: string) => { valid: boolean; message?: string };
59
61
 
60
62
  @property({
61
63
  type: Boolean,
@@ -63,6 +65,11 @@ export class DeesInputText extends DeesInputBase {
63
65
  })
64
66
  accessor vintegrated: boolean = false;
65
67
 
68
+ @property({ attribute: false })
69
+ accessor validConfirmed: boolean = false;
70
+
71
+ private validTimeout: ReturnType<typeof setTimeout> | undefined;
72
+
66
73
  public static styles = [
67
74
  themeDefaultStyles,
68
75
  ...DeesInputBase.baseStyles,
@@ -127,7 +134,7 @@ export class DeesInputText extends DeesInputBase {
127
134
  .showPassword {
128
135
  position: absolute;
129
136
  right: 1px;
130
- top: 50%;
137
+ top: 20px;
131
138
  transform: translateY(-50%);
132
139
  display: flex;
133
140
  align-items: center;
@@ -145,6 +152,29 @@ export class DeesInputText extends DeesInputBase {
145
152
  color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 93.9%)')};
146
153
  }
147
154
 
155
+ /* Valid checkmark icon */
156
+ .validIcon {
157
+ position: absolute;
158
+ right: 10px;
159
+ top: 20px;
160
+ transform: translateY(-50%);
161
+ display: flex;
162
+ align-items: center;
163
+ justify-content: center;
164
+ opacity: 0;
165
+ transition: opacity 0.2s ease;
166
+ pointer-events: none;
167
+ color: ${cssManager.bdTheme('hsl(142.1 76.2% 36.3%)', 'hsl(142.1 70.6% 45.3%)')};
168
+ }
169
+
170
+ .validIcon.show {
171
+ opacity: 1;
172
+ }
173
+
174
+ .validIcon dees-icon {
175
+ font-size: 18px;
176
+ }
177
+
148
178
  /* Validation styles */
149
179
  .validationContainer {
150
180
  margin-top: 4px;
@@ -156,7 +186,7 @@ export class DeesInputText extends DeesInputBase {
156
186
  overflow: hidden;
157
187
  }
158
188
 
159
- .validationContainer.error {
189
+ .validationContainer.invalid {
160
190
  background: ${cssManager.bdTheme('hsl(0 84.2% 60.2% / 0.1)', 'hsl(0 72.2% 50.6% / 0.1)')};
161
191
  color: ${cssManager.bdTheme('hsl(0 84.2% 60.2%)', 'hsl(0 72.2% 50.6%)')};
162
192
  }
@@ -239,9 +269,9 @@ export class DeesInputText extends DeesInputBase {
239
269
  input {
240
270
  font-family: ${this.isPasswordBool ? cssMonoFontFamily : 'inherit'};
241
271
  letter-spacing: ${this.isPasswordBool ? '0.5px' : 'normal'};
242
- padding-right: ${this.isPasswordBool ? '48px' : '12px'};
272
+ padding-right: ${this.isPasswordBool ? '48px' : this.validConfirmed ? '40px' : '12px'};
243
273
  }
244
- ${this.validationText
274
+ ${this.validationText && !this.validConfirmed
245
275
  ? css`
246
276
  .validationContainer {
247
277
  height: auto;
@@ -275,9 +305,12 @@ export class DeesInputText extends DeesInputBase {
275
305
  </div>
276
306
  `
277
307
  : html``}
308
+ <div class="validIcon ${this.validConfirmed ? 'show' : ''}">
309
+ <dees-icon .icon=${'lucide:Check'}></dees-icon>
310
+ </div>
278
311
  ${this.validationText
279
312
  ? html`
280
- <div class="validationContainer ${this.validationState || 'error'}">
313
+ <div class="validationContainer ${this.validationState || 'invalid'}">
281
314
  ${this.validationText}
282
315
  </div>
283
316
  `
@@ -288,15 +321,97 @@ export class DeesInputText extends DeesInputBase {
288
321
  }
289
322
 
290
323
  firstUpdated() {
291
- // Input event handling is already done in updateValue method
324
+ if (this.validationFunction && this.value) {
325
+ const result = this.validationFunction(this.value);
326
+ this.validationState = result.valid ? 'valid' : 'invalid';
327
+ this.validationText = result.message || '';
328
+ if (result.valid) {
329
+ this.validConfirmed = false;
330
+ this.validTimeout = setTimeout(() => {
331
+ this.validConfirmed = true;
332
+ this.validationState = undefined as any;
333
+ }, 500);
334
+ }
335
+ }
292
336
  }
293
337
 
294
338
  public async updateValue(eventArg: Event) {
295
339
  const target: any = eventArg.target;
296
340
  this.value = target.value;
341
+ if (this.validationFunction) {
342
+ const result = this.validationFunction(this.value);
343
+ this.validationState = result.valid ? 'valid' : 'invalid';
344
+ this.validationText = result.message || '';
345
+ if (result.valid) {
346
+ this.validConfirmed = false;
347
+ clearTimeout(this.validTimeout);
348
+ this.validTimeout = setTimeout(() => {
349
+ this.validConfirmed = true;
350
+ this.validationState = undefined as any;
351
+ }, 500);
352
+ } else {
353
+ clearTimeout(this.validTimeout);
354
+ this.validConfirmed = false;
355
+ }
356
+ }
297
357
  this.changeSubject.next(this);
298
358
  }
299
359
 
360
+ public getContextMenuItems() {
361
+ const input = this.shadowRoot!.querySelector('input')!;
362
+ const hasSelection = input.selectionStart !== input.selectionEnd;
363
+ return [
364
+ {
365
+ name: 'Cut',
366
+ iconName: 'lucide:Scissors',
367
+ shortcut: 'Cmd+X',
368
+ disabled: !hasSelection,
369
+ action: async () => {
370
+ const selected = this.value.substring(input.selectionStart!, input.selectionEnd!);
371
+ await navigator.clipboard.writeText(selected);
372
+ const start = input.selectionStart!;
373
+ this.value = this.value.substring(0, start) + this.value.substring(input.selectionEnd!);
374
+ input.value = this.value;
375
+ input.setSelectionRange(start, start);
376
+ this.changeSubject.next(this);
377
+ },
378
+ },
379
+ {
380
+ name: 'Copy',
381
+ iconName: 'lucide:Copy',
382
+ shortcut: 'Cmd+C',
383
+ disabled: !hasSelection,
384
+ action: async () => {
385
+ const selected = this.value.substring(input.selectionStart!, input.selectionEnd!);
386
+ await navigator.clipboard.writeText(selected);
387
+ },
388
+ },
389
+ {
390
+ name: 'Paste',
391
+ iconName: 'lucide:ClipboardPaste',
392
+ shortcut: 'Cmd+V',
393
+ action: async () => {
394
+ const text = await navigator.clipboard.readText();
395
+ const start = input.selectionStart!;
396
+ const end = input.selectionEnd!;
397
+ this.value = this.value.substring(0, start) + text + this.value.substring(end);
398
+ input.value = this.value;
399
+ input.setSelectionRange(start + text.length, start + text.length);
400
+ this.changeSubject.next(this);
401
+ },
402
+ },
403
+ { divider: true },
404
+ {
405
+ name: 'Select All',
406
+ iconName: 'lucide:TextCursorInput',
407
+ shortcut: 'Cmd+A',
408
+ action: async () => {
409
+ input.select();
410
+ },
411
+ },
412
+ ];
413
+ }
414
+
300
415
  public getValue(): string {
301
416
  return this.value;
302
417
  }
@@ -100,11 +100,7 @@ export class DeesTile extends DeesElement {
100
100
  border-radius: 8px;
101
101
  border-top: 1px solid var(--dees-color-border-subtle);
102
102
  border-bottom: 1px solid var(--dees-color-border-subtle);
103
- overflow-x: hidden;
104
- overflow-y: auto;
105
- overscroll-behavior: contain;
106
- scrollbar-width: thin;
107
- scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
103
+ overflow: hidden;
108
104
  }
109
105
 
110
106
  .tile-content.no-footer {
@@ -153,6 +153,14 @@ export class DeesModal extends DeesElement {
153
153
  overscroll-behavior: contain;
154
154
  }
155
155
 
156
+ dees-tile::part(content) {
157
+ overflow-x: hidden;
158
+ overflow-y: auto;
159
+ overscroll-behavior: contain;
160
+ scrollbar-width: thin;
161
+ scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
162
+ }
163
+
156
164
  dees-tile::part(outer) {
157
165
  box-shadow:
158
166
  0 0 0 1px ${cssManager.bdTheme('hsl(0 0% 0% / 0.03)', 'hsl(0 0% 100% / 0.03)')},