@design.estate/dees-catalog 3.96.3 → 3.97.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 (32) hide show
  1. package/dist_bundle/bundle.js +3137 -3113
  2. package/dist_ts_web/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/elements/00group-chart/dees-chart-area/component.d.ts +21 -2
  4. package/dist_ts_web/elements/00group-chart/dees-chart-area/component.js +109 -48
  5. package/dist_ts_web/elements/00group-chart/dees-chart-area/demo.js +17 -2
  6. package/dist_ts_web/elements/00group-chart/dees-chart-area/styles.js +5 -4
  7. package/dist_ts_web/elements/00group-chart/dees-chart-area/template.js +7 -6
  8. package/dist_ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.js +6 -5
  9. package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.d.ts +0 -1
  10. package/dist_ts_web/elements/00group-dataview/dees-table/dees-table.js +11 -21
  11. package/dist_ts_web/elements/00group-input/dees-input-multitoggle/dees-input-multitoggle.js +4 -20
  12. package/dist_ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.js +1 -2
  13. package/dist_ts_web/elements/00group-utility/dees-icon/dees-icon.d.ts +1 -2
  14. package/dist_ts_web/elements/00group-utility/dees-icon/dees-icon.js +80 -52
  15. package/dist_ts_web/elements/00theme.d.ts +0 -2
  16. package/dist_ts_web/elements/00theme.js +1 -7
  17. package/dist_watch/bundle.js +235637 -0
  18. package/dist_watch/bundle.js.map +7 -0
  19. package/dist_watch/index.html +28 -0
  20. package/package.json +3 -3
  21. package/readme.md +0 -5
  22. package/ts_web/00_commitinfo_data.ts +1 -1
  23. package/ts_web/elements/00group-chart/dees-chart-area/component.ts +99 -47
  24. package/ts_web/elements/00group-chart/dees-chart-area/demo.ts +16 -1
  25. package/ts_web/elements/00group-chart/dees-chart-area/styles.ts +4 -3
  26. package/ts_web/elements/00group-chart/dees-chart-area/template.ts +6 -5
  27. package/ts_web/elements/00group-dataview/dees-statsgrid/dees-statsgrid.ts +6 -5
  28. package/ts_web/elements/00group-dataview/dees-table/dees-table.ts +27 -43
  29. package/ts_web/elements/00group-input/dees-input-multitoggle/dees-input-multitoggle.ts +3 -19
  30. package/ts_web/elements/00group-simple/dees-simple-appdash/dees-simple-appdash.ts +0 -1
  31. package/ts_web/elements/00group-utility/dees-icon/dees-icon.ts +91 -55
  32. package/ts_web/elements/00theme.ts +0 -8
@@ -37,17 +37,16 @@ export type IconWithPrefix = `lucide:${string}` | string;
37
37
  // Legacy type kept for consumers that still import it. `iconFA` itself is no longer supported.
38
38
  export type TIconKey = string;
39
39
 
40
- // Cache opaque mask sources. Color is applied separately through currentColor,
41
- // so theme and inherited text-color changes never require rebuilding geometry.
42
- const iconMaskCache = new Map<string, string>();
40
+ // Use a global static cache for all icons to reduce rendering
41
+ const iconCache = new Map<string, string>();
43
42
 
44
43
  // Clear cache items occasionally to prevent memory leaks
45
44
  const MAX_CACHE_SIZE = 500;
46
45
  function limitCacheSize() {
47
- if (iconMaskCache.size > MAX_CACHE_SIZE) {
46
+ if (iconCache.size > MAX_CACHE_SIZE) {
48
47
  // Remove oldest entries (first 20% of items)
49
- const keysToDelete = Array.from(iconMaskCache.keys()).slice(0, MAX_CACHE_SIZE / 5);
50
- keysToDelete.forEach(key => iconMaskCache.delete(key));
48
+ const keysToDelete = Array.from(iconCache.keys()).slice(0, MAX_CACHE_SIZE / 5);
49
+ keysToDelete.forEach(key => iconCache.delete(key));
51
50
  }
52
51
  }
53
52
 
@@ -152,42 +151,53 @@ export class DeesIcon extends DeesElement {
152
151
  }
153
152
  }
154
153
 
