@pnlight/sdk-react 0.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.
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/RemoteUi.d.ts +16 -0
- package/dist/RemoteUi.d.ts.map +1 -0
- package/dist/RemoteUi.js +48 -0
- package/dist/RemoteUi.js.map +1 -0
- package/dist/custom-components.d.ts +4 -0
- package/dist/custom-components.d.ts.map +1 -0
- package/dist/custom-components.js +909 -0
- package/dist/custom-components.js.map +1 -0
- package/dist/dialogs.d.ts +32 -0
- package/dist/dialogs.d.ts.map +1 -0
- package/dist/dialogs.js +107 -0
- package/dist/dialogs.js.map +1 -0
- package/dist/flow.d.ts +88 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +270 -0
- package/dist/flow.js.map +1 -0
- package/dist/haptics.d.ts +7 -0
- package/dist/haptics.d.ts.map +1 -0
- package/dist/haptics.js +69 -0
- package/dist/haptics.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.d.ts +27 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +192 -0
- package/dist/runtime.js.map +1 -0
- package/dist/safe-area.d.ts +22 -0
- package/dist/safe-area.d.ts.map +1 -0
- package/dist/safe-area.js +104 -0
- package/dist/safe-area.js.map +1 -0
- package/dist/schema-version.d.ts +11 -0
- package/dist/schema-version.d.ts.map +1 -0
- package/dist/schema-version.js +30 -0
- package/dist/schema-version.js.map +1 -0
- package/dist/styles.css +172 -0
- package/package.json +54 -0
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
const BUTTON_PROPS = [
|
|
2
|
+
"title",
|
|
3
|
+
"background_color",
|
|
4
|
+
"background_color_end",
|
|
5
|
+
"title_color",
|
|
6
|
+
"corner_radius",
|
|
7
|
+
"font_size",
|
|
8
|
+
"font_weight",
|
|
9
|
+
"horizontal_padding",
|
|
10
|
+
"vertical_padding",
|
|
11
|
+
"icon",
|
|
12
|
+
"icon_size",
|
|
13
|
+
"icon_weight",
|
|
14
|
+
"icon_color",
|
|
15
|
+
"icon_spacing",
|
|
16
|
+
"loading",
|
|
17
|
+
"disabled",
|
|
18
|
+
"disabled_alpha",
|
|
19
|
+
"disabled_background_color",
|
|
20
|
+
"disabled_title_color",
|
|
21
|
+
"loading_indicator_color",
|
|
22
|
+
"loading_indicator_style",
|
|
23
|
+
"url",
|
|
24
|
+
"log_id",
|
|
25
|
+
"accessibility_label",
|
|
26
|
+
"shimmer",
|
|
27
|
+
"bounce",
|
|
28
|
+
"glass"
|
|
29
|
+
];
|
|
30
|
+
const LOADER_PROPS = ["style", "color", "accessibility_label"];
|
|
31
|
+
const PREPEND_LIST_PROPS = [
|
|
32
|
+
"instance_id",
|
|
33
|
+
"count",
|
|
34
|
+
"count_variable",
|
|
35
|
+
"items",
|
|
36
|
+
"reduced_motion",
|
|
37
|
+
"status_text",
|
|
38
|
+
"card_background_color",
|
|
39
|
+
"title_color",
|
|
40
|
+
"body_color",
|
|
41
|
+
"status_color",
|
|
42
|
+
"corner_radius",
|
|
43
|
+
"title_font_size",
|
|
44
|
+
"title_font_weight",
|
|
45
|
+
"body_font_size",
|
|
46
|
+
"body_font_weight",
|
|
47
|
+
"status_font_size",
|
|
48
|
+
"status_font_weight",
|
|
49
|
+
"list_horizontal_padding",
|
|
50
|
+
"row_spacing",
|
|
51
|
+
"bottom_padding",
|
|
52
|
+
"row_horizontal_padding",
|
|
53
|
+
"row_vertical_padding",
|
|
54
|
+
"icon_size",
|
|
55
|
+
"icon_text_spacing",
|
|
56
|
+
"text_status_spacing",
|
|
57
|
+
"animation_duration",
|
|
58
|
+
"slide_distance",
|
|
59
|
+
"fade",
|
|
60
|
+
"slide",
|
|
61
|
+
"shows_scroll_indicator"
|
|
62
|
+
];
|
|
63
|
+
const prependListSnapshots = new WeakMap();
|
|
64
|
+
function parseBoolean(value, fallback = false) {
|
|
65
|
+
if (typeof value === "boolean")
|
|
66
|
+
return value;
|
|
67
|
+
if (typeof value === "number")
|
|
68
|
+
return value !== 0;
|
|
69
|
+
if (typeof value === "string") {
|
|
70
|
+
if (["true", "yes", "1"].includes(value.toLowerCase()))
|
|
71
|
+
return true;
|
|
72
|
+
if (["false", "no", "0", ""].includes(value.toLowerCase()))
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
return fallback;
|
|
76
|
+
}
|
|
77
|
+
function parseNumber(value, fallback) {
|
|
78
|
+
if (value == null || value === "")
|
|
79
|
+
return fallback;
|
|
80
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
81
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
82
|
+
}
|
|
83
|
+
function parseObject(value) {
|
|
84
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
if (typeof value !== "string")
|
|
88
|
+
return null;
|
|
89
|
+
try {
|
|
90
|
+
const parsed = JSON.parse(value);
|
|
91
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
92
|
+
? parsed
|
|
93
|
+
: null;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function parseArray(value) {
|
|
100
|
+
if (Array.isArray(value))
|
|
101
|
+
return value;
|
|
102
|
+
if (typeof value !== "string")
|
|
103
|
+
return [];
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(value);
|
|
106
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function cssColor(value, fallback) {
|
|
113
|
+
if (typeof value !== "string")
|
|
114
|
+
return fallback;
|
|
115
|
+
const hex = value.trim();
|
|
116
|
+
if (/^#[0-9a-f]{6}$/i.test(hex))
|
|
117
|
+
return hex;
|
|
118
|
+
if (/^#[0-9a-f]{8}$/i.test(hex)) {
|
|
119
|
+
const alpha = Number.parseInt(hex.slice(1, 3), 16) / 255;
|
|
120
|
+
const red = Number.parseInt(hex.slice(3, 5), 16);
|
|
121
|
+
const green = Number.parseInt(hex.slice(5, 7), 16);
|
|
122
|
+
const blue = Number.parseInt(hex.slice(7, 9), 16);
|
|
123
|
+
return `rgba(${red}, ${green}, ${blue}, ${alpha.toFixed(3)})`;
|
|
124
|
+
}
|
|
125
|
+
return fallback;
|
|
126
|
+
}
|
|
127
|
+
function fontWeight(value, fallback = 600) {
|
|
128
|
+
const weights = {
|
|
129
|
+
ultralight: 200,
|
|
130
|
+
thin: 200,
|
|
131
|
+
light: 300,
|
|
132
|
+
regular: 400,
|
|
133
|
+
medium: 500,
|
|
134
|
+
semibold: 600,
|
|
135
|
+
bold: 700,
|
|
136
|
+
heavy: 800,
|
|
137
|
+
black: 900
|
|
138
|
+
};
|
|
139
|
+
return weights[String(value ?? "").toLowerCase()] ?? fallback;
|
|
140
|
+
}
|
|
141
|
+
function iconMarkup(name, size, weight) {
|
|
142
|
+
const icons = {
|
|
143
|
+
xmark: X,
|
|
144
|
+
"xmark.circle": CircleX,
|
|
145
|
+
plus: Plus,
|
|
146
|
+
"plus.circle": CirclePlus,
|
|
147
|
+
minus: Minus,
|
|
148
|
+
"minus.circle": CircleMinus,
|
|
149
|
+
checkmark: Check,
|
|
150
|
+
gear: Settings,
|
|
151
|
+
gearshape: Settings,
|
|
152
|
+
heart: Heart,
|
|
153
|
+
"heart.fill": Heart,
|
|
154
|
+
star: Star,
|
|
155
|
+
"star.fill": Star,
|
|
156
|
+
info: Info,
|
|
157
|
+
questionmark: CircleHelp,
|
|
158
|
+
"chevron.left": ChevronLeft,
|
|
159
|
+
"chevron.right": ChevronRight,
|
|
160
|
+
"arrow.left": ArrowLeft,
|
|
161
|
+
"arrow.right": ArrowRight,
|
|
162
|
+
ellipsis: Ellipsis,
|
|
163
|
+
trash: Trash2,
|
|
164
|
+
"shield.lefthalf.filled": ShieldHalf
|
|
165
|
+
};
|
|
166
|
+
const key = String(name ?? "").trim().toLowerCase();
|
|
167
|
+
const node = icons[key] ?? CircleHelp;
|
|
168
|
+
const strokeWidths = {
|
|
169
|
+
ultralight: 1,
|
|
170
|
+
thin: 1.25,
|
|
171
|
+
light: 1.5,
|
|
172
|
+
regular: 2,
|
|
173
|
+
medium: 2.25,
|
|
174
|
+
semibold: 2.5,
|
|
175
|
+
bold: 2.75,
|
|
176
|
+
heavy: 3,
|
|
177
|
+
black: 3.25
|
|
178
|
+
};
|
|
179
|
+
const svg = createElement(node, {
|
|
180
|
+
width: size,
|
|
181
|
+
height: size,
|
|
182
|
+
stroke: "currentColor",
|
|
183
|
+
"stroke-width": strokeWidths[String(weight ?? "semibold").toLowerCase()] ?? 2.5,
|
|
184
|
+
"aria-hidden": "true"
|
|
185
|
+
});
|
|
186
|
+
if (key.endsWith(".fill")) {
|
|
187
|
+
svg.setAttribute("fill", "currentColor");
|
|
188
|
+
}
|
|
189
|
+
return svg.outerHTML;
|
|
190
|
+
}
|
|
191
|
+
class PNLightElement extends HTMLElement {
|
|
192
|
+
values = new Map();
|
|
193
|
+
context;
|
|
194
|
+
scheduled = false;
|
|
195
|
+
divKitApiCallback(context) {
|
|
196
|
+
this.context = context;
|
|
197
|
+
}
|
|
198
|
+
defineProps(names) {
|
|
199
|
+
for (const name of names) {
|
|
200
|
+
if (Object.prototype.hasOwnProperty.call(this, name))
|
|
201
|
+
continue;
|
|
202
|
+
Object.defineProperty(this, name, {
|
|
203
|
+
configurable: true,
|
|
204
|
+
get: () => this.values.get(name) ?? this.getAttribute(name),
|
|
205
|
+
set: (value) => {
|
|
206
|
+
this.values.set(name, value);
|
|
207
|
+
this.scheduleRender();
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
value(name) {
|
|
213
|
+
return this.values.has(name)
|
|
214
|
+
? this.values.get(name)
|
|
215
|
+
: this.getAttribute(name);
|
|
216
|
+
}
|
|
217
|
+
scheduleRender() {
|
|
218
|
+
if (this.scheduled)
|
|
219
|
+
return;
|
|
220
|
+
this.scheduled = true;
|
|
221
|
+
queueMicrotask(() => {
|
|
222
|
+
this.scheduled = false;
|
|
223
|
+
if (this.isConnected)
|
|
224
|
+
this.render();
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
fireAction() {
|
|
228
|
+
const url = this.value("url");
|
|
229
|
+
const logId = this.value("log_id");
|
|
230
|
+
const action = {
|
|
231
|
+
log_id: typeof logId === "string" && logId
|
|
232
|
+
? logId
|
|
233
|
+
: "pnlight_custom_component",
|
|
234
|
+
...(typeof url === "string" && url ? { url } : {})
|
|
235
|
+
};
|
|
236
|
+
// Always expose a DOM event for web hosts. DivKit's extension context is
|
|
237
|
+
// still invoked below, but not every web integration forwards custom URLs
|
|
238
|
+
// through `onCustomAction`.
|
|
239
|
+
const shouldExecuteInDivKit = this.dispatchEvent(new CustomEvent("pnlight-action", {
|
|
240
|
+
bubbles: true,
|
|
241
|
+
cancelable: true,
|
|
242
|
+
composed: true,
|
|
243
|
+
detail: action
|
|
244
|
+
}));
|
|
245
|
+
if (shouldExecuteInDivKit) {
|
|
246
|
+
this.context?.execAction(action);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
class PNLightButtonElement extends PNLightElement {
|
|
251
|
+
kind;
|
|
252
|
+
root;
|
|
253
|
+
constructor(kind) {
|
|
254
|
+
super();
|
|
255
|
+
this.kind = kind;
|
|
256
|
+
this.defineProps(BUTTON_PROPS);
|
|
257
|
+
this.root = this.attachShadow({ mode: "open" });
|
|
258
|
+
}
|
|
259
|
+
static get observedAttributes() {
|
|
260
|
+
return [...BUTTON_PROPS];
|
|
261
|
+
}
|
|
262
|
+
connectedCallback() {
|
|
263
|
+
this.render();
|
|
264
|
+
}
|
|
265
|
+
attributeChangedCallback(name, _oldValue, value) {
|
|
266
|
+
this.values.set(name, value);
|
|
267
|
+
this.scheduleRender();
|
|
268
|
+
}
|
|
269
|
+
shimmerConfig(defaultEnabled) {
|
|
270
|
+
const raw = this.value("shimmer");
|
|
271
|
+
const object = parseObject(raw);
|
|
272
|
+
if (!object) {
|
|
273
|
+
return {
|
|
274
|
+
enabled: raw == null ? defaultEnabled : parseBoolean(raw, defaultEnabled),
|
|
275
|
+
color: "rgba(255, 255, 255, 0.45)",
|
|
276
|
+
duration: 1.4,
|
|
277
|
+
pause: 1.1,
|
|
278
|
+
bandWidth: 0.3,
|
|
279
|
+
angle: 16
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
enabled: parseBoolean(object.enabled, true),
|
|
284
|
+
color: cssColor(object.color, "rgba(255, 255, 255, 0.45)"),
|
|
285
|
+
duration: Math.max(0.1, parseNumber(object.duration, 1.4)),
|
|
286
|
+
pause: Math.max(0, parseNumber(object.pause ?? object.delay, 1.1)),
|
|
287
|
+
bandWidth: Math.min(1, Math.max(0.05, parseNumber(object.band_width, 0.3))),
|
|
288
|
+
angle: parseNumber(object.angle, 16)
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
bounceConfig() {
|
|
292
|
+
const defaultIdle = this.kind === "cta";
|
|
293
|
+
const raw = this.value("bounce");
|
|
294
|
+
if (!parseObject(raw)) {
|
|
295
|
+
const enabled = raw == null ? null : parseBoolean(raw);
|
|
296
|
+
return {
|
|
297
|
+
idleEnabled: enabled ?? defaultIdle,
|
|
298
|
+
idleScale: 1.03,
|
|
299
|
+
idlePeriod: 2.6,
|
|
300
|
+
pressEnabled: enabled ?? true,
|
|
301
|
+
pressScale: 0.96
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const object = parseObject(raw);
|
|
305
|
+
const idle = parseObject(object.idle);
|
|
306
|
+
const press = parseObject(object.press);
|
|
307
|
+
return {
|
|
308
|
+
idleEnabled: idle
|
|
309
|
+
? parseBoolean(idle.enabled, defaultIdle)
|
|
310
|
+
: object.idle == null
|
|
311
|
+
? defaultIdle
|
|
312
|
+
: parseBoolean(object.idle, defaultIdle),
|
|
313
|
+
idleScale: parseNumber(idle?.scale, 1.03),
|
|
314
|
+
idlePeriod: Math.max(0.1, parseNumber(idle?.period, 2.6)),
|
|
315
|
+
pressEnabled: press
|
|
316
|
+
? parseBoolean(press.enabled, true)
|
|
317
|
+
: object.press == null
|
|
318
|
+
? true
|
|
319
|
+
: parseBoolean(object.press, true),
|
|
320
|
+
pressScale: parseNumber(press?.scale, 0.96)
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
render() {
|
|
324
|
+
const isIcon = this.kind === "icon";
|
|
325
|
+
const title = String(this.value("title") ?? "");
|
|
326
|
+
const icon = this.value("icon");
|
|
327
|
+
const iconSize = parseNumber(this.value("icon_size"), 20);
|
|
328
|
+
const loading = parseBoolean(this.value("loading"));
|
|
329
|
+
const disabled = parseBoolean(this.value("disabled"));
|
|
330
|
+
const inactive = loading || disabled;
|
|
331
|
+
const titleColor = cssColor(this.value(disabled ? "disabled_title_color" : "title_color"), isIcon ? "#111827" : "#ffffff");
|
|
332
|
+
const iconColor = cssColor(this.value("icon_color"), titleColor);
|
|
333
|
+
const defaultBackground = isIcon ? "rgba(118, 118, 128, 0.18)" : "#007aff";
|
|
334
|
+
const background = cssColor(this.value(disabled ? "disabled_background_color" : "background_color"), defaultBackground);
|
|
335
|
+
const gradientEnd = this.value("background_color_end");
|
|
336
|
+
const shimmer = this.shimmerConfig(!isIcon);
|
|
337
|
+
const bounce = this.bounceConfig();
|
|
338
|
+
const explicitRadius = this.value("corner_radius");
|
|
339
|
+
const radius = isIcon && explicitRadius == null
|
|
340
|
+
? "999px"
|
|
341
|
+
: `${parseNumber(explicitRadius, 14)}px`;
|
|
342
|
+
const glassValue = this.value("glass");
|
|
343
|
+
const glassObject = parseObject(glassValue);
|
|
344
|
+
const glassEnabled = glassValue == null
|
|
345
|
+
? isIcon && this.value("background_color") == null
|
|
346
|
+
: glassObject
|
|
347
|
+
? parseBoolean(glassObject.enabled, true)
|
|
348
|
+
: parseBoolean(glassValue);
|
|
349
|
+
const glassTint = cssColor(glassObject?.tint, background);
|
|
350
|
+
const fill = gradientEnd
|
|
351
|
+
? `linear-gradient(90deg, ${background}, ${cssColor(gradientEnd, background)})`
|
|
352
|
+
: glassEnabled
|
|
353
|
+
? glassTint
|
|
354
|
+
: background;
|
|
355
|
+
const disabledAlpha = parseNumber(this.value("disabled_alpha"), 0.45);
|
|
356
|
+
const accessibilityLabel = String(this.value("accessibility_label") ?? (loading ? "Loading" : title || icon || "Button"));
|
|
357
|
+
this.root.innerHTML = `
|
|
358
|
+
<style>
|
|
359
|
+
:host {
|
|
360
|
+
display: block;
|
|
361
|
+
width: 100%;
|
|
362
|
+
height: 100%;
|
|
363
|
+
overflow: visible;
|
|
364
|
+
contain: none;
|
|
365
|
+
--idle-scale: ${bounce.idleScale};
|
|
366
|
+
--idle-period: ${bounce.idlePeriod}s;
|
|
367
|
+
--press-scale: ${bounce.pressScale};
|
|
368
|
+
}
|
|
369
|
+
.pulse {
|
|
370
|
+
position: relative;
|
|
371
|
+
width: 100%;
|
|
372
|
+
height: 100%;
|
|
373
|
+
overflow: visible;
|
|
374
|
+
transform-origin: center;
|
|
375
|
+
animation: ${bounce.idleEnabled && !inactive ? "pnlight-idle var(--idle-period) ease-in-out infinite" : "none"};
|
|
376
|
+
will-change: transform;
|
|
377
|
+
}
|
|
378
|
+
button {
|
|
379
|
+
position: relative;
|
|
380
|
+
display: flex;
|
|
381
|
+
width: 100%;
|
|
382
|
+
height: 100%;
|
|
383
|
+
min-width: 0;
|
|
384
|
+
align-items: center;
|
|
385
|
+
justify-content: center;
|
|
386
|
+
gap: ${parseNumber(this.value("icon_spacing"), 8)}px;
|
|
387
|
+
padding: ${parseNumber(this.value("vertical_padding"), isIcon ? 12 : 16)}px ${parseNumber(this.value("horizontal_padding"), isIcon ? 12 : 24)}px;
|
|
388
|
+
overflow: hidden;
|
|
389
|
+
border: ${glassEnabled ? "1px solid rgba(255,255,255,.38)" : "0"};
|
|
390
|
+
border-radius: ${radius};
|
|
391
|
+
background: ${fill};
|
|
392
|
+
box-shadow: ${glassEnabled ? "inset 0 1px 0 rgba(255,255,255,.42), 0 8px 24px rgba(15,23,42,.12)" : "0 8px 18px rgba(15,23,42,.10)"};
|
|
393
|
+
color: ${titleColor};
|
|
394
|
+
cursor: ${inactive ? "default" : "pointer"};
|
|
395
|
+
font: inherit;
|
|
396
|
+
opacity: ${disabled ? disabledAlpha : 1};
|
|
397
|
+
-webkit-backdrop-filter: ${glassEnabled ? "blur(18px) saturate(150%)" : "none"};
|
|
398
|
+
backdrop-filter: ${glassEnabled ? "blur(18px) saturate(150%)" : "none"};
|
|
399
|
+
transform: scale(1);
|
|
400
|
+
transition: transform 180ms cubic-bezier(.2,.8,.2,1), filter 180ms ease;
|
|
401
|
+
-webkit-tap-highlight-color: transparent;
|
|
402
|
+
}
|
|
403
|
+
button:focus-visible {
|
|
404
|
+
outline: 3px solid rgba(8, 126, 245, .35);
|
|
405
|
+
outline-offset: 3px;
|
|
406
|
+
}
|
|
407
|
+
button:not(:disabled):hover {
|
|
408
|
+
filter: brightness(1.035);
|
|
409
|
+
}
|
|
410
|
+
button:not(:disabled):active {
|
|
411
|
+
transform: ${bounce.pressEnabled ? "scale(var(--press-scale))" : "scale(1)"};
|
|
412
|
+
}
|
|
413
|
+
button::after {
|
|
414
|
+
content: "";
|
|
415
|
+
position: absolute;
|
|
416
|
+
z-index: 3;
|
|
417
|
+
inset: 0;
|
|
418
|
+
border-radius: inherit;
|
|
419
|
+
background: rgba(255, 255, 255, .36);
|
|
420
|
+
opacity: 0;
|
|
421
|
+
pointer-events: none;
|
|
422
|
+
transform: scale(.72);
|
|
423
|
+
}
|
|
424
|
+
button.tap-confirmed {
|
|
425
|
+
animation: pnlight-tap-confirmed 320ms cubic-bezier(.2,.8,.2,1);
|
|
426
|
+
}
|
|
427
|
+
button.tap-confirmed::after {
|
|
428
|
+
animation: pnlight-tap-flash 360ms ease-out;
|
|
429
|
+
}
|
|
430
|
+
.label {
|
|
431
|
+
position: relative;
|
|
432
|
+
z-index: 2;
|
|
433
|
+
overflow: hidden;
|
|
434
|
+
text-overflow: ellipsis;
|
|
435
|
+
white-space: nowrap;
|
|
436
|
+
font-size: ${parseNumber(this.value("font_size"), 18)}px;
|
|
437
|
+
font-weight: ${fontWeight(this.value("font_weight"))};
|
|
438
|
+
line-height: 1.1;
|
|
439
|
+
}
|
|
440
|
+
.icon {
|
|
441
|
+
position: relative;
|
|
442
|
+
z-index: 2;
|
|
443
|
+
display: grid;
|
|
444
|
+
min-width: 1em;
|
|
445
|
+
flex: 0 0 auto;
|
|
446
|
+
place-items: center;
|
|
447
|
+
color: ${iconColor};
|
|
448
|
+
font-size: ${iconSize}px;
|
|
449
|
+
line-height: 1;
|
|
450
|
+
}
|
|
451
|
+
.icon svg {
|
|
452
|
+
display: block;
|
|
453
|
+
width: 1em;
|
|
454
|
+
height: 1em;
|
|
455
|
+
}
|
|
456
|
+
.shimmer {
|
|
457
|
+
position: absolute;
|
|
458
|
+
z-index: 1;
|
|
459
|
+
inset: -70% auto -70% -45%;
|
|
460
|
+
width: ${Math.round(shimmer.bandWidth * 100)}%;
|
|
461
|
+
background: linear-gradient(90deg, transparent, ${shimmer.color}, transparent);
|
|
462
|
+
transform: skewX(${-shimmer.angle}deg) translateX(-220%);
|
|
463
|
+
animation: ${shimmer.enabled && !inactive ? `pnlight-shimmer ${shimmer.duration + shimmer.pause}s linear infinite` : "none"};
|
|
464
|
+
pointer-events: none;
|
|
465
|
+
}
|
|
466
|
+
.spinner {
|
|
467
|
+
position: relative;
|
|
468
|
+
z-index: 2;
|
|
469
|
+
width: ${this.value("loading_indicator_style") === "large" ? 25 : 20}px;
|
|
470
|
+
height: ${this.value("loading_indicator_style") === "large" ? 25 : 20}px;
|
|
471
|
+
border: 2.5px solid color-mix(in srgb, ${cssColor(this.value("loading_indicator_color"), titleColor)} 28%, transparent);
|
|
472
|
+
border-top-color: ${cssColor(this.value("loading_indicator_color"), titleColor)};
|
|
473
|
+
border-radius: 50%;
|
|
474
|
+
animation: pnlight-spin .72s linear infinite;
|
|
475
|
+
}
|
|
476
|
+
@keyframes pnlight-idle {
|
|
477
|
+
0%, 11%, 100% { transform: scale(1); }
|
|
478
|
+
5% { transform: scale(var(--idle-scale)); }
|
|
479
|
+
}
|
|
480
|
+
@keyframes pnlight-shimmer {
|
|
481
|
+
0% { transform: skewX(${-shimmer.angle}deg) translateX(-220%); }
|
|
482
|
+
${Math.max(1, Math.min(99, (shimmer.duration / (shimmer.duration + shimmer.pause)) * 100)).toFixed(1)}%,
|
|
483
|
+
100% { transform: skewX(${-shimmer.angle}deg) translateX(650%); }
|
|
484
|
+
}
|
|
485
|
+
@keyframes pnlight-spin { to { transform: rotate(360deg); } }
|
|
486
|
+
@keyframes pnlight-tap-confirmed {
|
|
487
|
+
0% { transform: scale(1); }
|
|
488
|
+
30% { transform: scale(${bounce.pressEnabled ? bounce.pressScale : 0.97}); }
|
|
489
|
+
65% { transform: scale(1.025); }
|
|
490
|
+
100% { transform: scale(1); }
|
|
491
|
+
}
|
|
492
|
+
@keyframes pnlight-tap-flash {
|
|
493
|
+
0% { opacity: 0; transform: scale(.72); }
|
|
494
|
+
25% { opacity: 1; }
|
|
495
|
+
100% { opacity: 0; transform: scale(1); }
|
|
496
|
+
}
|
|
497
|
+
@media (prefers-reduced-motion: reduce) {
|
|
498
|
+
.pulse, .shimmer, .spinner { animation-duration: 1ms !important; animation-iteration-count: 1 !important; }
|
|
499
|
+
button { transition: none; }
|
|
500
|
+
}
|
|
501
|
+
</style>
|
|
502
|
+
<div class="pulse">
|
|
503
|
+
<button type="button" ${inactive ? "disabled" : ""} aria-label="${escapeHtml(accessibilityLabel)}" aria-busy="${loading}">
|
|
504
|
+
${shimmer.enabled && !inactive ? '<span class="shimmer" aria-hidden="true"></span>' : ""}
|
|
505
|
+
${loading
|
|
506
|
+
? '<span class="spinner" aria-hidden="true"></span>'
|
|
507
|
+
: `${icon ? `<span class="icon" aria-hidden="true">${iconMarkup(icon, iconSize, this.value("icon_weight"))}</span>` : ""}${title ? `<span class="label">${escapeHtml(title)}</span>` : ""}`}
|
|
508
|
+
</button>
|
|
509
|
+
</div>
|
|
510
|
+
`;
|
|
511
|
+
const button = this.root.querySelector("button");
|
|
512
|
+
button?.addEventListener("click", () => {
|
|
513
|
+
button.classList.remove("tap-confirmed");
|
|
514
|
+
// Restart the confirmation animation on consecutive taps.
|
|
515
|
+
void button.getBoundingClientRect();
|
|
516
|
+
button.classList.add("tap-confirmed");
|
|
517
|
+
this.fireAction();
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
class PNLightCtaButton extends PNLightButtonElement {
|
|
522
|
+
constructor() {
|
|
523
|
+
super("cta");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
class PNLightIconButton extends PNLightButtonElement {
|
|
527
|
+
constructor() {
|
|
528
|
+
super("icon");
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
class PNLightCircularLoader extends PNLightElement {
|
|
532
|
+
root;
|
|
533
|
+
constructor() {
|
|
534
|
+
super();
|
|
535
|
+
this.defineProps(LOADER_PROPS);
|
|
536
|
+
this.root = this.attachShadow({ mode: "open" });
|
|
537
|
+
}
|
|
538
|
+
static get observedAttributes() {
|
|
539
|
+
return [...LOADER_PROPS];
|
|
540
|
+
}
|
|
541
|
+
connectedCallback() {
|
|
542
|
+
this.render();
|
|
543
|
+
}
|
|
544
|
+
attributeChangedCallback(name, _oldValue, value) {
|
|
545
|
+
this.values.set(name, value);
|
|
546
|
+
this.scheduleRender();
|
|
547
|
+
}
|
|
548
|
+
render() {
|
|
549
|
+
const large = this.value("style") === "large";
|
|
550
|
+
const size = large ? 36 : 22;
|
|
551
|
+
const color = cssColor(this.value("color"), "#111827");
|
|
552
|
+
const label = String(this.value("accessibility_label") ?? "Loading");
|
|
553
|
+
this.root.innerHTML = `
|
|
554
|
+
<style>
|
|
555
|
+
:host {
|
|
556
|
+
display: grid;
|
|
557
|
+
width: 100%;
|
|
558
|
+
height: 100%;
|
|
559
|
+
place-items: center;
|
|
560
|
+
}
|
|
561
|
+
.spinner {
|
|
562
|
+
width: ${size}px;
|
|
563
|
+
height: ${size}px;
|
|
564
|
+
box-sizing: border-box;
|
|
565
|
+
border: ${large ? 4 : 3}px solid color-mix(in srgb, ${color} 22%, transparent);
|
|
566
|
+
border-top-color: ${color};
|
|
567
|
+
border-radius: 50%;
|
|
568
|
+
animation: pnlight-spin .72s linear infinite;
|
|
569
|
+
}
|
|
570
|
+
@keyframes pnlight-spin { to { transform: rotate(360deg); } }
|
|
571
|
+
@media (prefers-reduced-motion: reduce) {
|
|
572
|
+
.spinner { animation-duration: 1.6s; }
|
|
573
|
+
}
|
|
574
|
+
</style>
|
|
575
|
+
<div class="spinner" role="status" aria-label="${escapeHtml(label)}"></div>
|
|
576
|
+
`;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
class PNLightAnimatedPrependList extends PNLightElement {
|
|
580
|
+
root;
|
|
581
|
+
list;
|
|
582
|
+
viewport;
|
|
583
|
+
instanceId = "";
|
|
584
|
+
displayedCount = 0;
|
|
585
|
+
itemsSignature = "";
|
|
586
|
+
styleSignature = "";
|
|
587
|
+
initialized = false;
|
|
588
|
+
unsubscribeCount;
|
|
589
|
+
constructor() {
|
|
590
|
+
super();
|
|
591
|
+
this.defineProps(PREPEND_LIST_PROPS);
|
|
592
|
+
this.root = this.attachShadow({ mode: "open" });
|
|
593
|
+
}
|
|
594
|
+
static get observedAttributes() {
|
|
595
|
+
return [...PREPEND_LIST_PROPS];
|
|
596
|
+
}
|
|
597
|
+
connectedCallback() {
|
|
598
|
+
this.render();
|
|
599
|
+
this.bindCountVariable();
|
|
600
|
+
}
|
|
601
|
+
disconnectedCallback() {
|
|
602
|
+
this.unsubscribeCount?.();
|
|
603
|
+
this.unsubscribeCount = undefined;
|
|
604
|
+
}
|
|
605
|
+
divKitApiCallback(context) {
|
|
606
|
+
super.divKitApiCallback(context);
|
|
607
|
+
this.bindCountVariable();
|
|
608
|
+
}
|
|
609
|
+
attributeChangedCallback(name, _oldValue, value) {
|
|
610
|
+
this.values.set(name, value);
|
|
611
|
+
this.scheduleRender();
|
|
612
|
+
}
|
|
613
|
+
render() {
|
|
614
|
+
const items = this.parsedItems();
|
|
615
|
+
const count = Math.min(items.length, Math.max(0, Math.floor(parseNumber(this.value("count"), 0))));
|
|
616
|
+
const instanceId = String(this.value("instance_id") ?? "pnlight.animated_prepend_list.default");
|
|
617
|
+
const itemsSignature = JSON.stringify(items);
|
|
618
|
+
const styleSignature = this.currentStyleSignature();
|
|
619
|
+
const instanceChanged = this.instanceId !== instanceId;
|
|
620
|
+
const styleChanged = this.styleSignature !== styleSignature;
|
|
621
|
+
const itemsChanged = this.itemsSignature !== itemsSignature;
|
|
622
|
+
const snapshotStore = this.snapshotStore();
|
|
623
|
+
const snapshot = instanceChanged
|
|
624
|
+
? snapshotStore.get(instanceId)
|
|
625
|
+
: undefined;
|
|
626
|
+
const canRestoreSnapshot = snapshot?.itemsSignature === itemsSignature &&
|
|
627
|
+
snapshot.styleSignature === styleSignature;
|
|
628
|
+
if (!this.initialized || instanceChanged || styleChanged) {
|
|
629
|
+
this.installShell();
|
|
630
|
+
}
|
|
631
|
+
if (instanceChanged) {
|
|
632
|
+
this.displayedCount = canRestoreSnapshot && snapshot
|
|
633
|
+
? snapshot.displayedCount
|
|
634
|
+
: 0;
|
|
635
|
+
}
|
|
636
|
+
const reducedMotion = parseBoolean(this.value("reduced_motion")) ||
|
|
637
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
638
|
+
const canAnimateInPlace = this.initialized &&
|
|
639
|
+
!instanceChanged &&
|
|
640
|
+
!styleChanged &&
|
|
641
|
+
!itemsChanged &&
|
|
642
|
+
count === this.displayedCount + 1 &&
|
|
643
|
+
!reducedMotion;
|
|
644
|
+
const canAnimateFromSnapshot = instanceChanged &&
|
|
645
|
+
canRestoreSnapshot &&
|
|
646
|
+
count === this.displayedCount + 1 &&
|
|
647
|
+
!reducedMotion;
|
|
648
|
+
const canAnimate = canAnimateInPlace || canAnimateFromSnapshot;
|
|
649
|
+
if (canAnimate) {
|
|
650
|
+
if (canAnimateFromSnapshot) {
|
|
651
|
+
this.rebuild(items, this.displayedCount);
|
|
652
|
+
}
|
|
653
|
+
this.prependRow(items[this.displayedCount], this.displayedCount);
|
|
654
|
+
}
|
|
655
|
+
else if (!this.initialized ||
|
|
656
|
+
instanceChanged ||
|
|
657
|
+
styleChanged ||
|
|
658
|
+
itemsChanged ||
|
|
659
|
+
count !== this.displayedCount) {
|
|
660
|
+
this.rebuild(items, count);
|
|
661
|
+
}
|
|
662
|
+
this.initialized = true;
|
|
663
|
+
this.instanceId = instanceId;
|
|
664
|
+
this.displayedCount = count;
|
|
665
|
+
this.itemsSignature = itemsSignature;
|
|
666
|
+
this.styleSignature = styleSignature;
|
|
667
|
+
snapshotStore.set(instanceId, {
|
|
668
|
+
displayedCount: count,
|
|
669
|
+
itemsSignature,
|
|
670
|
+
styleSignature
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
bindCountVariable() {
|
|
674
|
+
this.unsubscribeCount?.();
|
|
675
|
+
this.unsubscribeCount = undefined;
|
|
676
|
+
const name = String(this.value("count_variable") ?? "").trim();
|
|
677
|
+
if (!name || !this.context?.variables)
|
|
678
|
+
return;
|
|
679
|
+
const variable = this.context.variables.get(name);
|
|
680
|
+
if (!variable)
|
|
681
|
+
return;
|
|
682
|
+
const update = (value) => {
|
|
683
|
+
this.values.set("count", Number(value));
|
|
684
|
+
this.scheduleRender();
|
|
685
|
+
};
|
|
686
|
+
update(variable.getValue());
|
|
687
|
+
this.unsubscribeCount = variable.subscribe(update);
|
|
688
|
+
}
|
|
689
|
+
snapshotStore() {
|
|
690
|
+
const scope = this.closest(".pnlight-flow-route") ??
|
|
691
|
+
this.closest(".pnlight-remote-ui") ??
|
|
692
|
+
this.parentElement ??
|
|
693
|
+
this;
|
|
694
|
+
let store = prependListSnapshots.get(scope);
|
|
695
|
+
if (!store) {
|
|
696
|
+
store = new Map();
|
|
697
|
+
prependListSnapshots.set(scope, store);
|
|
698
|
+
}
|
|
699
|
+
return store;
|
|
700
|
+
}
|
|
701
|
+
parsedItems() {
|
|
702
|
+
return parseArray(this.value("items")).flatMap((raw) => {
|
|
703
|
+
const item = parseObject(raw);
|
|
704
|
+
if (!item)
|
|
705
|
+
return [];
|
|
706
|
+
const title = typeof item.title === "string" ? item.title : "";
|
|
707
|
+
const body = typeof item.body === "string" ? item.body : "";
|
|
708
|
+
const iconPreview = typeof item.icon_preview === "string" ? item.icon_preview : "";
|
|
709
|
+
if (!title || !body || !iconPreview.startsWith("data:image/"))
|
|
710
|
+
return [];
|
|
711
|
+
return [{ title, body, iconPreview }];
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
currentStyleSignature() {
|
|
715
|
+
return JSON.stringify(PREPEND_LIST_PROPS
|
|
716
|
+
.filter((name) => ![
|
|
717
|
+
"instance_id",
|
|
718
|
+
"count",
|
|
719
|
+
"count_variable",
|
|
720
|
+
"items",
|
|
721
|
+
"reduced_motion"
|
|
722
|
+
].includes(name))
|
|
723
|
+
.map((name) => this.value(name)));
|
|
724
|
+
}
|
|
725
|
+
installShell() {
|
|
726
|
+
const showsIndicator = parseBoolean(this.value("shows_scroll_indicator"));
|
|
727
|
+
const listHorizontalPadding = Math.max(0, parseNumber(this.value("list_horizontal_padding"), 4));
|
|
728
|
+
const rowSpacing = Math.max(0, parseNumber(this.value("row_spacing"), 15));
|
|
729
|
+
const bottomPadding = Math.max(0, parseNumber(this.value("bottom_padding"), 20));
|
|
730
|
+
const rowHorizontalPadding = Math.max(0, parseNumber(this.value("row_horizontal_padding"), 16));
|
|
731
|
+
const rowVerticalPadding = Math.max(0, parseNumber(this.value("row_vertical_padding"), 16));
|
|
732
|
+
const iconSize = Math.max(0, parseNumber(this.value("icon_size"), 20));
|
|
733
|
+
const iconTextSpacing = Math.max(0, parseNumber(this.value("icon_text_spacing"), 13));
|
|
734
|
+
const textStatusSpacing = Math.max(0, parseNumber(this.value("text_status_spacing"), 13));
|
|
735
|
+
const cornerRadius = Math.max(0, parseNumber(this.value("corner_radius"), 20));
|
|
736
|
+
this.root.innerHTML = `
|
|
737
|
+
<style>
|
|
738
|
+
:host {
|
|
739
|
+
display: block;
|
|
740
|
+
width: 100%;
|
|
741
|
+
height: 100%;
|
|
742
|
+
min-width: 0;
|
|
743
|
+
min-height: 0;
|
|
744
|
+
overflow: hidden;
|
|
745
|
+
contain: layout paint;
|
|
746
|
+
}
|
|
747
|
+
.viewport {
|
|
748
|
+
box-sizing: border-box;
|
|
749
|
+
width: 100%;
|
|
750
|
+
height: 100%;
|
|
751
|
+
padding: 0 ${listHorizontalPadding}px ${bottomPadding}px;
|
|
752
|
+
overflow-x: hidden;
|
|
753
|
+
overflow-y: auto;
|
|
754
|
+
scrollbar-width: ${showsIndicator ? "auto" : "none"};
|
|
755
|
+
overscroll-behavior: contain;
|
|
756
|
+
}
|
|
757
|
+
.viewport::-webkit-scrollbar {
|
|
758
|
+
display: ${showsIndicator ? "block" : "none"};
|
|
759
|
+
}
|
|
760
|
+
.list {
|
|
761
|
+
display: flex;
|
|
762
|
+
width: 100%;
|
|
763
|
+
flex-direction: column;
|
|
764
|
+
gap: ${rowSpacing}px;
|
|
765
|
+
}
|
|
766
|
+
.row {
|
|
767
|
+
box-sizing: border-box;
|
|
768
|
+
display: flex;
|
|
769
|
+
width: 100%;
|
|
770
|
+
min-width: 0;
|
|
771
|
+
align-items: center;
|
|
772
|
+
padding: ${rowVerticalPadding}px ${rowHorizontalPadding}px;
|
|
773
|
+
overflow: hidden;
|
|
774
|
+
border-radius: ${cornerRadius}px;
|
|
775
|
+
background: ${cssColor(this.value("card_background_color"), "#fefefe")};
|
|
776
|
+
transform-origin: top center;
|
|
777
|
+
}
|
|
778
|
+
.icon {
|
|
779
|
+
display: block;
|
|
780
|
+
flex: 0 0 auto;
|
|
781
|
+
width: ${iconSize}px;
|
|
782
|
+
height: ${iconSize}px;
|
|
783
|
+
margin-right: ${iconTextSpacing}px;
|
|
784
|
+
object-fit: contain;
|
|
785
|
+
}
|
|
786
|
+
.copy {
|
|
787
|
+
flex: 1 1 auto;
|
|
788
|
+
min-width: 0;
|
|
789
|
+
}
|
|
790
|
+
.title,
|
|
791
|
+
.body {
|
|
792
|
+
overflow-wrap: anywhere;
|
|
793
|
+
}
|
|
794
|
+
.title {
|
|
795
|
+
color: ${cssColor(this.value("title_color"), "#1c1c1e")};
|
|
796
|
+
font-size: ${Math.max(1, parseNumber(this.value("title_font_size"), 14))}px;
|
|
797
|
+
font-weight: ${fontWeight(this.value("title_font_weight"), 700)};
|
|
798
|
+
}
|
|
799
|
+
.body {
|
|
800
|
+
color: ${cssColor(this.value("body_color"), "#3a3a3c")};
|
|
801
|
+
font-size: ${Math.max(1, parseNumber(this.value("body_font_size"), 12))}px;
|
|
802
|
+
font-weight: ${fontWeight(this.value("body_font_weight"), 300)};
|
|
803
|
+
}
|
|
804
|
+
.status {
|
|
805
|
+
flex: 0 0 auto;
|
|
806
|
+
margin-left: ${textStatusSpacing}px;
|
|
807
|
+
color: ${cssColor(this.value("status_color"), "#ff3b30")};
|
|
808
|
+
font-size: ${Math.max(1, parseNumber(this.value("status_font_size"), 12))}px;
|
|
809
|
+
font-weight: ${fontWeight(this.value("status_font_weight"), 600)};
|
|
810
|
+
white-space: nowrap;
|
|
811
|
+
}
|
|
812
|
+
</style>
|
|
813
|
+
<div class="viewport">
|
|
814
|
+
<div class="list" role="list"></div>
|
|
815
|
+
</div>
|
|
816
|
+
`;
|
|
817
|
+
this.viewport = this.root.querySelector(".viewport") ?? undefined;
|
|
818
|
+
this.list = this.root.querySelector(".list") ?? undefined;
|
|
819
|
+
}
|
|
820
|
+
rebuild(items, count) {
|
|
821
|
+
if (!this.list)
|
|
822
|
+
return;
|
|
823
|
+
this.list.replaceChildren(...Array.from({ length: count }, (_, offset) => {
|
|
824
|
+
const index = count - offset - 1;
|
|
825
|
+
return this.createRow(items[index], index);
|
|
826
|
+
}));
|
|
827
|
+
this.viewport?.scrollTo({ top: 0, behavior: "auto" });
|
|
828
|
+
}
|
|
829
|
+
prependRow(item, index) {
|
|
830
|
+
if (!this.list)
|
|
831
|
+
return;
|
|
832
|
+
const oldRows = [...this.list.querySelectorAll(".row")];
|
|
833
|
+
const oldPositions = new Map(oldRows.map((row) => [row.dataset.index ?? "", row.getBoundingClientRect().top]));
|
|
834
|
+
const row = this.createRow(item, index);
|
|
835
|
+
this.list.prepend(row);
|
|
836
|
+
const duration = Math.max(0, parseNumber(this.value("animation_duration"), 0.36) * 1000);
|
|
837
|
+
const slideDistance = Math.max(0, parseNumber(this.value("slide_distance"), 8));
|
|
838
|
+
const fades = parseBoolean(this.value("fade"), true);
|
|
839
|
+
const slides = parseBoolean(this.value("slide"), true);
|
|
840
|
+
const easing = "cubic-bezier(.4, 0, .2, 1)";
|
|
841
|
+
if (duration > 0) {
|
|
842
|
+
for (const existingRow of oldRows) {
|
|
843
|
+
const oldTop = oldPositions.get(existingRow.dataset.index ?? "");
|
|
844
|
+
if (oldTop == null)
|
|
845
|
+
continue;
|
|
846
|
+
const delta = oldTop - existingRow.getBoundingClientRect().top;
|
|
847
|
+
if (Math.abs(delta) < 0.5)
|
|
848
|
+
continue;
|
|
849
|
+
existingRow.animate([{ transform: `translateY(${delta}px)` }, { transform: "translateY(0)" }], { duration, easing });
|
|
850
|
+
}
|
|
851
|
+
row.animate([
|
|
852
|
+
{
|
|
853
|
+
opacity: fades ? 0 : 1,
|
|
854
|
+
transform: slides ? `translateY(${-slideDistance}px)` : "translateY(0)"
|
|
855
|
+
},
|
|
856
|
+
{ opacity: 1, transform: "translateY(0)" }
|
|
857
|
+
], { duration, easing });
|
|
858
|
+
}
|
|
859
|
+
this.viewport?.scrollTo({ top: 0, behavior: "auto" });
|
|
860
|
+
}
|
|
861
|
+
createRow(item, index) {
|
|
862
|
+
const status = String(this.value("status_text") ?? "");
|
|
863
|
+
const row = document.createElement("div");
|
|
864
|
+
row.className = "row";
|
|
865
|
+
row.dataset.index = String(index);
|
|
866
|
+
row.setAttribute("role", "listitem");
|
|
867
|
+
row.setAttribute("aria-label", [item.title, item.body, status].filter(Boolean).join(". "));
|
|
868
|
+
row.innerHTML = `
|
|
869
|
+
<img class="icon" src="${escapeHtml(item.iconPreview)}" alt="" aria-hidden="true" />
|
|
870
|
+
<div class="copy">
|
|
871
|
+
<div class="title">${escapeHtml(item.title)}</div>
|
|
872
|
+
<div class="body">${escapeHtml(item.body)}</div>
|
|
873
|
+
</div>
|
|
874
|
+
${status ? `<div class="status">${escapeHtml(status)}</div>` : ""}
|
|
875
|
+
`;
|
|
876
|
+
return row;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
function escapeHtml(value) {
|
|
880
|
+
return value
|
|
881
|
+
.replaceAll("&", "&")
|
|
882
|
+
.replaceAll("<", "<")
|
|
883
|
+
.replaceAll(">", ">")
|
|
884
|
+
.replaceAll('"', """)
|
|
885
|
+
.replaceAll("'", "'");
|
|
886
|
+
}
|
|
887
|
+
export function registerPNLightComponents() {
|
|
888
|
+
if (!customElements.get("pnlight-cta-button")) {
|
|
889
|
+
customElements.define("pnlight-cta-button", PNLightCtaButton);
|
|
890
|
+
}
|
|
891
|
+
if (!customElements.get("pnlight-icon-button")) {
|
|
892
|
+
customElements.define("pnlight-icon-button", PNLightIconButton);
|
|
893
|
+
}
|
|
894
|
+
if (!customElements.get("pnlight-circular-loader")) {
|
|
895
|
+
customElements.define("pnlight-circular-loader", PNLightCircularLoader);
|
|
896
|
+
}
|
|
897
|
+
if (!customElements.get("pnlight-animated-prepend-list")) {
|
|
898
|
+
customElements.define("pnlight-animated-prepend-list", PNLightAnimatedPrependList);
|
|
899
|
+
}
|
|
900
|
+
return new Map([
|
|
901
|
+
["pnlight.cta_button", { element: "pnlight-cta-button" }],
|
|
902
|
+
["pnlight.icon_button", { element: "pnlight-icon-button" }],
|
|
903
|
+
["pnlight.circular_loader", { element: "pnlight-circular-loader" }],
|
|
904
|
+
["pnlight.animated_prepend_list", { element: "pnlight-animated-prepend-list" }],
|
|
905
|
+
["pnlight.animated_threat_list", { element: "pnlight-animated-prepend-list" }]
|
|
906
|
+
]);
|
|
907
|
+
}
|
|
908
|
+
import { ArrowLeft, ArrowRight, Check, ChevronLeft, ChevronRight, CircleHelp, CircleMinus, CirclePlus, CircleX, Ellipsis, Heart, Info, Minus, Plus, Settings, ShieldHalf, Star, Trash2, X, createElement } from "lucide";
|
|
909
|
+
//# sourceMappingURL=custom-components.js.map
|