Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 7 additions & 59 deletions .claude/skills/lit-migration/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ Migrate Tyler Forge components from the legacy component/core/adapter/template a
- Complexity level (simple/moderate/complex)

2. **Identify migration patterns** by reviewing similar migrated components:
- Simple light DOM: `packages/forge/src/lib/accordion/accordion.ts` (branch: `feat/accordion-lit`)
- Complex with shadow DOM: `feat/expansion-panel-lit` branch
- With custom setters: `packages/forge/src/lib/icon/icon.ts` (branch: `feat/icon-lit`)
- Simple light DOM: `packages/forge/src/lib/accordion/accordion.ts`
- Complex with shadow DOM: `packages/forge/src/lib/expansion-panel/expansion-panel.ts`
- With custom setters: `packages/forge/src/lib/icon/icon.ts`

3. **Create migration branch**:
```bash
Expand All @@ -44,9 +44,7 @@ Migrate Tyler Forge components from the legacy component/core/adapter/template a

**Goal**: Set up new file structure and delete legacy files.

1. **Ensure clean git state** - commit or stash any changes first

2. **Delete legacy files**:
1. **Delete legacy files**:
- `component-adapter.ts`
- `component-core.ts`
- `component.html` (if exists)
Expand Down Expand Up @@ -827,8 +825,6 @@ Tests should pass without modification. If they fail:
- Check event names and detail structure
- Ensure deprecated interfaces are still exported
- Verify attribute reflection behavior
<<<<<<< feat/divider-lit
=======
- Add `await element.updateComplete` between property changes and assertions that depend on listener state or `willUpdate()` side effects

```typescript
Expand All @@ -845,8 +841,6 @@ dispatchKeyboardEvent({ key: 'a', ctrlKey: true });
expect(spy).toHaveBeenCalledOnce();
```

> > > > > > > main

#### 2. Run Build

```bash
Expand Down Expand Up @@ -989,48 +983,10 @@ BREAKING CHANGE: Internal architecture changed from component/core/adapter patte
- All functionality preserved with improved performance and maintainability
```

#### 6. Commit Changes

Use conventional commit format:
#### 6. Create Changeset

```bash
git add .
git commit -m "feat(component-name)!: migrate to Lit

BREAKING CHANGE: Internal architecture changed to Lit.
Component API remains the same for consumers."
```

#### 7. Create Pull Request

```bash
# Push branch
git push -u origin feat/component-name-lit

# Create PR using gh CLI
gh pr create --title "feat(component-name)!: migrate to Lit" --body "$(cat <<'EOF'
## Summary
Migrates component-name from legacy component/core/adapter/template architecture to Lit-based component.

## Changes
- Consolidated 4 files into single component file
- Replaced core/adapter pattern with Lit reactive properties
- Maintained all existing functionality and public API
- Added backward compatibility for legacy decorators

## Testing
- [ ] All existing tests pass
- [ ] Build succeeds
- [ ] Linter passes
- [ ] Visual testing in Storybook verified
- [ ] Accessibility verified

## Breaking Changes
Internal architecture changed - consumers should see no differences, but internal implementation details are no longer accessible.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
pnpm changeset
```

## Quick Reference
Expand Down Expand Up @@ -1250,37 +1206,29 @@ Study these completed migrations for patterns:

### Simple Shadow DOM Component

- **Branch**: `feat/divider-lit`
- **File**: `packages/forge/src/lib/divider/divider.ts`
- **Patterns**: Boolean reflected property, custom state, shadow DOM, ElementInternals, `:state(...)` SCSS

### Simple Light DOM Component

- **Branch**: `feat/accordion-lit`
- **File**: `packages/forge/src/lib/accordion/accordion.ts`
- **Patterns**: Basic properties, event handling, light DOM, no render method

### Complex Shadow DOM Component

- **Branch**: `feat/expansion-panel-lit`
- **File**: `packages/forge/src/lib/expansion-panel/expansion-panel.ts`
- **Patterns**: ElementInternals, custom states, controllers, animations, shadow DOM

### Component with Custom Setters

- **Branch**: `feat/icon-lit`
- **File**: `packages/forge/src/lib/icon/icon.ts`
- **Patterns**: Property validation, custom setters, lazy loading, external content

# <<<<<<< feat/divider-lit

### Non-Visual Utility Component (No Template, No Shadow DOM)

- **Branch**: `feat/keyboard-shortcut-lit`
- **File**: `packages/forge/src/lib/keyboard-shortcut/keyboard-shortcut.ts`
- **Patterns**: `createRenderRoot()` returning `this`, no `render()`, `display: none` in `connectedCallback`, `willUpdate()` for listener management, `isConnected` guard, old value via `changedProperties.get()`, `#disconnect(capture = this.capture)` optional parameter for old-value disconnect

