{"_id":"@asim3bird/sh-upload","name":"@asim3bird/sh-upload","dist-tags":{"latest":"0.0.2"},"versions":{"0.0.2":{"name":"@asim3bird/sh-upload","version":"0.0.2","description":"Drag-and-drop media upload web component for S3 (works with any bundler or vanilla JS)","main":"dist/index.cjs.js","module":"dist/index.js","types":"dist/types/index.d.ts","collection":"dist/collection/collection-manifest.json","collection:main":"dist/collection/index.js","unpkg":"dist/sh-upload/sh-upload.esm.js","exports":{".":{"import":"./dist/sh-upload/sh-upload.esm.js","require":"./dist/cjs/sh-upload.cjs.js","types":"./dist/types/index.d.ts"},"./loader":{"import":"./loader/index.js","require":"./loader/index.cjs","types":"./loader/index.d.ts"},"./sh-upload":{"import":"./dist/components/sh-upload.js","types":"./dist/components/sh-upload.d.ts"}},"repository":{"type":"git","url":"git+https://github.com/3-Bird/socialhouse-stencil.git"},"scripts":{"build":"stencil build","start":"stencil build --dev --watch --serve","test":"stencil test --spec --e2e","test.watch":"stencil test --spec --e2e --watchAll","generate":"stencil generate","prepublishOnly":"npm run build"},"devDependencies":{"@stencil/core":"^4.27.1","@types/jest":"^29.5.14","@types/node":"^22.13.5","jest":"^29.7.0","jest-cli":"^29.7.0","puppeteer":"^24.3.0"},"license":"MIT","gitHead":"05e251b45a1346b5756ebbee043a5780bd6a290f","_id":"@asim3bird/sh-upload@0.0.2","bugs":{"url":"https://github.com/3-Bird/socialhouse-stencil/issues"},"homepage":"https://github.com/3-Bird/socialhouse-stencil#readme","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-Nes3Ta9XMrhxnl6XXca/NXu99wGKL5QWkzg9P8AQI3a9FjnoXyc1Z470wRUNgfj0mk6C2duKUL2QI0q2v+16Jg==","shasum":"efedbfb76cd2abecacd6b76b4ac26dbb951ad8b9","tarball":"https://registry.npmjs.org/@asim3bird/sh-upload/-/sh-upload-0.0.2.tgz","fileCount":93,"unpackedSize":5324155,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDn7JFOz2HlxaCQM1vuwwK4oao19FBSrrRo0zSYJdjAwwIhAN67zuKzYOKBYnDPtJefGhg2/77zWK3InjKnPZxDp+uG"}]},"_npmUser":{"name":"asim3bird","email":"asim@3bird.nl"},"directories":{},"maintainers":[{"name":"asim3bird","email":"asim@3bird.nl"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sh-upload_0.0.2_1773913175081_0.8398490722325398"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-19T09:39:34.986Z","0.0.2":"2026-03-19T09:39:35.362Z","modified":"2026-03-19T09:39:35.543Z"},"maintainers":[{"name":"asim3bird","email":"asim@3bird.nl"}],"description":"Drag-and-drop media upload web component for S3 (works with any bundler or vanilla JS)","homepage":"https://github.com/3-Bird/socialhouse-stencil#readme","repository":{"type":"git","url":"git+https://github.com/3-Bird/socialhouse-stencil.git"},"bugs":{"url":"https://github.com/3-Bird/socialhouse-stencil/issues"},"license":"MIT","readme":"# sh-upload\n\nA **drag-and-drop media upload web component** built with **StencilJS** that uploads images and videos **directly to Amazon S3** using signed upload policies.\n\n`<sh-upload>` validates an API token, fetches upload policies, handles expiration, retries, and emits upload events — all inside a fully encapsulated Shadow DOM component.\n\n---\n\n## ✨ Features\n\n- **Drag & drop + file picker uploads** - Intuitive file selection interface\n- **Image & video support** - Accepts `image/*` and `video/*` file types (jpg, png, gif, mp4, mov, avi, wmv)\n- **Direct browser → S3 uploads** - Files upload directly to Amazon S3 using signed upload policies\n- **Automatic upload policy refresh** - Policies are automatically refreshed before expiration\n- **Token validation** - Validates API token on component load and when token changes via `/v1/house/details` endpoint\n- **Error & retry handling** - Visual error states with retry button for failed validations or expired policies\n- **Individual file status tracking** - Each file shows its own upload status (uploading, success, error) with visual indicators\n- **File previews** - Image previews with status overlays (loading spinner, success checkmark, error icon)\n- **Multiple file uploads** - Upload multiple files simultaneously with configurable maximum limit\n- **Multiple orientation options** - `vertical`, `horizontal`, or `compact` layouts\n- **Light/dark mode support** - Theme switching with `light` or `dark` modes\n- **Social House branding** - Logo display that adapts based on orientation and mode, plus \"Powered by Social House\" footer\n- **Shadow DOM encapsulated styles** - Fully isolated component styles\n- **Framework-agnostic** - Works with **any bundler** (Vite, Webpack, Rollup, etc.) or **vanilla JS** (no build step)\n\n---\n\n## 📦 Installation\n\n```bash\nnpm install sh-upload\n```\n\n---\n\n## 🚀 Integration\n\n### Vanilla (no bundler)\n\nUse the component from a CDN with a single script tag (no install required):\n\n```html\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n  <title>sh-upload Example</title>\n  <script type=\"module\" src=\"https://unpkg.com/sh-upload\"></script>\n</head>\n<body>\n  <sh-upload\n    api-key=\"your-api-key\"\n    base-url=\"https://api.example.com/\"\n    house-id=\"your-house-id\"\n    max-files=\"10\"\n    orientation=\"compact\"\n    mode=\"light\">\n  </sh-upload>\n\n  <script>\n    document.querySelector('sh-upload').addEventListener('uploadSuccess', (e) => {\n      console.log('Upload successful:', e.detail.key);\n    });\n  </script>\n</body>\n</html>\n```\n\nWith npm and a local build, use the same ESM entry:\n\n```html\n<script type=\"module\" src=\"node_modules/sh-upload/dist/sh-upload/sh-upload.esm.js\"></script>\n```\n\n---\n\n### React\n\n#### 1. Import the component loader\n\n```tsx\nimport { defineCustomElements } from 'sh-upload/loader';\n\n// Call this once in your app initialization\ndefineCustomElements();\n```\n\n#### 2. Use the component in your React component\n\n```tsx\nimport React, { useRef, useEffect } from 'react';\n\nfunction UploadComponent() {\n  const uploadRef = useRef<HTMLShUploadElement>(null);\n\n  useEffect(() => {\n    const uploadElement = uploadRef.current;\n    if (!uploadElement) return;\n\n    const handleSuccess = (event: CustomEvent<{ key: string }>) => {\n      console.log('Upload successful:', event.detail.key);\n      // Handle successful upload\n    };\n\n    const handleError = (event: CustomEvent<any>) => {\n      console.error('Upload error:', event.detail);\n      // Handle upload error\n    };\n\n    uploadElement.addEventListener('uploadSuccess', handleSuccess);\n    uploadElement.addEventListener('uploadError', handleError);\n\n    return () => {\n      uploadElement.removeEventListener('uploadSuccess', handleSuccess);\n      uploadElement.removeEventListener('uploadError', handleError);\n    };\n  }, []);\n\n  return (\n    <sh-upload\n      ref={uploadRef}\n      token=\"your-api-token\"\n      baseUrl=\"https://api.example.com/\"\n      eventName=\"your-event-name\"\n      maxFiles={10}\n      orientation=\"compact\"\n      mode=\"light\"\n    />\n  );\n}\n\nexport default UploadComponent;\n```\n\n#### 3. TypeScript support (optional)\n\nAdd type definitions to your `tsconfig.json`:\n\n```json\n{\n  \"compilerOptions\": {\n    \"types\": [\"sh-upload/dist/types\"]\n  }\n}\n```\n\n---\n\n### Angular\n\n#### 1. Import the component loader in `main.ts` or `app.module.ts`\n\n```typescript\nimport { defineCustomElements } from 'sh-upload/loader';\n\n// Call this once in your app initialization\ndefineCustomElements();\n```\n\n#### 2. Use the component in your Angular template\n\n```html\n<!-- app.component.html -->\n<sh-upload\n  [token]=\"apiToken\"\n  [baseUrl]=\"baseUrl\"\n  [eventName]=\"eventName\"\n  [maxFiles]=\"10\"\n  orientation=\"compact\"\n  mode=\"light\"\n  (uploadSuccess)=\"onUploadSuccess($event)\"\n  (uploadError)=\"onUploadError($event)\">\n</sh-upload>\n```\n\n#### 3. Handle events in your component\n\n```typescript\n// app.component.ts\nimport { Component } from '@angular/core';\n\n@Component({\n  selector: 'app-root',\n  templateUrl: './app.component.html',\n  styleUrls: ['./app.component.css']\n})\nexport class AppComponent {\n  apiToken = 'your-api-token';\n  baseUrl = 'https://api.example.com/';\n  eventName = 'your-event-name';\n\n  onUploadSuccess(event: CustomEvent<{ key: string }>) {\n    console.log('Upload successful:', event.detail.key);\n    // Handle successful upload\n  }\n\n  onUploadError(event: CustomEvent<any>) {\n    console.error('Upload error:', event.detail);\n    // Handle upload error\n  }\n}\n```\n\n#### 4. Add CUSTOM_ELEMENTS_SCHEMA to your module\n\n```typescript\nimport { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';\nimport { BrowserModule } from '@angular/platform-browser';\nimport { AppComponent } from './app.component';\n\n@NgModule({\n  declarations: [AppComponent],\n  imports: [BrowserModule],\n  providers: [],\n  bootstrap: [AppComponent],\n  schemas: [CUSTOM_ELEMENTS_SCHEMA] // Add this\n})\nexport class AppModule { }\n```\n\n---\n\n### TypeScript (Plain HTML/TypeScript)\n\n#### 1. Include the component script\n\nUse the CDN (see **Vanilla** above) or your bundler’s public path to `node_modules/sh-upload/dist/sh-upload/sh-upload.esm.js`.\n\n#### 2. TypeScript with type definitions\n\n```typescript\nimport type { HTMLShUploadElement } from 'sh-upload';\n\nconst uploadElement = document.querySelector<HTMLShUploadElement>('sh-upload');\n\nif (uploadElement) {\n  uploadElement.token = 'your-api-token';\n  uploadElement.baseUrl = 'https://api.example.com/';\n  uploadElement.eventName = 'your-event-name';\n  uploadElement.maxFiles = 10;\n  uploadElement.orientation = 'compact';\n  uploadElement.mode = 'light';\n\n  uploadElement.addEventListener('uploadSuccess', (event: CustomEvent<{ key: string }>) => {\n    console.log('Upload successful:', event.detail.key);\n  });\n\n  uploadElement.addEventListener('uploadError', (event: CustomEvent<any>) => {\n    console.error('Upload error:', event.detail);\n  });\n}\n```\n\n---\n\n## 📋 Component Props\n\n| Prop | Type | Default | Description |\n|------|------|---------|-------------|\n| `token` | `string` | **required** | API authentication token |\n| `baseUrl` | `string` | **required** | Base URL for API requests |\n| `eventName` | `string` | `'bubty'` | Event name for upload policy |\n| `maxFiles` | `number` | `10` | Maximum number of files to upload |\n| `orientation` | `'vertical' \\| 'horizontal' \\| 'compact'` | `'compact'` | Component orientation |\n| `mode` | `'dark' \\| 'light'` | `'light'` | Color theme |\n\n## 📡 Events\n\n| Event | Payload | Description |\n|-------|---------|-------------|\n| `uploadSuccess` | `{ key: string }` | Emitted when a file upload succeeds. The `key` is the S3 object key for the uploaded file. |\n| `uploadError` | `any` | Emitted when a file upload fails. Contains error details from the upload request. |\n\n---\n\n## 🎨 UI Components\n\nThe component includes several visual elements:\n\n- **Logo** - Social House logo displayed at the top, automatically selected based on `orientation` and `mode` props\n- **Dropzone** - Main upload area with drag-and-drop functionality and visual icons\n- **File Previews** - Thumbnail previews for images with status indicators:\n  - Loading spinner during upload\n  - Green checkmark on success\n  - Red error icon on failure\n- **Upload Button** - File picker button to select files\n- **Error State** - Displays error messages with a retry button when validation fails or policies expire\n- **Footer** - \"Powered by Social House\" branding at the bottom\n\n## 🔄 Upload Behavior\n\n- Files are uploaded **sequentially** (one after another) to ensure proper policy management\n- Each file's upload status is tracked independently\n- Upload policies are automatically refreshed if they're close to expiring (within 10 seconds)\n- Failed uploads are marked with an error state but don't block subsequent uploads\n- The component validates the API token on mount and whenever the `token` prop changes\n\n---\n\n## 📤 Publishing to npm\n\nTo publish this package as `sh-upload`:\n\n1. **Log in to npm** (one-time):\n   ```bash\n   npm login\n   ```\n\n2. **Bump version** (optional):\n   ```bash\n   npm version patch   # or minor / major\n   ```\n\n3. **Publish**:\n   ```bash\n   npm publish\n   ```\n   The `prepublishOnly` script runs `npm run build` automatically before publish.\n\nThe package is built so it works with **every bundler** (Vite, Webpack, Rollup, Parcel, etc.) and **vanilla JS**:\n\n- **Vanilla**: Use `<script type=\"module\" src=\"https://unpkg.com/sh-upload\"></script>` (unpkg resolves to the ESM bundle).\n- **Bundlers**: `import 'sh-upload'` or `import { defineCustomElements } from 'sh-upload/loader'` then `defineCustomElements()`.\n- **Tree-shaking**: `import 'sh-upload/sh-upload'` to load only the custom element (auto-defined).\n\n---","readmeFilename":"README.md","_rev":"1-a8d0602d20e1cd44e2d6786efbd0bbbf"}