@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.
@@ -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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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
+ });
@@ -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 };
@@ -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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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
+ });
@@ -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 };
@@ -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, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
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
+ }