Skip to content

Commit

Permalink
feat: improve lit-ts example with shared Component class (#1995)
Browse files Browse the repository at this point in the history
  • Loading branch information
gperdomor authored Oct 28, 2024
1 parent 85aa147 commit 00a4857
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 136 deletions.
50 changes: 16 additions & 34 deletions examples/lit-ts/src/accordion-element.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,39 @@
import { spread } from "@open-wc/lit-helpers"
import * as accordion from "@zag-js/accordion"
import { StateFrom } from "@zag-js/core"
import { Machine } from "@zag-js/core"
import { accordionData } from "@zag-js/shared"
import { LitElement, html, unsafeCSS } from "lit"
import { customElement, state } from "lit/decorators.js"
import { normalizeProps } from "./normalize-props"
import { PropTypes } from "@zag-js/types"
import { html, unsafeCSS } from "lit"
import { customElement } from "lit/decorators.js"
import styles from "../../../shared/src/css/accordion.css?inline"
import { Component } from "./component"
import { normalizeProps } from "./normalize-props"

@customElement("accordion-element")
export class AccordionElement extends LitElement {
private service: accordion.Service

@state()
private state: StateFrom<accordion.Service>

constructor() {
super()
this.service = accordion.machine({ id: "1" })
this.service._created()

this.state = this.service.getState()
this.service.subscribe((state) => {
this.state = state
})
}

connectedCallback(): void {
super.connectedCallback()
this.service.start()
export class AccordionElement extends Component<accordion.Context, accordion.Api, accordion.Service> {
initService(context: accordion.Context): Machine<any, any, any> {
return accordion.machine({ ...context, id: "1" })
}

disconnectedCallback(): void {
super.disconnectedCallback()
this.service.stop()
initApi(): accordion.Api<PropTypes> {
return accordion.connect(this.state, this.service.send, normalizeProps)
}

render() {
const api = accordion.connect(this.state, this.service.send, normalizeProps)

return html`
<div ${spread(api.getRootProps())}>
<div ${spread(this.api.getRootProps())}>
${accordionData.map(
(item) =>
html`<div ${spread(api.getItemProps({ value: item.id }))}>
html`<div ${spread(this.api.getItemProps({ value: item.id }))}>
<h3>
<button data-testid=${`${item.id}:trigger`} ${spread(api.getItemTriggerProps({ value: item.id }))}>
<button data-testid=${`${item.id}:trigger`} ${spread(this.api.getItemTriggerProps({ value: item.id }))}>
${item.label}
<div ${spread(api.getItemIndicatorProps({ value: item.id }))}>
<div ${spread(this.api.getItemIndicatorProps({ value: item.id }))}>
<ArrowRight />
</div>
</button>
</h3>
<div data-testid=${`${item.id}:content`} ${spread(api.getItemContentProps({ value: item.id }))}>
<div data-testid=${`${item.id}:content`} ${spread(this.api.getItemContentProps({ value: item.id }))}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua.
</div>
Expand Down
45 changes: 14 additions & 31 deletions examples/lit-ts/src/avatar-element.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,31 @@
import { spread } from "@open-wc/lit-helpers"
import * as avatar from "@zag-js/avatar"
import { StateFrom } from "@zag-js/core"
import { LitElement, html, unsafeCSS } from "lit"
import { customElement, state } from "lit/decorators.js"
import { normalizeProps } from "./normalize-props"
import { Machine } from "@zag-js/core"
import { PropTypes } from "@zag-js/types"
import { html, unsafeCSS } from "lit"
import { customElement } from "lit/decorators.js"
import styles from "../../../shared/src/css/avatar.css?inline"
import { Component } from "./component"
import { normalizeProps } from "./normalize-props"

@customElement("avatar-element")
export class AvatarElement extends LitElement {
private service: avatar.Service

@state()
private state: StateFrom<avatar.Service>

constructor() {
super()
this.service = avatar.machine({ id: "1" })
this.service._created()

this.state = this.service.getState()
this.service.subscribe((state) => {
this.state = state
})
}

connectedCallback(): void {
super.connectedCallback()
this.service.start()
export class AvatarElement extends Component<avatar.Context, avatar.Api, avatar.Service> {
initService(context: avatar.Context): Machine<any, any, any> {
return avatar.machine({ ...context, id: "1" })
}

disconnectedCallback(): void {
super.disconnectedCallback()
this.service.stop()
initApi(): avatar.Api<PropTypes> {
return avatar.connect(this.state, this.service.send, normalizeProps)
}

render() {
const api = avatar.connect(this.state, this.service.send, normalizeProps)
const src =
"https://images.unsplash.com/photo-1633332755192-727a05c4013d?w=800&auto=format&fit=crop&q=60&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxzZWFyY2h8M3x8aGVhZHNob3R8ZW58MHx8MHx8fDA%3D"

return html`
<div ${spread(api.getRootProps())}>
<span ${spread(api.getFallbackProps())}>PA</span>
<img src=${src} ${spread(api.getImageProps())} />
<div ${spread(this.api.getRootProps())}>
<span ${spread(this.api.getFallbackProps())}>PA</span>
<img src=${src} ${spread(this.api.getImageProps())} />
</div>
`
}
Expand Down
52 changes: 17 additions & 35 deletions examples/lit-ts/src/carousel-element.ts
Original file line number Diff line number Diff line change
@@ -1,52 +1,34 @@
import { spread } from "@open-wc/lit-helpers"
import * as carousel from "@zag-js/carousel"
import { StateFrom } from "@zag-js/core"
import { Machine } from "@zag-js/core"
import { carouselData } from "@zag-js/shared"
import { LitElement, html, unsafeCSS } from "lit"
import { customElement, state } from "lit/decorators.js"
import { normalizeProps } from "./normalize-props"
import { PropTypes } from "@zag-js/types"
import { html, unsafeCSS } from "lit"
import { customElement } from "lit/decorators.js"
import styles from "../../../shared/src/css/carousel.css?inline"
import { Component } from "./component"
import { normalizeProps } from "./normalize-props"

@customElement("carousel-element")
export class CarouselElement extends LitElement {
private service: carousel.Service

@state()
private state: StateFrom<carousel.Service>

constructor() {
super()
this.service = carousel.machine({ id: "1", index: 0, spacing: "20px", slidesPerView: 2 })
this.service._created()

this.state = this.service.getState()
this.service.subscribe((state) => {
this.state = state
})
}

connectedCallback(): void {
super.connectedCallback()
this.service.start()
export class CarouselElement extends Component<carousel.Context, carousel.Api, carousel.Service> {
initService(context: carousel.Context): Machine<any, any, any> {
return carousel.machine({ ...context, id: "1", index: 0, spacing: "20px", slidesPerView: 2 })
}

disconnectedCallback(): void {
super.disconnectedCallback()
this.service.stop()
initApi(): carousel.Api<PropTypes> {
return carousel.connect(this.state, this.service.send, normalizeProps)
}

render() {
const api = carousel.connect(this.state, this.service.send, normalizeProps)

return html`
<div ${spread(api.getRootProps())}>
<button ${spread(api.getPrevTriggerProps())}>Prev</button>
<button ${spread(api.getNextTriggerProps())}>Next</button>
<div ${spread(api.getViewportProps())}>
<div ${spread(api.getItemGroupProps())}>
<div ${spread(this.api.getRootProps())}>
<button ${spread(this.api.getPrevTriggerProps())}>Prev</button>
<button ${spread(this.api.getNextTriggerProps())}>Next</button>
<div ${spread(this.api.getViewportProps())}>
<div ${spread(this.api.getItemGroupProps())}>
${carouselData.map(
(image, index) =>
html`<div ${spread(api.getItemProps({ index }))}>
html`<div ${spread(this.api.getItemProps({ index }))}>
<img src="${image}" alt="" style="height: 300px; width: 100%; object-fit: cover;" />
</div>`,
)}
Expand Down
44 changes: 44 additions & 0 deletions examples/lit-ts/src/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Machine, StateFrom } from "@zag-js/core"
import { LitElement } from "lit"
import { state } from "lit/decorators.js"

interface ComponentInterface<Api, Service> {
api: Api
service: ReturnType<any>
state: StateFrom<Service>
}

export abstract class Component<Context, Api, Service> extends LitElement implements ComponentInterface<Api, Service> {
api: Api
service: ReturnType<any>

@state()
state: StateFrom<Service>

abstract initService(context: Context): Machine<any, any, any>
abstract initApi(): Api

constructor(context: Context) {
super()
this.service = this.initService(context)
this.service._created()

this.state = this.service.getState()
this.api = this.initApi()

this.service.subscribe((state: StateFrom<Service>) => {
this.state = state
this.api = this.initApi()
})
}

override connectedCallback(): void {
super.connectedCallback()
this.service.start()
}

override disconnectedCallback(): void {
super.disconnectedCallback()
this.service.stop()
}
}
58 changes: 22 additions & 36 deletions examples/lit-ts/src/menu-element.ts
Original file line number Diff line number Diff line change
@@ -1,57 +1,43 @@
import { spread } from "@open-wc/lit-helpers"
import { Machine } from "@zag-js/core"
import * as menu from "@zag-js/menu"
import { StateFrom } from "@zag-js/core"
import { LitElement, html, unsafeCSS } from "lit"
import { customElement, state } from "lit/decorators.js"
import { normalizeProps } from "./normalize-props"
import { PropTypes } from "@zag-js/types"
import { html, unsafeCSS } from "lit"
import { customElement } from "lit/decorators.js"
import styles from "../../../shared/src/css/menu.css?inline"
import { Component } from "./component"
import { normalizeProps } from "./normalize-props"

@customElement("menu-element")
export class MenuElement extends LitElement {
private service: menu.Service

@state()
private state: StateFrom<menu.Service>

constructor() {
super()
export class MenuElement extends Component<menu.Context, menu.Api, menu.Service> {
initService(context: menu.Context): Machine<any, any, any> {
const host = this
this.service = menu.machine({

return menu.machine({
...context,
id: "1",
onSelect: console.log,
getRootNode() {
return host.shadowRoot as ShadowRoot
},
})
this.service._created()

this.state = this.service.getState()
this.service.subscribe((state) => {
this.state = state
})
}

connectedCallback(): void {
super.connectedCallback()
this.service.start()
}

disconnectedCallback(): void {
super.disconnectedCallback()
this.service.stop()
initApi(): menu.Api<PropTypes> {
return menu.connect(this.state, this.service.send, normalizeProps)
}

render() {
const api = menu.connect(this.state, this.service.send, normalizeProps)

return html`
<button ${spread(api.getTriggerProps())}>Actions <span ${spread(api.getIndicatorProps())}></span></button>
<div ${spread(api.getPositionerProps())}>
<ul ${spread(api.getContentProps())}>
<li ${spread(api.getItemProps({ value: "edit" }))}>Edit</li>
<li ${spread(api.getItemProps({ value: "duplicate" }))}>Duplicate</li>
<li ${spread(api.getItemProps({ value: "delete" }))}>Delete</li>
<li ${spread(api.getItemProps({ value: "export" }))}>Export...</li>
<button ${spread(this.api.getTriggerProps())}>
Actions <span ${spread(this.api.getIndicatorProps())}></span>
</button>
<div ${spread(this.api.getPositionerProps())}>
<ul ${spread(this.api.getContentProps())}>
<li ${spread(this.api.getItemProps({ value: "edit" }))}>Edit</li>
<li ${spread(this.api.getItemProps({ value: "duplicate" }))}>Duplicate</li>
<li ${spread(this.api.getItemProps({ value: "delete" }))}>Delete</li>
<li ${spread(this.api.getItemProps({ value: "export" }))}>Export...</li>
</ul>
</div>
`
Expand Down

0 comments on commit 00a4857

Please sign in to comment.