@signalwire/web-components 1.0.0-dev-20260428141127 → 1.0.0-dev-20260428183200

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 (187) hide show
  1. package/README.md +45 -52
  2. package/dist/_virtual/_commonjsHelpers.js +9 -0
  3. package/dist/_virtual/_commonjsHelpers.js.map +1 -0
  4. package/dist/_virtual/prism-python.js +28 -0
  5. package/dist/_virtual/prism-python.js.map +1 -0
  6. package/dist/_virtual/prism-python2.js +5 -0
  7. package/dist/_virtual/prism-python2.js.map +1 -0
  8. package/dist/_virtual/prism-typescript.js +28 -0
  9. package/dist/_virtual/prism-typescript.js.map +1 -0
  10. package/dist/_virtual/prism-typescript2.js +5 -0
  11. package/dist/_virtual/prism-typescript2.js.map +1 -0
  12. package/dist/_virtual/prism.js +28 -0
  13. package/dist/_virtual/prism.js.map +1 -0
  14. package/dist/_virtual/prism2.js +5 -0
  15. package/dist/_virtual/prism2.js.map +1 -0
  16. package/dist/assets/sw_background.webp.js +5 -0
  17. package/dist/assets/sw_background.webp.js.map +1 -0
  18. package/dist/components/UI/DEFAULT_BACKGROUND.d.ts +4 -0
  19. package/dist/components/UI/DEFAULT_BACKGROUND.d.ts.map +1 -0
  20. package/dist/components/UI/DEFAULT_BACKGROUND.js +5 -0
  21. package/dist/components/UI/DEFAULT_BACKGROUND.js.map +1 -0
  22. package/dist/components/UI/controls/sw-ui-control-bar.d.ts +114 -0
  23. package/dist/components/UI/controls/sw-ui-control-bar.d.ts.map +1 -0
  24. package/dist/components/UI/controls/sw-ui-control-bar.js +324 -0
  25. package/dist/components/UI/controls/sw-ui-control-bar.js.map +1 -0
  26. package/dist/components/UI/controls/sw-ui-dialpad.d.ts +57 -0
  27. package/dist/components/UI/controls/sw-ui-dialpad.d.ts.map +1 -0
  28. package/dist/components/UI/controls/sw-ui-dialpad.js +319 -0
  29. package/dist/components/UI/controls/sw-ui-dialpad.js.map +1 -0
  30. package/dist/components/UI/controls/sw-ui-dropup.d.ts +42 -0
  31. package/dist/components/UI/controls/sw-ui-dropup.d.ts.map +1 -0
  32. package/dist/components/UI/controls/sw-ui-dropup.js +137 -0
  33. package/dist/components/UI/controls/sw-ui-dropup.js.map +1 -0
  34. package/dist/components/UI/controls/sw-ui-split-button.d.ts +44 -0
  35. package/dist/components/UI/controls/sw-ui-split-button.d.ts.map +1 -0
  36. package/dist/components/UI/controls/sw-ui-split-button.js +177 -0
  37. package/dist/components/UI/controls/sw-ui-split-button.js.map +1 -0
  38. package/dist/components/UI/icons/backspace.svg.js +10 -0
  39. package/dist/components/UI/icons/backspace.svg.js.map +1 -0
  40. package/dist/components/UI/icons/camera-off.svg.js +8 -0
  41. package/dist/components/UI/icons/camera-off.svg.js.map +1 -0
  42. package/dist/components/UI/icons/camera-on.svg.js +8 -0
  43. package/dist/components/UI/icons/camera-on.svg.js.map +1 -0
  44. package/dist/components/UI/icons/check-circle.svg.js +6 -0
  45. package/dist/components/UI/icons/check-circle.svg.js.map +1 -0
  46. package/dist/components/UI/icons/chevron-up.svg.js +8 -0
  47. package/dist/components/UI/icons/chevron-up.svg.js.map +1 -0
  48. package/dist/components/UI/icons/close.svg.js +6 -0
  49. package/dist/components/UI/icons/close.svg.js.map +1 -0
  50. package/dist/components/UI/icons/copy.svg.js +6 -0
  51. package/dist/components/UI/icons/copy.svg.js.map +1 -0
  52. package/dist/components/UI/icons/download.svg.js +6 -0
  53. package/dist/components/UI/icons/download.svg.js.map +1 -0
  54. package/dist/components/UI/icons/fullscreen-exit.svg.js +8 -0
  55. package/dist/components/UI/icons/fullscreen-exit.svg.js.map +1 -0
  56. package/dist/components/UI/icons/fullscreen.svg.js +8 -0
  57. package/dist/components/UI/icons/fullscreen.svg.js.map +1 -0
  58. package/dist/components/UI/icons/hand-raise.svg.js +6 -0
  59. package/dist/components/UI/icons/hand-raise.svg.js.map +1 -0
  60. package/dist/components/UI/icons/icons.d.ts +31 -0
  61. package/dist/components/UI/icons/icons.d.ts.map +1 -0
  62. package/dist/components/UI/icons/icons.js +60 -0
  63. package/dist/components/UI/icons/icons.js.map +1 -0
  64. package/dist/components/UI/icons/index.d.ts +4 -0
  65. package/dist/components/UI/icons/index.d.ts.map +1 -0
  66. package/dist/components/UI/icons/info-circle.svg.js +6 -0
  67. package/dist/components/UI/icons/info-circle.svg.js.map +1 -0
  68. package/dist/components/UI/icons/mic-off.svg.js +8 -0
  69. package/dist/components/UI/icons/mic-off.svg.js.map +1 -0
  70. package/dist/components/UI/icons/mic-on.svg.js +8 -0
  71. package/dist/components/UI/icons/mic-on.svg.js.map +1 -0
  72. package/dist/components/UI/icons/person.svg.js +8 -0
  73. package/dist/components/UI/icons/person.svg.js.map +1 -0
  74. package/dist/components/UI/icons/phone-call.svg.js +8 -0
  75. package/dist/components/UI/icons/phone-call.svg.js.map +1 -0
  76. package/dist/components/UI/icons/phone-end.svg.js +8 -0
  77. package/dist/components/UI/icons/phone-end.svg.js.map +1 -0
  78. package/dist/components/UI/icons/room.svg.js +8 -0
  79. package/dist/components/UI/icons/room.svg.js.map +1 -0
  80. package/dist/components/UI/icons/screen-share-off.svg.js +9 -0
  81. package/dist/components/UI/icons/screen-share-off.svg.js.map +1 -0
  82. package/dist/components/UI/icons/screen-share.svg.js +9 -0
  83. package/dist/components/UI/icons/screen-share.svg.js.map +1 -0
  84. package/dist/components/UI/icons/sendIcon.svg.js +9 -0
  85. package/dist/components/UI/icons/sendIcon.svg.js.map +1 -0
  86. package/dist/components/UI/icons/settings.svg.js +8 -0
  87. package/dist/components/UI/icons/settings.svg.js.map +1 -0
  88. package/dist/components/UI/icons/speaker-off.svg.js +8 -0
  89. package/dist/components/UI/icons/speaker-off.svg.js.map +1 -0
  90. package/dist/components/UI/icons/speaker-on.svg.js +8 -0
  91. package/dist/components/UI/icons/speaker-on.svg.js.map +1 -0
  92. package/dist/components/UI/icons/spinner.svg.js +9 -0
  93. package/dist/components/UI/icons/spinner.svg.js.map +1 -0
  94. package/dist/components/UI/icons/sw-logo.svg.js +11 -0
  95. package/dist/components/UI/icons/sw-logo.svg.js.map +1 -0
  96. package/dist/components/UI/icons/sw-ui-icon.d.ts +28 -0
  97. package/dist/components/UI/icons/sw-ui-icon.d.ts.map +1 -0
  98. package/dist/components/UI/icons/sw-ui-icon.js +47 -0
  99. package/dist/components/UI/icons/sw-ui-icon.js.map +1 -0
  100. package/dist/components/UI/icons/transcript.svg.js +10 -0
  101. package/dist/components/UI/icons/transcript.svg.js.map +1 -0
  102. package/dist/components/UI/index.d.ts +18 -0
  103. package/dist/components/UI/index.d.ts.map +1 -0
  104. package/dist/components/UI/layout/sw-ui-background.d.ts +33 -0
  105. package/dist/components/UI/layout/sw-ui-background.d.ts.map +1 -0
  106. package/dist/components/UI/layout/sw-ui-background.js +106 -0
  107. package/dist/components/UI/layout/sw-ui-background.js.map +1 -0
  108. package/dist/components/UI/layout/sw-ui-call-layout.d.ts +69 -0
  109. package/dist/components/UI/layout/sw-ui-call-layout.d.ts.map +1 -0
  110. package/dist/components/UI/layout/sw-ui-call-layout.js +278 -0
  111. package/dist/components/UI/layout/sw-ui-call-layout.js.map +1 -0
  112. package/dist/components/UI/layout/sw-ui-content-drawer.d.ts +50 -0
  113. package/dist/components/UI/layout/sw-ui-content-drawer.d.ts.map +1 -0
  114. package/dist/components/UI/layout/sw-ui-content-drawer.js +413 -0
  115. package/dist/components/UI/layout/sw-ui-content-drawer.js.map +1 -0
  116. package/dist/components/UI/layout/sw-ui-modal.d.ts +31 -0
  117. package/dist/components/UI/layout/sw-ui-modal.d.ts.map +1 -0
  118. package/dist/components/UI/layout/sw-ui-modal.js +150 -0
  119. package/dist/components/UI/layout/sw-ui-modal.js.map +1 -0
  120. package/dist/components/UI/layout/sw-ui-responsive-container.d.ts +15 -0
  121. package/dist/components/UI/layout/sw-ui-responsive-container.d.ts.map +1 -0
  122. package/dist/components/UI/layout/sw-ui-responsive-container.js +78 -0
  123. package/dist/components/UI/layout/sw-ui-responsive-container.js.map +1 -0
  124. package/dist/components/UI/sw-ui-alert.d.ts +37 -0
  125. package/dist/components/UI/sw-ui-alert.d.ts.map +1 -0
  126. package/dist/components/UI/sw-ui-alert.js +126 -0
  127. package/dist/components/UI/sw-ui-alert.js.map +1 -0
  128. package/dist/components/UI/sw-ui-transcript-view.d.ts +56 -0
  129. package/dist/components/UI/sw-ui-transcript-view.d.ts.map +1 -0
  130. package/dist/components/UI/sw-ui-transcript-view.js +341 -0
  131. package/dist/components/UI/sw-ui-transcript-view.js.map +1 -0
  132. package/dist/components/directory.d.ts +10 -18
  133. package/dist/components/directory.d.ts.map +1 -1
  134. package/dist/components/directory.js +129 -198
  135. package/dist/components/directory.js.map +1 -1
  136. package/dist/embed/signalwire-web-components-embed.iife.js +2336 -982
  137. package/dist/embed/signalwire-web-components-embed.iife.js.map +1 -1
  138. package/dist/embed/signalwire-web-components-embed.umd.cjs +2336 -982
  139. package/dist/embed/signalwire-web-components-embed.umd.cjs.map +1 -1
  140. package/dist/embed.d.ts +1 -1
  141. package/dist/embed.d.ts.map +1 -1
  142. package/dist/index.d.ts +2 -3
  143. package/dist/index.d.ts.map +1 -1
  144. package/dist/index.js +54 -33
  145. package/dist/index.js.map +1 -1
  146. package/dist/node_modules/dompurify/dist/purify.es.js +597 -0
  147. package/dist/node_modules/dompurify/dist/purify.es.js.map +1 -0
  148. package/dist/node_modules/marked/lib/marked.esm.js +1475 -0
  149. package/dist/node_modules/marked/lib/marked.esm.js.map +1 -0
  150. package/dist/node_modules/prismjs/components/prism-bash.js +220 -0
  151. package/dist/node_modules/prismjs/components/prism-bash.js.map +1 -0
  152. package/dist/node_modules/prismjs/components/prism-css.js +56 -0
  153. package/dist/node_modules/prismjs/components/prism-css.js.map +1 -0
  154. package/dist/node_modules/prismjs/components/prism-javascript.js +138 -0
  155. package/dist/node_modules/prismjs/components/prism-javascript.js.map +1 -0
  156. package/dist/node_modules/prismjs/components/prism-json.js +26 -0
  157. package/dist/node_modules/prismjs/components/prism-json.js.map +1 -0
  158. package/dist/node_modules/prismjs/components/prism-markdown.js +301 -0
  159. package/dist/node_modules/prismjs/components/prism-markdown.js.map +1 -0
  160. package/dist/node_modules/prismjs/components/prism-python.js +69 -0
  161. package/dist/node_modules/prismjs/components/prism-python.js.map +1 -0
  162. package/dist/node_modules/prismjs/components/prism-sql.js +34 -0
  163. package/dist/node_modules/prismjs/components/prism-sql.js.map +1 -0
  164. package/dist/node_modules/prismjs/components/prism-typescript.js +53 -0
  165. package/dist/node_modules/prismjs/components/prism-typescript.js.map +1 -0
  166. package/dist/node_modules/prismjs/components/prism-yaml.js +67 -0
  167. package/dist/node_modules/prismjs/components/prism-yaml.js.map +1 -0
  168. package/dist/node_modules/prismjs/prism.js +1165 -0
  169. package/dist/node_modules/prismjs/prism.js.map +1 -0
  170. package/dist/react.d.ts +3 -3
  171. package/dist/utils/prism.d.ts +4 -0
  172. package/dist/utils/prism.d.ts.map +1 -0
  173. package/dist/utils/prism.js +34 -0
  174. package/dist/utils/prism.js.map +1 -0
  175. package/dist/utils/transcriptToMarkdown.d.ts +14 -0
  176. package/dist/utils/transcriptToMarkdown.d.ts.map +1 -0
  177. package/dist/utils/transcriptToMarkdown.js +59 -0
  178. package/dist/utils/transcriptToMarkdown.js.map +1 -0
  179. package/package.json +53 -9
  180. package/dist/components/dialpad.d.ts +0 -74
  181. package/dist/components/dialpad.d.ts.map +0 -1
  182. package/dist/components/dialpad.js +0 -372
  183. package/dist/components/dialpad.js.map +0 -1
  184. package/dist/components/example-button.d.ts +0 -21
  185. package/dist/components/example-button.d.ts.map +0 -1
  186. package/dist/components/example-button.js +0 -74
  187. package/dist/components/example-button.js.map +0 -1
