{"_id":"@2londres/shareable-preview","_rev":"3-48fa9fc5c81c628092ba5604c74631e6","name":"@2londres/shareable-preview","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@2londres/shareable-preview","version":"1.0.0","_id":"@2londres/shareable-preview@1.0.0","maintainers":[{"name":"martio007","email":"managerboah@gmail.com"}],"dist":{"shasum":"b16a5843747c35792cbdd7d768d3886d41dbb0f4","tarball":"https://registry.npmjs.org/@2londres/shareable-preview/-/shareable-preview-1.0.0.tgz","fileCount":6,"integrity":"sha512-MMeIP4BYlu3G7vSRovh4KKmN/EBOYi4DhVaj7XIJ9gtO8uMHlK5pVD57d+e0wzf/xjeSC3MEc30OEbgpWjhgWg==","signatures":[{"sig":"MEUCICYEYcEzDaWxBZjvM7/9U6Me2QvR1wwsYPMTZl1brDNxAiEAufK7ZlPtmN+GoaUSG8fppzRuwk3N7T4H2vcAgofOI7Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":110083},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"martio007","email":"managerboah@gmail.com"},"_npmVersion":"11.11.0","description":"React component for shareable data preview with debug/user modes","directories":{},"_nodeVersion":"25.8.0","dependencies":{"clsx":"^2.1.1","lucide-react":"^0.400.0","tailwind-merge":"^2.4.0","@radix-ui/react-slot":"^1.2.0","@radix-ui/react-tabs":"^1.0.4","@radix-ui/react-dialog":"^1.1.6","class-variance-authority":"^0.7.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^18.3.1","react-dom":"^18.3.1","typescript":"^5.2.2","@types/node":"^20.14.10","@types/react":"^18.3.3","@types/react-dom":"^18.3.0"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/shareable-preview_1.0.0_1773409772087_0.21202733916730643","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@2londres/shareable-preview","version":"1.0.2","_id":"@2londres/shareable-preview@1.0.2","maintainers":[{"name":"martio007","email":"managerboah@gmail.com"}],"dist":{"shasum":"c346d2a7473d7bc7fe8b548102c7b730cc2c1402","tarball":"https://registry.npmjs.org/@2londres/shareable-preview/-/shareable-preview-1.0.2.tgz","fileCount":6,"integrity":"sha512-zmNTo7vGHUHudYQN6bTpOk10BiWGY6kA0bkVKePHApmL+e+Cmsa23Lk+tNvhUtQXwmxQ4KfbTYoP3C5VnO5S3Q==","signatures":[{"sig":"MEUCIQDepn/XNIOe1rwzJiMks6UBqR+HFo+92qZ1v8FyBtjLTgIgPWHt3jQDuKujo3pP6i2qOfMxCv8ZiNIfmZ3CnXjs6gM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":115375},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"gitHead":"c57b54b26275b5ce2ec7fcad5545fadc83dbce21","scripts":{"dev":"tsup --watch","build":"tsup"},"_npmUser":{"name":"martio007","email":"managerboah@gmail.com"},"_npmVersion":"11.12.0","description":"React component for shareable data preview with debug/user modes","directories":{},"_nodeVersion":"25.8.0","dependencies":{"clsx":"^2.1.1","lucide-react":"^0.400.0","tailwind-merge":"^2.4.0","@radix-ui/react-slot":"^1.2.0","@radix-ui/react-tabs":"^1.0.4","@radix-ui/react-dialog":"^1.1.6","class-variance-authority":"^0.7.1"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.3.0","react":"^18.3.1","react-dom":"^18.3.1","typescript":"^5.2.2","@types/node":"^20.14.10","@types/react":"^18.3.3","@types/react-dom":"^18.3.0"},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/shareable-preview_1.0.2_1776113315126_0.03232522302482432","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@2londres/shareable-preview","version":"1.0.3","description":"React component for shareable data preview with debug/user modes","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"}},"peerDependencies":{"react":">=18.0.0","react-dom":">=18.0.0"},"dependencies":{"@radix-ui/react-dialog":"^1.1.6","@radix-ui/react-tabs":"^1.0.4","@radix-ui/react-slot":"^1.2.0","class-variance-authority":"^0.7.1","clsx":"^2.1.1","lucide-react":"^0.400.0","tailwind-merge":"^2.4.0"},"devDependencies":{"@types/node":"^20.14.10","@types/react":"^18.3.3","@types/react-dom":"^18.3.0","react":"^18.3.1","react-dom":"^18.3.1","tsup":"^8.3.0","typescript":"^5.2.2"},"scripts":{"build":"tsup","dev":"tsup --watch"},"_id":"@2londres/shareable-preview@1.0.3","_integrity":"sha512-kqyfC4VX8b+ACiJFyDZmMKmpL0EIsFpBPCsyzFhDWa7oDPDLA0chXn/PKx3CuUt/B/TNp09HClhshky99R+RmQ==","_resolved":"/private/var/folders/35/hyb4ps8n75j9b_m55_nrmdv40000gp/T/99ddcfde92b1d319cf930fb43be735a1/2londres-shareable-preview-1.0.3.tgz","_from":"file:2londres-shareable-preview-1.0.3.tgz","_nodeVersion":"25.8.0","_npmVersion":"11.12.0","dist":{"integrity":"sha512-kqyfC4VX8b+ACiJFyDZmMKmpL0EIsFpBPCsyzFhDWa7oDPDLA0chXn/PKx3CuUt/B/TNp09HClhshky99R+RmQ==","shasum":"b9687cc98147c81ca7e0167956e27b4b81d8d8ed","tarball":"https://registry.npmjs.org/@2londres/shareable-preview/-/shareable-preview-1.0.3.tgz","fileCount":6,"unpackedSize":115374,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDQYC3ydkF+QGQTawjT3N0ZW9DoDr89zca4ne2z6NaYcQIgPf31BwLf699ExjbVRL0HhkLX0+IouEf9dPmYrQVrT6E="}]},"_npmUser":{"name":"martio007","email":"managerboah@gmail.com"},"directories":{},"maintainers":[{"name":"martio007","email":"managerboah@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/shareable-preview_1.0.3_1776113496008_0.12752674292577737"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-13T13:49:32.015Z","modified":"2026-04-13T20:51:36.224Z","1.0.0":"2026-03-13T13:49:32.236Z","1.0.2":"2026-04-13T20:48:35.282Z","1.0.3":"2026-04-13T20:51:36.125Z"},"description":"React component for shareable data preview with debug/user modes","maintainers":[{"name":"martio007","email":"managerboah@gmail.com"}],"readme":"# @2londres/shareable-preview\n\nReact component for shareable data preview with debug/user modes, custom views, field filtering, and validation buttons.\n\n## Installation\n\n```bash\npnpm add @2londres/shareable-preview\n# or\nnpm install @2londres/shareable-preview\n```\n\n## Peer dependencies\n\n- `react` >= 18.0.0\n- `react-dom` >= 18.0.0\n\nYour project must have Tailwind CSS configured (the component uses Tailwind classes).\n\n## Basic usage\n\n<!-- TODO: Replace with your own recording -->\n![Basic usage](docs/assets/basic-usage.gif)\n\n```tsx\nimport { ShareablePreview } from \"@2londres/shareable-preview\";\n\n<ShareablePreview\n  data={{ foo: \"bar\", count: 42 }}\n  title=\"My Preview\"\n  description=\"Verify the information before validation\"\n  mode=\"user\"\n/>\n```\n\nWith actions:\n\n```tsx\n<ShareablePreview\n  data={myData}\n  title=\"Preview\"\n  actions={[\n    { label: \"Confirm\", onClick: () => {} },\n    { label: \"Delete\", onClick: () => {} },\n  ]}\n/>\n```\n\n## Props\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `data` | `unknown` | Data to preview |\n| `title` | `string` | Preview title |\n| `description` | `string` | Optional description |\n| `actions` | `ShareablePreviewAction[]` | Action buttons |\n| `shareUrl` | `string` | URL to copy when sharing |\n| `labels` | `Partial<Record<string, string>>` | Override default labels (i18n) |\n| `onNotify` | `(type: 'success' \\| 'error', key: string) => void` | Callback for notifications (copy, download, etc.) |\n| `eyeDevMode` | `'development' \\| 'production'` | Show/hide debug UI (default: `process.env.NODE_ENV`) |\n| `mode` | `'debug' \\| 'user'` | Default view mode |\n| `inline` | `boolean` | Render inline without dialog |\n| `customView` | `Component` | Single custom view component |\n| `customViewProps` | `object` | Props passed to custom view (including field filters) |\n| `customViews` | `Array` | Multiple views with tabs (id, label, view, viewProps, actions) |\n| `defaultOpen` | `boolean` | Open dialog by default |\n| `onOpenChange` | `(open: boolean) => void` | Callback when dialog open state changes |\n\n## Action buttons (ValidationButton)\n\nActions display as gradient buttons with icons and visual effects at the bottom of the preview.\n\n<!-- TODO: Replace with your own recording -->\n![Action buttons](docs/assets/action-buttons.gif)\n\n### Action props\n\n| Prop | Type | Description |\n|------|------|-------------|\n| `label` | `string` | Button text |\n| `onClick` | `() => void` | Click handler |\n| `variant` | `\"green\" \\| \"red\" \\| \"blue\" \\| \"purple\" \\| \"orange\"` | Gradient color (auto-detected if absent) |\n| `icon` | `LucideIcon \\| string \\| ReactElement` | Icon (auto-detected from label if absent) |\n| `withPulse` | `boolean` | Pulse animation to draw attention |\n| `withIndicator` | `boolean` | Animated yellow dot in top-right corner |\n| `buttonClassName` | `string` | Additional CSS classes |\n| `disabled` | `boolean` | Disable button |\n| `order` | `number` | Display order (lower = left) |\n\n### Auto-detection\n\n- **Red variant**: labels containing \"delete\", \"cancel\", \"reject\", etc.\n- **Green variant**: \"confirm\", \"validate\", \"approve\", etc.\n- **Icon**: inferred from label (confirm → CheckCircle, cancel → XCircle, etc.)\n\n### Example — Transaction approval\n\n```tsx\n<ShareablePreview\n  data={previewData}\n  title=\"Preview\"\n  mode=\"user\"\n  customView={MultipleTransactionsView}\n  defaultOpen\n  onOpenChange={(open) => !open && setShowPreview(false)}\n  actions={[\n    { label: \"Confirm\", onClick: () => { setIsOpen(true); setShowPreview(false); }, variant: \"green\", withIndicator: true },\n    { label: \"Reject\", onClick: () => { setIsRejectOpen(true); setShowPreview(false); }, variant: \"red\" },\n    { label: \"Cancel\", onClick: () => setShowPreview(false), variant: \"blue\", order: 0 },\n  ]}\n/>\n```\n\n## Custom views\n\n<!-- TODO: Replace with your own recording -->\n![Custom views with tabs](docs/assets/custom-views.gif)\n\n### Single view (`customView`)\n\n```tsx\n<ShareablePreview\n  data={data}\n  customView={TransactionView}\n  customViewProps={{\n    excludedKeys: [\"id\", \"host_id\"],\n    excludedNestedKeys: [\"transaction_rule\", \"country\"],\n    maxDepth: 7,\n  }}\n/>\n```\n\n### Multiple views with tabs (`customViews`)\n\n```tsx\nimport { ShareablePreview, UserView } from \"@2londres/shareable-preview\";\n\n<ShareablePreview\n  data={data}\n  customViews={[\n    {\n      id: \"summary\",\n      label: \"Summary\",\n      view: UserView,\n      viewProps: { includedKeys: [\"amount\", \"currency\", \"reference\"] },\n      actions: [\n        { label: \"Validate\", variant: \"green\", onClick: handleValidate },\n        { label: \"Cancel\", variant: \"red\", onClick: handleCancel },\n      ],\n    },\n    {\n      id: \"full\",\n      label: \"Full details\",\n      view: TransactionView,\n      viewProps: { excludedKeys: [\"id\"], maxDepth: 7 },\n      actions: [\n        { label: \"Confirm\", variant: \"green\", onClick: handleConfirm },\n        { label: \"Reject\", variant: \"red\", onClick: handleReject },\n      ],\n    },\n  ]}\n/>\n```\n\nEach tab can have its **own actions**. If a view has no `actions`, the global actions are used.\n\n## Field filtering\n\n<!-- TODO: Replace with your own recording -->\n![Field filtering](docs/assets/field-filtering.gif)\n\nOptions passed via `customViewProps` or `viewProps` (in `customViews`). Compatible with `UserView`.\n\n| Option | Type | Description |\n|--------|------|-------------|\n| `includedKeys` | `string[]` | **Whitelist**: only these top-level keys |\n| `excludedKeys` | `string[]` | **Blacklist**: exclude these keys |\n| `includedNestedKeys` | `string[]` | Whitelist for nested paths |\n| `excludedNestedKeys` | `string[]` | Blacklist for nested paths |\n| `maxDepth` | `number` | Maximum recursion depth |\n\n## Helper `createPreviewActions`\n\n```tsx\nimport { createPreviewActions, ShareablePreview } from \"@2londres/shareable-preview\";\n\nconst actions = createPreviewActions({\n  onConfirm: () => { setIsOpen(true); setShowPreview(false); },\n  onReject: () => { setIsRejectOpen(true); setShowPreview(false); },\n  onCancel: () => setShowPreview(false),\n  labels: { confirm: \"Confirm\", reject: \"Reject\", cancel: \"Cancel\" },\n  withIndicatorOnConfirm: true,\n});\n\n<ShareablePreview data={previewData} actions={actions} mode=\"user\" />\n```\n\n## Internationalization\n\nThe package uses `labels` and `onNotify` for i18n without depending on react-i18next:\n\n<!-- TODO: Replace with your own recording -->\n![Internationalization](docs/assets/i18n.gif)\n\n```tsx\n<ShareablePreview\n  data={data}\n  labels={{\n    shareablePreviewDefaultTitle: \"Preview\",\n    shareablePreviewOpen: \"Open preview\",\n  }}\n  onNotify={(type, key) => {\n    if (type === \"success\") toast.success(key);\n    else toast.error(key);\n  }}\n/>\n```\n\n### With react-i18next\n\n```tsx\nimport { useTranslation } from \"react-i18next\";\nimport { ShareablePreview } from \"@2londres/shareable-preview\";\n\nconst keys = [\n  \"shareablePreviewCopySuccess\",\n  \"shareablePreviewShareLinkCopied\",\n  \"shareablePreviewClipboardError\",\n];\n\n<ShareablePreview\n  data={data}\n  labels={Object.fromEntries(keys.map((k) => [k, t(k)]))}\n  onNotify={(type, key) => {\n    if (type === \"success\") notifSilence(key);\n    else notifSilenceError(key);\n  }}\n/>\n```\n\n## Publishing to npm\n\n```bash\npnpm build\nnpm publish --access public\n```\n","readmeFilename":"README.md"}