{"_id":"@aarongustafson/content-warning","_rev":"3-d46896079d1956533aa65b39dd496b6d","name":"@aarongustafson/content-warning","dist-tags":{"latest":"1.1.0"},"versions":{"0.0.1":{"name":"@aarongustafson/content-warning","version":"0.0.1","keywords":["html","custom element","web component"],"author":{"url":"https://www.aaron-gustafson.com/","name":"Aaron Gustafson","email":"aaron@easy-designs.net"},"license":"MIT","_id":"@aarongustafson/content-warning@0.0.1","maintainers":[{"name":"aarongustafson","email":"aaron@easy-designs.net"}],"homepage":"https://github.com/aarongustafson/content-warning#readme","bugs":{"url":"https://github.com/aarongustafson/content-warning/issues"},"dist":{"shasum":"d81ff77f41d2248a55c46bf9fed445957283c534","tarball":"https://registry.npmjs.org/@aarongustafson/content-warning/-/content-warning-0.0.1.tgz","fileCount":8,"integrity":"sha512-Cz5Yh6BWt/DR6NzRoqJp5Pwbp4PIZyXiacGBBuRZZaVaJX03KQaflnQ8wbuiQMUNajqiG70kNtnRSxt+o9gxbA==","signatures":[{"sig":"MEUCIFBT6dvQAAImFPPQ43kgBuKG7RgX2sbTCm10vV6BfK0dAiEAswrQFh/Bf39bAK6Lfd1YtIwaJiYxgpWIP0xjXvBqvuQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":27660},"main":"index.js","type":"module","module":"content-warning.js","engines":{"node":">=14.0.0"},"exports":{".":{"import":"./index.js"},"./define.js":{"import":"./define.js"},"./content-warning.js":{"types":"./content-warning.d.ts","import":"./content-warning.js"},"./custom-elements.json":"./custom-elements.json"},"gitHead":"a1e1995c410a92772e0bb8c139c6b2767f9011b6","scripts":{"lint":"npm run lint:eslint && npm run lint:prettier","test":"vitest","setup":"node scripts/setup.js","format":"npm run format:eslint && npm run format:prettier","test:ui":"vitest --ui","version":"node scripts/update-demo-versions.js && git add demo/esm.html","test:run":"vitest run","lint:eslint":"eslint .","format:eslint":"eslint . --fix","lint:prettier":"prettier \"**/*.js\" --check --ignore-path .gitignore","test:coverage":"vitest run --coverage","format:prettier":"prettier \"**/*.js\" --write --ignore-path .gitignore"},"_npmUser":{"name":"aarongustafson","email":"aaron@easy-designs.net"},"repository":{"url":"git+https://github.com/aarongustafson/content-warning.git","type":"git"},"_npmVersion":"11.6.2","description":"A web component for block and inline content warnings.","directories":{},"_nodeVersion":"24.11.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"customElements":"custom-elements.json","devDependencies":{"eslint":"^9.39.1","vitest":"^4.0.10","prettier":"^3.6.2","happy-dom":"^20.0.10","@vitest/ui":"^4.0.10","@vitest/coverage-v8":"^4.0.10","@testing-library/dom":"^10.4.1","@open-wc/eslint-config":"^13.0.0","eslint-config-prettier":"^10.1.8","@testing-library/user-event":"^14.6.1"},"_npmOperationalInternal":{"tmp":"tmp/content-warning_0.0.1_1766512333944_0.588931778562328","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@aarongustafson/content-warning","version":"1.0.0","keywords":["html","custom element","web component"],"author":{"url":"https://www.aaron-gustafson.com/","name":"Aaron Gustafson","email":"aaron@easy-designs.net"},"license":"MIT","_id":"@aarongustafson/content-warning@1.0.0","maintainers":[{"name":"aarongustafson","email":"aaron@easy-designs.net"}],"homepage":"https://github.com/aarongustafson/content-warning#readme","bugs":{"url":"https://github.com/aarongustafson/content-warning/issues"},"dist":{"shasum":"dc7cab437d48db331be465816ff78ac0329c9144","tarball":"https://registry.npmjs.org/@aarongustafson/content-warning/-/content-warning-1.0.0.tgz","fileCount":8,"integrity":"sha512-98sr1x0xHSCHGDzHV01i88m7tX/q9jSTmvwns7qautS8GtEpc/H/8tXuG8qbGSq7xQ6UF75b6vzl0+faxRR2lA==","signatures":[{"sig":"MEUCIFL/MjPZioAvWZcDBzDEImPOF1Cmb8frEXEAEsZw5XIiAiEAnF9CZPkJ5E7N5LHleyvw6hmYfS+bFXTk8HY8hnbV81Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aarongustafson%2fcontent-warning@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":27703},"main":"index.js","type":"module","module":"content-warning.js","engines":{"node":">=14.0.0"},"exports":{".":{"import":"./index.js"},"./define.js":{"import":"./define.js"},"./content-warning.js":{"types":"./content-warning.d.ts","import":"./content-warning.js"},"./custom-elements.json":"./custom-elements.json"},"gitHead":"4b303065b8f41ac0ba9dcfdb1167e3fe178ed871","scripts":{"lint":"npm run lint:eslint && npm run lint:prettier","test":"vitest","setup":"node scripts/setup.js","format":"npm run format:eslint && npm run format:prettier","test:ui":"vitest --ui","version":"node scripts/update-demo-versions.js && git add demo/esm.html","test:run":"vitest run","lint:eslint":"eslint .","postversion":"git push --follow-tags","format:eslint":"eslint . --fix","lint:prettier":"prettier \"**/*.js\" --check --ignore-path .gitignore","test:coverage":"vitest run --coverage","format:prettier":"prettier \"**/*.js\" --write --ignore-path .gitignore"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b32380f8-40b6-4e3c-a104-5cfd9bc1ae8f"}},"repository":{"url":"git+https://github.com/aarongustafson/content-warning.git","type":"git"},"_npmVersion":"11.7.0","description":"A web component for block and inline content warnings.","directories":{},"_nodeVersion":"20.19.6","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"customElements":"custom-elements.json","devDependencies":{"eslint":"^9.39.1","vitest":"^4.0.10","prettier":"^3.6.2","happy-dom":"^20.0.10","@vitest/ui":"^4.0.10","@vitest/coverage-v8":"^4.0.10","@testing-library/dom":"^10.4.1","@open-wc/eslint-config":"^13.0.0","eslint-config-prettier":"^10.1.8","@testing-library/user-event":"^14.6.1"},"_npmOperationalInternal":{"tmp":"tmp/content-warning_1.0.0_1766512605756_0.20119742131633345","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@aarongustafson/content-warning","version":"1.1.0","description":"A web component for block and inline content warnings.","keywords":["html","custom element","web component"],"author":{"name":"Aaron Gustafson","email":"aaron@easy-designs.net","url":"https://www.aaron-gustafson.com/"},"license":"MIT","homepage":"https://github.com/aarongustafson/content-warning#readme","repository":{"type":"git","url":"git+https://github.com/aarongustafson/content-warning.git"},"bugs":{"url":"https://github.com/aarongustafson/content-warning/issues"},"type":"module","main":"index.js","module":"content-warning.js","customElements":"custom-elements.json","exports":{".":{"import":"./index.js"},"./content-warning.js":{"types":"./content-warning.d.ts","import":"./content-warning.js"},"./define.js":{"import":"./define.js"},"./custom-elements.json":"./custom-elements.json"},"engines":{"node":">=14.0.0"},"scripts":{"setup":"node scripts/setup.js","test":"vitest","test:ui":"vitest --ui","test:run":"vitest run","test:coverage":"vitest run --coverage","lint":"npm run lint:eslint && npm run lint:prettier","format":"npm run format:eslint && npm run format:prettier","lint:eslint":"eslint .","format:eslint":"eslint . --fix","lint:prettier":"prettier \"**/*.js\" --check --ignore-path .gitignore","format:prettier":"prettier \"**/*.js\" --write --ignore-path .gitignore","version":"node scripts/update-demo-versions.js && git add demo/esm.html","postversion":"git push --follow-tags"},"devDependencies":{"@open-wc/eslint-config":"^13.0.0","@testing-library/dom":"^10.4.1","@testing-library/user-event":"^14.6.1","@vitest/coverage-v8":"^4.0.10","@vitest/ui":"^4.0.10","eslint":"^9.39.1","eslint-config-prettier":"^10.1.8","happy-dom":"^20.0.10","prettier":"^3.6.2","vitest":"^4.0.10"},"publishConfig":{"access":"public"},"gitHead":"61ab1414d181aa94091752920eef7656bdb3f63c","_id":"@aarongustafson/content-warning@1.1.0","_nodeVersion":"20.19.6","_npmVersion":"11.7.0","dist":{"integrity":"sha512-jDRU3nqOraIF7thtwj4FmAIpiljMGDhKLjjDz8igXlJHOEdmakuT5l3o4oAS9Mx6wCEOOWr1yw5DbxjtguNFEA==","shasum":"c5b1e68f9f62b640989656fa3e41238cf229e2ea","tarball":"https://registry.npmjs.org/@aarongustafson/content-warning/-/content-warning-1.1.0.tgz","fileCount":8,"unpackedSize":34649,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aarongustafson%2fcontent-warning@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBDk2au9Gr5gjQp6fSUenSO6hy9qwJOQtEs+3XJFx3HxAiEAr7HywpRrlbXpe662uBNWN6g8qykpk7ClLSvWo2sPSQQ="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b32380f8-40b6-4e3c-a104-5cfd9bc1ae8f"}},"directories":{},"maintainers":[{"name":"aarongustafson","email":"aaron@easy-designs.net"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/content-warning_1.1.0_1767311447518_0.3846686924476814"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-23T17:52:13.844Z","modified":"2026-01-01T23:50:48.099Z","0.0.1":"2025-12-23T17:52:14.101Z","1.0.0":"2025-12-23T17:56:45.893Z","1.1.0":"2026-01-01T23:50:47.665Z"},"bugs":{"url":"https://github.com/aarongustafson/content-warning/issues"},"author":{"name":"Aaron Gustafson","email":"aaron@easy-designs.net","url":"https://www.aaron-gustafson.com/"},"license":"MIT","homepage":"https://github.com/aarongustafson/content-warning#readme","keywords":["html","custom element","web component"],"repository":{"type":"git","url":"git+https://github.com/aarongustafson/content-warning.git"},"description":"A web component for block and inline content warnings.","maintainers":[{"name":"aarongustafson","email":"aaron@easy-designs.net"}],"readme":"# content-warning Web Component\n\n[![npm version](https://img.shields.io/npm/v/@aarongustafson/content-warning.svg)](https://www.npmjs.com/package/@aarongustafson/content-warning) [![Build Status](https://img.shields.io/github/actions/workflow/status/aarongustafson/content-warning/ci.yml?branch=main)](https://github.com/aarongustafson/content-warning/actions)\n\nA web component for block and inline content warnings.\n\nBased on the [original concept](https://codepen.io/aarongustafson/pen/QWZpqPe) by Aaron Gustafson.\n\n## Demo\n\n[Live Demo](https://aarongustafson.github.io/content-warning/demo/) ([Source](./demo/index.html))\n\nAdditional demos:\n\n- [ESM CDN Demo](https://aarongustafson.github.io/content-warning/demo/esm.html) ([Source](./demo/esm.html))\n- [Unpkg CDN Demo](https://aarongustafson.github.io/content-warning/demo/unpkg.html) ([Source](./demo/unpkg.html))\n\n## Installation\n\n```bash\nnpm install @aarongustafson/content-warning\n```\n\n## Usage\n\n### Option 1: Auto-define the custom element (easiest)\n\nImport the package to automatically define the `<content-warning>` custom element:\n\n```javascript\nimport '@aarongustafson/content-warning';\n```\n\nOr use the define-only script in HTML:\n\n```html\n<script\n  src=\"./node_modules/@aarongustafson/content-warning/define.js\"\n  type=\"module\"\n></script>\n```\n\n### Option 2: Import the class and define manually\n\nImport the class and define the custom element with your preferred tag name:\n\n```javascript\nimport { ContentWarningElement } from '@aarongustafson/content-warning/content-warning.js';\n\ncustomElements.define('my-custom-name', ContentWarningElement);\n```\n\n### Basic Example\n\n```html\n<!-- Block content warning -->\n<content-warning type=\"violence spoilers\">\n  <p>This content contains violence and spoilers for the series finale.</p>\n</content-warning>\n\n<!-- Inline content warning -->\n<p>\n  The character dies in\n  <content-warning type=\"spoilers\" inline>episode 5</content-warning>.\n</p>\n```\n\n## Reader Mode Safety\n\n**Important:** Reader Mode parsers (Edge Immersive Reader, Safari Reader, etc.) extract content **before JavaScript runs**. To prevent Reader Mode from extracting content inside `<content-warning>` elements, add the `hidden` attribute:\n\n```html\n<content-warning type=\"violence\" hidden>\n  <p>This content will be hidden from Reader Mode.</p>\n</content-warning>\n```\n\n**How it works:**\n1. **Before JS runs**: The `hidden` attribute hides the element → Reader Mode skips it entirely\n2. **When component initializes**: The component automatically removes the `hidden` attribute\n3. **After initialization**: The component's Shadow DOM hiding logic takes over\n\n**Without the `hidden` attribute**, Reader Mode will extract and display the content even though it appears hidden in the normal page view.\n\n**Note:** The `hidden` attribute is automatically removed when the component boots, so you don't need to manage it yourself.\n\n## Content Hiding Modes\n\nThe component offers two modes for hiding content, each with different trade-offs:\n\n### Default Mode (Recommended)\n\n**Reader Mode Safe** - Content is truly hidden from Reader Mode and screen readers until revealed.\n\n```html\n<content-warning type=\"sensitive content\">\n  <p>This content is completely hidden until revealed.</p>\n</content-warning>\n```\n\n- Uses `hidden` and `inert` attributes on the content wrapper\n- Content is **not** extracted by Reader Mode (Edge, Safari, etc.)\n- Content is hidden from screen readers via native attributes\n- Best for sensitive content that should be truly hidden\n\n### Blur Mode\n\n**Visual Only** - Content is visually obscured but still present in the DOM.\n\n```html\n<content-warning type=\"spoilers\" blur>\n  <p>This content is blurred but technically visible in the DOM.</p>\n</content-warning>\n```\n\n- Uses CSS `filter: blur()` to obscure content visually\n- Uses `aria-hidden=\"true\"` to hide from screen readers\n- Content **may be** extracted by Reader Mode (not guaranteed to be hidden)\n- Customizable blur amount via `--content-warning-blur-amount` CSS property\n- Best for aesthetic preference when complete hiding isn't critical\n\n**Trade-off Summary:**\n\n- **Without `blur`**: Maximum safety and hiding (recommended for sensitive content)\n- **With `blur`**: Visual obscuring effect (not fully hidden from all contexts)\n\n## Attributes\n\n| Attribute      | Type      | Default             | Description                                                            |\n| -------------- | --------- | ------------------- | ---------------------------------------------------------------------- |\n| `type`         | `string`  | `\"content\"`         | Space-separated list of warning types (e.g., \"violence spoilers nsfw\") |\n| `label-prefix` | `string`  | `\"Content Warning\"` | The prefix text for the warning label                                  |\n| `label-suffix` | `string`  | `\"Click to reveal\"` | The suffix text for the warning label. Set to `\"false\"` to hide.       |\n| `inline`       | `boolean` | `false`             | Display the warning inline instead of as a block overlay               |\n| `blur`         | `boolean` | `false`             | Use blur visual effect instead of complete hiding (NOT Reader Mode safe) |\n\n**Default Button Label Format:** `{prefix}: {type} {suffix}`\n\nExample: \"Content Warning: violence spoilers Click to reveal\"\n\n**Note:** Punctuation and spacing between label parts are controlled via CSS pseudo-elements (`:after` and `:before`), making them easy to customize without affecting the underlying text content.\n\n## Events\n\nThe component fires custom events that you can listen to:\n\n| Event                      | Description                                                    | Detail                                           |\n| -------------------------- | -------------------------------------------------------------- | ------------------------------------------------ |\n| `content-warning:revealed` | Fired when the user reveals the content by clicking the button | `{ type: string }` - The type of content warning |\n\n### Example Event Handling\n\n```javascript\nconst element = document.querySelector('content-warning');\n\nelement.addEventListener('content-warning:revealed', (event) => {\n  console.log('Content revealed:', event.detail.type);\n  // Track analytics, log user action, etc.\n});\n```\n\n## Properties\n\n| Property      | Type                  | Description                                   |\n| ------------- | --------------------- | --------------------------------------------- |\n| `type`        | `string`              | Get/set the warning type(s)                   |\n| `labelPrefix` | `string`              | Get/set the prefix text for the warning label |\n| `labelSuffix` | `string`              | Get/set the suffix text for the warning label |\n| `revealed`    | `boolean` (read-only) | Whether the content has been revealed         |\n\n## CSS Custom Properties\n\nCustomize the component's appearance with CSS variables:\n\n| Property                          | Default | Description                                   |\n| --------------------------------- | ------- | --------------------------------------------- |\n| `--content-warning-color`         | `#fff`  | Outline color for focus state                 |\n| `--content-warning-blur-amount`   | `10px`  | Amount of blur in blur mode (e.g., `5px`, `20px`) |\n\n### Example\n\n```css\ncontent-warning {\n  --content-warning-color: #ff6b6b;\n  --content-warning-blur-amount: 15px;\n}\n```\n\n## Shadow Parts\n\nYou can style internal elements using CSS Shadow Parts:\n\n| Part           | Description                                       |\n| -------------- | ------------------------------------------------- |\n| `overlay`      | The full-area overlay div that covers the content |\n| `button`       | The warning button element inside the overlay     |\n| `label-prefix` | The prefix text span (e.g., \"Content Warning\")    |\n\n### Example Styling\n\n```css\n/* Style the full-area overlay */\ncontent-warning::part(overlay) {\n  background: rgba(139, 0, 0, 0.95);\n}\n\n/* Style the button inside the overlay */\ncontent-warning::part(button) {\n  color: #fff;\n  border: 3px solid #ff6b6b;\n  padding: 2rem;\n  font-size: 1.25rem;\n  text-transform: uppercase;\n  letter-spacing: 0.1em;\n  background: rgba(0, 0, 0, 0.5);\n  border-radius: 0.5rem;\n}\n\n/* Style individual label parts */\ncontent-warning::part(label-prefix) {\n  font-weight: bold;\n}\n\ncontent-warning::part(label-type) {\n  font-style: italic;\n  color: #ff6b6b;\n}\n\ncontent-warning::part(label-suffix) {\n  font-size: 0.875em;\n  opacity: 0.9;\n}\n\n/* Style inline warnings differently */\ncontent-warning[inline]::part(overlay) {\n  background: #333;\n}\n\ncontent-warning[inline]::part(button) {\n  padding: 0.5rem 0.75rem;\n  border-radius: 0.25rem;\n}\n```\n\n## Internationalization (i18n)\n\nCustomize the button label for different languages using `label-prefix` and `label-suffix` attributes:\n\n```html\n<!-- Spanish -->\n<content-warning\n  type=\"violencia gore\"\n  label-prefix=\"Advertencia de Contenido\"\n  label-suffix=\"Haz clic para revelar\"\n>\n  <img src=\"image.jpg\" alt=\"Sensitive image\" />\n</content-warning>\n\n<!-- French -->\n<content-warning\n  type=\"contenu sensible\"\n  label-prefix=\"Avertissement\"\n  label-suffix=\"Cliquez pour révéler\"\n>\n  <p>Contenu en français...</p>\n</content-warning>\n\n<!-- No suffix -->\n<content-warning type=\"graphic content\" label-suffix=\"false\">\n  <p>Content without suffix text</p>\n</content-warning>\n```\n\nStyle each label part individually:\n\n````css\ncontent-warning::part(label-prefix) {\n  font-weight: bold;\n}\n\ncontent-warning::part(label-type) {\n  font-style: italic;\n  color: #ff6b6b;\n}\n\ncontent-warning::part(label-suffix) {\n  font-size: 0.875em;\n  opacity: 0.9;\n}\n```\n\n### Customizing Punctuation\n\nPunctuation and spacing between label parts are controlled via CSS pseudo-elements:\n\n```css\n/* Default punctuation (already applied) */\n.label-prefix::after {\n  content: \": \"; /* Colon and space after prefix */\n}\n\n[part=\"label-type\"]::before {\n  content: \" \"; /* Space before type */\n}\n\n[part=\"label-suffix\"]::before {\n  content: \" \"; /* Space before suffix */\n}\n\n/* Customize punctuation */\ncontent-warning::part(button) .label-prefix::after {\n  content: \" — \"; /* Em dash instead of colon */\n}\n\n/* Remove punctuation entirely */\ncontent-warning::part(button) .label-prefix::after {\n  content: \" \"; /* Just a space */\n}\n```adding: 0.5rem 0.75rem;\n  border-radius: 0.25rem;\n}\n````\n\n## Accessibility\n\nThe component follows accessibility best practices:\n\n- Uses a semantic `<button>` element for the warning interaction\n- Button is keyboard accessible by default\n- Content is hidden from screen readers until revealed (both modes use `aria-hidden` or `hidden` attribute)\n- **Default mode**: Uses `hidden` + `inert` attributes (Reader Mode safe)\n- **Blur mode**: Uses `aria-hidden=\"true\"` (visual obscuring only)\n- Sets `role=\"alert\"` on the host element when content is revealed\n- Clones revealed content into a persistent `role=\"alert\"` region for screen reader announcement\n- Screen readers announce the revealed content automatically\n- Focuses the revealed content for additional context\n\n## Browser Support\n\nThis component uses modern web standards:\n\n- Custom Elements v1\n- Shadow DOM v1\n- ES Modules\n\nFor older browsers, you may need polyfills.\n\n## Development\n\n```bash\n# Install dependencies\nnpm install\n\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Lint code\nnpm run lint\n\n# Format code\nnpm run format\n\n# View demo\nopen demo/index.html\n```\n\n## License\n\nMIT © [Aaron Gustafson](https://www.aaron-gustafson.com/)\n","readmeFilename":"README.md"}