solid-tom-ui 1.0.11 → 1.0.15
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/README.md +246 -246
- package/dist/README.md +246 -246
- package/dist/components/avatar/avatar.js.map +1 -1
- package/dist/components/badge/badge.js.map +1 -1
- package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/carousel/carousel.js.map +1 -1
- package/dist/components/chat-bubble/chatBubble.js.map +1 -1
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/collapse/collapse.js.map +1 -1
- package/dist/components/context-menu/context-menu.js.map +1 -1
- package/dist/components/context-menu/context-menu.store.js.map +1 -1
- package/dist/components/divider/divider.js.map +1 -1
- package/dist/components/dropdown/dropdown.js.map +1 -1
- package/dist/components/dropdown/dropdown.store.js.map +1 -1
- package/dist/components/float-button/float-button.js.map +1 -1
- package/dist/components/hover-3d-image/hover-3d-image.js.map +1 -1
- package/dist/components/image-preview/image-preview.js.map +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/input/input.utils.js.map +1 -1
- package/dist/components/input/variants/input-color.js.map +1 -1
- package/dist/components/input/variants/input-date.js.map +1 -1
- package/dist/components/input/variants/input-number.d.ts.map +1 -1
- package/dist/components/input/variants/input-number.js +1 -1
- package/dist/components/input/variants/input-number.js.map +1 -1
- package/dist/components/input/variants/input-otp.js.map +1 -1
- package/dist/components/input/variants/input-password.js.map +1 -1
- package/dist/components/input/variants/input-radio.js.map +1 -1
- package/dist/components/input/variants/input-range.js.map +1 -1
- package/dist/components/input/variants/input-text.d.ts.map +1 -1
- package/dist/components/input/variants/input-text.js +1 -1
- package/dist/components/input/variants/input-text.js.map +1 -1
- package/dist/components/input/variants/input-textarea.js.map +1 -1
- package/dist/components/loading/loading.js.map +1 -1
- package/dist/components/mansory/mansory.js.map +1 -1
- package/dist/components/menu/menu.js.map +1 -1
- package/dist/components/modal/modal.js.map +1 -1
- package/dist/components/modal/modalContext.js.map +1 -1
- package/dist/components/pagination/pagination.js.map +1 -1
- package/dist/components/progress-bar/progress-bar.js.map +1 -1
- package/dist/components/qr-code/qr-code.js.map +1 -1
- package/dist/components/select/select.js +1 -1
- package/dist/components/select/select.js.map +1 -1
- package/dist/components/select-zone/select-zone.js.map +1 -1
- package/dist/components/skeleton/skeleton.js.map +1 -1
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/splitter/splitter.js.map +1 -1
- package/dist/components/steps/steps.js.map +1 -1
- package/dist/components/swap/swap.js.map +1 -1
- package/dist/components/switch/switch.js.map +1 -1
- package/dist/components/tab/tab.js.map +1 -1
- package/dist/components/table/table.js.map +1 -1
- package/dist/components/timeline/timeline.js.map +1 -1
- package/dist/components/toast/icons/ErrorIcon.js.map +1 -1
- package/dist/components/toast/icons/IconCircle.js.map +1 -1
- package/dist/components/toast/icons/InfoIcon.js.map +1 -1
- package/dist/components/toast/icons/LoaderIcon.js.map +1 -1
- package/dist/components/toast/icons/SuccessIcon.js.map +1 -1
- package/dist/components/toast/icons/WarningIcon.js.map +1 -1
- package/dist/components/toast/toast.js.map +1 -1
- package/dist/components/toast/toast.store.js.map +1 -1
- package/dist/components/tooltip/tooltip.js.map +1 -1
- package/dist/components/tour/tour.js.map +1 -1
- package/dist/components/upload/upload.js.map +1 -1
- package/dist/components/z-index/z-index.context.js.map +1 -1
- package/dist/components/z-index/z-index.js.map +1 -1
- package/dist/components/z-index/z-index.store.js.map +1 -1
- package/dist/components/z-index/z-index.types.js.map +1 -1
- package/dist/package.json +1 -1
- package/dist/skill/avatar.skill.md.txt +255 -255
- package/dist/skill/badge.skill.md.txt +223 -223
- package/dist/skill/breadcrumb.skill.md.txt +177 -177
- package/dist/skill/button.skill.md.txt +198 -198
- package/dist/skill/carousel.skill.md.txt +406 -406
- package/dist/skill/chat-bubble.skill.md.txt +342 -342
- package/dist/skill/checkbox.skill.md.txt +326 -326
- package/dist/skill/code-preview.skill.md.txt +240 -240
- package/dist/skill/collapse.skill.md.txt +329 -329
- package/dist/skill/context-menu.skill.md.txt +233 -233
- package/dist/skill/diff.skill.md.txt +244 -244
- package/dist/skill/divider.skill.md.txt +151 -151
- package/dist/skill/doc.skill.md.txt +191 -191
- package/dist/skill/drawer.skill.md.txt +157 -157
- package/dist/skill/dropdown.skill.md.txt +198 -198
- package/dist/skill/float-button.skill.md.txt +315 -315
- package/dist/skill/hover-3d-image.skill.md.txt +120 -120
- package/dist/skill/iframe.skill.md.txt +114 -114
- package/dist/skill/image-preview.skill.md.txt +162 -162
- package/dist/skill/indicator.skill.md.txt +60 -60
- package/dist/skill/input.skill.md.txt +489 -489
- package/dist/skill/loading.skill.md.txt +127 -127
- package/dist/skill/menu.skill.md.txt +476 -476
- package/dist/skill/modal.skill.md.txt +359 -359
- package/dist/skill/pagination.skill.md.txt +405 -405
- package/dist/skill/progress-bar.skill.md.txt +207 -207
- package/dist/skill/qr-code.skill.md.txt +136 -136
- package/dist/skill/rating.skill.md.txt +167 -167
- package/dist/skill/select-zone.skill.md.txt +93 -93
- package/dist/skill/select.skill.md.txt +663 -663
- package/dist/skill/skeleton.skill.md.txt +192 -192
- package/dist/skill/slider.skill.md.txt +404 -404
- package/dist/skill/splitter.skill.md.txt +411 -411
- package/dist/skill/steps.skill.md.txt +264 -264
- package/dist/skill/swap.skill.md.txt +139 -139
- package/dist/skill/switch.skill.md.txt +191 -191
- package/dist/skill/tab.skill.md.txt +484 -484
- package/dist/skill/table.example.header.md.txt +666 -666
- package/dist/skill/table.skill.md.txt +1407 -1407
- package/dist/skill/text-rotate.skill.md.txt +186 -186
- package/dist/skill/timeline.skill.md.txt +247 -247
- package/dist/skill/toast.skill.md.txt +531 -531
- package/dist/skill/tooltip.skill.md.txt +222 -222
- package/dist/skill/tour.skill.md.txt +156 -156
- package/dist/skill/upload.skill.md.txt +358 -358
- package/dist/utils/cn.js.map +1 -1
- package/dist/utils/element-tracker.js.map +1 -1
- package/dist/utils/helper.js.map +1 -1
- package/dist/utils/hoc.js.map +1 -1
- package/package.json +132 -133
|
@@ -1,222 +1,222 @@
|
|
|
1
|
-
## COMPONENT IDENTITY
|
|
2
|
-
- **Import**: `import { Tooltip } from 'solid-tom-ui';`
|
|
3
|
-
- **Export**: `Tooltip` (named export)
|
|
4
|
-
- **Framework**: SolidJS
|
|
5
|
-
- **Purpose**: Tooltip component — DaisyUI + CVA styling engine; two render modes (default / portal) controlled by `type` prop
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## TYPE SIGNATURE
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
// Unified entry point — render mode controlled by `type` prop
|
|
13
|
-
type TooltipProps = TooltipDefaultProps | TooltipPortalProps;
|
|
14
|
-
|
|
15
|
-
// Default mode (IO-based, no overflow clip)
|
|
16
|
-
type TooltipDefaultProps = {
|
|
17
|
-
type?: 'default'; // omit or set 'default'
|
|
18
|
-
hidden?: boolean;
|
|
19
|
-
children: JSX.Element;
|
|
20
|
-
position?: 'top' | 'bottom' | 'left' | 'right'; // default: 'top'
|
|
21
|
-
color?: BaseColorProps; // default: 'neutral'
|
|
22
|
-
zIndex?: number;
|
|
23
|
-
class?: {
|
|
24
|
-
root?: string;
|
|
25
|
-
content?: string;
|
|
26
|
-
};
|
|
27
|
-
} & (WithContent | WithCustomContent);
|
|
28
|
-
|
|
29
|
-
// Portal mode (event-delegation, escapes overflow:hidden)
|
|
30
|
-
type TooltipPortalProps = {
|
|
31
|
-
type: 'portal'; // REQUIRED to activate portal mode
|
|
32
|
-
hidden?: boolean;
|
|
33
|
-
children: SolidComponent;
|
|
34
|
-
position?: 'top' | 'bottom' | 'left' | 'right'; // default: 'top'
|
|
35
|
-
color?: BaseColorProps; // default: 'neutral'
|
|
36
|
-
zIndex?: number;
|
|
37
|
-
class?: {
|
|
38
|
-
root?: string;
|
|
39
|
-
content?: string;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* `id` of the overflow:hidden parent container.
|
|
43
|
-
* Required when type='portal'.
|
|
44
|
-
*/
|
|
45
|
-
containerId: string;
|
|
46
|
-
} & (WithContent | WithCustomContent);
|
|
47
|
-
|
|
48
|
-
// MUTUALLY EXCLUSIVE — use ONE of the two below:
|
|
49
|
-
type WithContent = {
|
|
50
|
-
content: string; // plain text tooltip
|
|
51
|
-
customContent?: never;
|
|
52
|
-
};
|
|
53
|
-
type WithCustomContent = {
|
|
54
|
-
content?: never;
|
|
55
|
-
customContent: JSX.Element; // arbitrary JSX tooltip body
|
|
56
|
-
};
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### CONSTRAINTS
|
|
60
|
-
|
|
61
|
-
- `content` and `customContent` are mutually exclusive.
|
|
62
|
-
- `containerId` is **required** when `type='portal'`. TypeScript will error if omitted.
|
|
63
|
-
- `TooltipPortal` is still exported as a backward-compat alias for `<Tooltip type="portal" ...>`.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
## PROP REFERENCE
|
|
68
|
-
|
|
69
|
-
| Prop | Type | Default | Description |
|
|
70
|
-
| --------------- | ---------------------------------------- | ----------- | ----------------------------------------------------------------------------- |
|
|
71
|
-
| `type` | `'default' \| 'portal'` | `'default'` | Render mode: IO-based (default) or event-delegation portal |
|
|
72
|
-
| `children` | `JSX.Element` / `SolidComponent` | — | **Required.** The element that triggers the tooltip on hover |
|
|
73
|
-
| `content` | `string` | — | Plain text shown in tooltip |
|
|
74
|
-
| `customContent` | `JSX.Element` | — | Arbitrary JSX rendered inside tooltip bubble |
|
|
75
|
-
| `position` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Direction tooltip appears relative to trigger |
|
|
76
|
-
| `color` | `BaseColorProps` | `'neutral'` | DaisyUI color variant |
|
|
77
|
-
| `hidden` | `boolean` | `undefined` | When `true`, bypasses tooltip wrapper entirely — renders children only |
|
|
78
|
-
| `zIndex` | `number` | `undefined` | Override automatic z-index management |
|
|
79
|
-
| `containerId` | `string` | — | **Required when `type='portal'`.** The `id` of the element causing clipping |
|
|
80
|
-
| `class.root` | `string` | `undefined` | Extra Tailwind classes on the outer wrapper div |
|
|
81
|
-
| `class.content` | `string` | `undefined` | Extra Tailwind classes on the tooltip bubble |
|
|
82
|
-
|
|
83
|
-
---
|
|
84
|
-
|
|
85
|
-
## TYPE DECISION RULE
|
|
86
|
-
|
|
87
|
-
> **Always default to `type='default'` (or omit the `type` prop entirely).**
|
|
88
|
-
> Only switch to `type='portal'` when the tooltip is **clipped by `overflow:hidden`, `overflow:clip`, or `clip-path`** on a parent container.
|
|
89
|
-
|
|
90
|
-
| Situation | Choice |
|
|
91
|
-
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
92
|
-
| Tooltip renders normally, not clipped | `type='default'` _(default — no declaration needed)_ |
|
|
93
|
-
| Tooltip is inside a container with `overflow:hidden` / `overflow:clip` | `type='portal'` + `containerId` pointing to that specific container |
|
|
94
|
-
| Tooltip inside a scrollable table with hundreds of cells | `type='portal'` + same `containerId` for all tooltips (the table's wrapper) |
|
|
95
|
-
| Not sure whether it will be clipped | Try default first; switch to portal only if you observe the tooltip being cut |
|
|
96
|
-
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
## CHOOSING THE RIGHT `containerId`
|
|
100
|
-
|
|
101
|
-
> **`containerId` must identify the specific element that is causing the tooltip to be hidden — not a global ancestor.**
|
|
102
|
-
|
|
103
|
-
1. Find the element with `overflow:hidden` / `overflow:clip`.
|
|
104
|
-
2. Assign that element an `id`.
|
|
105
|
-
3. Pass that `id` as `containerId`.
|
|
106
|
-
|
|
107
|
-
### What NOT to use as `containerId`
|
|
108
|
-
|
|
109
|
-
| ❌ Avoid | Why |
|
|
110
|
-
| ---------------------------------------------- | ----------------------------------------------------------- |
|
|
111
|
-
| `containerId="html-root"` (pointing to `<html>`) | Near-global listener — defeats all scoping |
|
|
112
|
-
| `containerId="root"` (app root div) | Too broad — still covers the entire application |
|
|
113
|
-
|
|
114
|
-
---
|
|
115
|
-
|
|
116
|
-
## USAGE PATTERNS
|
|
117
|
-
|
|
118
|
-
### Pattern 1 — Plain text tooltip (most common)
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
<Tooltip content="Save your work" position="top" color="primary">
|
|
122
|
-
<Button>Save</Button>
|
|
123
|
-
</Tooltip>
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Pattern 2 — Custom JSX content
|
|
127
|
-
|
|
128
|
-
```tsx
|
|
129
|
-
<Tooltip
|
|
130
|
-
position="bottom"
|
|
131
|
-
color="info"
|
|
132
|
-
customContent={
|
|
133
|
-
<div class="bg-info text-info-content rounded-lg p-2">
|
|
134
|
-
<p class="font-bold">Title</p>
|
|
135
|
-
<p class="text-sm">Description text</p>
|
|
136
|
-
</div>
|
|
137
|
-
}
|
|
138
|
-
>
|
|
139
|
-
<Button>Hover me</Button>
|
|
140
|
-
</Tooltip>
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Pattern 3 — Conditionally hidden tooltip
|
|
144
|
-
|
|
145
|
-
```tsx
|
|
146
|
-
<Tooltip content="Only when permitted" hidden={!userHasPermission}>
|
|
147
|
-
<Button>Action</Button>
|
|
148
|
-
</Tooltip>
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Pattern 4 — Portal mode (only when tooltip is clipped by overflow:hidden)
|
|
152
|
-
|
|
153
|
-
```tsx
|
|
154
|
-
<div id="my-overflow-box" style={{ overflow: 'hidden' }}>
|
|
155
|
-
<Tooltip type="portal" content="Escapes overflow!" containerId="my-overflow-box" position="top">
|
|
156
|
-
<Button>Hover me</Button>
|
|
157
|
-
</Tooltip>
|
|
158
|
-
</div>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Pattern 5 — Portal on many cells in a table (performance-optimized)
|
|
162
|
-
|
|
163
|
-
```tsx
|
|
164
|
-
// All tooltips sharing the same containerId use ONE pair of listeners
|
|
165
|
-
<div id="my-table-container" class="max-h-64 overflow-auto">
|
|
166
|
-
<table>
|
|
167
|
-
<tbody>
|
|
168
|
-
<For each={rows}>
|
|
169
|
-
{row => (
|
|
170
|
-
<tr>
|
|
171
|
-
<td>
|
|
172
|
-
<Tooltip
|
|
173
|
-
type="portal"
|
|
174
|
-
content={row.label}
|
|
175
|
-
position="top"
|
|
176
|
-
color="primary"
|
|
177
|
-
containerId="my-table-container"
|
|
178
|
-
>
|
|
179
|
-
<span>{row.value}</span>
|
|
180
|
-
</Tooltip>
|
|
181
|
-
</td>
|
|
182
|
-
</tr>
|
|
183
|
-
)}
|
|
184
|
-
</For>
|
|
185
|
-
</tbody>
|
|
186
|
-
</table>
|
|
187
|
-
</div>
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## BEHAVIOR NOTES FOR AGENTS
|
|
193
|
-
|
|
194
|
-
1. **`hidden` prop short-circuits all tooltip logic** — when `hidden={true}`, renders `<>{children}</>` only.
|
|
195
|
-
|
|
196
|
-
2. **`type='default'` uses IntersectionObserver** — a CSS sentinel (`too08`) inside the wrapper becomes visible on `:hover`, triggering the IO callback which appends the bubble to `document.body`. Zero JS event listeners on the trigger.
|
|
197
|
-
|
|
198
|
-
3. **`type='portal'` uses event delegation** — internally uses a `WeakMap<Element, ContainerState>` keyed by the resolved container. Multiple tooltips with the same `containerId` share a single `mouseover`/`mouseout` listener pair.
|
|
199
|
-
|
|
200
|
-
4. **`containerId` timing** — registration is deferred via `queueMicrotask` so it is safe even when the container is a parent in the same JSX tree.
|
|
201
|
-
|
|
202
|
-
5. **`TooltipPortal` is a backward-compat alias** — `<TooltipPortal containerId="x" ...>` is equivalent to `<Tooltip type="portal" containerId="x" ...>`.
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## COMMON MISTAKES TO AVOID
|
|
207
|
-
|
|
208
|
-
| Mistake | Correct approach |
|
|
209
|
-
| ------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
|
210
|
-
| Providing both `content` and `customContent` | Use only one — they are mutually exclusive |
|
|
211
|
-
| Using `type='portal'` as the default for every tooltip | Only use it when the tooltip is actually clipped by overflow |
|
|
212
|
-
| Using `type='portal'` without `containerId` | TypeScript will error — always provide `containerId` |
|
|
213
|
-
| Using `containerId="html-root"` or pointing to `<html>` | Creates a near-global listener. Point to the specific overflow container |
|
|
214
|
-
| Using different `containerId` values in a loop | All tooltips in the same container should share the same `containerId` |
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Component Conventions
|
|
219
|
-
|
|
220
|
-
> **CSS encoding**: internal CSS classes use short encoded names (e.g. `too01`, `too06`) per project convention.
|
|
221
|
-
|
|
222
|
-
> **Unique IDs**: uses `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|
|
1
|
+
## COMPONENT IDENTITY
|
|
2
|
+
- **Import**: `import { Tooltip } from 'solid-tom-ui';`
|
|
3
|
+
- **Export**: `Tooltip` (named export)
|
|
4
|
+
- **Framework**: SolidJS
|
|
5
|
+
- **Purpose**: Tooltip component — DaisyUI + CVA styling engine; two render modes (default / portal) controlled by `type` prop
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## TYPE SIGNATURE
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
// Unified entry point — render mode controlled by `type` prop
|
|
13
|
+
type TooltipProps = TooltipDefaultProps | TooltipPortalProps;
|
|
14
|
+
|
|
15
|
+
// Default mode (IO-based, no overflow clip)
|
|
16
|
+
type TooltipDefaultProps = {
|
|
17
|
+
type?: 'default'; // omit or set 'default'
|
|
18
|
+
hidden?: boolean;
|
|
19
|
+
children: JSX.Element;
|
|
20
|
+
position?: 'top' | 'bottom' | 'left' | 'right'; // default: 'top'
|
|
21
|
+
color?: BaseColorProps; // default: 'neutral'
|
|
22
|
+
zIndex?: number;
|
|
23
|
+
class?: {
|
|
24
|
+
root?: string;
|
|
25
|
+
content?: string;
|
|
26
|
+
};
|
|
27
|
+
} & (WithContent | WithCustomContent);
|
|
28
|
+
|
|
29
|
+
// Portal mode (event-delegation, escapes overflow:hidden)
|
|
30
|
+
type TooltipPortalProps = {
|
|
31
|
+
type: 'portal'; // REQUIRED to activate portal mode
|
|
32
|
+
hidden?: boolean;
|
|
33
|
+
children: SolidComponent;
|
|
34
|
+
position?: 'top' | 'bottom' | 'left' | 'right'; // default: 'top'
|
|
35
|
+
color?: BaseColorProps; // default: 'neutral'
|
|
36
|
+
zIndex?: number;
|
|
37
|
+
class?: {
|
|
38
|
+
root?: string;
|
|
39
|
+
content?: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* `id` of the overflow:hidden parent container.
|
|
43
|
+
* Required when type='portal'.
|
|
44
|
+
*/
|
|
45
|
+
containerId: string;
|
|
46
|
+
} & (WithContent | WithCustomContent);
|
|
47
|
+
|
|
48
|
+
// MUTUALLY EXCLUSIVE — use ONE of the two below:
|
|
49
|
+
type WithContent = {
|
|
50
|
+
content: string; // plain text tooltip
|
|
51
|
+
customContent?: never;
|
|
52
|
+
};
|
|
53
|
+
type WithCustomContent = {
|
|
54
|
+
content?: never;
|
|
55
|
+
customContent: JSX.Element; // arbitrary JSX tooltip body
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### CONSTRAINTS
|
|
60
|
+
|
|
61
|
+
- `content` and `customContent` are mutually exclusive.
|
|
62
|
+
- `containerId` is **required** when `type='portal'`. TypeScript will error if omitted.
|
|
63
|
+
- `TooltipPortal` is still exported as a backward-compat alias for `<Tooltip type="portal" ...>`.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## PROP REFERENCE
|
|
68
|
+
|
|
69
|
+
| Prop | Type | Default | Description |
|
|
70
|
+
| --------------- | ---------------------------------------- | ----------- | ----------------------------------------------------------------------------- |
|
|
71
|
+
| `type` | `'default' \| 'portal'` | `'default'` | Render mode: IO-based (default) or event-delegation portal |
|
|
72
|
+
| `children` | `JSX.Element` / `SolidComponent` | — | **Required.** The element that triggers the tooltip on hover |
|
|
73
|
+
| `content` | `string` | — | Plain text shown in tooltip |
|
|
74
|
+
| `customContent` | `JSX.Element` | — | Arbitrary JSX rendered inside tooltip bubble |
|
|
75
|
+
| `position` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | Direction tooltip appears relative to trigger |
|
|
76
|
+
| `color` | `BaseColorProps` | `'neutral'` | DaisyUI color variant |
|
|
77
|
+
| `hidden` | `boolean` | `undefined` | When `true`, bypasses tooltip wrapper entirely — renders children only |
|
|
78
|
+
| `zIndex` | `number` | `undefined` | Override automatic z-index management |
|
|
79
|
+
| `containerId` | `string` | — | **Required when `type='portal'`.** The `id` of the element causing clipping |
|
|
80
|
+
| `class.root` | `string` | `undefined` | Extra Tailwind classes on the outer wrapper div |
|
|
81
|
+
| `class.content` | `string` | `undefined` | Extra Tailwind classes on the tooltip bubble |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## TYPE DECISION RULE
|
|
86
|
+
|
|
87
|
+
> **Always default to `type='default'` (or omit the `type` prop entirely).**
|
|
88
|
+
> Only switch to `type='portal'` when the tooltip is **clipped by `overflow:hidden`, `overflow:clip`, or `clip-path`** on a parent container.
|
|
89
|
+
|
|
90
|
+
| Situation | Choice |
|
|
91
|
+
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
92
|
+
| Tooltip renders normally, not clipped | `type='default'` _(default — no declaration needed)_ |
|
|
93
|
+
| Tooltip is inside a container with `overflow:hidden` / `overflow:clip` | `type='portal'` + `containerId` pointing to that specific container |
|
|
94
|
+
| Tooltip inside a scrollable table with hundreds of cells | `type='portal'` + same `containerId` for all tooltips (the table's wrapper) |
|
|
95
|
+
| Not sure whether it will be clipped | Try default first; switch to portal only if you observe the tooltip being cut |
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## CHOOSING THE RIGHT `containerId`
|
|
100
|
+
|
|
101
|
+
> **`containerId` must identify the specific element that is causing the tooltip to be hidden — not a global ancestor.**
|
|
102
|
+
|
|
103
|
+
1. Find the element with `overflow:hidden` / `overflow:clip`.
|
|
104
|
+
2. Assign that element an `id`.
|
|
105
|
+
3. Pass that `id` as `containerId`.
|
|
106
|
+
|
|
107
|
+
### What NOT to use as `containerId`
|
|
108
|
+
|
|
109
|
+
| ❌ Avoid | Why |
|
|
110
|
+
| ---------------------------------------------- | ----------------------------------------------------------- |
|
|
111
|
+
| `containerId="html-root"` (pointing to `<html>`) | Near-global listener — defeats all scoping |
|
|
112
|
+
| `containerId="root"` (app root div) | Too broad — still covers the entire application |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## USAGE PATTERNS
|
|
117
|
+
|
|
118
|
+
### Pattern 1 — Plain text tooltip (most common)
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
<Tooltip content="Save your work" position="top" color="primary">
|
|
122
|
+
<Button>Save</Button>
|
|
123
|
+
</Tooltip>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Pattern 2 — Custom JSX content
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
<Tooltip
|
|
130
|
+
position="bottom"
|
|
131
|
+
color="info"
|
|
132
|
+
customContent={
|
|
133
|
+
<div class="bg-info text-info-content rounded-lg p-2">
|
|
134
|
+
<p class="font-bold">Title</p>
|
|
135
|
+
<p class="text-sm">Description text</p>
|
|
136
|
+
</div>
|
|
137
|
+
}
|
|
138
|
+
>
|
|
139
|
+
<Button>Hover me</Button>
|
|
140
|
+
</Tooltip>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Pattern 3 — Conditionally hidden tooltip
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
<Tooltip content="Only when permitted" hidden={!userHasPermission}>
|
|
147
|
+
<Button>Action</Button>
|
|
148
|
+
</Tooltip>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Pattern 4 — Portal mode (only when tooltip is clipped by overflow:hidden)
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
<div id="my-overflow-box" style={{ overflow: 'hidden' }}>
|
|
155
|
+
<Tooltip type="portal" content="Escapes overflow!" containerId="my-overflow-box" position="top">
|
|
156
|
+
<Button>Hover me</Button>
|
|
157
|
+
</Tooltip>
|
|
158
|
+
</div>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Pattern 5 — Portal on many cells in a table (performance-optimized)
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
// All tooltips sharing the same containerId use ONE pair of listeners
|
|
165
|
+
<div id="my-table-container" class="max-h-64 overflow-auto">
|
|
166
|
+
<table>
|
|
167
|
+
<tbody>
|
|
168
|
+
<For each={rows}>
|
|
169
|
+
{row => (
|
|
170
|
+
<tr>
|
|
171
|
+
<td>
|
|
172
|
+
<Tooltip
|
|
173
|
+
type="portal"
|
|
174
|
+
content={row.label}
|
|
175
|
+
position="top"
|
|
176
|
+
color="primary"
|
|
177
|
+
containerId="my-table-container"
|
|
178
|
+
>
|
|
179
|
+
<span>{row.value}</span>
|
|
180
|
+
</Tooltip>
|
|
181
|
+
</td>
|
|
182
|
+
</tr>
|
|
183
|
+
)}
|
|
184
|
+
</For>
|
|
185
|
+
</tbody>
|
|
186
|
+
</table>
|
|
187
|
+
</div>
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## BEHAVIOR NOTES FOR AGENTS
|
|
193
|
+
|
|
194
|
+
1. **`hidden` prop short-circuits all tooltip logic** — when `hidden={true}`, renders `<>{children}</>` only.
|
|
195
|
+
|
|
196
|
+
2. **`type='default'` uses IntersectionObserver** — a CSS sentinel (`too08`) inside the wrapper becomes visible on `:hover`, triggering the IO callback which appends the bubble to `document.body`. Zero JS event listeners on the trigger.
|
|
197
|
+
|
|
198
|
+
3. **`type='portal'` uses event delegation** — internally uses a `WeakMap<Element, ContainerState>` keyed by the resolved container. Multiple tooltips with the same `containerId` share a single `mouseover`/`mouseout` listener pair.
|
|
199
|
+
|
|
200
|
+
4. **`containerId` timing** — registration is deferred via `queueMicrotask` so it is safe even when the container is a parent in the same JSX tree.
|
|
201
|
+
|
|
202
|
+
5. **`TooltipPortal` is a backward-compat alias** — `<TooltipPortal containerId="x" ...>` is equivalent to `<Tooltip type="portal" containerId="x" ...>`.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## COMMON MISTAKES TO AVOID
|
|
207
|
+
|
|
208
|
+
| Mistake | Correct approach |
|
|
209
|
+
| ------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
|
210
|
+
| Providing both `content` and `customContent` | Use only one — they are mutually exclusive |
|
|
211
|
+
| Using `type='portal'` as the default for every tooltip | Only use it when the tooltip is actually clipped by overflow |
|
|
212
|
+
| Using `type='portal'` without `containerId` | TypeScript will error — always provide `containerId` |
|
|
213
|
+
| Using `containerId="html-root"` or pointing to `<html>` | Creates a near-global listener. Point to the specific overflow container |
|
|
214
|
+
| Using different `containerId` values in a loop | All tooltips in the same container should share the same `containerId` |
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Component Conventions
|
|
219
|
+
|
|
220
|
+
> **CSS encoding**: internal CSS classes use short encoded names (e.g. `too01`, `too06`) per project convention.
|
|
221
|
+
|
|
222
|
+
> **Unique IDs**: uses `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|