feat(components): Add reusable message input component, refactor element properties to use accessor, update styles and docs, bump dependencies
This commit is contained in:
14
changelog.md
14
changelog.md
@@ -1,5 +1,19 @@
|
||||
# Changelog
|
||||
|
||||
## 2025-12-08 - 1.3.0 - feat(components)
|
||||
Add reusable message input component, refactor element properties to use accessor, update styles and docs, bump dependencies
|
||||
|
||||
- Add new <sio-message-input> component (auto-resizing textarea, file picker, send/files events) and integrate it into sio-conversation-view
|
||||
- Refactor multiple element class fields to use the 'accessor' property pattern (sio-button, sio-combox, sio-conversation-view, sio-dropdown-menu, sio-fab, sio-icon, sio-image-lightbox, sio-pdf-viewer, sio-recorder, etc.)
|
||||
- Significant visual and UX updates to sio-button (new secondary variant, sizing, spacing, icon sizing, focus/disabled behavior)
|
||||
- Move inline conversation input logic into the new component and simplify message handling (dispatch send-message event with text and attachments)
|
||||
- Improve PDF viewer: safer async pdf.js loader, resize observer for responsive rendering, better error fallback and lifecycle cleanup
|
||||
- Enhance image lightbox (PDF handling via sio-pdf-viewer, zoom/drag controls, keyboard shortcuts, download/open actions)
|
||||
- Add icon caching and make lucide upgrade (cache limit, PascalCase lookup) to reduce re-renders
|
||||
- Polish tokens/styles: spacing, radii, shadows, transitions and small responsive/layout tweaks (e.g. main page padding)
|
||||
- Update README to reflect the public package name, components, quick start and development instructions
|
||||
- Bump runtime and dev dependencies (dees-element/domtools/wcctools, lucide, git.zone tools, push.rocks smartenv/types) and adjust tsconfig (target/module settings simplified)
|
||||
|
||||
## 2025-04-20 - 1.2.4 - fix(build)
|
||||
Update build script and async function signature
|
||||
|
||||
|
||||
23
package.json
23
package.json
@@ -15,26 +15,25 @@
|
||||
"author": "Lossless GmbH",
|
||||
"license": "UNLICENSED",
|
||||
"dependencies": {
|
||||
"@design.estate/dees-domtools": "^2.3.3",
|
||||
"@design.estate/dees-element": "^2.1.2",
|
||||
"@design.estate/dees-wcctools": "^1.1.1",
|
||||
"@design.estate/dees-domtools": "^2.3.6",
|
||||
"@design.estate/dees-element": "^2.1.3",
|
||||
"@design.estate/dees-wcctools": "^1.2.1",
|
||||
"@losslessone_private/loint-pubapi": "^1.0.14",
|
||||
"@social.io/interfaces": "^1.2.1",
|
||||
"lucide": "^0.525.0",
|
||||
"lucide": "^0.556.0",
|
||||
"rrweb": "2.0.0-alpha.4",
|
||||
"rrweb-player": "1.0.0-alpha.4",
|
||||
"rrweb-snapshot": "2.0.0-alpha.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbuild": "^2.6.4",
|
||||
"@git.zone/tsbundle": "^2.5.1",
|
||||
"@git.zone/tsrun": "^1.3.3",
|
||||
"@git.zone/tstest": "^2.3.1",
|
||||
"@git.zone/tswatch": "^2.1.2",
|
||||
"@git.zone/tsbuild": "^3.1.2",
|
||||
"@git.zone/tsbundle": "^2.6.3",
|
||||
"@git.zone/tsrun": "^2.0.0",
|
||||
"@git.zone/tstest": "^3.1.3",
|
||||
"@git.zone/tswatch": "^2.3.5",
|
||||
"@push.rocks/projectinfo": "^5.0.2",
|
||||
"@push.rocks/smartenv": "^5.0.12",
|
||||
"@push.rocks/tapbundle": "^6.0.3",
|
||||
"@types/node": "^22.14.1"
|
||||
"@push.rocks/smartenv": "^6.0.0",
|
||||
"@types/node": "^24.10.1"
|
||||
},
|
||||
"files": [
|
||||
"ts/**/*",
|
||||
|
||||
7916
pnpm-lock.yaml
generated
7916
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
220
readme.md
220
readme.md
@@ -1,34 +1,204 @@
|
||||
# @social.io/private/catalog
|
||||
# @social.io/catalog
|
||||
|
||||
the element catalog for the lossless organization
|
||||
A modern, beautifully designed UI component library for building conversational interfaces and support chat experiences. Built with Lit Element and TypeScript.
|
||||
|
||||
## Availabililty and Links
|
||||
## Issue Reporting and Security
|
||||
|
||||
- [npmjs.org (npm package)](https://www.npmjs.com/package/@social.io_private/catalog)
|
||||
- [gitlab.com (source)](https://gitlab.com/social.io/private/catalog)
|
||||
- [github.com (source mirror)](https://github.com/social.io/private/catalog)
|
||||
- [docs (typedoc)](https://social.io/private.gitlab.io/catalog/)
|
||||
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||
|
||||
## Status for master
|
||||
## 🎯 Features
|
||||
|
||||
| Status Category | Status Badge |
|
||||
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
||||
| GitLab Pipelines | [](https://lossless.cloud) |
|
||||
| GitLab Pipline Test Coverage | [](https://lossless.cloud) |
|
||||
| npm | [](https://lossless.cloud) |
|
||||
| Snyk | [](https://lossless.cloud) |
|
||||
| TypeScript Support | [](https://lossless.cloud) |
|
||||
| node Support | [](https://nodejs.org/dist/latest-v10.x/docs/api/) |
|
||||
| Code Style | [](https://lossless.cloud) |
|
||||
| PackagePhobia (total standalone install weight) | [](https://lossless.cloud) |
|
||||
| PackagePhobia (package size on registry) | [](https://lossless.cloud) |
|
||||
| BundlePhobia (total size when bundled) | [](https://lossless.cloud) |
|
||||
- **Complete Chat UI** - Ready-to-use conversation components with message threads, typing indicators, and attachments
|
||||
- **Floating Action Button** - Eye-catching FAB with smooth animations for triggering the chat interface
|
||||
- **PDF Viewer** - Built-in PDF rendering with zoom, pagination, and download capabilities
|
||||
- **Image Lightbox** - Full-featured lightbox with zoom, pan, and keyboard navigation
|
||||
- **Modern Design Tokens** - Consistent styling with customizable colors, spacing, typography, and shadows
|
||||
- **Dark Mode Ready** - Full light/dark theme support out of the box
|
||||
- **Accessibility** - Keyboard navigation and proper ARIA attributes
|
||||
- **TypeScript First** - Full type definitions for all components
|
||||
|
||||
## Usage
|
||||
## 📦 Installation
|
||||
|
||||
For further information read the linked docs at the top of this readme.
|
||||
```bash
|
||||
npm install @social.io/catalog
|
||||
# or
|
||||
pnpm add @social.io/catalog
|
||||
```
|
||||
|
||||
## Legal
|
||||
## 🚀 Quick Start
|
||||
|
||||
> UNLICENSED licensed | **©** [Task Venture Capital GmbH](https://task.vc)
|
||||
> | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
|
||||
```typescript
|
||||
import { SioFab, SioCombox } from '@social.io/catalog';
|
||||
|
||||
// Components auto-register as custom elements
|
||||
// Just use them in your HTML:
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- Floating Action Button that opens the chat -->
|
||||
<sio-fab></sio-fab>
|
||||
|
||||
<!-- Or use the full chat box directly -->
|
||||
<sio-combox></sio-combox>
|
||||
```
|
||||
|
||||
## 🧩 Components
|
||||
|
||||
### Core Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `<sio-fab>` | Floating action button with animated chat icon |
|
||||
| `<sio-combox>` | Complete chat interface with conversation list and message view |
|
||||
| `<sio-button>` | Styled button with variants (primary, secondary, destructive, outline, ghost) |
|
||||
| `<sio-icon>` | Lucide icon wrapper with size and color customization |
|
||||
| `<sio-dropdown-menu>` | Animated dropdown menu with keyboard support |
|
||||
|
||||
### Conversation Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `<sio-conversation-selector>` | Searchable list of conversations with unread indicators |
|
||||
| `<sio-conversation-view>` | Message thread with typing indicators and file attachments |
|
||||
| `<sio-message-input>` | Auto-expanding textarea with file upload |
|
||||
|
||||
### Media Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `<sio-image-lightbox>` | Fullscreen image viewer with zoom and pan |
|
||||
| `<sio-pdf-viewer>` | PDF renderer with page navigation and zoom controls |
|
||||
|
||||
### Utility Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| `<sio-recorder>` | Session recording using rrweb |
|
||||
|
||||
## 💅 Styling & Theming
|
||||
|
||||
The library uses CSS custom properties for theming. The design system includes:
|
||||
|
||||
- **Colors** - Primary, secondary, accent, destructive, muted, and semantic colors
|
||||
- **Typography** - System font stack with size and weight variants
|
||||
- **Spacing** - Consistent spacing scale (0.5rem increments)
|
||||
- **Radius** - Border radius tokens from sm to full
|
||||
- **Shadows** - Elevation system from sm to 2xl
|
||||
- **Transitions** - Smooth animation presets
|
||||
|
||||
### Dark Mode
|
||||
|
||||
Dark mode is automatically supported. The components use `bdTheme()` helper that switches between light and dark values:
|
||||
|
||||
```typescript
|
||||
import { bdTheme } from '@social.io/catalog';
|
||||
|
||||
// Usage in styles
|
||||
css`
|
||||
background: ${bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 10%)')};
|
||||
`
|
||||
```
|
||||
|
||||
## 📖 Usage Examples
|
||||
|
||||
### Basic Chat FAB
|
||||
|
||||
```html
|
||||
<sio-fab></sio-fab>
|
||||
```
|
||||
|
||||
The FAB opens a complete chat interface when clicked. It includes:
|
||||
- Keyboard shortcut (Ctrl+S) to toggle
|
||||
- Smooth scale and pulse animations
|
||||
- Gradient background with glow effects
|
||||
|
||||
### Custom Button Variants
|
||||
|
||||
```html
|
||||
<sio-button type="primary">Submit</sio-button>
|
||||
<sio-button type="destructive">Delete</sio-button>
|
||||
<sio-button type="outline">Cancel</sio-button>
|
||||
<sio-button type="ghost" size="sm">
|
||||
<sio-icon icon="settings"></sio-icon>
|
||||
</sio-button>
|
||||
```
|
||||
|
||||
### Image Lightbox
|
||||
|
||||
```typescript
|
||||
const lightbox = document.querySelector('sio-image-lightbox');
|
||||
lightbox.open({
|
||||
url: 'https://example.com/photo.jpg',
|
||||
name: 'My Photo',
|
||||
size: 1024000
|
||||
});
|
||||
```
|
||||
|
||||
### PDF Viewer
|
||||
|
||||
```html
|
||||
<sio-pdf-viewer
|
||||
url="https://example.com/document.pdf"
|
||||
fileName="document.pdf"
|
||||
></sio-pdf-viewer>
|
||||
```
|
||||
|
||||
### Dropdown Menu
|
||||
|
||||
```html
|
||||
<sio-dropdown-menu
|
||||
.items=${[
|
||||
{ id: 'edit', label: 'Edit', icon: 'pencil' },
|
||||
{ id: 'delete', label: 'Delete', icon: 'trash', destructive: true }
|
||||
]}
|
||||
@item-selected=${(e) => console.log('Selected:', e.detail.item)}
|
||||
>
|
||||
<sio-button type="ghost">
|
||||
<sio-icon icon="more-vertical"></sio-icon>
|
||||
</sio-button>
|
||||
</sio-dropdown-menu>
|
||||
```
|
||||
|
||||
## 🔧 Development
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Start development server with hot reload
|
||||
pnpm watch
|
||||
|
||||
# Run tests
|
||||
pnpm test
|
||||
|
||||
# Build for production
|
||||
pnpm build
|
||||
```
|
||||
|
||||
## 📚 Dependencies
|
||||
|
||||
- **@design.estate/dees-element** - Lit Element base with utilities
|
||||
- **@design.estate/dees-domtools** - DOM manipulation helpers
|
||||
- **lucide** - Beautiful open-source icons
|
||||
- **rrweb** - Session recording/replay (for recorder component)
|
||||
|
||||
## License and Legal Information
|
||||
|
||||
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||
|
||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||
|
||||
### Trademarks
|
||||
|
||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||
|
||||
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||
|
||||
### Company Information
|
||||
|
||||
Task Venture Capital GmbH
|
||||
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||
|
||||
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||
|
||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@social.io/catalog',
|
||||
version: '1.2.4',
|
||||
version: '1.3.0',
|
||||
description: 'catalog for social.io'
|
||||
}
|
||||
|
||||
@@ -153,6 +153,12 @@ export const getColor = (colorName: keyof typeof colors, isDark: boolean = false
|
||||
};
|
||||
|
||||
// CSS helper for theme-aware colors
|
||||
export const bdTheme = (colorName: keyof typeof colors) => {
|
||||
export const bdTheme = (colorNameOrLight: keyof typeof colors | string, dark?: string) => {
|
||||
if (dark) {
|
||||
// Direct color values provided
|
||||
return cssManager.bdTheme(colorNameOrLight as string, dark);
|
||||
}
|
||||
// Color name from palette
|
||||
const colorName = colorNameOrLight as keyof typeof colors;
|
||||
return cssManager.bdTheme(colors[colorName].light, colors[colorName].dark);
|
||||
};
|
||||
@@ -6,6 +6,7 @@ export * from './sio-dropdown-menu.js';
|
||||
// Conversation components
|
||||
export * from './sio-conversation-selector.js';
|
||||
export * from './sio-conversation-view.js';
|
||||
export * from './sio-message-input.js';
|
||||
export * from './sio-combox.js';
|
||||
|
||||
// Other components
|
||||
|
||||
@@ -36,19 +36,19 @@ export class SioButton extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: String })
|
||||
public text: string = '';
|
||||
public accessor text: string = '';
|
||||
|
||||
@property({ type: String })
|
||||
public type: 'default' | 'primary' | 'destructive' | 'outline' | 'ghost' = 'default';
|
||||
public accessor type: 'default' | 'primary' | 'secondary' | 'destructive' | 'outline' | 'ghost' = 'default';
|
||||
|
||||
@property({ type: String })
|
||||
public size: 'sm' | 'default' | 'lg' = 'default';
|
||||
public accessor size: 'sm' | 'default' | 'lg' = 'default';
|
||||
|
||||
@property({ type: Boolean, reflect: true })
|
||||
public disabled: boolean = false;
|
||||
public accessor disabled: boolean = false;
|
||||
|
||||
@property({ type: String })
|
||||
public status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||
public accessor status: 'normal' | 'pending' | 'success' | 'error' = 'normal';
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
@@ -68,117 +68,123 @@ export class SioButton extends DeesElement {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
white-space: nowrap;
|
||||
border-radius: ${unsafeCSS(radius.md)};
|
||||
border-radius: 6px;
|
||||
font-weight: 500;
|
||||
transition: ${unsafeCSS(transitions.all)};
|
||||
font-size: 14px;
|
||||
line-height: 1;
|
||||
letter-spacing: -0.01em;
|
||||
transition: all 120ms ease;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
border: 1px solid transparent;
|
||||
gap: ${unsafeCSS(spacing["2"])};
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.5;
|
||||
border: none;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
/* Size variants */
|
||||
.button.size-sm {
|
||||
height: 32px;
|
||||
padding: 0 ${unsafeCSS(spacing["3"])};
|
||||
padding: 0 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.button.size-default {
|
||||
height: 36px;
|
||||
padding: 0 ${unsafeCSS(spacing["4"])};
|
||||
padding: 0 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.button.size-lg {
|
||||
height: 44px;
|
||||
padding: 0 ${unsafeCSS(spacing["6"])};
|
||||
font-size: 16px;
|
||||
height: 42px;
|
||||
padding: 0 24px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
/* Type variants */
|
||||
.button.default {
|
||||
background: ${bdTheme('background')};
|
||||
color: ${bdTheme('foreground')};
|
||||
border-color: ${bdTheme('border')};
|
||||
box-shadow: ${unsafeCSS(shadows.sm)};
|
||||
background: ${bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
||||
color: ${bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 95%)')};
|
||||
}
|
||||
|
||||
.button.default:hover:not(.disabled) {
|
||||
background: ${bdTheme('accent')};
|
||||
border-color: ${bdTheme('accent')};
|
||||
transform: translateY(-1px);
|
||||
box-shadow: ${unsafeCSS(shadows.md)};
|
||||
background: ${bdTheme('hsl(0 0% 91%)', 'hsl(0 0% 20%)')};
|
||||
}
|
||||
|
||||
.button.default:active:not(.disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow: ${unsafeCSS(shadows.sm)};
|
||||
background: ${bdTheme('hsl(0 0% 87%)', 'hsl(0 0% 18%)')};
|
||||
}
|
||||
|
||||
.button.primary {
|
||||
background: ${bdTheme('primary')};
|
||||
color: ${bdTheme('primaryForeground')};
|
||||
box-shadow: ${unsafeCSS(shadows.sm)};
|
||||
background: ${bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 95%)')};
|
||||
color: ${bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 0%)')};
|
||||
}
|
||||
|
||||
.button.primary:hover:not(.disabled) {
|
||||
opacity: 0.9;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: ${unsafeCSS(shadows.md)};
|
||||
background: ${bdTheme('hsl(0 0% 25%)', 'hsl(0 0% 100%)')};
|
||||
}
|
||||
|
||||
.button.primary:active:not(.disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow: ${unsafeCSS(shadows.sm)};
|
||||
background: ${bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 90%)')};
|
||||
}
|
||||
|
||||
/* Secondary variant */
|
||||
.button.secondary {
|
||||
background: transparent;
|
||||
color: ${bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 95%)')};
|
||||
box-shadow: inset 0 0 0 1px ${bdTheme('hsl(0 0% 85%)', 'hsl(0 0% 25%)')};
|
||||
}
|
||||
|
||||
.button.secondary:hover:not(.disabled) {
|
||||
background: ${bdTheme('hsl(0 0% 96%)', 'hsl(0 0% 15%)')};
|
||||
}
|
||||
|
||||
.button.secondary:active:not(.disabled) {
|
||||
background: ${bdTheme('hsl(0 0% 92%)', 'hsl(0 0% 12%)')};
|
||||
}
|
||||
|
||||
/* Destructive variant */
|
||||
.button.destructive {
|
||||
background: ${bdTheme('destructive')};
|
||||
color: ${bdTheme('destructiveForeground')};
|
||||
background: ${bdTheme('hsl(0 100% 95%)', 'hsl(0 50% 20%)')};
|
||||
color: ${bdTheme('hsl(0 100% 45%)', 'hsl(0 100% 75%)')};
|
||||
}
|
||||
|
||||
.button.destructive:hover:not(.disabled) {
|
||||
opacity: 0.9;
|
||||
background: ${bdTheme('hsl(0 100% 45%)', 'hsl(0 100% 50%)')};
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button.destructive:active:not(.disabled) {
|
||||
transform: translateY(1px);
|
||||
background: ${bdTheme('hsl(0 100% 40%)', 'hsl(0 100% 45%)')};
|
||||
color: white;
|
||||
}
|
||||
|
||||
.button.outline {
|
||||
background: transparent;
|
||||
color: ${bdTheme('foreground')};
|
||||
border-color: ${bdTheme('border')};
|
||||
color: ${bdTheme('hsl(0 0% 40%)', 'hsl(0 0% 70%)')};
|
||||
box-shadow: inset 0 0 0 1.5px ${bdTheme('hsl(0 0% 90%)', 'hsl(0 0% 30%)')};
|
||||
}
|
||||
|
||||
.button.outline:hover:not(.disabled) {
|
||||
background: ${bdTheme('accent')};
|
||||
color: ${bdTheme('accentForeground')};
|
||||
color: ${bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 95%)')};
|
||||
box-shadow: inset 0 0 0 1.5px ${bdTheme('hsl(0 0% 70%)', 'hsl(0 0% 50%)')};
|
||||
}
|
||||
|
||||
.button.outline:active:not(.disabled) {
|
||||
transform: translateY(1px);
|
||||
background: ${bdTheme('hsl(0 0% 95%)', 'hsl(0 0% 15%)')};
|
||||
}
|
||||
|
||||
.button.ghost {
|
||||
background: transparent;
|
||||
color: ${bdTheme('foreground')};
|
||||
border-color: transparent;
|
||||
color: ${bdTheme('hsl(0 0% 40%)', 'hsl(0 0% 70%)')};
|
||||
}
|
||||
|
||||
.button.ghost:hover:not(.disabled) {
|
||||
background: ${bdTheme('accent')};
|
||||
color: ${bdTheme('accentForeground')};
|
||||
border-color: transparent;
|
||||
color: ${bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 95%)')};
|
||||
background: ${bdTheme('hsl(0 0% 0% / 0.05)', 'hsl(0 0% 100% / 0.05)')};
|
||||
}
|
||||
|
||||
.button.ghost:active:not(.disabled) {
|
||||
background: ${bdTheme('accent')};
|
||||
opacity: 0.8;
|
||||
background: ${bdTheme('hsl(0 0% 0% / 0.1)', 'hsl(0 0% 100% / 0.1)')};
|
||||
}
|
||||
|
||||
/* Status states */
|
||||
@@ -214,13 +220,31 @@ export class SioButton extends DeesElement {
|
||||
.button.disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
/* Focus state */
|
||||
.button:focus-visible {
|
||||
outline: 2px solid ${bdTheme('ring')};
|
||||
outline: 2px solid ${bdTheme('hsl(0 0% 15% / 0.2)', 'hsl(0 0% 95% / 0.2)')};
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Icon sizing within buttons */
|
||||
.button sio-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.button.size-sm sio-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.button.size-lg sio-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -260,6 +284,7 @@ export class SioButton extends DeesElement {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Let the native click bubble normally
|
||||
// Don't dispatch a custom event to avoid double-triggering
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ export class SioCombox extends DeesElement {
|
||||
public static demo = () => html` <sio-combox></sio-combox> `;
|
||||
|
||||
@property({ type: Object })
|
||||
public referenceObject: HTMLElement;
|
||||
public accessor referenceObject: HTMLElement;
|
||||
|
||||
@state()
|
||||
private selectedConversationId: string | null = null;
|
||||
private accessor selectedConversationId: string | null = null;
|
||||
|
||||
@state()
|
||||
private conversations: IConversation[] = [
|
||||
private accessor conversations: IConversation[] = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Technical Support',
|
||||
@@ -72,7 +72,7 @@ export class SioCombox extends DeesElement {
|
||||
];
|
||||
|
||||
@state()
|
||||
private messages: { [conversationId: string]: IMessage[] } = {
|
||||
private accessor messages: { [conversationId: string]: IMessage[] } = {
|
||||
'1': [
|
||||
{ id: '1', text: 'Hi, I\'m having trouble logging in', sender: 'user', time: '10:00 AM' },
|
||||
{ id: '2', text: 'I can help you with that. Can you tell me what error you\'re seeing?', sender: 'support', time: '10:02 AM' },
|
||||
|
||||
@@ -38,13 +38,13 @@ export class SioConversationSelector extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: Array })
|
||||
public conversations: IConversation[] = [];
|
||||
public accessor conversations: IConversation[] = [];
|
||||
|
||||
@property({ type: String })
|
||||
public selectedConversationId: string | null = null;
|
||||
public accessor selectedConversationId: string | null = null;
|
||||
|
||||
@state()
|
||||
private searchQuery: string = '';
|
||||
private accessor searchQuery: string = '';
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
|
||||
@@ -15,9 +15,11 @@ import { colors, bdTheme } from './00colors.js';
|
||||
import { spacing, radius, shadows, transitions } from './00tokens.js';
|
||||
import { fontFamilies, typography } from './00fonts.js';
|
||||
import { SioDropdownMenu, type IDropdownMenuItem } from './sio-dropdown-menu.js';
|
||||
import { SioMessageInput } from './sio-message-input.js';
|
||||
|
||||
// Make sure components are loaded
|
||||
SioDropdownMenu;
|
||||
SioMessageInput;
|
||||
|
||||
// Types
|
||||
export interface IAttachment {
|
||||
@@ -57,22 +59,19 @@ export class SioConversationView extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: Object })
|
||||
public conversation: IConversationData | null = null;
|
||||
public accessor conversation: IConversationData | null = null;
|
||||
|
||||
@state()
|
||||
private messageText: string = '';
|
||||
private accessor isTyping: boolean = false;
|
||||
|
||||
@state()
|
||||
private isTyping: boolean = false;
|
||||
private accessor isDragging: boolean = false;
|
||||
|
||||
@state()
|
||||
private isDragging: boolean = false;
|
||||
private accessor uploadingFiles: Map<string, { file: File; progress: number }> = new Map();
|
||||
|
||||
@state()
|
||||
private uploadingFiles: Map<string, { file: File; progress: number }> = new Map();
|
||||
|
||||
@state()
|
||||
private pendingAttachments: IAttachment[] = [];
|
||||
private accessor pendingAttachments: IAttachment[] = [];
|
||||
|
||||
private dropdownMenuItems: IDropdownMenuItem[] = [
|
||||
{ id: 'mute', label: 'Mute notifications', icon: 'bell-off' },
|
||||
@@ -238,45 +237,6 @@ export class SioConversationView extends DeesElement {
|
||||
-webkit-backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
display: flex;
|
||||
gap: ${unsafeCSS(spacing["2"])};
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
flex: 1;
|
||||
min-height: 42px;
|
||||
max-height: 120px;
|
||||
padding: ${unsafeCSS(spacing["2.5"])} ${unsafeCSS(spacing[3])};
|
||||
background: ${bdTheme('secondary')};
|
||||
border: 1px solid ${bdTheme('border')};
|
||||
border-radius: ${unsafeCSS(radius.xl)};
|
||||
font-size: 0.9375rem;
|
||||
color: ${bdTheme('foreground')};
|
||||
outline: none;
|
||||
resize: none;
|
||||
font-family: ${unsafeCSS(fontFamilies.sans)};
|
||||
line-height: 1.5;
|
||||
transition: ${unsafeCSS(transitions.all)};
|
||||
}
|
||||
|
||||
.message-input::placeholder {
|
||||
color: ${bdTheme('mutedForeground')};
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.message-input:focus {
|
||||
border-color: ${bdTheme('ring')};
|
||||
background: ${bdTheme('background')};
|
||||
box-shadow: 0 0 0 3px ${bdTheme('ring')}15;
|
||||
}
|
||||
|
||||
.input-actions {
|
||||
display: flex;
|
||||
gap: ${unsafeCSS(spacing["1"])};
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
@@ -440,7 +400,8 @@ export class SioConversationView extends DeesElement {
|
||||
.pending-attachments {
|
||||
padding: ${unsafeCSS(spacing["2"])} ${unsafeCSS(spacing["3"])};
|
||||
background: ${bdTheme('secondary')};
|
||||
border-radius: ${unsafeCSS(radius.md)};
|
||||
border: 1px solid ${bdTheme('border')};
|
||||
border-radius: ${unsafeCSS(radius.lg)};
|
||||
margin-bottom: ${unsafeCSS(spacing["2"])};
|
||||
}
|
||||
|
||||
@@ -480,10 +441,6 @@ export class SioConversationView extends DeesElement {
|
||||
.remove-attachment:hover {
|
||||
color: ${bdTheme('destructive')};
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
@@ -606,41 +563,10 @@ export class SioConversationView extends DeesElement {
|
||||
`)}
|
||||
</div>
|
||||
` : ''}
|
||||
<div class="input-wrapper">
|
||||
<textarea
|
||||
class="message-input"
|
||||
placeholder="Type a message..."
|
||||
.value=${this.messageText}
|
||||
@input=${this.handleInput}
|
||||
@keydown=${this.handleKeyDown}
|
||||
rows="1"
|
||||
></textarea>
|
||||
<div class="input-actions">
|
||||
<input
|
||||
type="file"
|
||||
class="file-input"
|
||||
id="fileInput"
|
||||
multiple
|
||||
accept="image/*,.pdf,.doc,.docx,.txt"
|
||||
@change=${this.handleFileSelect}
|
||||
/>
|
||||
<sio-button type="ghost" size="sm" @click=${(e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
this.openFileSelector();
|
||||
}}>
|
||||
<sio-icon icon="paperclip" size="16"></sio-icon>
|
||||
</sio-button>
|
||||
<sio-button
|
||||
type="primary"
|
||||
size="sm"
|
||||
?disabled=${!this.messageText.trim() && this.pendingAttachments.length === 0}
|
||||
@click=${this.sendMessage}
|
||||
>
|
||||
<sio-icon icon="send" size="16"></sio-icon>
|
||||
</sio-button>
|
||||
</div>
|
||||
</div>
|
||||
<sio-message-input
|
||||
@send-message=${this.handleMessageSend}
|
||||
@files-selected=${this.handleFilesSelected}
|
||||
></sio-message-input>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -652,28 +578,14 @@ export class SioConversationView extends DeesElement {
|
||||
}));
|
||||
}
|
||||
|
||||
private handleInput(e: Event) {
|
||||
const textarea = e.target as HTMLTextAreaElement;
|
||||
this.messageText = textarea.value;
|
||||
private handleMessageSend(event: CustomEvent) {
|
||||
const { text, attachments } = event.detail;
|
||||
|
||||
// Auto-resize textarea
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
|
||||
}
|
||||
|
||||
private handleKeyDown(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
this.sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private sendMessage() {
|
||||
if (!this.messageText.trim() && this.pendingAttachments.length === 0) return;
|
||||
if (!text.trim() && attachments.length === 0) return;
|
||||
|
||||
const message: IMessage = {
|
||||
id: Date.now().toString(),
|
||||
text: this.messageText.trim(),
|
||||
text: text.trim(),
|
||||
sender: 'user',
|
||||
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
||||
status: 'sending',
|
||||
@@ -687,13 +599,8 @@ export class SioConversationView extends DeesElement {
|
||||
composed: true
|
||||
}));
|
||||
|
||||
// Clear input and attachments
|
||||
this.messageText = '';
|
||||
// Clear pending attachments
|
||||
this.pendingAttachments = [];
|
||||
const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement;
|
||||
if (textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
}
|
||||
|
||||
// Simulate typing indicator (remove in production)
|
||||
setTimeout(() => {
|
||||
@@ -704,6 +611,13 @@ export class SioConversationView extends DeesElement {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
private handleFilesSelected(event: CustomEvent) {
|
||||
const { files } = event.detail;
|
||||
// Handle files if needed
|
||||
// For now, we're handling attachments separately in the parent component
|
||||
}
|
||||
|
||||
|
||||
public updated() {
|
||||
// Scroll to bottom when new messages arrive
|
||||
const container = this.shadowRoot?.querySelector('#messages');
|
||||
|
||||
@@ -49,13 +49,13 @@ export class SioDropdownMenu extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: Array })
|
||||
public items: IDropdownMenuItem[] = [];
|
||||
public accessor items: IDropdownMenuItem[] = [];
|
||||
|
||||
@property({ type: String })
|
||||
public align: 'left' | 'right' = 'right';
|
||||
public accessor align: 'left' | 'right' = 'right';
|
||||
|
||||
@state()
|
||||
private isOpen: boolean = false;
|
||||
private accessor isOpen: boolean = false;
|
||||
|
||||
private documentClickHandler: (e: MouseEvent) => void;
|
||||
private scrollHandler: () => void;
|
||||
|
||||
@@ -29,13 +29,13 @@ declare global {
|
||||
@customElement('sio-fab')
|
||||
export class SioFab extends DeesElement {
|
||||
@property({ type: Boolean })
|
||||
public showCombox = false;
|
||||
public accessor showCombox = false;
|
||||
|
||||
@state()
|
||||
private hasShownOnce = false;
|
||||
private accessor hasShownOnce = false;
|
||||
|
||||
@state()
|
||||
private shouldPulse = false;
|
||||
private accessor shouldPulse = false;
|
||||
|
||||
public static demo = () => html` <sio-fab .showCombox=${true}></sio-fab> `;
|
||||
|
||||
|
||||
@@ -29,16 +29,16 @@ export class SioIcon extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: String })
|
||||
public icon: string;
|
||||
public accessor icon: string;
|
||||
|
||||
@property({ type: Number })
|
||||
public size: number = 24;
|
||||
public accessor size: number = 24;
|
||||
|
||||
@property({ type: String })
|
||||
public color: string = 'currentColor';
|
||||
public accessor color: string = 'currentColor';
|
||||
|
||||
@property({ type: Number })
|
||||
public strokeWidth: number = 2;
|
||||
public accessor strokeWidth: number = 2;
|
||||
|
||||
// Cache for rendered icons
|
||||
private static iconCache = new Map<string, string>();
|
||||
|
||||
@@ -46,11 +46,11 @@ export class SioImageLightbox extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: Boolean })
|
||||
public isOpen: boolean = false;
|
||||
public accessor isOpen: boolean = false;
|
||||
|
||||
@property({ type: Object })
|
||||
public file: ILightboxFile | null = null;
|
||||
|
||||
public accessor file: ILightboxFile | null = null;
|
||||
|
||||
// For backwards compatibility
|
||||
public get image(): ILightboxFile | null {
|
||||
return this.file;
|
||||
@@ -60,16 +60,16 @@ export class SioImageLightbox extends DeesElement {
|
||||
}
|
||||
|
||||
@state()
|
||||
private fileLoaded: boolean = false;
|
||||
private accessor fileLoaded: boolean = false;
|
||||
|
||||
@state()
|
||||
private scale: number = 1;
|
||||
private accessor scale: number = 1;
|
||||
|
||||
@state()
|
||||
private translateX: number = 0;
|
||||
private accessor translateX: number = 0;
|
||||
|
||||
@state()
|
||||
private translateY: number = 0;
|
||||
private accessor translateY: number = 0;
|
||||
|
||||
private isDragging: boolean = false;
|
||||
private startX: number = 0;
|
||||
|
||||
279
ts_web/elements/sio-message-input.ts
Normal file
279
ts_web/elements/sio-message-input.ts
Normal file
@@ -0,0 +1,279 @@
|
||||
import {
|
||||
DeesElement,
|
||||
property,
|
||||
html,
|
||||
customElement,
|
||||
type TemplateResult,
|
||||
cssManager,
|
||||
css,
|
||||
unsafeCSS,
|
||||
state,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
// Import design tokens
|
||||
import { colors, bdTheme } from './00colors.js';
|
||||
import { spacing, radius, shadows, transitions } from './00tokens.js';
|
||||
import { fontFamilies, typography } from './00fonts.js';
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'sio-message-input': SioMessageInput;
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('sio-message-input')
|
||||
export class SioMessageInput extends DeesElement {
|
||||
public static demo = () => html`
|
||||
<sio-message-input style="width: 600px;"></sio-message-input>
|
||||
`;
|
||||
|
||||
@property({ type: String })
|
||||
public accessor placeholder: string = 'Type a message...';
|
||||
|
||||
@property({ type: Boolean })
|
||||
public accessor disabled: boolean = false;
|
||||
|
||||
@state()
|
||||
private accessor messageText: string = '';
|
||||
|
||||
@state()
|
||||
private accessor pendingAttachments: File[] = [];
|
||||
|
||||
public static styles = [
|
||||
cssManager.defaultStyles,
|
||||
css`
|
||||
:host {
|
||||
display: block;
|
||||
font-family: ${unsafeCSS(fontFamilies.sans)};
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
background: ${bdTheme('secondary')};
|
||||
border: 1px solid ${bdTheme('border')};
|
||||
border-radius: 24px;
|
||||
padding: 2px;
|
||||
transition: all 200ms ease;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.input-container:focus-within {
|
||||
border-color: ${bdTheme('ring')};
|
||||
background: ${bdTheme('background')};
|
||||
}
|
||||
|
||||
.message-input {
|
||||
flex: 1;
|
||||
min-height: 44px;
|
||||
max-height: 120px;
|
||||
padding: 12px 16px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 15px;
|
||||
color: ${bdTheme('foreground')};
|
||||
outline: none;
|
||||
resize: none;
|
||||
font-family: ${unsafeCSS(fontFamilies.sans)};
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.message-input::placeholder {
|
||||
color: ${bdTheme('mutedForeground')};
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: ${bdTheme('mutedForeground')};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 120ms ease;
|
||||
position: relative;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.action-button:hover {
|
||||
color: ${bdTheme('foreground')};
|
||||
background: ${bdTheme('hsl(0 0% 0% / 0.05)', 'hsl(0 0% 100% / 0.05)')};
|
||||
}
|
||||
|
||||
.action-button:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.action-button.attachment {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.action-button.attachment:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.action-button.send {
|
||||
background: ${bdTheme('primary')};
|
||||
color: white;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.action-button.send:hover {
|
||||
background: ${bdTheme('hsl(221 83% 49%)', 'hsl(217 91% 65%)')};
|
||||
}
|
||||
|
||||
.action-button.send:disabled {
|
||||
opacity: 0.3;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.action-button.send:disabled:hover {
|
||||
background: ${bdTheme('primary')};
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Icon styles */
|
||||
sio-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.action-button.send sio-icon {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
|
||||
public render(): TemplateResult {
|
||||
return html`
|
||||
<div class="input-container">
|
||||
<textarea
|
||||
class="message-input"
|
||||
placeholder="${this.placeholder}"
|
||||
.value=${this.messageText}
|
||||
@input=${this.handleInput}
|
||||
@keydown=${this.handleKeyDown}
|
||||
?disabled=${this.disabled}
|
||||
rows="1"
|
||||
></textarea>
|
||||
|
||||
<div class="action-buttons">
|
||||
<input
|
||||
type="file"
|
||||
class="file-input"
|
||||
id="fileInput"
|
||||
multiple
|
||||
accept="image/*,.pdf,.doc,.docx,.txt"
|
||||
@change=${this.handleFileSelect}
|
||||
/>
|
||||
<button
|
||||
class="action-button attachment"
|
||||
@click=${this.openFileSelector}
|
||||
?disabled=${this.disabled}
|
||||
>
|
||||
<sio-icon icon="paperclip"></sio-icon>
|
||||
</button>
|
||||
<button
|
||||
class="action-button send"
|
||||
?disabled=${!this.messageText.trim() || this.disabled}
|
||||
@click=${this.sendMessage}
|
||||
>
|
||||
<sio-icon icon="send"></sio-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
private handleInput(event: Event) {
|
||||
const textarea = event.target as HTMLTextAreaElement;
|
||||
this.messageText = textarea.value;
|
||||
|
||||
// Auto-resize textarea
|
||||
textarea.style.height = 'auto';
|
||||
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||
}
|
||||
|
||||
private handleKeyDown(event: KeyboardEvent) {
|
||||
if (event.key === 'Enter' && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
this.sendMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private sendMessage() {
|
||||
if (!this.messageText.trim() && this.pendingAttachments.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dispatchEvent(new CustomEvent('send-message', {
|
||||
detail: {
|
||||
text: this.messageText,
|
||||
attachments: this.pendingAttachments
|
||||
},
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
|
||||
// Clear input
|
||||
this.messageText = '';
|
||||
this.pendingAttachments = [];
|
||||
|
||||
// Reset textarea height
|
||||
const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement;
|
||||
if (textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
}
|
||||
}
|
||||
|
||||
private openFileSelector() {
|
||||
const fileInput = this.shadowRoot?.querySelector('#fileInput') as HTMLInputElement;
|
||||
if (fileInput) {
|
||||
fileInput.click();
|
||||
}
|
||||
}
|
||||
|
||||
private handleFileSelect(event: Event) {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const files = Array.from(input.files || []);
|
||||
|
||||
this.pendingAttachments = [...this.pendingAttachments, ...files];
|
||||
|
||||
this.dispatchEvent(new CustomEvent('files-selected', {
|
||||
detail: { files },
|
||||
bubbles: true,
|
||||
composed: true
|
||||
}));
|
||||
|
||||
input.value = ''; // Clear input for re-selection
|
||||
}
|
||||
|
||||
public focus() {
|
||||
const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement;
|
||||
textarea?.focus();
|
||||
}
|
||||
|
||||
public clear() {
|
||||
this.messageText = '';
|
||||
this.pendingAttachments = [];
|
||||
const textarea = this.shadowRoot?.querySelector('.message-input') as HTMLTextAreaElement;
|
||||
if (textarea) {
|
||||
textarea.style.height = 'auto';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
css,
|
||||
unsafeCSS,
|
||||
state,
|
||||
type PropertyValues,
|
||||
} from '@design.estate/dees-element';
|
||||
|
||||
// Import design tokens
|
||||
@@ -37,28 +36,28 @@ export class SioPdfViewer extends DeesElement {
|
||||
`;
|
||||
|
||||
@property({ type: String })
|
||||
public url: string = '';
|
||||
public accessor url: string = '';
|
||||
|
||||
@property({ type: String })
|
||||
public fileName: string = 'document.pdf';
|
||||
public accessor fileName: string = 'document.pdf';
|
||||
|
||||
@state()
|
||||
private isLoading: boolean = true;
|
||||
private accessor isLoading: boolean = true;
|
||||
|
||||
@state()
|
||||
private hasError: boolean = false;
|
||||
|
||||
private accessor hasError: boolean = false;
|
||||
|
||||
@state()
|
||||
private pdfDocument: any = null;
|
||||
|
||||
private accessor pdfDocument: any = null;
|
||||
|
||||
@state()
|
||||
private currentPage: number = 1;
|
||||
|
||||
private accessor currentPage: number = 1;
|
||||
|
||||
@state()
|
||||
private totalPages: number = 0;
|
||||
|
||||
private accessor totalPages: number = 0;
|
||||
|
||||
@state()
|
||||
private scale: number = 1;
|
||||
private accessor scale: number = 1;
|
||||
|
||||
private static pdfJsLoaded: boolean = false;
|
||||
private static pdfJsLoading: Promise<void> | null = null;
|
||||
@@ -399,7 +398,7 @@ export class SioPdfViewer extends DeesElement {
|
||||
}
|
||||
}
|
||||
|
||||
public async firstUpdated(_changedProperties: PropertyValues) {
|
||||
public async firstUpdated(_changedProperties: any) {
|
||||
super.firstUpdated(_changedProperties);
|
||||
|
||||
// Set up resize observer for responsive rendering after first render
|
||||
|
||||
@@ -47,7 +47,7 @@ export class SioRecorder extends DeesElement {
|
||||
* Query for the div in our template that will be used for playback.
|
||||
*/
|
||||
@query('#playback')
|
||||
private playbackDiv!: HTMLDivElement;
|
||||
private accessor playbackDiv!: HTMLDivElement;
|
||||
|
||||
static styles = css`
|
||||
:host {
|
||||
|
||||
@@ -12,7 +12,7 @@ export const mainpage = () => html`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
padding: 0;
|
||||
}
|
||||
.demo-section {
|
||||
background: white;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"useDefineForClassFields": false,
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"esModuleInterop": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {}
|
||||
},
|
||||
"exclude": [
|
||||
"dist_*/**/*.d.ts"
|
||||
|
||||
Reference in New Issue
Block a user