@antglobal/copilot-cards-web 1.0.7 → 1.0.8
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/README.md +45 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +73 -36
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ The package includes the core schema and action APIs, responsive rendering, Shad
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npm install @antglobal/copilot-cards-web
|
|
10
|
+
npm install @antglobal/copilot-cards-web@1.0.7
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
`@antglobal/copilot-cards-core` is installed automatically.
|
|
@@ -50,6 +50,50 @@ card.updateVariables({ userName: "Alice" });
|
|
|
50
50
|
card.dispose();
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
## Stable host updates
|
|
54
|
+
|
|
55
|
+
Create the card once and keep its `CardInstance`. Input events should update
|
|
56
|
+
only the variables that changed. Do not call `renderCard()` again for input updates,
|
|
57
|
+
because remounting the card recreates image elements and can cause visible flicker.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import {
|
|
61
|
+
renderCard,
|
|
62
|
+
type CardInstance,
|
|
63
|
+
type CardSchema,
|
|
64
|
+
} from "@antglobal/copilot-cards-web";
|
|
65
|
+
|
|
66
|
+
let card: CardInstance | null = null;
|
|
67
|
+
|
|
68
|
+
export function mountDataRechargeCard(
|
|
69
|
+
container: HTMLElement,
|
|
70
|
+
schema: CardSchema,
|
|
71
|
+
): void {
|
|
72
|
+
card?.dispose();
|
|
73
|
+
card = renderCard(container, schema, {
|
|
74
|
+
emit: (eventName, payload) => {
|
|
75
|
+
if (eventName !== "dataRecharge.phone.input") return;
|
|
76
|
+
|
|
77
|
+
const value = String(
|
|
78
|
+
(payload as { value?: unknown } | undefined)?.value ?? "",
|
|
79
|
+
);
|
|
80
|
+
if (!card) return;
|
|
81
|
+
card.updateVariables({ phoneNumber: value });
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function unmountDataRechargeCard(): void {
|
|
87
|
+
card?.dispose();
|
|
88
|
+
card = null;
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Keep `skuOptions` and `isSkuLoading` out of each keystroke patch unless their
|
|
93
|
+
values actually changed. Fetching or filtering SKU data can run from the
|
|
94
|
+
`dataRecharge.phone.commit` event instead of remounting the card on every
|
|
95
|
+
`dataRecharge.phone.input` event.
|
|
96
|
+
|
|
53
97
|
## Framework usage
|
|
54
98
|
|
|
55
99
|
The renderer accesses browser APIs and should be loaded on the client in frameworks that perform server-side rendering.
|
package/dist/index.d.ts
CHANGED
|
@@ -707,6 +707,10 @@ declare class CardInput extends BaseElement {
|
|
|
707
707
|
declare class CardImage extends BaseElement {
|
|
708
708
|
static readonly is = "ai-card-image";
|
|
709
709
|
private _lightbox;
|
|
710
|
+
private readonly _wiredImages;
|
|
711
|
+
private readonly _wiredLightboxes;
|
|
712
|
+
private readonly _wiredCloseButtons;
|
|
713
|
+
private readonly _handleEscape;
|
|
710
714
|
protected render(): void;
|
|
711
715
|
private applyHostDimension;
|
|
712
716
|
private resolveDeclaredDimension;
|
package/dist/index.js
CHANGED
|
@@ -2464,7 +2464,9 @@ class BaseElement extends HTMLElement {
|
|
|
2464
2464
|
}
|
|
2465
2465
|
}
|
|
2466
2466
|
for (const attribute of Array.from(desired.attributes)) {
|
|
2467
|
-
current.
|
|
2467
|
+
if (current.getAttribute(attribute.name) !== attribute.value) {
|
|
2468
|
+
current.setAttribute(attribute.name, attribute.value);
|
|
2469
|
+
}
|
|
2468
2470
|
}
|
|
2469
2471
|
if (current === preserved)
|
|
2470
2472
|
return;
|
|
@@ -3895,6 +3897,14 @@ class CardImage extends BaseElement {
|
|
|
3895
3897
|
constructor() {
|
|
3896
3898
|
super(...arguments);
|
|
3897
3899
|
this._lightbox = null;
|
|
3900
|
+
this._wiredImages = new WeakSet();
|
|
3901
|
+
this._wiredLightboxes = new WeakSet();
|
|
3902
|
+
this._wiredCloseButtons = new WeakSet();
|
|
3903
|
+
this._handleEscape = (event) => {
|
|
3904
|
+
if (event.key === 'Escape' && this._lightbox) {
|
|
3905
|
+
this.closeLightbox(this._lightbox);
|
|
3906
|
+
}
|
|
3907
|
+
};
|
|
3898
3908
|
}
|
|
3899
3909
|
render() {
|
|
3900
3910
|
if (!this.shadowRoot || !this._node)
|
|
@@ -3935,7 +3945,7 @@ class CardImage extends BaseElement {
|
|
|
3935
3945
|
imgStyles.push(`object-fit:${objectFit}`);
|
|
3936
3946
|
if (inlineStyle)
|
|
3937
3947
|
imgStyles.push(inlineStyle);
|
|
3938
|
-
|
|
3948
|
+
const markup = `
|
|
3939
3949
|
<style>
|
|
3940
3950
|
:host {
|
|
3941
3951
|
display: inline-block;
|
|
@@ -4043,11 +4053,25 @@ class CardImage extends BaseElement {
|
|
|
4043
4053
|
loading="lazy"
|
|
4044
4054
|
/>
|
|
4045
4055
|
</div>
|
|
4046
|
-
|
|
4047
|
-
<
|
|
4048
|
-
|
|
4049
|
-
|
|
4050
|
-
|
|
4056
|
+
${preview ? `
|
|
4057
|
+
<div class="lightbox">
|
|
4058
|
+
<button class="lightbox-close" aria-label="Close">×</button>
|
|
4059
|
+
<img class="lightbox-image" src="${imgSrc}" alt="${imgAlt}" />
|
|
4060
|
+
</div>
|
|
4061
|
+
` : ''}
|
|
4062
|
+
`;
|
|
4063
|
+
const currentImage = this.shadowRoot.querySelector('.card-image');
|
|
4064
|
+
const keepError = currentImage?.classList.contains('error') === true
|
|
4065
|
+
&& currentImage.getAttribute('src') === imgSrc;
|
|
4066
|
+
if (this._lightbox?.classList.contains('open')) {
|
|
4067
|
+
this.closeLightbox(this._lightbox);
|
|
4068
|
+
}
|
|
4069
|
+
if (!currentImage
|
|
4070
|
+
|| !this.patchShadowHTMLPreservingElement(markup, currentImage, '.card-image')) {
|
|
4071
|
+
this.setShadowHTML(markup);
|
|
4072
|
+
}
|
|
4073
|
+
if (keepError)
|
|
4074
|
+
currentImage.classList.add('error');
|
|
4051
4075
|
this.bindEvents(preview);
|
|
4052
4076
|
}
|
|
4053
4077
|
applyHostDimension(property, styleValue, propValue) {
|
|
@@ -4076,53 +4100,66 @@ class CardImage extends BaseElement {
|
|
|
4076
4100
|
const img = this.shadowRoot.querySelector('.card-image');
|
|
4077
4101
|
const lightbox = this.shadowRoot.querySelector('.lightbox');
|
|
4078
4102
|
const closeBtn = this.shadowRoot.querySelector('.lightbox-close');
|
|
4079
|
-
if (!img
|
|
4103
|
+
if (!img)
|
|
4080
4104
|
return;
|
|
4081
4105
|
// Handle image load/error states
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4106
|
+
if (!this._wiredImages.has(img)) {
|
|
4107
|
+
this._wiredImages.add(img);
|
|
4108
|
+
img.addEventListener('load', () => {
|
|
4109
|
+
img.classList.remove('loading');
|
|
4110
|
+
img.classList.remove('error');
|
|
4111
|
+
});
|
|
4112
|
+
img.addEventListener('error', () => {
|
|
4113
|
+
img.classList.remove('loading');
|
|
4114
|
+
img.classList.add('error');
|
|
4115
|
+
});
|
|
4116
|
+
img.addEventListener('click', (event) => {
|
|
4117
|
+
if (this._props.preview === false)
|
|
4118
|
+
return;
|
|
4119
|
+
const activeLightbox = this.shadowRoot?.querySelector('.lightbox');
|
|
4120
|
+
if (!activeLightbox)
|
|
4121
|
+
return;
|
|
4122
|
+
event.stopPropagation();
|
|
4123
|
+
this.openLightbox(activeLightbox);
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
if (!preview || !lightbox || !closeBtn) {
|
|
4127
|
+
this._lightbox = null;
|
|
4090
4128
|
return;
|
|
4091
|
-
|
|
4092
|
-
img.addEventListener('click', (e) => {
|
|
4093
|
-
e.stopPropagation();
|
|
4094
|
-
this.openLightbox(lightbox);
|
|
4095
|
-
});
|
|
4129
|
+
}
|
|
4096
4130
|
// Close lightbox on overlay/close button click
|
|
4097
|
-
|
|
4098
|
-
this.
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4131
|
+
if (!this._wiredLightboxes.has(lightbox)) {
|
|
4132
|
+
this._wiredLightboxes.add(lightbox);
|
|
4133
|
+
lightbox.addEventListener('click', () => {
|
|
4134
|
+
this.closeLightbox(lightbox);
|
|
4135
|
+
});
|
|
4136
|
+
}
|
|
4137
|
+
if (!this._wiredCloseButtons.has(closeBtn)) {
|
|
4138
|
+
this._wiredCloseButtons.add(closeBtn);
|
|
4139
|
+
closeBtn.addEventListener('click', (event) => {
|
|
4140
|
+
event.stopPropagation();
|
|
4141
|
+
this.closeLightbox(lightbox);
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4104
4144
|
// Close on Escape key
|
|
4105
4145
|
this._lightbox = lightbox;
|
|
4106
4146
|
}
|
|
4107
4147
|
openLightbox(lightbox) {
|
|
4148
|
+
this._lightbox = lightbox;
|
|
4108
4149
|
lightbox.classList.add('open');
|
|
4109
4150
|
document.body.style.overflow = 'hidden';
|
|
4110
|
-
|
|
4111
|
-
const handleEscape = (e) => {
|
|
4112
|
-
if (e.key === 'Escape') {
|
|
4113
|
-
this.closeLightbox(lightbox);
|
|
4114
|
-
document.removeEventListener('keydown', handleEscape);
|
|
4115
|
-
}
|
|
4116
|
-
};
|
|
4117
|
-
document.addEventListener('keydown', handleEscape);
|
|
4151
|
+
document.addEventListener('keydown', this._handleEscape);
|
|
4118
4152
|
}
|
|
4119
4153
|
closeLightbox(lightbox) {
|
|
4120
4154
|
lightbox.classList.remove('open');
|
|
4121
4155
|
document.body.style.overflow = '';
|
|
4156
|
+
document.removeEventListener('keydown', this._handleEscape);
|
|
4122
4157
|
}
|
|
4123
4158
|
disconnectedCallback() {
|
|
4124
4159
|
// Ensure body overflow is restored when element is removed
|
|
4125
4160
|
document.body.style.overflow = '';
|
|
4161
|
+
document.removeEventListener('keydown', this._handleEscape);
|
|
4162
|
+
this._lightbox = null;
|
|
4126
4163
|
}
|
|
4127
4164
|
}
|
|
4128
4165
|
CardImage.is = 'ai-card-image';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antglobal/copilot-cards-web",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "Web Component renderer for copilot bot card SDK — PC + Mobile + WebView unified rendering via Custom Elements",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
],
|
|
29
29
|
"license": "MIT",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@antglobal/copilot-cards-core": "^1.0.
|
|
31
|
+
"@antglobal/copilot-cards-core": "^1.0.8",
|
|
32
32
|
"echarts": "^5.6.0",
|
|
33
33
|
"marked": "^18.0.5",
|
|
34
34
|
"tslib": "^2.8.1",
|