From 2487908afc24f21766356cd85dbf37ec98ff65df Mon Sep 17 00:00:00 2001 From: Christoph Schmatzler Date: Thu, 11 Jul 2024 22:14:11 +0200 Subject: [PATCH] wip Signed-off-by: Christoph Schmatzler --- .github/workflows/main.yml | 80 ++++ .mise.toml | 5 - .prettierignore | 1 + README.md | 6 +- Taskfile.yml | 24 +- biome.json | 29 -- hooks/accordion.ts | 8 +- hooks/collapsible.ts | 14 +- hooks/combobox.ts | 32 +- hooks/dialog.ts | 18 +- hooks/dist/index.d.mts | 305 +++++++------ hooks/dist/index.d.ts | 305 +++++++------ hooks/dist/index.js | 252 +++++------ hooks/dist/index.mjs | 201 ++++----- hooks/pin-input.ts | 28 +- hooks/popover.ts | 10 +- hooks/tooltip.ts | 8 +- hooks/util.ts | 38 +- lib/turboprop/headless/accordion.ex | 12 +- package-lock.json | 645 +++++++++------------------- package.json | 30 +- prettier.config.js | 4 + test/turboprop_test.exs | 2 - 23 files changed, 941 insertions(+), 1116 deletions(-) create mode 100644 .github/workflows/main.yml delete mode 100644 .mise.toml create mode 100644 .prettierignore delete mode 100644 biome.json create mode 100644 prettier.config.js delete mode 100644 test/turboprop_test.exs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..9e30590 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,80 @@ +on: + push: + branches: + - main + pull_request: + +jobs: + elixir: + name: Elixir (OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}}) + strategy: + matrix: + include: + - elixir: 1.13.4 + otp: 24.3 + - elixir: 1.15.4 + otp: 25.3 + - elixir: 1.16.3 + otp: 26.2 + - elixir: 1.17.2 + otp: 27.0 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.elixir }} + otp-version: ${{ matrix.otp }} + + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Restore deps and _build cache + uses: actions/cache@v4 + with: + path: | + deps + _build + key: deps-elixir-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }} + restore-keys: | + deps-elixir-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }} + + - name: Run CI script + run: task elixir-ci + + node: + name: Node + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version-file: .tool-versions + + - name: Install Task + uses: arduino/setup-task@v2 + with: + version: 3.x + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Restore deps and _build cache + uses: actions/cache@v4 + with: + path: | + deps + _build + key: deps-node-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + deps-node-${{ runner.os }}- + + - name: Run CI script + run: task node-ci diff --git a/.mise.toml b/.mise.toml deleted file mode 100644 index 069d4f1..0000000 --- a/.mise.toml +++ /dev/null @@ -1,5 +0,0 @@ -[tasks.pre-commit] -run = [ - "task check-format", - "task lint" -] diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..aec13a3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +/hooks/dist/ diff --git a/README.md b/README.md index 8c5c46e..6da762e 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ A toolkit to build beautiful, accessible components for Phoenix using Tailwind a This project is still at version `0.1` and should not be used in production as here still is a lot of documentation going on. - The Turboprops Hook API will most definitely change, and the amount of hooks currently available is very limited. In addition to that, -they might not be fully documented or lack options. + they might not be fully documented or lack options. - The Turboprop Merge API is considered stable, but it lacks the ability to configure it with custom Tailwind themes and the documentation -is considered work in progress. + is considered work in progress. ## Contributing @@ -57,7 +57,7 @@ This includes: - ARIA attributes You can either install and use them through the hex.pm dependency and some helpers we offer to add the relevant attributes to a component, -or install them directly through npm and adding the attributes yourself. +or install them directly through npm and adding the attributes yourself. As an example, this renders a fully accessible dropdown menu: diff --git a/Taskfile.yml b/Taskfile.yml index c934a3c..538b1a8 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -13,21 +13,27 @@ tasks: - install-dependencies cmds: - mix format - - npx @biomejs/biome format --write . + - npx prettier --write . - check-format: - desc: Check whether the project is formatted + ci: + desc: Run the CI pipeline + deps: + - elixir-ci + - node-ci + + elixir-ci: + desc: Run the CI pipeline (Elixir) deps: - install-dependencies cmds: - mix format --check-formatted - - npx @biomejs/biome format . + - mix test - lint: - desc: Lint the project - deps: - - install-npm-dependencies - cmd: npx @biomejs/biome lint . + node-ci: + desc: Run the CI pipeline (node) + cmds: + - npx prettier --check . + - npx tsc --noEmit -p . build: desc: Build the hooks diff --git a/biome.json b/biome.json deleted file mode 100644 index faff6b3..0000000 --- a/biome.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://biomejs.dev/schemas/1.8.1/schema.json", - "vcs": { - "enabled": true, - "clientKind": "git", - "useIgnoreFile": true - }, - "files": { - "ignore": ["hooks/dist/"] - }, - "organizeImports": { - "enabled": true - }, - "formatter": { - "enabled": true, - "indentStyle": "space", - "indentWidth": 2, - "lineWidth": 140 - }, - "linter": { - "enabled": true, - "rules": { - "recommended": true, - "suspicious": { - "noExplicitAny": "off" - } - } - } -} diff --git a/hooks/accordion.ts b/hooks/accordion.ts index 0816780..f2a85e7 100644 --- a/hooks/accordion.ts +++ b/hooks/accordion.ts @@ -1,5 +1,5 @@ import * as accordion from "@zag-js/accordion"; -import { normalizeProps, spreadProps, renderPart } from "./util"; +import { normalizeProps, spreadProps, renderPart, getBooleanOption } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -76,9 +76,9 @@ export default { return { id: this.el.id, value: [""], - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - collapsible: this.el.dataset.collapsible === "true" || this.el.dataset.collapsible === "", + disabled: getBooleanOption(this.el, "disabled"), + multiple: getBooleanOption(this.el, "multiple"), + collapsible: getBooleanOption(this.el, "collapsible"), onValueChange: (details: accordion.ValueChangeDetails) => { if (this.el.dataset.onValueChange) { this.pushEvent(this.el.dataset.onValueChange, details); diff --git a/hooks/collapsible.ts b/hooks/collapsible.ts index 7c0b7ad..2dc87c3 100644 --- a/hooks/collapsible.ts +++ b/hooks/collapsible.ts @@ -1,5 +1,5 @@ import * as collapsible from "@zag-js/collapsible"; -import { normalizeProps, renderPart } from "./util"; +import { getOption, getBooleanOption, normalizeProps, renderPart } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -41,18 +41,10 @@ export default { }, context(): collapsible.Context { - let dir: string | undefined = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"] as const; - - if (dir !== undefined && !validDirs.includes(dir as any)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = undefined; - } - return { id: this.el.id, - dir: dir as Dir, - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", + dir: getOption(this.el, "dir", ["ltr", "rtl"]) as Dir, + disabled: getBooleanOption(this.el, "disabled"), onOpenChange: (details: collapsible.OpenChangeDetails) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); diff --git a/hooks/combobox.ts b/hooks/combobox.ts index bb477d6..2aa8714 100644 --- a/hooks/combobox.ts +++ b/hooks/combobox.ts @@ -1,6 +1,6 @@ import * as combobox from "@zag-js/combobox"; import type { Collection } from "@zag-js/collection"; -import { getAttributes, restoreAttributes, normalizeProps, renderPart, spreadProps } from "./util"; +import { getAttributes, restoreAttributes, normalizeProps, renderPart, spreadProps, getBooleanOption, getOption } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -94,33 +94,17 @@ export default { }, context(): combobox.Context { - let inputBehavior: string | undefined = this.el.dataset.inputBehavior; - const validInputBehaviors = ["autohighlight", "autocomplete", "none"] as const; - - if (inputBehavior !== undefined && !validInputBehaviors.includes(inputBehavior as any)) { - console.error(`Invalid 'inputBehavior' specified: '${inputBehavior}'. Expected 'autohighlight', 'autocomplete' or 'none'.`); - inputBehavior = undefined; - } - - let selectionBehavior: string | undefined = this.el.dataset.selectionBehavior; - const validSelectionBehaviors = ["clear", "replace", "preserve"] as const; - - if (selectionBehavior !== undefined && !validSelectionBehaviors.includes(selectionBehavior as any)) { - console.error(`Invalid 'selectionBehavior' specified: '${selectionBehavior}'. Expected 'clear', 'replace' or 'preserve'.`); - selectionBehavior = undefined; - } - return { id: this.el.id, name: this.el.dataset.name, collection: this.collection(), - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - readOnly: this.el.dataset.readOnly === "true" || this.el.dataset.readOnly === "", - loopFocus: this.el.dataset.loopFocus === "true" || this.el.dataset.loopFocus === "", - allowCustomValue: this.el.dataset.allowCustomValue === "true" || this.el.dataset.allowCustomValue === "", - inputBehavior: inputBehavior as InputBehavior, - selectionBehavior: selectionBehavior as SelectionBehavior, + inputBehavior: getOption(this.el, "inputBehavior", ["autohighlight", "autocomplete", "none"]) as InputBehavior, + selectionBehavior: getOption(this.el, "selectionBehavior", ["clear", "replace", "preserve"]) as SelectionBehavior, + multiple: getBooleanOption(this.el, "multiple"), + disabled: getBooleanOption(this.el, "disabled"), + readOnly: getBooleanOption(this.el, "readOnly"), + loopFocus: getBooleanOption(this.el, "loopFocus"), + allowCustomValue: getBooleanOption(this.el, "allowCustomValue"), onOpenChange: (details: combobox.OpenChangeDetails) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); diff --git a/hooks/dialog.ts b/hooks/dialog.ts index 6a3dc34..fed9212 100644 --- a/hooks/dialog.ts +++ b/hooks/dialog.ts @@ -1,5 +1,5 @@ import * as dialog from "@zag-js/dialog"; -import { normalizeProps, renderPart } from "./util"; +import { getOption, getBooleanOption, normalizeProps, renderPart } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -41,20 +41,12 @@ export default { }, context(): dialog.Context { - let role: string | undefined = this.el.dataset.role; - const validRoles = ["dialog", "alertdialog"] as const; - - if (role !== undefined && !validRoles.includes(role as any)) { - console.error(`Invalid 'role' specified: '${role}'. Expected 'dialog' or 'alertdialog'.`); - role = undefined; - } - return { id: this.el.id, - role: role as Role, - preventScroll: this.el.dataset.preventScroll === "true" || this.el.dataset.preventScroll === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + role: getOption(this.el, "role", ["dialog", "alertdialog"]) as Role, + preventScroll: getBooleanOption(this.el, "preventScroll"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details: dialog.OpenChangeDetails) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); diff --git a/hooks/dist/index.d.mts b/hooks/dist/index.d.mts index 73512b8..ee04d9a 100644 --- a/hooks/dist/index.d.mts +++ b/hooks/dist/index.d.mts @@ -1,205 +1,242 @@ -import * as _zag_js_types from '@zag-js/types'; -import * as tooltip from '@zag-js/tooltip'; -import { Machine } from '@zag-js/core'; -import { ViewHook } from 'phoenix_live_view'; -import * as popover from '@zag-js/popover'; -import * as pinInput from '@zag-js/pin-input'; -import * as menu from '@zag-js/menu'; -import * as dialog from '@zag-js/dialog'; -import * as combobox from '@zag-js/combobox'; -import { Collection } from '@zag-js/collection'; -import * as collapsible from '@zag-js/collapsible'; -import * as clipboard from '@zag-js/clipboard'; -import * as accordion from '@zag-js/accordion'; +import * as _zag_js_types from "@zag-js/types"; +import * as tooltip from "@zag-js/tooltip"; +import { Machine } from "@zag-js/core"; +import { ViewHook } from "phoenix_live_view"; +import * as popover from "@zag-js/popover"; +import * as pinInput from "@zag-js/pin-input"; +import * as menu from "@zag-js/menu"; +import * as dialog from "@zag-js/dialog"; +import * as combobox from "@zag-js/combobox"; +import { Collection } from "@zag-js/collection"; +import * as collapsible from "@zag-js/collapsible"; +import * as clipboard from "@zag-js/clipboard"; +import * as accordion from "@zag-js/accordion"; interface ComponentInterface { - el: HTMLElement; - service: ReturnType; - api: Api; - init(): void; - destroy(): void; - render(): void; + el: HTMLElement; + service: ReturnType; + api: Api; + init(): void; + destroy(): void; + render(): void; } declare abstract class Component implements ComponentInterface { - el: HTMLElement; - service: ReturnType; - api: Api; - abstract initService(context: Context): Machine; - abstract initApi(): Api; - abstract render(): void; - constructor(el: HTMLElement, context: Context); - init: () => void; - destroy: () => void; + el: HTMLElement; + service: ReturnType; + api: Api; + abstract initService(context: Context): Machine; + abstract initApi(): Api; + abstract render(): void; + constructor(el: HTMLElement, context: Context); + init: () => void; + destroy: () => void; } declare class Tooltip extends Component { - initService(context: tooltip.Context): Machine; - initApi(): tooltip.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - onOpenChange(details: tooltip.OpenChangeDetails): void; + initService(context: tooltip.Context): Machine; + initApi(): tooltip.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + onOpenChange(details: tooltip.OpenChangeDetails): void; } interface TooltipHook extends ViewHook { - tooltip: Tooltip; - context(): tooltip.Context; + tooltip: Tooltip; + context(): tooltip.Context; } declare const _default$9: TooltipHook; declare class Portal { - el: HTMLElement; - parent: HTMLElement | null; - target: string | null; - screen: number; - mediaQuery: MediaQueryList | null; - constructor(el: HTMLElement, target: string, { screen }: { - screen?: number; - }); - update(): void; - onResize(e: MediaQueryList | MediaQueryListEvent): void; - destroy(): void; + el: HTMLElement; + parent: HTMLElement | null; + target: string | null; + screen: number; + mediaQuery: MediaQueryList | null; + constructor( + el: HTMLElement, + target: string, + { + screen, + }: { + screen?: number; + }, + ); + update(): void; + onResize(e: MediaQueryList | MediaQueryListEvent): void; + destroy(): void; } interface PortalHook extends ViewHook { - portal: Portal; + portal: Portal; } declare const _default$8: PortalHook; declare class Popover extends Component { - initService(context: popover.Context): Machine; - initApi(): popover.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: popover.Context): Machine; + initApi(): popover.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface PopoverHook extends ViewHook { - popover: Popover; - context(): popover.Context; + popover: Popover; + context(): popover.Context; } declare const _default$7: PopoverHook; declare class PinInput extends Component { - initService(context: pinInput.Context): Machine; - initApi(): pinInput.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - clearValue(): void; - render(): void; - renderInputs(): void; + initService(context: pinInput.Context): Machine; + initApi(): pinInput.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + clearValue(): void; + render(): void; + renderInputs(): void; } interface PinInputHook extends ViewHook { - pinInput: PinInput; - context(): pinInput.Context; + pinInput: PinInput; + context(): pinInput.Context; } declare const _default$6: PinInputHook; declare class Menu extends Component { - initService(context: menu.Context): Machine; - initApi(): menu.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - renderItemGroupLabels(): void; - renderItemGroups(): void; - renderItems(): void; - renderSeparators(): void; + initService(context: menu.Context): Machine; + initApi(): menu.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + renderItemGroupLabels(): void; + renderItemGroups(): void; + renderItems(): void; + renderSeparators(): void; } interface MenuHook extends ViewHook { - menu: Menu; - context: { - id: string; - }; + menu: Menu; + context: { + id: string; + }; } declare const _default$5: MenuHook; declare class Dialog extends Component { - initService(context: dialog.Context): Machine; - initApi(): dialog.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: dialog.Context): Machine; + initApi(): dialog.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface DialogHook extends ViewHook { - dialog: Dialog; - context(): dialog.Context; + dialog: Dialog; + context(): dialog.Context; } declare const _default$4: DialogHook; type Item = { - value: string; - label: string; + value: string; + label: string; }; declare class Combobox extends Component { - initService(context: combobox.Context): Machine; - initApi(): combobox.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>, unknown>; - render(): void; - renderItems(): void; + initService(context: combobox.Context): Machine; + initApi(): combobox.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }>, + unknown + >; + render(): void; + renderItems(): void; } interface ComboboxHook extends ViewHook { - state: any; - combobox: Combobox; - attributeCache: any; - items(): Item[]; - collection(): Collection; - context(): combobox.Context; + state: any; + combobox: Combobox; + attributeCache: any; + items(): Item[]; + collection(): Collection; + context(): combobox.Context; } declare const _default$3: ComboboxHook; declare class Collapsible extends Component { - initService(context: collapsible.Context): Machine; - initApi(): collapsible.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: collapsible.Context): Machine; + initApi(): collapsible.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface CollapsibleHook extends ViewHook { - collapsible: Collapsible; - context(): collapsible.Context; + collapsible: Collapsible; + context(): collapsible.Context; } declare const _default$2: CollapsibleHook; declare class Clipboard extends Component { - initService(context: clipboard.Context): Machine; - initApi(): clipboard.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: clipboard.Context): Machine; + initApi(): clipboard.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface ClipboardHook extends ViewHook { - clipboard: Clipboard; - context(): clipboard.Context; + clipboard: Clipboard; + context(): clipboard.Context; } declare const _default$1: ClipboardHook; declare class Accordion extends Component { - initService(context: accordion.Context): Machine; - initApi(): accordion.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - renderItems(): void; - renderItemTrigger(item: HTMLElement, value: string): void; - renderItemIndicator(item: HTMLElement, value: string): void; - renderItemContent(item: HTMLElement, value: string): void; + initService(context: accordion.Context): Machine; + initApi(): accordion.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + renderItems(): void; + renderItemTrigger(item: HTMLElement, value: string): void; + renderItemIndicator(item: HTMLElement, value: string): void; + renderItemContent(item: HTMLElement, value: string): void; } interface AccordionHook extends ViewHook { - accordion: Accordion; - context(): accordion.Context; + accordion: Accordion; + context(): accordion.Context; } declare const _default: AccordionHook; declare const Hooks: { - Accordion: AccordionHook; - Clipboard: ClipboardHook; - Collapsible: CollapsibleHook; - Combobox: ComboboxHook; - Dialog: DialogHook; - Menu: MenuHook; - PinInput: PinInputHook; - Popover: PopoverHook; - Portal: PortalHook; - Tooltip: TooltipHook; + Accordion: AccordionHook; + Clipboard: ClipboardHook; + Collapsible: CollapsibleHook; + Combobox: ComboboxHook; + Dialog: DialogHook; + Menu: MenuHook; + PinInput: PinInputHook; + Popover: PopoverHook; + Portal: PortalHook; + Tooltip: TooltipHook; }; -export { _default as Accordion, _default$1 as Clipboard, _default$2 as Collapsible, _default$3 as Combobox, _default$4 as Dialog, Hooks, _default$5 as Menu, _default$6 as PinInput, _default$7 as Popover, _default$8 as Portal, _default$9 as Tooltip }; +export { + _default as Accordion, + _default$1 as Clipboard, + _default$2 as Collapsible, + _default$3 as Combobox, + _default$4 as Dialog, + Hooks, + _default$5 as Menu, + _default$6 as PinInput, + _default$7 as Popover, + _default$8 as Portal, + _default$9 as Tooltip, +}; diff --git a/hooks/dist/index.d.ts b/hooks/dist/index.d.ts index 73512b8..ee04d9a 100644 --- a/hooks/dist/index.d.ts +++ b/hooks/dist/index.d.ts @@ -1,205 +1,242 @@ -import * as _zag_js_types from '@zag-js/types'; -import * as tooltip from '@zag-js/tooltip'; -import { Machine } from '@zag-js/core'; -import { ViewHook } from 'phoenix_live_view'; -import * as popover from '@zag-js/popover'; -import * as pinInput from '@zag-js/pin-input'; -import * as menu from '@zag-js/menu'; -import * as dialog from '@zag-js/dialog'; -import * as combobox from '@zag-js/combobox'; -import { Collection } from '@zag-js/collection'; -import * as collapsible from '@zag-js/collapsible'; -import * as clipboard from '@zag-js/clipboard'; -import * as accordion from '@zag-js/accordion'; +import * as _zag_js_types from "@zag-js/types"; +import * as tooltip from "@zag-js/tooltip"; +import { Machine } from "@zag-js/core"; +import { ViewHook } from "phoenix_live_view"; +import * as popover from "@zag-js/popover"; +import * as pinInput from "@zag-js/pin-input"; +import * as menu from "@zag-js/menu"; +import * as dialog from "@zag-js/dialog"; +import * as combobox from "@zag-js/combobox"; +import { Collection } from "@zag-js/collection"; +import * as collapsible from "@zag-js/collapsible"; +import * as clipboard from "@zag-js/clipboard"; +import * as accordion from "@zag-js/accordion"; interface ComponentInterface { - el: HTMLElement; - service: ReturnType; - api: Api; - init(): void; - destroy(): void; - render(): void; + el: HTMLElement; + service: ReturnType; + api: Api; + init(): void; + destroy(): void; + render(): void; } declare abstract class Component implements ComponentInterface { - el: HTMLElement; - service: ReturnType; - api: Api; - abstract initService(context: Context): Machine; - abstract initApi(): Api; - abstract render(): void; - constructor(el: HTMLElement, context: Context); - init: () => void; - destroy: () => void; + el: HTMLElement; + service: ReturnType; + api: Api; + abstract initService(context: Context): Machine; + abstract initApi(): Api; + abstract render(): void; + constructor(el: HTMLElement, context: Context); + init: () => void; + destroy: () => void; } declare class Tooltip extends Component { - initService(context: tooltip.Context): Machine; - initApi(): tooltip.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - onOpenChange(details: tooltip.OpenChangeDetails): void; + initService(context: tooltip.Context): Machine; + initApi(): tooltip.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + onOpenChange(details: tooltip.OpenChangeDetails): void; } interface TooltipHook extends ViewHook { - tooltip: Tooltip; - context(): tooltip.Context; + tooltip: Tooltip; + context(): tooltip.Context; } declare const _default$9: TooltipHook; declare class Portal { - el: HTMLElement; - parent: HTMLElement | null; - target: string | null; - screen: number; - mediaQuery: MediaQueryList | null; - constructor(el: HTMLElement, target: string, { screen }: { - screen?: number; - }); - update(): void; - onResize(e: MediaQueryList | MediaQueryListEvent): void; - destroy(): void; + el: HTMLElement; + parent: HTMLElement | null; + target: string | null; + screen: number; + mediaQuery: MediaQueryList | null; + constructor( + el: HTMLElement, + target: string, + { + screen, + }: { + screen?: number; + }, + ); + update(): void; + onResize(e: MediaQueryList | MediaQueryListEvent): void; + destroy(): void; } interface PortalHook extends ViewHook { - portal: Portal; + portal: Portal; } declare const _default$8: PortalHook; declare class Popover extends Component { - initService(context: popover.Context): Machine; - initApi(): popover.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: popover.Context): Machine; + initApi(): popover.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface PopoverHook extends ViewHook { - popover: Popover; - context(): popover.Context; + popover: Popover; + context(): popover.Context; } declare const _default$7: PopoverHook; declare class PinInput extends Component { - initService(context: pinInput.Context): Machine; - initApi(): pinInput.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - clearValue(): void; - render(): void; - renderInputs(): void; + initService(context: pinInput.Context): Machine; + initApi(): pinInput.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + clearValue(): void; + render(): void; + renderInputs(): void; } interface PinInputHook extends ViewHook { - pinInput: PinInput; - context(): pinInput.Context; + pinInput: PinInput; + context(): pinInput.Context; } declare const _default$6: PinInputHook; declare class Menu extends Component { - initService(context: menu.Context): Machine; - initApi(): menu.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - renderItemGroupLabels(): void; - renderItemGroups(): void; - renderItems(): void; - renderSeparators(): void; + initService(context: menu.Context): Machine; + initApi(): menu.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + renderItemGroupLabels(): void; + renderItemGroups(): void; + renderItems(): void; + renderSeparators(): void; } interface MenuHook extends ViewHook { - menu: Menu; - context: { - id: string; - }; + menu: Menu; + context: { + id: string; + }; } declare const _default$5: MenuHook; declare class Dialog extends Component { - initService(context: dialog.Context): Machine; - initApi(): dialog.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: dialog.Context): Machine; + initApi(): dialog.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface DialogHook extends ViewHook { - dialog: Dialog; - context(): dialog.Context; + dialog: Dialog; + context(): dialog.Context; } declare const _default$4: DialogHook; type Item = { - value: string; - label: string; + value: string; + label: string; }; declare class Combobox extends Component { - initService(context: combobox.Context): Machine; - initApi(): combobox.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>, unknown>; - render(): void; - renderItems(): void; + initService(context: combobox.Context): Machine; + initApi(): combobox.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }>, + unknown + >; + render(): void; + renderItems(): void; } interface ComboboxHook extends ViewHook { - state: any; - combobox: Combobox; - attributeCache: any; - items(): Item[]; - collection(): Collection; - context(): combobox.Context; + state: any; + combobox: Combobox; + attributeCache: any; + items(): Item[]; + collection(): Collection; + context(): combobox.Context; } declare const _default$3: ComboboxHook; declare class Collapsible extends Component { - initService(context: collapsible.Context): Machine; - initApi(): collapsible.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: collapsible.Context): Machine; + initApi(): collapsible.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface CollapsibleHook extends ViewHook { - collapsible: Collapsible; - context(): collapsible.Context; + collapsible: Collapsible; + context(): collapsible.Context; } declare const _default$2: CollapsibleHook; declare class Clipboard extends Component { - initService(context: clipboard.Context): Machine; - initApi(): clipboard.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; + initService(context: clipboard.Context): Machine; + initApi(): clipboard.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; } interface ClipboardHook extends ViewHook { - clipboard: Clipboard; - context(): clipboard.Context; + clipboard: Clipboard; + context(): clipboard.Context; } declare const _default$1: ClipboardHook; declare class Accordion extends Component { - initService(context: accordion.Context): Machine; - initApi(): accordion.Api<_zag_js_types.PropTypes<{ - [x: string]: any; - }>>; - render(): void; - renderItems(): void; - renderItemTrigger(item: HTMLElement, value: string): void; - renderItemIndicator(item: HTMLElement, value: string): void; - renderItemContent(item: HTMLElement, value: string): void; + initService(context: accordion.Context): Machine; + initApi(): accordion.Api< + _zag_js_types.PropTypes<{ + [x: string]: any; + }> + >; + render(): void; + renderItems(): void; + renderItemTrigger(item: HTMLElement, value: string): void; + renderItemIndicator(item: HTMLElement, value: string): void; + renderItemContent(item: HTMLElement, value: string): void; } interface AccordionHook extends ViewHook { - accordion: Accordion; - context(): accordion.Context; + accordion: Accordion; + context(): accordion.Context; } declare const _default: AccordionHook; declare const Hooks: { - Accordion: AccordionHook; - Clipboard: ClipboardHook; - Collapsible: CollapsibleHook; - Combobox: ComboboxHook; - Dialog: DialogHook; - Menu: MenuHook; - PinInput: PinInputHook; - Popover: PopoverHook; - Portal: PortalHook; - Tooltip: TooltipHook; + Accordion: AccordionHook; + Clipboard: ClipboardHook; + Collapsible: CollapsibleHook; + Combobox: ComboboxHook; + Dialog: DialogHook; + Menu: MenuHook; + PinInput: PinInputHook; + Popover: PopoverHook; + Portal: PortalHook; + Tooltip: TooltipHook; }; -export { _default as Accordion, _default$1 as Clipboard, _default$2 as Collapsible, _default$3 as Combobox, _default$4 as Dialog, Hooks, _default$5 as Menu, _default$6 as PinInput, _default$7 as Popover, _default$8 as Portal, _default$9 as Tooltip }; +export { + _default as Accordion, + _default$1 as Clipboard, + _default$2 as Collapsible, + _default$3 as Combobox, + _default$4 as Dialog, + Hooks, + _default$5 as Menu, + _default$6 as PinInput, + _default$7 as Popover, + _default$8 as Portal, + _default$9 as Tooltip, +}; diff --git a/hooks/dist/index.js b/hooks/dist/index.js index c6af541..fb48bd9 100644 --- a/hooks/dist/index.js +++ b/hooks/dist/index.js @@ -5,27 +5,30 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __defNormalProp = (obj, key, value) => + key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : (obj[key] = value); var __export = (target, all) => { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); + for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { + if ((from && typeof from === "object") || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); +var __toESM = (mod, isNodeMode, target) => ( + (target = mod != null ? __create(__getProtoOf(mod)) : {}), + __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod, + ) +); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); @@ -42,7 +45,7 @@ __export(hooks_exports, { PinInput: () => pin_input_default, Popover: () => popover_default, Portal: () => portal_default, - Tooltip: () => tooltip_default + Tooltip: () => tooltip_default, }); module.exports = __toCommonJS(hooks_exports); @@ -59,7 +62,7 @@ var propMap = { htmlFor: "for", className: "class", defaultValue: "value", - defaultChecked: "checked" + defaultChecked: "checked", }; var prevAttrsMap = /* @__PURE__ */ new WeakMap(); var toStyleString = (style) => { @@ -131,6 +134,19 @@ var renderPart = (root, name, api) => { const getterName = `get${camelizedName}Props`; if (part) spreadProps(part, api[getterName]()); }; +var getOption = (el, name, validOptions) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + let initial = el.dataset[kebabName]; + if (initial !== void 0 && !validOptions.includes(initial)) { + console.error(`Invalid '${name}' specified: '${initial}'. Expected one of '${validOptions.join("', '")}'.`); + initial = void 0; + } + return initial; +}; +var getBooleanOption = (el, name) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + return el.dataset[kebabName] === "true" || el.dataset[kebabName] === ""; +}; var getAttributes = (root, name) => { const part = root.querySelector(`[data-part='${name}']`); if (!part) return; @@ -142,9 +158,9 @@ var getAttributes = (root, name) => { } return { part: name, - style: part.style.cssText, + cssText: part.style.cssText, hasFocus: part === document.activeElement, - attrs + attrs, }; }; var restoreAttributes = (root, attributeMaps) => { @@ -154,7 +170,7 @@ var restoreAttributes = (root, attributeMaps) => { for (const attr of attributeMap.attrs) { part.setAttribute(attr.name, attr.value); } - part.style.cssText = attributeMap.style; + part.style.cssText = attributeMap.cssText; if (attributeMap.hasFocus) part.focus(); } }; @@ -239,16 +255,16 @@ var accordion_default = { return { id: this.el.id, value: [""], - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - collapsible: this.el.dataset.collapsible === "true" || this.el.dataset.collapsible === "", + disabled: getBooleanOption(this.el, "disabled"), + multiple: getBooleanOption(this.el, "multiple"), + collapsible: getBooleanOption(this.el, "collapsible"), onValueChange: (details) => { if (this.el.dataset.onValueChange) { this.pushEvent(this.el.dataset.onValueChange, details); } - } + }, }; - } + }, }; // hooks/clipboard.ts @@ -284,9 +300,9 @@ var clipboard_default = { if (this.el.dataset.onStatusChange) { this.pushEvent(this.el.dataset.onStatusChange, details); } - } + }, }; - } + }, }; // hooks/collapsible.ts @@ -315,23 +331,17 @@ var collapsible_default = { this.collapsible.destroy(); }, context() { - let dir = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"]; - if (dir !== void 0 && !validDirs.includes(dir)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = void 0; - } return { id: this.el.id, - dir, - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", + dir: getOption(this.el, "dir", ["ltr", "rtl"]), + disabled: getBooleanOption(this.el, "disabled"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/combobox.ts @@ -380,47 +390,37 @@ var combobox_default = { this.combobox.destroy(); }, items() { - return Array.from(this.el.querySelectorAll("[data-part='item']")).map((item) => { - const value = item.dataset.value; - const label = item.dataset.label; - if (!value || !label) { - console.error("Missing `data-value` or `data-label` attribute on item."); - return; - } - return { value, label }; - }).filter((value) => value !== void 0); + return Array.from(this.el.querySelectorAll("[data-part='item']")) + .map((item) => { + const value = item.dataset.value; + const label = item.dataset.label; + if (!value || !label) { + console.error("Missing `data-value` or `data-label` attribute on item."); + return; + } + return { value, label }; + }) + .filter((value) => value !== void 0); }, collection() { return combobox.collection({ items: this.items(), itemToValue: (item) => item.value, - itemToString: (item) => item.label + itemToString: (item) => item.label, }); }, context() { - let inputBehavior = this.el.dataset.inputBehavior; - const validInputBehaviors = ["autohighlight", "autocomplete", "none"]; - if (inputBehavior !== void 0 && !validInputBehaviors.includes(inputBehavior)) { - console.error(`Invalid 'inputBehavior' specified: '${inputBehavior}'. Expected 'autohighlight', 'autocomplete' or 'none'.`); - inputBehavior = void 0; - } - let selectionBehavior = this.el.dataset.selectionBehavior; - const validSelectionBehaviors = ["clear", "replace", "preserve"]; - if (selectionBehavior !== void 0 && !validSelectionBehaviors.includes(selectionBehavior)) { - console.error(`Invalid 'selectionBehavior' specified: '${selectionBehavior}'. Expected 'clear', 'replace' or 'preserve'.`); - selectionBehavior = void 0; - } return { id: this.el.id, name: this.el.dataset.name, collection: this.collection(), - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - readOnly: this.el.dataset.readOnly === "true" || this.el.dataset.readOnly === "", - loopFocus: this.el.dataset.loopFocus === "true" || this.el.dataset.loopFocus === "", - allowCustomValue: this.el.dataset.allowCustomValue === "true" || this.el.dataset.allowCustomValue === "", - inputBehavior, - selectionBehavior, + inputBehavior: getOption(this.el, "inputBehavior", ["autohighlight", "autocomplete", "none"]), + selectionBehavior: getOption(this.el, "selectionBehavior", ["clear", "replace", "preserve"]), + multiple: getBooleanOption(this.el, "multiple"), + disabled: getBooleanOption(this.el, "disabled"), + readOnly: getBooleanOption(this.el, "readOnly"), + loopFocus: getBooleanOption(this.el, "loopFocus"), + allowCustomValue: getBooleanOption(this.el, "allowCustomValue"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); @@ -440,9 +440,9 @@ var combobox_default = { if (this.el.dataset.onValueChange) { this.pushEvent(this.el.dataset.onValueChange, details); } - } + }, }; - } + }, }; // hooks/dialog.ts @@ -471,25 +471,19 @@ var dialog_default = { this.dialog.destroy(); }, context() { - let role = this.el.dataset.role; - const validRoles = ["dialog", "alertdialog"]; - if (role !== void 0 && !validRoles.includes(role)) { - console.error(`Invalid 'role' specified: '${role}'. Expected 'dialog' or 'alertdialog'.`); - role = void 0; - } return { id: this.el.id, - role, - preventScroll: this.el.dataset.preventScroll === "true" || this.el.dataset.preventScroll === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + role: getOption(this.el, "role", ["dialog", "alertdialog"]), + preventScroll: getBooleanOption(this.el, "preventScroll"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/menu.ts @@ -540,8 +534,7 @@ var Menu = class extends Component { } } renderSeparators() { - for (const separator of this.el.querySelectorAll("[data-part='separator']")) - spreadProps(separator, this.api.getSeparatorProps()); + for (const separator of this.el.querySelectorAll("[data-part='separator']")) spreadProps(separator, this.api.getSeparatorProps()); } }; var menu_default = { @@ -555,7 +548,7 @@ var menu_default = { }, beforeDestroy() { this.menu.destroy(); - } + }, }; // hooks/pin-input.ts @@ -599,26 +592,14 @@ var pin_input_default = { this.pinInput.destroy(); }, context() { - let type = this.el.dataset.type; - const validTypes = ["alphanumeric", "numeric", "alphabetic"]; - if (type !== void 0 && !validTypes.includes(type)) { - console.error(`Invalid 'type' specified: '${type}'. Expected 'alphanumeric', 'numeric' or 'alphabetic'.`); - type = void 0; - } - let dir = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"]; - if (dir !== void 0 && !validDirs.includes(dir)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = void 0; - } return { id: this.el.id, - type, - otp: this.el.dataset.otp === "true" || this.el.dataset.otp === "", - mask: this.el.dataset.mask === "true" || this.el.dataset.mask === "", - blurOnComplete: this.el.dataset.blurOnComplete === "true" || this.el.dataset.blurOnComplete === "", placeholder: this.el.dataset.placeholder, - dir, + type: getOption(this.el, "type", ["alphanumeric", "numeric", "alphabetic"]), + dir: getOption(this.el, "dir", ["ltr", "rtl"]), + otp: getBooleanOption(this.el, "otp"), + mask: getBooleanOption(this.el, "mask"), + blurOnComplete: getBooleanOption(this.el, "blurOnComplete"), onValueChange: (details) => { if (this.el.dataset.onChange) { this.pushEvent(this.el.dataset.onChange, details); @@ -633,9 +614,9 @@ var pin_input_default = { if (this.el.dataset.onInvalid) { this.pushEvent(this.el.dataset.onInvalid, details); } - } + }, }; - } + }, }; // hooks/popover.ts @@ -666,17 +647,17 @@ var popover_default = { context() { return { id: this.el.id, - autoFocus: this.el.dataset.autoFocus === "true" || this.el.dataset.autoFocus === "", - modal: this.el.dataset.modal === "true" || this.el.dataset.modal === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + autoFocus: getBooleanOption(this.el, "autoFocus"), + modal: getBooleanOption(this.el, "modal"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/portal.ts @@ -718,24 +699,18 @@ var Portal = class { }; var portal_default = { mounted() { - const parentWithHook = this.el.parentElement?.closest("[phx-hook]"); - console.log(parentWithHook); - window.requestAnimationFrame(() => { - if (!this.el.dataset.target) return; - this.portal = new Portal(this.el, this.el.dataset.target, { screen: 400 }); - this.portal.update(); - if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); - }); + if (!this.el.dataset.target) return; + this.portal = new Portal(this.el, this.el.dataset.target, { screen: 400 }); + this.portal.update(); + if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); }, updated() { - window.requestAnimationFrame(() => { - this.portal.update(); - if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); - }); + this.portal.update(); + if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); }, beforeDestroy() { this.portal.destroy(); - } + }, }; // hooks/tooltip.ts @@ -782,20 +757,20 @@ var tooltip_default = { id: this.el.id, openDelay, closeDelay, - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", - closeOnScroll: this.el.dataset.closeOnScroll === "true" || this.el.dataset.closeOnScroll === "", - closeOnPointerDown: this.el.dataset.closeOnPointerDown === "true" || this.el.dataset.closeOnPointerDown === "", positioning: { - placement: this.el.dataset.positioningPlacement + placement: this.el.dataset.positioningPlacement, }, + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), + closeOnScroll: getBooleanOption(this.el, "closeOnScroll"), + closeOnPointerDown: getBooleanOption(this.el, "closeOnPointerDown"), onOpenChange: (details) => { this.tooltip.onOpenChange(details); if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/index.ts @@ -809,19 +784,20 @@ var Hooks = { PinInput: pin_input_default, Popover: popover_default, Portal: portal_default, - Tooltip: tooltip_default + Tooltip: tooltip_default, }; // Annotate the CommonJS export names for ESM import in node: -0 && (module.exports = { - Accordion, - Clipboard, - Collapsible, - Combobox, - Dialog, - Hooks, - Menu, - PinInput, - Popover, - Portal, - Tooltip -}); +0 && + (module.exports = { + Accordion, + Clipboard, + Collapsible, + Combobox, + Dialog, + Hooks, + Menu, + PinInput, + Popover, + Portal, + Tooltip, + }); diff --git a/hooks/dist/index.mjs b/hooks/dist/index.mjs index e350571..b58be63 100644 --- a/hooks/dist/index.mjs +++ b/hooks/dist/index.mjs @@ -1,5 +1,6 @@ var __defProp = Object.defineProperty; -var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __defNormalProp = (obj, key, value) => + key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : (obj[key] = value); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // hooks/accordion.ts @@ -15,7 +16,7 @@ var propMap = { htmlFor: "for", className: "class", defaultValue: "value", - defaultChecked: "checked" + defaultChecked: "checked", }; var prevAttrsMap = /* @__PURE__ */ new WeakMap(); var toStyleString = (style) => { @@ -87,6 +88,19 @@ var renderPart = (root, name, api) => { const getterName = `get${camelizedName}Props`; if (part) spreadProps(part, api[getterName]()); }; +var getOption = (el, name, validOptions) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + let initial = el.dataset[kebabName]; + if (initial !== void 0 && !validOptions.includes(initial)) { + console.error(`Invalid '${name}' specified: '${initial}'. Expected one of '${validOptions.join("', '")}'.`); + initial = void 0; + } + return initial; +}; +var getBooleanOption = (el, name) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + return el.dataset[kebabName] === "true" || el.dataset[kebabName] === ""; +}; var getAttributes = (root, name) => { const part = root.querySelector(`[data-part='${name}']`); if (!part) return; @@ -98,9 +112,9 @@ var getAttributes = (root, name) => { } return { part: name, - style: part.style.cssText, + cssText: part.style.cssText, hasFocus: part === document.activeElement, - attrs + attrs, }; }; var restoreAttributes = (root, attributeMaps) => { @@ -110,7 +124,7 @@ var restoreAttributes = (root, attributeMaps) => { for (const attr of attributeMap.attrs) { part.setAttribute(attr.name, attr.value); } - part.style.cssText = attributeMap.style; + part.style.cssText = attributeMap.cssText; if (attributeMap.hasFocus) part.focus(); } }; @@ -195,16 +209,16 @@ var accordion_default = { return { id: this.el.id, value: [""], - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - collapsible: this.el.dataset.collapsible === "true" || this.el.dataset.collapsible === "", + disabled: getBooleanOption(this.el, "disabled"), + multiple: getBooleanOption(this.el, "multiple"), + collapsible: getBooleanOption(this.el, "collapsible"), onValueChange: (details) => { if (this.el.dataset.onValueChange) { this.pushEvent(this.el.dataset.onValueChange, details); } - } + }, }; - } + }, }; // hooks/clipboard.ts @@ -240,9 +254,9 @@ var clipboard_default = { if (this.el.dataset.onStatusChange) { this.pushEvent(this.el.dataset.onStatusChange, details); } - } + }, }; - } + }, }; // hooks/collapsible.ts @@ -271,23 +285,17 @@ var collapsible_default = { this.collapsible.destroy(); }, context() { - let dir = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"]; - if (dir !== void 0 && !validDirs.includes(dir)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = void 0; - } return { id: this.el.id, - dir, - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", + dir: getOption(this.el, "dir", ["ltr", "rtl"]), + disabled: getBooleanOption(this.el, "disabled"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/combobox.ts @@ -336,47 +344,37 @@ var combobox_default = { this.combobox.destroy(); }, items() { - return Array.from(this.el.querySelectorAll("[data-part='item']")).map((item) => { - const value = item.dataset.value; - const label = item.dataset.label; - if (!value || !label) { - console.error("Missing `data-value` or `data-label` attribute on item."); - return; - } - return { value, label }; - }).filter((value) => value !== void 0); + return Array.from(this.el.querySelectorAll("[data-part='item']")) + .map((item) => { + const value = item.dataset.value; + const label = item.dataset.label; + if (!value || !label) { + console.error("Missing `data-value` or `data-label` attribute on item."); + return; + } + return { value, label }; + }) + .filter((value) => value !== void 0); }, collection() { return combobox.collection({ items: this.items(), itemToValue: (item) => item.value, - itemToString: (item) => item.label + itemToString: (item) => item.label, }); }, context() { - let inputBehavior = this.el.dataset.inputBehavior; - const validInputBehaviors = ["autohighlight", "autocomplete", "none"]; - if (inputBehavior !== void 0 && !validInputBehaviors.includes(inputBehavior)) { - console.error(`Invalid 'inputBehavior' specified: '${inputBehavior}'. Expected 'autohighlight', 'autocomplete' or 'none'.`); - inputBehavior = void 0; - } - let selectionBehavior = this.el.dataset.selectionBehavior; - const validSelectionBehaviors = ["clear", "replace", "preserve"]; - if (selectionBehavior !== void 0 && !validSelectionBehaviors.includes(selectionBehavior)) { - console.error(`Invalid 'selectionBehavior' specified: '${selectionBehavior}'. Expected 'clear', 'replace' or 'preserve'.`); - selectionBehavior = void 0; - } return { id: this.el.id, name: this.el.dataset.name, collection: this.collection(), - multiple: this.el.dataset.multiple === "true" || this.el.dataset.multiple === "", - disabled: this.el.dataset.disabled === "true" || this.el.dataset.disabled === "", - readOnly: this.el.dataset.readOnly === "true" || this.el.dataset.readOnly === "", - loopFocus: this.el.dataset.loopFocus === "true" || this.el.dataset.loopFocus === "", - allowCustomValue: this.el.dataset.allowCustomValue === "true" || this.el.dataset.allowCustomValue === "", - inputBehavior, - selectionBehavior, + inputBehavior: getOption(this.el, "inputBehavior", ["autohighlight", "autocomplete", "none"]), + selectionBehavior: getOption(this.el, "selectionBehavior", ["clear", "replace", "preserve"]), + multiple: getBooleanOption(this.el, "multiple"), + disabled: getBooleanOption(this.el, "disabled"), + readOnly: getBooleanOption(this.el, "readOnly"), + loopFocus: getBooleanOption(this.el, "loopFocus"), + allowCustomValue: getBooleanOption(this.el, "allowCustomValue"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); @@ -396,9 +394,9 @@ var combobox_default = { if (this.el.dataset.onValueChange) { this.pushEvent(this.el.dataset.onValueChange, details); } - } + }, }; - } + }, }; // hooks/dialog.ts @@ -427,25 +425,19 @@ var dialog_default = { this.dialog.destroy(); }, context() { - let role = this.el.dataset.role; - const validRoles = ["dialog", "alertdialog"]; - if (role !== void 0 && !validRoles.includes(role)) { - console.error(`Invalid 'role' specified: '${role}'. Expected 'dialog' or 'alertdialog'.`); - role = void 0; - } return { id: this.el.id, - role, - preventScroll: this.el.dataset.preventScroll === "true" || this.el.dataset.preventScroll === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + role: getOption(this.el, "role", ["dialog", "alertdialog"]), + preventScroll: getBooleanOption(this.el, "preventScroll"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/menu.ts @@ -496,8 +488,7 @@ var Menu = class extends Component { } } renderSeparators() { - for (const separator of this.el.querySelectorAll("[data-part='separator']")) - spreadProps(separator, this.api.getSeparatorProps()); + for (const separator of this.el.querySelectorAll("[data-part='separator']")) spreadProps(separator, this.api.getSeparatorProps()); } }; var menu_default = { @@ -511,7 +502,7 @@ var menu_default = { }, beforeDestroy() { this.menu.destroy(); - } + }, }; // hooks/pin-input.ts @@ -555,26 +546,14 @@ var pin_input_default = { this.pinInput.destroy(); }, context() { - let type = this.el.dataset.type; - const validTypes = ["alphanumeric", "numeric", "alphabetic"]; - if (type !== void 0 && !validTypes.includes(type)) { - console.error(`Invalid 'type' specified: '${type}'. Expected 'alphanumeric', 'numeric' or 'alphabetic'.`); - type = void 0; - } - let dir = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"]; - if (dir !== void 0 && !validDirs.includes(dir)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = void 0; - } return { id: this.el.id, - type, - otp: this.el.dataset.otp === "true" || this.el.dataset.otp === "", - mask: this.el.dataset.mask === "true" || this.el.dataset.mask === "", - blurOnComplete: this.el.dataset.blurOnComplete === "true" || this.el.dataset.blurOnComplete === "", placeholder: this.el.dataset.placeholder, - dir, + type: getOption(this.el, "type", ["alphanumeric", "numeric", "alphabetic"]), + dir: getOption(this.el, "dir", ["ltr", "rtl"]), + otp: getBooleanOption(this.el, "otp"), + mask: getBooleanOption(this.el, "mask"), + blurOnComplete: getBooleanOption(this.el, "blurOnComplete"), onValueChange: (details) => { if (this.el.dataset.onChange) { this.pushEvent(this.el.dataset.onChange, details); @@ -589,9 +568,9 @@ var pin_input_default = { if (this.el.dataset.onInvalid) { this.pushEvent(this.el.dataset.onInvalid, details); } - } + }, }; - } + }, }; // hooks/popover.ts @@ -622,17 +601,17 @@ var popover_default = { context() { return { id: this.el.id, - autoFocus: this.el.dataset.autoFocus === "true" || this.el.dataset.autoFocus === "", - modal: this.el.dataset.modal === "true" || this.el.dataset.modal === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + autoFocus: getBooleanOption(this.el, "autoFocus"), + modal: getBooleanOption(this.el, "modal"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/portal.ts @@ -674,24 +653,18 @@ var Portal = class { }; var portal_default = { mounted() { - const parentWithHook = this.el.parentElement?.closest("[phx-hook]"); - console.log(parentWithHook); - window.requestAnimationFrame(() => { - if (!this.el.dataset.target) return; - this.portal = new Portal(this.el, this.el.dataset.target, { screen: 400 }); - this.portal.update(); - if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); - }); + if (!this.el.dataset.target) return; + this.portal = new Portal(this.el, this.el.dataset.target, { screen: 400 }); + this.portal.update(); + if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); }, updated() { - window.requestAnimationFrame(() => { - this.portal.update(); - if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); - }); + this.portal.update(); + if (this.portal.mediaQuery) this.portal.onResize(this.portal.mediaQuery); }, beforeDestroy() { this.portal.destroy(); - } + }, }; // hooks/tooltip.ts @@ -738,20 +711,20 @@ var tooltip_default = { id: this.el.id, openDelay, closeDelay, - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", - closeOnScroll: this.el.dataset.closeOnScroll === "true" || this.el.dataset.closeOnScroll === "", - closeOnPointerDown: this.el.dataset.closeOnPointerDown === "true" || this.el.dataset.closeOnPointerDown === "", positioning: { - placement: this.el.dataset.positioningPlacement + placement: this.el.dataset.positioningPlacement, }, + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), + closeOnScroll: getBooleanOption(this.el, "closeOnScroll"), + closeOnPointerDown: getBooleanOption(this.el, "closeOnPointerDown"), onOpenChange: (details) => { this.tooltip.onOpenChange(details); if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); } - } + }, }; - } + }, }; // hooks/index.ts @@ -765,7 +738,7 @@ var Hooks = { PinInput: pin_input_default, Popover: popover_default, Portal: portal_default, - Tooltip: tooltip_default + Tooltip: tooltip_default, }; export { accordion_default as Accordion, @@ -778,5 +751,5 @@ export { pin_input_default as PinInput, popover_default as Popover, portal_default as Portal, - tooltip_default as Tooltip + tooltip_default as Tooltip, }; diff --git a/hooks/pin-input.ts b/hooks/pin-input.ts index e391763..c07657e 100644 --- a/hooks/pin-input.ts +++ b/hooks/pin-input.ts @@ -1,5 +1,5 @@ import * as pinInput from "@zag-js/pin-input"; -import { normalizeProps, spreadProps, renderPart } from "./util"; +import { normalizeProps, spreadProps, renderPart, getBooleanOption, getOption } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -60,30 +60,14 @@ export default { }, context(): pinInput.Context { - let type: string | undefined = this.el.dataset.type; - const validTypes = ["alphanumeric", "numeric", "alphabetic"] as const; - - if (type !== undefined && !validTypes.includes(type as any)) { - console.error(`Invalid 'type' specified: '${type}'. Expected 'alphanumeric', 'numeric' or 'alphabetic'.`); - type = undefined; - } - - let dir: string | undefined = this.el.dataset.dir; - const validDirs = ["ltr", "rtl"] as const; - - if (dir !== undefined && !validDirs.includes(dir as any)) { - console.error(`Invalid 'dir' specified: '${dir}'. Expected 'ltr' or 'rtl'.`); - dir = undefined; - } - return { id: this.el.id, - type: type as Type, - otp: this.el.dataset.otp === "true" || this.el.dataset.otp === "", - mask: this.el.dataset.mask === "true" || this.el.dataset.mask === "", - blurOnComplete: this.el.dataset.blurOnComplete === "true" || this.el.dataset.blurOnComplete === "", placeholder: this.el.dataset.placeholder, - dir: dir as Dir, + type: getOption(this.el, "type", ["alphanumeric", "numeric", "alphabetic"] as const) as Type, + dir: getOption(this.el, "dir", ["ltr", "rtl"] as const) as Dir, + otp: getBooleanOption(this.el, "otp"), + mask: getBooleanOption(this.el, "mask"), + blurOnComplete: getBooleanOption(this.el, "blurOnComplete"), onValueChange: (details: pinInput.ValueChangeDetails) => { if (this.el.dataset.onChange) { this.pushEvent(this.el.dataset.onChange, details); diff --git a/hooks/popover.ts b/hooks/popover.ts index 9a9fc63..98c0d6b 100644 --- a/hooks/popover.ts +++ b/hooks/popover.ts @@ -1,5 +1,5 @@ import * as popover from "@zag-js/popover"; -import { normalizeProps, renderPart } from "./util"; +import { getBooleanOption, normalizeProps, renderPart } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -41,10 +41,10 @@ export default { context(): popover.Context { return { id: this.el.id, - autoFocus: this.el.dataset.autoFocus === "true" || this.el.dataset.autoFocus === "", - modal: this.el.dataset.modal === "true" || this.el.dataset.modal === "", - closeOnInteractOutside: this.el.dataset.closeOnInteractOutside === "true" || this.el.dataset.closeOnInteractOutside === "", - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", + autoFocus: getBooleanOption(this.el, "autoFocus"), + modal: getBooleanOption(this.el, "modal"), + closeOnInteractOutside: getBooleanOption(this.el, "closeOnInteractOutside"), + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), onOpenChange: (details: popover.OpenChangeDetails) => { if (this.el.dataset.onOpenChange) { this.pushEvent(this.el.dataset.onOpenChange, details); diff --git a/hooks/tooltip.ts b/hooks/tooltip.ts index 21c2d2a..f6c4e28 100644 --- a/hooks/tooltip.ts +++ b/hooks/tooltip.ts @@ -1,5 +1,5 @@ import * as tooltip from "@zag-js/tooltip"; -import { normalizeProps, renderPart } from "./util"; +import { getBooleanOption, normalizeProps, renderPart } from "./util"; import { Component } from "./component"; import type { ViewHook } from "phoenix_live_view"; import type { Machine } from "@zag-js/core"; @@ -60,12 +60,12 @@ export default { id: this.el.id, openDelay: openDelay, closeDelay: closeDelay, - closeOnEscape: this.el.dataset.closeOnEscape === "true" || this.el.dataset.closeOnEscape === "", - closeOnScroll: this.el.dataset.closeOnScroll === "true" || this.el.dataset.closeOnScroll === "", - closeOnPointerDown: this.el.dataset.closeOnPointerDown === "true" || this.el.dataset.closeOnPointerDown === "", positioning: { placement: this.el.dataset.positioningPlacement as tooltip.Placement, }, + closeOnEscape: getBooleanOption(this.el, "closeOnEscape"), + closeOnScroll: getBooleanOption(this.el, "closeOnScroll"), + closeOnPointerDown: getBooleanOption(this.el, "closeOnPointerDown"), onOpenChange: (details: tooltip.OpenChangeDetails) => { this.tooltip.onOpenChange(details); if (this.el.dataset.onOpenChange) { diff --git a/hooks/util.ts b/hooks/util.ts index cf7a0a0..6492cf3 100644 --- a/hooks/util.ts +++ b/hooks/util.ts @@ -5,18 +5,14 @@ type Attribute = { value: string; }; -type AttributeMap = { +type AttributeCache = { part: string; - style: string; + cssText: string; hasFocus: boolean; attrs: Attribute[]; }; -export interface Attrs { - [key: string]: any; -} - -const propMap: Attrs = { +const propMap: Record = { onFocus: "onFocusin", onBlur: "onFocusout", onChange: "onInput", @@ -27,12 +23,13 @@ const propMap: Attrs = { defaultChecked: "checked", }; -const prevAttrsMap = new WeakMap(); +const prevAttrsMap = new WeakMap>(); const toStyleString = (style: any) => { return Object.entries(style).reduce((styleString, [key, value]) => { if (value === null || value === undefined) return styleString; const formattedKey = key.startsWith("--") ? key : key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`); + return `${styleString}${formattedKey}:${value};`; }, ""); }; @@ -52,7 +49,7 @@ export const normalizeProps = createNormalizer((props: any) => { }, {}); }); -export const spreadProps = (node: HTMLElement, attrs: Attrs) => { +export const spreadProps = (node: HTMLElement, attrs: Record) => { const oldAttrs = prevAttrsMap.get(node) || {}; const attrKeys = Object.keys(attrs); @@ -120,6 +117,23 @@ export const renderPart = (root: HTMLElement, name: string, api: any) => { if (part) spreadProps(part, api[getterName]()); }; +export const getOption = (el: HTMLElement, name: string, validOptions: string[]) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + let initial: string | undefined = el.dataset[kebabName]; + + if (initial !== undefined && !validOptions.includes(initial as any)) { + console.error(`Invalid '${name}' specified: '${initial}'. Expected one of '${validOptions.join("', '")}'.`); + initial = undefined; + } + + return initial; +}; + +export const getBooleanOption = (el: HTMLElement, name: string) => { + const kebabName = name.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(); + return el.dataset[kebabName] === "true" || el.dataset[kebabName] === ""; +}; + export const getAttributes = (root: HTMLElement, name: string) => { const part = root.querySelector(`[data-part='${name}']`); if (!part) return; @@ -133,13 +147,13 @@ export const getAttributes = (root: HTMLElement, name: string) => { return { part: name, - style: part.style.cssText, + cssText: part.style.cssText, hasFocus: part === document.activeElement, attrs, }; }; -export const restoreAttributes = (root: HTMLElement, attributeMaps: AttributeMap[]) => { +export const restoreAttributes = (root: HTMLElement, attributeMaps: AttributeCache[]) => { for (const attributeMap of attributeMaps) { const part = root.querySelector(`[data-part='${attributeMap.part}']`); if (!part) return; @@ -147,7 +161,7 @@ export const restoreAttributes = (root: HTMLElement, attributeMaps: AttributeMap for (const attr of attributeMap.attrs) { part.setAttribute(attr.name, attr.value); } - part.style.cssText = attributeMap.style; + part.style.cssText = attributeMap.cssText; if (attributeMap.hasFocus) part.focus(); } }; diff --git a/lib/turboprop/headless/accordion.ex b/lib/turboprop/headless/accordion.ex index 278ec44..ff0d5bd 100644 --- a/lib/turboprop/headless/accordion.ex +++ b/lib/turboprop/headless/accordion.ex @@ -5,11 +5,20 @@ defmodule Turboprop.Headless.Accordion do import Turboprop.Headless attr :id, :string, default: nil - attr :as, :any, default: "div" + + attr :as, :any, + default: "div", + doc: """ + Element or component to render as. + + Can either be a string representing an HTML element, such as `div`, `section` or `button`, or a captured function component, such as + `&card/1` or `&button/1`. + """ attr :disabled, :boolean, default: false, doc: "Disable opening and closing items." attr :collapsible, :boolean, default: true, doc: "Allow closing an item after opening it." attr :multiple, :boolean, default: false, doc: "Allow multiple items to be open at once." + attr :on_value_change, :string, default: nil, doc: "Event to send when the value of open items changes." attr :rest, :global @@ -19,6 +28,7 @@ defmodule Turboprop.Headless.Accordion do {disabled, assigns} = Map.pop(assigns, :disabled) {collapsible, assigns} = Map.pop(assigns, :collapsible) {multiple, assigns} = Map.pop(assigns, :multiple) + {on_value_change, assigns} = Map.pop(assigns, :on_value_change) render_as_tag_or_component(assigns, %{ diff --git a/package-lock.json b/package-lock.json index c678d38..6ec6839 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,187 +9,22 @@ "version": "0.4.2", "license": "MIT", "dependencies": { - "@zag-js/accordion": "^0.59.0", - "@zag-js/clipboard": "^0.59.0", - "@zag-js/collapsible": "^0.59.0", - "@zag-js/combobox": "^0.59.0", - "@zag-js/dialog": "^0.59.0", - "@zag-js/menu": "^0.59.0", - "@zag-js/pin-input": "^0.59.0", - "@zag-js/popover": "^0.59.0", - "@zag-js/tooltip": "^0.59.0", - "@zag-js/types": "^0.59.0", - "valtio": "^1.13.2" + "@zag-js/accordion": "^0.60.0", + "@zag-js/clipboard": "^0.60.0", + "@zag-js/collapsible": "^0.60.0", + "@zag-js/combobox": "^0.60.0", + "@zag-js/dialog": "^0.60.0", + "@zag-js/menu": "^0.60.0", + "@zag-js/pin-input": "^0.60.0", + "@zag-js/popover": "^0.60.0", + "@zag-js/tooltip": "^0.60.0", + "@zag-js/types": "^0.60.0" }, "devDependencies": { - "@biomejs/biome": "^1.8.2", "@types/phoenix_live_view": "^0.18.5", + "prettier": "^3.3.2", "tsup": "^8.1.0", - "typescript": "^5.5.2" - } - }, - "node_modules/@biomejs/biome": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-1.8.3.tgz", - "integrity": "sha512-/uUV3MV+vyAczO+vKrPdOW0Iaet7UnJMU4bNMinggGJTAnBPjCoLEYcyYtYHNnUNYlv4xZMH6hVIQCAozq8d5w==", - "dev": true, - "hasInstallScript": true, - "license": "MIT OR Apache-2.0", - "bin": { - "biome": "bin/biome" - }, - "engines": { - "node": ">=14.21.3" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/biome" - }, - "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "1.8.3", - "@biomejs/cli-darwin-x64": "1.8.3", - "@biomejs/cli-linux-arm64": "1.8.3", - "@biomejs/cli-linux-arm64-musl": "1.8.3", - "@biomejs/cli-linux-x64": "1.8.3", - "@biomejs/cli-linux-x64-musl": "1.8.3", - "@biomejs/cli-win32-arm64": "1.8.3", - "@biomejs/cli-win32-x64": "1.8.3" - } - }, - "node_modules/@biomejs/cli-darwin-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-1.8.3.tgz", - "integrity": "sha512-9DYOjclFpKrH/m1Oz75SSExR8VKvNSSsLnVIqdnKexj6NwmiMlKk94Wa1kZEdv6MCOHGHgyyoV57Cw8WzL5n3A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-darwin-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-1.8.3.tgz", - "integrity": "sha512-UeW44L/AtbmOF7KXLCoM+9PSgPo0IDcyEUfIoOXYeANaNXXf9mLUwV1GeF2OWjyic5zj6CnAJ9uzk2LT3v/wAw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-1.8.3.tgz", - "integrity": "sha512-fed2ji8s+I/m8upWpTJGanqiJ0rnlHOK3DdxsyVLZQ8ClY6qLuPc9uehCREBifRJLl/iJyQpHIRufLDeotsPtw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.8.3.tgz", - "integrity": "sha512-9yjUfOFN7wrYsXt/T/gEWfvVxKlnh3yBpnScw98IF+oOeCYb5/b/+K7YNqKROV2i1DlMjg9g/EcN9wvj+NkMuQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-1.8.3.tgz", - "integrity": "sha512-I8G2QmuE1teISyT8ie1HXsjFRz9L1m5n83U1O6m30Kw+kPMPSKjag6QGUn+sXT8V+XWIZxFFBoTDEDZW2KPDDw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-1.8.3.tgz", - "integrity": "sha512-UHrGJX7PrKMKzPGoEsooKC9jXJMa28TUSMjcIlbDnIO4EAavCoVmNQaIuUSH0Ls2mpGMwUIf+aZJv657zfWWjA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-arm64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-1.8.3.tgz", - "integrity": "sha512-J+Hu9WvrBevfy06eU1Na0lpc7uR9tibm9maHynLIoAjLZpQU3IW+OKHUtyL8p6/3pT2Ju5t5emReeIS2SAxhkQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" - } - }, - "node_modules/@biomejs/cli-win32-x64": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-1.8.3.tgz", - "integrity": "sha512-/PJ59vA1pnQeKahemaQf4Nyj7IKUvGQSc3Ze1uIGi+Wvr1xF7rGobSrAAG01T/gUDG21vkDsZYM03NAmPiVkqg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT OR Apache-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=14.21.3" + "typescript": "^5.5.3" } }, "node_modules/@esbuild/aix-ppc64": { @@ -584,28 +419,28 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.3.tgz", - "integrity": "sha512-1ZpCvYf788/ZXOhRQGFxnYQOVgeU+pi0i+d0Ow34La7qjIXETi6RNswGVKkA6KcDO8/+Ysu2E/CeUmmeEBDvTg==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", + "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.3" + "@floating-ui/utils": "^0.2.4" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.6.tgz", - "integrity": "sha512-qiTYajAnh3P+38kECeffMSQgbvXty2VB6rS+42iWR4FPIlZjLK84E9qtLnMTLIpPz2znD/TaFqaiavMUrS+Hcw==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", + "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.0.0", - "@floating-ui/utils": "^0.2.3" + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.4" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.3.tgz", - "integrity": "sha512-XGndio0l5/Gvd6CLIABvsav9HHezgDFFhDfHk1bvLfr9ni8dojqLSvBbotJEjmIwNHL7vK4QzBJTdBRoB+c1ww==", + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", + "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==", "license": "MIT" }, "node_modules/@isaacs/cliui": { @@ -977,281 +812,282 @@ } }, "node_modules/@zag-js/accordion": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-0.59.0.tgz", - "integrity": "sha512-tZBp37qZlVqmK3QF1U8ro2jR26f37Up9bppY5oAksiXXnNf+WeZtGVg3am2MjfyP87YhbDpYiwdXqXLSqPHABA==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-0.60.0.tgz", + "integrity": "sha512-Pd7roAv7/YBJgCBFjE/UH+wospp2Wkn9p/g83oO0KmmidBhyJr9ad/15OODfAk9pGPOtwRDUkE04WD4ofhWYMg==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/anatomy": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-0.59.0.tgz", - "integrity": "sha512-AhZc6QZUmruBtnbizuxNPUp+LEvRFo+5aDRyE61WOFNbLZmRWH+VjxXGFo22+cm/+Ek/6daG+wG6lrMtKjP+Lg==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-0.60.0.tgz", + "integrity": "sha512-WlQM91y7fscHZry43TZ//YsLMZlK3QMQv29GxvlAnvxhTF++WUXKlL26HX41CtN3MwFk6PyLtGAwH2MyHuzOiQ==", "license": "MIT" }, "node_modules/@zag-js/aria-hidden": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/aria-hidden/-/aria-hidden-0.59.0.tgz", - "integrity": "sha512-/JSi0lj5cjZ+mugSap84G1mgxQO0KTxEESED81GdASqp8eCmQ14J4mruJtJxbwmBklxh8XlrAsw78EQx0tg6Rg==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/aria-hidden/-/aria-hidden-0.60.0.tgz", + "integrity": "sha512-Hl6/c1cu1HDAk68bYLN19ctTlhuG//DP8og1Sv1MCiFXe/U/nGDGaAYlzbeNRqW8y1ZJGyzSfLq7wr4VHH0Fdw==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "0.59.0" + "@zag-js/dom-query": "0.60.0" } }, "node_modules/@zag-js/clipboard": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/clipboard/-/clipboard-0.59.0.tgz", - "integrity": "sha512-Guiu3ho55ihQRjJNqdWRsUUp+irts5xh1lph02mTVNc3Er9dHpdVqP/SAhGKZWZJZC4yXbd32J1bWDzPDk1rQw==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/clipboard/-/clipboard-0.60.0.tgz", + "integrity": "sha512-VN3CoPaN+WSnzzMgQHj7ltmXYHYC2GuQIas/EtXHdtEuhGnclfV+q3ZnYUjzK744LDI6OY43xrxV+y7dDgHqqQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/collapsible": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/collapsible/-/collapsible-0.59.0.tgz", - "integrity": "sha512-QwHEBoFI1YPEIAoSRky7G8r/mZicC4a7cHGCN84VdOB1Sv1uiRfv8Y1A5aHpX5lNPJtrS/HRsyugCkmWUjfW4w==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/collapsible/-/collapsible-0.60.0.tgz", + "integrity": "sha512-jcPc4awp4fLauaQT43ydyHRjv6ZO2QPhps9eVEZ/+NQTyMJxeO+c+ObPzI+mh2juT+AusiuNYqkX7G6kDtEZvA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/collection": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/collection/-/collection-0.59.0.tgz", - "integrity": "sha512-btv1Ff7XukC4UYlKK8IzCG2H7KGRtPCA8QShuMDWM8mI5dqyTac27JjjhAV1jL6WGh14EDMS/DzK8+O2MsmFRQ==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/collection/-/collection-0.60.0.tgz", + "integrity": "sha512-gXu3FBTpkLDtlT1P8iHOt6lLDfs7Gfq7fqeY6rxi9LJ8udUVQVks9d3zExa1cmsu5fWe1LoPhjMcDlaFs7YeWQ==", "license": "MIT", "dependencies": { - "@zag-js/utils": "0.59.0" + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/combobox": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/combobox/-/combobox-0.59.0.tgz", - "integrity": "sha512-TXgT9QqRig5MOtpMikxbUCnqFdJ4vXR95l+3UMvM+b9vw9L6nHIb6sS7V3fhJ+YBhO1V4iMMh9uZ30c5szY/xQ==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/combobox/-/combobox-0.60.0.tgz", + "integrity": "sha512-SQqfn24Khk0dO4bESg4D9CgWpX8ogfTwREgl5NnL99jDA+G6T1RPD7mbdyPinbDTYmEg0RFu7RnkwHyjr9/IQA==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/aria-hidden": "0.59.0", - "@zag-js/collection": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dismissable": "0.59.0", - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/popper": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/aria-hidden": "0.60.0", + "@zag-js/collection": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dismissable": "0.60.0", + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/popper": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/core": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-0.59.0.tgz", - "integrity": "sha512-M/4AodFhmkylvHfT6vMEPKWyAZaUgMYF3uTYveEDJzMY7SNs4eZVLq31Os9kqNJN5sQLt7QBoyCdMfVJYD+f1Q==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-0.60.0.tgz", + "integrity": "sha512-wClgnrIkNNPP6icF3MlfOSGUPqXLAJhYef78B6EZRcfMO3ZcFqT83rY6FsT76sozhnZdIIlg9f7D+KATStjbSg==", "license": "MIT", "dependencies": { - "@zag-js/store": "0.59.0", + "@zag-js/store": "0.60.0", "klona": "2.0.6" } }, "node_modules/@zag-js/dialog": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/dialog/-/dialog-0.59.0.tgz", - "integrity": "sha512-NEGq6bw5O8KQWJygwfDNXBVfrXVDVEbXJyIhSS32fEMGPNk6WqGVer4o1JvOSK2TWSUrw31E75m/z0WGSTFiVQ==", - "license": "MIT", - "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/aria-hidden": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dismissable": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/remove-scroll": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/dialog/-/dialog-0.60.0.tgz", + "integrity": "sha512-SfT8Nan+TmcaTmoxHUK2iARt/02MoU0BsXXuMdjlznbMGpzEmSvz1pQeBPoZpdFyQoQVmL/M01Q6d4kF/5BrGg==", + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "0.60.0", + "@zag-js/aria-hidden": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dismissable": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/remove-scroll": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0", "focus-trap": "7.5.4" } }, "node_modules/@zag-js/dismissable": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/dismissable/-/dismissable-0.59.0.tgz", - "integrity": "sha512-/G5g1BrkbBTCxW/QGCbcyEF8TtToFl5hPq6hKIeRI5AgF7RYPljyuiUpGTkevNMsJ06bUJrZTxAoJBMgShUmMA==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/dismissable/-/dismissable-0.60.0.tgz", + "integrity": "sha512-B2l8nIbSVQFw3ISfcieVVCTAAym/eLDuRnbmzvy6DVAhFq4UamGuQ++abXNZJVMoNEp6hoaZj858G7Jt9y5jyw==", "license": "MIT", "dependencies": { - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/interact-outside": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/interact-outside": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/dom-event": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/dom-event/-/dom-event-0.59.0.tgz", - "integrity": "sha512-m+M1wIxzCsf88xiCzd8vo9/oReCT7YtXgki8KmsdCpm1C37bfjKSwDo4dIg/hgaUFtFHmvOOzY2qq7jemgRZ9w==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/dom-event/-/dom-event-0.60.0.tgz", + "integrity": "sha512-9Qz+HBotMhBUlXPTIb6NezFDoe/PlkTD9O3I70cxEDsoe+Bm/37/ZgB52n9NyEn15Bm3G9g3iZYMTnBvfxq3xg==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "0.59.0", - "@zag-js/text-selection": "0.59.0", - "@zag-js/types": "0.59.0" + "@zag-js/dom-query": "0.60.0", + "@zag-js/text-selection": "0.60.0", + "@zag-js/types": "0.60.0" } }, "node_modules/@zag-js/dom-query": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.59.0.tgz", - "integrity": "sha512-sNsIyUzNLEFp8Alk4XqC4hIV2MiDOv4XBAptP0t4b18lr9/2mvAJMJhzm/0PJF10Id1gLjVj+lYNSc9l2wGXBw==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-0.60.0.tgz", + "integrity": "sha512-d7ecLbw3Dqq3glsj4Wmp6Gw6ggjSTCzqF2RbuuOBKVRxGDivlq78E9438uKvkySt3t4mPefaHuwhQp1VfYdDSQ==", "license": "MIT" }, "node_modules/@zag-js/form-utils": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/form-utils/-/form-utils-0.59.0.tgz", - "integrity": "sha512-TDbCo9OEARuZFuVWMNn6afVZVEg4rBPZhLOBNZ1gg/yB4qtJLvWTC44sU3s/ZrQCofck2JGydYGuQ0POHszF5g==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/form-utils/-/form-utils-0.60.0.tgz", + "integrity": "sha512-FVPXhNB3aDv0lCc0hub7le4Ujyvwl9Uo74DKXMcXVNsc/DuCUYDGaxx9oZ1vezqKOI7XVEyXedPtFtCYjC8wRw==", "license": "MIT" }, "node_modules/@zag-js/interact-outside": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/interact-outside/-/interact-outside-0.59.0.tgz", - "integrity": "sha512-5zMYJvcE6wnuONUQwOHwewZp0T4DxWYvCQDvJeHFDl+pEjgM3LWlkEwGhic68Fyyd9qLatiLFdO9GoAZ+jLb3A==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/interact-outside/-/interact-outside-0.60.0.tgz", + "integrity": "sha512-uYn1C/vOiFEhUa3E7w9lhYCEzKwINnuLLLEodSNYlZdDX5bgWHPmoQIGn6l3Xy7fj8/wPoFmU7TTC3WuO8TaAQ==", "license": "MIT", "dependencies": { - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/menu": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/menu/-/menu-0.59.0.tgz", - "integrity": "sha512-sA8YRofM9rR3GqntuTGpeQRv0diFKQN3NaQFoP9kqupuP8pCtY8fGNlk3lbburEdT4vX46/ak/wRcbhsCJsF0A==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/menu/-/menu-0.60.0.tgz", + "integrity": "sha512-AyIeTJjmhqEoFs8cRxcDnGGv7GTKTFPZJSU0Z/8WDxoz5ACKpYUrNiAZ2mVjfclFAVlWtyhuGValOB3kfiQkbQ==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dismissable": "0.59.0", - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/popper": "0.59.0", - "@zag-js/rect-utils": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dismissable": "0.60.0", + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/popper": "0.60.0", + "@zag-js/rect-utils": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/pin-input": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/pin-input/-/pin-input-0.59.0.tgz", - "integrity": "sha512-e3NpQfyh+XP5ktKiOIN2bC+o0iqc+frP+Lmjb2hYl9OIKyNXQN5iavaqBYxaz6QUVPrpPlYMXhCzQHIXzs6T0Q==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/pin-input/-/pin-input-0.60.0.tgz", + "integrity": "sha512-JtZ0w3DLMWr0sHWlitn3ULsOGHFKOWjMkO4VKMRDy5LY8V8df9Fw84tD0hYA42H8zDGVbGL7jNMQ6D8ekwSm2Q==", "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/form-utils": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/form-utils": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/popover": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/popover/-/popover-0.59.0.tgz", - "integrity": "sha512-8UDugEuWvGnUyC1+XoWmebxdjmXULr4+Y/EyB6ALRL1RUpduU3oMomkdXVm4sHGyqU0Rd/qHNeLg+yKaeGRN0Q==", - "license": "MIT", - "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/aria-hidden": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dismissable": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/popper": "0.59.0", - "@zag-js/remove-scroll": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/popover/-/popover-0.60.0.tgz", + "integrity": "sha512-vXtwASh7M0VcI/LTlcJI+wFIl6ke4z8sxBZKVMpkSanXNsMZln/9Q84dgRmku5H5siie3q/zutCLqn52OETyEA==", + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "0.60.0", + "@zag-js/aria-hidden": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dismissable": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/popper": "0.60.0", + "@zag-js/remove-scroll": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0", "focus-trap": "7.5.4" } }, "node_modules/@zag-js/popper": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/popper/-/popper-0.59.0.tgz", - "integrity": "sha512-VTpXJgdMapsjxpJjGskv9YHyfPJ7VWCV1Fpd/bTLxNiw7h+0maAJ6PrwN/Q3v0H8jpPGX1NCg+pTX1gFYpZgKQ==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/popper/-/popper-0.60.0.tgz", + "integrity": "sha512-ny5SPNVowJH8UYlBICmqwVUY+YDivOV7S+EInAPzQ76yIQNLsfOMQpp9PvXjRpRywRyE72JysKMWBekYdU58Ow==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "1.6.6", - "@zag-js/dom-query": "0.59.0", - "@zag-js/utils": "0.59.0" + "@floating-ui/dom": "1.6.7", + "@zag-js/dom-query": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/rect-utils": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/rect-utils/-/rect-utils-0.59.0.tgz", - "integrity": "sha512-J6vSAJRTSAR6gOQqXpfQwmwTBgm75GojyHk5XItmJj5pVD1UfM3XqKBj0HRjwJMIP20TPWkrIF0OU39R0ZXDmQ==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/rect-utils/-/rect-utils-0.60.0.tgz", + "integrity": "sha512-HCseVffbxGN/W0FoT4aY0Qhylx5i7gEWbXBylrRDw5bAjAac6nuF6R/xzF/6KtXhnA+sni9ekGYeWYWBhLl2NQ==", "license": "MIT" }, "node_modules/@zag-js/remove-scroll": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/remove-scroll/-/remove-scroll-0.59.0.tgz", - "integrity": "sha512-+WzXfcYYL4v6Ri5z/UE1MMgfQAojZInN6ETZWMlfjGu6v3MK4OErrlmAuBmDepMmA95FTYnmsi/6lHz0DEhExg==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/remove-scroll/-/remove-scroll-0.60.0.tgz", + "integrity": "sha512-LzHDtYuZubmfkAUG29Ffjv6GHPsBp+47+TQ5ZkLxpw2mA3n2BG2KULnjA5WS3n4OEJEQ1Giaozg7dedSyNEyuw==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "0.59.0" + "@zag-js/dom-query": "0.60.0" } }, "node_modules/@zag-js/store": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-0.59.0.tgz", - "integrity": "sha512-JzHCqUiKrLRQNG/KS9AGLo8/ynn2ZWUWGq/IEK8q/nSDMJ9GcwqpCmYJkF41WliRkVxenxqY4bZdVgMlm4m6LA==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-0.60.0.tgz", + "integrity": "sha512-Py6szzxWOtpaB99CBd4JcqhD8DljF2Pkw6z5UPLKhd95P/QmNCRHluOK3nkW/dE7i6kfRHvCzNAXENxV5PCGbQ==", "license": "MIT", "dependencies": { "proxy-compare": "3.0.0" } }, "node_modules/@zag-js/text-selection": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/text-selection/-/text-selection-0.59.0.tgz", - "integrity": "sha512-Dzl5jPAiVI3pOf7N5mSmBJJV4byIwWFu5ehXT0nqsRfpi4NXWELzW5OOGe5MplkpIjtuZAr8awK94B8jg17C2w==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/text-selection/-/text-selection-0.60.0.tgz", + "integrity": "sha512-Prh0Z6O9L0bKkZDiloiO6dDqceeRaDdqSjrHpAl/CbT8B6fkw14SAKLFUWGSSAnjVdLTN4YAm3d1UmN0N1UAow==", "license": "MIT", "dependencies": { - "@zag-js/dom-query": "0.59.0" + "@zag-js/dom-query": "0.60.0" } }, "node_modules/@zag-js/tooltip": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/tooltip/-/tooltip-0.59.0.tgz", - "integrity": "sha512-Tr8l7fXFKuXdh8NZM3+uGshxUykwX21tK9NjXCbHB6PKO4goZX2fhKcJgUW/8/r02OZrjadoj7rXYcEFPVVh3A==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/tooltip/-/tooltip-0.60.0.tgz", + "integrity": "sha512-uJx0uhoSsjEJDkIRu6lWvR08Oxrud0OUkaSB4LFCJ7wWe1aB5XJU79UYNSjJZrcWprY0ypAjEZ+7yqalw8dR6g==", + "license": "MIT", "dependencies": { - "@zag-js/anatomy": "0.59.0", - "@zag-js/core": "0.59.0", - "@zag-js/dom-event": "0.59.0", - "@zag-js/dom-query": "0.59.0", - "@zag-js/popper": "0.59.0", - "@zag-js/types": "0.59.0", - "@zag-js/utils": "0.59.0" + "@zag-js/anatomy": "0.60.0", + "@zag-js/core": "0.60.0", + "@zag-js/dom-event": "0.60.0", + "@zag-js/dom-query": "0.60.0", + "@zag-js/popper": "0.60.0", + "@zag-js/types": "0.60.0", + "@zag-js/utils": "0.60.0" } }, "node_modules/@zag-js/types": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-0.59.0.tgz", - "integrity": "sha512-PBKDtqNJLn2jqknX/0ZcT/KWEpJSmge2yBMjIsfjB77Fq4vaqldFOGLmZowX8fAFA0FpH6F2bZ0lU9TpU1iozQ==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-0.60.0.tgz", + "integrity": "sha512-/C+kwW+crTiPKkpOnVQKPJZubvboUWAk2jjkz0hONeMe4BTxGgtX7CZ8ZP5FaeqT2RCr7OK8oMBOxVAjKfObzw==", "license": "MIT", "dependencies": { "csstype": "3.1.3" } }, "node_modules/@zag-js/utils": { - "version": "0.59.0", - "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-0.59.0.tgz", - "integrity": "sha512-rj9eGenmgE1gaOQdcTHtaHa0Kzy7gzzlR1OATnQmqwpU7C+XArhyceCESbDCc3AQVNqJAHfKb5DggaXgcB2Bwg==", + "version": "0.60.0", + "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-0.60.0.tgz", + "integrity": "sha512-8F3fEPtD5W7cwaYwAf24cgMSN8NaRRNNkXUvy+aiVvpW1FhDngfCxRgWKRlkr5b2Da6S9GwbCaxRqcEHfj/erQ==", "license": "MIT" }, "node_modules/ansi-regex": { @@ -1474,15 +1310,6 @@ } } }, - "node_modules/derive-valtio": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/derive-valtio/-/derive-valtio-0.1.0.tgz", - "integrity": "sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==", - "license": "MIT", - "peerDependencies": { - "valtio": "*" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -1862,13 +1689,6 @@ "node": ">=10" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT", - "peer": true - }, "node_modules/klona": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", @@ -1915,19 +1735,6 @@ "dev": true, "license": "MIT" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lru-cache": { "version": "10.2.2", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", @@ -2230,6 +2037,22 @@ } } }, + "node_modules/prettier": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/proxy-compare": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.0.tgz", @@ -2267,19 +2090,6 @@ ], "license": "MIT" }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -2696,9 +2506,9 @@ } }, "node_modules/typescript": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", - "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2709,47 +2519,6 @@ "node": ">=14.17" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/valtio": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.13.2.tgz", - "integrity": "sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==", - "license": "MIT", - "dependencies": { - "derive-valtio": "0.1.0", - "proxy-compare": "2.6.0", - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=12.20.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react": { - "optional": true - } - } - }, - "node_modules/valtio/node_modules/proxy-compare": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.6.0.tgz", - "integrity": "sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==", - "license": "MIT" - }, "node_modules/webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index 6a14d0d..af1ddf9 100644 --- a/package.json +++ b/package.json @@ -2,26 +2,28 @@ "name": "@leuchtturm/turboprop", "version": "0.4.2", "license": "MIT", + "type": "module", "module": "hooks/dist/index.mjs", "types": "hooks/dist/index.d.ts", - "files": ["hooks/"], + "files": [ + "hooks/" + ], "dependencies": { - "@zag-js/accordion": "^0.59.0", - "@zag-js/clipboard": "^0.59.0", - "@zag-js/collapsible": "^0.59.0", - "@zag-js/combobox": "^0.59.0", - "@zag-js/dialog": "^0.59.0", - "@zag-js/menu": "^0.59.0", - "@zag-js/pin-input": "^0.59.0", - "@zag-js/popover": "^0.59.0", - "@zag-js/tooltip": "^0.59.0", - "@zag-js/types": "^0.59.0", - "valtio": "^1.13.2" + "@zag-js/accordion": "^0.60.0", + "@zag-js/clipboard": "^0.60.0", + "@zag-js/collapsible": "^0.60.0", + "@zag-js/combobox": "^0.60.0", + "@zag-js/dialog": "^0.60.0", + "@zag-js/menu": "^0.60.0", + "@zag-js/pin-input": "^0.60.0", + "@zag-js/popover": "^0.60.0", + "@zag-js/tooltip": "^0.60.0", + "@zag-js/types": "^0.60.0" }, "devDependencies": { - "@biomejs/biome": "^1.8.2", "@types/phoenix_live_view": "^0.18.5", + "prettier": "^3.3.2", "tsup": "^8.1.0", - "typescript": "^5.5.2" + "typescript": "^5.5.3" } } diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 0000000..162de87 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,4 @@ +export default { + printWidth: 140, + tabWidth: 2, +}; diff --git a/test/turboprop_test.exs b/test/turboprop_test.exs deleted file mode 100644 index 7a74fcd..0000000 --- a/test/turboprop_test.exs +++ /dev/null @@ -1,2 +0,0 @@ -defmodule TurbopropTest do -end