155
- private createLucideMaskImage(iconName: string): string {
156
- const pascalCaseName = lucideNameToPascalCase(iconName);
157
- const cacheKey = `lucide:${pascalCaseName}:${this.iconSize}:${this.strokeWidth}`;
158
- const cachedMask = iconMaskCache.get(cacheKey);
159
- if (cachedMask) return cachedMask;
160
-
161
- if (!(lucideIcons as any)[pascalCaseName]) {
162
- throw new Error(`Lucide icon '${pascalCaseName}' was not found`);
163
- }
164
-
165
- const svgElement = createElement((lucideIcons as any)[pascalCaseName], {
166
- color: '#fff',
167
- size: this.iconSize,
168
- strokeWidth: this.strokeWidth,
169
- });
170
- if (!svgElement) {
171
- throw new Error(`Lucide did not create an element for '${pascalCaseName}'`);
154
+ private renderLucideIcon(iconName: string): string {
155
+ // Create a cache key based on all visual properties
156
+ const cacheKey = `lucide:${iconName}:${this.iconSize}:${this.color}:${this.strokeWidth}`;
157
+
158
+ // Check if we already have this icon in the cache
159
+ if (iconCache.has(cacheKey)) {
160
+ return iconCache.get(cacheKey) || '';
172
161
  }
173
162
 
174
- // The mask must be completely opaque. The consumer's inherited color,
175
- // including any alpha, is painted exactly once behind this geometry.
176
- svgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
177
- svgElement.setAttribute('color', '#fff');
178
- svgElement.setAttribute('stroke', '#fff');
179
- svgElement.setAttribute('fill', 'none');
180
-
181
- const maskImage = `url("data:image/svg+xml,${encodeURIComponent(svgElement.outerHTML)}")`;
182
- iconMaskCache.set(cacheKey, maskImage);
183
- limitCacheSize();
184
- return maskImage;
185
- }
163
+ try {
164
+ // Get the Pascal case icon name (Menu instead of menu, FileText instead of file-text)
165
+ const pascalCaseName = lucideNameToPascalCase(iconName);
166
+
167
+ // Check if the icon exists in lucideIcons
168
+ if (!(lucideIcons as any)[pascalCaseName]) {
169
+ console.warn(`Lucide icon '${pascalCaseName}' not found in lucideIcons object`);
170
+ return '';
171
+ }
186
172
 
187
- private clearIconContainer(container: HTMLElement): void {
188
- container.style.backgroundColor = 'transparent';
189
- container.style.setProperty('mask-image', 'none');
190
- container.style.setProperty('-webkit-mask-image', 'none');
173
+ // Use the exact pattern from Lucide documentation
174
+ const svgElement = createElement((lucideIcons as any)[pascalCaseName], {
175
+ color: this.color,
176
+ size: this.iconSize,
177
+ strokeWidth: this.strokeWidth
178
+ });
179
+
180
+ if (!svgElement) {
181
+ console.warn(`createElement returned empty result for ${pascalCaseName}`);
182
+ return '';
183
+ }
184
+
185
+ // Get the HTML
186
+ const result = svgElement.outerHTML;
187
+
188
+ // Cache the result for future use
189
+ iconCache.set(cacheKey, result);
190
+ limitCacheSize();
191
+
192
+ return result;
193
+ } catch (error) {
194
+ console.error(`Error rendering Lucide icon ${iconName}:`, error);
195
+
196
+ // Create a fallback SVG with the icon name
197
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${this.iconSize}" height="${this.iconSize}" viewBox="0 0 24 24" fill="none" stroke="${this.color}" stroke-width="${this.strokeWidth}" stroke-linecap="round" stroke-linejoin="round">
198
+ <text x="50%" y="50%" font-size="6" text-anchor="middle" dominant-baseline="middle" fill="${this.color}">${iconName}</text>
199
+ </svg>`;
200
+ }
191
201
  }
192
202
 
193
203
  public static styles = [
@@ -203,14 +213,11 @@ export class DeesIcon extends DeesElement {
203
213
  pointer-events: none;
204
214
  }
205
215
 
206
- #iconContainer {
207
- background-color: currentColor;
208
- mask-position: center;
209
- mask-repeat: no-repeat;
210
- mask-size: 100% 100%;
211
- -webkit-mask-position: center;
212
- -webkit-mask-repeat: no-repeat;
213
- -webkit-mask-size: 100% 100%;
216
+ /* Improve rendering performance */
217
+ #iconContainer svg {
218
+ display: block;
219
+ height: 100%;
220
+ width: 100%;
214
221
  will-change: transform; /* Helps with animations */
215
222
  contain: strict; /* Performance optimization */
216
223
  }
@@ -237,11 +244,11 @@ export class DeesIcon extends DeesElement {
237
244
  }
238
245
 
239
246
  const effectiveIcon = this.getEffectiveIcon();
240
- const container = this.shadowRoot?.querySelector('#iconContainer') as HTMLElement | null;
247
+ const container = this.shadowRoot?.querySelector('#iconContainer');
241
248
  if (!container) return;
242
249
 
243
250
  if (!effectiveIcon) {
244
- this.clearIconContainer(container);
251
+ container.innerHTML = '';
245
252
  this.lastIcon = effectiveIcon;
246
253
  this.lastIconSize = this.iconSize;
247
254
  this.lastColor = this.color;
@@ -269,16 +276,45 @@ export class DeesIcon extends DeesElement {
269
276
  const { type, name } = this.parseIconString(effectiveIcon);
270
277
 
271
278
  if (type === 'lucide') {
272
- const maskImage = this.createLucideMaskImage(name);
273
- container.style.backgroundColor = this.color === 'currentColor' ? '' : this.color;
274
- container.style.setProperty('mask-image', maskImage);
275
- container.style.setProperty('-webkit-mask-image', maskImage);
279
+ // For Lucide, use direct DOM manipulation as shown in the docs
280
+ // This approach avoids HTML string issues
281
+ container.innerHTML = ''; // Clear container
282
+
283
+ try {
284
+ // Convert to PascalCase (handles kebab-case Lucide ids like "file-text")
285
+ const pascalCaseName = lucideNameToPascalCase(name);
286
+
287
+ if ((lucideIcons as any)[pascalCaseName]) {
288
+ // Use the documented pattern from Lucide docs
289
+ const svgElement = createElement((lucideIcons as any)[pascalCaseName], {
290
+ color: this.color,
291
+ size: this.iconSize,
292
+ strokeWidth: this.strokeWidth
293
+ });
294
+
295
+ if (svgElement) {
296
+ // Directly append the element
297
+ container.appendChild(svgElement);
298
+ return; // Exit early since we've added the element
299
+ }
300
+ }
301
+
302
+ // If we reach here, something went wrong
303
+ throw new Error(`Could not create element for ${pascalCaseName}`);
304
+ } catch (error) {
305
+ console.error(`Error rendering Lucide icon:`, error);
306
+
307
+ // Fall back to the string-based approach
308
+ const iconHtml = this.renderLucideIcon(name);
309
+ if (iconHtml) {
310
+ container.innerHTML = iconHtml;
311
+ }
312
+ }
276
313
  } else {
277
- this.clearIconContainer(container);
314
+ container.innerHTML = '';
278
315
  console.error(`dees-icon: fa:${name} is no longer supported. Use icon="lucide:${name}" or another Lucide icon.`);
279
316
  }
280
317
  } catch (error) {
281
- this.clearIconContainer(container);
282
318
  console.error(`Error updating icon ${effectiveIcon}:`, error);
283
319
  }
284
320
  }
@@ -37,8 +37,6 @@ export interface IThemeColors {
37
37
  bgTertiary: string;
38
38
  /** Recessed shell/window base; content surfaces sit elevated above it (both themes). */
39
39
  bgCanvas: string;
40
- /** Opaque system-label base used when opacity must be composited at element level. */
41
- labelBase?: string;
42
40
  textPrimary: string;
43
41
  textSecondary: string;
44
42
  textMuted: string;
@@ -228,7 +226,6 @@ export const themeDefaults: ITheme = {
228
226
  bgSecondary: '#f2f2f7', // secondarySystemBackground / grouped
229
227
  bgTertiary: '#e9e9eb', // tertiary recess (headers, hovers)
230
228
  bgCanvas: '#f2f2f7', // recessed shell base (systemGroupedBackground)
231
- labelBase: '#3c3c43', // opaque system label base
232
229
  textPrimary: '#1d1d1f', // near-black label
233
230
  textSecondary: 'rgba(60, 60, 67, 0.60)', // secondaryLabel
234
231
  textMuted: 'rgba(60, 60, 67, 0.30)', // tertiaryLabel
@@ -261,7 +258,6 @@ export const themeDefaults: ITheme = {
261
258
  bgSecondary: '#1c1c1e', // secondarySystemBackground / systemGray6 — cards, panels
262
259
  bgTertiary: '#2c2c2e', // tertiarySystemBackground / systemGray5 — headers, hovers
263
260
  bgCanvas: '#000000', // recessed shell base (true black, matches systemBackground)
264
- labelBase: '#ebebf5', // opaque system label base
265
261
  textPrimary: '#f5f5f7', // near-white label
266
262
  textSecondary: 'rgba(235, 235, 245, 0.60)', // secondaryLabel
267
263
  textMuted: 'rgba(235, 235, 245, 0.30)', // tertiaryLabel
@@ -528,10 +524,6 @@ export const themeDefaultStyles: CSSResult = css`
528
524
  /* ========================================
529
525
  * Colors — Text / Label tiers
530
526
  * ======================================== */
531
- --dees-color-label-base: ${cssManager.bdTheme(l.labelBase || '#3c3c43', d.labelBase || '#ebebf5')};
532
- --dees-label-opacity-secondary: 0.6;
533
- --dees-label-opacity-muted: 0.3;
534
- --dees-label-opacity-quaternary: 0.18;
535
527
  --dees-color-text-primary: ${cssManager.bdTheme(l.textPrimary, d.textPrimary)};
536
528
  --dees-color-text-secondary: ${cssManager.bdTheme(l.textSecondary, d.textSecondary)};
537
529
  --dees-color-text-muted: ${cssManager.bdTheme(l.textMuted, d.textMuted)};