@yenio-pld/blocks 0.0.0-stage → 0.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/README.md +100 -2
- package/dist/avatar.cjs +88 -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 +84 -0
- package/dist/avatar.js.map +1 -0
- package/dist/consent.cjs +85 -0
- package/dist/consent.cjs.map +1 -0
- package/dist/consent.d.cts +20 -0
- package/dist/consent.d.ts +20 -0
- package/dist/consent.js +73 -0
- package/dist/consent.js.map +1 -0
- package/dist/index.cjs +4053 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +859 -0
- package/dist/index.d.ts +859 -0
- package/dist/index.js +3947 -0
- package/dist/index.js.map +1 -0
- package/dist/theme-init.cjs +12 -0
- package/dist/theme-init.cjs.map +1 -0
- package/dist/theme-init.d.cts +11 -0
- package/dist/theme-init.d.ts +11 -0
- package/dist/theme-init.js +8 -0
- package/dist/theme-init.js.map +1 -0
- package/dist/ui/alert-dialog.d.ts +15 -0
- package/dist/ui/alert-dialog.js +137 -0
- package/dist/ui/alert-dialog.js.map +1 -0
- package/dist/ui/alert.d.ts +11 -0
- package/dist/ui/alert.js +57 -0
- package/dist/ui/alert.js.map +1 -0
- package/dist/ui/avatar.d.ts +13 -0
- package/dist/ui/avatar.js +105 -0
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge.d.ts +13 -0
- package/dist/ui/badge.js +33 -0
- package/dist/ui/badge.js.map +1 -0
- package/dist/ui/breadcrumb.d.ts +12 -0
- package/dist/ui/breadcrumb.js +121 -0
- package/dist/ui/breadcrumb.js.map +1 -0
- package/dist/ui/bubble.d.ts +19 -0
- package/dist/ui/bubble.js +120 -0
- package/dist/ui/bubble.js.map +1 -0
- package/dist/ui/button.d.ts +12 -0
- package/dist/ui/button.js +59 -0
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.d.ts +10 -0
- package/dist/ui/card.js +55 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/collapsible.d.ts +8 -0
- package/dist/ui/collapsible.js +17 -0
- package/dist/ui/collapsible.js.map +1 -0
- package/dist/ui/dialog.d.ts +16 -0
- package/dist/ui/dialog.js +125 -0
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.d.ts +31 -0
- package/dist/ui/dropdown-menu.js +244 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/input-otp.d.ts +39 -0
- package/dist/ui/input-otp.js +53 -0
- package/dist/ui/input-otp.js.map +1 -0
- package/dist/ui/input.d.ts +5 -0
- package/dist/ui/input.js +28 -0
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/label.d.ts +7 -0
- package/dist/ui/label.js +29 -0
- package/dist/ui/label.js.map +1 -0
- package/dist/ui/message.d.ts +12 -0
- package/dist/ui/message.js +93 -0
- package/dist/ui/message.js.map +1 -0
- package/dist/ui/progress.d.ts +9 -0
- package/dist/ui/progress.js +41 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/separator.d.ts +6 -0
- package/dist/ui/separator.js +31 -0
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/sheet.d.ts +16 -0
- package/dist/ui/sheet.js +127 -0
- package/dist/ui/sheet.js.map +1 -0
- package/dist/ui/sidebar.d.ts +69 -0
- package/dist/ui/sidebar.js +624 -0
- package/dist/ui/sidebar.js.map +1 -0
- package/dist/ui/skeleton.d.ts +5 -0
- package/dist/ui/skeleton.js +26 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/sonner.d.ts +6 -0
- package/dist/ui/sonner.js +25 -0
- package/dist/ui/sonner.js.map +1 -0
- package/dist/ui/switch.d.ts +8 -0
- package/dist/ui/switch.js +38 -0
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/table.d.ts +11 -0
- package/dist/ui/table.js +85 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/tooltip.d.ts +9 -0
- package/dist/ui/tooltip.js +67 -0
- package/dist/ui/tooltip.js.map +1 -0
- package/dist/ui/use-mobile.d.ts +3 -0
- package/dist/ui/use-mobile.js +24 -0
- package/dist/ui/use-mobile.js.map +1 -0
- package/package.json +281 -5
- package/scripts/check-theme.mjs +74 -0
- package/src/theme.css +191 -0
package/README.md
CHANGED
|
@@ -1,3 +1,101 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @yenio-pld/blocks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Shared UI for Yenio applications: shadcn primitives, the provisional theme, product chrome, and PLD components.
|
|
4
|
+
|
|
5
|
+
The main entry is a Client Component boundary (`"use client"`). Import avatar helpers from `@yenio-pld/blocks/avatar` and cookie helpers from `@yenio-pld/blocks/consent` in React Server Components. Import `THEME_INIT_SCRIPT` from `@yenio-pld/blocks/theme-init` in root layouts. That entry has no client boundary.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @yenio-pld/blocks
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peers:
|
|
14
|
+
|
|
15
|
+
- `framer-motion` — `ThemeSwitcher`, `LanguageSwitcher`, `AvatarEditorDialog`
|
|
16
|
+
- `next-themes` — `ThemeSwitcher` and `@yenio-pld/blocks/ui/sonner`
|
|
17
|
+
- `lucide-react` — icons
|
|
18
|
+
- `react` / `react-dom`
|
|
19
|
+
|
|
20
|
+
`next-themes` contract: `attribute="class"`, `storageKey="theme"`, default `system`.
|
|
21
|
+
|
|
22
|
+
## Tailwind
|
|
23
|
+
|
|
24
|
+
Scan the built package so utilities are not purged:
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
@source "../../node_modules/@yenio-pld/blocks/dist/**/*.{js,cjs,mjs}";
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Import the shared light and dark palette. Do not paste `:root` / `.dark` color tokens into the app. `src/theme.css` is the only color-token source. The palette is provisional (precise, calm, trustworthy) until brand sign-off.
|
|
31
|
+
|
|
32
|
+
```css
|
|
33
|
+
@import "tailwindcss";
|
|
34
|
+
@import "@yenio-pld/blocks/theme.css";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`theme.css` is CSS only. It does not pull the client barrel. The `@source` glob is recursive so classes in `dist/ui` are kept.
|
|
38
|
+
|
|
39
|
+
Fail the app build if a stylesheet redeclares those tokens:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
node node_modules/@yenio-pld/blocks/scripts/check-theme.mjs src
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Skeleton loading uses `--skeleton` / `bg-skeleton` (chroma 0), not `--primary` or `--accent`.
|
|
46
|
+
|
|
47
|
+
## UI primitives
|
|
48
|
+
|
|
49
|
+
Import each shadcn primitive from its own entry. A button import does not load the sidebar, the toast library, or the main chrome barrel:
|
|
50
|
+
|
|
51
|
+
```tsx
|
|
52
|
+
import { Button } from "@yenio-pld/blocks/ui/button";
|
|
53
|
+
import { Dialog, DialogContent } from "@yenio-pld/blocks/ui/dialog";
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`@yenio-pld/blocks/ui/sonner` needs the `next-themes` peer. Product chrome (empty state, confirm dialog, bell, switchers, legal, upload) and the PLD components stay on the main entry.
|
|
57
|
+
|
|
58
|
+
## PLD components
|
|
59
|
+
|
|
60
|
+
`AuditTimeline`, `RiskBadge`, `EntityGraph`, and `MatchReview` use the platform identifiers (`notice`, `beneficialOwner`, `sat69b`, `alert`). Pass user-visible copy through `labels`. Stories use `es-MX` defaults. English strings in the components are fallbacks.
|
|
61
|
+
|
|
62
|
+
`RiskBadge` does not invent a numeric score. When `smeVerified` is false it shows an unverified-rule label.
|
|
63
|
+
|
|
64
|
+
`MatchReview` calls `onResolve(status, reason)` only with a non-empty reason. A claim with `unverified` or a source URL that is not `https` is labeled unverified and is not styled as confirmed.
|
|
65
|
+
|
|
66
|
+
## Theme before paint
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import {
|
|
70
|
+
THEME_INIT_SCRIPT,
|
|
71
|
+
THEME_INIT_SCRIPT_ID,
|
|
72
|
+
} from "@yenio-pld/blocks/theme-init";
|
|
73
|
+
|
|
74
|
+
<script
|
|
75
|
+
id={THEME_INIT_SCRIPT_ID}
|
|
76
|
+
dangerouslySetInnerHTML={{ __html: THEME_INIT_SCRIPT }}
|
|
77
|
+
/>;
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## i18n
|
|
81
|
+
|
|
82
|
+
`LanguageSwitcher` defaults to `es-MX` and `en`. Pass `labels` from next-intl in the apps.
|
|
83
|
+
|
|
84
|
+
## Storybook
|
|
85
|
+
|
|
86
|
+
Stories live under `src/**/*.stories.tsx`. They are not part of the published package.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pnpm storybook
|
|
90
|
+
pnpm build-storybook
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Storybook serves on port 6006. The static build writes `storybook-static/`. Preview CSS imports `src/theme.css` and loads Inter.
|
|
94
|
+
|
|
95
|
+
## Quality gate
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pnpm run ci:check
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
That runs format, lint, typecheck, Vitest coverage (85% lines, functions, statements, and branches), the theme-token check, and the package build. GitHub CI also builds Storybook. Versions are owned by semantic-release (`dev` publishes the `rc` channel). Do not hand-bump `package.json`.
|
package/dist/avatar.cjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
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
|
+
return parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("").toUpperCase();
|
|
68
|
+
}
|
|
69
|
+
function getAvatarColors(name) {
|
|
70
|
+
const normalized = name.trim().toLowerCase();
|
|
71
|
+
if (!normalized) {
|
|
72
|
+
return { ...EMPTY_COLORS };
|
|
73
|
+
}
|
|
74
|
+
const backgroundColor = AVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length];
|
|
75
|
+
return {
|
|
76
|
+
backgroundColor,
|
|
77
|
+
color: contrastingTextColor(backgroundColor)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function avatarFallbackStyle(name) {
|
|
81
|
+
return getAvatarColors(name);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
exports.avatarFallbackStyle = avatarFallbackStyle;
|
|
85
|
+
exports.getAvatarColors = getAvatarColors;
|
|
86
|
+
exports.getInitials = getInitials;
|
|
87
|
+
//# sourceMappingURL=avatar.cjs.map
|
|
88
|
+
//# 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\treturn parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\")\n\t\t.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,84 @@
|
|
|
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
|
+
return parts.slice(0, Math.max(1, max)).map((part) => part.charAt(0)).join("").toUpperCase();
|
|
66
|
+
}
|
|
67
|
+
function getAvatarColors(name) {
|
|
68
|
+
const normalized = name.trim().toLowerCase();
|
|
69
|
+
if (!normalized) {
|
|
70
|
+
return { ...EMPTY_COLORS };
|
|
71
|
+
}
|
|
72
|
+
const backgroundColor = AVATAR_PALETTE[hashString(normalized) % AVATAR_PALETTE.length];
|
|
73
|
+
return {
|
|
74
|
+
backgroundColor,
|
|
75
|
+
color: contrastingTextColor(backgroundColor)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function avatarFallbackStyle(name) {
|
|
79
|
+
return getAvatarColors(name);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export { avatarFallbackStyle, getAvatarColors, getInitials };
|
|
83
|
+
//# sourceMappingURL=avatar.js.map
|
|
84
|
+
//# 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\treturn parts\n\t\t.slice(0, Math.max(1, max))\n\t\t.map((part) => part.charAt(0))\n\t\t.join(\"\")\n\t\t.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/consent.cjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/lib/cookie-consent.ts
|
|
4
|
+
var COOKIE_CONSENT_NAME = "yenio-cookie-consent";
|
|
5
|
+
var COOKIE_CONSENT_VALUES = ["necessary", "all"];
|
|
6
|
+
var COOKIE_CONSENT_MAX_AGE = 180 * 24 * 60 * 60;
|
|
7
|
+
function isCookieConsentValue(value) {
|
|
8
|
+
return typeof value === "string" && COOKIE_CONSENT_VALUES.includes(value);
|
|
9
|
+
}
|
|
10
|
+
function cookieConsentAllowsReplay(value) {
|
|
11
|
+
return value === "all";
|
|
12
|
+
}
|
|
13
|
+
function cookieDomainFromHostname(hostname) {
|
|
14
|
+
const host = hostname.toLowerCase();
|
|
15
|
+
if (host === "localhost" || host === "127.0.0.1") return void 0;
|
|
16
|
+
if (host.endsWith(".yenio.mx") || host === "yenio.mx") return ".yenio.mx";
|
|
17
|
+
if (host.endsWith(".yenio-pld.workers.dev") || host === "yenio-pld.workers.dev") {
|
|
18
|
+
return ".yenio-pld.workers.dev";
|
|
19
|
+
}
|
|
20
|
+
return void 0;
|
|
21
|
+
}
|
|
22
|
+
function readCookieMap(cookieSource) {
|
|
23
|
+
const map = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const part of cookieSource.split(";")) {
|
|
25
|
+
const trimmed = part.trim();
|
|
26
|
+
if (!trimmed) continue;
|
|
27
|
+
const eq = trimmed.indexOf("=");
|
|
28
|
+
if (eq < 0) continue;
|
|
29
|
+
const name = trimmed.slice(0, eq).trim();
|
|
30
|
+
const raw = trimmed.slice(eq + 1).trim();
|
|
31
|
+
map.set(name, decodeURIComponent(raw));
|
|
32
|
+
}
|
|
33
|
+
return map;
|
|
34
|
+
}
|
|
35
|
+
function parseCookieConsent(cookieSource) {
|
|
36
|
+
const raw = readCookieMap(cookieSource).get(COOKIE_CONSENT_NAME);
|
|
37
|
+
return isCookieConsentValue(raw) ? raw : null;
|
|
38
|
+
}
|
|
39
|
+
function readCookieConsent() {
|
|
40
|
+
if (typeof document === "undefined") return null;
|
|
41
|
+
return parseCookieConsent(document.cookie);
|
|
42
|
+
}
|
|
43
|
+
function serializeCookieConsent(value, options = {}) {
|
|
44
|
+
const maxAge = options.maxAge ?? COOKIE_CONSENT_MAX_AGE;
|
|
45
|
+
const secure = options.secure ?? (typeof window !== "undefined" && window.location.protocol === "https:");
|
|
46
|
+
const parts = [
|
|
47
|
+
`${COOKIE_CONSENT_NAME}=${encodeURIComponent(value)}`,
|
|
48
|
+
"Path=/",
|
|
49
|
+
`Max-Age=${maxAge}`,
|
|
50
|
+
"SameSite=Lax"
|
|
51
|
+
];
|
|
52
|
+
if (options.domain) {
|
|
53
|
+
parts.push(`Domain=${options.domain}`);
|
|
54
|
+
}
|
|
55
|
+
if (secure) {
|
|
56
|
+
parts.push("Secure");
|
|
57
|
+
}
|
|
58
|
+
return parts.join("; ");
|
|
59
|
+
}
|
|
60
|
+
function writeCookieConsent(value, options = {}) {
|
|
61
|
+
if (typeof document === "undefined") return;
|
|
62
|
+
document.cookie = serializeCookieConsent(value, options);
|
|
63
|
+
}
|
|
64
|
+
function isEmbeddedWindow() {
|
|
65
|
+
if (typeof window === "undefined") return false;
|
|
66
|
+
try {
|
|
67
|
+
return window.self !== window.top;
|
|
68
|
+
} catch {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
exports.COOKIE_CONSENT_MAX_AGE = COOKIE_CONSENT_MAX_AGE;
|
|
74
|
+
exports.COOKIE_CONSENT_NAME = COOKIE_CONSENT_NAME;
|
|
75
|
+
exports.COOKIE_CONSENT_VALUES = COOKIE_CONSENT_VALUES;
|
|
76
|
+
exports.cookieConsentAllowsReplay = cookieConsentAllowsReplay;
|
|
77
|
+
exports.cookieDomainFromHostname = cookieDomainFromHostname;
|
|
78
|
+
exports.isCookieConsentValue = isCookieConsentValue;
|
|
79
|
+
exports.isEmbeddedWindow = isEmbeddedWindow;
|
|
80
|
+
exports.parseCookieConsent = parseCookieConsent;
|
|
81
|
+
exports.readCookieConsent = readCookieConsent;
|
|
82
|
+
exports.serializeCookieConsent = serializeCookieConsent;
|
|
83
|
+
exports.writeCookieConsent = writeCookieConsent;
|
|
84
|
+
//# sourceMappingURL=consent.cjs.map
|
|
85
|
+
//# sourceMappingURL=consent.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cookie-consent.ts"],"names":[],"mappings":"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","file":"consent.cjs","sourcesContent":["export const COOKIE_CONSENT_NAME = \"yenio-cookie-consent\";\n\nexport const COOKIE_CONSENT_VALUES = [\"necessary\", \"all\"] as const;\n\nexport type CookieConsentValue = (typeof COOKIE_CONSENT_VALUES)[number];\n\n/** ~180 days, matching contracts §1.2. */\nexport const COOKIE_CONSENT_MAX_AGE = 180 * 24 * 60 * 60;\n\nexport type WriteCookieConsentOptions = {\n\tdomain?: string;\n\tsecure?: boolean;\n\tmaxAge?: number;\n};\n\nexport function isCookieConsentValue(\n\tvalue: unknown,\n): value is CookieConsentValue {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(COOKIE_CONSENT_VALUES as readonly string[]).includes(value)\n\t);\n}\n\nexport function cookieConsentAllowsReplay(\n\tvalue: CookieConsentValue | null | undefined,\n): boolean {\n\treturn value === \"all\";\n}\n\nexport function cookieDomainFromHostname(hostname: string): string | undefined {\n\tconst host = hostname.toLowerCase();\n\tif (host === \"localhost\" || host === \"127.0.0.1\") return undefined;\n\tif (host.endsWith(\".yenio.mx\") || host === \"yenio.mx\") return \".yenio.mx\";\n\tif (\n\t\thost.endsWith(\".yenio-pld.workers.dev\") ||\n\t\thost === \"yenio-pld.workers.dev\"\n\t) {\n\t\treturn \".yenio-pld.workers.dev\";\n\t}\n\treturn undefined;\n}\n\nfunction readCookieMap(cookieSource: string): Map<string, string> {\n\tconst map = new Map<string, string>();\n\tfor (const part of cookieSource.split(\";\")) {\n\t\tconst trimmed = part.trim();\n\t\tif (!trimmed) continue;\n\t\tconst eq = trimmed.indexOf(\"=\");\n\t\tif (eq < 0) continue;\n\t\tconst name = trimmed.slice(0, eq).trim();\n\t\tconst raw = trimmed.slice(eq + 1).trim();\n\t\tmap.set(name, decodeURIComponent(raw));\n\t}\n\treturn map;\n}\n\nexport function parseCookieConsent(\n\tcookieSource: string,\n): CookieConsentValue | null {\n\tconst raw = readCookieMap(cookieSource).get(COOKIE_CONSENT_NAME);\n\treturn isCookieConsentValue(raw) ? raw : null;\n}\n\nexport function readCookieConsent(): CookieConsentValue | null {\n\tif (typeof document === \"undefined\") return null;\n\treturn parseCookieConsent(document.cookie);\n}\n\nexport function serializeCookieConsent(\n\tvalue: CookieConsentValue,\n\toptions: WriteCookieConsentOptions = {},\n): string {\n\tconst maxAge = options.maxAge ?? COOKIE_CONSENT_MAX_AGE;\n\tconst secure =\n\t\toptions.secure ??\n\t\t(typeof window !== \"undefined\" && window.location.protocol === \"https:\");\n\tconst parts = [\n\t\t`${COOKIE_CONSENT_NAME}=${encodeURIComponent(value)}`,\n\t\t\"Path=/\",\n\t\t`Max-Age=${maxAge}`,\n\t\t\"SameSite=Lax\",\n\t];\n\tif (options.domain) {\n\t\tparts.push(`Domain=${options.domain}`);\n\t}\n\tif (secure) {\n\t\tparts.push(\"Secure\");\n\t}\n\treturn parts.join(\"; \");\n}\n\nexport function writeCookieConsent(\n\tvalue: CookieConsentValue,\n\toptions: WriteCookieConsentOptions = {},\n): void {\n\tif (typeof document === \"undefined\") return;\n\tdocument.cookie = serializeCookieConsent(value, options);\n}\n\nexport function isEmbeddedWindow(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\ttry {\n\t\treturn window.self !== window.top;\n\t} catch {\n\t\treturn true;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare const COOKIE_CONSENT_NAME = "yenio-cookie-consent";
|
|
2
|
+
declare const COOKIE_CONSENT_VALUES: readonly ["necessary", "all"];
|
|
3
|
+
type CookieConsentValue = (typeof COOKIE_CONSENT_VALUES)[number];
|
|
4
|
+
/** ~180 days, matching contracts §1.2. */
|
|
5
|
+
declare const COOKIE_CONSENT_MAX_AGE: number;
|
|
6
|
+
type WriteCookieConsentOptions = {
|
|
7
|
+
domain?: string;
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
maxAge?: number;
|
|
10
|
+
};
|
|
11
|
+
declare function isCookieConsentValue(value: unknown): value is CookieConsentValue;
|
|
12
|
+
declare function cookieConsentAllowsReplay(value: CookieConsentValue | null | undefined): boolean;
|
|
13
|
+
declare function cookieDomainFromHostname(hostname: string): string | undefined;
|
|
14
|
+
declare function parseCookieConsent(cookieSource: string): CookieConsentValue | null;
|
|
15
|
+
declare function readCookieConsent(): CookieConsentValue | null;
|
|
16
|
+
declare function serializeCookieConsent(value: CookieConsentValue, options?: WriteCookieConsentOptions): string;
|
|
17
|
+
declare function writeCookieConsent(value: CookieConsentValue, options?: WriteCookieConsentOptions): void;
|
|
18
|
+
declare function isEmbeddedWindow(): boolean;
|
|
19
|
+
|
|
20
|
+
export { COOKIE_CONSENT_MAX_AGE, COOKIE_CONSENT_NAME, COOKIE_CONSENT_VALUES, type CookieConsentValue, type WriteCookieConsentOptions, cookieConsentAllowsReplay, cookieDomainFromHostname, isCookieConsentValue, isEmbeddedWindow, parseCookieConsent, readCookieConsent, serializeCookieConsent, writeCookieConsent };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare const COOKIE_CONSENT_NAME = "yenio-cookie-consent";
|
|
2
|
+
declare const COOKIE_CONSENT_VALUES: readonly ["necessary", "all"];
|
|
3
|
+
type CookieConsentValue = (typeof COOKIE_CONSENT_VALUES)[number];
|
|
4
|
+
/** ~180 days, matching contracts §1.2. */
|
|
5
|
+
declare const COOKIE_CONSENT_MAX_AGE: number;
|
|
6
|
+
type WriteCookieConsentOptions = {
|
|
7
|
+
domain?: string;
|
|
8
|
+
secure?: boolean;
|
|
9
|
+
maxAge?: number;
|
|
10
|
+
};
|
|
11
|
+
declare function isCookieConsentValue(value: unknown): value is CookieConsentValue;
|
|
12
|
+
declare function cookieConsentAllowsReplay(value: CookieConsentValue | null | undefined): boolean;
|
|
13
|
+
declare function cookieDomainFromHostname(hostname: string): string | undefined;
|
|
14
|
+
declare function parseCookieConsent(cookieSource: string): CookieConsentValue | null;
|
|
15
|
+
declare function readCookieConsent(): CookieConsentValue | null;
|
|
16
|
+
declare function serializeCookieConsent(value: CookieConsentValue, options?: WriteCookieConsentOptions): string;
|
|
17
|
+
declare function writeCookieConsent(value: CookieConsentValue, options?: WriteCookieConsentOptions): void;
|
|
18
|
+
declare function isEmbeddedWindow(): boolean;
|
|
19
|
+
|
|
20
|
+
export { COOKIE_CONSENT_MAX_AGE, COOKIE_CONSENT_NAME, COOKIE_CONSENT_VALUES, type CookieConsentValue, type WriteCookieConsentOptions, cookieConsentAllowsReplay, cookieDomainFromHostname, isCookieConsentValue, isEmbeddedWindow, parseCookieConsent, readCookieConsent, serializeCookieConsent, writeCookieConsent };
|
package/dist/consent.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// src/lib/cookie-consent.ts
|
|
2
|
+
var COOKIE_CONSENT_NAME = "yenio-cookie-consent";
|
|
3
|
+
var COOKIE_CONSENT_VALUES = ["necessary", "all"];
|
|
4
|
+
var COOKIE_CONSENT_MAX_AGE = 180 * 24 * 60 * 60;
|
|
5
|
+
function isCookieConsentValue(value) {
|
|
6
|
+
return typeof value === "string" && COOKIE_CONSENT_VALUES.includes(value);
|
|
7
|
+
}
|
|
8
|
+
function cookieConsentAllowsReplay(value) {
|
|
9
|
+
return value === "all";
|
|
10
|
+
}
|
|
11
|
+
function cookieDomainFromHostname(hostname) {
|
|
12
|
+
const host = hostname.toLowerCase();
|
|
13
|
+
if (host === "localhost" || host === "127.0.0.1") return void 0;
|
|
14
|
+
if (host.endsWith(".yenio.mx") || host === "yenio.mx") return ".yenio.mx";
|
|
15
|
+
if (host.endsWith(".yenio-pld.workers.dev") || host === "yenio-pld.workers.dev") {
|
|
16
|
+
return ".yenio-pld.workers.dev";
|
|
17
|
+
}
|
|
18
|
+
return void 0;
|
|
19
|
+
}
|
|
20
|
+
function readCookieMap(cookieSource) {
|
|
21
|
+
const map = /* @__PURE__ */ new Map();
|
|
22
|
+
for (const part of cookieSource.split(";")) {
|
|
23
|
+
const trimmed = part.trim();
|
|
24
|
+
if (!trimmed) continue;
|
|
25
|
+
const eq = trimmed.indexOf("=");
|
|
26
|
+
if (eq < 0) continue;
|
|
27
|
+
const name = trimmed.slice(0, eq).trim();
|
|
28
|
+
const raw = trimmed.slice(eq + 1).trim();
|
|
29
|
+
map.set(name, decodeURIComponent(raw));
|
|
30
|
+
}
|
|
31
|
+
return map;
|
|
32
|
+
}
|
|
33
|
+
function parseCookieConsent(cookieSource) {
|
|
34
|
+
const raw = readCookieMap(cookieSource).get(COOKIE_CONSENT_NAME);
|
|
35
|
+
return isCookieConsentValue(raw) ? raw : null;
|
|
36
|
+
}
|
|
37
|
+
function readCookieConsent() {
|
|
38
|
+
if (typeof document === "undefined") return null;
|
|
39
|
+
return parseCookieConsent(document.cookie);
|
|
40
|
+
}
|
|
41
|
+
function serializeCookieConsent(value, options = {}) {
|
|
42
|
+
const maxAge = options.maxAge ?? COOKIE_CONSENT_MAX_AGE;
|
|
43
|
+
const secure = options.secure ?? (typeof window !== "undefined" && window.location.protocol === "https:");
|
|
44
|
+
const parts = [
|
|
45
|
+
`${COOKIE_CONSENT_NAME}=${encodeURIComponent(value)}`,
|
|
46
|
+
"Path=/",
|
|
47
|
+
`Max-Age=${maxAge}`,
|
|
48
|
+
"SameSite=Lax"
|
|
49
|
+
];
|
|
50
|
+
if (options.domain) {
|
|
51
|
+
parts.push(`Domain=${options.domain}`);
|
|
52
|
+
}
|
|
53
|
+
if (secure) {
|
|
54
|
+
parts.push("Secure");
|
|
55
|
+
}
|
|
56
|
+
return parts.join("; ");
|
|
57
|
+
}
|
|
58
|
+
function writeCookieConsent(value, options = {}) {
|
|
59
|
+
if (typeof document === "undefined") return;
|
|
60
|
+
document.cookie = serializeCookieConsent(value, options);
|
|
61
|
+
}
|
|
62
|
+
function isEmbeddedWindow() {
|
|
63
|
+
if (typeof window === "undefined") return false;
|
|
64
|
+
try {
|
|
65
|
+
return window.self !== window.top;
|
|
66
|
+
} catch {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { COOKIE_CONSENT_MAX_AGE, COOKIE_CONSENT_NAME, COOKIE_CONSENT_VALUES, cookieConsentAllowsReplay, cookieDomainFromHostname, isCookieConsentValue, isEmbeddedWindow, parseCookieConsent, readCookieConsent, serializeCookieConsent, writeCookieConsent };
|
|
72
|
+
//# sourceMappingURL=consent.js.map
|
|
73
|
+
//# sourceMappingURL=consent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/cookie-consent.ts"],"names":[],"mappings":"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","file":"consent.js","sourcesContent":["export const COOKIE_CONSENT_NAME = \"yenio-cookie-consent\";\n\nexport const COOKIE_CONSENT_VALUES = [\"necessary\", \"all\"] as const;\n\nexport type CookieConsentValue = (typeof COOKIE_CONSENT_VALUES)[number];\n\n/** ~180 days, matching contracts §1.2. */\nexport const COOKIE_CONSENT_MAX_AGE = 180 * 24 * 60 * 60;\n\nexport type WriteCookieConsentOptions = {\n\tdomain?: string;\n\tsecure?: boolean;\n\tmaxAge?: number;\n};\n\nexport function isCookieConsentValue(\n\tvalue: unknown,\n): value is CookieConsentValue {\n\treturn (\n\t\ttypeof value === \"string\" &&\n\t\t(COOKIE_CONSENT_VALUES as readonly string[]).includes(value)\n\t);\n}\n\nexport function cookieConsentAllowsReplay(\n\tvalue: CookieConsentValue | null | undefined,\n): boolean {\n\treturn value === \"all\";\n}\n\nexport function cookieDomainFromHostname(hostname: string): string | undefined {\n\tconst host = hostname.toLowerCase();\n\tif (host === \"localhost\" || host === \"127.0.0.1\") return undefined;\n\tif (host.endsWith(\".yenio.mx\") || host === \"yenio.mx\") return \".yenio.mx\";\n\tif (\n\t\thost.endsWith(\".yenio-pld.workers.dev\") ||\n\t\thost === \"yenio-pld.workers.dev\"\n\t) {\n\t\treturn \".yenio-pld.workers.dev\";\n\t}\n\treturn undefined;\n}\n\nfunction readCookieMap(cookieSource: string): Map<string, string> {\n\tconst map = new Map<string, string>();\n\tfor (const part of cookieSource.split(\";\")) {\n\t\tconst trimmed = part.trim();\n\t\tif (!trimmed) continue;\n\t\tconst eq = trimmed.indexOf(\"=\");\n\t\tif (eq < 0) continue;\n\t\tconst name = trimmed.slice(0, eq).trim();\n\t\tconst raw = trimmed.slice(eq + 1).trim();\n\t\tmap.set(name, decodeURIComponent(raw));\n\t}\n\treturn map;\n}\n\nexport function parseCookieConsent(\n\tcookieSource: string,\n): CookieConsentValue | null {\n\tconst raw = readCookieMap(cookieSource).get(COOKIE_CONSENT_NAME);\n\treturn isCookieConsentValue(raw) ? raw : null;\n}\n\nexport function readCookieConsent(): CookieConsentValue | null {\n\tif (typeof document === \"undefined\") return null;\n\treturn parseCookieConsent(document.cookie);\n}\n\nexport function serializeCookieConsent(\n\tvalue: CookieConsentValue,\n\toptions: WriteCookieConsentOptions = {},\n): string {\n\tconst maxAge = options.maxAge ?? COOKIE_CONSENT_MAX_AGE;\n\tconst secure =\n\t\toptions.secure ??\n\t\t(typeof window !== \"undefined\" && window.location.protocol === \"https:\");\n\tconst parts = [\n\t\t`${COOKIE_CONSENT_NAME}=${encodeURIComponent(value)}`,\n\t\t\"Path=/\",\n\t\t`Max-Age=${maxAge}`,\n\t\t\"SameSite=Lax\",\n\t];\n\tif (options.domain) {\n\t\tparts.push(`Domain=${options.domain}`);\n\t}\n\tif (secure) {\n\t\tparts.push(\"Secure\");\n\t}\n\treturn parts.join(\"; \");\n}\n\nexport function writeCookieConsent(\n\tvalue: CookieConsentValue,\n\toptions: WriteCookieConsentOptions = {},\n): void {\n\tif (typeof document === \"undefined\") return;\n\tdocument.cookie = serializeCookieConsent(value, options);\n}\n\nexport function isEmbeddedWindow(): boolean {\n\tif (typeof window === \"undefined\") return false;\n\ttry {\n\t\treturn window.self !== window.top;\n\t} catch {\n\t\treturn true;\n\t}\n}\n"]}
|