@sesionario/blocks 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/avatar.cjs +89 -0
- package/dist/avatar.cjs.map +1 -0
- package/dist/avatar.d.cts +18 -0
- package/dist/avatar.d.ts +18 -0
- package/dist/avatar.js +85 -0
- package/dist/avatar.js.map +1 -0
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -19
- package/dist/index.d.ts +7 -19
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -12,6 +12,14 @@ Shared feedback patterns include `ConfirmDestructiveDialog` (confirm before dele
|
|
|
12
12
|
pnpm add @sesionario/blocks
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
The main entry is a Client Component boundary. Pure helpers that must run in
|
|
16
|
+
React Server Components (e.g. avatar initials/colors) should be imported from
|
|
17
|
+
the server-safe subpath:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { avatarFallbackStyle, getInitials } from "@sesionario/blocks/avatar";
|
|
21
|
+
```
|
|
22
|
+
|
|
15
23
|
Peer dependencies (install in the consuming app as needed):
|
|
16
24
|
|
|
17
25
|
- `react`, `react-dom`
|
package/dist/avatar.cjs
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/lib/avatar.ts
|
|
4
|
+
var EMPTY_COLORS = {
|
|
5
|
+
backgroundColor: "#9ca3af",
|
|
6
|
+
color: "#111111"
|
|
7
|
+
};
|
|
8
|
+
var AVATAR_PALETTE = [
|
|
9
|
+
"#4f6d8c",
|
|
10
|
+
// slate blue
|
|
11
|
+
"#3d7a6a",
|
|
12
|
+
// teal
|
|
13
|
+
"#6b5b8a",
|
|
14
|
+
// muted purple
|
|
15
|
+
"#8a5a4a",
|
|
16
|
+
// warm brown
|
|
17
|
+
"#4a7a8a",
|
|
18
|
+
// steel cyan
|
|
19
|
+
"#7a6b4a",
|
|
20
|
+
// olive
|
|
21
|
+
"#5a6b8a",
|
|
22
|
+
// periwinkle
|
|
23
|
+
"#8a4a5a",
|
|
24
|
+
// rose
|
|
25
|
+
"#4a8a6b",
|
|
26
|
+
// green
|
|
27
|
+
"#6b4a7a",
|
|
28
|
+
// plum
|
|
29
|
+
"#8a6b4a",
|
|
30
|
+
// amber brown
|
|
31
|
+
"#4a5a8a",
|
|
32
|
+
// indigo
|
|
33
|
+
"#7a4a6b",
|
|
34
|
+
// mauve
|
|
35
|
+
"#5a8a4a",
|
|
36
|
+
// leaf
|
|
37
|
+
"#8a5a7a",
|
|
38
|
+
// dusty pink
|
|
39
|
+
"#3d6b7a"
|
|
40
|
+
// deep teal
|
|
41
|
+
];
|
|
42
|
+
function hashString(input) {
|
|
43
|
+
let hash = 2166136261;
|
|
44
|
+
for (let i = 0; i < input.length; i++) {
|
|
45
|
+
hash ^= input.charCodeAt(i);
|
|
46
|
+
hash = Math.imul(hash, 16777619);
|
|
47
|
+
}
|
|
48
|
+
return hash >>> 0;
|
|
49
|
+
}
|
|
50
|
+
function srgbToLinear(channel) {
|
|
51
|
+
const c = channel / 255;
|
|
52
|
+
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
53
|
+
}
|
|
54
|
+
function relativeLuminance(hex) {
|
|
55
|
+
const normalized = hex.replace("#", "");
|
|
56
|
+
const r = Number.parseInt(normalized.slice(0, 2), 16);
|
|
57
|
+
const g = Number.parseInt(normalized.slice(2, 4), 16);
|
|
58
|
+
const b = Number.parseInt(normalized.slice(4, 6), 16);
|
|
59
|
+
return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
|
|
60
|
+
}
|
|
61
|
+
function contrastingTextColor(backgroundHex) {
|
|
62
|
+
return relativeLuminance(backgroundHex) > 0.179 ? "#111111" : "#ffffff";
|
|
63
|
+
}
|
|
64
|
+
function getInitials(name, max = 2) {
|
|
65
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
66
|
+
if (parts.length === 0) return "?";
|
|
67
|
+
const letters = parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("");
|
|
68
|
+
return letters.toUpperCase() || "?";
|
|
69
|
+
}
|
|
70
|
+
function getAvatarColors(name) {
|
|
71
|
+
const normalized = name.trim().toLowerCase();
|
|
72
|
+
if (!normalized) {
|
|
73
|
+
return { ...EMPTY_COLORS };
|
|
74
|
+
}
|
|
75
|
+
const backgroundColor = AVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length];
|
|
76
|
+
return {
|
|
77
|
+
backgroundColor,
|
|
78
|
+
color: contrastingTextColor(backgroundColor)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
function avatarFallbackStyle(name) {
|
|
82
|
+
return getAvatarColors(name);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
exports.avatarFallbackStyle = avatarFallbackStyle;
|
|
86
|
+
exports.getAvatarColors = getAvatarColors;
|
|
87
|
+
exports.getInitials = getInitials;
|
|
88
|
+
//# sourceMappingURL=avatar.cjs.map
|
|
89
|
+
//# sourceMappingURL=avatar.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.cjs","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\tconst letters = parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\");\n\treturn letters.toUpperCase() || \"?\";\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type AvatarColors = {
|
|
2
|
+
backgroundColor: string;
|
|
3
|
+
color: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Word-based initials from a display name (max letters, default 2).
|
|
7
|
+
* Empty / whitespace-only names yield `"?"`.
|
|
8
|
+
*/
|
|
9
|
+
declare function getInitials(name: string, max?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Deterministic background + contrasting foreground from a full name.
|
|
12
|
+
* Same name (case-insensitive) always maps to the same colors.
|
|
13
|
+
*/
|
|
14
|
+
declare function getAvatarColors(name: string): AvatarColors;
|
|
15
|
+
/** CSS style object for `AvatarFallback` (or any letter-avatar container). */
|
|
16
|
+
declare function avatarFallbackStyle(name: string): Pick<AvatarColors, "backgroundColor" | "color">;
|
|
17
|
+
|
|
18
|
+
export { type AvatarColors, avatarFallbackStyle, getAvatarColors, getInitials };
|
package/dist/avatar.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
type AvatarColors = {
|
|
2
|
+
backgroundColor: string;
|
|
3
|
+
color: string;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Word-based initials from a display name (max letters, default 2).
|
|
7
|
+
* Empty / whitespace-only names yield `"?"`.
|
|
8
|
+
*/
|
|
9
|
+
declare function getInitials(name: string, max?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Deterministic background + contrasting foreground from a full name.
|
|
12
|
+
* Same name (case-insensitive) always maps to the same colors.
|
|
13
|
+
*/
|
|
14
|
+
declare function getAvatarColors(name: string): AvatarColors;
|
|
15
|
+
/** CSS style object for `AvatarFallback` (or any letter-avatar container). */
|
|
16
|
+
declare function avatarFallbackStyle(name: string): Pick<AvatarColors, "backgroundColor" | "color">;
|
|
17
|
+
|
|
18
|
+
export { type AvatarColors, avatarFallbackStyle, getAvatarColors, getInitials };
|
package/dist/avatar.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// src/lib/avatar.ts
|
|
2
|
+
var EMPTY_COLORS = {
|
|
3
|
+
backgroundColor: "#9ca3af",
|
|
4
|
+
color: "#111111"
|
|
5
|
+
};
|
|
6
|
+
var AVATAR_PALETTE = [
|
|
7
|
+
"#4f6d8c",
|
|
8
|
+
// slate blue
|
|
9
|
+
"#3d7a6a",
|
|
10
|
+
// teal
|
|
11
|
+
"#6b5b8a",
|
|
12
|
+
// muted purple
|
|
13
|
+
"#8a5a4a",
|
|
14
|
+
// warm brown
|
|
15
|
+
"#4a7a8a",
|
|
16
|
+
// steel cyan
|
|
17
|
+
"#7a6b4a",
|
|
18
|
+
// olive
|
|
19
|
+
"#5a6b8a",
|
|
20
|
+
// periwinkle
|
|
21
|
+
"#8a4a5a",
|
|
22
|
+
// rose
|
|
23
|
+
"#4a8a6b",
|
|
24
|
+
// green
|
|
25
|
+
"#6b4a7a",
|
|
26
|
+
// plum
|
|
27
|
+
"#8a6b4a",
|
|
28
|
+
// amber brown
|
|
29
|
+
"#4a5a8a",
|
|
30
|
+
// indigo
|
|
31
|
+
"#7a4a6b",
|
|
32
|
+
// mauve
|
|
33
|
+
"#5a8a4a",
|
|
34
|
+
// leaf
|
|
35
|
+
"#8a5a7a",
|
|
36
|
+
// dusty pink
|
|
37
|
+
"#3d6b7a"
|
|
38
|
+
// deep teal
|
|
39
|
+
];
|
|
40
|
+
function hashString(input) {
|
|
41
|
+
let hash = 2166136261;
|
|
42
|
+
for (let i = 0; i < input.length; i++) {
|
|
43
|
+
hash ^= input.charCodeAt(i);
|
|
44
|
+
hash = Math.imul(hash, 16777619);
|
|
45
|
+
}
|
|
46
|
+
return hash >>> 0;
|
|
47
|
+
}
|
|
48
|
+
function srgbToLinear(channel) {
|
|
49
|
+
const c = channel / 255;
|
|
50
|
+
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
51
|
+
}
|
|
52
|
+
function relativeLuminance(hex) {
|
|
53
|
+
const normalized = hex.replace("#", "");
|
|
54
|
+
const r = Number.parseInt(normalized.slice(0, 2), 16);
|
|
55
|
+
const g = Number.parseInt(normalized.slice(2, 4), 16);
|
|
56
|
+
const b = Number.parseInt(normalized.slice(4, 6), 16);
|
|
57
|
+
return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
|
|
58
|
+
}
|
|
59
|
+
function contrastingTextColor(backgroundHex) {
|
|
60
|
+
return relativeLuminance(backgroundHex) > 0.179 ? "#111111" : "#ffffff";
|
|
61
|
+
}
|
|
62
|
+
function getInitials(name, max = 2) {
|
|
63
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
64
|
+
if (parts.length === 0) return "?";
|
|
65
|
+
const letters = parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("");
|
|
66
|
+
return letters.toUpperCase() || "?";
|
|
67
|
+
}
|
|
68
|
+
function getAvatarColors(name) {
|
|
69
|
+
const normalized = name.trim().toLowerCase();
|
|
70
|
+
if (!normalized) {
|
|
71
|
+
return { ...EMPTY_COLORS };
|
|
72
|
+
}
|
|
73
|
+
const backgroundColor = AVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length];
|
|
74
|
+
return {
|
|
75
|
+
backgroundColor,
|
|
76
|
+
color: contrastingTextColor(backgroundColor)
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function avatarFallbackStyle(name) {
|
|
80
|
+
return getAvatarColors(name);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { avatarFallbackStyle, getAvatarColors, getInitials };
|
|
84
|
+
//# sourceMappingURL=avatar.js.map
|
|
85
|
+
//# sourceMappingURL=avatar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/avatar.ts"],"names":[],"mappings":"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","file":"avatar.js","sourcesContent":["/** Neutral fallback when the name is empty. */\nconst EMPTY_COLORS = {\n\tbackgroundColor: \"#9ca3af\",\n\tcolor: \"#111111\",\n} as const;\n\n/**\n * Curated mid-lightness palette — professional, calm hues that stay\n * distinct when hashed by name and contrast well with black or white text.\n */\nconst AVATAR_PALETTE = [\n\t\"#4f6d8c\", // slate blue\n\t\"#3d7a6a\", // teal\n\t\"#6b5b8a\", // muted purple\n\t\"#8a5a4a\", // warm brown\n\t\"#4a7a8a\", // steel cyan\n\t\"#7a6b4a\", // olive\n\t\"#5a6b8a\", // periwinkle\n\t\"#8a4a5a\", // rose\n\t\"#4a8a6b\", // green\n\t\"#6b4a7a\", // plum\n\t\"#8a6b4a\", // amber brown\n\t\"#4a5a8a\", // indigo\n\t\"#7a4a6b\", // mauve\n\t\"#5a8a4a\", // leaf\n\t\"#8a5a7a\", // dusty pink\n\t\"#3d6b7a\", // deep teal\n] as const;\n\nexport type AvatarColors = {\n\tbackgroundColor: string;\n\tcolor: string;\n};\n\n/** FNV-1a 32-bit hash — stable across runtimes for the same string. */\nfunction hashString(input: string): number {\n\tlet hash = 0x811c9dc5;\n\tfor (let i = 0; i < input.length; i++) {\n\t\thash ^= input.charCodeAt(i);\n\t\thash = Math.imul(hash, 0x01000193);\n\t}\n\treturn hash >>> 0;\n}\n\nfunction srgbToLinear(channel: number): number {\n\tconst c = channel / 255;\n\treturn c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;\n}\n\n/** Relative luminance (WCAG) for a hex color like `#rrggbb`. */\nfunction relativeLuminance(hex: string): number {\n\tconst normalized = hex.replace(\"#\", \"\");\n\tconst r = Number.parseInt(normalized.slice(0, 2), 16);\n\tconst g = Number.parseInt(normalized.slice(2, 4), 16);\n\tconst b = Number.parseInt(normalized.slice(4, 6), 16);\n\treturn (\n\t\t0.2126 * srgbToLinear(r) +\n\t\t0.7152 * srgbToLinear(g) +\n\t\t0.0722 * srgbToLinear(b)\n\t);\n}\n\nfunction contrastingTextColor(backgroundHex: string): \"#ffffff\" | \"#111111\" {\n\t// Threshold ~0.179 ≈ contrast preference for mid tones (WCAG-inspired).\n\treturn relativeLuminance(backgroundHex) > 0.179 ? \"#111111\" : \"#ffffff\";\n}\n\n/**\n * Word-based initials from a display name (max letters, default 2).\n * Empty / whitespace-only names yield `\"?\"`.\n */\nexport function getInitials(name: string, max = 2): string {\n\tconst parts = name.trim().split(/\\s+/).filter(Boolean);\n\tif (parts.length === 0) return \"?\";\n\tconst letters = parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\");\n\treturn letters.toUpperCase() || \"?\";\n}\n\n/**\n * Deterministic background + contrasting foreground from a full name.\n * Same name (case-insensitive) always maps to the same colors.\n */\nexport function getAvatarColors(name: string): AvatarColors {\n\tconst normalized = name.trim().toLowerCase();\n\tif (!normalized) {\n\t\treturn { ...EMPTY_COLORS };\n\t}\n\tconst backgroundColor =\n\t\tAVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length]!;\n\treturn {\n\t\tbackgroundColor,\n\t\tcolor: contrastingTextColor(backgroundColor),\n\t};\n}\n\n/** CSS style object for `AvatarFallback` (or any letter-avatar container). */\nexport function avatarFallbackStyle(\n\tname: string,\n): Pick<AvatarColors, \"backgroundColor\" | \"color\"> {\n\treturn getAvatarColors(name);\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1987,6 +1987,8 @@ function AvatarEditorDialog({
|
|
|
1987
1987
|
dialogTitle = "Edit Avatar",
|
|
1988
1988
|
acceptText = "Accept",
|
|
1989
1989
|
cancelText = "Cancel",
|
|
1990
|
+
savingText = "Saving...",
|
|
1991
|
+
savedText = "Saved!",
|
|
1990
1992
|
successMessage = "Avatar saved successfully!",
|
|
1991
1993
|
errorMessage = "Failed to save avatar. Please try again.",
|
|
1992
1994
|
className
|
|
@@ -2148,10 +2150,10 @@ function AvatarEditorDialog({
|
|
|
2148
2150
|
)
|
|
2149
2151
|
}
|
|
2150
2152
|
),
|
|
2151
|
-
|
|
2153
|
+
savingText
|
|
2152
2154
|
] }) : feedback?.type === "success" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2153
2155
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: cn("mr-2", isMobile ? "w-5 h-5" : "w-4 h-4") }),
|
|
2154
|
-
|
|
2156
|
+
savedText
|
|
2155
2157
|
] }) : acceptText
|
|
2156
2158
|
}
|
|
2157
2159
|
)
|