@@ -0,0 +1,319 @@
1
+ import { LitElement as u, html as d, css as g } from "lit";
2
+ import { property as p, state as c, customElement as h } from "lit/decorators.js";
3
+ var b = Object.defineProperty, f = Object.getOwnPropertyDescriptor, a = (t, e, l, r) => {
4
+ for (var s = r > 1 ? void 0 : r ? f(e, l) : e, o = t.length - 1, n; o >= 0; o--)
5
+ (n = t[o]) && (s = (r ? n(e, l, s) : n(s)) || s);
6
+ return r && s && b(e, l, s), s;
7
+ };
8
+ const v = /^[0-9*#]$/, y = [
9
+ { digit: "1", letters: "" },
10
+ { digit: "2", letters: "ABC" },
11
+ { digit: "3", letters: "DEF" },
12
+ { digit: "4", letters: "GHI" },
13
+ { digit: "5", letters: "JKL" },
14
+ { digit: "6", letters: "MNO" },
15
+ { digit: "7", letters: "PQRS" },
16
+ { digit: "8", letters: "TUV" },
17
+ { digit: "9", letters: "WXYZ" },
18
+ { digit: "*", letters: "" },
19
+ { digit: "0", letters: "+" },
20
+ { digit: "#", letters: "" }
21
+ ];
22
+ let i = class extends u {
23
+ constructor() {
24
+ super(...arguments), this.showCallButton = !1, this.allowText = !1, this.placeholder = "Enter number", this.digits = "", this.pressedKey = null;
25
+ }
26
+ _pressDigit(t) {
27
+ this.digits += t, this.pressedKey = t, this.dispatchEvent(
28
+ new CustomEvent("sw-digit-press", {
29
+ detail: { digit: t, digits: this.digits },
30
+ bubbles: !0,
31
+ composed: !0
32
+ })
33
+ ), setTimeout(() => {
34
+ this.pressedKey = null;
35
+ }, 100);
36
+ }
37
+ _backspace() {
38
+ this.digits.length !== 0 && (this.digits = this.digits.slice(0, -1), this.dispatchEvent(
39
+ new CustomEvent("sw-dialpad-backspace", {
40
+ detail: { digits: this.digits },
41
+ bubbles: !0,
42
+ composed: !0
43
+ })
44
+ ));
45
+ }
46
+ _dial() {
47
+ this.digits.length !== 0 && this.dispatchEvent(
48
+ new CustomEvent("sw-dial", {
49
+ detail: { digits: this.digits },
50
+ bubbles: !0,
51
+ composed: !0
52
+ })
53
+ );
54
+ }
55
+ /**
56
+ * Handle keyboard input on the display field.
57
+ * We intercept all keys and manage state ourselves to prevent the browser
58
+ * from accumulating non-DTMF characters in the input value.
59
+ */
60
+ _onKeyDown(t) {
61
+ const { key: e } = t;
62
+ if (this.allowText) {
63
+ e === "Enter" && this.showCallButton && (t.preventDefault(), this._dial());
64
+ return;
65
+ }
66
+ v.test(e) ? (t.preventDefault(), this._pressDigit(e)) : e === "Backspace" ? (t.preventDefault(), this._backspace()) : e === "Enter" && this.showCallButton ? (t.preventDefault(), this._dial()) : e !== "Tab" && !t.ctrlKey && !t.metaKey && t.preventDefault();
67
+ }
68
+ _onInput(t) {
69
+ if (!this.allowText) return;
70
+ const e = t.target.value;
71
+ this.digits = e, this.dispatchEvent(
72
+ new CustomEvent("sw-dialpad-input", {
73
+ detail: { digits: this.digits },
74
+ bubbles: !0,
75
+ composed: !0
76
+ })
77
+ );
78
+ }
79
+ render() {
80
+ return d`
81
+ <div class="container" part="container">
82
+ <div class="display" part="display">
83
+ <input
84
+ type=${this.allowText ? "text" : "tel"}
85
+ class="display-input"
86
+ .value=${this.digits}
87
+ placeholder=${this.placeholder}
88
+ @keydown=${this._onKeyDown}
89
+ @input=${this._onInput}
90
+ aria-label="Phone number input"
91
+ />
92
+ <button
93
+ class="backspace-button"
94
+ @click=${this._backspace}
95
+ ?disabled=${this.digits.length === 0}
96
+ aria-label="Delete last digit"
97
+ >
98
+ <sw-ui-icon name="backspace" size="24"></sw-ui-icon>
99
+ </button>
100
+ </div>
101
+
102
+ <div class="keypad" part="keypad" role="group" aria-label="Telephone keypad">
103
+ ${y.map(
104
+ (t) => d`
105
+ <button
106
+ class="key ${this.pressedKey === t.digit ? "pressed" : ""}"
107
+ part="key ${this.pressedKey === t.digit ? "key-pressed" : ""}"
108
+ @click=${() => this._pressDigit(t.digit)}
109
+ aria-label="${t.digit}${t.letters ? `, ${t.letters}` : ""}"
110
+ >
111
+ <span class="key-digit">${t.digit}</span>
112
+ <span class="key-letters">${t.letters}</span>
113
+ </button>
114
+ `
115
+ )}
116
+ </div>
117
+
118
+ ${this.showCallButton ? d`
119
+ <button
120
+ class="call-button"
121
+ part="call-button"
122
+ @click=${this._dial}
123
+ ?disabled=${this.digits.length === 0}
124
+ aria-label="Call ${this.digits}"
125
+ >
126
+ <sw-ui-icon name="phone-call" size="20"></sw-ui-icon> Call
127
+ </button>
128
+ ` : null}
129
+ </div>
130
+ `;
131
+ }
132
+ };
133
+ i.styles = g`
134
+ :host {
135
+ --sw-dialpad-display-size: 32px;
136
+ --sw-dialpad-key-size: 24px;
137
+ display: block;
138
+ font-family: var(--type-family-body);
139
+ }
140
+
141
+ .container {
142
+ display: flex;
143
+ flex-direction: column;
144
+ gap: var(--sp-3);
145
+ padding: var(--sp-4);
146
+ max-width: 280px;
147
+ background: var(--bg-surface);
148
+ border-radius: var(--radius-md);
149
+ }
150
+
151
+ .display {
152
+ display: flex;
153
+ align-items: center;
154
+ justify-content: space-between;
155
+ padding: var(--sp-3) var(--sp-4);
156
+ background: var(--bg-surface-raised);
157
+ border-radius: var(--radius-md);
158
+ min-height: 48px;
159
+ }
160
+
161
+ .display-input {
162
+ flex: 1;
163
+ font-size: var(--sw-dialpad-display-size);
164
+ font-weight: 500;
165
+ font-family: var(--type-family-body);
166
+ color: var(--fg-default);
167
+ background: transparent;
168
+ border: none;
169
+ outline: none;
170
+ letter-spacing: 2px;
171
+ text-align: center;
172
+ width: 100%;
173
+ }
174
+
175
+ .display-input::placeholder {
176
+ color: var(--fg-muted);
177
+ font-size: var(--type-size-body);
178
+ letter-spacing: normal;
179
+ }
180
+
181
+ .backspace-button {
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ width: 40px;
186
+ height: 40px;
187
+ background: transparent;
188
+ border: none;
189
+ border-radius: var(--radius-md);
190
+ cursor: pointer;
191
+ color: var(--fg-muted);
192
+ transition:
193
+ background-color 0.15s ease,
194
+ color 0.15s ease;
195
+ }
196
+
197
+ .backspace-button:hover {
198
+ background: var(--interactive-dropdown-hover);
199
+ color: var(--fg-default);
200
+ }
201
+
202
+ .backspace-button:disabled {
203
+ opacity: 0.3;
204
+ cursor: not-allowed;
205
+ }
206
+
207
+ .backspace-button sw-ui-icon {
208
+ pointer-events: none;
209
+ }
210
+
211
+ .keypad {
212
+ display: grid;
213
+ grid-template-columns: repeat(3, minmax(0, 72px));
214
+ justify-content: center;
215
+ gap: var(--sp-2);
216
+ }
217
+
218
+ .key {
219
+ display: flex;
220
+ flex-direction: column;
221
+ align-items: center;
222
+ justify-content: center;
223
+ min-width: 0;
224
+ aspect-ratio: 1;
225
+ background: var(--bg-surface);
226
+ border: 1px solid var(--border-default);
227
+ border-radius: var(--radius-full);
228
+ cursor: pointer;
229
+ transition:
230
+ background-color 0.1s ease,
231
+ transform 0.1s ease;
232
+ user-select: none;
233
+ -webkit-user-select: none;
234
+ -webkit-tap-highlight-color: transparent;
235
+ }
236
+
237
+ .key:hover {
238
+ background: var(--bg-surface-raised);
239
+ }
240
+
241
+ .key:active,
242
+ .key.pressed {
243
+ background: var(--interactive-dropdown-hover);
244
+ transform: scale(0.95);
245
+ }
246
+
247
+ .key-digit {
248
+ font-size: var(--sw-dialpad-key-size);
249
+ font-weight: 500;
250
+ color: var(--fg-default);
251
+ line-height: 1;
252
+ }
253
+
254
+ .key-letters {
255
+ font-size: var(--type-size-caption);
256
+ color: var(--fg-muted);
257
+ text-transform: uppercase;
258
+ letter-spacing: 1px;
259
+ margin-top: 2px;
260
+ min-height: 14px;
261
+ }
262
+
263
+ .call-button {
264
+ display: flex;
265
+ align-items: center;
266
+ justify-content: center;
267
+ width: 100%;
268
+ height: 56px;
269
+ background: var(--interactive-status-success);
270
+ border: none;
271
+ border-radius: var(--radius-md);
272
+ cursor: pointer;
273
+ color: white;
274
+ font-size: var(--type-size-body);
275
+ font-weight: 600;
276
+ font-family: var(--type-family-body);
277
+ transition: background-color 0.15s ease;
278
+ gap: var(--sp-2);
279
+ }
280
+
281
+ .call-button:hover {
282
+ background: #0ea472;
283
+ }
284
+
285
+ .call-button:active {
286
+ background: #0d9668;
287
+ }
288
+
289
+ .call-button:disabled {
290
+ opacity: 0.5;
291
+ cursor: not-allowed;
292
+ }
293
+
294
+ .call-button sw-ui-icon {
295
+ pointer-events: none;
296
+ }
297
+ `;
298
+ a([
299
+ p({ type: Boolean, reflect: !0, attribute: "show-call-button" })
300
+ ], i.prototype, "showCallButton", 2);
301
+ a([
302
+ p({ type: Boolean, reflect: !0, attribute: "allow-text" })
303
+ ], i.prototype, "allowText", 2);
304
+ a([
305
+ p({ type: String })
306
+ ], i.prototype, "placeholder", 2);
307
+ a([
308
+ c()
309
+ ], i.prototype, "digits", 2);
310
+ a([
311
+ c()
312
+ ], i.prototype, "pressedKey", 2);
313
+ i = a([
314
+ h("sw-ui-dialpad")
315
+ ], i);
316
+ export {
317
+ i as SwUiDialpad
318
+ };
319
+ //# sourceMappingURL=sw-ui-dialpad.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sw-ui-dialpad.js","sources":["../../../../src/components/UI/controls/sw-ui-dialpad.ts"],"sourcesContent":["/**\n * Dialpad Component\n *\n * A 12-key telephone keypad (0-9, *, #) for entering phone numbers\n * and sending DTMF tones during active calls. Pure UI component — no\n * call logic. Use `sw-call-dialpad` for a version that integrates with\n * a call context.\n *\n * @example\n * ```html\n * <sw-dialpad show-call-button></sw-dialpad>\n * ```\n *\n * @fires sw-digit-press - Fired when a digit button is pressed. Detail: `{ digit: string, digits: string }`\n * @fires sw-dialpad-backspace - Fired when the backspace button is pressed. Detail: `{ digits: string }`\n * @fires sw-dial - Fired when the call button is pressed. Detail: `{ digits: string }`\n * @fires sw-dialpad-input - Fired when free-text input changes (only when `allow-text` is set). Detail: `{ digits: string }`\n *\n * @cssprop [--interactive-button-primary-bg=#044ef4] - Primary accent color.\n * @cssprop [--interactive-button-primary-hover=#0342cf] - Primary color on hover.\n * @cssprop [--interactive-status-success=#22c55e] - Success/call button color.\n * @cssprop [--interactive-button-destructive-bg=#dc2626] - Danger/hangup button color.\n * @cssprop [--bg-surface=#181a28] - Component background.\n * @cssprop [--fg-default=#f0f0f4] - Text color.\n * @cssprop [--fg-muted=#a0a0aa] - Muted text color.\n * @cssprop [--border-default=rgba(255,255,255,0.12)] - Border color.\n */\n\nimport { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport '../icons/sw-ui-icon.js';\n\nconst DTMF_PATTERN = /^[0-9*#]$/;\n\n/**\n * Key layout for standard telephone keypad\n */\nconst KEYS = [\n { digit: '1', letters: '' },\n { digit: '2', letters: 'ABC' },\n { digit: '3', letters: 'DEF' },\n { digit: '4', letters: 'GHI' },\n { digit: '5', letters: 'JKL' },\n { digit: '6', letters: 'MNO' },\n { digit: '7', letters: 'PQRS' },\n { digit: '8', letters: 'TUV' },\n { digit: '9', letters: 'WXYZ' },\n { digit: '*', letters: '' },\n { digit: '0', letters: '+' },\n { digit: '#', letters: '' }\n] as const;\n\n@customElement('sw-ui-dialpad')\nexport class SwUiDialpad extends LitElement {\n static styles = css`\n :host {\n --sw-dialpad-display-size: 32px;\n --sw-dialpad-key-size: 24px;\n display: block;\n font-family: var(--type-family-body);\n }\n\n .container {\n display: flex;\n flex-direction: column;\n gap: var(--sp-3);\n padding: var(--sp-4);\n max-width: 280px;\n background: var(--bg-surface);\n border-radius: var(--radius-md);\n }\n\n .display {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--sp-3) var(--sp-4);\n background: var(--bg-surface-raised);\n border-radius: var(--radius-md);\n min-height: 48px;\n }\n\n .display-input {\n flex: 1;\n font-size: var(--sw-dialpad-display-size);\n font-weight: 500;\n font-family: var(--type-family-body);\n color: var(--fg-default);\n background: transparent;\n border: none;\n outline: none;\n letter-spacing: 2px;\n text-align: center;\n width: 100%;\n }\n\n .display-input::placeholder {\n color: var(--fg-muted);\n font-size: var(--type-size-body);\n letter-spacing: normal;\n }\n\n .backspace-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: transparent;\n border: none;\n border-radius: var(--radius-md);\n cursor: pointer;\n color: var(--fg-muted);\n transition:\n background-color 0.15s ease,\n color 0.15s ease;\n }\n\n .backspace-button:hover {\n background: var(--interactive-dropdown-hover);\n color: var(--fg-default);\n }\n\n .backspace-button:disabled {\n opacity: 0.3;\n cursor: not-allowed;\n }\n\n .backspace-button sw-ui-icon {\n pointer-events: none;\n }\n\n .keypad {\n display: grid;\n grid-template-columns: repeat(3, minmax(0, 72px));\n justify-content: center;\n gap: var(--sp-2);\n }\n\n .key {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n min-width: 0;\n aspect-ratio: 1;\n background: var(--bg-surface);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-full);\n cursor: pointer;\n transition:\n background-color 0.1s ease,\n transform 0.1s ease;\n user-select: none;\n -webkit-user-select: none;\n -webkit-tap-highlight-color: transparent;\n }\n\n .key:hover {\n background: var(--bg-surface-raised);\n }\n\n .key:active,\n .key.pressed {\n background: var(--interactive-dropdown-hover);\n transform: scale(0.95);\n }\n\n .key-digit {\n font-size: var(--sw-dialpad-key-size);\n font-weight: 500;\n color: var(--fg-default);\n line-height: 1;\n }\n\n .key-letters {\n font-size: var(--type-size-caption);\n color: var(--fg-muted);\n text-transform: uppercase;\n letter-spacing: 1px;\n margin-top: 2px;\n min-height: 14px;\n }\n\n .call-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 56px;\n background: var(--interactive-status-success);\n border: none;\n border-radius: var(--radius-md);\n cursor: pointer;\n color: white;\n font-size: var(--type-size-body);\n font-weight: 600;\n font-family: var(--type-family-body);\n transition: background-color 0.15s ease;\n gap: var(--sp-2);\n }\n\n .call-button:hover {\n background: #0ea472;\n }\n\n .call-button:active {\n background: #0d9668;\n }\n\n .call-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .call-button sw-ui-icon {\n pointer-events: none;\n }\n `;\n\n /** Whether to display the call button below the keypad. */\n @property({ type: Boolean, reflect: true, attribute: 'show-call-button' })\n showCallButton: boolean = false;\n\n /** Allow free-text input in the display field (e.g., SIP URIs, vanity letters). Keypad buttons still append DTMF digits. */\n @property({ type: Boolean, reflect: true, attribute: 'allow-text' })\n allowText: boolean = false;\n\n /** Placeholder text shown in the digit display input. */\n @property({ type: String })\n placeholder: string = 'Enter number';\n\n @state() private digits: string = '';\n @state() private pressedKey: string | null = null;\n\n private _pressDigit(digit: string) {\n this.digits += digit;\n this.pressedKey = digit;\n\n this.dispatchEvent(\n new CustomEvent('sw-digit-press', {\n detail: { digit, digits: this.digits },\n bubbles: true,\n composed: true\n })\n );\n\n setTimeout(() => {\n this.pressedKey = null;\n }, 100);\n }\n\n private _backspace() {\n if (this.digits.length === 0) return;\n this.digits = this.digits.slice(0, -1);\n this.dispatchEvent(\n new CustomEvent('sw-dialpad-backspace', {\n detail: { digits: this.digits },\n bubbles: true,\n composed: true\n })\n );\n }\n\n private _dial() {\n if (this.digits.length === 0) return;\n this.dispatchEvent(\n new CustomEvent('sw-dial', {\n detail: { digits: this.digits },\n bubbles: true,\n composed: true\n })\n );\n }\n\n /**\n * Handle keyboard input on the display field.\n * We intercept all keys and manage state ourselves to prevent the browser\n * from accumulating non-DTMF characters in the input value.\n */\n private _onKeyDown(e: KeyboardEvent) {\n const { key } = e;\n\n if (this.allowText) {\n if (key === 'Enter' && this.showCallButton) {\n e.preventDefault();\n this._dial();\n }\n return;\n }\n\n if (DTMF_PATTERN.test(key)) {\n e.preventDefault();\n this._pressDigit(key);\n } else if (key === 'Backspace') {\n e.preventDefault();\n this._backspace();\n } else if (key === 'Enter' && this.showCallButton) {\n e.preventDefault();\n this._dial();\n } else if (key !== 'Tab' && !e.ctrlKey && !e.metaKey) {\n // Block all other printable characters\n e.preventDefault();\n }\n }\n\n private _onInput(e: Event) {\n if (!this.allowText) return;\n const value = (e.target as HTMLInputElement).value;\n this.digits = value;\n this.dispatchEvent(\n new CustomEvent('sw-dialpad-input', {\n detail: { digits: this.digits },\n bubbles: true,\n composed: true\n })\n );\n }\n\n render() {\n return html`\n <div class=\"container\" part=\"container\">\n <div class=\"display\" part=\"display\">\n <input\n type=${this.allowText ? 'text' : 'tel'}\n class=\"display-input\"\n .value=${this.digits}\n placeholder=${this.placeholder}\n @keydown=${this._onKeyDown}\n @input=${this._onInput}\n aria-label=\"Phone number input\"\n />\n <button\n class=\"backspace-button\"\n @click=${this._backspace}\n ?disabled=${this.digits.length === 0}\n aria-label=\"Delete last digit\"\n >\n <sw-ui-icon name=\"backspace\" size=\"24\"></sw-ui-icon>\n </button>\n </div>\n\n <div class=\"keypad\" part=\"keypad\" role=\"group\" aria-label=\"Telephone keypad\">\n ${KEYS.map(\n (key) => html`\n <button\n class=\"key ${this.pressedKey === key.digit ? 'pressed' : ''}\"\n part=\"key ${this.pressedKey === key.digit ? 'key-pressed' : ''}\"\n @click=${() => this._pressDigit(key.digit)}\n aria-label=\"${key.digit}${key.letters ? `, ${key.letters}` : ''}\"\n >\n <span class=\"key-digit\">${key.digit}</span>\n <span class=\"key-letters\">${key.letters}</span>\n </button>\n `\n )}\n </div>\n\n ${this.showCallButton\n ? html`\n <button\n class=\"call-button\"\n part=\"call-button\"\n @click=${this._dial}\n ?disabled=${this.digits.length === 0}\n aria-label=\"Call ${this.digits}\"\n >\n <sw-ui-icon name=\"phone-call\" size=\"20\"></sw-ui-icon> Call\n </button>\n `\n : null}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-ui-dialpad': SwUiDialpad;\n }\n}\n"],"names":["DTMF_PATTERN","KEYS","SwUiDialpad","LitElement","digit","e","key","value","html","css","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { LitElement } from 'lit';
2
+ export type DropUpItem = {
3
+ label: string;
4
+ id: string;
5
+ selected?: boolean;
6
+ };
7
+ /**
8
+ * Dropdown (opens upward) menu anchored to a trigger element.
9
+ *
10
+ * @fires sw-dropup-select - User picked an item. `detail` is the selected `DropUpItem`.
11
+ * @fires sw-dropup-close - Outside click closed the menu.
12
+ *
13
+ * @cssprop --sw-dropup-offset [4px] - gap between anchor and menu
14
+ * @cssprop --sw-dropup-max-width [200px] - maximum menu width
15
+ * @cssprop --sw-dropup-bg [#1f2937] - menu background
16
+ * @cssprop --sw-dropup-border [1px solid rgba(255,255,255,0.1)] - menu border
17
+ * @cssprop --sw-dropup-radius [8px] - menu border-radius
18
+ * @cssprop --sw-dropup-shadow [0 4px 12px rgba(0,0,0,0.4)] - menu box-shadow
19
+ * @cssprop --sw-dropup-color [#e5e7eb] - item text colour
20
+ * @cssprop --sw-dropup-item-hover [rgba(255,255,255,0.08)] - item hover background
21
+ * @cssprop --sw-dropup-item-active [rgba(255,255,255,0.15)] - selected item background
22
+ */
23
+ export declare class SwUiDropup extends LitElement {
24
+ static styles: import("lit").CSSResult;
25
+ items: Array<DropUpItem | string>;
26
+ open: boolean;
27
+ anchor?: Element;
28
+ private _menu;
29
+ private _outsideClickHandler;
30
+ updated(changed: Map<string, unknown>): void;
31
+ private _positionToAnchor;
32
+ disconnectedCallback(): void;
33
+ private normalizeItem;
34
+ private onSelect;
35
+ render(): import("lit-html").TemplateResult<1>;
36
+ }
37
+ declare global {
38
+ interface HTMLElementTagNameMap {
39
+ 'sw-ui-dropup': SwUiDropup;
40
+ }
41
+ }
42
+ //# sourceMappingURL=sw-ui-dropup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sw-ui-dropup.d.ts","sourceRoot":"","sources":["../../../../src/components/UI/controls/sw-ui-dropup.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAGrD,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE3E;;;;;;;;;;;;;;;GAeG;AACH,qBACa,UAAW,SAAQ,UAAU;IACxC,MAAM,CAAC,MAAM,0BA2CX;IAmBF,KAAK,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,CAAM;IAGvC,IAAI,UAAS;IAIb,MAAM,CAAC,EAAE,OAAO,CAAC;IAGjB,OAAO,CAAC,KAAK,CAAe;IAE5B,OAAO,CAAC,oBAAoB,CAK1B;IAEF,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;IAarC,OAAO,CAAC,iBAAiB;IAWzB,oBAAoB;IAKpB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,QAAQ;IAehB,MAAM;CAkBP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,cAAc,EAAE,UAAU,CAAC;KAC5B;CACF"}
@@ -0,0 +1,137 @@
1
+ import { LitElement as c, html as d, nothing as p, css as m } from "lit";
2
+ import { property as u, query as h, customElement as f } from "lit/decorators.js";
3
+ var b = Object.defineProperty, v = Object.getOwnPropertyDescriptor, i = (e, t, s, o) => {
4
+ for (var r = o > 1 ? void 0 : o ? v(t, s) : t, a = e.length - 1, l; a >= 0; a--)
5
+ (l = e[a]) && (r = (o ? l(t, s, r) : l(r)) || r);
6
+ return o && r && b(t, s, r), r;
7
+ };
8
+ let n = class extends c {
9
+ constructor() {
10
+ super(...arguments), this.items = [], this.open = !1, this._outsideClickHandler = (e) => {
11
+ const t = e.composedPath();
12
+ !t.includes(this) && (!this.anchor || !t.includes(this.anchor)) && this.dispatchEvent(new CustomEvent("sw-dropup-close", { bubbles: !0, composed: !0 }));
13
+ };
14
+ }
15
+ updated(e) {
16
+ e.has("open") && (this.open ? (document.addEventListener("mousedown", this._outsideClickHandler), this.anchor && this._positionToAnchor()) : document.removeEventListener("mousedown", this._outsideClickHandler));
17
+ }
18
+ _positionToAnchor() {
19
+ const e = this.anchor.getBoundingClientRect(), t = 4;
20
+ this._menu.style.position = "fixed", this._menu.style.top = `${e.top - t}px`, this._menu.style.bottom = "auto", this._menu.style.left = `${e.left + e.width / 2}px`, this._menu.style.right = "auto", this._menu.style.transform = "translateX(-50%) translateY(-100%)";
21
+ }
22
+ disconnectedCallback() {
23
+ super.disconnectedCallback(), document.removeEventListener("mousedown", this._outsideClickHandler);
24
+ }
25
+ normalizeItem(e) {
26
+ return typeof e == "string" ? { label: e, id: e, selected: !1 } : e;
27
+ }
28
+ onSelect(e) {
29
+ const t = { ...e, selected: !0 };
30
+ this.items = (this.items ?? []).map((s) => {
31
+ const o = this.normalizeItem(s);
32
+ return { ...o, selected: o.id === e.id };
33
+ }), this.dispatchEvent(
34
+ new CustomEvent("sw-dropup-select", {
35
+ detail: t,
36
+ bubbles: !0,
37
+ composed: !0
38
+ })
39
+ );
40
+ }
41
+ render() {
42
+ const e = (this.items ?? []).map((t) => {
43
+ const s = this.normalizeItem(t);
44
+ return d`
45
+ <button
46
+ part="item"
47
+ @click=${() => this.onSelect(s)}
48
+ class=${s.selected === !0 ? "selected" : ""}
49
+ >
50
+ ${s.label}
51
+ </button>
52
+ `;
53
+ });
54
+ return d`
55
+ <div part="menu" class="menu ${this.open ? "open" : ""}">${e.length ? e : p}</div>
56
+ `;
57
+ }
58
+ };
59
+ n.styles = m`
60
+ :host {
61
+ display: inline-block;
62
+ position: relative;
63
+ }
64
+
65
+ .menu {
66
+ position: absolute;
67
+ bottom: calc(100% + var(--sw-dropup-offset, 4px));
68
+ left: 0;
69
+ display: none;
70
+ flex-direction: column;
71
+ border: 1px solid var(--border-default);
72
+ background: var(--bg-page);
73
+ color: var(--fg-default);
74
+ font-family: var(--type-family-body);
75
+ font-size: var(--type-size-small);
76
+ min-width: 120px;
77
+ max-width: var(--sw-dropup-max-width, 200px);
78
+ border-radius: var(--radius-md);
79
+ box-shadow: var(--shadow-md);
80
+ overflow: hidden;
81
+ }
82
+
83
+ .menu.open {
84
+ display: flex;
85
+ }
86
+
87
+ button {
88
+ all: unset;
89
+ padding: 8px 12px;
90
+ cursor: pointer;
91
+ font-size: 0.8125rem;
92
+ transition: background var(--transition-fast);
93
+ }
94
+
95
+ button.selected {
96
+ background: var(--bg-surface-raised);
97
+ }
98
+
99
+ button:hover {
100
+ background: var(--bg-surface);
101
+ }
102
+ `;
103
+ i([
104
+ u({
105
+ reflect: !0,
106
+ converter: {
107
+ fromAttribute(e) {
108
+ if (!e) return [];
109
+ try {
110
+ const t = JSON.parse(e);
111
+ return Array.isArray(t) ? t : [];
112
+ } catch {
113
+ return [];
114
+ }
115
+ },
116
+ toAttribute(e) {
117
+ return JSON.stringify(e);
118
+ }
119
+ }
120
+ })
121
+ ], n.prototype, "items", 2);
122
+ i([
123
+ u({ type: Boolean, reflect: !0 })
124
+ ], n.prototype, "open", 2);
125
+ i([
126
+ u({ attribute: !1 })
127
+ ], n.prototype, "anchor", 2);
128
+ i([
129
+ h(".menu")
130
+ ], n.prototype, "_menu", 2);
131
+ n = i([
132
+ f("sw-ui-dropup")
133
+ ], n);
134
+ export {
135
+ n as SwUiDropup
136
+ };
137
+ //# sourceMappingURL=sw-ui-dropup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sw-ui-dropup.js","sources":["../../../../src/components/UI/controls/sw-ui-dropup.ts"],"sourcesContent":["import { LitElement, html, css, nothing } from 'lit';\nimport { customElement, property, query } from 'lit/decorators.js';\n\nexport type DropUpItem = { label: string; id: string; selected?: boolean };\n\n/**\n * Dropdown (opens upward) menu anchored to a trigger element.\n *\n * @fires sw-dropup-select - User picked an item. `detail` is the selected `DropUpItem`.\n * @fires sw-dropup-close - Outside click closed the menu.\n *\n * @cssprop --sw-dropup-offset [4px] - gap between anchor and menu\n * @cssprop --sw-dropup-max-width [200px] - maximum menu width\n * @cssprop --sw-dropup-bg [#1f2937] - menu background\n * @cssprop --sw-dropup-border [1px solid rgba(255,255,255,0.1)] - menu border\n * @cssprop --sw-dropup-radius [8px] - menu border-radius\n * @cssprop --sw-dropup-shadow [0 4px 12px rgba(0,0,0,0.4)] - menu box-shadow\n * @cssprop --sw-dropup-color [#e5e7eb] - item text colour\n * @cssprop --sw-dropup-item-hover [rgba(255,255,255,0.08)] - item hover background\n * @cssprop --sw-dropup-item-active [rgba(255,255,255,0.15)] - selected item background\n */\n@customElement('sw-ui-dropup')\nexport class SwUiDropup extends LitElement {\n static styles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n .menu {\n position: absolute;\n bottom: calc(100% + var(--sw-dropup-offset, 4px));\n left: 0;\n display: none;\n flex-direction: column;\n border: 1px solid var(--border-default);\n background: var(--bg-page);\n color: var(--fg-default);\n font-family: var(--type-family-body);\n font-size: var(--type-size-small);\n min-width: 120px;\n max-width: var(--sw-dropup-max-width, 200px);\n border-radius: var(--radius-md);\n box-shadow: var(--shadow-md);\n overflow: hidden;\n }\n\n .menu.open {\n display: flex;\n }\n\n button {\n all: unset;\n padding: 8px 12px;\n cursor: pointer;\n font-size: 0.8125rem;\n transition: background var(--transition-fast);\n }\n\n button.selected {\n background: var(--bg-surface-raised);\n }\n\n button:hover {\n background: var(--bg-surface);\n }\n `;\n\n @property({\n reflect: true,\n converter: {\n fromAttribute(value: string | null): Array<DropUpItem | string> {\n if (!value) return [];\n try {\n const parsed: unknown = JSON.parse(value);\n return Array.isArray(parsed) ? (parsed as Array<DropUpItem | string>) : [];\n } catch {\n return [];\n }\n },\n toAttribute(value: Array<DropUpItem | string>): string {\n return JSON.stringify(value);\n }\n }\n })\n items: Array<DropUpItem | string> = [];\n\n @property({ type: Boolean, reflect: true })\n open = false;\n\n // Optional element treated as \"inside\" for outside-click AND used as the position anchor\n @property({ attribute: false })\n anchor?: Element;\n\n @query('.menu')\n private _menu!: HTMLElement;\n\n private _outsideClickHandler = (e: MouseEvent) => {\n const path = e.composedPath();\n if (!path.includes(this) && (!this.anchor || !path.includes(this.anchor))) {\n this.dispatchEvent(new CustomEvent('sw-dropup-close', { bubbles: true, composed: true }));\n }\n };\n\n updated(changed: Map<string, unknown>) {\n if (!changed.has('open')) return;\n\n if (this.open) {\n document.addEventListener('mousedown', this._outsideClickHandler);\n if (this.anchor) {\n this._positionToAnchor();\n }\n } else {\n document.removeEventListener('mousedown', this._outsideClickHandler);\n }\n }\n\n private _positionToAnchor() {\n const rect = this.anchor!.getBoundingClientRect();\n const offset = 4;\n this._menu.style.position = 'fixed';\n this._menu.style.top = `${rect.top - offset}px`;\n this._menu.style.bottom = 'auto';\n this._menu.style.left = `${rect.left + rect.width / 2}px`;\n this._menu.style.right = 'auto';\n this._menu.style.transform = 'translateX(-50%) translateY(-100%)';\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('mousedown', this._outsideClickHandler);\n }\n\n private normalizeItem(item: DropUpItem | string): DropUpItem {\n if (typeof item === 'string') {\n return { label: item, id: item, selected: false };\n }\n return item;\n }\n\n private onSelect(item: DropUpItem) {\n const selectedItem = { ...item, selected: true };\n this.items = (this.items ?? []).map((i) => {\n const normalized = this.normalizeItem(i);\n return { ...normalized, selected: normalized.id === item.id };\n });\n this.dispatchEvent(\n new CustomEvent('sw-dropup-select', {\n detail: selectedItem,\n bubbles: true,\n composed: true\n })\n );\n }\n\n render() {\n const list = (this.items ?? []).map((i) => {\n const item = this.normalizeItem(i);\n return html`\n <button\n part=\"item\"\n @click=${() => this.onSelect(item)}\n class=${item.selected === true ? 'selected' : ''}\n >\n ${item.label}\n </button>\n `;\n });\n\n return html`\n <div part=\"menu\" class=\"menu ${this.open ? 'open' : ''}\">${list.length ? list : nothing}</div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'sw-ui-dropup': SwUiDropup;\n }\n}\n"],"names":["SwUiDropup","LitElement","path","changed","rect","offset","item","selectedItem","i","normalized","list","html","nothing","css","__decorateClass","property","value","parsed","query","customElement"],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { LitElement } from 'lit';
2
+ import type { DropUpItem } from './sw-ui-dropup';
3
+ /**
4
+ * Pill-shaped split button: main action + optional chevron dropdown.
5
+ *
6
+ * When `items` is non-empty, renders as a unified pill with a subtle
7
+ * divider between the icon area and the chevron: `[ 🎤 | ▲ ]`
8
+ *
9
+ * When `items` is empty, renders as a single pill button.
10
+ *
11
+ * - **active/inactive** slots → toggle button, dispatches `sw-split-button-toggle`
12
+ * - **default** slot only → push button, dispatches `sw-split-button-click`
13
+ *
14
+ * @slot active - icon shown when active
15
+ * @slot inactive - icon shown when inactive
16
+ * @slot (default)- icon for a non-toggle button
17
+ *
18
+ * @fires sw-split-button-toggle - Fired on toggle-mode click. `detail` is the new active state (boolean).
19
+ * @fires sw-split-button-click - Fired on push-mode click. No detail.
20
+ *
21
+ * @cssprop --sw-split-button-size [44px] - height (width auto-fits content)
22
+ * @cssprop --sw-split-button-bg - button background (falls back to --bg-surface)
23
+ * @cssprop --sw-split-button-bg-hover - hover background (falls back to --bg-surface-raised)
24
+ * @cssprop --sw-split-button-color - icon colour (falls back to --fg-default)
25
+ * @cssprop --sw-split-button-radius - border-radius (falls back to --radius-full)
26
+ */
27
+ export declare class SwUiSplitButton extends LitElement {
28
+ static styles: import("lit").CSSResult;
29
+ items: Array<DropUpItem | string>;
30
+ active: boolean;
31
+ private _dropupOpen;
32
+ private _hasNamedSlots;
33
+ private _chevronBtn;
34
+ private _onDropupSelect;
35
+ private _updateNamedSlots;
36
+ private _onMainClick;
37
+ render(): import("lit-html").TemplateResult<1>;
38
+ }
39
+ declare global {
40
+ interface HTMLElementTagNameMap {
41
+ 'sw-ui-split-button': SwUiSplitButton;
42
+ }
43
+ }
44
+ //# sourceMappingURL=sw-ui-split-button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sw-ui-split-button.d.ts","sourceRoot":"","sources":["../../../../src/components/UI/controls/sw-ui-split-button.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBACa,eAAgB,SAAQ,UAAU;IAC7C,MAAM,CAAC,MAAM,0BAwEX;IAkBF,KAAK,EAAE,KAAK,CAAC,UAAU,GAAG,MAAM,CAAC,CAAM;IAGvC,MAAM,EAAE,OAAO,CAAS;IAGxB,OAAO,CAAC,WAAW,CAAkB;IAGrC,OAAO,CAAC,cAAc,CAAS;IAG/B,OAAO,CAAC,WAAW,CAAqB;IAExC,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,YAAY;IAepB,MAAM;CAsCP;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,eAAe,CAAC;KACvC;CACF"}