Changes
4 changed files (+125/-13)
-
-
@@ -623,8 +623,8 @@ group : GroupProps Msg -> List (Html.Html Msg) -> Html.Html Msggroup { title, description } children = node "x-field-group" [] (p [ slot "title" ] title :: (description |> Maybe.map (p [ slot "description" ]) |> Maybe.withDefault (text "")) (span [ slot "title" ] title :: (description |> Maybe.map (span [ slot "description" ]) |> Maybe.withDefault (text "")) :: children )
-
-
-
@@ -137,8 +137,8 @@ panelItems : Model -> List (Html Msg)panelItems model = [ node "x-field-group" [] [ p [ slot "title" ] [ text "Preferences" ] , p [ slot "description" ] [ text "These parameters are saved to this browser, and will not be shared." ] [ span [ slot "title" ] [ text "Preferences" ] , span [ slot "description" ] [ text "These parameters are saved to this browser, and will not be shared." ] , node "x-field" [] [ span [ slot "title" ] [ text "Preview Color Theme" ]
-
-
-
@@ -11,22 +11,81 @@:host { display: flex; flex-direction: column; gap: 0.5rem; } .header { appearance: none; border: 0; padding: 0; padding: 1em; margin: 0; display: grid; grid-template-columns: 1fr min-content; gap: 0 0.5rem; grid-template-areas: "title caret" "description description"; background: transparent; outline: 0; text-align: start; } .caret { align-self: center; display: flex; justify-content: center; align-items: center; width: 1.5rem; height: 1.5rem; font-family: "Barlow", sans-serif; font-size: 1rem; border-radius: 50%; transition: background-color 80ms ease-out; } .header { margin-bottom: 1rem; .header:hover, .header:focus-visible { .caret { background-color: ButtonFace; } } .caret-symbol { margin-left: 0.18em; transform: rotate(90deg); @media not (prefers-reduced-motion: reduce) { transition: transform 100ms ease-out; } } :host([opened]) .caret-symbol { transform: rotate(90deg) scaleX(-1); } ::slotted([slot="title"]) { grid-area: title; font-weight: 300; font-size: 1.2rem; } ::slotted([slot="description"]) { grid-area: description; padding: 0.5em 0; font-size: 0.8rem; opacity: 0.8; } .body { display: none; flex-direction: column; gap: 0.5rem; padding: 1em; } :host([opened]) .body { display: flex; }
-
-
-
@@ -9,6 +9,10 @@import css from "./x-field-group.css"; export class XFieldGroup extends HTMLElement { static observedAttributes = ["opened"]; #trigger = document.createElement("button"); constructor() { super();
-
@@ -16,23 +20,72 @@ const shadow = this.attachShadow({mode: "open", }); const bodyId = "group-" + (typeof crypto.randomUUID === "function" ? crypto.randomUUID() : Math.floor(Math.random() * 0xffffffff).toString(16)); const style = document.createElement("style"); style.textContent = css; shadow.appendChild(style); const header = document.createElement("div"); header.classList.add("header"); shadow.appendChild(header); this.#trigger.setAttribute("aria-expanded", "true"); this.#trigger.setAttribute("aria-controls", bodyId); this.#trigger.classList.add("header"); shadow.appendChild(this.#trigger); const title = document.createElement("slot"); title.name = "title"; header.appendChild(title); this.#trigger.appendChild(title); const description = document.createElement("slot"); description.name = "description"; header.appendChild(description); this.#trigger.appendChild(description); const caret = document.createElement("span"); caret.classList.add("caret"); this.#trigger.appendChild(caret); const caretSymbol = document.createElement("span"); caretSymbol.classList.add("caret-symbol"); caretSymbol.textContent = ">"; caret.appendChild(caretSymbol); const body = document.createElement("div"); body.id = bodyId; body.classList.add("body"); shadow.appendChild(body); const slot = document.createElement("slot"); shadow.appendChild(slot); body.appendChild(slot); } connectedCallback() { this.setAttribute("opened", ""); this.#trigger.addEventListener("click", this.#onToggleClick); } disconnectedCallback() { this.#trigger.removeEventListener("click", this.#onToggleClick); } attributeChangedCallback(name, _oldValue, newValue) { if (name !== "opened") { return; } const isOpened = typeof newValue === "string"; this.#trigger.setAttribute("aria-expanded", isOpened.toString()); } #onToggleClick = (event) => { event.preventDefault(); if (this.hasAttribute("opened")) { this.removeAttribute("opened"); } else { this.setAttribute("opened", ""); } }; }
-