xertica-ui 2.1.2 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/README.md +1 -1
- package/bin/cli.ts +1 -1
- package/bin/generate-tokens.ts +13 -7
- package/components/assistant/xertica-assistant/index.ts +2 -0
- package/components/assistant/xertica-assistant/parts/AssistantCollapsedView.tsx +97 -0
- package/components/assistant/xertica-assistant/parts/AssistantConversationList.tsx +104 -0
- package/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.tsx +81 -0
- package/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.tsx +86 -0
- package/components/assistant/xertica-assistant/parts/AssistantHeader.tsx +77 -0
- package/components/assistant/xertica-assistant/parts/AssistantMessageBubble.tsx +573 -0
- package/components/assistant/xertica-assistant/parts/AssistantTabBar.tsx +65 -0
- package/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.tsx +41 -0
- package/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.tsx +98 -0
- package/components/assistant/xertica-assistant/parts/index.ts +16 -0
- package/components/assistant/xertica-assistant/types.ts +139 -0
- package/components/assistant/xertica-assistant/use-assistant.ts +559 -0
- package/components/assistant/xertica-assistant/xertica-assistant.stories.tsx +200 -0
- package/components/assistant/xertica-assistant/xertica-assistant.tsx +198 -1460
- package/components/brand/theme-toggle/ThemeToggle.tsx +8 -27
- package/components/hooks/index.ts +3 -0
- package/components/hooks/use-layout-shortcuts.ts +46 -0
- package/components/layout/sidebar/index.ts +2 -0
- package/components/layout/sidebar/sidebar.stories.tsx +160 -8
- package/components/layout/sidebar/sidebar.tsx +606 -497
- package/components/layout/sidebar/use-sidebar.ts +104 -0
- package/components/media/audio-player/AudioPlayer.tsx +131 -206
- package/components/media/audio-player/use-audio-player.ts +298 -0
- package/components/pages/home-page/HomePage.tsx +1 -1
- package/components/pages/template-content/TemplateContent.tsx +5 -5
- package/components/pages/template-page/TemplatePage.tsx +5 -5
- package/components/shared/CustomTooltipContent.tsx +52 -0
- package/components/shared/layout-constants.ts +1 -1
- package/components/ui/chart/chart.stories.tsx +966 -7
- package/components/ui/chart/chart.tsx +918 -45
- package/components/ui/file-upload/file-upload.stories.tsx +100 -0
- package/components/ui/file-upload/file-upload.tsx +14 -74
- package/components/ui/file-upload/index.ts +1 -0
- package/components/ui/file-upload/use-file-upload.ts +181 -0
- package/components/ui/pagination/index.ts +2 -0
- package/components/ui/pagination/pagination.stories.tsx +94 -0
- package/components/ui/pagination/use-pagination.ts +194 -0
- package/components/ui/rich-text-editor/index.ts +2 -0
- package/components/ui/rich-text-editor/rich-text-editor.stories.tsx +129 -1
- package/components/ui/rich-text-editor/rich-text-editor.tsx +86 -305
- package/components/ui/rich-text-editor/use-rich-text-editor.ts +439 -0
- package/components/ui/stepper/index.ts +3 -1
- package/components/ui/stepper/stepper.stories.tsx +116 -0
- package/components/ui/stepper/stepper.tsx +4 -4
- package/components/ui/stepper/use-stepper.ts +137 -0
- package/components/ui/tree-view/index.ts +4 -1
- package/components/ui/tree-view/tree-view.stories.tsx +110 -4
- package/components/ui/tree-view/tree-view.tsx +17 -125
- package/components/ui/tree-view/use-tree-view.ts +229 -0
- package/contexts/AssistenteContext.tsx +17 -54
- package/contexts/BrandColorsContext.tsx +6 -17
- package/contexts/LayoutContext.tsx +5 -31
- package/dist/AssistantChart-BAudAfne.cjs +3591 -0
- package/dist/AssistantChart-BP8upjMk.js +3565 -0
- package/dist/AudioPlayer-1ypwE2Wh.cjs +936 -0
- package/dist/AudioPlayer-DuKXrCfy.js +937 -0
- package/dist/CustomTooltipContent-DHjkY0ww.js +40 -0
- package/dist/CustomTooltipContent-c_K-DWRr.cjs +56 -0
- package/dist/LanguageContext-BwhwC3G2.js +657 -0
- package/dist/LanguageContext-DvUt5jBg.cjs +656 -0
- package/dist/LayoutContext-BDmcZfMH.cjs +84 -0
- package/dist/LayoutContext-dbQvdC4O.js +85 -0
- package/dist/ThemeContext-RTy1m2Uq.js +82 -0
- package/dist/ThemeContext-bSzuOit2.cjs +81 -0
- package/dist/VerifyEmailPage-C_ihbcth.js +2828 -0
- package/dist/VerifyEmailPage-Dt7zgA4w.cjs +2827 -0
- package/dist/XerticaProvider-CW9hpCdF.cjs +39 -0
- package/dist/XerticaProvider-siSt9uG2.js +40 -0
- package/dist/XerticaXLogo-D8jf0SNv.cjs +214 -0
- package/dist/XerticaXLogo-fAJMy3H4.js +215 -0
- package/dist/assistant.cjs.js +2 -1
- package/dist/assistant.es.js +3 -2
- package/dist/brand.cjs.js +2 -2
- package/dist/brand.es.js +2 -2
- package/dist/cli.js +14 -8
- package/dist/components/assistant/xertica-assistant/index.d.ts +2 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantCollapsedView.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantConversationList.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantDocumentEditor.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantFeedbackDialog.d.ts +19 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantHeader.d.ts +11 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantMessageBubble.d.ts +29 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTabBar.d.ts +13 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantTypingIndicator.d.ts +4 -0
- package/dist/components/assistant/xertica-assistant/parts/AssistantWelcomeScreen.d.ts +17 -0
- package/dist/components/assistant/xertica-assistant/parts/index.d.ts +16 -0
- package/dist/components/assistant/xertica-assistant/types.d.ts +106 -0
- package/dist/components/assistant/xertica-assistant/use-assistant.d.ts +125 -0
- package/dist/components/assistant/xertica-assistant/xertica-assistant.d.ts +8 -97
- package/dist/components/hooks/index.d.ts +3 -0
- package/dist/components/hooks/use-layout-shortcuts.d.ts +22 -0
- package/dist/components/layout/sidebar/index.d.ts +2 -0
- package/dist/components/layout/sidebar/sidebar.d.ts +80 -0
- package/dist/components/layout/sidebar/use-sidebar.d.ts +22 -0
- package/dist/components/media/audio-player/AudioPlayer.d.ts +4 -1
- package/dist/components/media/audio-player/use-audio-player.d.ts +72 -0
- package/dist/components/shared/CustomTooltipContent.d.ts +20 -0
- package/dist/components/shared/layout-constants.d.ts +1 -1
- package/dist/components/ui/alert/alert.d.ts +1 -1
- package/dist/components/ui/badge/badge.d.ts +1 -1
- package/dist/components/ui/button/button.d.ts +2 -2
- package/dist/components/ui/chart/chart.d.ts +162 -5
- package/dist/components/ui/file-upload/file-upload.d.ts +2 -0
- package/dist/components/ui/file-upload/index.d.ts +1 -0
- package/dist/components/ui/file-upload/use-file-upload.d.ts +49 -0
- package/dist/components/ui/pagination/index.d.ts +2 -0
- package/dist/components/ui/pagination/use-pagination.d.ts +78 -0
- package/dist/components/ui/rich-text-editor/index.d.ts +2 -0
- package/dist/components/ui/rich-text-editor/use-rich-text-editor.d.ts +107 -0
- package/dist/components/ui/stepper/index.d.ts +3 -1
- package/dist/components/ui/stepper/stepper.d.ts +2 -2
- package/dist/components/ui/stepper/use-stepper.d.ts +60 -0
- package/dist/components/ui/tree-view/index.d.ts +4 -1
- package/dist/components/ui/tree-view/tree-view.d.ts +4 -6
- package/dist/components/ui/tree-view/use-tree-view.d.ts +60 -0
- package/dist/contexts/AssistenteContext.d.ts +10 -49
- package/dist/hooks.cjs.js +30 -10
- package/dist/hooks.es.js +25 -4
- package/dist/index.cjs.js +20 -9
- package/dist/index.es.js +38 -27
- package/dist/layout.cjs.js +82 -1
- package/dist/layout.es.js +83 -2
- package/dist/media.cjs.js +1 -1
- package/dist/media.es.js +1 -1
- package/dist/pages.cjs.js +1 -1
- package/dist/pages.es.js +1 -1
- package/dist/rich-text-editor-BmsjY03B.js +2949 -0
- package/dist/rich-text-editor-GS2kpTAK.cjs +2966 -0
- package/dist/sidebar-CVUGHOS_.cjs +756 -0
- package/dist/sidebar-CmvwjnVb.js +757 -0
- package/dist/ui.cjs.js +12 -2
- package/dist/ui.es.js +24 -14
- package/dist/use-audio-player-Bkh23vQ3.js +177 -0
- package/dist/use-audio-player-Dn1NR9xN.cjs +176 -0
- package/dist/utils/color-utils.d.ts +51 -0
- package/dist/xertica-assistant-BMqdyRVi.js +2082 -0
- package/dist/xertica-assistant-Bj3vBCq_.cjs +2081 -0
- package/dist/xertica-ui.css +1 -1
- package/docs/ai-usage.md +28 -10
- package/docs/architecture-improvements.md +463 -0
- package/docs/architecture.md +77 -1
- package/docs/components/assistant-chart.md +1 -1
- package/docs/components/assistant.md +159 -0
- package/docs/components/audio-player.md +46 -0
- package/docs/components/branding.md +251 -0
- package/docs/components/chart.md +354 -39
- package/docs/components/code-block.md +108 -0
- package/docs/components/file-upload.md +119 -2
- package/docs/components/formatted-document.md +113 -0
- package/docs/components/hooks.md +430 -0
- package/docs/components/image-with-fallback.md +106 -0
- package/docs/components/map-layers.md +140 -0
- package/docs/components/modern-chat-input.md +163 -0
- package/docs/components/pages.md +351 -0
- package/docs/components/pagination.md +187 -0
- package/docs/components/rich-text-editor.md +164 -0
- package/docs/components/sidebar.md +153 -4
- package/docs/components/stepper.md +157 -12
- package/docs/components/tree-view.md +164 -6
- package/docs/doc-audit.md +223 -0
- package/docs/getting-started.md +155 -1
- package/docs/guidelines.md +14 -8
- package/docs/layout.md +2 -2
- package/docs/llms.md +29 -9
- package/docs/patterns/detail-page.md +276 -0
- package/docs/patterns/settings.md +346 -0
- package/docs/patterns/wizard.md +217 -0
- package/guidelines/Guidelines.md +5 -3
- package/llms.txt +1 -1
- package/package.json +10 -10
- package/styles/xertica/tokens.css +41 -12
- package/templates/CLAUDE.md +16 -6
- package/templates/guidelines/Guidelines.md +16 -4
- package/templates/package.json +3 -3
- package/templates/src/styles/xertica/tokens.css +39 -10
- package/utils/color-utils.ts +72 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# ImageWithFallback
|
|
2
|
+
|
|
3
|
+
A drop-in replacement for the native `<img>` element that gracefully handles broken or missing image URLs by displaying a placeholder SVG instead of a broken image icon.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { ImageWithFallback } from 'xertica-ui';
|
|
11
|
+
// or from the figma subpath (internal)
|
|
12
|
+
import { ImageWithFallback } from 'xertica-ui/ui';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
<ImageWithFallback
|
|
21
|
+
src="https://example.com/photo.jpg"
|
|
22
|
+
alt="User profile photo"
|
|
23
|
+
className="w-32 h-32 rounded-lg object-cover"
|
|
24
|
+
/>
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Props
|
|
30
|
+
|
|
31
|
+
`ImageWithFallback` accepts all standard HTML `<img>` attributes:
|
|
32
|
+
|
|
33
|
+
| Prop | Type | Description |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| `src` | `string` | Image URL. If this fails to load, the fallback placeholder is shown. |
|
|
36
|
+
| `alt` | `string` | Accessible alternative text (required for accessibility) |
|
|
37
|
+
| `className` | `string` | CSS classes applied to both the `<img>` and the fallback container |
|
|
38
|
+
| `style` | `CSSProperties` | Inline styles applied to both states |
|
|
39
|
+
| `...rest` | `ImgHTMLAttributes` | All other standard `<img>` attributes (`width`, `height`, `loading`, etc.) |
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Behavior
|
|
44
|
+
|
|
45
|
+
1. **Normal state**: Renders a standard `<img>` element with the provided `src`.
|
|
46
|
+
2. **Error state**: When the image fails to load (`onError` fires), the component switches to a fallback `<div>` containing a centered placeholder SVG (a simple broken-image icon).
|
|
47
|
+
3. **Fallback container**: The fallback `<div>` uses `bg-gray-100` and inherits the same `className` and `style` as the original image, so it maintains the same dimensions and shape.
|
|
48
|
+
4. **Original URL preserved**: The fallback `<img>` stores the original URL in `data-original-url` for debugging purposes.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Usage Examples
|
|
53
|
+
|
|
54
|
+
### Hero Image with Fallback
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
<ImageWithFallback
|
|
58
|
+
src={article.heroImageUrl}
|
|
59
|
+
alt={article.title}
|
|
60
|
+
className="w-full h-48 object-cover rounded-t-lg"
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### User Avatar with Fallback
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<ImageWithFallback
|
|
68
|
+
src={user.avatarUrl}
|
|
69
|
+
alt={`${user.name} avatar`}
|
|
70
|
+
className="w-10 h-10 rounded-full object-cover"
|
|
71
|
+
/>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
> **Note**: For user avatars, prefer the `<Avatar>` component which has built-in fallback support via `<AvatarFallback>` (shows initials). Use `ImageWithFallback` for non-avatar images.
|
|
75
|
+
|
|
76
|
+
### Lazy Loading
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
<ImageWithFallback
|
|
80
|
+
src={product.imageUrl}
|
|
81
|
+
alt={product.name}
|
|
82
|
+
loading="lazy"
|
|
83
|
+
className="w-full aspect-square object-contain"
|
|
84
|
+
/>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Comparison: `ImageWithFallback` vs `Avatar`
|
|
90
|
+
|
|
91
|
+
| Feature | `ImageWithFallback` | `Avatar` |
|
|
92
|
+
|---|---|---|
|
|
93
|
+
| Fallback type | SVG placeholder icon | Text initials |
|
|
94
|
+
| Use case | General images, hero images, thumbnails | User profile pictures |
|
|
95
|
+
| Shape | Any (controlled by `className`) | Circle (default) |
|
|
96
|
+
| Import | `xertica-ui/ui` | `xertica-ui/ui` |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## AI Rules
|
|
101
|
+
|
|
102
|
+
> [!IMPORTANT]
|
|
103
|
+
> - **Always provide `alt`**: The `alt` attribute is required for accessibility. Never omit it. Use an empty string (`alt=""`) only for purely decorative images.
|
|
104
|
+
> - **Use for external images**: Use `ImageWithFallback` whenever the image URL comes from an external source (API, user upload, CMS) that may be unavailable. For static local assets, a regular `<img>` is acceptable.
|
|
105
|
+
> - **Do not use for avatars**: For user profile pictures, use the `<Avatar>` + `<AvatarFallback>` pattern instead — it shows initials which is more informative than a broken-image icon.
|
|
106
|
+
> - **Maintain dimensions in fallback**: The fallback container inherits `className` and `style`, so always set explicit dimensions (via Tailwind classes like `w-32 h-32` or inline styles) to prevent layout shift when the fallback renders.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# MapLayers / useMapLayers
|
|
2
|
+
|
|
3
|
+
A hook for managing Google Maps native overlay layers (traffic, transit, bicycling) on a map instance. Used internally by the `Map` component via its `layers` prop.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { useMapLayers } from 'xertica-ui/ui';
|
|
11
|
+
// or
|
|
12
|
+
import { useMapLayers, MapLayersConfig } from 'xertica-ui';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## `useMapLayers`
|
|
18
|
+
|
|
19
|
+
A React hook that attaches and detaches Google Maps overlay layers reactively based on a configuration object.
|
|
20
|
+
|
|
21
|
+
### Signature
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
function useMapLayers(
|
|
25
|
+
map: google.maps.Map | null,
|
|
26
|
+
layers: MapLayersConfig
|
|
27
|
+
): void
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Parameters
|
|
31
|
+
|
|
32
|
+
| Parameter | Type | Description |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `map` | `google.maps.Map \| null` | The Google Maps instance to attach layers to. Pass `null` to skip (layers are not rendered). |
|
|
35
|
+
| `layers` | `MapLayersConfig` | Configuration object specifying which layers to display |
|
|
36
|
+
|
|
37
|
+
### `MapLayersConfig`
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
interface MapLayersConfig {
|
|
41
|
+
traffic?: boolean; // Real-time traffic overlay
|
|
42
|
+
transit?: boolean; // Public transit routes overlay
|
|
43
|
+
bicycling?: boolean; // Bicycle route overlay
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Available Layers
|
|
50
|
+
|
|
51
|
+
| Layer | Key | Description |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| Traffic | `traffic` | Real-time traffic conditions with color-coded road segments |
|
|
54
|
+
| Transit | `transit` | Public transit routes (bus, metro, train) |
|
|
55
|
+
| Bicycling | `bicycling` | Dedicated bicycle lanes and paths |
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Standalone Hook
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { useMapLayers } from 'xertica-ui/ui';
|
|
65
|
+
|
|
66
|
+
function MapWithLayers() {
|
|
67
|
+
const [mapInstance, setMapInstance] = useState<google.maps.Map | null>(null);
|
|
68
|
+
const [showTraffic, setShowTraffic] = useState(false);
|
|
69
|
+
const [showTransit, setShowTransit] = useState(false);
|
|
70
|
+
|
|
71
|
+
useMapLayers(mapInstance, {
|
|
72
|
+
traffic: showTraffic,
|
|
73
|
+
transit: showTransit,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<div>
|
|
78
|
+
<label>
|
|
79
|
+
<input
|
|
80
|
+
type="checkbox"
|
|
81
|
+
checked={showTraffic}
|
|
82
|
+
onChange={e => setShowTraffic(e.target.checked)}
|
|
83
|
+
/>
|
|
84
|
+
Traffic
|
|
85
|
+
</label>
|
|
86
|
+
{/* map container */}
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Via `Map` Component (Recommended)
|
|
93
|
+
|
|
94
|
+
The `Map` component accepts a `layers` prop that internally uses `useMapLayers`:
|
|
95
|
+
|
|
96
|
+
```tsx
|
|
97
|
+
import { Map } from 'xertica-ui/ui';
|
|
98
|
+
|
|
99
|
+
<Map
|
|
100
|
+
center={{ lat: -23.5505, lng: -46.6333 }}
|
|
101
|
+
zoom={12}
|
|
102
|
+
layers={{
|
|
103
|
+
traffic: true,
|
|
104
|
+
transit: false,
|
|
105
|
+
bicycling: false,
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Behavior
|
|
113
|
+
|
|
114
|
+
- **Reactive**: Layers are added or removed automatically when the `layers` config changes.
|
|
115
|
+
- **Cleanup**: Each layer is removed from the map on component unmount (via `useEffect` cleanup).
|
|
116
|
+
- **Null-safe**: If `map` is `null`, the hook does nothing. This is safe to use before the map instance is ready.
|
|
117
|
+
- **Singleton layers**: Each layer type is created once and reused (stored in refs). Toggling a layer on/off does not create new instances.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Prerequisites
|
|
122
|
+
|
|
123
|
+
The Google Maps JavaScript API must be loaded before using this hook. Use `GoogleMapsLoader` or `XerticaProvider` with a `googleMapsApiKey`:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import { XerticaProvider } from 'xertica-ui/brand';
|
|
127
|
+
|
|
128
|
+
<XerticaProvider googleMapsApiKey="YOUR_API_KEY">
|
|
129
|
+
<App />
|
|
130
|
+
</XerticaProvider>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## AI Rules
|
|
136
|
+
|
|
137
|
+
> [!IMPORTANT]
|
|
138
|
+
> - **Use via `Map` component when possible**: The `Map` component's `layers` prop is the recommended way to enable overlays. Use `useMapLayers` directly only when building a custom map integration.
|
|
139
|
+
> - **Requires Google Maps API**: This hook uses `google.maps.TrafficLayer`, `google.maps.TransitLayer`, and `google.maps.BicyclingLayer`. These are only available after the Maps JavaScript API is loaded.
|
|
140
|
+
> - **Pass `null` safely**: If the map instance is not yet available, pass `null` as the first argument. The hook will skip all operations until a valid map is provided.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# ModernChatInput
|
|
2
|
+
|
|
3
|
+
An advanced floating chat input with rich action chips, voice recording simulation, and file attachment support. Used as the primary input interface inside `XerticaAssistant`.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { ModernChatInput } from 'xertica-ui/assistant';
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Basic Usage
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
const [message, setMessage] = useState('');
|
|
19
|
+
|
|
20
|
+
<ModernChatInput
|
|
21
|
+
value={message}
|
|
22
|
+
onChange={setMessage}
|
|
23
|
+
onSubmit={() => {
|
|
24
|
+
console.log('Sending:', message);
|
|
25
|
+
setMessage('');
|
|
26
|
+
}}
|
|
27
|
+
/>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Props
|
|
33
|
+
|
|
34
|
+
| Prop | Type | Default | Description |
|
|
35
|
+
|---|---|---|---|
|
|
36
|
+
| `value` | `string` | _(required)_ | Current input text value |
|
|
37
|
+
| `onChange` | `(value: string) => void` | _(required)_ | Callback fired on every keystroke |
|
|
38
|
+
| `onSubmit` | `(action?: ActionType) => void` | _(required)_ | Callback fired when user submits (Enter key or send button) |
|
|
39
|
+
| `placeholder` | `string` | `'Mande uma mensagem para o Xertica'` | Input placeholder text |
|
|
40
|
+
| `disabled` | `boolean` | `false` | Disables the input and all action buttons |
|
|
41
|
+
| `onFileUpload` | `() => void` | — | Callback for the file attachment button |
|
|
42
|
+
| `onAudioUpload` | `() => void` | — | Callback for the audio upload button |
|
|
43
|
+
| `onVoiceRecording` | `(transcript: string) => void` | — | Callback fired when voice recording finishes |
|
|
44
|
+
| `isFullPage` | `boolean` | `false` | Adjusts layout for full-page assistant view |
|
|
45
|
+
| `enableAudioInput` | `boolean` | `true` | Shows/hides the voice recording button |
|
|
46
|
+
| `enableFileAttachment` | `boolean` | `true` | Shows/hides the file attachment button |
|
|
47
|
+
| `enableDocumentCreation` | `boolean` | `true` | Shows/hides the "Create document" action chip |
|
|
48
|
+
| `enablePodcastGeneration` | `boolean` | `true` | Shows/hides the "Generate podcast" action chip |
|
|
49
|
+
| `enableSearch` | `boolean` | `true` | Shows/hides the "Search" action chip |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## `ActionType`
|
|
54
|
+
|
|
55
|
+
The `onSubmit` callback receives an optional `ActionType` parameter indicating which special action was triggered:
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
type ActionType = 'document' | 'podcast' | 'search' | null;
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Value | Trigger | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `null` | Enter key or send button | Standard text message |
|
|
64
|
+
| `'document'` | "Create document" chip | Triggers document generation workflow |
|
|
65
|
+
| `'podcast'` | "Generate podcast" chip | Triggers audio podcast generation |
|
|
66
|
+
| `'search'` | "Search" chip | Triggers knowledge base search |
|
|
67
|
+
|
|
68
|
+
### Handling Actions
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<ModernChatInput
|
|
72
|
+
value={message}
|
|
73
|
+
onChange={setMessage}
|
|
74
|
+
onSubmit={(action) => {
|
|
75
|
+
if (action === 'document') {
|
|
76
|
+
// trigger document generation
|
|
77
|
+
} else if (action === 'podcast') {
|
|
78
|
+
// trigger podcast generation
|
|
79
|
+
} else if (action === 'search') {
|
|
80
|
+
// trigger search
|
|
81
|
+
} else {
|
|
82
|
+
// send regular message
|
|
83
|
+
}
|
|
84
|
+
setMessage('');
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Features
|
|
92
|
+
|
|
93
|
+
### Auto-Resizing Textarea
|
|
94
|
+
|
|
95
|
+
The input grows vertically as the user types, up to a maximum height of 100px. Beyond that, it becomes scrollable.
|
|
96
|
+
|
|
97
|
+
### Action Chips
|
|
98
|
+
|
|
99
|
+
A `+` button opens a popover with quick-action chips:
|
|
100
|
+
- **Document** (`FileText` icon) — triggers `onSubmit('document')`
|
|
101
|
+
- **Podcast** (`Radio` icon) — triggers `onSubmit('podcast')`
|
|
102
|
+
- **Search** (`Search` icon) — triggers `onSubmit('search')`
|
|
103
|
+
|
|
104
|
+
Each chip can be individually disabled via props.
|
|
105
|
+
|
|
106
|
+
### Voice Recording (Simulated)
|
|
107
|
+
|
|
108
|
+
When `enableAudioInput={true}`, a microphone button is shown. Clicking it:
|
|
109
|
+
1. Shows a recording indicator with a pulsing animation
|
|
110
|
+
2. After 3 seconds, calls `onVoiceRecording` with a simulated transcript string
|
|
111
|
+
3. Returns to idle state
|
|
112
|
+
|
|
113
|
+
> **Note**: Voice recording is simulated — it does not use the browser's MediaRecorder API. The transcript returned is a placeholder string for UI demonstration purposes.
|
|
114
|
+
|
|
115
|
+
### Keyboard Shortcuts
|
|
116
|
+
|
|
117
|
+
- **Enter** — submits the message
|
|
118
|
+
- **Shift+Enter** — inserts a newline (multi-line input)
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Usage with XerticaAssistant
|
|
123
|
+
|
|
124
|
+
`ModernChatInput` is used internally by `XerticaAssistant`. You typically do not need to use it directly unless building a custom chat interface:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { ModernChatInput } from 'xertica-ui/assistant';
|
|
128
|
+
import { useAssistant } from 'xertica-ui/assistant'; // internal hook
|
|
129
|
+
|
|
130
|
+
function CustomChatInterface() {
|
|
131
|
+
const [message, setMessage] = useState('');
|
|
132
|
+
|
|
133
|
+
const handleSubmit = (action?: ActionType) => {
|
|
134
|
+
// handle message or action
|
|
135
|
+
setMessage('');
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<div className="flex flex-col h-screen">
|
|
140
|
+
<div className="flex-1 overflow-y-auto">
|
|
141
|
+
{/* messages */}
|
|
142
|
+
</div>
|
|
143
|
+
<ModernChatInput
|
|
144
|
+
value={message}
|
|
145
|
+
onChange={setMessage}
|
|
146
|
+
onSubmit={handleSubmit}
|
|
147
|
+
isFullPage={true}
|
|
148
|
+
/>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## AI Rules
|
|
157
|
+
|
|
158
|
+
> [!IMPORTANT]
|
|
159
|
+
> - **Controlled component**: Always provide both `value` and `onChange`. This is a controlled input — do not use it uncontrolled.
|
|
160
|
+
> - **Clear after submit**: Call `setMessage('')` (or equivalent) inside `onSubmit` to reset the input after sending.
|
|
161
|
+
> - **`isFullPage` for page layouts**: Set `isFullPage={true}` when using the input in a full-page assistant view (not the sidebar panel). This adjusts padding and max-width.
|
|
162
|
+
> - **Voice recording is simulated**: Do not rely on `onVoiceRecording` for real speech-to-text. Integrate a real STT service and pass the transcript via `onChange` instead.
|
|
163
|
+
> - **Disable unused actions**: If your application does not support document generation or podcasts, set `enableDocumentCreation={false}` and `enablePodcastGeneration={false}` to avoid confusing users.
|