@design.estate/dees-catalog 3.76.1 → 3.78.0

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 (39) hide show
  1. package/dist_bundle/bundle.js +963 -734
  2. package/dist_ts_web/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +28 -3
  4. package/dist_ts_web/elements/00group-dataview/dees-table/styles.js +28 -1
  5. package/dist_ts_web/elements/00group-dataview/dees-table/types.d.ts +15 -0
  6. package/dist_ts_web/elements/00group-input/dees-input-dropdown/dees-input-dropdown.demo.js +1 -7
  7. package/dist_ts_web/elements/00group-input/dees-input-iban/dees-input-iban.demo.js +1 -7
  8. package/dist_ts_web/elements/00group-input/dees-input-phone/dees-input-phone.demo.js +1 -7
  9. package/dist_ts_web/elements/00group-input/dees-input-quantityselector/dees-input-quantityselector.demo.js +1 -7
  10. package/dist_ts_web/elements/00group-input/dees-input-radiogroup/dees-input-radiogroup.demo.js +1 -7
  11. package/dist_ts_web/elements/00group-input/dees-input-text/dees-input-text.demo.js +1 -7
  12. package/dist_ts_web/elements/00group-input/dees-input-typelist/dees-input-typelist.demo.js +1 -7
  13. package/dist_ts_web/elements/00group-layout/dees-settings/dees-settings.d.ts +33 -0
  14. package/dist_ts_web/elements/00group-layout/dees-settings/dees-settings.demo.d.ts +2 -0
  15. package/dist_ts_web/elements/00group-layout/dees-settings/dees-settings.demo.js +60 -0
  16. package/dist_ts_web/elements/00group-layout/dees-settings/dees-settings.js +240 -0
  17. package/dist_ts_web/elements/00group-layout/dees-settings/index.d.ts +1 -0
  18. package/dist_ts_web/elements/00group-layout/dees-settings/index.js +2 -0
  19. package/dist_ts_web/elements/00group-layout/index.d.ts +1 -0
  20. package/dist_ts_web/elements/00group-layout/index.js +2 -1
  21. package/dist_watch/bundle.js +442 -449
  22. package/dist_watch/bundle.js.map +2 -2
  23. package/package.json +1 -1
  24. package/readme.md +19 -12
  25. package/ts_web/00_commitinfo_data.ts +1 -1
  26. package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +28 -2
  27. package/ts_web/elements/00group-dataview/dees-table/styles.ts +33 -0
  28. package/ts_web/elements/00group-dataview/dees-table/types.ts +19 -0
  29. package/ts_web/elements/00group-input/dees-input-dropdown/dees-input-dropdown.demo.ts +0 -6
  30. package/ts_web/elements/00group-input/dees-input-iban/dees-input-iban.demo.ts +0 -6
  31. package/ts_web/elements/00group-input/dees-input-phone/dees-input-phone.demo.ts +0 -6
  32. package/ts_web/elements/00group-input/dees-input-quantityselector/dees-input-quantityselector.demo.ts +0 -6
  33. package/ts_web/elements/00group-input/dees-input-radiogroup/dees-input-radiogroup.demo.ts +0 -6
  34. package/ts_web/elements/00group-input/dees-input-text/dees-input-text.demo.ts +0 -6
  35. package/ts_web/elements/00group-input/dees-input-typelist/dees-input-typelist.demo.ts +0 -6
  36. package/ts_web/elements/00group-layout/dees-settings/dees-settings.demo.ts +65 -0
  37. package/ts_web/elements/00group-layout/dees-settings/dees-settings.ts +196 -0
  38. package/ts_web/elements/00group-layout/dees-settings/index.ts +1 -0
  39. package/ts_web/elements/00group-layout/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@design.estate/dees-catalog",
