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,244 +1,244 @@
|
|
|
1
|
-
## COMPONENT IDENTITY
|
|
2
|
-
- **Import**: `import { Diff } from 'solid-tom-ui';`
|
|
3
|
-
- **Export**: `Diff` (named export)
|
|
4
|
-
- **Framework**: SolidJS
|
|
5
|
-
- **Purpose**: Interactive image/content comparison slider — user drags a resizer to reveal left vs right panels; NOT a `ParentComponent`, content passed via `images` prop array
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## TYPE SIGNATURE
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
type DiffProps = {
|
|
13
|
-
images: SolidComponent[]; // REQUIRED — must be exactly 2 elements
|
|
14
|
-
class?: string; // extra classes on root <figure>
|
|
15
|
-
};
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## CLASS SLOTS
|
|
19
|
-
|
|
20
|
-
`Diff` is a single-element component — the `class` prop targets the root `<figure>` only. There are no named slots.
|
|
21
|
-
|
|
22
|
-
> **CSS encoding**: internal CSS classes follow the project convention using short encoded names (e.g. `df01`, `df02`). Do not reference DaisyUI's `diff-item-1` / `diff-item-2` class names directly in your own styles — use the `class` prop or wrap with your own container.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## PROP REFERENCE
|
|
27
|
-
|
|
28
|
-
| Prop | Type | Required | Description |
|
|
29
|
-
| -------- | ------------------ | -------- | ------------------------------------------------------------------------------------- |
|
|
30
|
-
| `images` | `SolidComponent[]` | ✅ YES | Array of **exactly 2** JSX elements — index `0` = left panel, index `1` = right panel |
|
|
31
|
-
| `class` | `string` | ❌ NO | Extra Tailwind classes appended to the root `<figure>` element |
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## HARD CONSTRAINT: `images` must have exactly 2 elements
|
|
36
|
-
|
|
37
|
-
- Passing fewer or more than 2 elements → component returns `<></>` (renders nothing) and fires `console.warn('You need to provide exactly 2 images')`
|
|
38
|
-
- There is no partial rendering fallback — the entire component is suppressed
|
|
39
|
-
|
|
40
|
-
```ts
|
|
41
|
-
// ✅ Valid
|
|
42
|
-
images={[<img src="a.webp" />, <img src="b.webp" />]}
|
|
43
|
-
|
|
44
|
-
// ❌ Invalid — renders nothing
|
|
45
|
-
images={[<img src="a.webp" />]}
|
|
46
|
-
images={[<img src="a.webp" />, <img src="b.webp" />, <img src="c.webp" />]}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## INTERNAL DOM STRUCTURE
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
<figure class="diff aspect-video [class]" tabindex="0">
|
|
55
|
-
│
|
|
56
|
-
├── <div class="diff-item-1" role="img" tabindex="0">
|
|
57
|
-
│ {images[0]} ← LEFT panel (revealed by dragging resizer right)
|
|
58
|
-
│ </div>
|
|
59
|
-
│
|
|
60
|
-
├── <div class="diff-item-2" role="img">
|
|
61
|
-
│ {images[1]} ← RIGHT panel (base/background layer)
|
|
62
|
-
│ </div>
|
|
63
|
-
│
|
|
64
|
-
└── <div class="diff-resizer"></div> ← invisible drag handle
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Layer rendering order
|
|
68
|
-
|
|
69
|
-
- `diff-item-2` (right/background) renders behind — visible in full by default
|
|
70
|
-
- `diff-item-1` (left/foreground) renders on top with `z-index: 1`, clipped by the resizer position
|
|
71
|
-
- Dragging resizer RIGHT → reveals more of `images[0]` (left panel)
|
|
72
|
-
- Dragging resizer LEFT → reveals more of `images[1]` (right panel)
|
|
73
|
-
|
|
74
|
-
---
|
|
75
|
-
|
|
76
|
-
## INTERACTION MECHANISM — CSS-only, no JS state
|
|
77
|
-
|
|
78
|
-
The slider is driven entirely by CSS using a native `resize: horizontal` invisible div (`.diff-resizer`):
|
|
79
|
-
|
|
80
|
-
- Default resizer position: `width: 50cqi` → panels shown 50/50
|
|
81
|
-
- Resizer `min-width: 1rem`, `max-width: calc(100cqi - 1rem)` — cannot be dragged beyond edges
|
|
82
|
-
- **Keyboard accessible**: `<figure tabindex="0">` and `<div class="diff-item-1" tabindex="0">` both focusable
|
|
83
|
-
- Focus on `<figure>` → resizer snaps to `min-width: 95cqi` (left panel nearly full)
|
|
84
|
-
- Focus on `diff-item-1` → resizer snaps to `min-width: 5cqi` (right panel nearly full)
|
|
85
|
-
- Snap transitions animated with `transition: min-width 0.3s ease-out`
|
|
86
|
-
|
|
87
|
-
Agents do NOT manage any open/close or drag state — it is fully CSS-driven.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## CONTENT RULES FOR `images[0]` AND `images[1]`
|
|
92
|
-
|
|
93
|
-
Both slots accept **any JSX element**, not just `<img>`. Internal CSS applies to all direct children:
|
|
94
|
-
|
|
95
|
-
```css
|
|
96
|
-
/* Applied to direct children of both diff-item-1 and diff-item-2 */
|
|
97
|
-
position: absolute;
|
|
98
|
-
top: 0;
|
|
99
|
-
bottom: 0;
|
|
100
|
-
left: 0;
|
|
101
|
-
height: 100%;
|
|
102
|
-
width: 100cqi;
|
|
103
|
-
object-fit: cover;
|
|
104
|
-
object-position: center;
|
|
105
|
-
pointer-events: none;
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### What this means for agents:
|
|
109
|
-
|
|
110
|
-
- **`<img>`**: works perfectly — `object-fit: cover` is applied automatically
|
|
111
|
-
- **`<div>`**: also works — div fills the full panel area. Use `grid place-content-center` or flex for internal layout
|
|
112
|
-
- **Interactive elements inside panels**: will NOT work — `pointer-events: none` is applied to all children. Do NOT put buttons, links, or inputs inside `images`
|
|
113
|
-
- **Do NOT add layout wrappers** around the img/div — children are positioned absolutely with `width: 100cqi`
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
## ASPECT RATIO
|
|
118
|
-
|
|
119
|
-
- Root `<figure>` always has class `aspect-video` (16:9 ratio) applied by default
|
|
120
|
-
- To change aspect ratio, override via `class` prop:
|
|
121
|
-
|
|
122
|
-
```tsx
|
|
123
|
-
// Square
|
|
124
|
-
<Diff images={[...]} class="aspect-square" />
|
|
125
|
-
|
|
126
|
-
// Custom ratio
|
|
127
|
-
<Diff images={[...]} class="aspect-4/3" />
|
|
128
|
-
|
|
129
|
-
// Fixed height
|
|
130
|
-
<Diff images={[...]} class="h-100" />
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## USAGE PATTERNS
|
|
136
|
-
|
|
137
|
-
### Pattern 1 — Image vs image (most common)
|
|
138
|
-
|
|
139
|
-
```tsx
|
|
140
|
-
<Diff
|
|
141
|
-
images={[
|
|
142
|
-
<img alt="before" src="/images/before.webp" />,
|
|
143
|
-
<img alt="after" src="/images/after.webp" />,
|
|
144
|
-
]}
|
|
145
|
-
/>
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Pattern 2 — Image vs custom div content
|
|
149
|
-
|
|
150
|
-
```tsx
|
|
151
|
-
<Diff
|
|
152
|
-
images={[
|
|
153
|
-
<img alt="photo" src="/images/photo.webp" />,
|
|
154
|
-
<div class="bg-base-200 text-base-content grid place-content-center text-6xl font-black">
|
|
155
|
-
BEFORE
|
|
156
|
-
</div>,
|
|
157
|
-
]}
|
|
158
|
-
/>
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### Pattern 3 — Custom aspect ratio
|
|
162
|
-
|
|
163
|
-
```tsx
|
|
164
|
-
<Diff
|
|
165
|
-
class="aspect-square w-100"
|
|
166
|
-
images={[
|
|
167
|
-
<img alt="original" src="/images/original.webp" />,
|
|
168
|
-
<img alt="filtered" src="/images/filtered.webp" />,
|
|
169
|
-
]}
|
|
170
|
-
/>
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Pattern 4 — Two styled div panels
|
|
174
|
-
|
|
175
|
-
```tsx
|
|
176
|
-
<Diff
|
|
177
|
-
images={[
|
|
178
|
-
<div class="bg-primary text-primary-content grid place-content-center text-4xl font-bold">
|
|
179
|
-
Dark Mode
|
|
180
|
-
</div>,
|
|
181
|
-
<div class="bg-base-100 text-base-content grid place-content-center text-4xl font-bold">
|
|
182
|
-
Light Mode
|
|
183
|
-
</div>,
|
|
184
|
-
]}
|
|
185
|
-
/>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
## BEHAVIOR NOTES FOR AGENTS
|
|
191
|
-
|
|
192
|
-
1. **`images[0]` = left (foreground), `images[1]` = right (background)** — the order determines which panel is clipped by the drag handle. Left panel sits on top and is revealed by dragging right.
|
|
193
|
-
|
|
194
|
-
2. **Component is a `<figure>` element** — semantically appropriate for media comparison. Root is not a `<div>`.
|
|
195
|
-
|
|
196
|
-
3. **`pointer-events: none` on all panel children** — nothing inside `images[0]` or `images[1]` can be clicked, hovered, or interacted with. Only the resizer handle is interactive.
|
|
197
|
-
|
|
198
|
-
4. **No JS drag state** — the drag interaction is entirely driven by the native browser `resize: horizontal` CSS property on `.diff-resizer`. No SolidJS signals or event handlers involved.
|
|
199
|
-
|
|
200
|
-
5. **`class` prop targets the root `<figure>` only** — cannot target internal `.diff-item-1`, `.diff-item-2`, or `.diff-resizer` via this prop.
|
|
201
|
-
|
|
202
|
-
6. **Width fills container** — root `<figure>` has `width: 100%`. Wrap in a sized container or use `class="w-[500px]"` to constrain.
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## COMMON MISTAKES TO AVOID
|
|
207
|
-
|
|
208
|
-
| Mistake | Correct approach |
|
|
209
|
-
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
210
|
-
| Passing 1 or 3+ items in `images` | Always pass exactly 2 elements — no more, no less |
|
|
211
|
-
| Putting interactive elements (buttons, links) inside `images` | `pointer-events: none` blocks all interactions inside panels |
|
|
212
|
-
| Wrapping `<img>` in an extra `<div>` | Pass `<img>` directly — children are already positioned absolutely to fill the panel |
|
|
213
|
-
| Expecting `class` to style inner panels | `class` only applies to the root `<figure>` |
|
|
214
|
-
| Assuming left panel is `images[1]` | `images[0]` = left/foreground (clipped), `images[1]` = right/background |
|
|
215
|
-
| Using without a sized container | Add `w-full`, `w-[Npx]` or similar to control width |
|
|
216
|
-
|
|
217
|
-
---
|
|
218
|
-
|
|
219
|
-
## FULL EXAMPLE
|
|
220
|
-
|
|
221
|
-
```tsx
|
|
222
|
-
import { Diff } from 'solid-tom-ui';
|
|
223
|
-
|
|
224
|
-
// Image comparison
|
|
225
|
-
<Diff
|
|
226
|
-
images={[
|
|
227
|
-
<img alt="sharp" src="/images/sharp.webp" />,
|
|
228
|
-
<img alt="blurred" src="/images/blurred.webp" />,
|
|
229
|
-
]}
|
|
230
|
-
/>
|
|
231
|
-
|
|
232
|
-
// Image vs label panel, square aspect
|
|
233
|
-
<Diff
|
|
234
|
-
class="aspect-square w-full max-w-lg"
|
|
235
|
-
images={[
|
|
236
|
-
<img alt="photo" src="/images/photo.webp" />,
|
|
237
|
-
<div class="bg-neutral text-neutral-content grid place-content-center text-5xl font-black">
|
|
238
|
-
Solid UI
|
|
239
|
-
</div>,
|
|
240
|
-
]}
|
|
241
|
-
/>
|
|
242
|
-
```
|
|
243
|
-
|
|
244
|
-
> **Unique IDs**: if this component needs to generate HTML `id` attributes, always use `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|
|
1
|
+
## COMPONENT IDENTITY
|
|
2
|
+
- **Import**: `import { Diff } from 'solid-tom-ui';`
|
|
3
|
+
- **Export**: `Diff` (named export)
|
|
4
|
+
- **Framework**: SolidJS
|
|
5
|
+
- **Purpose**: Interactive image/content comparison slider — user drags a resizer to reveal left vs right panels; NOT a `ParentComponent`, content passed via `images` prop array
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## TYPE SIGNATURE
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
type DiffProps = {
|
|
13
|
+
images: SolidComponent[]; // REQUIRED — must be exactly 2 elements
|
|
14
|
+
class?: string; // extra classes on root <figure>
|
|
15
|
+
};
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## CLASS SLOTS
|
|
19
|
+
|
|
20
|
+
`Diff` is a single-element component — the `class` prop targets the root `<figure>` only. There are no named slots.
|
|
21
|
+
|
|
22
|
+
> **CSS encoding**: internal CSS classes follow the project convention using short encoded names (e.g. `df01`, `df02`). Do not reference DaisyUI's `diff-item-1` / `diff-item-2` class names directly in your own styles — use the `class` prop or wrap with your own container.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## PROP REFERENCE
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Required | Description |
|
|
29
|
+
| -------- | ------------------ | -------- | ------------------------------------------------------------------------------------- |
|
|
30
|
+
| `images` | `SolidComponent[]` | ✅ YES | Array of **exactly 2** JSX elements — index `0` = left panel, index `1` = right panel |
|
|
31
|
+
| `class` | `string` | ❌ NO | Extra Tailwind classes appended to the root `<figure>` element |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## HARD CONSTRAINT: `images` must have exactly 2 elements
|
|
36
|
+
|
|
37
|
+
- Passing fewer or more than 2 elements → component returns `<></>` (renders nothing) and fires `console.warn('You need to provide exactly 2 images')`
|
|
38
|
+
- There is no partial rendering fallback — the entire component is suppressed
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// ✅ Valid
|
|
42
|
+
images={[<img src="a.webp" />, <img src="b.webp" />]}
|
|
43
|
+
|
|
44
|
+
// ❌ Invalid — renders nothing
|
|
45
|
+
images={[<img src="a.webp" />]}
|
|
46
|
+
images={[<img src="a.webp" />, <img src="b.webp" />, <img src="c.webp" />]}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## INTERNAL DOM STRUCTURE
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
<figure class="diff aspect-video [class]" tabindex="0">
|
|
55
|
+
│
|
|
56
|
+
├── <div class="diff-item-1" role="img" tabindex="0">
|
|
57
|
+
│ {images[0]} ← LEFT panel (revealed by dragging resizer right)
|
|
58
|
+
│ </div>
|
|
59
|
+
│
|
|
60
|
+
├── <div class="diff-item-2" role="img">
|
|
61
|
+
│ {images[1]} ← RIGHT panel (base/background layer)
|
|
62
|
+
│ </div>
|
|
63
|
+
│
|
|
64
|
+
└── <div class="diff-resizer"></div> ← invisible drag handle
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Layer rendering order
|
|
68
|
+
|
|
69
|
+
- `diff-item-2` (right/background) renders behind — visible in full by default
|
|
70
|
+
- `diff-item-1` (left/foreground) renders on top with `z-index: 1`, clipped by the resizer position
|
|
71
|
+
- Dragging resizer RIGHT → reveals more of `images[0]` (left panel)
|
|
72
|
+
- Dragging resizer LEFT → reveals more of `images[1]` (right panel)
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## INTERACTION MECHANISM — CSS-only, no JS state
|
|
77
|
+
|
|
78
|
+
The slider is driven entirely by CSS using a native `resize: horizontal` invisible div (`.diff-resizer`):
|
|
79
|
+
|
|
80
|
+
- Default resizer position: `width: 50cqi` → panels shown 50/50
|
|
81
|
+
- Resizer `min-width: 1rem`, `max-width: calc(100cqi - 1rem)` — cannot be dragged beyond edges
|
|
82
|
+
- **Keyboard accessible**: `<figure tabindex="0">` and `<div class="diff-item-1" tabindex="0">` both focusable
|
|
83
|
+
- Focus on `<figure>` → resizer snaps to `min-width: 95cqi` (left panel nearly full)
|
|
84
|
+
- Focus on `diff-item-1` → resizer snaps to `min-width: 5cqi` (right panel nearly full)
|
|
85
|
+
- Snap transitions animated with `transition: min-width 0.3s ease-out`
|
|
86
|
+
|
|
87
|
+
Agents do NOT manage any open/close or drag state — it is fully CSS-driven.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## CONTENT RULES FOR `images[0]` AND `images[1]`
|
|
92
|
+
|
|
93
|
+
Both slots accept **any JSX element**, not just `<img>`. Internal CSS applies to all direct children:
|
|
94
|
+
|
|
95
|
+
```css
|
|
96
|
+
/* Applied to direct children of both diff-item-1 and diff-item-2 */
|
|
97
|
+
position: absolute;
|
|
98
|
+
top: 0;
|
|
99
|
+
bottom: 0;
|
|
100
|
+
left: 0;
|
|
101
|
+
height: 100%;
|
|
102
|
+
width: 100cqi;
|
|
103
|
+
object-fit: cover;
|
|
104
|
+
object-position: center;
|
|
105
|
+
pointer-events: none;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### What this means for agents:
|
|
109
|
+
|
|
110
|
+
- **`<img>`**: works perfectly — `object-fit: cover` is applied automatically
|
|
111
|
+
- **`<div>`**: also works — div fills the full panel area. Use `grid place-content-center` or flex for internal layout
|
|
112
|
+
- **Interactive elements inside panels**: will NOT work — `pointer-events: none` is applied to all children. Do NOT put buttons, links, or inputs inside `images`
|
|
113
|
+
- **Do NOT add layout wrappers** around the img/div — children are positioned absolutely with `width: 100cqi`
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## ASPECT RATIO
|
|
118
|
+
|
|
119
|
+
- Root `<figure>` always has class `aspect-video` (16:9 ratio) applied by default
|
|
120
|
+
- To change aspect ratio, override via `class` prop:
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
// Square
|
|
124
|
+
<Diff images={[...]} class="aspect-square" />
|
|
125
|
+
|
|
126
|
+
// Custom ratio
|
|
127
|
+
<Diff images={[...]} class="aspect-4/3" />
|
|
128
|
+
|
|
129
|
+
// Fixed height
|
|
130
|
+
<Diff images={[...]} class="h-100" />
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## USAGE PATTERNS
|
|
136
|
+
|
|
137
|
+
### Pattern 1 — Image vs image (most common)
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<Diff
|
|
141
|
+
images={[
|
|
142
|
+
<img alt="before" src="/images/before.webp" />,
|
|
143
|
+
<img alt="after" src="/images/after.webp" />,
|
|
144
|
+
]}
|
|
145
|
+
/>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Pattern 2 — Image vs custom div content
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
<Diff
|
|
152
|
+
images={[
|
|
153
|
+
<img alt="photo" src="/images/photo.webp" />,
|
|
154
|
+
<div class="bg-base-200 text-base-content grid place-content-center text-6xl font-black">
|
|
155
|
+
BEFORE
|
|
156
|
+
</div>,
|
|
157
|
+
]}
|
|
158
|
+
/>
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Pattern 3 — Custom aspect ratio
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<Diff
|
|
165
|
+
class="aspect-square w-100"
|
|
166
|
+
images={[
|
|
167
|
+
<img alt="original" src="/images/original.webp" />,
|
|
168
|
+
<img alt="filtered" src="/images/filtered.webp" />,
|
|
169
|
+
]}
|
|
170
|
+
/>
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Pattern 4 — Two styled div panels
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
<Diff
|
|
177
|
+
images={[
|
|
178
|
+
<div class="bg-primary text-primary-content grid place-content-center text-4xl font-bold">
|
|
179
|
+
Dark Mode
|
|
180
|
+
</div>,
|
|
181
|
+
<div class="bg-base-100 text-base-content grid place-content-center text-4xl font-bold">
|
|
182
|
+
Light Mode
|
|
183
|
+
</div>,
|
|
184
|
+
]}
|
|
185
|
+
/>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## BEHAVIOR NOTES FOR AGENTS
|
|
191
|
+
|
|
192
|
+
1. **`images[0]` = left (foreground), `images[1]` = right (background)** — the order determines which panel is clipped by the drag handle. Left panel sits on top and is revealed by dragging right.
|
|
193
|
+
|
|
194
|
+
2. **Component is a `<figure>` element** — semantically appropriate for media comparison. Root is not a `<div>`.
|
|
195
|
+
|
|
196
|
+
3. **`pointer-events: none` on all panel children** — nothing inside `images[0]` or `images[1]` can be clicked, hovered, or interacted with. Only the resizer handle is interactive.
|
|
197
|
+
|
|
198
|
+
4. **No JS drag state** — the drag interaction is entirely driven by the native browser `resize: horizontal` CSS property on `.diff-resizer`. No SolidJS signals or event handlers involved.
|
|
199
|
+
|
|
200
|
+
5. **`class` prop targets the root `<figure>` only** — cannot target internal `.diff-item-1`, `.diff-item-2`, or `.diff-resizer` via this prop.
|
|
201
|
+
|
|
202
|
+
6. **Width fills container** — root `<figure>` has `width: 100%`. Wrap in a sized container or use `class="w-[500px]"` to constrain.
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## COMMON MISTAKES TO AVOID
|
|
207
|
+
|
|
208
|
+
| Mistake | Correct approach |
|
|
209
|
+
| ------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
|
210
|
+
| Passing 1 or 3+ items in `images` | Always pass exactly 2 elements — no more, no less |
|
|
211
|
+
| Putting interactive elements (buttons, links) inside `images` | `pointer-events: none` blocks all interactions inside panels |
|
|
212
|
+
| Wrapping `<img>` in an extra `<div>` | Pass `<img>` directly — children are already positioned absolutely to fill the panel |
|
|
213
|
+
| Expecting `class` to style inner panels | `class` only applies to the root `<figure>` |
|
|
214
|
+
| Assuming left panel is `images[1]` | `images[0]` = left/foreground (clipped), `images[1]` = right/background |
|
|
215
|
+
| Using without a sized container | Add `w-full`, `w-[Npx]` or similar to control width |
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## FULL EXAMPLE
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
import { Diff } from 'solid-tom-ui';
|
|
223
|
+
|
|
224
|
+
// Image comparison
|
|
225
|
+
<Diff
|
|
226
|
+
images={[
|
|
227
|
+
<img alt="sharp" src="/images/sharp.webp" />,
|
|
228
|
+
<img alt="blurred" src="/images/blurred.webp" />,
|
|
229
|
+
]}
|
|
230
|
+
/>
|
|
231
|
+
|
|
232
|
+
// Image vs label panel, square aspect
|
|
233
|
+
<Diff
|
|
234
|
+
class="aspect-square w-full max-w-lg"
|
|
235
|
+
images={[
|
|
236
|
+
<img alt="photo" src="/images/photo.webp" />,
|
|
237
|
+
<div class="bg-neutral text-neutral-content grid place-content-center text-5xl font-black">
|
|
238
|
+
Solid UI
|
|
239
|
+
</div>,
|
|
240
|
+
]}
|
|
241
|
+
/>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
> **Unique IDs**: if this component needs to generate HTML `id` attributes, always use `createUniqueId()` from `solid-js` — never `Math.random()` or `Date.now()`.
|