@pixerate/editor 0.246.0 → 0.249.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/README.md +1 -0
- package/dist/animation-editor/index.cjs +64 -61
- package/dist/animation-editor/index.js +8 -5
- package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-GCKK7V2I.cjs} +14 -11
- package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-T3JZST44.js} +7 -4
- package/dist/canvas/index.cjs +8 -8
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-UVPD55UZ.cjs → chunk-2SMMZDMG.cjs} +35 -35
- package/dist/chunk-2VJAVXLI.js +192 -0
- package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
- package/dist/chunk-3K6HWEXZ.cjs +92 -0
- package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
- package/dist/chunk-4D6KP5BV.js +92 -0
- package/dist/chunk-5RH3VXAK.js +269 -0
- package/dist/{chunk-LDPLEZ5T.js → chunk-6BIDVPED.js} +1 -1
- package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
- package/dist/chunk-BOHDJJ2O.cjs +192 -0
- package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
- package/dist/{chunk-DQWPMGH2.js → chunk-DOIU7VJG.js} +1 -1
- package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
- package/dist/chunk-EJLRBS5Q.js +301 -0
- package/dist/{chunk-Q2UYUWAZ.cjs → chunk-H4AOUUBE.cjs} +679 -164
- package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
- package/dist/{chunk-FK5LTDOO.cjs → chunk-IOFVM3L3.cjs} +7 -7
- package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
- package/dist/{chunk-VDAWA546.js → chunk-J7T5QZ45.js} +614 -99
- package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
- package/dist/{chunk-5MFDD7SP.cjs → chunk-KYX7NZ5V.cjs} +1 -1
- package/dist/chunk-LJRCU3BJ.cjs +301 -0
- package/dist/{chunk-XTWXBQD4.cjs → chunk-LP2MCSBE.cjs} +593 -236
- package/dist/{chunk-A23PSOBB.js → chunk-O75V4ZS3.js} +1 -1
- package/dist/chunk-OTTT5N3K.js +322 -0
- package/dist/{chunk-N6WUB3Y5.js → chunk-PZP2SZIZ.js} +2 -2
- package/dist/{chunk-4PMCMWQS.js → chunk-UBRJOIR5.js} +367 -10
- package/dist/chunk-W5M3J7PV.cjs +322 -0
- package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
- package/dist/{chunk-CEPKXLBS.cjs → chunk-WLJZZHUZ.cjs} +23 -23
- package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
- package/dist/chunk-ZEYMKDYS.cjs +269 -0
- package/dist/image-editor/effect-tools.d.cts +37 -4
- package/dist/image-editor/effect-tools.d.ts +37 -4
- package/dist/image-editor/index.cjs +1340 -1828
- package/dist/image-editor/index.d.cts +1 -1
- package/dist/image-editor/index.d.ts +1 -1
- package/dist/image-editor/index.js +298 -786
- package/dist/paint/index.cjs +8 -5
- package/dist/paint/index.js +13 -10
- package/dist/paint-editor/controller.d.cts +71 -2
- package/dist/paint-editor/controller.d.ts +71 -2
- package/dist/paint-editor/index.cjs +901 -589
- package/dist/paint-editor/index.d.cts +3 -0
- package/dist/paint-editor/index.d.ts +3 -0
- package/dist/paint-editor/index.js +365 -53
- package/dist/paint-editor/procedural.d.cts +82 -5
- package/dist/paint-editor/procedural.d.ts +82 -5
- package/dist/paint-editor/sticker-art.d.cts +55 -0
- package/dist/paint-editor/sticker-art.d.ts +55 -0
- package/dist/paint-editor/stickers.d.cts +30 -17
- package/dist/paint-editor/stickers.d.ts +30 -17
- package/dist/paint-editor/stroke.d.cts +4 -0
- package/dist/paint-editor/stroke.d.ts +4 -0
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/paint-editor/ui.d.cts +25 -4
- package/dist/paint-editor/ui.d.ts +25 -4
- package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.cts} +32 -5
- package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.ts} +32 -5
- package/dist/raster/index.cjs +17 -3
- package/dist/raster/index.d.cts +1 -0
- package/dist/raster/index.d.ts +1 -0
- package/dist/raster/index.js +23 -9
- package/dist/stickers/browser.d.cts +48 -0
- package/dist/stickers/browser.d.ts +48 -0
- package/dist/stickers/combine.d.cts +10 -0
- package/dist/stickers/combine.d.ts +10 -0
- package/dist/stickers/conformance.d.cts +18 -0
- package/dist/stickers/conformance.d.ts +18 -0
- package/dist/stickers/editor.d.cts +14 -0
- package/dist/stickers/editor.d.ts +14 -0
- package/dist/stickers/errors.d.cts +6 -0
- package/dist/stickers/errors.d.ts +6 -0
- package/dist/stickers/fake.d.cts +16 -0
- package/dist/stickers/fake.d.ts +16 -0
- package/dist/stickers/helpers.d.cts +51 -0
- package/dist/stickers/helpers.d.ts +51 -0
- package/dist/stickers/index.cjs +331 -0
- package/dist/stickers/index.d.cts +16 -0
- package/dist/stickers/index.d.ts +16 -0
- package/dist/stickers/index.js +331 -0
- package/dist/stickers/stamps.d.cts +13 -0
- package/dist/stickers/stamps.d.ts +13 -0
- package/dist/stickers/tools.d.cts +25 -0
- package/dist/stickers/tools.d.ts +25 -0
- package/dist/stickers/types.d.cts +123 -0
- package/dist/stickers/types.d.ts +123 -0
- package/dist/vector/index.cjs +978 -975
- package/dist/vector/index.js +9 -6
- package/package.json +11 -1
- package/skills/README.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +26 -32
- package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
- package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
- package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
- package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
- package/skills/pixerate-stickers/SKILL.md +45 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import {
|
|
2
|
+
StickerBrowser,
|
|
3
|
+
editorStickers,
|
|
4
|
+
stampOutline,
|
|
5
|
+
stampPixels
|
|
6
|
+
} from "../chunk-EJLRBS5Q.js";
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_STICKER_PAGE,
|
|
9
|
+
EDITOR_STICKERS_ID,
|
|
10
|
+
MAX_STICKER_PAGE,
|
|
11
|
+
STAMP_KINDS,
|
|
12
|
+
StickerError,
|
|
13
|
+
StickersSlot,
|
|
14
|
+
checkStickerSearchOptions,
|
|
15
|
+
closestStickerRefs,
|
|
16
|
+
createStickerToolProvider,
|
|
17
|
+
createStickerTools,
|
|
18
|
+
describeStickerRef,
|
|
19
|
+
editorStampOf,
|
|
20
|
+
normalizeStickerRef,
|
|
21
|
+
parseStickerRef,
|
|
22
|
+
stampCoverage,
|
|
23
|
+
stickerForAgent,
|
|
24
|
+
stickerIdFor,
|
|
25
|
+
stickerPage,
|
|
26
|
+
stickerRefOf
|
|
27
|
+
} from "../chunk-5RH3VXAK.js";
|
|
28
|
+
import "../chunk-4D6KP5BV.js";
|
|
29
|
+
import {
|
|
30
|
+
pngDataUrl
|
|
31
|
+
} from "../chunk-OTTT5N3K.js";
|
|
32
|
+
import "../chunk-QGHEDC7B.js";
|
|
33
|
+
|
|
34
|
+
// src/stickers/fake.ts
|
|
35
|
+
var CATALOGUE = [
|
|
36
|
+
...["sun", "moon", "cloud", "rain", "snow", "wind"].map((w, i) => ({ id: `weather-${w}`, name: w[0].toUpperCase() + w.slice(1), category: "weather", tags: ["weather", w], shape: "badge", colours: [["#f59e0b", "#64748b", "#94a3b8", "#2563eb", "#e0f2fe", "#14b8a6"][i], "#ffffff"], commercial: true })),
|
|
37
|
+
...["apple", "pear", "cherry", "lemon", "grape"].map((f, i) => ({ id: `fruit-${f}`, name: f[0].toUpperCase() + f.slice(1), category: "food", tags: ["fruit", f], shape: "tile", colours: [["#dc2626", "#84cc16", "#be123c", "#facc15", "#7c3aed"][i], "#166534"], commercial: true })),
|
|
38
|
+
...["new", "sale", "hot", "free"].map((b, i) => ({ id: `badge-${b}`, name: `${b[0].toUpperCase() + b.slice(1)} badge`, category: "badges", tags: ["badge", "label", b], shape: "badge", colours: [["#16a34a", "#dc2626", "#ea580c", "#0891b2"][i], "#ffffff"], commercial: true })),
|
|
39
|
+
{ id: "art-sketch", name: "Sketch", category: "art", tags: ["drawing", "non-commercial"], shape: "tile", colours: ["#1f2937", "#fde68a"], commercial: false }
|
|
40
|
+
];
|
|
41
|
+
var W = 120;
|
|
42
|
+
var H = 120;
|
|
43
|
+
function summaryOf(s) {
|
|
44
|
+
return {
|
|
45
|
+
id: s.id,
|
|
46
|
+
name: s.name,
|
|
47
|
+
category: s.category,
|
|
48
|
+
tags: s.tags,
|
|
49
|
+
description: s.shape === "badge" ? "A flat badge (tintable)." : "A two-colour tile.",
|
|
50
|
+
width: W,
|
|
51
|
+
height: H,
|
|
52
|
+
formats: ["svg", "png"],
|
|
53
|
+
licence: s.commercial ? { spdx: "CC0-1.0", name: "CC0 1.0", commercial: true } : { spdx: "CC-BY-NC-4.0", name: "CC BY-NC 4.0", attribution: "Fake Artist", commercial: false },
|
|
54
|
+
tintable: s.shape === "badge"
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function svgOf(s, fill) {
|
|
58
|
+
if (s.shape === "badge") {
|
|
59
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}"><path fill="${fill}" fill-rule="evenodd" d="M60 6A54 54 0 1 1 59.9 6ZM45 45H75V75H45Z"/></svg>`;
|
|
60
|
+
}
|
|
61
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}"><rect x="10" y="10" width="100" height="100" fill="${s.colours[0]}"/><rect x="10" y="10" width="100" height="50" fill="${s.colours[1]}"/></svg>`;
|
|
62
|
+
}
|
|
63
|
+
function pixelsOf(s, size, fill) {
|
|
64
|
+
const out = new Uint8ClampedArray(size * size * 4);
|
|
65
|
+
const hex = (c) => [parseInt(c.slice(1, 3), 16), parseInt(c.slice(3, 5), 16), parseInt(c.slice(5, 7), 16)];
|
|
66
|
+
for (let y = 0; y < size; y++) {
|
|
67
|
+
for (let x = 0; x < size; x++) {
|
|
68
|
+
const u = (x + 0.5) / size * W;
|
|
69
|
+
const v = (y + 0.5) / size * H;
|
|
70
|
+
let rgb = null;
|
|
71
|
+
if (s.shape === "badge") {
|
|
72
|
+
const inDisc = Math.hypot(u - 60, v - 60) <= 54;
|
|
73
|
+
const inNotch = u >= 45 && u <= 75 && v >= 45 && v <= 75;
|
|
74
|
+
if (inDisc && !inNotch) rgb = hex(fill);
|
|
75
|
+
} else if (u >= 10 && u <= 110 && v >= 10 && v <= 110) rgb = hex(v < 60 ? s.colours[1] : s.colours[0]);
|
|
76
|
+
if (!rgb) continue;
|
|
77
|
+
const i = (y * size + x) * 4;
|
|
78
|
+
out[i] = rgb[0];
|
|
79
|
+
out[i + 1] = rgb[1];
|
|
80
|
+
out[i + 2] = rgb[2];
|
|
81
|
+
out[i + 3] = 255;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
function createFakeStickerProvider(options = {}) {
|
|
87
|
+
const summaries = CATALOGUE.map(summaryOf);
|
|
88
|
+
const find = (id) => CATALOGUE.find((s) => s.id === id);
|
|
89
|
+
return {
|
|
90
|
+
id: options.id ?? "fake",
|
|
91
|
+
name: "Fake stickers",
|
|
92
|
+
version: "1",
|
|
93
|
+
capabilities: { supportsSearch: true, supportsSvg: true, supportsRaster: true, maxSize: 512 },
|
|
94
|
+
list: (o) => stickerPage(summaries, o),
|
|
95
|
+
search: (q, o) => stickerPage(summaries, o, q),
|
|
96
|
+
describe(id) {
|
|
97
|
+
const s = find(id);
|
|
98
|
+
if (!s) return void 0;
|
|
99
|
+
return { ...summaryOf(s), silhouette: s.shape === "badge" ? "M60 6A54 54 0 1 1 59.9 6Z" : "M10 10H110V110H10Z", colours: s.shape === "badge" ? [s.colours[0]] : [...s.colours] };
|
|
100
|
+
},
|
|
101
|
+
categories: () => [...new Set(CATALOGUE.map((s) => s.category))].map((c) => ({ id: c, name: c, count: CATALOGUE.filter((s) => s.category === c).length })),
|
|
102
|
+
async load(id, o = {}) {
|
|
103
|
+
if (options.loadDelayMs) await new Promise((r) => setTimeout(r, options.loadDelayMs));
|
|
104
|
+
const s = find(id);
|
|
105
|
+
if (!s) throw new StickerError("unknown_sticker", `No fake sticker "${id}".`);
|
|
106
|
+
if (options.failIds?.includes(id)) throw new StickerError("load_failed", `The fake sticker "${id}" failed to load (failIds).`);
|
|
107
|
+
const fill = s.shape === "badge" && o.colour ? o.colour.toLowerCase() : s.colours[0];
|
|
108
|
+
if (o.format === "png") {
|
|
109
|
+
const size = o.size ?? 128;
|
|
110
|
+
if (!(Number.isInteger(size) && size >= 8 && size <= 512)) throw new StickerError("invalid_argument", `size must be 8..512 px, got ${size}.`);
|
|
111
|
+
return { kind: "image", url: pngDataUrl(size, size, pixelsOf(s, size, fill)), width: size, height: size };
|
|
112
|
+
}
|
|
113
|
+
return { kind: "svg", svg: svgOf(s, fill) };
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// src/stickers/combine.ts
|
|
119
|
+
function combineStickerProviders(providers, options = {}) {
|
|
120
|
+
const ids = providers.map((p) => p.id);
|
|
121
|
+
const dup = ids.find((id, i) => ids.indexOf(id) !== i);
|
|
122
|
+
if (dup) throw new StickerError("invalid_argument", `Two sticker providers have the id "${dup}"; give each a unique id.`);
|
|
123
|
+
const byId = new Map(providers.map((p) => [p.id, p]));
|
|
124
|
+
const owner = (ref) => {
|
|
125
|
+
const { provider, id } = parseStickerRef(ref);
|
|
126
|
+
const p = byId.get(provider);
|
|
127
|
+
if (!p) throw new StickerError("unknown_provider", `No sticker provider "${provider}"; the providers are ${ids.join(", ") || "none"}.`);
|
|
128
|
+
return { p, id };
|
|
129
|
+
};
|
|
130
|
+
const prefix = (p, s) => ({ ...s, id: stickerRefOf(p, s.id) });
|
|
131
|
+
const page = async (query, o = {}) => {
|
|
132
|
+
const { after, limit = DEFAULT_STICKER_PAGE, ...filters } = o;
|
|
133
|
+
checkStickerSearchOptions({ limit });
|
|
134
|
+
let i = 0;
|
|
135
|
+
let inner;
|
|
136
|
+
if (after !== void 0) {
|
|
137
|
+
const m = /^(\d+)\|(.*)$/.exec(after);
|
|
138
|
+
if (!m || Number(m[1]) >= providers.length) throw new StickerError("invalid_argument", `after "${after}" is not a cursor from this provider; pass the next value of the previous page.`);
|
|
139
|
+
i = Number(m[1]);
|
|
140
|
+
inner = m[2] || void 0;
|
|
141
|
+
}
|
|
142
|
+
const get = (p, opts) => query === null ? p.list(opts) : p.search(query, opts);
|
|
143
|
+
let total = 0;
|
|
144
|
+
for (const p of providers) total += (await get(p, { ...filters, limit: 1 })).total;
|
|
145
|
+
const items = [];
|
|
146
|
+
let next;
|
|
147
|
+
while (i < providers.length && items.length < limit) {
|
|
148
|
+
const p = providers[i];
|
|
149
|
+
const res = await get(p, { ...filters, limit: limit - items.length, ...inner ? { after: inner } : {} });
|
|
150
|
+
items.push(...res.items.map((s) => prefix(p, s)));
|
|
151
|
+
if (res.next && res.items.length) {
|
|
152
|
+
inner = res.next;
|
|
153
|
+
if (items.length >= limit) next = `${i}|${inner}`;
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
i++;
|
|
157
|
+
inner = void 0;
|
|
158
|
+
}
|
|
159
|
+
if (!next && items.length >= limit && i < providers.length) next = `${i}|`;
|
|
160
|
+
return { items, total, ...next ? { next } : {} };
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
id: options.id ?? "stickers",
|
|
164
|
+
name: options.name ?? providers.map((p) => p.name).join(" + "),
|
|
165
|
+
namespaced: true,
|
|
166
|
+
capabilities: {
|
|
167
|
+
supportsSearch: providers.some((p) => p.capabilities.supportsSearch),
|
|
168
|
+
supportsSvg: providers.some((p) => p.capabilities.supportsSvg),
|
|
169
|
+
supportsRaster: providers.some((p) => p.capabilities.supportsRaster),
|
|
170
|
+
...providers.every((p) => p.capabilities.maxSize) ? { maxSize: Math.max(...providers.map((p) => p.capabilities.maxSize)) } : {}
|
|
171
|
+
},
|
|
172
|
+
list: (o) => page(null, o),
|
|
173
|
+
search: (q, o) => page(q, o),
|
|
174
|
+
async describe(ref) {
|
|
175
|
+
let o;
|
|
176
|
+
try {
|
|
177
|
+
o = owner(ref);
|
|
178
|
+
} catch {
|
|
179
|
+
return void 0;
|
|
180
|
+
}
|
|
181
|
+
const d = await o.p.describe(o.id);
|
|
182
|
+
return d ? { ...d, id: stickerRefOf(o.p, d.id) } : void 0;
|
|
183
|
+
},
|
|
184
|
+
async load(ref, o) {
|
|
185
|
+
const { p, id } = owner(ref);
|
|
186
|
+
return p.load(id, o);
|
|
187
|
+
},
|
|
188
|
+
async categories() {
|
|
189
|
+
const counts = /* @__PURE__ */ new Map();
|
|
190
|
+
for (const p of providers) {
|
|
191
|
+
for (const c of await p.categories?.() ?? []) {
|
|
192
|
+
const had = counts.get(c.id);
|
|
193
|
+
counts.set(c.id, { id: c.id, name: had?.name ?? c.name, count: (had?.count ?? 0) + c.count });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return [...counts.values()];
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/stickers/conformance.ts
|
|
202
|
+
var HEX = /^#[0-9a-fA-F]{6}$/;
|
|
203
|
+
function checkSummary(s, provider, issues) {
|
|
204
|
+
const at = (message) => issues.push({ stickerId: s.id, message });
|
|
205
|
+
if (typeof s.id !== "string" || !s.id) at("id is missing");
|
|
206
|
+
if (!provider.namespaced && s.id.includes(":")) at('id contains ":" (refs are provider:id; only a combined provider lists refs)');
|
|
207
|
+
if (typeof s.name !== "string" || !s.name) at("name is missing");
|
|
208
|
+
if (typeof s.category !== "string" || !s.category) at("category is missing");
|
|
209
|
+
if (!(s.width > 0 && s.height > 0)) at(`width and height must be positive, got ${s.width} \xD7 ${s.height}`);
|
|
210
|
+
if (!Array.isArray(s.formats) || !s.formats.length || s.formats.some((f) => f !== "svg" && f !== "png")) at("formats must list svg and / or png");
|
|
211
|
+
if (s.formats?.includes("svg") && !provider.capabilities.supportsSvg) at("lists svg but capabilities.supportsSvg is false");
|
|
212
|
+
if (s.formats?.includes("png") && !provider.capabilities.supportsRaster) at("lists png but capabilities.supportsRaster is false");
|
|
213
|
+
if (!s.licence || typeof s.licence.name !== "string" || !s.licence.name) at("licence.name is missing (every sticker says how it may be used)");
|
|
214
|
+
if (typeof s.licence?.commercial !== "boolean") at("licence.commercial is not a boolean");
|
|
215
|
+
if (typeof s.tintable !== "boolean") at("tintable is not a boolean");
|
|
216
|
+
if (s.thumbnail !== void 0 && !/^(data:|https:)/.test(s.thumbnail)) at("thumbnail must be a data: or https: URL");
|
|
217
|
+
}
|
|
218
|
+
async function checkStickerProvider(provider, options = {}) {
|
|
219
|
+
const issues = [];
|
|
220
|
+
const top = (message) => issues.push({ message });
|
|
221
|
+
if (typeof provider.id !== "string" || !provider.id) top("provider has no id");
|
|
222
|
+
else if (provider.id.includes(":")) top('provider id contains ":"');
|
|
223
|
+
if (typeof provider.name !== "string" || !provider.name) top("provider has no name");
|
|
224
|
+
const caps = provider.capabilities;
|
|
225
|
+
for (const k of ["supportsSearch", "supportsSvg", "supportsRaster"]) if (typeof caps?.[k] !== "boolean") top(`capabilities.${k} is not a boolean`);
|
|
226
|
+
if (caps?.maxSize !== void 0 && !(caps.maxSize > 0)) top("capabilities.maxSize must be positive");
|
|
227
|
+
const all = [];
|
|
228
|
+
const ids = /* @__PURE__ */ new Set();
|
|
229
|
+
let after;
|
|
230
|
+
let total = -1;
|
|
231
|
+
for (let n = 0; n < (options.maxPages ?? 50); n++) {
|
|
232
|
+
let page;
|
|
233
|
+
try {
|
|
234
|
+
page = await provider.list({ limit: 10, ...after ? { after } : {} });
|
|
235
|
+
} catch (e) {
|
|
236
|
+
top(`list() rejected: ${e.message}`);
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
if (!Array.isArray(page?.items) || typeof page.total !== "number") {
|
|
240
|
+
top("list() did not return { items, total }");
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
if (page.items.length > 10) top(`list({ limit: 10 }) returned ${page.items.length} stickers`);
|
|
244
|
+
if (total === -1) total = page.total;
|
|
245
|
+
for (const s of page.items) {
|
|
246
|
+
if (ids.has(s.id)) top(`duplicate id "${s.id}"`);
|
|
247
|
+
ids.add(s.id);
|
|
248
|
+
all.push(s);
|
|
249
|
+
checkSummary(s, provider, issues);
|
|
250
|
+
}
|
|
251
|
+
if (!page.next) break;
|
|
252
|
+
if (!page.items.length) {
|
|
253
|
+
top("list() returned an empty page with a next cursor");
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
after = page.next;
|
|
257
|
+
}
|
|
258
|
+
if (total !== -1 && all.length !== total) top(`list() pages hold ${all.length} stickers but total says ${total}`);
|
|
259
|
+
try {
|
|
260
|
+
const found = await provider.search("", { limit: 1 });
|
|
261
|
+
if (found.total !== total) top(`search("") total ${found.total} differs from list() total ${total}`);
|
|
262
|
+
} catch (e) {
|
|
263
|
+
top(`search("") rejected: ${e.message}`);
|
|
264
|
+
}
|
|
265
|
+
const first = all[0];
|
|
266
|
+
if (first) {
|
|
267
|
+
const byCategory = await provider.list({ category: first.category, limit: 100 });
|
|
268
|
+
if (byCategory.items.some((s) => s.category !== first.category)) top(`list({ category: "${first.category}" }) returned stickers of other categories`);
|
|
269
|
+
const d = await provider.describe(first.id);
|
|
270
|
+
if (!d) top(`describe("${first.id}") returned nothing for a listed sticker`);
|
|
271
|
+
else if (d.id !== first.id) top(`describe("${first.id}") returned id "${d.id}"`);
|
|
272
|
+
if (d?.colours?.some((c) => !HEX.test(c))) top(`describe("${first.id}").colours must be #rrggbb`);
|
|
273
|
+
}
|
|
274
|
+
if (await provider.describe("__no_such_sticker__") !== void 0) top("describe of an unknown id returned a sticker");
|
|
275
|
+
let rejected = false;
|
|
276
|
+
try {
|
|
277
|
+
await provider.load("__no_such_sticker__");
|
|
278
|
+
} catch {
|
|
279
|
+
rejected = true;
|
|
280
|
+
}
|
|
281
|
+
if (!rejected) top("load of an unknown id did not reject");
|
|
282
|
+
for (const s of all.slice(0, options.loads ?? 3)) {
|
|
283
|
+
for (const format of s.formats ?? []) {
|
|
284
|
+
try {
|
|
285
|
+
const asset = await provider.load(s.id, { format, size: 32 });
|
|
286
|
+
if (format === "svg" && (asset.kind !== "svg" || !/<svg[\s>]/.test(asset.svg))) issues.push({ stickerId: s.id, message: 'load({ format: "svg" }) did not return SVG' });
|
|
287
|
+
if (format === "png" && (asset.kind !== "image" || !/^(data:|https:)/.test(asset.url) || !(asset.width > 0 && asset.height > 0))) issues.push({ stickerId: s.id, message: 'load({ format: "png" }) did not return an image URL with its size' });
|
|
288
|
+
} catch (e) {
|
|
289
|
+
issues.push({ stickerId: s.id, message: `load({ format: "${format}" }) rejected: ${e.message}` });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const tintable = all.find((s) => s.tintable);
|
|
294
|
+
if (tintable) {
|
|
295
|
+
try {
|
|
296
|
+
const a = await provider.load(tintable.id, { format: tintable.formats[0], colour: "#123456", size: 32 });
|
|
297
|
+
if (a.kind === "svg" && !/#123456/i.test(a.svg)) issues.push({ stickerId: tintable.id, message: "a tintable sticker loaded with colour #123456 does not use it" });
|
|
298
|
+
} catch (e) {
|
|
299
|
+
issues.push({ stickerId: tintable.id, message: `load with a colour rejected: ${e.message}` });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return issues;
|
|
303
|
+
}
|
|
304
|
+
export {
|
|
305
|
+
DEFAULT_STICKER_PAGE,
|
|
306
|
+
EDITOR_STICKERS_ID,
|
|
307
|
+
MAX_STICKER_PAGE,
|
|
308
|
+
STAMP_KINDS,
|
|
309
|
+
StickerBrowser,
|
|
310
|
+
StickerError,
|
|
311
|
+
StickersSlot,
|
|
312
|
+
checkStickerProvider,
|
|
313
|
+
checkStickerSearchOptions,
|
|
314
|
+
closestStickerRefs,
|
|
315
|
+
combineStickerProviders,
|
|
316
|
+
createFakeStickerProvider,
|
|
317
|
+
createStickerToolProvider,
|
|
318
|
+
createStickerTools,
|
|
319
|
+
describeStickerRef,
|
|
320
|
+
editorStampOf,
|
|
321
|
+
editorStickers,
|
|
322
|
+
normalizeStickerRef,
|
|
323
|
+
parseStickerRef,
|
|
324
|
+
stampCoverage,
|
|
325
|
+
stampOutline,
|
|
326
|
+
stampPixels,
|
|
327
|
+
stickerForAgent,
|
|
328
|
+
stickerIdFor,
|
|
329
|
+
stickerPage,
|
|
330
|
+
stickerRefOf
|
|
331
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's own sticker stamps: procedural shapes (dot, star, heart, leaf, petal flower,
|
|
3
|
+
* confetti, splat, sparkle, ring) defined by a coverage function over the unit square, so no
|
|
4
|
+
* artwork is bundled. The paint editor's sticker spray draws them directly; `editorStickers()`
|
|
5
|
+
* offers them to every editor as the built-in sticker set (SVG outlines and PNGs).
|
|
6
|
+
*/
|
|
7
|
+
export type StampKind = 'dot' | 'star' | 'heart' | 'leaf' | 'flower' | 'confetti' | 'splat' | 'sparkle' | 'ring';
|
|
8
|
+
export declare const STAMP_KINDS: readonly StampKind[];
|
|
9
|
+
/**
|
|
10
|
+
* Coverage of a stamp at a point (u, v) of its unit square (−1..1, y down), 0..1, before shading.
|
|
11
|
+
* `t` is the sticker's seed for shapes with random parts (splat, confetti).
|
|
12
|
+
*/
|
|
13
|
+
export declare function stampCoverage(kind: StampKind, u: number, v: number, t: number): number;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's own sticker stamps: procedural shapes (dot, star, heart, leaf, petal flower,
|
|
3
|
+
* confetti, splat, sparkle, ring) defined by a coverage function over the unit square, so no
|
|
4
|
+
* artwork is bundled. The paint editor's sticker spray draws them directly; `editorStickers()`
|
|
5
|
+
* offers them to every editor as the built-in sticker set (SVG outlines and PNGs).
|
|
6
|
+
*/
|
|
7
|
+
export type StampKind = 'dot' | 'star' | 'heart' | 'leaf' | 'flower' | 'confetti' | 'splat' | 'sparkle' | 'ring';
|
|
8
|
+
export declare const STAMP_KINDS: readonly StampKind[];
|
|
9
|
+
/**
|
|
10
|
+
* Coverage of a stamp at a point (u, v) of its unit square (−1..1, y down), 0..1, before shading.
|
|
11
|
+
* `t` is the sticker's seed for shapes with random parts (splat, confetti).
|
|
12
|
+
*/
|
|
13
|
+
export declare function stampCoverage(kind: StampKind, u: number, v: number, t: number): number;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tools for a sticker library: `find_stickers` (search and page) and `describe_sticker`.
|
|
3
|
+
* Every sticker comes back as a `ref` (`provider:id`) for the editors' tools that place or spray
|
|
4
|
+
* stickers. Refusals name the valid choices.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentTool, AgentToolProvider } from '../tools/registry.cjs';
|
|
7
|
+
import type { StickerDescription, StickerProvider, StickerRef, StickerSummary } from './types.cjs';
|
|
8
|
+
/** A summary as the tools return it: `ref` instead of the provider's id. */
|
|
9
|
+
export declare function stickerForAgent(provider: StickerProvider, s: StickerSummary): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Looks up `ref` in `provider`, refusing an unknown or foreign ref with the closest ones it has.
|
|
12
|
+
* The editors use it to check refs before spraying or placing them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function describeStickerRef(provider: StickerProvider, ref: StickerRef): Promise<StickerDescription>;
|
|
15
|
+
export interface StickerToolsOptions {
|
|
16
|
+
/** The provider to use, read on every call (an editor's `StickersSlot`). */
|
|
17
|
+
provider: () => StickerProvider;
|
|
18
|
+
}
|
|
19
|
+
/** `find_stickers` and `describe_sticker` over the provider `options.provider()` returns. */
|
|
20
|
+
export declare function createStickerTools(options: StickerToolsOptions): AgentTool[];
|
|
21
|
+
/** The sticker library tools as a provider (id `stickers` by default). */
|
|
22
|
+
export declare function createStickerToolProvider(options: StickerToolsOptions & {
|
|
23
|
+
id?: string;
|
|
24
|
+
namespace?: string;
|
|
25
|
+
}): AgentToolProvider;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent tools for a sticker library: `find_stickers` (search and page) and `describe_sticker`.
|
|
3
|
+
* Every sticker comes back as a `ref` (`provider:id`) for the editors' tools that place or spray
|
|
4
|
+
* stickers. Refusals name the valid choices.
|
|
5
|
+
*/
|
|
6
|
+
import type { AgentTool, AgentToolProvider } from '../tools/registry.js';
|
|
7
|
+
import type { StickerDescription, StickerProvider, StickerRef, StickerSummary } from './types.js';
|
|
8
|
+
/** A summary as the tools return it: `ref` instead of the provider's id. */
|
|
9
|
+
export declare function stickerForAgent(provider: StickerProvider, s: StickerSummary): Record<string, unknown>;
|
|
10
|
+
/**
|
|
11
|
+
* Looks up `ref` in `provider`, refusing an unknown or foreign ref with the closest ones it has.
|
|
12
|
+
* The editors use it to check refs before spraying or placing them.
|
|
13
|
+
*/
|
|
14
|
+
export declare function describeStickerRef(provider: StickerProvider, ref: StickerRef): Promise<StickerDescription>;
|
|
15
|
+
export interface StickerToolsOptions {
|
|
16
|
+
/** The provider to use, read on every call (an editor's `StickersSlot`). */
|
|
17
|
+
provider: () => StickerProvider;
|
|
18
|
+
}
|
|
19
|
+
/** `find_stickers` and `describe_sticker` over the provider `options.provider()` returns. */
|
|
20
|
+
export declare function createStickerTools(options: StickerToolsOptions): AgentTool[];
|
|
21
|
+
/** The sticker library tools as a provider (id `stickers` by default). */
|
|
22
|
+
export declare function createStickerToolProvider(options: StickerToolsOptions & {
|
|
23
|
+
id?: string;
|
|
24
|
+
namespace?: string;
|
|
25
|
+
}): AgentToolProvider;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sticker provider contract: how an editor finds, describes and loads stickers from a library
|
|
3
|
+
* it knows nothing about (the editor's own stamps, a brand pack, user uploads, a third-party API).
|
|
4
|
+
* Libraries implement it structurally, like `EffectProvider` and `FontProvider`.
|
|
5
|
+
*
|
|
6
|
+
* Ids are the provider's own; a `StickerRef` (`provider:id`) names a sticker across providers
|
|
7
|
+
* (`combineStickerProviders` lists them that way).
|
|
8
|
+
*/
|
|
9
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
10
|
+
/** How a sticker's art may be used. Every sticker says. */
|
|
11
|
+
export interface StickerLicence {
|
|
12
|
+
/** SPDX id when there is one (`MIT`, `CC-BY-4.0`). */
|
|
13
|
+
spdx?: string;
|
|
14
|
+
/** Human-readable name. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Credit line the licence asks for. */
|
|
17
|
+
attribution?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
/** May be used commercially. */
|
|
20
|
+
commercial: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type StickerFormat = 'svg' | 'png';
|
|
23
|
+
/** A sticker in a list or search result. */
|
|
24
|
+
export interface StickerSummary {
|
|
25
|
+
/** The provider's id (no `:` needed; `combineStickerProviders` prefixes its own). */
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
category: string;
|
|
29
|
+
tags?: string[];
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Natural size in px, for layout before the art is loaded. */
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
/** A small `data:` or `https:` image. */
|
|
35
|
+
thumbnail?: string;
|
|
36
|
+
/** The formats `load` can return. */
|
|
37
|
+
formats: StickerFormat[];
|
|
38
|
+
licence: StickerLicence;
|
|
39
|
+
/** Flat, single-colour art: `load(id, { colour })` recolours it (the paint editor's spray colours it). */
|
|
40
|
+
tintable: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Everything about one sticker. */
|
|
43
|
+
export interface StickerDescription extends StickerSummary {
|
|
44
|
+
/** SVG path data of its outline, in its natural box (for die-cut treatments). */
|
|
45
|
+
silhouette?: string;
|
|
46
|
+
/** Dominant colours #rrggbb, for matching and recolouring. */
|
|
47
|
+
colours?: string[];
|
|
48
|
+
variants?: {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
}[];
|
|
52
|
+
}
|
|
53
|
+
/** A sticker's art. */
|
|
54
|
+
export type StickerAsset = {
|
|
55
|
+
kind: 'svg';
|
|
56
|
+
svg: string;
|
|
57
|
+
silhouette?: string;
|
|
58
|
+
}
|
|
59
|
+
/** `url`: a `data:` or `https:` image. */
|
|
60
|
+
| {
|
|
61
|
+
kind: 'image';
|
|
62
|
+
url: string;
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
};
|
|
66
|
+
/** One page of results. Pages stay small; follow `next` (pass it as `after`). */
|
|
67
|
+
export interface StickerPage {
|
|
68
|
+
items: StickerSummary[];
|
|
69
|
+
/** How many match in all. */
|
|
70
|
+
total: number;
|
|
71
|
+
next?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface StickerSearchOptions {
|
|
74
|
+
category?: string;
|
|
75
|
+
/** Every tag must match. */
|
|
76
|
+
tags?: string[];
|
|
77
|
+
/** Page size (providers cap it; 1..100, default 24). */
|
|
78
|
+
limit?: number;
|
|
79
|
+
/** `next` from the previous page. */
|
|
80
|
+
after?: string;
|
|
81
|
+
licence?: {
|
|
82
|
+
commercial?: boolean;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export interface StickerLoadOptions {
|
|
86
|
+
format?: StickerFormat;
|
|
87
|
+
/** Longest side in px for raster art. */
|
|
88
|
+
size?: number;
|
|
89
|
+
/** #rrggbb: recolour a tintable sticker. */
|
|
90
|
+
colour?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface StickerProviderCapabilities {
|
|
93
|
+
supportsSearch: boolean;
|
|
94
|
+
supportsSvg: boolean;
|
|
95
|
+
supportsRaster: boolean;
|
|
96
|
+
/** The largest raster `size` it loads. */
|
|
97
|
+
maxSize?: number;
|
|
98
|
+
}
|
|
99
|
+
export interface StickerProvider {
|
|
100
|
+
/** Short and unique among the providers an editor uses: `editor`, `acme-brand`, `uploads`. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
readonly name: string;
|
|
103
|
+
readonly version?: string;
|
|
104
|
+
readonly capabilities: StickerProviderCapabilities;
|
|
105
|
+
/** Its ids are already refs (`provider:id`): a combination of providers (`combineStickerProviders`). */
|
|
106
|
+
readonly namespaced?: boolean;
|
|
107
|
+
/** The stickers, a page at a time; `category` and `tags` filter. */
|
|
108
|
+
list(options?: StickerSearchOptions): MaybePromise<StickerPage>;
|
|
109
|
+
/** Stickers matching words in their name, tags, category or description; `""` is `list`. */
|
|
110
|
+
search(query: string, options?: StickerSearchOptions): MaybePromise<StickerPage>;
|
|
111
|
+
/** A sticker by id, or `undefined`. */
|
|
112
|
+
describe(id: string): MaybePromise<StickerDescription | undefined>;
|
|
113
|
+
/** The art; rejects with a `StickerError` (`unknown_sticker`, `unsupported_format`) when it can't. */
|
|
114
|
+
load(id: string, options?: StickerLoadOptions): MaybePromise<StickerAsset>;
|
|
115
|
+
/** Categories with counts, when the provider knows them. */
|
|
116
|
+
categories?(): MaybePromise<Array<{
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
count: number;
|
|
120
|
+
}>>;
|
|
121
|
+
}
|
|
122
|
+
/** `provider:id`, the name of a sticker across providers. A bare editor stamp (`"star"`) means `editor:star`. */
|
|
123
|
+
export type StickerRef = string;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sticker provider contract: how an editor finds, describes and loads stickers from a library
|
|
3
|
+
* it knows nothing about (the editor's own stamps, a brand pack, user uploads, a third-party API).
|
|
4
|
+
* Libraries implement it structurally, like `EffectProvider` and `FontProvider`.
|
|
5
|
+
*
|
|
6
|
+
* Ids are the provider's own; a `StickerRef` (`provider:id`) names a sticker across providers
|
|
7
|
+
* (`combineStickerProviders` lists them that way).
|
|
8
|
+
*/
|
|
9
|
+
export type MaybePromise<T> = T | Promise<T>;
|
|
10
|
+
/** How a sticker's art may be used. Every sticker says. */
|
|
11
|
+
export interface StickerLicence {
|
|
12
|
+
/** SPDX id when there is one (`MIT`, `CC-BY-4.0`). */
|
|
13
|
+
spdx?: string;
|
|
14
|
+
/** Human-readable name. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Credit line the licence asks for. */
|
|
17
|
+
attribution?: string;
|
|
18
|
+
url?: string;
|
|
19
|
+
/** May be used commercially. */
|
|
20
|
+
commercial: boolean;
|
|
21
|
+
}
|
|
22
|
+
export type StickerFormat = 'svg' | 'png';
|
|
23
|
+
/** A sticker in a list or search result. */
|
|
24
|
+
export interface StickerSummary {
|
|
25
|
+
/** The provider's id (no `:` needed; `combineStickerProviders` prefixes its own). */
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
category: string;
|
|
29
|
+
tags?: string[];
|
|
30
|
+
description?: string;
|
|
31
|
+
/** Natural size in px, for layout before the art is loaded. */
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
/** A small `data:` or `https:` image. */
|
|
35
|
+
thumbnail?: string;
|
|
36
|
+
/** The formats `load` can return. */
|
|
37
|
+
formats: StickerFormat[];
|
|
38
|
+
licence: StickerLicence;
|
|
39
|
+
/** Flat, single-colour art: `load(id, { colour })` recolours it (the paint editor's spray colours it). */
|
|
40
|
+
tintable: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Everything about one sticker. */
|
|
43
|
+
export interface StickerDescription extends StickerSummary {
|
|
44
|
+
/** SVG path data of its outline, in its natural box (for die-cut treatments). */
|
|
45
|
+
silhouette?: string;
|
|
46
|
+
/** Dominant colours #rrggbb, for matching and recolouring. */
|
|
47
|
+
colours?: string[];
|
|
48
|
+
variants?: {
|
|
49
|
+
id: string;
|
|
50
|
+
name: string;
|
|
51
|
+
}[];
|
|
52
|
+
}
|
|
53
|
+
/** A sticker's art. */
|
|
54
|
+
export type StickerAsset = {
|
|
55
|
+
kind: 'svg';
|
|
56
|
+
svg: string;
|
|
57
|
+
silhouette?: string;
|
|
58
|
+
}
|
|
59
|
+
/** `url`: a `data:` or `https:` image. */
|
|
60
|
+
| {
|
|
61
|
+
kind: 'image';
|
|
62
|
+
url: string;
|
|
63
|
+
width: number;
|
|
64
|
+
height: number;
|
|
65
|
+
};
|
|
66
|
+
/** One page of results. Pages stay small; follow `next` (pass it as `after`). */
|
|
67
|
+
export interface StickerPage {
|
|
68
|
+
items: StickerSummary[];
|
|
69
|
+
/** How many match in all. */
|
|
70
|
+
total: number;
|
|
71
|
+
next?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface StickerSearchOptions {
|
|
74
|
+
category?: string;
|
|
75
|
+
/** Every tag must match. */
|
|
76
|
+
tags?: string[];
|
|
77
|
+
/** Page size (providers cap it; 1..100, default 24). */
|
|
78
|
+
limit?: number;
|
|
79
|
+
/** `next` from the previous page. */
|
|
80
|
+
after?: string;
|
|
81
|
+
licence?: {
|
|
82
|
+
commercial?: boolean;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export interface StickerLoadOptions {
|
|
86
|
+
format?: StickerFormat;
|
|
87
|
+
/** Longest side in px for raster art. */
|
|
88
|
+
size?: number;
|
|
89
|
+
/** #rrggbb: recolour a tintable sticker. */
|
|
90
|
+
colour?: string;
|
|
91
|
+
}
|
|
92
|
+
export interface StickerProviderCapabilities {
|
|
93
|
+
supportsSearch: boolean;
|
|
94
|
+
supportsSvg: boolean;
|
|
95
|
+
supportsRaster: boolean;
|
|
96
|
+
/** The largest raster `size` it loads. */
|
|
97
|
+
maxSize?: number;
|
|
98
|
+
}
|
|
99
|
+
export interface StickerProvider {
|
|
100
|
+
/** Short and unique among the providers an editor uses: `editor`, `acme-brand`, `uploads`. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
readonly name: string;
|
|
103
|
+
readonly version?: string;
|
|
104
|
+
readonly capabilities: StickerProviderCapabilities;
|
|
105
|
+
/** Its ids are already refs (`provider:id`): a combination of providers (`combineStickerProviders`). */
|
|
106
|
+
readonly namespaced?: boolean;
|
|
107
|
+
/** The stickers, a page at a time; `category` and `tags` filter. */
|
|
108
|
+
list(options?: StickerSearchOptions): MaybePromise<StickerPage>;
|
|
109
|
+
/** Stickers matching words in their name, tags, category or description; `""` is `list`. */
|
|
110
|
+
search(query: string, options?: StickerSearchOptions): MaybePromise<StickerPage>;
|
|
111
|
+
/** A sticker by id, or `undefined`. */
|
|
112
|
+
describe(id: string): MaybePromise<StickerDescription | undefined>;
|
|
113
|
+
/** The art; rejects with a `StickerError` (`unknown_sticker`, `unsupported_format`) when it can't. */
|
|
114
|
+
load(id: string, options?: StickerLoadOptions): MaybePromise<StickerAsset>;
|
|
115
|
+
/** Categories with counts, when the provider knows them. */
|
|
116
|
+
categories?(): MaybePromise<Array<{
|
|
117
|
+
id: string;
|
|
118
|
+
name: string;
|
|
119
|
+
count: number;
|
|
120
|
+
}>>;
|
|
121
|
+
}
|
|
122
|
+
/** `provider:id`, the name of a sticker across providers. A bare editor stamp (`"star"`) means `editor:star`. */
|
|
123
|
+
export type StickerRef = string;
|