@social.io/catalog 1.3.0 → 2.1.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 (130) hide show
  1. package/.smartconfig.json +51 -0
  2. package/dist_bundle/bundle.js +5455 -3248
  3. package/dist_ts_web/00_commitinfo_data.js +3 -3
  4. package/dist_ts_web/elements/index.d.ts +21 -3
  5. package/dist_ts_web/elements/index.js +28 -7
  6. package/dist_ts_web/elements/sio-ai-card.d.ts +39 -0
  7. package/dist_ts_web/elements/sio-ai-card.js +229 -0
  8. package/dist_ts_web/elements/sio-avatar.d.ts +46 -0
  9. package/dist_ts_web/elements/sio-avatar.js +379 -0
  10. package/dist_ts_web/elements/sio-bucket-header.d.ts +36 -0
  11. package/dist_ts_web/elements/sio-bucket-header.js +197 -0
  12. package/dist_ts_web/elements/sio-button.d.ts +7 -3
  13. package/dist_ts_web/elements/sio-button.js +253 -152
  14. package/dist_ts_web/elements/sio-channel-rail.d.ts +38 -0
  15. package/dist_ts_web/elements/sio-channel-rail.js +288 -0
  16. package/dist_ts_web/elements/sio-chip.d.ts +25 -0
  17. package/dist_ts_web/elements/sio-chip.js +188 -0
  18. package/dist_ts_web/elements/sio-cmdk.d.ts +59 -0
  19. package/dist_ts_web/elements/sio-cmdk.js +471 -0
  20. package/dist_ts_web/elements/sio-combox.d.ts +55 -1
  21. package/dist_ts_web/elements/sio-combox.js +458 -261
  22. package/dist_ts_web/elements/sio-composer.d.ts +48 -0
  23. package/dist_ts_web/elements/sio-composer.js +357 -0
  24. package/dist_ts_web/elements/sio-conversation-selector.d.ts +41 -1
  25. package/dist_ts_web/elements/sio-conversation-selector.js +426 -238
  26. package/dist_ts_web/elements/sio-conversation-view.d.ts +34 -6
  27. package/dist_ts_web/elements/sio-conversation-view.js +738 -564
  28. package/dist_ts_web/elements/sio-dropdown-menu.d.ts +6 -6
  29. package/dist_ts_web/elements/sio-dropdown-menu.js +223 -169
  30. package/dist_ts_web/elements/sio-fab.d.ts +23 -5
  31. package/dist_ts_web/elements/sio-fab.js +259 -235
  32. package/dist_ts_web/elements/sio-glass-toolbar.d.ts +22 -0
  33. package/dist_ts_web/elements/sio-glass-toolbar.js +178 -0
  34. package/dist_ts_web/elements/sio-icon.d.ts +1 -0
  35. package/dist_ts_web/elements/sio-icon.js +254 -94
  36. package/dist_ts_web/elements/sio-image-lightbox.d.ts +3 -4
  37. package/dist_ts_web/elements/sio-image-lightbox.js +282 -191
  38. package/dist_ts_web/elements/sio-inset-list.d.ts +28 -0
  39. package/dist_ts_web/elements/sio-inset-list.js +191 -0
  40. package/dist_ts_web/elements/sio-kbd.d.ts +16 -0
  41. package/dist_ts_web/elements/sio-kbd.js +117 -0
  42. package/dist_ts_web/elements/sio-list-row.d.ts +55 -0
  43. package/dist_ts_web/elements/sio-list-row.js +462 -0
  44. package/dist_ts_web/elements/sio-logo-render.d.ts +42 -0
  45. package/dist_ts_web/elements/sio-logo-render.js +306 -0
  46. package/dist_ts_web/elements/sio-logo.d.ts +64 -0
  47. package/dist_ts_web/elements/sio-logo.js +393 -0
  48. package/dist_ts_web/elements/sio-message-input.d.ts +25 -4
  49. package/dist_ts_web/elements/sio-message-input.js +231 -226
  50. package/dist_ts_web/elements/sio-paper-thumb.d.ts +24 -0
  51. package/dist_ts_web/elements/sio-paper-thumb.js +293 -0
  52. package/dist_ts_web/elements/sio-pdf-viewer.d.ts +2 -0
  53. package/dist_ts_web/elements/sio-pdf-viewer.js +344 -244
  54. package/dist_ts_web/elements/sio-segmented.d.ts +32 -0
  55. package/dist_ts_web/elements/sio-segmented.js +217 -0
  56. package/dist_ts_web/elements/sio-step-timeline.d.ts +28 -0
  57. package/dist_ts_web/elements/sio-step-timeline.js +222 -0
  58. package/dist_ts_web/elements/sio-tab-bar.d.ts +36 -0
  59. package/dist_ts_web/elements/sio-tab-bar.js +232 -0
  60. package/dist_ts_web/elements/sio-unread-badge.d.ts +25 -0
  61. package/dist_ts_web/elements/sio-unread-badge.js +203 -0
  62. package/dist_ts_web/elements/sio-waveform.d.ts +34 -0
  63. package/dist_ts_web/elements/sio-waveform.js +304 -0
  64. package/dist_ts_web/elements/tokens.d.ts +70 -0
  65. package/dist_ts_web/elements/tokens.js +277 -0
  66. package/dist_ts_web/pages/firstpage.d.ts +5 -0
  67. package/dist_ts_web/pages/firstpage.js +21 -2
  68. package/dist_ts_web/pages/mainpage.d.ts +6 -0
  69. package/dist_ts_web/pages/mainpage.js +111 -39
  70. package/{license → license.md} +3 -1
  71. package/package.json +23 -29
  72. package/readme.hints.md +82 -0
  73. package/readme.md +113 -146
  74. package/ts_web/00_commitinfo_data.ts +2 -2
  75. package/ts_web/elements/index.ts +31 -7
  76. package/ts_web/elements/sio-ai-card.ts +175 -0
  77. package/ts_web/elements/sio-avatar.ts +295 -0
  78. package/ts_web/elements/sio-bucket-header.ts +157 -0
  79. package/ts_web/elements/sio-button.ts +149 -127
  80. package/ts_web/elements/sio-channel-rail.ts +256 -0
  81. package/ts_web/elements/sio-chip.ts +134 -0
  82. package/ts_web/elements/sio-cmdk.ts +461 -0
  83. package/ts_web/elements/sio-combox.ts +327 -204
  84. package/ts_web/elements/sio-composer.ts +306 -0
  85. package/ts_web/elements/sio-conversation-selector.ts +350 -228
  86. package/ts_web/elements/sio-conversation-view.ts +573 -457
  87. package/ts_web/elements/sio-dropdown-menu.ts +112 -130
  88. package/ts_web/elements/sio-fab.ts +192 -227
  89. package/ts_web/elements/sio-glass-toolbar.ts +140 -0
  90. package/ts_web/elements/sio-icon.ts +147 -25
  91. package/ts_web/elements/sio-image-lightbox.ts +62 -64
  92. package/ts_web/elements/sio-inset-list.ts +140 -0
  93. package/ts_web/elements/sio-kbd.ts +80 -0
  94. package/ts_web/elements/sio-list-row.ts +393 -0
  95. package/ts_web/elements/sio-logo-render.ts +367 -0
  96. package/ts_web/elements/sio-logo.ts +311 -0
  97. package/ts_web/elements/sio-message-input.ts +142 -221
  98. package/ts_web/elements/sio-paper-thumb.ts +244 -0
  99. package/ts_web/elements/sio-pdf-viewer.ts +58 -60
  100. package/ts_web/elements/sio-segmented.ts +183 -0
  101. package/ts_web/elements/sio-step-timeline.ts +179 -0
  102. package/ts_web/elements/sio-tab-bar.ts +195 -0
  103. package/ts_web/elements/sio-unread-badge.ts +147 -0
  104. package/ts_web/elements/sio-waveform.ts +239 -0
  105. package/ts_web/elements/tokens.ts +297 -0
  106. package/ts_web/pages/firstpage.ts +20 -1
  107. package/ts_web/pages/mainpage.ts +111 -39
  108. package/dist_bundle/bundle.js.map +0 -7
  109. package/dist_ts_web/elements/00colors.d.ts +0 -108
  110. package/dist_ts_web/elements/00colors.js +0 -137
  111. package/dist_ts_web/elements/00fonts.d.ts +0 -60
  112. package/dist_ts_web/elements/00fonts.js +0 -129
  113. package/dist_ts_web/elements/00tokens.d.ts +0 -123
  114. package/dist_ts_web/elements/00tokens.js +0 -176
  115. package/dist_ts_web/elements/sio-conversation-list.d.ts +0 -20
  116. package/dist_ts_web/elements/sio-conversation-list.js +0 -495
  117. package/dist_ts_web/elements/sio-recorder.d.ts +0 -60
  118. package/dist_ts_web/elements/sio-recorder.js +0 -173
  119. package/dist_ts_web/elements/sio-subwidget-conversations.d.ts +0 -16
  120. package/dist_ts_web/elements/sio-subwidget-conversations.js +0 -350
  121. package/dist_ts_web/elements/sio-subwidget-onboardme.d.ts +0 -7
  122. package/dist_ts_web/elements/sio-subwidget-onboardme.js +0 -243
  123. package/dist_watch/bundle.js +0 -81694
  124. package/dist_watch/bundle.js.map +0 -7
  125. package/dist_watch/index.html +0 -25
  126. package/npmextra.json +0 -19
  127. package/ts_web/elements/00colors.ts +0 -164
  128. package/ts_web/elements/00fonts.ts +0 -145
  129. package/ts_web/elements/00tokens.ts +0 -197
  130. package/ts_web/elements/sio-recorder.ts +0 -213
