Skip to content

Commit cf86e26

Browse files
committed
feat(compiler): in package source react skin -> html skin (module)
1 parent 546989c commit cf86e26

103 files changed

Lines changed: 11512 additions & 347 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

commitlint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default {
3030
'skins',
3131
'test',
3232
'utils',
33+
'compiler',
3334
]],
3435
},
3536
};
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Component Mapping Reference
2+
3+
**Purpose**: Documents the verified mapping between React components and HTML web components
4+
5+
**Status**: ✅ Verified against `packages/html` implementation
6+
7+
---
8+
9+
## Transformation Rules
10+
11+
### Simple Components
12+
13+
| React Component | HTML Element | Notes |
14+
| ---------------------- | ------------------------------ | ---------------------- |
15+
| `<PlayButton>` | `<media-play-button>` | ✅ Verified |
16+
| `<MuteButton>` | `<media-mute-button>` | ✅ Verified |
17+
| `<FullscreenButton>` | `<media-fullscreen-button>` | ✅ Verified |
18+
| `<MediaContainer>` | `<media-container>` | ✅ Verified |
19+
| `<CurrentTimeDisplay>` | `<media-current-time-display>` | ✅ Verified |
20+
| `<DurationDisplay>` | `<media-duration-display>` | ✅ Verified |
21+
| `<PreviewTimeDisplay>` | `<media-preview-time-display>` | ✅ Verified |
22+
| `<Popover>` | `<media-popover>` | Single element in HTML |
23+
| `<Tooltip>` | `<media-tooltip>` | Single element in HTML |
24+
25+
### Icon Components
26+
27+
| React Component | HTML Element |
28+
| ----------------------- | ------------------------------- |
29+
| `<PlayIcon>` | `<media-play-icon>` |
30+
| `<PauseIcon>` | `<media-pause-icon>` |
31+
| `<VolumeHighIcon>` | `<media-volume-high-icon>` |
32+
| `<VolumeLowIcon>` | `<media-volume-low-icon>` |
33+
| `<VolumeOffIcon>` | `<media-volume-off-icon>` |
34+
| `<FullscreenEnterIcon>` | `<media-fullscreen-enter-icon>` |
35+
| `<FullscreenExitIcon>` | `<media-fullscreen-exit-icon>` |
36+
37+
### Compound Components (TimeSlider)
38+
39+
**Important**: `.Root` maps to base element name (no `-root` suffix)
40+
41+
| React Component | HTML Element | Rule |
42+
| ----------------------- | ------------------------------ | ------------------- |
43+
| `<TimeSlider.Root>` | `<media-time-slider>` | ⚠️ Root → base name |
44+
| `<TimeSlider.Track>` | `<media-time-slider-track>` | ✅ Standard |
45+
| `<TimeSlider.Progress>` | `<media-time-slider-progress>` | ✅ Standard |
46+
| `<TimeSlider.Pointer>` | `<media-time-slider-pointer>` | ✅ Standard |
47+
| `<TimeSlider.Thumb>` | `<media-time-slider-thumb>` | ✅ Standard |
48+
49+
### Compound Components (VolumeSlider)
50+
51+
| React Component | HTML Element | Rule |
52+
| -------------------------- | --------------------------------- | ------------------- |
53+
| `<VolumeSlider.Root>` | `<media-volume-slider>` | ⚠️ Root → base name |
54+
| `<VolumeSlider.Track>` | `<media-volume-slider-track>` | ✅ Standard |
55+
| `<VolumeSlider.Progress>` | `<media-volume-slider-progress>` | ✅ Standard |
56+
| `<VolumeSlider.Indicator>` | `<media-volume-slider-indicator>` | ✅ Standard |
57+
| `<VolumeSlider.Thumb>` | `<media-volume-slider-thumb>` | ✅ Standard |
58+
59+
---
60+
61+
## Algorithm
62+
63+
### Element Name Transformation
64+
65+
1. **Built-in HTML elements** → Unchanged
66+
- `<div>`, `<button>`, `<span>`, etc. → lowercase, no prefix
67+
68+
2. **Simple custom elements** → PascalCase to kebab-case with prefix
69+
- `<PlayButton>``media-` + `play-button``<media-play-button>`
70+
71+
3. **Compound elements (Member expressions)**
72+
- Extract object and property: `TimeSlider.Root``TimeSlider` + `Root`
73+
- **Special case**: If property is `Root` → use base name only
74+
- `TimeSlider.Root``media-time-slider` (NOT `media-time-slider-root`)
75+
- **All other properties**: Concatenate and transform
76+
- `TimeSlider.Track``TimeSlider` + `Track``media-time-slider-track`
77+
78+
### Pseudo-Code
79+
80+
```typescript
81+
function transformElementName(name) {
82+
if (isBuiltIn(name)) {
83+
return name.toLowerCase();
84+
}
85+
86+
if (isMemberExpression(name)) {
87+
const object = getObjectName(name); // "TimeSlider"
88+
const property = getPropertyName(name); // "Root"
89+
90+
if (property === 'Root') {
91+
return `media-${pascalToKebab(object)}`;
92+
}
93+
94+
const combined = object + property; // "TimeSliderTrack"
95+
return `media-${pascalToKebab(combined)}`;
96+
}
97+
98+
// Simple element
99+
return `media-${pascalToKebab(name)}`;
100+
}
101+
```
102+
103+
---
104+
105+
## Components Requiring Structural Transformation
106+
107+
These React components use floating-ui and require **structural transformation**, not just element name mapping.
108+
109+
### Tooltip Pattern
110+
111+
**React version** (nested compound components):
112+
113+
```tsx
114+
<Tooltip.Root delay={500}>
115+
<Tooltip.Trigger>
116+
<PlayButton>
117+
<PlayIcon />
118+
</PlayButton>
119+
</Tooltip.Trigger>
120+
<Tooltip.Portal>
121+
<Tooltip.Positioner side="top" sideOffset={12} collisionPadding={12}>
122+
<Tooltip.Popup>
123+
<span>Play</span>
124+
</Tooltip.Popup>
125+
</Tooltip.Positioner>
126+
</Tooltip.Portal>
127+
</Tooltip.Root>
128+
```
129+
130+
**HTML version** (flat with commandfor linking):
131+
132+
```html
133+
<media-play-button commandfor="play-tooltip" class="button">
134+
<media-play-icon class="icon"></media-play-icon>
135+
</media-play-button>
136+
<media-tooltip
137+
id="play-tooltip"
138+
popover="manual"
139+
delay="500"
140+
side="top"
141+
side-offset="12"
142+
collision-padding="12"
143+
>
144+
<span>Play</span>
145+
</media-tooltip>
146+
```
147+
148+
### Popover Pattern
149+
150+
**React version**:
151+
152+
```tsx
153+
<Popover.Root openOnHover delay={200} closeDelay={100}>
154+
<Popover.Trigger>
155+
<MuteButton>...</MuteButton>
156+
</Popover.Trigger>
157+
<Popover.Portal>
158+
<Popover.Positioner side="top" sideOffset={12}>
159+
<Popover.Popup>
160+
<VolumeSlider.Root>...</VolumeSlider.Root>
161+
</Popover.Popup>
162+
</Popover.Positioner>
163+
</Popover.Portal>
164+
</Popover.Root>
165+
```
166+
167+
**HTML version**:
168+
169+
```html
170+
<media-mute-button commandfor="volume-slider-popover" command="toggle-popover">
171+
...
172+
</media-mute-button>
173+
<media-popover
174+
id="volume-slider-popover"
175+
popover="manual"
176+
open-on-hover
177+
delay="200"
178+
close-delay="100"
179+
side="top"
180+
side-offset="12"
181+
>
182+
<media-volume-slider orientation="vertical">...</media-volume-slider>
183+
</media-popover>
184+
```
185+
186+
### Required Transformations
187+
188+
1. **Flatten nested structure** - Remove Root/Trigger/Portal/Positioner/Popup wrappers
189+
2. **Extract trigger element** - First child of Trigger becomes standalone
190+
3. **Generate IDs** - Create unique IDs for linking (e.g., `play-tooltip`)
191+
4. **Add commandfor attribute** - Link trigger to tooltip/popover
192+
5. **Merge attributes** - Combine attrs from Root/Positioner/Popup into single element
193+
6. **Move content** - Content from Popup becomes tooltip/popover children
194+
195+
### Status
196+
197+
**v0.1**: ❌ Not implemented - Tooltip/Popover will compile but produce incorrect structure
198+
**Future**: ⏳ Requires transformation rule system (Phase 2+)
199+
200+
**Current behavior**: Naively transforms compound components
201+
202+
- `<Tooltip.Root>``<media-tooltip>` (Root rule)
203+
- `<Tooltip.Trigger>``<media-tooltip-trigger>`
204+
- Result: Incorrect nested structure instead of flat HTML pattern
205+
206+
---
207+
208+
## Test Coverage
209+
210+
**Verified in test suite** (26/26 tests passing):
211+
212+
✅ All simple components (PlayButton, MuteButton, etc.)
213+
✅ All icon components
214+
✅ All TimeSlider subcomponents (including Root special case)
215+
✅ All VolumeSlider subcomponents (including Root special case)
216+
✅ Nested structures
217+
✅ Attribute transformation
218+
✅ className extraction
219+
✅ {children} → slot transformation
220+
221+
---
222+
223+
## Current Limitations (v0.1)
224+
225+
1. **Template literal classNames** - Not fully resolved
226+
- `className={\`${styles.A} ${styles.B}\`}` → Not extracted
227+
- **Workaround**: Use single className references for now
228+
229+
2. **Tooltip/Popover compound components** - Need special handling
230+
- React version uses floating-ui with many subcomponents
231+
- HTML version is single element
232+
- **Future**: Add transformation rules or replacement logic
233+
234+
3. **Complex className expressions** - Not supported
235+
- Conditional classNames
236+
- Array/object classNames
237+
- Computed values
238+
239+
---
240+
241+
**Last Updated**: 2025-11-07
242+
**Package Version**: @videojs/compiler@0.1.0

0 commit comments

Comments
 (0)