{"_id":"@arc-lang/arc-cookie-bar","_rev":"2-e410bc8f7dc9d7739e9d82a81f2533b1","name":"@arc-lang/arc-cookie-bar","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@arc-lang/arc-cookie-bar","version":"0.1.0","keywords":["arc","gdpr","cookie","consent","cookie-bar","privacy","ccpa","cookie-consent"],"license":"MIT","_id":"@arc-lang/arc-cookie-bar@0.1.0","maintainers":[{"name":"kobecuppens","email":"kobecuppens@hotmail.com"}],"homepage":"https://arc-language.dev/docs/cookie-bar","bugs":{"url":"https://github.com/arc-language/arc-web/issues"},"dist":{"shasum":"390b5a9faf9b699476f82371f7fd02899eee388b","tarball":"https://registry.npmjs.org/@arc-lang/arc-cookie-bar/-/arc-cookie-bar-0.1.0.tgz","fileCount":7,"integrity":"sha512-mIxd+bieoWsaZClH6qhBpW5/9DQdTL7O1EBEKkX98hSeP5nGgxXZoPLOfV8u12IqJT3XjweJ14KjV4vuPJbFAw==","signatures":[{"sig":"MEUCIQC/MnMbkjWQBkA3Ib/4Nwq2EZplZYTIAzLPOV8zfUztaQIgMY3k1t1tD0m0y8vxztmwImbnwmDzPnsp+KXTDfWLBp0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20950},"main":"src/index.js","engines":{"node":">=18.0.0"},"gitHead":"e03743d19182dc504db15a93de5757353dac329c","_npmUser":{"name":"kobecuppens","email":"kobecuppens@hotmail.com"},"repository":{"url":"git+https://github.com/arc-language/arc-web.git","type":"git","directory":"packages/arc-cookie-bar"},"_npmVersion":"11.12.1","description":"GDPR-compliant cookie consent bar for Arc public pages. Granular categories, localStorage persistence, zero dependencies.","directories":{},"sideEffects":false,"_nodeVersion":"24.15.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"peerDependencies":{"@arc-lang/arc":">=0.2.0"},"peerDependenciesMeta":{"@arc-lang/arc":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/arc-cookie-bar_0.1.0_1780407171744_0.9764945283487387","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@arc-lang/arc-cookie-bar","version":"0.1.2","description":"GDPR-compliant cookie consent bar for Arc public pages. Granular categories, localStorage persistence, zero dependencies.","main":"src/index.js","keywords":["arc","gdpr","cookie","consent","cookie-bar","privacy","ccpa","cookie-consent"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/arc-language/arc-cookie-bar.git"},"homepage":"https://arc-language.dev/docs/cookie-bar","bugs":{"url":"https://github.com/arc-language/arc-cookie-bar/issues"},"engines":{"node":">=18.0.0"},"peerDependencies":{"@arc-lang/arc":">=0.2.0"},"peerDependenciesMeta":{"@arc-lang/arc":{"optional":true}},"sideEffects":false,"publishConfig":{"access":"public"},"gitHead":"1264a98fa6397d891a61ad55a7f32bdb31421f1d","_id":"@arc-lang/arc-cookie-bar@0.1.2","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-CaEkXxDpGx2u6HoMf1wnmSRhSEfAiQoy8/sqLbyQK+B5NZDaY3sWOFE1o2ghbe9r5L+WV3fQXnQ0oT28QVCI/w==","shasum":"fa64056b3333d4f9fd7a478cc8cb1e92dcee1734","tarball":"https://registry.npmjs.org/@arc-lang/arc-cookie-bar/-/arc-cookie-bar-0.1.2.tgz","fileCount":7,"unpackedSize":21585,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCIcgZetJ60fs+xxzIxxg4nyAMouT94b483I3pnFwbCQgIgUGcfRiJGNEHdZmaOrgA+UpqphsZFlrcAArGZqgv/2VY="}]},"_npmUser":{"name":"kobecuppens","email":"kobecuppens@hotmail.com"},"directories":{},"maintainers":[{"name":"kobecuppens","email":"kobecuppens@hotmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/arc-cookie-bar_0.1.2_1780410142204_0.343584419660127"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-02T13:32:51.542Z","modified":"2026-06-02T14:22:22.491Z","0.1.0":"2026-06-02T13:32:51.874Z","0.1.2":"2026-06-02T14:22:22.357Z"},"bugs":{"url":"https://github.com/arc-language/arc-cookie-bar/issues"},"license":"MIT","homepage":"https://arc-language.dev/docs/cookie-bar","keywords":["arc","gdpr","cookie","consent","cookie-bar","privacy","ccpa","cookie-consent"],"repository":{"type":"git","url":"git+https://github.com/arc-language/arc-cookie-bar.git"},"description":"GDPR-compliant cookie consent bar for Arc public pages. Granular categories, localStorage persistence, zero dependencies.","maintainers":[{"name":"kobecuppens","email":"kobecuppens@hotmail.com"}],"readme":"# arc-cookie-bar\n\nGDPR/CCPA-compliant cookie consent bar for Arc public pages. Three consent flows, granular per-category toggles, localStorage persistence, and an optional server-side audit log — zero dependencies, ~3.5KB inline (CSS + JS + HTML).\n\n## Features\n\n- **Three consent flows** — Accept All, Reject All, or per-category customization\n- **localStorage persistence** — survives reloads; configurable expiry (default 365 days)\n- **`arcCookieConsent` event** — fires on every page load with stored or fresh prefs\n- **`window.arcCookieBar` API** — `open()`, `getConsent()`, `reset()` for programmatic control\n- **Three positions** — `bottom` (default), `top`, `modal`\n- **Server audit log** — opt-in `POST /arc-cookie-bar/api/consent` with IP anonymization\n- **Arc theme** — inherits `--ui-*` CSS variables automatically\n- **GPU-composited animations** — `will-change: transform, opacity` on the banner\n- **Accessible** — `role=\"dialog\"`, `aria-modal`, `aria-expanded`, keyboard nav, Escape to dismiss\n- **GDPR-safe server logging** — IPv4 last octet zeroed, IPv6 truncated to 64 bits\n- **Zero dependencies** — no npm installs, no build step\n\n## Install\n\n```bash\nnpm install @arc-lang/arc-cookie-bar\n```\n\nAdd to `arc.config.json`:\n\n```json\n{\n  \"packages\": [\"@arc-lang/arc-cookie-bar\"]\n}\n```\n\n## Quick start\n\n```arc\nimport CookieBar from \"@arc-cookie-bar/widgets/CookieBar.arc\"\n\npage \"Home\"\n  CookieBar(policyUrl=\"/privacy\")\n  main\n    h1 \"Welcome\"\n```\n\nThe bar appears on first visit, stores consent for 365 days, and fires `arcCookieConsent` on every subsequent load so your scripts can conditionally initialise trackers.\n\n## Widget props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `position` | String | `\"bottom\"` | `\"bottom\"` \\| `\"top\"` \\| `\"modal\"` |\n| `categories` | String | `\"necessary,analytics,marketing\"` | Comma-separated consent categories |\n| `policyUrl` | String | `\"/privacy\"` | Link to your cookie/privacy policy |\n| `expires` | Int | `365` | Days before consent expires and bar re-appears |\n| `title` | String | `\"We use cookies\"` | Banner headline |\n| `description` | String | `\"…\"` | Banner body text |\n| `serverPersist` | Bool | `false` | POST each decision to `/arc-cookie-bar/api/consent` |\n\n## Reacting to consent\n\n`arcCookieConsent` fires on every page load — immediately with stored prefs if consent already exists, or after the user acts on the banner. Wire it before any tracker initialisation:\n\n```html\n<script>\nwindow.addEventListener('arcCookieConsent', function(e) {\n  if (e.detail.analytics) initGA4()\n  if (e.detail.marketing) initMetaPixel()\n})\n</script>\n```\n\n`e.detail` is a flat object of booleans, one per category:\n\n```json\n{ \"necessary\": true, \"analytics\": true, \"marketing\": false, \"_e\": 1748736000000 }\n```\n\n(`_e` is the expiry timestamp — ignore it in your handler.)\n\n## `window.arcCookieBar` API\n\n```javascript\nwindow.arcCookieBar.open()         // re-open the bar (e.g. from a footer \"Cookie settings\" link)\nwindow.arcCookieBar.getConsent()   // returns stored consent object, or null if not yet set / expired\nwindow.arcCookieBar.reset()        // clear localStorage and re-show the bar (useful for testing)\n```\n\nWire a footer link:\n\n```arc\nbutton onclick=\"window.arcCookieBar.open()\" \"Cookie settings\"\n```\n\n## Custom categories\n\nYou can define any categories:\n\n```arc\nCookieBar(\n  categories=\"necessary,analytics,marketing,preferences,social\"\n  policyUrl=\"/cookies\"\n)\n```\n\n`necessary` is always locked on. Built-in descriptions exist for `necessary`, `analytics`, `marketing`, and `preferences`. Any other name renders without a description.\n\n## Server-side consent logging\n\nFor GDPR audit trails, enable server persistence:\n\n```arc\nCookieBar(serverPersist=true policyUrl=\"/privacy\")\n```\n\nEach consent decision POSTs to `POST /arc-cookie-bar/api/consent`. The table is created lazily on first request — no migration needed.\n\n**Schema:**\n\n| Column | Type | Description |\n|--------|------|-------------|\n| `id` | INTEGER | Auto-increment PK |\n| `necessary` | INTEGER | Always `1` |\n| `analytics` | INTEGER | `1` if accepted |\n| `marketing` | INTEGER | `1` if accepted |\n| `preferences` | INTEGER | `1` if accepted |\n| `ip` | TEXT | Anonymized IP — IPv4 last octet zeroed (`1.2.3.0`), IPv6 truncated to 64 bits (`2001:db8:1:2::`) |\n| `ua` | TEXT | User-agent string, max 512 chars |\n| `created_at` | TEXT | UTC timestamp |\n\n**Security:** The consent endpoint accepts anonymous POSTs. It records consent decisions only — no personal data beyond the anonymized IP. If you want to reject requests from outside your domain, add a CSRF check or restrict with an Arc middleware.\n\n## Positions\n\n```arc\nCookieBar(position=\"bottom\")   // fixed to bottom (default) — slides up on show\nCookieBar(position=\"top\")      // fixed to top — slides down on show\nCookieBar(position=\"modal\")    // centered overlay with semi-transparent backdrop\n```\n\n## Theming\n\nThe bar inherits your Arc theme's CSS variables:\n\n| Variable | Used for |\n|----------|---------|\n| `--ui-bg` | Banner background |\n| `--ui-bg-2` | \"Reject all\" button background |\n| `--ui-text` | Primary text |\n| `--ui-muted` | Secondary text and category descriptions |\n| `--ui-border` | Border, divider, and toggle track |\n| `--ui-accent` | \"Accept all\" button, links, active toggle |\n| `--ui-radius` | Border radius for bar and buttons |\n| `--arc-font-sans` | Font family |\n\nOverride specific elements by targeting `.arc-cb` in your own stylesheet:\n\n```css\n.arc-cb { --ui-accent: #6366f1; }         /* custom accent */\n.arc-cb__btn--accept { font-weight: 700; } /* bolder accept button */\n```\n\n## Performance\n\n| Metric | Value |\n|--------|-------|\n| Client payload (CSS + JS + HTML) | ~3.5 KB inline |\n| Consent check on repeat visit | ~0.1 ms (single `localStorage.getItem` + `JSON.parse`) |\n| First-paint impact | None — bar starts hidden, shown after paint |\n| DOM nodes (banner) | 14 |\n| DOM nodes (customize panel, when open) | +4 per category |\n| Server INSERT | O(log n) SQLite B-tree — < 0.1 ms |\n\n## GDPR compliance notes\n\n- `necessary` is always `true` and its toggle is disabled — no legal basis needed\n- All other categories default to `false` — opt-in by default\n- Consent is re-prompted after `expires` days\n- Server-side IP is anonymized before storage — IPv4 last octet zeroed, IPv6 truncated to first 64 bits\n- Consent records are write-only from the browser — no read endpoint is provided\n\n## Browser support\n\nAll evergreen browsers (Chrome 80+, Firefox 75+, Safari 14+, Edge 80+). No IE11 support — uses `CustomEvent`, `fetch`, `localStorage`, `requestAnimationFrame`, and optional chaining via `?.` in Arc-compiled server code only.\n\n## License\n\nMIT — see [LICENSE](./LICENSE)\n","readmeFilename":"README.md"}