@@ -3,13 +3,46 @@ import {
3
3
  html,
4
4
  property,
5
5
  customElement,
6
- cssManager,
7
6
  css,
8
7
  type TemplateResult,
9
8
  } from '@design.estate/dees-element';
10
9
 
11
10
  import * as lucideIcons from 'lucide';
12
- import { createElement } from 'lucide';
11
+ import {
12
+ Archive,
13
+ Check,
14
+ ChevronDown,
15
+ ChevronLeft,
16
+ ChevronRight,
17
+ ChevronUp,
18
+ Clock,
19
+ Download,
20
+ FileText,
21
+ Forward,
22
+ Grid2x2,
23
+ Mail,
24
+ MessageCircle,
25
+ Mic,
26
+ MicOff,
27
+ MonitorUp,
28
+ Paperclip,
29
+ Pencil,
30
+ Phone,
31
+ PhoneOff,
32
+ Plus,
33
+ Reply,
34
+ Search,
35
+ Send,
36
+ Sparkles,
37
+ Star,
38
+ Trash2,
39
+ Users,
40
+ Video,
41
+ X,
42
+ createElement,
43
+ type IconNode,
44
+ } from 'lucide';
45
+ import { sioElementStyles } from './tokens.js';
13
46
 
14
47
  declare global {
15
48
  interface HTMLElementTagNameMap {
@@ -17,19 +50,86 @@ declare global {
17
50
  }
18
51
  }
19
52
 
53
+ /**
54
+ * v7 icon aliases — the design's SF-symbol-flavored names mapped onto lucide.
55
+ * Anything not listed here falls through to the PascalCase lucide lookup,
56
+ * so every lucide icon stays addressable by its kebab-case name.
57
+ */
58
+ const sioIconAliases: Record<string, IconNode> = {
59
+ // channels
60
+ envelope: Mail,
61
+ mail: Mail,
62
+ 'message-circle': MessageCircle,
63
+ phone: Phone,
64
+ 'file-text': FileText,
65
+ // unified feed / triage
66
+ 'grid-2x2': Grid2x2,
67
+ grid: Grid2x2,
68
+ sparkles: Sparkles,
69
+ star: Star,
70
+ paperclip: Paperclip,
71
+ archive: Archive,
72
+ clock: Clock,
73
+ trash: Trash2,
74
+ reply: Reply,
75
+ forward: Forward,
76
+ // composer / navigation
77
+ search: Search,
78
+ send: Send,
79
+ plus: Plus,
80
+ chevron: ChevronRight,
81
+ 'chevron-left': ChevronLeft,
82
+ 'chevron-right': ChevronRight,
83
+ 'chevron-up': ChevronUp,
84
+ 'chevron-down': ChevronDown,
85
+ // calls / meetings
86
+ mic: Mic,
87
+ 'mic-off': MicOff,
88
+ video: Video,
89
+ 'monitor-up': MonitorUp,
90
+ users: Users,
91
+ 'phone-off': PhoneOff,
92
+ // generic
93
+ check: Check,
94
+ x: X,
95
+ download: Download,
96
+ pencil: Pencil,
97
+ };
98
+
20
99
  @customElement('sio-icon')
21
100
  export class SioIcon extends DeesElement {
22
101
  public static demo = () => html`
23
- <div style="display: flex; gap: 16px; align-items: center;">
24
- <sio-icon icon="search"></sio-icon>
25
- <sio-icon icon="message-square" color="#3b82f6"></sio-icon>
26
- <sio-icon icon="x" size="32"></sio-icon>
27
- <sio-icon icon="send" strokeWidth="3"></sio-icon>
102
+ <div style="display: flex; flex-direction: column; gap: 16px; font-family: var(--sio-font-sf); color: var(--sio-label);">
103
+ <div style="display: flex; gap: 16px; align-items: center;">
104
+ <sio-icon icon="envelope" style="color: var(--sio-ch-mail);"></sio-icon>
105
+ <sio-icon icon="message-circle" style="color: var(--sio-ch-chats);"></sio-icon>
106
+ <sio-icon icon="phone" style="color: var(--sio-ch-calls);"></sio-icon>
107
+ <sio-icon icon="file-text" style="color: var(--sio-ch-letters);"></sio-icon>
108
+ <sio-icon icon="grid-2x2" style="color: var(--sio-tint);"></sio-icon>
109
+ <sio-icon icon="sparkles" style="color: var(--sio-tint);"></sio-icon>
110
+ </div>
111
+ <div style="display: flex; gap: 16px; align-items: center; color: var(--sio-label-3);">
112
+ <sio-icon icon="star" size="18"></sio-icon>
113
+ <sio-icon icon="paperclip" size="18"></sio-icon>
114
+ <sio-icon icon="archive" size="18"></sio-icon>
115
+ <sio-icon icon="clock" size="18"></sio-icon>
116
+ <sio-icon icon="reply" size="18"></sio-icon>
117
+ <sio-icon icon="forward" size="18"></sio-icon>
118
+ <sio-icon icon="trash" size="18" style="color: var(--sio-red);"></sio-icon>
119
+ </div>
120
+ <div style="display: flex; gap: 16px; align-items: center; color: var(--sio-label-2);">
121
+ <sio-icon icon="mic" size="20"></sio-icon>
122
+ <sio-icon icon="video" size="20"></sio-icon>
123
+ <sio-icon icon="monitor-up" size="20"></sio-icon>
124
+ <sio-icon icon="users" size="20"></sio-icon>
125
+ <sio-icon icon="phone-off" size="20" style="color: var(--sio-red);"></sio-icon>
126
+ <sio-icon icon="send" size="20" style="color: var(--sio-tint);"></sio-icon>
127
+ </div>
28
128
  </div>
29
129
  `;
30
130
 
31
131
  @property({ type: String })
32
- public accessor icon: string;
132
+ public accessor icon: string = '';
33
133
 
34
134
  @property({ type: Number })
35
135
  public accessor size: number = 24;
@@ -38,7 +138,7 @@ export class SioIcon extends DeesElement {
38
138
  public accessor color: string = 'currentColor';
39
139
 
40
140
  @property({ type: Number })
41
- public accessor strokeWidth: number = 2;
141
+ public accessor strokeWidth: number = 1.75;
42
142
 
43
143
  // Cache for rendered icons
44
144
  private static iconCache = new Map<string, string>();
@@ -51,7 +151,7 @@ export class SioIcon extends DeesElement {
51
151
  private lastStrokeWidth: number | null = null;
52
152
 
53
153
  public static styles = [
54
- cssManager.defaultStyles,
154
+ ...sioElementStyles,
55
155
  css`
56
156
  :host {
57
157
  display: inline-flex;
@@ -59,14 +159,15 @@ export class SioIcon extends DeesElement {
59
159
  justify-content: center;
60
160
  line-height: 1;
61
161
  vertical-align: middle;
162
+ color: currentColor;
62
163
  }
63
-
164
+
64
165
  #iconContainer {
65
166
  display: flex;
66
167
  align-items: center;
67
168
  justify-content: center;
68
169
  }
69
-
170
+
70
171
  #iconContainer svg {
71
172
  display: block;
72
173
  width: 100%;
@@ -81,6 +182,31 @@ export class SioIcon extends DeesElement {
81
182
  `;
82
183
  }
83
184
 
185
+ private resolveIconNode(): IconNode | undefined {
186
+ const iconName = this.icon
187
+ .replace(/^lucide:/, '')
188
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
189
+ .toLowerCase();
190
+
191
+ const aliasNode = sioIconAliases[iconName];
192
+ if (aliasNode) {
193
+ return aliasNode;
194
+ }
195
+
196
+ // Convert icon name to PascalCase (e.g., 'message-square' -> 'MessageSquare')
197
+ const pascalCaseName = iconName
198
+ .split('-')
199
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
200
+ .join('');
201
+
202
+ const lucideNode = (lucideIcons as Record<string, unknown>)[pascalCaseName];
203
+ if (Array.isArray(lucideNode)) {
204
+ return lucideNode as IconNode;
205
+ }
206
+
207
+ return undefined;
208
+ }
209
+
84
210
  public updated() {
85
211
  // Check if we need to update
86
212
  if (
@@ -114,33 +240,29 @@ export class SioIcon extends DeesElement {
114
240
  }
115
241
 
116
242
  try {
117
- // Convert icon name to PascalCase (e.g., 'message-square' -> 'MessageSquare')
118
- const pascalCaseName = this.icon
119
- .split('-')
120
- .map(part => part.charAt(0).toUpperCase() + part.slice(1))
121
- .join('');
122
-
123
- const iconComponent = (lucideIcons as any)[pascalCaseName];
124
- if (!iconComponent) {
125
- console.warn(`Lucide icon '${pascalCaseName}' not found`);
243
+ const iconNode = this.resolveIconNode();
244
+ if (!iconNode) {
245
+ console.warn(`sio-icon: lucide icon '${this.icon}' not found`);
126
246
  return;
127
247
  }
128
248
 
129
249
  // Create the icon element
130
- const svgElement = createElement(iconComponent, {
250
+ const svgElement = createElement(iconNode, {
131
251
  size: this.size,
132
252
  color: this.color,
133
253
  strokeWidth: this.strokeWidth,
134
254
  });
135
255
 
136
256
  if (svgElement) {
257
+ svgElement.setAttribute('aria-hidden', 'true');
258
+
137
259
  // Cache the result
138
260
  const svgString = svgElement.outerHTML;
139
261
  SioIcon.iconCache.set(cacheKey, svgString);
140
-
262
+
141
263
  // Limit cache size
142
264
  if (SioIcon.iconCache.size > SioIcon.MAX_CACHE_SIZE) {
143
- const firstKey = SioIcon.iconCache.keys().next().value;
265
+ const firstKey = SioIcon.iconCache.keys().next().value!;
144
266
  SioIcon.iconCache.delete(firstKey);
145
267
  }
146
268
 
@@ -160,4 +282,4 @@ export class SioIcon extends DeesElement {
160
282
  this.lastColor = null;
161
283
  this.lastStrokeWidth = null;
162
284
  }
163
- }
285
+ }
@@ -4,19 +4,15 @@ import {
4
4
  html,
5
5
  customElement,
6
6
  type TemplateResult,
7
- cssManager,
8
7
  css,
9
- unsafeCSS,
10
8
  state,
11
9
  } from '@design.estate/dees-element';
12
10
 
13
- // Import design tokens
14
- import { colors, bdTheme } from './00colors.js';
15
- import { spacing, radius, shadows, transitions } from './00tokens.js';
16
- import { fontFamilies } from './00fonts.js';
11
+ import { sioElementStyles } from './tokens.js';
17
12
 
18
13
  // Import components
19
14
  import { SioPdfViewer } from './sio-pdf-viewer.js';
15
+ import './sio-icon.js';
20
16
  SioPdfViewer;
21
17
 
22
18
  export interface ILightboxFile {
@@ -26,9 +22,6 @@ export interface ILightboxFile {
26
22
  type?: string;
27
23
  }
28
24
 
29
- // For backwards compatibility
30
- export type ILightboxImage = ILightboxFile;
31
-
32
25
  declare global {
33
26
  interface HTMLElementTagNameMap {
34
27
  'sio-image-lightbox': SioImageLightbox;
@@ -51,13 +44,7 @@ export class SioImageLightbox extends DeesElement {
51
44
  @property({ type: Object })
52
45
  public accessor file: ILightboxFile | null = null;
53
46
 
54
- // For backwards compatibility
55
- public get image(): ILightboxFile | null {
56
- return this.file;
57
- }
58
- public set image(value: ILightboxFile | null) {
59
- this.file = value;
60
- }
47
+ private closeCleanupTimeout: ReturnType<typeof setTimeout> | null = null;
61
48
 
62
49
  @state()
63
50
  private accessor fileLoaded: boolean = false;
@@ -76,14 +63,14 @@ export class SioImageLightbox extends DeesElement {
76
63
  private startY: number = 0;
77
64
 
78
65
  public static styles = [
79
- cssManager.defaultStyles,
66
+ ...sioElementStyles,
80
67
  css`
81
68
  :host {
82
69
  position: fixed;
83
70
  inset: 0;
84
71
  z-index: 10000;
85
72
  pointer-events: none;
86
- font-family: ${unsafeCSS(fontFamilies.sans)};
73
+ font-family: var(--sio-font-sf);
87
74
  isolation: isolate;
88
75
  }
89
76
 
@@ -112,7 +99,7 @@ export class SioImageLightbox extends DeesElement {
112
99
  display: flex;
113
100
  align-items: center;
114
101
  justify-content: center;
115
- padding: ${unsafeCSS(spacing["8"])};
102
+ padding: 32px;
116
103
  pointer-events: none;
117
104
  opacity: 0;
118
105
  transform: scale(0.9);
@@ -148,8 +135,8 @@ export class SioImageLightbox extends DeesElement {
148
135
  display: block;
149
136
  max-width: 100%;
150
137
  max-height: 90vh;
151
- border-radius: ${unsafeCSS(radius.lg)};
152
- box-shadow: ${unsafeCSS(shadows["2xl"])};
138
+ border-radius: var(--sio-radius-lg);
139
+ box-shadow: 0 32px 64px -12px rgba(0, 0, 0, 0.35);
153
140
  opacity: 0;
154
141
  transition: opacity 300ms ease;
155
142
  }
@@ -157,13 +144,13 @@ export class SioImageLightbox extends DeesElement {
157
144
  .image.loaded {
158
145
  opacity: 1;
159
146
  }
160
-
147
+
161
148
  .pdf-viewer {
162
149
  width: 90vw;
163
150
  height: 90vh;
164
- border-radius: ${unsafeCSS(radius.lg)};
165
- box-shadow: ${unsafeCSS(shadows["2xl"])};
166
- background: white;
151
+ border-radius: var(--sio-radius-lg);
152
+ box-shadow: 0 32px 64px -12px rgba(0, 0, 0, 0.35);
153
+ background: var(--sio-surface);
167
154
  opacity: 0;
168
155
  transition: opacity 300ms ease;
169
156
  border: none;
@@ -178,10 +165,10 @@ export class SioImageLightbox extends DeesElement {
178
165
  top: 50%;
179
166
  left: 50%;
180
167
  transform: translate(-50%, -50%);
181
- color: white;
168
+ color: #fff; /* on-scrim constant */
182
169
  display: flex;
183
170
  align-items: center;
184
- gap: ${unsafeCSS(spacing["2"])};
171
+ gap: 8px;
185
172
  }
186
173
 
187
174
  .spinner {
@@ -199,10 +186,10 @@ export class SioImageLightbox extends DeesElement {
199
186
 
200
187
  .controls {
201
188
  position: absolute;
202
- top: ${unsafeCSS(spacing["4"])};
203
- right: ${unsafeCSS(spacing["4"])};
189
+ top: 16px;
190
+ right: 16px;
204
191
  display: flex;
205
- gap: ${unsafeCSS(spacing["2"])};
192
+ gap: 8px;
206
193
  opacity: 0;
207
194
  transition: opacity 200ms ease;
208
195
  z-index: 10;
@@ -215,17 +202,17 @@ export class SioImageLightbox extends DeesElement {
215
202
  .control-button {
216
203
  width: 40px;
217
204
  height: 40px;
218
- border-radius: ${unsafeCSS(radius.full)};
219
- background: rgba(0, 0, 0, 0.5);
220
- backdrop-filter: blur(10px);
221
- -webkit-backdrop-filter: blur(10px);
222
- border: 1px solid rgba(255, 255, 255, 0.1);
223
- color: white;
205
+ border-radius: 50%;
206
+ background: rgba(0, 0, 0, 0.5); /* scrim glass */
207
+ backdrop-filter: blur(28px) saturate(180%);
208
+ -webkit-backdrop-filter: blur(28px) saturate(180%);
209
+ border: var(--sio-hairline) solid rgba(255, 255, 255, 0.1);
210
+ color: #fff; /* on-scrim constant */
224
211
  display: flex;
225
212
  align-items: center;
226
213
  justify-content: center;
227
214
  cursor: pointer;
228
- transition: ${unsafeCSS(transitions.all)};
215
+ transition: all 150ms ease;
229
216
  }
230
217
 
231
218
  .control-button:hover {
@@ -239,16 +226,16 @@ export class SioImageLightbox extends DeesElement {
239
226
 
240
227
  .info {
241
228
  position: absolute;
242
- bottom: ${unsafeCSS(spacing["4"])};
243
- left: ${unsafeCSS(spacing["4"])};
244
- right: ${unsafeCSS(spacing["4"])};
245
- background: rgba(0, 0, 0, 0.7);
246
- backdrop-filter: blur(10px);
247
- -webkit-backdrop-filter: blur(10px);
248
- border: 1px solid rgba(255, 255, 255, 0.1);
249
- border-radius: ${unsafeCSS(radius.lg)};
250
- padding: ${unsafeCSS(spacing["3"])} ${unsafeCSS(spacing["4"])};
251
- color: white;
229
+ bottom: 16px;
230
+ left: 16px;
231
+ right: 16px;
232
+ background: rgba(0, 0, 0, 0.7); /* scrim glass */
233
+ backdrop-filter: blur(28px) saturate(180%);
234
+ -webkit-backdrop-filter: blur(28px) saturate(180%);
235
+ border: var(--sio-hairline) solid rgba(255, 255, 255, 0.1);
236
+ border-radius: var(--sio-radius-lg);
237
+ padding: 12px 16px;
238
+ color: #fff; /* on-scrim constant */
252
239
  display: flex;
253
240
  justify-content: space-between;
254
241
  align-items: center;
@@ -265,27 +252,29 @@ export class SioImageLightbox extends DeesElement {
265
252
 
266
253
  .info-name {
267
254
  font-weight: 500;
268
- font-size: 0.9375rem;
255
+ font-size: 15px;
256
+ letter-spacing: -0.24px;
269
257
  }
270
258
 
271
259
  .info-actions {
272
260
  display: flex;
273
- gap: ${unsafeCSS(spacing["3"])};
261
+ gap: 12px;
274
262
  }
275
263
 
276
264
  .info-button {
277
265
  background: none;
278
266
  border: none;
279
- color: white;
267
+ color: #fff; /* on-scrim constant */
280
268
  opacity: 0.8;
281
269
  cursor: pointer;
282
270
  display: flex;
283
271
  align-items: center;
284
- gap: ${unsafeCSS(spacing["1"])};
285
- font-size: 0.875rem;
286
- padding: ${unsafeCSS(spacing["1"])} ${unsafeCSS(spacing["2"])};
287
- border-radius: ${unsafeCSS(radius.md)};
288
- transition: ${unsafeCSS(transitions.all)};
272
+ gap: 4px;
273
+ font-size: 13px;
274
+ font-family: inherit;
275
+ padding: 4px 8px;
276
+ border-radius: var(--sio-radius-sm);
277
+ transition: all 150ms ease;
289
278
  }
290
279
 
291
280
  .info-button:hover {
@@ -295,19 +284,19 @@ export class SioImageLightbox extends DeesElement {
295
284
 
296
285
  @media (max-width: 600px) {
297
286
  .container {
298
- padding: ${unsafeCSS(spacing["4"])};
287
+ padding: 16px;
299
288
  }
300
289
 
301
290
  .controls {
302
- top: ${unsafeCSS(spacing["2"])};
303
- right: ${unsafeCSS(spacing["2"])};
291
+ top: 8px;
292
+ right: 8px;
304
293
  }
305
294
 
306
295
  .info {
307
- bottom: ${unsafeCSS(spacing["2"])};
308
- left: ${unsafeCSS(spacing["2"])};
309
- right: ${unsafeCSS(spacing["2"])};
310
- padding: ${unsafeCSS(spacing["2"])} ${unsafeCSS(spacing["3"])};
296
+ bottom: 8px;
297
+ left: 8px;
298
+ right: 8px;
299
+ padding: 8px 12px;
311
300
  }
312
301
  }
313
302
  `,
@@ -400,7 +389,11 @@ export class SioImageLightbox extends DeesElement {
400
389
  `;
401
390
  }
402
391
 
403
- public async open(file: ILightboxFile | ILightboxImage) {
392
+ public async open(file: ILightboxFile) {
393
+ if (this.closeCleanupTimeout) {
394
+ clearTimeout(this.closeCleanupTimeout);
395
+ this.closeCleanupTimeout = null;
396
+ }
404
397
  this.file = file;
405
398
  this.fileLoaded = false;
406
399
  this.resetZoom();
@@ -432,7 +425,8 @@ export class SioImageLightbox extends DeesElement {
432
425
  }));
433
426
 
434
427
  // Clean up after animation
435
- setTimeout(() => {
428
+ this.closeCleanupTimeout = setTimeout(() => {
429
+ this.closeCleanupTimeout = null;
436
430
  this.file = null;
437
431
  this.fileLoaded = false;
438
432
  this.resetZoom();
@@ -516,5 +510,9 @@ export class SioImageLightbox extends DeesElement {
516
510
  public async disconnectedCallback() {
517
511
  await super.disconnectedCallback();
518
512
  document.removeEventListener('keydown', this.handleKeyDown);
513
+ if (this.closeCleanupTimeout) {
514
+ clearTimeout(this.closeCleanupTimeout);
515
+ this.closeCleanupTimeout = null;
516
+ }
519
517
  }
520
518
  }
@@ -0,0 +1,140 @@
1
+ import {
2
+ DeesElement,
3
+ html,
4
+ property,
5
+ customElement,
6
+ css,
7
+ type TemplateResult,
8
+ } from '@design.estate/dees-element';
9
+ import { sioElementStyles } from './tokens.js';
10
+ import './sio-list-row.js';
11
+
12
+ declare global {
13
+ interface HTMLElementTagNameMap {
14
+ 'sio-inset-list': SioInsetList;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * sio-inset-list — iOS grouped ("inset") card list container
20
+ * (design source: SIORowMobile groups in SocialIOiOS.jsx).
21
+ *
22
+ * Rounds children into an 18px card on the grouped canvas with 16px side
23
+ * margins (mobile), separates them with 0.5px inset hairlines, and takes an
24
+ * optional uppercase section header at the 32px inset.
25
+ *
26
+ * Separators: `sio-list-row` children draw their own text-aligned inset
27
+ * hairline (auto-hidden on the last row); all other children get a plain
28
+ * hairline between siblings from this container.
29
+ */
30
+ @customElement('sio-inset-list')
31
+ export class SioInsetList extends DeesElement {
32
+ public static demo = () => html`
33
+ <div style="max-width: 420px; background: var(--sio-bg); padding: 18px 0; font-family: var(--sio-font-sf); border-radius: 12px;">
34
+ <sio-inset-list header="Today">
35
+ <sio-list-row
36
+ unread
37
+ title="Maya Lindqvist"
38
+ time="09:41"
39
+ subject="Q3 numbers ahead of the board call"
40
+ preview="Attached the deck — the growth slide still needs your revenue split before Thursday."
41
+ density="comfortable"
42
+ >
43
+ <span
44
+ slot="avatar"
45
+ style="width: 30px; height: 30px; border-radius: 50%; background: var(--sio-ch-mail); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; letter-spacing: -0.2px;"
46
+ >ML</span>
47
+ </sio-list-row>
48
+ <sio-list-row
49
+ unread
50
+ title="Jonas Weber"
51
+ time="08:12"
52
+ subject="Launch copy — final review"
53
+ preview="I folded your edits in. One open question on the pricing line."
54
+ density="comfortable"
55
+ >
56
+ <span
57
+ slot="avatar"
58
+ style="width: 30px; height: 30px; border-radius: 50%; background: var(--sio-ch-chats); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; letter-spacing: -0.2px;"
59
+ >JW</span>
60
+ </sio-list-row>
61
+ <sio-list-row
62
+ title="Deutsche Post"
63
+ time="Yesterday"
64
+ subject="Letter scanned: Finanzamt München"
65
+ preview="2 pages · OCR ready · deadline detected: Jul 24"
66
+ density="comfortable"
67
+ >
68
+ <span
69
+ slot="avatar"
70
+ style="width: 30px; height: 30px; border-radius: 50%; background: var(--sio-ch-letters); color: #fff; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; letter-spacing: -0.2px;"
71
+ >DP</span>
72
+ </sio-list-row>
73
+ </sio-inset-list>
74
+ <div style="height: 18px;"></div>
75
+ <sio-inset-list header="Notifications">
76
+ <div style="padding: 12px 16px; font-size: 15px; color: var(--sio-label); display: flex; align-items: center;">
77
+ <span style="flex: 1;">Priority only</span>
78
+ <span style="font-size: 15px; color: var(--sio-label-3);">On</span>
79
+ </div>
80
+ <div style="padding: 12px 16px; font-size: 15px; color: var(--sio-label); display: flex; align-items: center;">
81
+ <span style="flex: 1;">Quiet hours</span>
82
+ <span style="font-size: 15px; color: var(--sio-label-3);">22:00 – 07:00</span>
83
+ </div>
84
+ <div style="padding: 12px 16px; font-size: 15px; color: var(--sio-tint);">Add exception…</div>
85
+ </sio-inset-list>
86
+ </div>
87
+ `;
88
+
89
+ /** Optional uppercase section header rendered above the card at the 32px inset. */
90
+ @property({ type: String })
91
+ public accessor header = '';
92
+
93
+ /** Drops the 16px side margins (embedding in desktop columns). */
94
+ @property({ type: Boolean, reflect: true })
95
+ public accessor flush = false;
96
+
97
+ public static styles = [
98
+ ...sioElementStyles,
99
+ css`
100
+ :host {
101
+ display: block;
102
+ font-family: var(--sio-font-sf);
103
+ }
104
+ .section-header {
105
+ padding: 6px 32px;
106
+ font-size: 13px;
107
+ font-weight: 600;
108
+ color: var(--sio-label-3);
109
+ letter-spacing: -0.08px;
110
+ text-transform: uppercase;
111
+ }
112
+ :host([flush]) .section-header {
113
+ padding: 6px 16px;
114
+ }
115
+ .card {
116
+ background: var(--sio-surface);
117
+ margin: 0 16px;
118
+ border-radius: 18px;
119
+ overflow: hidden;
120
+ }
121
+ :host([flush]) .card {
122
+ margin: 0;
123
+ }
124
+ /* plain hairline between non-row children; sio-list-row draws its own
125
+ inset hairline and hides it on :last-child itself */
126
+ ::slotted(:not(sio-list-row):not(:last-child)) {
127
+ border-bottom: var(--sio-hairline) solid var(--sio-separator);
128
+ }
129
+ `,
130
+ ];
131
+
132
+ public render(): TemplateResult {
133
+ return html`
134
+ ${this.header ? html`<div class="section-header">${this.header}</div>` : html``}
135
+ <div class="card">
136
+ <slot></slot>
137
+ </div>
138
+ `;
139
+ }
140
+ }