@avyn/initials-avatar 1.0.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/dist/chunk-PMFHYTR7.js +153 -0
- package/dist/index.cjs +187 -0
- package/dist/index.d.cts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +26 -0
- package/dist/react.cjs +160 -0
- package/dist/react.d.cts +16 -0
- package/dist/react.d.ts +16 -0
- package/dist/react.js +58 -0
- package/dist/vue.cjs +179 -0
- package/dist/vue.d.cts +146 -0
- package/dist/vue.d.ts +146 -0
- package/dist/vue.js +76 -0
- package/package.json +59 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var DEFAULT_SIZE = 96;
|
|
3
|
+
var DEFAULT_FONT_FAMILY = '"Segoe UI", Arial, sans-serif';
|
|
4
|
+
function getInitials(name) {
|
|
5
|
+
const cleaned = (name ?? "").trim();
|
|
6
|
+
if (!cleaned) return "?";
|
|
7
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
8
|
+
if (parts.length === 1) {
|
|
9
|
+
const [firstChar, secondChar] = [...parts[0]].filter(Boolean);
|
|
10
|
+
return (firstChar ?? "").toUpperCase() + (secondChar ?? "").toUpperCase();
|
|
11
|
+
}
|
|
12
|
+
const first = parts[0]?.[0] ?? "";
|
|
13
|
+
const last = parts[parts.length - 1]?.[0] ?? "";
|
|
14
|
+
return `${first}${last}`.toUpperCase();
|
|
15
|
+
}
|
|
16
|
+
function createAvatarSvg(name, options = {}) {
|
|
17
|
+
const size = options.size ?? DEFAULT_SIZE;
|
|
18
|
+
const backgroundColor = options.backgroundColor ?? stringToColor(name);
|
|
19
|
+
const fontColor = options.fontColor ?? "#ffffff";
|
|
20
|
+
const fontSize = options.fontSize ?? Math.round(size * 0.42);
|
|
21
|
+
const fontFamily = options.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
22
|
+
const borderWidth = options.borderWidth ?? 0;
|
|
23
|
+
const borderColor = options.borderColor ?? "transparent";
|
|
24
|
+
const borderRadius = clamp(options.borderRadius ?? size * 0.2, 0, size / 2);
|
|
25
|
+
const fontWeight = options.bold ? 700 : 600;
|
|
26
|
+
const initials = (options.initialsOverride ?? getInitials(name)).slice(0, 3);
|
|
27
|
+
const ariaLabel = name && name.trim().length > 0 ? name.trim() : "Avatar";
|
|
28
|
+
return [
|
|
29
|
+
'<svg xmlns="http://www.w3.org/2000/svg" role="img"',
|
|
30
|
+
` width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"`,
|
|
31
|
+
` aria-label="${escapeXml(ariaLabel)}">`,
|
|
32
|
+
`<rect width="${size}" height="${size}" fill="${escapeXml(backgroundColor)}"`,
|
|
33
|
+
` stroke="${escapeXml(borderColor)}" stroke-width="${borderWidth}"`,
|
|
34
|
+
` rx="${borderRadius}" ry="${borderRadius}"/>`,
|
|
35
|
+
`<text x="50%" y="50%" fill="${escapeXml(fontColor)}"`,
|
|
36
|
+
` font-family="${escapeXml(fontFamily)}" font-size="${fontSize}"`,
|
|
37
|
+
` font-weight="${fontWeight}" text-anchor="middle"`,
|
|
38
|
+
' dominant-baseline="central">',
|
|
39
|
+
`${escapeXml(initials)}`,
|
|
40
|
+
"</text>",
|
|
41
|
+
"</svg>"
|
|
42
|
+
].join("");
|
|
43
|
+
}
|
|
44
|
+
function createAvatarDataUri(name, options = {}) {
|
|
45
|
+
const svg = createAvatarSvg(name, options);
|
|
46
|
+
const encoded = toBase64(svg);
|
|
47
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
48
|
+
}
|
|
49
|
+
function createAvatar(name, options = {}) {
|
|
50
|
+
const svg = createAvatarSvg(name, options);
|
|
51
|
+
const dataUri = createAvatarDataUri(name, options);
|
|
52
|
+
return { svg, dataUri };
|
|
53
|
+
}
|
|
54
|
+
function createHttpResponse(name, options = {}) {
|
|
55
|
+
return {
|
|
56
|
+
contentType: "image/svg+xml",
|
|
57
|
+
body: createAvatarSvg(name, options)
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function sendExpressAvatar(res, name, options = {}, handlerOptions = {}) {
|
|
61
|
+
const payload = createHttpResponse(name, options);
|
|
62
|
+
res.setHeader?.("Content-Type", payload.contentType);
|
|
63
|
+
if (handlerOptions.cacheControl) res.setHeader?.("Cache-Control", handlerOptions.cacheControl);
|
|
64
|
+
res.send(payload.body);
|
|
65
|
+
}
|
|
66
|
+
function sendFastifyAvatar(reply, name, options = {}, handlerOptions = {}) {
|
|
67
|
+
const payload = createHttpResponse(name, options);
|
|
68
|
+
reply.header?.("Content-Type", payload.contentType);
|
|
69
|
+
if (handlerOptions.cacheControl) reply.header?.("Cache-Control", handlerOptions.cacheControl);
|
|
70
|
+
reply.send(payload.body);
|
|
71
|
+
}
|
|
72
|
+
function sendNestAvatar(res, name, options = {}, handlerOptions = {}) {
|
|
73
|
+
const payload = createHttpResponse(name, options);
|
|
74
|
+
const set = res.header ?? res.setHeader;
|
|
75
|
+
set?.call(res, "Content-Type", payload.contentType);
|
|
76
|
+
if (handlerOptions.cacheControl) set?.call(res, "Cache-Control", handlerOptions.cacheControl);
|
|
77
|
+
res.send(payload.body);
|
|
78
|
+
}
|
|
79
|
+
function createExpressHandler(handlerOptions = {}) {
|
|
80
|
+
return (req, res) => {
|
|
81
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
82
|
+
sendExpressAvatar(res, name, handlerOptions.avatarOptions, handlerOptions);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function createFastifyHandler(handlerOptions = {}) {
|
|
86
|
+
return (req, reply) => {
|
|
87
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
88
|
+
sendFastifyAvatar(reply, name, handlerOptions.avatarOptions, handlerOptions);
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function createNestHandler(handlerOptions = {}) {
|
|
92
|
+
return (req, res) => {
|
|
93
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
94
|
+
sendNestAvatar(res, name, handlerOptions.avatarOptions, handlerOptions);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function resolveNameFromRequest(req, handlerOptions) {
|
|
98
|
+
if (handlerOptions.resolveName) return handlerOptions.resolveName(req);
|
|
99
|
+
const key = handlerOptions.nameKey ?? "name";
|
|
100
|
+
const record = req;
|
|
101
|
+
const maybeQuery = record?.query?.[key];
|
|
102
|
+
const maybeBody = record?.body?.[key];
|
|
103
|
+
const maybeParams = record?.params?.[key];
|
|
104
|
+
const candidate = [maybeQuery, maybeBody, maybeParams].find((value) => typeof value === "string" && value.trim().length > 0);
|
|
105
|
+
if (typeof candidate === "string") return candidate;
|
|
106
|
+
return void 0;
|
|
107
|
+
}
|
|
108
|
+
function clamp(value, min, max) {
|
|
109
|
+
if (Number.isNaN(value)) return min;
|
|
110
|
+
return Math.min(Math.max(value, min), max);
|
|
111
|
+
}
|
|
112
|
+
function escapeXml(value) {
|
|
113
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
114
|
+
}
|
|
115
|
+
function stringToColor(input) {
|
|
116
|
+
const value = (input ?? "").trim();
|
|
117
|
+
if (!value) return "#444444";
|
|
118
|
+
let hash = 0;
|
|
119
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
120
|
+
hash = value.charCodeAt(i) + ((hash << 5) - hash);
|
|
121
|
+
hash &= hash;
|
|
122
|
+
}
|
|
123
|
+
const hue = Math.abs(hash) % 360;
|
|
124
|
+
const saturation = 65;
|
|
125
|
+
const lightness = 55;
|
|
126
|
+
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
127
|
+
}
|
|
128
|
+
function toBase64(svg) {
|
|
129
|
+
const globalRef = typeof globalThis !== "undefined" ? globalThis : void 0;
|
|
130
|
+
const bufferCtor = globalRef && globalRef.Buffer;
|
|
131
|
+
if (bufferCtor) {
|
|
132
|
+
return bufferCtor.from(svg, "utf8").toString("base64");
|
|
133
|
+
}
|
|
134
|
+
const btoaFn = globalRef && globalRef.btoa;
|
|
135
|
+
if (btoaFn) {
|
|
136
|
+
return btoaFn(unescape(encodeURIComponent(svg)));
|
|
137
|
+
}
|
|
138
|
+
throw new Error("No base64 encoder available in this environment.");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
getInitials,
|
|
143
|
+
createAvatarSvg,
|
|
144
|
+
createAvatarDataUri,
|
|
145
|
+
createAvatar,
|
|
146
|
+
createHttpResponse,
|
|
147
|
+
sendExpressAvatar,
|
|
148
|
+
sendFastifyAvatar,
|
|
149
|
+
sendNestAvatar,
|
|
150
|
+
createExpressHandler,
|
|
151
|
+
createFastifyHandler,
|
|
152
|
+
createNestHandler
|
|
153
|
+
};
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createAvatar: () => createAvatar,
|
|
24
|
+
createAvatarDataUri: () => createAvatarDataUri,
|
|
25
|
+
createAvatarSvg: () => createAvatarSvg,
|
|
26
|
+
createExpressHandler: () => createExpressHandler,
|
|
27
|
+
createFastifyHandler: () => createFastifyHandler,
|
|
28
|
+
createHttpResponse: () => createHttpResponse,
|
|
29
|
+
createNestHandler: () => createNestHandler,
|
|
30
|
+
getInitials: () => getInitials,
|
|
31
|
+
sendExpressAvatar: () => sendExpressAvatar,
|
|
32
|
+
sendFastifyAvatar: () => sendFastifyAvatar,
|
|
33
|
+
sendNestAvatar: () => sendNestAvatar
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
|
+
var DEFAULT_SIZE = 96;
|
|
37
|
+
var DEFAULT_FONT_FAMILY = '"Segoe UI", Arial, sans-serif';
|
|
38
|
+
function getInitials(name) {
|
|
39
|
+
const cleaned = (name ?? "").trim();
|
|
40
|
+
if (!cleaned) return "?";
|
|
41
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
42
|
+
if (parts.length === 1) {
|
|
43
|
+
const [firstChar, secondChar] = [...parts[0]].filter(Boolean);
|
|
44
|
+
return (firstChar ?? "").toUpperCase() + (secondChar ?? "").toUpperCase();
|
|
45
|
+
}
|
|
46
|
+
const first = parts[0]?.[0] ?? "";
|
|
47
|
+
const last = parts[parts.length - 1]?.[0] ?? "";
|
|
48
|
+
return `${first}${last}`.toUpperCase();
|
|
49
|
+
}
|
|
50
|
+
function createAvatarSvg(name, options = {}) {
|
|
51
|
+
const size = options.size ?? DEFAULT_SIZE;
|
|
52
|
+
const backgroundColor = options.backgroundColor ?? stringToColor(name);
|
|
53
|
+
const fontColor = options.fontColor ?? "#ffffff";
|
|
54
|
+
const fontSize = options.fontSize ?? Math.round(size * 0.42);
|
|
55
|
+
const fontFamily = options.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
56
|
+
const borderWidth = options.borderWidth ?? 0;
|
|
57
|
+
const borderColor = options.borderColor ?? "transparent";
|
|
58
|
+
const borderRadius = clamp(options.borderRadius ?? size * 0.2, 0, size / 2);
|
|
59
|
+
const fontWeight = options.bold ? 700 : 600;
|
|
60
|
+
const initials = (options.initialsOverride ?? getInitials(name)).slice(0, 3);
|
|
61
|
+
const ariaLabel = name && name.trim().length > 0 ? name.trim() : "Avatar";
|
|
62
|
+
return [
|
|
63
|
+
'<svg xmlns="http://www.w3.org/2000/svg" role="img"',
|
|
64
|
+
` width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"`,
|
|
65
|
+
` aria-label="${escapeXml(ariaLabel)}">`,
|
|
66
|
+
`<rect width="${size}" height="${size}" fill="${escapeXml(backgroundColor)}"`,
|
|
67
|
+
` stroke="${escapeXml(borderColor)}" stroke-width="${borderWidth}"`,
|
|
68
|
+
` rx="${borderRadius}" ry="${borderRadius}"/>`,
|
|
69
|
+
`<text x="50%" y="50%" fill="${escapeXml(fontColor)}"`,
|
|
70
|
+
` font-family="${escapeXml(fontFamily)}" font-size="${fontSize}"`,
|
|
71
|
+
` font-weight="${fontWeight}" text-anchor="middle"`,
|
|
72
|
+
' dominant-baseline="central">',
|
|
73
|
+
`${escapeXml(initials)}`,
|
|
74
|
+
"</text>",
|
|
75
|
+
"</svg>"
|
|
76
|
+
].join("");
|
|
77
|
+
}
|
|
78
|
+
function createAvatarDataUri(name, options = {}) {
|
|
79
|
+
const svg = createAvatarSvg(name, options);
|
|
80
|
+
const encoded = toBase64(svg);
|
|
81
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
82
|
+
}
|
|
83
|
+
function createAvatar(name, options = {}) {
|
|
84
|
+
const svg = createAvatarSvg(name, options);
|
|
85
|
+
const dataUri = createAvatarDataUri(name, options);
|
|
86
|
+
return { svg, dataUri };
|
|
87
|
+
}
|
|
88
|
+
function createHttpResponse(name, options = {}) {
|
|
89
|
+
return {
|
|
90
|
+
contentType: "image/svg+xml",
|
|
91
|
+
body: createAvatarSvg(name, options)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function sendExpressAvatar(res, name, options = {}, handlerOptions = {}) {
|
|
95
|
+
const payload = createHttpResponse(name, options);
|
|
96
|
+
res.setHeader?.("Content-Type", payload.contentType);
|
|
97
|
+
if (handlerOptions.cacheControl) res.setHeader?.("Cache-Control", handlerOptions.cacheControl);
|
|
98
|
+
res.send(payload.body);
|
|
99
|
+
}
|
|
100
|
+
function sendFastifyAvatar(reply, name, options = {}, handlerOptions = {}) {
|
|
101
|
+
const payload = createHttpResponse(name, options);
|
|
102
|
+
reply.header?.("Content-Type", payload.contentType);
|
|
103
|
+
if (handlerOptions.cacheControl) reply.header?.("Cache-Control", handlerOptions.cacheControl);
|
|
104
|
+
reply.send(payload.body);
|
|
105
|
+
}
|
|
106
|
+
function sendNestAvatar(res, name, options = {}, handlerOptions = {}) {
|
|
107
|
+
const payload = createHttpResponse(name, options);
|
|
108
|
+
const set = res.header ?? res.setHeader;
|
|
109
|
+
set?.call(res, "Content-Type", payload.contentType);
|
|
110
|
+
if (handlerOptions.cacheControl) set?.call(res, "Cache-Control", handlerOptions.cacheControl);
|
|
111
|
+
res.send(payload.body);
|
|
112
|
+
}
|
|
113
|
+
function createExpressHandler(handlerOptions = {}) {
|
|
114
|
+
return (req, res) => {
|
|
115
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
116
|
+
sendExpressAvatar(res, name, handlerOptions.avatarOptions, handlerOptions);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function createFastifyHandler(handlerOptions = {}) {
|
|
120
|
+
return (req, reply) => {
|
|
121
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
122
|
+
sendFastifyAvatar(reply, name, handlerOptions.avatarOptions, handlerOptions);
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function createNestHandler(handlerOptions = {}) {
|
|
126
|
+
return (req, res) => {
|
|
127
|
+
const name = resolveNameFromRequest(req, handlerOptions) ?? "User";
|
|
128
|
+
sendNestAvatar(res, name, handlerOptions.avatarOptions, handlerOptions);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function resolveNameFromRequest(req, handlerOptions) {
|
|
132
|
+
if (handlerOptions.resolveName) return handlerOptions.resolveName(req);
|
|
133
|
+
const key = handlerOptions.nameKey ?? "name";
|
|
134
|
+
const record = req;
|
|
135
|
+
const maybeQuery = record?.query?.[key];
|
|
136
|
+
const maybeBody = record?.body?.[key];
|
|
137
|
+
const maybeParams = record?.params?.[key];
|
|
138
|
+
const candidate = [maybeQuery, maybeBody, maybeParams].find((value) => typeof value === "string" && value.trim().length > 0);
|
|
139
|
+
if (typeof candidate === "string") return candidate;
|
|
140
|
+
return void 0;
|
|
141
|
+
}
|
|
142
|
+
function clamp(value, min, max) {
|
|
143
|
+
if (Number.isNaN(value)) return min;
|
|
144
|
+
return Math.min(Math.max(value, min), max);
|
|
145
|
+
}
|
|
146
|
+
function escapeXml(value) {
|
|
147
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
148
|
+
}
|
|
149
|
+
function stringToColor(input) {
|
|
150
|
+
const value = (input ?? "").trim();
|
|
151
|
+
if (!value) return "#444444";
|
|
152
|
+
let hash = 0;
|
|
153
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
154
|
+
hash = value.charCodeAt(i) + ((hash << 5) - hash);
|
|
155
|
+
hash &= hash;
|
|
156
|
+
}
|
|
157
|
+
const hue = Math.abs(hash) % 360;
|
|
158
|
+
const saturation = 65;
|
|
159
|
+
const lightness = 55;
|
|
160
|
+
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
161
|
+
}
|
|
162
|
+
function toBase64(svg) {
|
|
163
|
+
const globalRef = typeof globalThis !== "undefined" ? globalThis : void 0;
|
|
164
|
+
const bufferCtor = globalRef && globalRef.Buffer;
|
|
165
|
+
if (bufferCtor) {
|
|
166
|
+
return bufferCtor.from(svg, "utf8").toString("base64");
|
|
167
|
+
}
|
|
168
|
+
const btoaFn = globalRef && globalRef.btoa;
|
|
169
|
+
if (btoaFn) {
|
|
170
|
+
return btoaFn(unescape(encodeURIComponent(svg)));
|
|
171
|
+
}
|
|
172
|
+
throw new Error("No base64 encoder available in this environment.");
|
|
173
|
+
}
|
|
174
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
175
|
+
0 && (module.exports = {
|
|
176
|
+
createAvatar,
|
|
177
|
+
createAvatarDataUri,
|
|
178
|
+
createAvatarSvg,
|
|
179
|
+
createExpressHandler,
|
|
180
|
+
createFastifyHandler,
|
|
181
|
+
createHttpResponse,
|
|
182
|
+
createNestHandler,
|
|
183
|
+
getInitials,
|
|
184
|
+
sendExpressAvatar,
|
|
185
|
+
sendFastifyAvatar,
|
|
186
|
+
sendNestAvatar
|
|
187
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
type AvatarOptions = {
|
|
2
|
+
/** Overall square size in pixels */
|
|
3
|
+
size?: number;
|
|
4
|
+
/** Background color (hex, rgb, hsl). Falls back to deterministic color from the name */
|
|
5
|
+
backgroundColor?: string;
|
|
6
|
+
/** Text color */
|
|
7
|
+
fontColor?: string;
|
|
8
|
+
/** Font size in pixels */
|
|
9
|
+
fontSize?: number;
|
|
10
|
+
/** Font family string */
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
/** Border width in pixels */
|
|
13
|
+
borderWidth?: number;
|
|
14
|
+
/** Border color */
|
|
15
|
+
borderColor?: string;
|
|
16
|
+
/** Corner radius in pixels */
|
|
17
|
+
borderRadius?: number;
|
|
18
|
+
/** Render bold text */
|
|
19
|
+
bold?: boolean;
|
|
20
|
+
/** Explicit initials override */
|
|
21
|
+
initialsOverride?: string;
|
|
22
|
+
};
|
|
23
|
+
type AvatarPayload = {
|
|
24
|
+
svg: string;
|
|
25
|
+
dataUri: string;
|
|
26
|
+
};
|
|
27
|
+
type ExpressResponseLike = {
|
|
28
|
+
setHeader?: (name: string, value: string) => unknown;
|
|
29
|
+
send: (body: unknown) => unknown;
|
|
30
|
+
};
|
|
31
|
+
type FastifyReplyLike = {
|
|
32
|
+
header?: (name: string, value: string) => unknown;
|
|
33
|
+
send: (body: unknown) => unknown;
|
|
34
|
+
};
|
|
35
|
+
type NestResponseLike = {
|
|
36
|
+
setHeader?: (name: string, value: string) => unknown;
|
|
37
|
+
header?: (name: string, value: string) => unknown;
|
|
38
|
+
send: (body: unknown) => unknown;
|
|
39
|
+
};
|
|
40
|
+
type HandlerOptions = {
|
|
41
|
+
/** Query/body key to read the name from when no resolver is provided */
|
|
42
|
+
nameKey?: string;
|
|
43
|
+
/** Custom resolver to derive the display name */
|
|
44
|
+
resolveName?: (req: unknown) => string | undefined;
|
|
45
|
+
/** Avatar rendering options */
|
|
46
|
+
avatarOptions?: AvatarOptions;
|
|
47
|
+
/** Optional cache control header value */
|
|
48
|
+
cacheControl?: string;
|
|
49
|
+
};
|
|
50
|
+
declare function getInitials(name: string): string;
|
|
51
|
+
declare function createAvatarSvg(name: string, options?: AvatarOptions): string;
|
|
52
|
+
declare function createAvatarDataUri(name: string, options?: AvatarOptions): string;
|
|
53
|
+
declare function createAvatar(name: string, options?: AvatarOptions): AvatarPayload;
|
|
54
|
+
declare function createHttpResponse(name: string, options?: AvatarOptions): {
|
|
55
|
+
contentType: string;
|
|
56
|
+
body: string;
|
|
57
|
+
};
|
|
58
|
+
declare function sendExpressAvatar(res: ExpressResponseLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
59
|
+
declare function sendFastifyAvatar(reply: FastifyReplyLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
60
|
+
declare function sendNestAvatar(res: NestResponseLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
61
|
+
declare function createExpressHandler(handlerOptions?: HandlerOptions): (req: unknown, res: ExpressResponseLike) => void;
|
|
62
|
+
declare function createFastifyHandler(handlerOptions?: HandlerOptions): (req: unknown, reply: FastifyReplyLike) => void;
|
|
63
|
+
declare function createNestHandler(handlerOptions?: HandlerOptions): (req: unknown, res: NestResponseLike) => void;
|
|
64
|
+
|
|
65
|
+
export { type AvatarOptions, type AvatarPayload, type ExpressResponseLike, type FastifyReplyLike, type HandlerOptions, type NestResponseLike, createAvatar, createAvatarDataUri, createAvatarSvg, createExpressHandler, createFastifyHandler, createHttpResponse, createNestHandler, getInitials, sendExpressAvatar, sendFastifyAvatar, sendNestAvatar };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
type AvatarOptions = {
|
|
2
|
+
/** Overall square size in pixels */
|
|
3
|
+
size?: number;
|
|
4
|
+
/** Background color (hex, rgb, hsl). Falls back to deterministic color from the name */
|
|
5
|
+
backgroundColor?: string;
|
|
6
|
+
/** Text color */
|
|
7
|
+
fontColor?: string;
|
|
8
|
+
/** Font size in pixels */
|
|
9
|
+
fontSize?: number;
|
|
10
|
+
/** Font family string */
|
|
11
|
+
fontFamily?: string;
|
|
12
|
+
/** Border width in pixels */
|
|
13
|
+
borderWidth?: number;
|
|
14
|
+
/** Border color */
|
|
15
|
+
borderColor?: string;
|
|
16
|
+
/** Corner radius in pixels */
|
|
17
|
+
borderRadius?: number;
|
|
18
|
+
/** Render bold text */
|
|
19
|
+
bold?: boolean;
|
|
20
|
+
/** Explicit initials override */
|
|
21
|
+
initialsOverride?: string;
|
|
22
|
+
};
|
|
23
|
+
type AvatarPayload = {
|
|
24
|
+
svg: string;
|
|
25
|
+
dataUri: string;
|
|
26
|
+
};
|
|
27
|
+
type ExpressResponseLike = {
|
|
28
|
+
setHeader?: (name: string, value: string) => unknown;
|
|
29
|
+
send: (body: unknown) => unknown;
|
|
30
|
+
};
|
|
31
|
+
type FastifyReplyLike = {
|
|
32
|
+
header?: (name: string, value: string) => unknown;
|
|
33
|
+
send: (body: unknown) => unknown;
|
|
34
|
+
};
|
|
35
|
+
type NestResponseLike = {
|
|
36
|
+
setHeader?: (name: string, value: string) => unknown;
|
|
37
|
+
header?: (name: string, value: string) => unknown;
|
|
38
|
+
send: (body: unknown) => unknown;
|
|
39
|
+
};
|
|
40
|
+
type HandlerOptions = {
|
|
41
|
+
/** Query/body key to read the name from when no resolver is provided */
|
|
42
|
+
nameKey?: string;
|
|
43
|
+
/** Custom resolver to derive the display name */
|
|
44
|
+
resolveName?: (req: unknown) => string | undefined;
|
|
45
|
+
/** Avatar rendering options */
|
|
46
|
+
avatarOptions?: AvatarOptions;
|
|
47
|
+
/** Optional cache control header value */
|
|
48
|
+
cacheControl?: string;
|
|
49
|
+
};
|
|
50
|
+
declare function getInitials(name: string): string;
|
|
51
|
+
declare function createAvatarSvg(name: string, options?: AvatarOptions): string;
|
|
52
|
+
declare function createAvatarDataUri(name: string, options?: AvatarOptions): string;
|
|
53
|
+
declare function createAvatar(name: string, options?: AvatarOptions): AvatarPayload;
|
|
54
|
+
declare function createHttpResponse(name: string, options?: AvatarOptions): {
|
|
55
|
+
contentType: string;
|
|
56
|
+
body: string;
|
|
57
|
+
};
|
|
58
|
+
declare function sendExpressAvatar(res: ExpressResponseLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
59
|
+
declare function sendFastifyAvatar(reply: FastifyReplyLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
60
|
+
declare function sendNestAvatar(res: NestResponseLike, name: string, options?: AvatarOptions, handlerOptions?: Omit<HandlerOptions, 'avatarOptions'>): void;
|
|
61
|
+
declare function createExpressHandler(handlerOptions?: HandlerOptions): (req: unknown, res: ExpressResponseLike) => void;
|
|
62
|
+
declare function createFastifyHandler(handlerOptions?: HandlerOptions): (req: unknown, reply: FastifyReplyLike) => void;
|
|
63
|
+
declare function createNestHandler(handlerOptions?: HandlerOptions): (req: unknown, res: NestResponseLike) => void;
|
|
64
|
+
|
|
65
|
+
export { type AvatarOptions, type AvatarPayload, type ExpressResponseLike, type FastifyReplyLike, type HandlerOptions, type NestResponseLike, createAvatar, createAvatarDataUri, createAvatarSvg, createExpressHandler, createFastifyHandler, createHttpResponse, createNestHandler, getInitials, sendExpressAvatar, sendFastifyAvatar, sendNestAvatar };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAvatar,
|
|
3
|
+
createAvatarDataUri,
|
|
4
|
+
createAvatarSvg,
|
|
5
|
+
createExpressHandler,
|
|
6
|
+
createFastifyHandler,
|
|
7
|
+
createHttpResponse,
|
|
8
|
+
createNestHandler,
|
|
9
|
+
getInitials,
|
|
10
|
+
sendExpressAvatar,
|
|
11
|
+
sendFastifyAvatar,
|
|
12
|
+
sendNestAvatar
|
|
13
|
+
} from "./chunk-PMFHYTR7.js";
|
|
14
|
+
export {
|
|
15
|
+
createAvatar,
|
|
16
|
+
createAvatarDataUri,
|
|
17
|
+
createAvatarSvg,
|
|
18
|
+
createExpressHandler,
|
|
19
|
+
createFastifyHandler,
|
|
20
|
+
createHttpResponse,
|
|
21
|
+
createNestHandler,
|
|
22
|
+
getInitials,
|
|
23
|
+
sendExpressAvatar,
|
|
24
|
+
sendFastifyAvatar,
|
|
25
|
+
sendNestAvatar
|
|
26
|
+
};
|
package/dist/react.cjs
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/react.tsx
|
|
21
|
+
var react_exports = {};
|
|
22
|
+
__export(react_exports, {
|
|
23
|
+
InitialsAvatar: () => InitialsAvatar,
|
|
24
|
+
default: () => react_default
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(react_exports);
|
|
27
|
+
var import_react = require("react");
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var DEFAULT_SIZE = 96;
|
|
31
|
+
var DEFAULT_FONT_FAMILY = '"Segoe UI", Arial, sans-serif';
|
|
32
|
+
function getInitials(name) {
|
|
33
|
+
const cleaned = (name ?? "").trim();
|
|
34
|
+
if (!cleaned) return "?";
|
|
35
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
36
|
+
if (parts.length === 1) {
|
|
37
|
+
const [firstChar, secondChar] = [...parts[0]].filter(Boolean);
|
|
38
|
+
return (firstChar ?? "").toUpperCase() + (secondChar ?? "").toUpperCase();
|
|
39
|
+
}
|
|
40
|
+
const first = parts[0]?.[0] ?? "";
|
|
41
|
+
const last = parts[parts.length - 1]?.[0] ?? "";
|
|
42
|
+
return `${first}${last}`.toUpperCase();
|
|
43
|
+
}
|
|
44
|
+
function createAvatarSvg(name, options = {}) {
|
|
45
|
+
const size = options.size ?? DEFAULT_SIZE;
|
|
46
|
+
const backgroundColor = options.backgroundColor ?? stringToColor(name);
|
|
47
|
+
const fontColor = options.fontColor ?? "#ffffff";
|
|
48
|
+
const fontSize = options.fontSize ?? Math.round(size * 0.42);
|
|
49
|
+
const fontFamily = options.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
50
|
+
const borderWidth = options.borderWidth ?? 0;
|
|
51
|
+
const borderColor = options.borderColor ?? "transparent";
|
|
52
|
+
const borderRadius = clamp(options.borderRadius ?? size * 0.2, 0, size / 2);
|
|
53
|
+
const fontWeight = options.bold ? 700 : 600;
|
|
54
|
+
const initials = (options.initialsOverride ?? getInitials(name)).slice(0, 3);
|
|
55
|
+
const ariaLabel = name && name.trim().length > 0 ? name.trim() : "Avatar";
|
|
56
|
+
return [
|
|
57
|
+
'<svg xmlns="http://www.w3.org/2000/svg" role="img"',
|
|
58
|
+
` width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"`,
|
|
59
|
+
` aria-label="${escapeXml(ariaLabel)}">`,
|
|
60
|
+
`<rect width="${size}" height="${size}" fill="${escapeXml(backgroundColor)}"`,
|
|
61
|
+
` stroke="${escapeXml(borderColor)}" stroke-width="${borderWidth}"`,
|
|
62
|
+
` rx="${borderRadius}" ry="${borderRadius}"/>`,
|
|
63
|
+
`<text x="50%" y="50%" fill="${escapeXml(fontColor)}"`,
|
|
64
|
+
` font-family="${escapeXml(fontFamily)}" font-size="${fontSize}"`,
|
|
65
|
+
` font-weight="${fontWeight}" text-anchor="middle"`,
|
|
66
|
+
' dominant-baseline="central">',
|
|
67
|
+
`${escapeXml(initials)}`,
|
|
68
|
+
"</text>",
|
|
69
|
+
"</svg>"
|
|
70
|
+
].join("");
|
|
71
|
+
}
|
|
72
|
+
function createAvatarDataUri(name, options = {}) {
|
|
73
|
+
const svg = createAvatarSvg(name, options);
|
|
74
|
+
const encoded = toBase64(svg);
|
|
75
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
76
|
+
}
|
|
77
|
+
function clamp(value, min, max) {
|
|
78
|
+
if (Number.isNaN(value)) return min;
|
|
79
|
+
return Math.min(Math.max(value, min), max);
|
|
80
|
+
}
|
|
81
|
+
function escapeXml(value) {
|
|
82
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
83
|
+
}
|
|
84
|
+
function stringToColor(input) {
|
|
85
|
+
const value = (input ?? "").trim();
|
|
86
|
+
if (!value) return "#444444";
|
|
87
|
+
let hash = 0;
|
|
88
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
89
|
+
hash = value.charCodeAt(i) + ((hash << 5) - hash);
|
|
90
|
+
hash &= hash;
|
|
91
|
+
}
|
|
92
|
+
const hue = Math.abs(hash) % 360;
|
|
93
|
+
const saturation = 65;
|
|
94
|
+
const lightness = 55;
|
|
95
|
+
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
96
|
+
}
|
|
97
|
+
function toBase64(svg) {
|
|
98
|
+
const globalRef = typeof globalThis !== "undefined" ? globalThis : void 0;
|
|
99
|
+
const bufferCtor = globalRef && globalRef.Buffer;
|
|
100
|
+
if (bufferCtor) {
|
|
101
|
+
return bufferCtor.from(svg, "utf8").toString("base64");
|
|
102
|
+
}
|
|
103
|
+
const btoaFn = globalRef && globalRef.btoa;
|
|
104
|
+
if (btoaFn) {
|
|
105
|
+
return btoaFn(unescape(encodeURIComponent(svg)));
|
|
106
|
+
}
|
|
107
|
+
throw new Error("No base64 encoder available in this environment.");
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/react.tsx
|
|
111
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
112
|
+
var DEFAULT_SIZE2 = 96;
|
|
113
|
+
var InitialsAvatar = ({
|
|
114
|
+
name,
|
|
115
|
+
alt,
|
|
116
|
+
as = "img",
|
|
117
|
+
className,
|
|
118
|
+
style,
|
|
119
|
+
title,
|
|
120
|
+
imgProps,
|
|
121
|
+
svgProps,
|
|
122
|
+
...avatarOptions
|
|
123
|
+
}) => {
|
|
124
|
+
const size = avatarOptions.size ?? DEFAULT_SIZE2;
|
|
125
|
+
const memoKey = (0, import_react.useMemo)(() => JSON.stringify(avatarOptions), [avatarOptions]);
|
|
126
|
+
const dataUri = (0, import_react.useMemo)(() => createAvatarDataUri(name, avatarOptions), [name, memoKey]);
|
|
127
|
+
const svgMarkup = (0, import_react.useMemo)(() => createAvatarSvg(name, avatarOptions), [name, memoKey]);
|
|
128
|
+
const fallbackAlt = alt ?? `Avatar for ${name || getInitials(name)}`;
|
|
129
|
+
if (as === "svg") {
|
|
130
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
131
|
+
"span",
|
|
132
|
+
{
|
|
133
|
+
className,
|
|
134
|
+
style,
|
|
135
|
+
dangerouslySetInnerHTML: { __html: svgMarkup },
|
|
136
|
+
"aria-label": fallbackAlt,
|
|
137
|
+
role: "img",
|
|
138
|
+
...svgProps
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
143
|
+
"img",
|
|
144
|
+
{
|
|
145
|
+
src: dataUri,
|
|
146
|
+
width: size,
|
|
147
|
+
height: size,
|
|
148
|
+
alt: fallbackAlt,
|
|
149
|
+
className,
|
|
150
|
+
style,
|
|
151
|
+
title,
|
|
152
|
+
...imgProps
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
};
|
|
156
|
+
var react_default = InitialsAvatar;
|
|
157
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
158
|
+
0 && (module.exports = {
|
|
159
|
+
InitialsAvatar
|
|
160
|
+
});
|
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { CSSProperties, ImgHTMLAttributes, HTMLAttributes } from 'react';
|
|
2
|
+
import { AvatarOptions } from './index.cjs';
|
|
3
|
+
|
|
4
|
+
type InitialsAvatarProps = AvatarOptions & {
|
|
5
|
+
name: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
as?: 'img' | 'svg';
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
title?: string;
|
|
11
|
+
imgProps?: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'title'>;
|
|
12
|
+
svgProps?: Omit<HTMLAttributes<HTMLSpanElement>, 'dangerouslySetInnerHTML'>;
|
|
13
|
+
};
|
|
14
|
+
declare const InitialsAvatar: React.FC<InitialsAvatarProps>;
|
|
15
|
+
|
|
16
|
+
export { AvatarOptions, InitialsAvatar, type InitialsAvatarProps, InitialsAvatar as default };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React, { CSSProperties, ImgHTMLAttributes, HTMLAttributes } from 'react';
|
|
2
|
+
import { AvatarOptions } from './index.js';
|
|
3
|
+
|
|
4
|
+
type InitialsAvatarProps = AvatarOptions & {
|
|
5
|
+
name: string;
|
|
6
|
+
alt?: string;
|
|
7
|
+
as?: 'img' | 'svg';
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
title?: string;
|
|
11
|
+
imgProps?: Omit<ImgHTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'title'>;
|
|
12
|
+
svgProps?: Omit<HTMLAttributes<HTMLSpanElement>, 'dangerouslySetInnerHTML'>;
|
|
13
|
+
};
|
|
14
|
+
declare const InitialsAvatar: React.FC<InitialsAvatarProps>;
|
|
15
|
+
|
|
16
|
+
export { AvatarOptions, InitialsAvatar, type InitialsAvatarProps, InitialsAvatar as default };
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAvatarDataUri,
|
|
3
|
+
createAvatarSvg,
|
|
4
|
+
getInitials
|
|
5
|
+
} from "./chunk-PMFHYTR7.js";
|
|
6
|
+
|
|
7
|
+
// src/react.tsx
|
|
8
|
+
import { useMemo } from "react";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
var DEFAULT_SIZE = 96;
|
|
11
|
+
var InitialsAvatar = ({
|
|
12
|
+
name,
|
|
13
|
+
alt,
|
|
14
|
+
as = "img",
|
|
15
|
+
className,
|
|
16
|
+
style,
|
|
17
|
+
title,
|
|
18
|
+
imgProps,
|
|
19
|
+
svgProps,
|
|
20
|
+
...avatarOptions
|
|
21
|
+
}) => {
|
|
22
|
+
const size = avatarOptions.size ?? DEFAULT_SIZE;
|
|
23
|
+
const memoKey = useMemo(() => JSON.stringify(avatarOptions), [avatarOptions]);
|
|
24
|
+
const dataUri = useMemo(() => createAvatarDataUri(name, avatarOptions), [name, memoKey]);
|
|
25
|
+
const svgMarkup = useMemo(() => createAvatarSvg(name, avatarOptions), [name, memoKey]);
|
|
26
|
+
const fallbackAlt = alt ?? `Avatar for ${name || getInitials(name)}`;
|
|
27
|
+
if (as === "svg") {
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
"span",
|
|
30
|
+
{
|
|
31
|
+
className,
|
|
32
|
+
style,
|
|
33
|
+
dangerouslySetInnerHTML: { __html: svgMarkup },
|
|
34
|
+
"aria-label": fallbackAlt,
|
|
35
|
+
role: "img",
|
|
36
|
+
...svgProps
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
return /* @__PURE__ */ jsx(
|
|
41
|
+
"img",
|
|
42
|
+
{
|
|
43
|
+
src: dataUri,
|
|
44
|
+
width: size,
|
|
45
|
+
height: size,
|
|
46
|
+
alt: fallbackAlt,
|
|
47
|
+
className,
|
|
48
|
+
style,
|
|
49
|
+
title,
|
|
50
|
+
...imgProps
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
var react_default = InitialsAvatar;
|
|
55
|
+
export {
|
|
56
|
+
InitialsAvatar,
|
|
57
|
+
react_default as default
|
|
58
|
+
};
|
package/dist/vue.cjs
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/vue.ts
|
|
21
|
+
var vue_exports = {};
|
|
22
|
+
__export(vue_exports, {
|
|
23
|
+
InitialsAvatar: () => InitialsAvatar,
|
|
24
|
+
InitialsAvatarPlugin: () => InitialsAvatarPlugin,
|
|
25
|
+
default: () => vue_default
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(vue_exports);
|
|
28
|
+
var import_vue = require("vue");
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var DEFAULT_SIZE = 96;
|
|
32
|
+
var DEFAULT_FONT_FAMILY = '"Segoe UI", Arial, sans-serif';
|
|
33
|
+
function getInitials(name) {
|
|
34
|
+
const cleaned = (name ?? "").trim();
|
|
35
|
+
if (!cleaned) return "?";
|
|
36
|
+
const parts = cleaned.split(/\s+/).filter(Boolean);
|
|
37
|
+
if (parts.length === 1) {
|
|
38
|
+
const [firstChar, secondChar] = [...parts[0]].filter(Boolean);
|
|
39
|
+
return (firstChar ?? "").toUpperCase() + (secondChar ?? "").toUpperCase();
|
|
40
|
+
}
|
|
41
|
+
const first = parts[0]?.[0] ?? "";
|
|
42
|
+
const last = parts[parts.length - 1]?.[0] ?? "";
|
|
43
|
+
return `${first}${last}`.toUpperCase();
|
|
44
|
+
}
|
|
45
|
+
function createAvatarSvg(name, options = {}) {
|
|
46
|
+
const size = options.size ?? DEFAULT_SIZE;
|
|
47
|
+
const backgroundColor = options.backgroundColor ?? stringToColor(name);
|
|
48
|
+
const fontColor = options.fontColor ?? "#ffffff";
|
|
49
|
+
const fontSize = options.fontSize ?? Math.round(size * 0.42);
|
|
50
|
+
const fontFamily = options.fontFamily ?? DEFAULT_FONT_FAMILY;
|
|
51
|
+
const borderWidth = options.borderWidth ?? 0;
|
|
52
|
+
const borderColor = options.borderColor ?? "transparent";
|
|
53
|
+
const borderRadius = clamp(options.borderRadius ?? size * 0.2, 0, size / 2);
|
|
54
|
+
const fontWeight = options.bold ? 700 : 600;
|
|
55
|
+
const initials = (options.initialsOverride ?? getInitials(name)).slice(0, 3);
|
|
56
|
+
const ariaLabel = name && name.trim().length > 0 ? name.trim() : "Avatar";
|
|
57
|
+
return [
|
|
58
|
+
'<svg xmlns="http://www.w3.org/2000/svg" role="img"',
|
|
59
|
+
` width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"`,
|
|
60
|
+
` aria-label="${escapeXml(ariaLabel)}">`,
|
|
61
|
+
`<rect width="${size}" height="${size}" fill="${escapeXml(backgroundColor)}"`,
|
|
62
|
+
` stroke="${escapeXml(borderColor)}" stroke-width="${borderWidth}"`,
|
|
63
|
+
` rx="${borderRadius}" ry="${borderRadius}"/>`,
|
|
64
|
+
`<text x="50%" y="50%" fill="${escapeXml(fontColor)}"`,
|
|
65
|
+
` font-family="${escapeXml(fontFamily)}" font-size="${fontSize}"`,
|
|
66
|
+
` font-weight="${fontWeight}" text-anchor="middle"`,
|
|
67
|
+
' dominant-baseline="central">',
|
|
68
|
+
`${escapeXml(initials)}`,
|
|
69
|
+
"</text>",
|
|
70
|
+
"</svg>"
|
|
71
|
+
].join("");
|
|
72
|
+
}
|
|
73
|
+
function createAvatarDataUri(name, options = {}) {
|
|
74
|
+
const svg = createAvatarSvg(name, options);
|
|
75
|
+
const encoded = toBase64(svg);
|
|
76
|
+
return `data:image/svg+xml;base64,${encoded}`;
|
|
77
|
+
}
|
|
78
|
+
function clamp(value, min, max) {
|
|
79
|
+
if (Number.isNaN(value)) return min;
|
|
80
|
+
return Math.min(Math.max(value, min), max);
|
|
81
|
+
}
|
|
82
|
+
function escapeXml(value) {
|
|
83
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
84
|
+
}
|
|
85
|
+
function stringToColor(input) {
|
|
86
|
+
const value = (input ?? "").trim();
|
|
87
|
+
if (!value) return "#444444";
|
|
88
|
+
let hash = 0;
|
|
89
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
90
|
+
hash = value.charCodeAt(i) + ((hash << 5) - hash);
|
|
91
|
+
hash &= hash;
|
|
92
|
+
}
|
|
93
|
+
const hue = Math.abs(hash) % 360;
|
|
94
|
+
const saturation = 65;
|
|
95
|
+
const lightness = 55;
|
|
96
|
+
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
97
|
+
}
|
|
98
|
+
function toBase64(svg) {
|
|
99
|
+
const globalRef = typeof globalThis !== "undefined" ? globalThis : void 0;
|
|
100
|
+
const bufferCtor = globalRef && globalRef.Buffer;
|
|
101
|
+
if (bufferCtor) {
|
|
102
|
+
return bufferCtor.from(svg, "utf8").toString("base64");
|
|
103
|
+
}
|
|
104
|
+
const btoaFn = globalRef && globalRef.btoa;
|
|
105
|
+
if (btoaFn) {
|
|
106
|
+
return btoaFn(unescape(encodeURIComponent(svg)));
|
|
107
|
+
}
|
|
108
|
+
throw new Error("No base64 encoder available in this environment.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// src/vue.ts
|
|
112
|
+
var DEFAULT_SIZE2 = 96;
|
|
113
|
+
var InitialsAvatar = (0, import_vue.defineComponent)({
|
|
114
|
+
name: "InitialsAvatar",
|
|
115
|
+
props: {
|
|
116
|
+
name: { type: String, required: true },
|
|
117
|
+
alt: { type: String, default: void 0 },
|
|
118
|
+
as: { type: String, default: "img" },
|
|
119
|
+
title: { type: String, default: void 0 },
|
|
120
|
+
size: { type: Number, default: void 0 },
|
|
121
|
+
backgroundColor: { type: String, default: void 0 },
|
|
122
|
+
fontColor: { type: String, default: void 0 },
|
|
123
|
+
fontSize: { type: Number, default: void 0 },
|
|
124
|
+
fontFamily: { type: String, default: void 0 },
|
|
125
|
+
borderWidth: { type: Number, default: void 0 },
|
|
126
|
+
borderColor: { type: String, default: void 0 },
|
|
127
|
+
borderRadius: { type: Number, default: void 0 },
|
|
128
|
+
bold: { type: Boolean, default: void 0 },
|
|
129
|
+
initialsOverride: { type: String, default: void 0 }
|
|
130
|
+
},
|
|
131
|
+
setup(props, { attrs }) {
|
|
132
|
+
const avatarOptions = (0, import_vue.computed)(() => ({
|
|
133
|
+
size: props.size,
|
|
134
|
+
backgroundColor: props.backgroundColor,
|
|
135
|
+
fontColor: props.fontColor,
|
|
136
|
+
fontSize: props.fontSize,
|
|
137
|
+
fontFamily: props.fontFamily,
|
|
138
|
+
borderWidth: props.borderWidth,
|
|
139
|
+
borderColor: props.borderColor,
|
|
140
|
+
borderRadius: props.borderRadius,
|
|
141
|
+
bold: props.bold,
|
|
142
|
+
initialsOverride: props.initialsOverride
|
|
143
|
+
}));
|
|
144
|
+
const dataUri = (0, import_vue.computed)(() => createAvatarDataUri(props.name, avatarOptions.value));
|
|
145
|
+
const svgMarkup = (0, import_vue.computed)(() => createAvatarSvg(props.name, avatarOptions.value));
|
|
146
|
+
const sizeValue = (0, import_vue.computed)(() => props.size ?? DEFAULT_SIZE2);
|
|
147
|
+
const altText = (0, import_vue.computed)(() => props.alt ?? `Avatar for ${props.name || getInitials(props.name)}`);
|
|
148
|
+
return () => {
|
|
149
|
+
if (props.as === "svg") {
|
|
150
|
+
return (0, import_vue.h)("span", {
|
|
151
|
+
...attrs,
|
|
152
|
+
innerHTML: svgMarkup.value,
|
|
153
|
+
role: "img",
|
|
154
|
+
"aria-label": altText.value,
|
|
155
|
+
title: props.title
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return (0, import_vue.h)("img", {
|
|
159
|
+
...attrs,
|
|
160
|
+
src: dataUri.value,
|
|
161
|
+
width: sizeValue.value,
|
|
162
|
+
height: sizeValue.value,
|
|
163
|
+
alt: altText.value,
|
|
164
|
+
title: props.title
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
var InitialsAvatarPlugin = {
|
|
170
|
+
install(app) {
|
|
171
|
+
app.component("InitialsAvatar", InitialsAvatar);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
var vue_default = InitialsAvatar;
|
|
175
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
176
|
+
0 && (module.exports = {
|
|
177
|
+
InitialsAvatar,
|
|
178
|
+
InitialsAvatarPlugin
|
|
179
|
+
});
|
package/dist/vue.d.cts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { PropType, App } from 'vue';
|
|
3
|
+
import { AvatarOptions } from './index.cjs';
|
|
4
|
+
|
|
5
|
+
type InitialsAvatarProps = AvatarOptions & {
|
|
6
|
+
name: string;
|
|
7
|
+
alt?: string;
|
|
8
|
+
as?: 'img' | 'svg';
|
|
9
|
+
title?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const InitialsAvatar: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
12
|
+
name: {
|
|
13
|
+
type: StringConstructor;
|
|
14
|
+
required: true;
|
|
15
|
+
};
|
|
16
|
+
alt: {
|
|
17
|
+
type: StringConstructor;
|
|
18
|
+
default: undefined;
|
|
19
|
+
};
|
|
20
|
+
as: {
|
|
21
|
+
type: PropType<"img" | "svg">;
|
|
22
|
+
default: string;
|
|
23
|
+
};
|
|
24
|
+
title: {
|
|
25
|
+
type: StringConstructor;
|
|
26
|
+
default: undefined;
|
|
27
|
+
};
|
|
28
|
+
size: {
|
|
29
|
+
type: NumberConstructor;
|
|
30
|
+
default: undefined;
|
|
31
|
+
};
|
|
32
|
+
backgroundColor: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
default: undefined;
|
|
35
|
+
};
|
|
36
|
+
fontColor: {
|
|
37
|
+
type: StringConstructor;
|
|
38
|
+
default: undefined;
|
|
39
|
+
};
|
|
40
|
+
fontSize: {
|
|
41
|
+
type: NumberConstructor;
|
|
42
|
+
default: undefined;
|
|
43
|
+
};
|
|
44
|
+
fontFamily: {
|
|
45
|
+
type: StringConstructor;
|
|
46
|
+
default: undefined;
|
|
47
|
+
};
|
|
48
|
+
borderWidth: {
|
|
49
|
+
type: NumberConstructor;
|
|
50
|
+
default: undefined;
|
|
51
|
+
};
|
|
52
|
+
borderColor: {
|
|
53
|
+
type: StringConstructor;
|
|
54
|
+
default: undefined;
|
|
55
|
+
};
|
|
56
|
+
borderRadius: {
|
|
57
|
+
type: NumberConstructor;
|
|
58
|
+
default: undefined;
|
|
59
|
+
};
|
|
60
|
+
bold: {
|
|
61
|
+
type: BooleanConstructor;
|
|
62
|
+
default: undefined;
|
|
63
|
+
};
|
|
64
|
+
initialsOverride: {
|
|
65
|
+
type: StringConstructor;
|
|
66
|
+
default: undefined;
|
|
67
|
+
};
|
|
68
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
69
|
+
[key: string]: any;
|
|
70
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
71
|
+
name: {
|
|
72
|
+
type: StringConstructor;
|
|
73
|
+
required: true;
|
|
74
|
+
};
|
|
75
|
+
alt: {
|
|
76
|
+
type: StringConstructor;
|
|
77
|
+
default: undefined;
|
|
78
|
+
};
|
|
79
|
+
as: {
|
|
80
|
+
type: PropType<"img" | "svg">;
|
|
81
|
+
default: string;
|
|
82
|
+
};
|
|
83
|
+
title: {
|
|
84
|
+
type: StringConstructor;
|
|
85
|
+
default: undefined;
|
|
86
|
+
};
|
|
87
|
+
size: {
|
|
88
|
+
type: NumberConstructor;
|
|
89
|
+
default: undefined;
|
|
90
|
+
};
|
|
91
|
+
backgroundColor: {
|
|
92
|
+
type: StringConstructor;
|
|
93
|
+
default: undefined;
|
|
94
|
+
};
|
|
95
|
+
fontColor: {
|
|
96
|
+
type: StringConstructor;
|
|
97
|
+
default: undefined;
|
|
98
|
+
};
|
|
99
|
+
fontSize: {
|
|
100
|
+
type: NumberConstructor;
|
|
101
|
+
default: undefined;
|
|
102
|
+
};
|
|
103
|
+
fontFamily: {
|
|
104
|
+
type: StringConstructor;
|
|
105
|
+
default: undefined;
|
|
106
|
+
};
|
|
107
|
+
borderWidth: {
|
|
108
|
+
type: NumberConstructor;
|
|
109
|
+
default: undefined;
|
|
110
|
+
};
|
|
111
|
+
borderColor: {
|
|
112
|
+
type: StringConstructor;
|
|
113
|
+
default: undefined;
|
|
114
|
+
};
|
|
115
|
+
borderRadius: {
|
|
116
|
+
type: NumberConstructor;
|
|
117
|
+
default: undefined;
|
|
118
|
+
};
|
|
119
|
+
bold: {
|
|
120
|
+
type: BooleanConstructor;
|
|
121
|
+
default: undefined;
|
|
122
|
+
};
|
|
123
|
+
initialsOverride: {
|
|
124
|
+
type: StringConstructor;
|
|
125
|
+
default: undefined;
|
|
126
|
+
};
|
|
127
|
+
}>> & Readonly<{}>, {
|
|
128
|
+
alt: string;
|
|
129
|
+
as: "img" | "svg";
|
|
130
|
+
title: string;
|
|
131
|
+
size: number;
|
|
132
|
+
backgroundColor: string;
|
|
133
|
+
fontColor: string;
|
|
134
|
+
fontSize: number;
|
|
135
|
+
fontFamily: string;
|
|
136
|
+
borderWidth: number;
|
|
137
|
+
borderColor: string;
|
|
138
|
+
borderRadius: number;
|
|
139
|
+
bold: boolean;
|
|
140
|
+
initialsOverride: string;
|
|
141
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
142
|
+
declare const InitialsAvatarPlugin: {
|
|
143
|
+
install(app: App): void;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export { AvatarOptions, InitialsAvatar, InitialsAvatarPlugin, type InitialsAvatarProps, InitialsAvatar as default };
|
package/dist/vue.d.ts
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import * as vue from 'vue';
|
|
2
|
+
import { PropType, App } from 'vue';
|
|
3
|
+
import { AvatarOptions } from './index.js';
|
|
4
|
+
|
|
5
|
+
type InitialsAvatarProps = AvatarOptions & {
|
|
6
|
+
name: string;
|
|
7
|
+
alt?: string;
|
|
8
|
+
as?: 'img' | 'svg';
|
|
9
|
+
title?: string;
|
|
10
|
+
};
|
|
11
|
+
declare const InitialsAvatar: vue.DefineComponent<vue.ExtractPropTypes<{
|
|
12
|
+
name: {
|
|
13
|
+
type: StringConstructor;
|
|
14
|
+
required: true;
|
|
15
|
+
};
|
|
16
|
+
alt: {
|
|
17
|
+
type: StringConstructor;
|
|
18
|
+
default: undefined;
|
|
19
|
+
};
|
|
20
|
+
as: {
|
|
21
|
+
type: PropType<"img" | "svg">;
|
|
22
|
+
default: string;
|
|
23
|
+
};
|
|
24
|
+
title: {
|
|
25
|
+
type: StringConstructor;
|
|
26
|
+
default: undefined;
|
|
27
|
+
};
|
|
28
|
+
size: {
|
|
29
|
+
type: NumberConstructor;
|
|
30
|
+
default: undefined;
|
|
31
|
+
};
|
|
32
|
+
backgroundColor: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
default: undefined;
|
|
35
|
+
};
|
|
36
|
+
fontColor: {
|
|
37
|
+
type: StringConstructor;
|
|
38
|
+
default: undefined;
|
|
39
|
+
};
|
|
40
|
+
fontSize: {
|
|
41
|
+
type: NumberConstructor;
|
|
42
|
+
default: undefined;
|
|
43
|
+
};
|
|
44
|
+
fontFamily: {
|
|
45
|
+
type: StringConstructor;
|
|
46
|
+
default: undefined;
|
|
47
|
+
};
|
|
48
|
+
borderWidth: {
|
|
49
|
+
type: NumberConstructor;
|
|
50
|
+
default: undefined;
|
|
51
|
+
};
|
|
52
|
+
borderColor: {
|
|
53
|
+
type: StringConstructor;
|
|
54
|
+
default: undefined;
|
|
55
|
+
};
|
|
56
|
+
borderRadius: {
|
|
57
|
+
type: NumberConstructor;
|
|
58
|
+
default: undefined;
|
|
59
|
+
};
|
|
60
|
+
bold: {
|
|
61
|
+
type: BooleanConstructor;
|
|
62
|
+
default: undefined;
|
|
63
|
+
};
|
|
64
|
+
initialsOverride: {
|
|
65
|
+
type: StringConstructor;
|
|
66
|
+
default: undefined;
|
|
67
|
+
};
|
|
68
|
+
}>, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
|
|
69
|
+
[key: string]: any;
|
|
70
|
+
}>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<vue.ExtractPropTypes<{
|
|
71
|
+
name: {
|
|
72
|
+
type: StringConstructor;
|
|
73
|
+
required: true;
|
|
74
|
+
};
|
|
75
|
+
alt: {
|
|
76
|
+
type: StringConstructor;
|
|
77
|
+
default: undefined;
|
|
78
|
+
};
|
|
79
|
+
as: {
|
|
80
|
+
type: PropType<"img" | "svg">;
|
|
81
|
+
default: string;
|
|
82
|
+
};
|
|
83
|
+
title: {
|
|
84
|
+
type: StringConstructor;
|
|
85
|
+
default: undefined;
|
|
86
|
+
};
|
|
87
|
+
size: {
|
|
88
|
+
type: NumberConstructor;
|
|
89
|
+
default: undefined;
|
|
90
|
+
};
|
|
91
|
+
backgroundColor: {
|
|
92
|
+
type: StringConstructor;
|
|
93
|
+
default: undefined;
|
|
94
|
+
};
|
|
95
|
+
fontColor: {
|
|
96
|
+
type: StringConstructor;
|
|
97
|
+
default: undefined;
|
|
98
|
+
};
|
|
99
|
+
fontSize: {
|
|
100
|
+
type: NumberConstructor;
|
|
101
|
+
default: undefined;
|
|
102
|
+
};
|
|
103
|
+
fontFamily: {
|
|
104
|
+
type: StringConstructor;
|
|
105
|
+
default: undefined;
|
|
106
|
+
};
|
|
107
|
+
borderWidth: {
|
|
108
|
+
type: NumberConstructor;
|
|
109
|
+
default: undefined;
|
|
110
|
+
};
|
|
111
|
+
borderColor: {
|
|
112
|
+
type: StringConstructor;
|
|
113
|
+
default: undefined;
|
|
114
|
+
};
|
|
115
|
+
borderRadius: {
|
|
116
|
+
type: NumberConstructor;
|
|
117
|
+
default: undefined;
|
|
118
|
+
};
|
|
119
|
+
bold: {
|
|
120
|
+
type: BooleanConstructor;
|
|
121
|
+
default: undefined;
|
|
122
|
+
};
|
|
123
|
+
initialsOverride: {
|
|
124
|
+
type: StringConstructor;
|
|
125
|
+
default: undefined;
|
|
126
|
+
};
|
|
127
|
+
}>> & Readonly<{}>, {
|
|
128
|
+
alt: string;
|
|
129
|
+
as: "img" | "svg";
|
|
130
|
+
title: string;
|
|
131
|
+
size: number;
|
|
132
|
+
backgroundColor: string;
|
|
133
|
+
fontColor: string;
|
|
134
|
+
fontSize: number;
|
|
135
|
+
fontFamily: string;
|
|
136
|
+
borderWidth: number;
|
|
137
|
+
borderColor: string;
|
|
138
|
+
borderRadius: number;
|
|
139
|
+
bold: boolean;
|
|
140
|
+
initialsOverride: string;
|
|
141
|
+
}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
|
|
142
|
+
declare const InitialsAvatarPlugin: {
|
|
143
|
+
install(app: App): void;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export { AvatarOptions, InitialsAvatar, InitialsAvatarPlugin, type InitialsAvatarProps, InitialsAvatar as default };
|
package/dist/vue.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAvatarDataUri,
|
|
3
|
+
createAvatarSvg,
|
|
4
|
+
getInitials
|
|
5
|
+
} from "./chunk-PMFHYTR7.js";
|
|
6
|
+
|
|
7
|
+
// src/vue.ts
|
|
8
|
+
import { computed, defineComponent, h } from "vue";
|
|
9
|
+
var DEFAULT_SIZE = 96;
|
|
10
|
+
var InitialsAvatar = defineComponent({
|
|
11
|
+
name: "InitialsAvatar",
|
|
12
|
+
props: {
|
|
13
|
+
name: { type: String, required: true },
|
|
14
|
+
alt: { type: String, default: void 0 },
|
|
15
|
+
as: { type: String, default: "img" },
|
|
16
|
+
title: { type: String, default: void 0 },
|
|
17
|
+
size: { type: Number, default: void 0 },
|
|
18
|
+
backgroundColor: { type: String, default: void 0 },
|
|
19
|
+
fontColor: { type: String, default: void 0 },
|
|
20
|
+
fontSize: { type: Number, default: void 0 },
|
|
21
|
+
fontFamily: { type: String, default: void 0 },
|
|
22
|
+
borderWidth: { type: Number, default: void 0 },
|
|
23
|
+
borderColor: { type: String, default: void 0 },
|
|
24
|
+
borderRadius: { type: Number, default: void 0 },
|
|
25
|
+
bold: { type: Boolean, default: void 0 },
|
|
26
|
+
initialsOverride: { type: String, default: void 0 }
|
|
27
|
+
},
|
|
28
|
+
setup(props, { attrs }) {
|
|
29
|
+
const avatarOptions = computed(() => ({
|
|
30
|
+
size: props.size,
|
|
31
|
+
backgroundColor: props.backgroundColor,
|
|
32
|
+
fontColor: props.fontColor,
|
|
33
|
+
fontSize: props.fontSize,
|
|
34
|
+
fontFamily: props.fontFamily,
|
|
35
|
+
borderWidth: props.borderWidth,
|
|
36
|
+
borderColor: props.borderColor,
|
|
37
|
+
borderRadius: props.borderRadius,
|
|
38
|
+
bold: props.bold,
|
|
39
|
+
initialsOverride: props.initialsOverride
|
|
40
|
+
}));
|
|
41
|
+
const dataUri = computed(() => createAvatarDataUri(props.name, avatarOptions.value));
|
|
42
|
+
const svgMarkup = computed(() => createAvatarSvg(props.name, avatarOptions.value));
|
|
43
|
+
const sizeValue = computed(() => props.size ?? DEFAULT_SIZE);
|
|
44
|
+
const altText = computed(() => props.alt ?? `Avatar for ${props.name || getInitials(props.name)}`);
|
|
45
|
+
return () => {
|
|
46
|
+
if (props.as === "svg") {
|
|
47
|
+
return h("span", {
|
|
48
|
+
...attrs,
|
|
49
|
+
innerHTML: svgMarkup.value,
|
|
50
|
+
role: "img",
|
|
51
|
+
"aria-label": altText.value,
|
|
52
|
+
title: props.title
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return h("img", {
|
|
56
|
+
...attrs,
|
|
57
|
+
src: dataUri.value,
|
|
58
|
+
width: sizeValue.value,
|
|
59
|
+
height: sizeValue.value,
|
|
60
|
+
alt: altText.value,
|
|
61
|
+
title: props.title
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
var InitialsAvatarPlugin = {
|
|
67
|
+
install(app) {
|
|
68
|
+
app.component("InitialsAvatar", InitialsAvatar);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var vue_default = InitialsAvatar;
|
|
72
|
+
export {
|
|
73
|
+
InitialsAvatar,
|
|
74
|
+
InitialsAvatarPlugin,
|
|
75
|
+
vue_default as default
|
|
76
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@avyn/initials-avatar",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Framework-agnostic SVG initials avatar generator",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
},
|
|
15
|
+
"./react": {
|
|
16
|
+
"import": "./dist/react.mjs",
|
|
17
|
+
"require": "./dist/react.cjs",
|
|
18
|
+
"types": "./dist/react.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./vue": {
|
|
21
|
+
"import": "./dist/vue.mjs",
|
|
22
|
+
"require": "./dist/vue.cjs",
|
|
23
|
+
"types": "./dist/vue.d.ts"
|
|
24
|
+
},
|
|
25
|
+
"./package.json": "./package.json"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup src/index.ts src/react.tsx src/vue.ts --format esm,cjs --dts --clean"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"avatar",
|
|
35
|
+
"initials",
|
|
36
|
+
"svg",
|
|
37
|
+
"node",
|
|
38
|
+
"browser",
|
|
39
|
+
"ssr"
|
|
40
|
+
],
|
|
41
|
+
"author": "@avyn",
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"sideEffects": false,
|
|
44
|
+
"peerDependencies": {
|
|
45
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
46
|
+
"vue": "^3.3.0"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"react": { "optional": true },
|
|
50
|
+
"vue": { "optional": true }
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/react": "^18.3.12",
|
|
54
|
+
"react": "^18.3.1",
|
|
55
|
+
"tsup": "^8.2.4",
|
|
56
|
+
"typescript": "^5.6.3",
|
|
57
|
+
"vue": "^3.5.13"
|
|
58
|
+
}
|
|
59
|
+
}
|