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.
Files changed (119) hide show
  1. package/README.md +246 -246
  2. package/dist/README.md +246 -246
  3. package/dist/components/avatar/avatar.js.map +1 -1
  4. package/dist/components/badge/badge.js.map +1 -1
  5. package/dist/components/breadcrumb/breadcrumb.js.map +1 -1
  6. package/dist/components/button/button.js.map +1 -1
  7. package/dist/components/carousel/carousel.js.map +1 -1
  8. package/dist/components/chat-bubble/chatBubble.js.map +1 -1
  9. package/dist/components/checkbox/checkbox.js.map +1 -1
  10. package/dist/components/collapse/collapse.js.map +1 -1
  11. package/dist/components/context-menu/context-menu.js.map +1 -1
  12. package/dist/components/context-menu/context-menu.store.js.map +1 -1
  13. package/dist/components/divider/divider.js.map +1 -1
  14. package/dist/components/dropdown/dropdown.js.map +1 -1
  15. package/dist/components/dropdown/dropdown.store.js.map +1 -1
  16. package/dist/components/float-button/float-button.js.map +1 -1
  17. package/dist/components/hover-3d-image/hover-3d-image.js.map +1 -1
  18. package/dist/components/image-preview/image-preview.js.map +1 -1
  19. package/dist/components/input/input.js.map +1 -1
  20. package/dist/components/input/input.utils.js.map +1 -1
  21. package/dist/components/input/variants/input-color.js.map +1 -1
  22. package/dist/components/input/variants/input-date.js.map +1 -1
  23. package/dist/components/input/variants/input-number.d.ts.map +1 -1
  24. package/dist/components/input/variants/input-number.js +1 -1
  25. package/dist/components/input/variants/input-number.js.map +1 -1
  26. package/dist/components/input/variants/input-otp.js.map +1 -1
  27. package/dist/components/input/variants/input-password.js.map +1 -1
  28. package/dist/components/input/variants/input-radio.js.map +1 -1
  29. package/dist/components/input/variants/input-range.js.map +1 -1
  30. package/dist/components/input/variants/input-text.d.ts.map +1 -1
  31. package/dist/components/input/variants/input-text.js +1 -1
  32. package/dist/components/input/variants/input-text.js.map +1 -1
  33. package/dist/components/input/variants/input-textarea.js.map +1 -1
  34. package/dist/components/loading/loading.js.map +1 -1
  35. package/dist/components/mansory/mansory.js.map +1 -1
  36. package/dist/components/menu/menu.js.map +1 -1
  37. package/dist/components/modal/modal.js.map +1 -1
  38. package/dist/components/modal/modalContext.js.map +1 -1
  39. package/dist/components/pagination/pagination.js.map +1 -1
  40. package/dist/components/progress-bar/progress-bar.js.map +1 -1
  41. package/dist/components/qr-code/qr-code.js.map +1 -1
  42. package/dist/components/select/select.js +1 -1
  43. package/dist/components/select/select.js.map +1 -1
  44. package/dist/components/select-zone/select-zone.js.map +1 -1
  45. package/dist/components/skeleton/skeleton.js.map +1 -1
  46. package/dist/components/slider/slider.js.map +1 -1
  47. package/dist/components/splitter/splitter.js.map +1 -1
  48. package/dist/components/steps/steps.js.map +1 -1
  49. package/dist/components/swap/swap.js.map +1 -1
  50. package/dist/components/switch/switch.js.map +1 -1
  51. package/dist/components/tab/tab.js.map +1 -1
  52. package/dist/components/table/table.js.map +1 -1
  53. package/dist/components/timeline/timeline.js.map +1 -1
  54. package/dist/components/toast/icons/ErrorIcon.js.map +1 -1
  55. package/dist/components/toast/icons/IconCircle.js.map +1 -1
  56. package/dist/components/toast/icons/InfoIcon.js.map +1 -1
  57. package/dist/components/toast/icons/LoaderIcon.js.map +1 -1
  58. package/dist/components/toast/icons/SuccessIcon.js.map +1 -1
  59. package/dist/components/toast/icons/WarningIcon.js.map +1 -1
  60. package/dist/components/toast/toast.js.map +1 -1
  61. package/dist/components/toast/toast.store.js.map +1 -1
  62. package/dist/components/tooltip/tooltip.js.map +1 -1
  63. package/dist/components/tour/tour.js.map +1 -1
  64. package/dist/components/upload/upload.js.map +1 -1
  65. package/dist/components/z-index/z-index.context.js.map +1 -1
  66. package/dist/components/z-index/z-index.js.map +1 -1
  67. package/dist/components/z-index/z-index.store.js.map +1 -1
  68. package/dist/components/z-index/z-index.types.js.map +1 -1
  69. package/dist/package.json +1 -1
  70. package/dist/skill/avatar.skill.md.txt +255 -255
  71. package/dist/skill/badge.skill.md.txt +223 -223
  72. package/dist/skill/breadcrumb.skill.md.txt +177 -177
  73. package/dist/skill/button.skill.md.txt +198 -198
  74. package/dist/skill/carousel.skill.md.txt +406 -406
  75. package/dist/skill/chat-bubble.skill.md.txt +342 -342
  76. package/dist/skill/checkbox.skill.md.txt +326 -326
  77. package/dist/skill/code-preview.skill.md.txt +240 -240
  78. package/dist/skill/collapse.skill.md.txt +329 -329
  79. package/dist/skill/context-menu.skill.md.txt +233 -233
  80. package/dist/skill/diff.skill.md.txt +244 -244
  81. package/dist/skill/divider.skill.md.txt +151 -151
  82. package/dist/skill/doc.skill.md.txt +191 -191
  83. package/dist/skill/drawer.skill.md.txt +157 -157
  84. package/dist/skill/dropdown.skill.md.txt +198 -198
  85. package/dist/skill/float-button.skill.md.txt +315 -315
  86. package/dist/skill/hover-3d-image.skill.md.txt +120 -120
  87. package/dist/skill/iframe.skill.md.txt +114 -114
  88. package/dist/skill/image-preview.skill.md.txt +162 -162
  89. package/dist/skill/indicator.skill.md.txt +60 -60
  90. package/dist/skill/input.skill.md.txt +489 -489
  91. package/dist/skill/loading.skill.md.txt +127 -127
  92. package/dist/skill/menu.skill.md.txt +476 -476
  93. package/dist/skill/modal.skill.md.txt +359 -359
  94. package/dist/skill/pagination.skill.md.txt +405 -405
  95. package/dist/skill/progress-bar.skill.md.txt +207 -207
  96. package/dist/skill/qr-code.skill.md.txt +136 -136
  97. package/dist/skill/rating.skill.md.txt +167 -167
  98. package/dist/skill/select-zone.skill.md.txt +93 -93
  99. package/dist/skill/select.skill.md.txt +663 -663
  100. package/dist/skill/skeleton.skill.md.txt +192 -192
  101. package/dist/skill/slider.skill.md.txt +404 -404
  102. package/dist/skill/splitter.skill.md.txt +411 -411
  103. package/dist/skill/steps.skill.md.txt +264 -264
  104. package/dist/skill/swap.skill.md.txt +139 -139
  105. package/dist/skill/switch.skill.md.txt +191 -191
  106. package/dist/skill/tab.skill.md.txt +484 -484
  107. package/dist/skill/table.example.header.md.txt +666 -666
  108. package/dist/skill/table.skill.md.txt +1407 -1407
  109. package/dist/skill/text-rotate.skill.md.txt +186 -186
  110. package/dist/skill/timeline.skill.md.txt +247 -247
  111. package/dist/skill/toast.skill.md.txt +531 -531
  112. package/dist/skill/tooltip.skill.md.txt +222 -222
  113. package/dist/skill/tour.skill.md.txt +156 -156
  114. package/dist/skill/upload.skill.md.txt +358 -358
  115. package/dist/utils/cn.js.map +1 -1
  116. package/dist/utils/element-tracker.js.map +1 -1
  117. package/dist/utils/helper.js.map +1 -1
  118. package/dist/utils/hoc.js.map +1 -1
  119. 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()`.