3
- "version": "3.76.1",
3
+ "version": "3.78.0",
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",
package/readme.md CHANGED
@@ -59,8 +59,8 @@ For developers working on this library, please refer to the [UI Components Playb
59
59
  | **Forms** | [`DeesForm`](#deesform), [`DeesInputText`](#deesinputtext), [`DeesInputCheckbox`](#deesinputcheckbox), [`DeesInputDropdown`](#deesinputdropdown), [`DeesInputRadiogroup`](#deesinputradiogroup), [`DeesInputFileupload`](#deesinputfileupload), [`DeesInputIban`](#deesinputiban), [`DeesInputPhone`](#deesinputphone), [`DeesInputQuantitySelector`](#deesinputquantityselector), [`DeesInputMultitoggle`](#deesinputmultitoggle), [`DeesInputToggle`](#deesinputtoggle), [`DeesInputTags`](#deesinputtags), [`DeesInputTypelist`](#deesinputtypelist), [`DeesInputList`](#deesinputlist), [`DeesInputProfilepicture`](#deesinputprofilepicture), [`DeesInputRichtext`](#deesinputrichtext), [`DeesInputWysiwyg`](#deesinputwysiwyg), [`DeesInputDatepicker`](#deesinputdatepicker), [`DeesInputSearchselect`](#deesinputsearchselect), [`DeesInputCode`](#deesinputcode), [`DeesFormSubmit`](#deesformsubmit) |
60
60
  | **App Shell (Layout)** | [`DeesAppui`](#deesappui-️), [`DeesAppuiMainmenu`](#deesappuimainmenu), [`DeesAppuiSecondarymenu`](#deesappuisecondarymenu), [`DeesAppuiMaincontent`](#deesappuimaincontent), [`DeesAppuiAppbar`](#deesappuiappbar), [`DeesAppuiActivitylog`](#deesappuiactivitylog), [`DeesAppuiBottombar`](#deesappuibottombar), [`DeesAppuiProfiledropdown`](#deesappuiprofiledropdown), [`DeesAppuiTabs`](#deesappuitabs), [`DeesMobileNavigation`](#deesmobilenavigation), [`DeesDashboardGrid`](#deesdashboardgrid) |
61
61
  | **Data Display** | [`DeesTable`](#deestable), [`DeesDataviewCodebox`](#deesdataviewcodebox), [`DeesDataviewStatusobject`](#deesdataviewstatusobject), [`DeesPdf`](#deespdf), [`DeesStatsGrid`](#deesstatsgrid), [`DeesPagination`](#deespagination), [`DeesStorageBrowser`](#deesstorgebrowser) |
62
- | **Media & Tiles** | [`DeesTilePdf`](#deestilepdf), [`DeesTileImage`](#deestileimage), [`DeesTileAudio`](#deestileaudio), [`DeesTileVideo`](#deestilevideo), [`DeesTileNote`](#deestilenote), [`DeesTileFolder`](#deestilefolder), [`DeesPreview`](#deespreview), [`DeesPdfViewer`](#deespdfviewer), [`DeesPdfPreview`](#deespdfpreview), [`DeesImageViewer`](#deesimageviewer), [`DeesAudioViewer`](#deesaudioviewer), [`DeesVideoViewer`](#deesvideoviewer) |
63
- | **Visualization** | [`DeesChartArea`](#deeschartarea), [`DeesChartLog`](#deeschartlog) |
62
+ | **Media & Thumbnails** | [`DeesThumbnailPdf`](#deesthumbnailpdf), [`DeesThumbnailImage`](#deesthumbnailimage), [`DeesThumbnailAudio`](#deesthumbnailaudio), [`DeesThumbnailVideo`](#deesthumbnalvideo), [`DeesThumbnailNote`](#deesthumbnailnote), [`DeesThumbnailFolder`](#deesthumbnailfolder), [`DeesPreview`](#deespreview), [`DeesPdfViewer`](#deespdfviewer), [`DeesImageViewer`](#deesimageviewer), [`DeesAudioViewer`](#deesaudioviewer), [`DeesVideoViewer`](#deesvideoviewer) |
63
+ | **Visualization** | [`DeesChartArea`](#deeschartarea), [`DeesChartBar`](#deeschartbar), [`DeesChartDonut`](#deeschartdonut), [`DeesChartGauge`](#deeschartgauge), [`DeesChartRadar`](#deeschartradar), [`DeesChartLog`](#deeschartlog) |
64
64
  | **Dialogs & Overlays** | [`DeesModal`](#deesmodal), [`DeesContextmenu`](#deescontextmenu), [`DeesSpeechbubble`](#deesspeechbubble), [`DeesWindowlayer`](#deeswindowlayer) |
65
65
  | **Navigation** | [`DeesStepper`](#deesstepper), [`DeesProgressbar`](#deesprogressbar) |
66
66
  | **Workspace / IDE** | [`DeesWorkspace`](#deesworkspace), [`DeesWorkspaceMonaco`](#deesworkspacemonaco), [`DeesWorkspaceDiffEditor`](#deesworkspacediffeditor), [`DeesWorkspaceFiletree`](#deesworkspacefiletree), [`DeesWorkspaceTerminal`](#deesworkspaceterminal), [`DeesWorkspaceTerminalPreview`](#deesworkspaceterminalpreview), [`DeesWorkspaceMarkdown`](#deesworkspacemarkdown), [`DeesWorkspaceMarkdownoutlet`](#deesworkspacemarkdownoutlet), [`DeesWorkspaceBottombar`](#deesworkspacebottombar) |
@@ -143,14 +143,13 @@ Display icons from FontAwesome and Lucide icon libraries with library prefixes.
143
143
  ```
144
144
 
145
145
  #### `DeesLabel`
146
- Text label component with optional icon and status indicators.
146
+ Text label component with optional required indicator and info tooltip. Used internally by all input components.
147
147
 
148
148
  ```typescript
149
149
  <dees-label
150
- text="Status" // Label text
151
- icon="info-circle" // Optional: icon name
152
- type="info" // Options: default, info, success, warning, error
153
- size="medium" // Options: small, medium, large
150
+ .label=${'Email Address'} // Label text
151
+ .required=${true} // Optional: shows red asterisk
152
+ .infoText=${'We will never share your email'} // Optional: shows hover info icon with tooltip
154
153
  ></dees-label>
155
154
  ```
156
155
 
@@ -321,7 +320,7 @@ Container component for form elements with built-in validation and data handling
321
320
  ```
322
321
 
323
322
  #### `DeesInputText`
324
- Text input field with validation and formatting options.
323
+ Text input field with validation, info tooltips, description text, and context menu (Cut/Copy/Paste/Select All).
325
324
 
326
325
  ```typescript
327
326
  <dees-input-text
@@ -330,10 +329,20 @@ Text input field with validation and formatting options.
330
329
  value="initial@value.com" // Initial value
331
330
  required // Makes the field required
332
331
  disabled // Disables the input
333
- placeholder="Enter your email"
332
+ .infoText=${'Hover icon tooltip text'} // Shows ⓘ icon on label with hover tooltip
333
+ .description=${'Permanent help text below the input'} // Small text below the input
334
+ .validationFunction=${(value) => { // Auto-validates on every keystroke
335
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
336
+ if (emailRegex.test(value)) {
337
+ return { valid: true, message: 'Email is valid' };
338
+ }
339
+ return { valid: false, message: 'Please enter a valid email' };
340
+ }}
334
341
  ></dees-input-text>
335
342
  ```
336
343
 
344
+ > 💡 **All input components** share these common properties from `DeesInputBase`: `key`, `label`, `required`, `disabled`, `infoText`, `description`, `layoutMode`, `labelPosition`.
345
+
337
346
  #### `DeesInputCheckbox`
338
347
  Checkbox input component for boolean values.
339
348
 
@@ -1780,7 +1789,7 @@ interface ITileFolderItem {
1780
1789
 
1781
1790
  ## License and Legal Information
1782
1791
 
1783
- This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./license) file.
1792
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
1784
1793
 
1785
1794
  **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
1786
1795
 
@@ -1798,5 +1807,3 @@ Registered at District Court Bremen HRB 35230 HB, Germany
1798
1807
  For any legal inquiries or further information, please contact us via email at hello@task.vc.
1799
1808
 
1800
1809
  By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
1801
-
1802
- By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@design.estate/dees-catalog',
6
- version: '3.76.1',
6
+ version: '3.78.0',
7
7
  description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
8
8
  }
@@ -695,6 +695,7 @@ export class DeesTable<T> extends DeesElement {
695
695
  this.__editingCell?.rowId === rowId &&
696
696
  this.__editingCell?.colKey === editKey;
697
697
  const isFlashing = !!flashSet?.has(editKey);
698
+ const useFlashBorder = isFlashing && !!col.flashBorder;
698
699
  const cellClasses = [
699
700
  isEditable ? 'editable' : '',
700
701
  isFocused && !isEditing ? 'focused' : '',
@@ -702,8 +703,13 @@ export class DeesTable<T> extends DeesElement {
702
703
  ]
703
704
  .filter(Boolean)
704
705
  .join(' ');
706
+ const flashClass = isFlashing
707
+ ? useFlashBorder
708
+ ? 'innerCellContainer flashing-border'
709
+ : 'innerCellContainer flashing'
710
+ : 'innerCellContainer';
705
711
  const innerHtml = html`<div
706
- class=${isFlashing ? 'innerCellContainer flashing' : 'innerCellContainer'}
712
+ class=${flashClass}
707
713
  >
708
714
  ${isEditing ? this.renderCellEditor(itemArg, col) : content}
709
715
  </div>`;
@@ -1362,6 +1368,7 @@ export class DeesTable<T> extends DeesElement {
1362
1368
 
1363
1369
  const effectiveColumns = this.__getEffectiveColumns();
1364
1370
  const visibleCols = effectiveColumns.filter((c) => !c.hidden);
1371
+ const colByKey = new Map<string, Column<T>>(visibleCols.map((c) => [String(c.key), c]));
1365
1372
  const nextSnapshot = new Map<string, Map<string, unknown>>();
1366
1373
  const newlyFlashing = new Map<string, Set<string>>();
1367
1374
 
@@ -1376,7 +1383,26 @@ export class DeesTable<T> extends DeesElement {
1376
1383
  const prevCells = this.__prevSnapshot?.get(rowId);
1377
1384
  if (!prevCells) continue; // new row — not an "update"
1378
1385
  for (const [colKey, nextVal] of cellMap) {
1379
- if (prevCells.get(colKey) !== nextVal) {
1386
+ const prevVal = prevCells.get(colKey);
1387
+
1388
+ // Look up the column definition for flash options.
1389
+ const colDef = colByKey.get(colKey);
1390
+
1391
+ // Determine whether the cell changed.
1392
+ let changed: boolean;
1393
+ if (colDef?.flashCompare) {
1394
+ // Explicit custom comparator — caller decides.
1395
+ changed = colDef.flashCompare(prevVal, nextVal);
1396
+ } else if (nextVal !== null && nextVal !== undefined && typeof nextVal === 'object') {
1397
+ // Non-primitive (TemplateResult, object, array, etc.) — skip by
1398
+ // default. Custom renderings don't benefit from the text-color
1399
+ // flash and reference inequality causes false positives.
1400
+ changed = false;
1401
+ } else {
1402
+ changed = prevVal !== nextVal;
1403
+ }
1404
+
1405
+ if (changed) {
1380
1406
  // Don't flash the cell the user is actively editing.
1381
1407
  if (
1382
1408
  this.__editingCell &&
@@ -404,11 +404,44 @@ export const tableStyles: CSSResult[] = [
404
404
  100% { color: var(--dees-color-text-primary); }
405
405
  }
406
406
 
407
+ /* Border/background flash variant for cells with styled content
408
+ (badges, icons, custom components) where a text-color animation
409
+ would be invisible. Activated via flashBorder on Column. */
410
+ .innerCellContainer.flashing-border {
411
+ animation: dees-table-cell-flash-border
412
+ var(--dees-table-flash-duration, 900ms)
413
+ var(--dees-table-flash-easing);
414
+ border-radius: 3px;
415
+ }
416
+
417
+ @keyframes dees-table-cell-flash-border {
418
+ 0%,
419
+ 35% {
420
+ box-shadow: inset 0 0 0 1.5px var(--dees-table-flash-color);
421
+ background: ${cssManager.bdTheme(
422
+ 'hsl(45 93% 62% / 0.10)',
423
+ 'hsl(45 93% 62% / 0.08)'
424
+ )};
425
+ }
426
+ 100% {
427
+ box-shadow: inset 0 0 0 1.5px transparent;
428
+ background: transparent;
429
+ }
430
+ }
431
+
407
432
  @media (prefers-reduced-motion: reduce) {
408
433
  .innerCellContainer.flashing {
409
434
  animation: none;
410
435
  color: var(--dees-table-flash-color);
411
436
  }
437
+ .innerCellContainer.flashing-border {
438
+ animation: none;
439
+ box-shadow: inset 0 0 0 1.5px var(--dees-table-flash-color);
440
+ background: ${cssManager.bdTheme(
441
+ 'hsl(45 93% 62% / 0.10)',
442
+ 'hsl(45 93% 62% / 0.08)'
443
+ )};
444
+ }
412
445
  }
413
446
 
414
447
  /* Dev-time warning banner shown when highlight-updates="flash" but
@@ -65,6 +65,25 @@ export interface Column<T = any> {
65
65
  parse?: (editorValue: any, row: T) => any;
66
66
  /** Validate the parsed value before commit. Return string for error, true/void for ok. */
67
67
  validate?: (value: any, row: T) => true | string | void;
68
+
69
+ // ─── Flash highlight options ───
70
+
71
+ /**
72
+ * Custom comparison for flash-on-update diffing.
73
+ * Return `true` if the cell should flash (i.e. the values differ).
74
+ * When absent, non-primitive cell values are skipped entirely
75
+ * (only strings, numbers, booleans, null, and undefined are diffed).
76
+ */
77
+ flashCompare?: (prevVal: any, nextVal: any) => boolean;
78
+
79
+ /**
80
+ * When `true`, flash this cell with a border/background pulse instead of
81
+ * the default text-color animation. Useful for cells containing styled
82
+ * badges, icons, or custom web-component renderings where a text-color
83
+ * change would be invisible.
84
+ * @default false
85
+ */
86
+ flashBorder?: boolean;
68
87
  }
69
88
 
70
89
  /**
@@ -31,12 +31,6 @@ export const demoFunc = () => html`
31
31
  flex-wrap: wrap;
32
32
  }
33
33
 
34
- .input-group {
35
- display: flex;
36
- flex-direction: column;
37
- gap: 16px;
38
- }
39
-
40
34
  .spacer {
41
35
  height: 200px;
42
36
  display: flex;
@@ -13,12 +13,6 @@ export const demoFunc = () => html`
13
13
  margin: 0 auto;
14
14
  }
15
15
 
16
- .input-group {
17
- display: flex;
18
- flex-direction: column;
19
- gap: 16px;
20
- }
21
-
22
16
  .payment-group {
23
17
  display: flex;
24
18
  align-items: center;
@@ -13,12 +13,6 @@ export const demoFunc = () => html`
13
13
  margin: 0 auto;
14
14
  }
15
15
 
16
- .input-group {
17
- display: flex;
18
- flex-direction: column;
19
- gap: 16px;
20
- }
21
-
22
16
  .horizontal-group {
23
17
  display: flex;
24
18
  align-items: center;
@@ -14,12 +14,6 @@ export const demoFunc = () => html`
14
14
  margin: 0 auto;
15
15
  }
16
16
 
17
- .input-group {
18
- display: flex;
19
- flex-direction: column;
20
- gap: 16px;
21
- }
22
-
23
17
  .shopping-grid {
24
18
  display: grid;
25
19
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
@@ -23,12 +23,6 @@ export const demoFunc = () => html`
23
23
  margin-bottom: 0;
24
24
  }
25
25
 
26
- .input-group {
27
- display: flex;
28
- flex-direction: column;
29
- gap: 16px;
30
- }
31
-
32
26
  .demo-grid {
33
27
  display: grid;
34
28
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
@@ -30,12 +30,6 @@ export const demoFunc = () => html`
30
30
  flex-wrap: wrap;
31
31
  }
32
32
 
33
- .input-group {
34
- display: flex;
35
- flex-direction: column;
36
- gap: 16px;
37
- }
38
-
39
33
  .grid-layout {
40
34
  display: grid;
41
35
  grid-template-columns: 1fr 1fr;
@@ -13,12 +13,6 @@ export const demoFunc = () => html`
13
13
  margin: 0 auto;
14
14
  }
15
15
 
16
- .input-group {
17
- display: flex;
18
- flex-direction: column;
19
- gap: 16px;
20
- }
21
-
22
16
  .horizontal-group {
23
17
  display: flex;
24
18
  gap: 24px;
@@ -0,0 +1,65 @@
1
+ import { html, css, cssManager } from '@design.estate/dees-element';
2
+ import './dees-settings.js';
3
+ import type { ISettingsField, ISettingsAction } from './dees-settings.js';
4
+
5
+ export const demoFunc = () => {
6
+ const acmeFields: ISettingsField[] = [
7
+ { key: 'email', label: 'Account email', value: 'admin@example.com' },
8
+ { key: 'status', label: 'Status', value: 'enabled' },
9
+ { key: 'mode', label: 'Mode', value: 'production' },
10
+ { key: 'autoRenew', label: 'Auto-renew', value: 'on' },
11
+ { key: 'threshold', label: 'Renewal threshold', value: '30 days' },
12
+ ];
13
+
14
+ const acmeActions: ISettingsAction[] = [
15
+ { name: 'Edit', action: () => console.log('Edit clicked') },
16
+ ];
17
+
18
+ const emptyActions: ISettingsAction[] = [
19
+ { name: 'Configure', action: () => console.log('Configure clicked') },
20
+ ];
21
+
22
+ const multiActions: ISettingsAction[] = [
23
+ { name: 'Reset', action: () => console.log('Reset clicked') },
24
+ { name: 'Edit', action: () => console.log('Edit clicked') },
25
+ ];
26
+
27
+ return html`
28
+ <dees-demowrapper>
29
+ <style>
30
+ ${css`
31
+ .demoBox {
32
+ background: ${cssManager.bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 9%)')};
33
+ padding: 40px;
34
+ display: flex;
35
+ flex-direction: column;
36
+ gap: 24px;
37
+ max-width: 600px;
38
+ }
39
+ `}
40
+ </style>
41
+ <div class="demoBox">
42
+ <dees-settings
43
+ .heading=${'ACME Settings'}
44
+ .settingsFields=${acmeFields}
45
+ .actions=${acmeActions}
46
+ ></dees-settings>
47
+
48
+ <dees-settings
49
+ .heading=${'ACME Settings'}
50
+ .description=${'No ACME configuration yet. Click Configure to set up automated TLS certificate issuance.'}
51
+ .actions=${emptyActions}
52
+ ></dees-settings>
53
+
54
+ <dees-settings
55
+ .heading=${'Server Config'}
56
+ .settingsFields=${[
57
+ { key: 'host', label: 'Hostname', value: 'proxy.example.com' },
58
+ { key: 'port', label: 'Port', value: '443' },
59
+ ]}
60
+ .actions=${multiActions}
61
+ ></dees-settings>
62
+ </div>
63
+ </dees-demowrapper>
64
+ `;
65
+ };
@@ -0,0 +1,196 @@
1
+ import {
2
+ customElement,
3
+ DeesElement,
4
+ html,
5
+ css,
6
+ cssManager,
7
+ property,
8
+ type TemplateResult,
9
+ } from '@design.estate/dees-element';
10
+ import { demoFunc } from './dees-settings.demo.js';
11
+ import { cssGeistFontFamily } from '../../00fonts.js';
12
+ import { themeDefaultStyles } from '../../00theme.js';
13
+ import '../../00group-layout/dees-tile/dees-tile.js';
14
+
15
+ declare global {
16
+ interface HTMLElementTagNameMap {
17
+ 'dees-settings': DeesSettings;
18
+ }
19
+ }
20
+
21
+ export interface ISettingsField {
22
+ key: string;
23
+ label: string;
24
+ value: string | TemplateResult;
25
+ }
26
+
27
+ export interface ISettingsAction {
28
+ name: string;
29
+ action: () => void | Promise<void>;
30
+ }
31
+
32
+ /**
33
+ * dees-settings — a read-only settings display tile with modal-style footer actions.
34
+ *
35
+ * Renders a dees-tile with a heading, a grid of label/value fields,
36
+ * and a footer action bar. When an action is clicked the component
37
+ * dispatches a `settings-action` CustomEvent with the action name.
38
+ */
39
+ @customElement('dees-settings')
40
+ export class DeesSettings extends DeesElement {
41
+ public static demo = demoFunc;
42
+ public static demoGroups = ['Layout'];
43
+
44
+ @property({ type: String })
45
+ accessor heading: string = '';
46
+
47
+ @property({ type: String })
48
+ accessor description: string = '';
49
+
50
+ @property({ attribute: false })
51
+ accessor settingsFields: ISettingsField[] = [];
52
+
53
+ @property({ attribute: false })
54
+ accessor actions: ISettingsAction[] = [];
55
+
56
+ public static styles = [
57
+ themeDefaultStyles,
58
+ cssManager.defaultStyles,
59
+ css`
60
+ :host {
61
+ display: block;
62
+ font-family: ${cssGeistFontFamily};
63
+ }
64
+
65
+ .settingsGrid {
66
+ display: grid;
67
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
68
+ gap: 12px 24px;
69
+ padding: 16px;
70
+ }
71
+
72
+ .settingsField {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: 2px;
76
+ }
77
+
78
+ .fieldLabel {
79
+ font-size: 11px;
80
+ text-transform: uppercase;
81
+ letter-spacing: 0.03em;
82
+ color: var(--dees-color-text-muted);
83
+ }
84
+
85
+ .fieldValue {
86
+ font-size: 13px;
87
+ color: var(--dees-color-text-primary);
88
+ }
89
+
90
+ .settingsDescription {
91
+ padding: 16px;
92
+ font-size: 13px;
93
+ line-height: 1.5;
94
+ color: var(--dees-color-text-muted);
95
+ }
96
+
97
+ .bottomButtons {
98
+ display: flex;
99
+ flex-direction: row;
100
+ justify-content: flex-end;
101
+ align-items: center;
102
+ gap: 0;
103
+ height: 36px;
104
+ width: 100%;
105
+ box-sizing: border-box;
106
+ }
107
+
108
+ .bottomButtons .bottomButton {
109
+ padding: 0 16px;
110
+ height: 100%;
111
+ text-align: center;
112
+ font-size: 12px;
113
+ font-weight: 500;
114
+ cursor: pointer;
115
+ user-select: none;
116
+ transition: all 0.15s ease;
117
+ background: transparent;
118
+ border: none;
119
+ border-left: 1px solid var(--dees-color-border-subtle);
120
+ color: var(--dees-color-text-muted);
121
+ white-space: nowrap;
122
+ display: flex;
123
+ align-items: center;
124
+ }
125
+
126
+ .bottomButtons .bottomButton:first-child {
127
+ border-left: none;
128
+ }
129
+
130
+ .bottomButtons .bottomButton:hover {
131
+ background: var(--dees-color-hover);
132
+ color: var(--dees-color-text-primary);
133
+ }
134
+
135
+ .bottomButtons .bottomButton:active {
136
+ background: ${cssManager.bdTheme('hsl(0 0% 92%)', 'hsl(0 0% 13%)')};
137
+ }
138
+
139
+ .bottomButtons .bottomButton.primary {
140
+ color: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8%)', 'hsl(213.1 93.9% 67.8%)')};
141
+ font-weight: 600;
142
+ }
143
+
144
+ .bottomButtons .bottomButton.primary:hover {
145
+ background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.08)', 'hsl(213.1 93.9% 67.8% / 0.08)')};
146
+ color: ${cssManager.bdTheme('hsl(217.2 91.2% 50%)', 'hsl(213.1 93.9% 75%)')};
147
+ }
148
+
149
+ .bottomButtons .bottomButton.primary:active {
150
+ background: ${cssManager.bdTheme('hsl(217.2 91.2% 59.8% / 0.15)', 'hsl(213.1 93.9% 67.8% / 0.15)')};
151
+ }
152
+ `,
153
+ ];
154
+
155
+ public render(): TemplateResult {
156
+ const hasFields = this.settingsFields.length > 0;
157
+ const hasActions = this.actions.length > 0;
158
+
159
+ return html`
160
+ <dees-tile .heading=${this.heading}>
161
+ ${hasFields
162
+ ? html`
163
+ <div class="settingsGrid">
164
+ ${this.settingsFields.map(
165
+ (field) => html`
166
+ <div class="settingsField">
167
+ <span class="fieldLabel">${field.label}</span>
168
+ <span class="fieldValue">${field.value}</span>
169
+ </div>
170
+ `,
171
+ )}
172
+ </div>
173
+ `
174
+ : html`
175
+ <div class="settingsDescription">${this.description}</div>
176
+ `}
177
+ ${hasActions
178
+ ? html`
179
+ <div slot="footer" class="bottomButtons">
180
+ ${this.actions.map(
181
+ (actionArg, index) => html`
182
+ <div
183
+ class="bottomButton ${index === this.actions.length - 1 ? 'primary' : ''}"
184
+ @click=${() => actionArg.action()}
185
+ >
186
+ ${actionArg.name}
187
+ </div>
188
+ `,
189
+ )}
190
+ </div>
191
+ `
192
+ : ''}
193
+ </dees-tile>
194
+ `;
195
+ }
196
+ }
@@ -0,0 +1 @@
1
+ export * from './dees-settings.js';
@@ -5,5 +5,6 @@ export * from './dees-heading/index.js';
5
5
  export * from './dees-label/index.js';
6
6
  export * from './dees-pagination/index.js';
7
7
  export * from './dees-panel/index.js';
8
+ export * from './dees-settings/index.js';
8
9
  export * from './dees-stepper/index.js';
9
10
  export * from './dees-tile/index.js';