> > > > > > > main

## Conventions Summary

**CRITICAL - Follow these conventions:**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,6 @@ public get step(): number {

### Property with Side Effects

<<<<<<< feat/divider-lit
When setter needs to trigger other updates immediately:

=======
Expand All @@ -441,8 +440,6 @@ public willUpdate(changedProperties: PropertyValues<this>): void {

**Custom setter approach** (only when you need synchronous value transformation):

> > > > > > > main

```typescript
/**
* The trigger element id.
Expand All @@ -451,11 +448,7 @@ public willUpdate(changedProperties: PropertyValues<this>): void {
@property({ reflect: true })
public set trigger(value: string) {
this.#trigger = value;
<<<<<<< feat/divider-lit
// Immediately resolve trigger element
=======
// Immediately resolve trigger element (synchronous lookup needed)
>>>>>>> main
this.triggerElement = value ? document.getElementById(value) : null;
}
public get trigger(): string {
Expand Down
1 change: 1 addition & 0 deletions packages/forge/src/dev/pages/drawer/drawer.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
border: 1px solid var(--forge-theme-outline);
background-color: var(--forge-theme-surface-dim);
height: 370px;
contain: paint;
}

.drawer-demo-container {
Expand Down
92 changes: 44 additions & 48 deletions packages/forge/src/lib/drawer/base/_core.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

@forward './token-utils';

@mixin core-styles() {
@mixin core-styles {
.forge-drawer {
@include tokens;
}
Expand All @@ -24,44 +24,50 @@
@include content;
}

&.left {
@include left;
&.no-transition {
transition: none !important;
}

&.right {
@include right;

&.closing {
@include closing(right);
&.animating {
.content {
@include animating-content;
}
}
}

&.closed {
@include closed(right);
}
:host(:not(:state(right))) {
.forge-drawer {
@include left;
}
}

&.closing {
@include closing(left);
:host(:state(right)) {
.forge-drawer {
@include right;
}
}

&.closed {
@include closed(left);
:host(:not(:state(open))) {
.forge-drawer {
@include closed;
}
}

&.no-transition {
@media (prefers-reduced-motion: reduce) {
.forge-drawer {
transition: none !important;
}
}
}

@mixin host() {
@mixin host {
display: grid;
box-sizing: border-box;
height: 100%;
overflow: hidden !important; // Using important to ensure that it overrides the scaffold overflow style
}

@mixin base() {
@mixin base {
width: #{token(width)};
height: 100%;
box-sizing: border-box;
Expand All @@ -74,65 +80,55 @@
background-color: #{token(background)};
border-color: #{token(border-color)};

transition-property: transform;
transition-property: width, display;
transition-duration: #{token(transition-duration)};
transition-timing-function: #{token(transition-easing)};
transition-behavior: allow-discrete;

@starting-style {
width: 0;
}
}

@mixin header() {
@mixin header {
grid-row: 1;
min-height: 0;
}

@mixin content() {
@mixin content {
@include scrollbar.base;

overflow-x: auto;
-webkit-overflow-scrolling: 'touch';

width: auto;
min-height: 0;
display: flex;
flex-direction: column;
grid-row: 2;
overflow-y: auto;
}

@mixin footer() {
@mixin footer {
grid-row: 3;
min-height: 0;
}

@mixin left() {
@mixin left {
border-right-width: #{token(border-width)};
border-right-style: solid;
}

@mixin right() {
@mixin right {
border-left-width: #{token(border-width)};
border-left-style: solid;
}

@mixin closed($direction: left) {
@include closed-direction($direction);

@mixin closed {
display: none;
width: 0;
border: none;
}

@mixin closing($direction: left) {
@include closed-direction($direction);

z-index: #{elevation.z-index-variable(surface)};
position: absolute;
top: 0;
right: 0;

transition-duration: #{token(transition-duration-close)};
}

@mixin closed-direction($direction: left) {
@if $direction == right {
transform: translateX(100%);
right: 0;
left: auto;
} @else {
transform: translateX(-100%);
left: 0;
}
@mixin animating-content {
width: #{token(width)};
}
Loading
Loading