├── .changeset ├── README.md └── config.json ├── .devcontainer ├── Dockerfile ├── devcontainer.json └── post-create.sh ├── .eslintignore ├── .eslintrc.cjs ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── reproduire │ └── needs-reproduction.md └── workflows │ ├── ci.yaml │ ├── preview.yml │ ├── production.yml │ ├── release.yml │ ├── reproduire-close.yml │ └── reproduire.yml ├── .gitignore ├── .gitpod.yml ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .storybook ├── main.ts └── preview.ts ├── .versionrc.cjs ├── .vscode ├── custom.code-snippets └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── RELEASE_NOTES └── the-big-bad.md ├── e2e ├── dialog.spec.ts ├── dropdown.spec.ts └── utils.ts ├── mdsvex.config.js ├── other ├── globalcss.html ├── tailwindconfig.html └── themes │ └── github-dark.json ├── package.json ├── playwright.config.ts ├── pnpm-lock.yaml ├── postcss.config.cjs ├── scripts ├── move_previews.py └── setupTest.ts ├── src ├── app.d.ts ├── app.html ├── app.postcss ├── constants.ts ├── docs │ ├── components │ │ ├── api-section-heading.svelte │ │ ├── callout.svelte │ │ ├── code-block.svelte │ │ ├── construction.svelte │ │ ├── contributor.svelte │ │ ├── contributors.svelte │ │ ├── custom-event-dialog.svelte │ │ ├── description.svelte │ │ ├── file-tabs │ │ │ ├── index.ts │ │ │ ├── list.svelte │ │ │ ├── root.svelte │ │ │ ├── tab.svelte │ │ │ └── tabs.svelte │ │ ├── icons │ │ │ ├── discord.svelte │ │ │ ├── github.svelte │ │ │ ├── index.ts │ │ │ ├── npm.svelte │ │ │ ├── pnpm.svelte │ │ │ └── yarn.svelte │ │ ├── index.ts │ │ ├── info-popover.svelte │ │ ├── install-tabs.svelte │ │ ├── js-indicator.svelte │ │ ├── kbd.svelte │ │ ├── logo.svelte │ │ ├── markdown │ │ │ ├── a.svelte │ │ │ ├── blockquote.svelte │ │ │ ├── code.svelte │ │ │ ├── h1.svelte │ │ │ ├── h2.svelte │ │ │ ├── h3.svelte │ │ │ ├── h4.svelte │ │ │ ├── h5.svelte │ │ │ ├── h6.svelte │ │ │ ├── hr.svelte │ │ │ ├── img.svelte │ │ │ ├── index.ts │ │ │ ├── kbd.svelte │ │ │ ├── layout.svelte │ │ │ ├── li.svelte │ │ │ ├── ol.svelte │ │ │ ├── p.svelte │ │ │ ├── pre.svelte │ │ │ └── ul.svelte │ │ ├── nav │ │ │ ├── index.ts │ │ │ ├── mobile-nav-link.svelte │ │ │ ├── mobile-nav.svelte │ │ │ ├── sidebar-nav.svelte │ │ │ └── theme-switch │ │ │ │ ├── index.ts │ │ │ │ ├── options.svelte │ │ │ │ ├── theme-icon.svelte │ │ │ │ ├── theme-switch.svelte │ │ │ │ └── types.ts │ │ ├── preview-style-select.svelte │ │ ├── preview-wrapper.svelte │ │ ├── preview.svelte │ │ ├── sections │ │ │ ├── api-reference.svelte │ │ │ ├── features.svelte │ │ │ └── index.ts │ │ ├── site-header.svelte │ │ ├── switch.svelte │ │ ├── table-of-contents │ │ │ ├── index.ts │ │ │ ├── table-of-contents.svelte │ │ │ └── tree.svelte │ │ ├── tables │ │ │ ├── api-table-heading.svelte │ │ │ ├── api-table.svelte │ │ │ ├── api-wrapper.svelte │ │ │ ├── custom-events-table.svelte │ │ │ ├── data-attr-table.svelte │ │ │ ├── index.ts │ │ │ ├── kbd-table.svelte │ │ │ ├── props-table.svelte │ │ │ └── returned-props-table.svelte │ │ ├── tabs │ │ │ ├── index.ts │ │ │ ├── list.svelte │ │ │ ├── root.svelte │ │ │ ├── tab.svelte │ │ │ └── tabs.svelte │ │ ├── tailwind-indicator.svelte │ │ ├── tooltip.svelte │ │ ├── type-dialog.svelte │ │ └── ui │ │ │ ├── button.svelte │ │ │ └── index.ts │ ├── config.ts │ ├── constants.ts │ ├── content │ │ ├── builders │ │ │ ├── accordion.md │ │ │ ├── avatar.md │ │ │ ├── calendar.md │ │ │ ├── checkbox.md │ │ │ ├── collapsible.md │ │ │ ├── combobox.md │ │ │ ├── context-menu.md │ │ │ ├── date-field.md │ │ │ ├── date-picker.md │ │ │ ├── date-range-field.md │ │ │ ├── date-range-picker.md │ │ │ ├── dialog.md │ │ │ ├── dropdown-menu.md │ │ │ ├── label.md │ │ │ ├── link-preview.md │ │ │ ├── menubar.md │ │ │ ├── pagination.md │ │ │ ├── pin-input.md │ │ │ ├── popover.md │ │ │ ├── progress.md │ │ │ ├── radio-group.md │ │ │ ├── range-calendar.md │ │ │ ├── scroll-area.md │ │ │ ├── select.md │ │ │ ├── separator.md │ │ │ ├── slider.md │ │ │ ├── switch.md │ │ │ ├── table-of-contents.md │ │ │ ├── tabs.md │ │ │ ├── tags-input.md │ │ │ ├── toast.md │ │ │ ├── toggle-group.md │ │ │ ├── toggle.md │ │ │ ├── toolbar.md │ │ │ ├── tooltip.md │ │ │ └── tree.md │ │ ├── controlled.md │ │ ├── dates.md │ │ ├── installation.md │ │ ├── introduction.md │ │ ├── preprocessor.md │ │ ├── transitions.md │ │ └── usage.md │ ├── data │ │ ├── builders │ │ │ ├── accordion.ts │ │ │ ├── avatar.ts │ │ │ ├── calendar.ts │ │ │ ├── checkbox.ts │ │ │ ├── collapsible.ts │ │ │ ├── combobox.ts │ │ │ ├── context-menu.ts │ │ │ ├── date-field.ts │ │ │ ├── date-picker.ts │ │ │ ├── date-range-field.ts │ │ │ ├── date-range-picker.ts │ │ │ ├── dialog.ts │ │ │ ├── dropdown-menu.ts │ │ │ ├── index.ts │ │ │ ├── label.ts │ │ │ ├── link-preview.ts │ │ │ ├── menu.ts │ │ │ ├── menubar.ts │ │ │ ├── pagination.ts │ │ │ ├── pin-input.ts │ │ │ ├── popover.ts │ │ │ ├── progress.ts │ │ │ ├── radio-group.ts │ │ │ ├── range-calendar.ts │ │ │ ├── scroll-area.ts │ │ │ ├── select.ts │ │ │ ├── separator.ts │ │ │ ├── slider.ts │ │ │ ├── switch.ts │ │ │ ├── table-of-contents.ts │ │ │ ├── tabs.ts │ │ │ ├── tags-input.ts │ │ │ ├── toast.ts │ │ │ ├── toggle-group.ts │ │ │ ├── toggle.ts │ │ │ ├── toolbar.ts │ │ │ ├── tooltip.ts │ │ │ └── tree.ts │ │ └── long-types │ │ │ ├── custom-event-detail.html │ │ │ ├── floating-config.ts │ │ │ ├── focus-prop.ts │ │ │ └── index.ts │ ├── highlighter.ts │ ├── info-popover.svelte │ ├── pp.js │ ├── pp.spec.ts │ ├── previews │ │ ├── .prettierrc │ │ ├── accordion │ │ │ ├── disabled │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── multiple │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── avatar │ │ │ └── main │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── calendar │ │ │ ├── changePh │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── changeValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── disabled │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── fixedWeeks │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── limitSelectedA │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── limitSelectedB │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── locale │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── minMax │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── monthSelect │ │ │ │ └── tailwind │ │ │ │ │ ├── MonthSelect.svelte │ │ │ │ │ └── index.svelte │ │ │ ├── multipleMonths │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multipleSelect │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── pagedNav │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── preventDeselect │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── reactToVal │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── unavailable │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── checkbox │ │ │ └── main │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── collapsible │ │ │ ├── main │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── sync │ │ │ │ └── tailwind │ │ │ │ ├── Collapsible.svelte │ │ │ │ └── index.svelte │ │ ├── combobox │ │ │ ├── debounce │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── group │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multi │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── shadow │ │ │ │ └── tailwind │ │ │ │ ├── ComboBox.svelte │ │ │ │ └── index.svelte │ │ ├── context-menu │ │ │ ├── main │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── modal │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── date-field │ │ │ ├── defaultValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── dtPlaceholder │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── readonlySegments │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut1 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut2 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut3 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut4 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut5 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut6 │ │ │ │ └── tailwind │ │ │ │ │ ├── DateField.svelte │ │ │ │ │ └── index.svelte │ │ │ ├── tut7 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut8 │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── tut9 │ │ │ │ └── tailwind │ │ │ │ │ ├── DateField.svelte │ │ │ │ │ └── index.svelte │ │ │ └── zdtPlaceholder │ │ │ │ └── tailwind │ │ │ │ ├── DateField.svelte │ │ │ │ └── index.svelte │ │ ├── date-picker │ │ │ ├── defaultPh │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── defaultValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── disabled │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── fixedWeeks │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── locale │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── minMax │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multipleMonths │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── pagedNav │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── preventDeselect │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── unavailable │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── usingValue │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── date-range-field │ │ │ ├── defaultPh │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── defaultValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── locales │ │ │ │ └── tailwind │ │ │ │ │ ├── DateRangeField.svelte │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── minMax │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── nowLA │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── nowLocalTz │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── readonlySegments │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── unavailable │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── valueAndPh │ │ │ │ └── tailwind │ │ │ │ ├── DateRangeField.svelte │ │ │ │ └── index.svelte │ │ ├── date-range-picker │ │ │ ├── defaultPh │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── defaultValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── disabled │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── fixedWeeks │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── locale │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── minMax │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multipleMonths │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── pagedNav │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── unavailable │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── usingValue │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── dialog │ │ │ ├── alert │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── controlled │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── drawer │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ ├── css │ │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── nested │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── dropdown-menu │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── modal │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── label │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── link-preview │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── menubar │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── pagination │ │ │ └── main │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── pin-input │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── popover │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── Popover.svelte │ │ │ │ │ └── index.svelte │ │ │ ├── modal │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── nested │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── progress │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── radio-group │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── range-calendar │ │ │ ├── changePh │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── changeValue │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── disabled │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── fixedWeeks │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── locale │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── LocaleCombobox.svelte │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── locales.ts │ │ │ ├── minMax │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multipleMonths │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── pagedNav │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── unavailable │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── scroll-area │ │ │ ├── always │ │ │ │ └── tailwind │ │ │ │ │ ├── flavors.ts │ │ │ │ │ └── index.svelte │ │ │ ├── auto │ │ │ │ └── tailwind │ │ │ │ │ ├── flavors.ts │ │ │ │ │ └── index.svelte │ │ │ ├── hover │ │ │ │ └── tailwind │ │ │ │ │ ├── flavors.ts │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ ├── flavors.ts │ │ │ │ │ └── index.svelte │ │ │ └── scroll │ │ │ │ └── tailwind │ │ │ │ ├── flavors.ts │ │ │ │ └── index.svelte │ │ ├── select │ │ │ ├── keyboard │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── multi │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── separator │ │ │ └── main │ │ │ │ ├── css │ │ │ │ └── index.svelte │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── slider │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── multiple │ │ │ │ └── tailwind │ │ │ │ │ ├── index.svelte │ │ │ │ │ └── slider.svelte │ │ │ ├── range │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── rtl_horizontal │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── rtl_vertical │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ ├── shadow │ │ │ │ └── tailwind │ │ │ │ │ ├── Slider.svelte │ │ │ │ │ └── index.svelte │ │ │ ├── ticks │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── vertical │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── switch │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── table-of-contents │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ ├── index.svelte │ │ │ │ └── tree.svelte │ │ ├── tabs │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── tags-input │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── toast │ │ │ ├── main │ │ │ │ └── tailwind │ │ │ │ │ └── index.svelte │ │ │ └── progress │ │ │ │ └── tailwind │ │ │ │ ├── index.svelte │ │ │ │ ├── select-hover.svelte │ │ │ │ └── toast.svelte │ │ ├── toggle-group │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── toggle │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── toolbar │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ ├── tooltip │ │ │ └── main │ │ │ │ └── tailwind │ │ │ │ └── index.svelte │ │ └── tree │ │ │ └── main │ │ │ └── tailwind │ │ │ ├── icons │ │ │ ├── JS.svelte │ │ │ └── Svelte.svelte │ │ │ ├── index.svelte │ │ │ └── tree.svelte │ ├── types.ts │ └── utils │ │ ├── content.ts │ │ ├── index.ts │ │ ├── preview.ts │ │ ├── string.ts │ │ ├── style.ts │ │ ├── transition.ts │ │ └── tree.ts ├── fonts.css ├── json │ └── contributors.json ├── lib │ ├── builders │ │ ├── accordion │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── avatar │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── calendar │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── checkbox │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── collapsible │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── combobox │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── context-menu │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── date-field │ │ │ ├── _internal │ │ │ │ ├── helpers.ts │ │ │ │ ├── parts.ts │ │ │ │ ├── tests │ │ │ │ │ └── helpers.spec.ts │ │ │ │ └── types.ts │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── date-picker │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── date-range-field │ │ │ ├── _internal │ │ │ │ └── helpers.ts │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── date-range-picker │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── dialog │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── dropdown-menu │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── hidden-input │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── index.ts │ │ ├── label │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── link-preview │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── listbox │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── menu │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── menubar │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── pagination │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── pin-input │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── popover │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── progress │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── radio-group │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── range-calendar │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── scroll-area │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ ├── scrollbars.ts │ │ │ └── types.ts │ │ ├── select │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── separator │ │ │ ├── create.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── slider │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── switch │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── table-of-contents │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── tabs │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── tags-input │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── helpers.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── toast │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── toggle-group │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── toggle │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── toolbar │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── tooltip │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ └── tree │ │ │ ├── create.ts │ │ │ ├── events.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ ├── index.ts │ ├── internal │ │ ├── actions │ │ │ ├── escape-keydown │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── floating │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── focus-trap │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── index.ts │ │ │ ├── interact-outside │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── melt │ │ │ │ └── index.ts │ │ │ ├── modal │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── popper │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ │ ├── portal.ts │ │ │ └── prevent-text-selection-overflow │ │ │ │ ├── action.ts │ │ │ │ ├── index.ts │ │ │ │ └── types.ts │ │ ├── helpers │ │ │ ├── array.ts │ │ │ ├── attr.ts │ │ │ ├── callbacks.ts │ │ │ ├── date │ │ │ │ ├── announcer.ts │ │ │ │ ├── calendar.ts │ │ │ │ ├── field.ts │ │ │ │ ├── focus.ts │ │ │ │ ├── formatter.ts │ │ │ │ ├── index.ts │ │ │ │ ├── placeholders.ts │ │ │ │ ├── store.ts │ │ │ │ ├── tests │ │ │ │ │ ├── FieldTest.svelte │ │ │ │ │ ├── calendar.spec.ts │ │ │ │ │ ├── field.spec.ts │ │ │ │ │ ├── formatter.spec.ts │ │ │ │ │ └── utils.spec.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── debounce.ts │ │ │ ├── dom.ts │ │ │ ├── elements.ts │ │ │ ├── event.ts │ │ │ ├── focus.ts │ │ │ ├── highlight.ts │ │ │ ├── id.ts │ │ │ ├── ignore.ts │ │ │ ├── index.ts │ │ │ ├── is.ts │ │ │ ├── keyboard.ts │ │ │ ├── lifecycle.ts │ │ │ ├── list.ts │ │ │ ├── locale.ts │ │ │ ├── makeElement.ts │ │ │ ├── math.ts │ │ │ ├── object.ts │ │ │ ├── overridable.ts │ │ │ ├── platform.ts │ │ │ ├── pointer.ts │ │ │ ├── polygon │ │ │ │ ├── hull.ts │ │ │ │ └── index.ts │ │ │ ├── rovingFocus.ts │ │ │ ├── scroll.ts │ │ │ ├── sleep.ts │ │ │ ├── store │ │ │ │ ├── debounceable.ts │ │ │ │ ├── derivedFromObject.ts │ │ │ │ ├── derivedVisible.ts │ │ │ │ ├── effect.ts │ │ │ │ ├── index.ts │ │ │ │ ├── lightable.ts │ │ │ │ ├── stateMachine.ts │ │ │ │ ├── toReadableStores.ts │ │ │ │ └── toWritableStores.ts │ │ │ ├── style.ts │ │ │ ├── tests │ │ │ │ ├── DomTest.svelte │ │ │ │ ├── ListDisabledTest.svelte │ │ │ │ ├── ListTest.svelte │ │ │ │ ├── array.spec.ts │ │ │ │ ├── callbacks.spec.ts │ │ │ │ ├── dom.spec.ts │ │ │ │ ├── effect.spec.ts │ │ │ │ ├── escape-keydown.spec.ts │ │ │ │ ├── keyboard.spec.ts │ │ │ │ ├── list.spec.ts │ │ │ │ ├── object.spec.ts │ │ │ │ ├── overridable.spec.ts │ │ │ │ └── withGet.spec.ts │ │ │ ├── typeahead.ts │ │ │ └── withGet.ts │ │ └── types.ts │ ├── shared │ │ └── index.ts │ └── sync.ts ├── markdown.postcss ├── pagefind.ts ├── pagefind │ ├── fragment │ │ ├── en_16f1fe9.pf_fragment │ │ ├── en_1d46621.pf_fragment │ │ ├── en_1eec87d.pf_fragment │ │ ├── en_1f88d81.pf_fragment │ │ ├── en_253ea28.pf_fragment │ │ ├── en_2bd0579.pf_fragment │ │ ├── en_2e237a4.pf_fragment │ │ ├── en_321e343.pf_fragment │ │ ├── en_34dd722.pf_fragment │ │ ├── en_35a7fed.pf_fragment │ │ ├── en_415ef09.pf_fragment │ │ ├── en_4161acc.pf_fragment │ │ ├── en_4923d38.pf_fragment │ │ ├── en_4a8730c.pf_fragment │ │ ├── en_4b19e66.pf_fragment │ │ ├── en_4fcecaf.pf_fragment │ │ ├── en_5383a1d.pf_fragment │ │ ├── en_56f028e.pf_fragment │ │ ├── en_5c106cb.pf_fragment │ │ ├── en_5f32e6f.pf_fragment │ │ ├── en_606d683.pf_fragment │ │ ├── en_61b54f5.pf_fragment │ │ ├── en_6367aa6.pf_fragment │ │ ├── en_6addd1e.pf_fragment │ │ ├── en_6b8464c.pf_fragment │ │ ├── en_749d563.pf_fragment │ │ ├── en_77c1fa3.pf_fragment │ │ ├── en_787f19f.pf_fragment │ │ ├── en_79a771c.pf_fragment │ │ ├── en_79c1fd7.pf_fragment │ │ ├── en_7a6a4a4.pf_fragment │ │ ├── en_7af1b43.pf_fragment │ │ ├── en_7cb8111.pf_fragment │ │ ├── en_7f1fe4e.pf_fragment │ │ ├── en_7f5f5d6.pf_fragment │ │ ├── en_80da96b.pf_fragment │ │ ├── en_84dca64.pf_fragment │ │ ├── en_862027d.pf_fragment │ │ ├── en_86eb18e.pf_fragment │ │ ├── en_86f4cb2.pf_fragment │ │ ├── en_87b486c.pf_fragment │ │ ├── en_88d7b94.pf_fragment │ │ ├── en_8dee4ed.pf_fragment │ │ ├── en_8eead83.pf_fragment │ │ ├── en_9b23e84.pf_fragment │ │ ├── en_9eb49a9.pf_fragment │ │ ├── en_9ee8ae6.pf_fragment │ │ ├── en_a6cfcc7.pf_fragment │ │ ├── en_a7cde16.pf_fragment │ │ ├── en_a881cb1.pf_fragment │ │ ├── en_aab8e97.pf_fragment │ │ ├── en_b29e78a.pf_fragment │ │ ├── en_b2f7e99.pf_fragment │ │ ├── en_b6f2f56.pf_fragment │ │ ├── en_bbd9fcd.pf_fragment │ │ ├── en_bec59c6.pf_fragment │ │ ├── en_bf89c03.pf_fragment │ │ ├── en_c1771c1.pf_fragment │ │ ├── en_c262815.pf_fragment │ │ ├── en_c3b0e25.pf_fragment │ │ ├── en_cc9b37e.pf_fragment │ │ ├── en_ceb1ab4.pf_fragment │ │ ├── en_d0dccd1.pf_fragment │ │ ├── en_d2d2dba.pf_fragment │ │ ├── en_d593b09.pf_fragment │ │ ├── en_e7ae582.pf_fragment │ │ ├── en_eab52f7.pf_fragment │ │ ├── en_f171c86.pf_fragment │ │ ├── en_f3c766e.pf_fragment │ │ ├── en_f4e7e33.pf_fragment │ │ ├── en_f8b9234.pf_fragment │ │ └── en_fab61f9.pf_fragment │ ├── index │ │ ├── en_18e7ecb.pf_index │ │ ├── en_7d6f722.pf_index │ │ └── en_a82e347.pf_index │ ├── pagefind-entry.json │ ├── pagefind-modular-ui.css │ ├── pagefind-modular-ui.js │ ├── pagefind-ui.css │ ├── pagefind-ui.js │ ├── pagefind.en_055429da4e.pf_meta │ ├── pagefind.en_aff7732c1a.pf_meta │ ├── wasm.en.pagefind │ └── wasm.unknown.pagefind ├── routes │ ├── (landing-ui) │ │ ├── accordion.svelte │ │ ├── pin-input.svelte │ │ ├── popover.svelte │ │ ├── search.svelte │ │ ├── slider.svelte │ │ ├── switch.svelte │ │ ├── tabs.svelte │ │ ├── tags-input.svelte │ │ ├── toggle-group.svelte │ │ └── toolbar.svelte │ ├── +error.svelte │ ├── +layout.server.ts │ ├── +layout.svelte │ ├── +layout.ts │ ├── +page.svelte │ ├── discord │ │ └── +page.ts │ ├── docs │ │ ├── +layout.svelte │ │ ├── +page.ts │ │ ├── [...slug] │ │ │ ├── +layout.server.ts │ │ │ ├── +page.server.ts │ │ │ ├── +page.svelte │ │ │ └── +page.ts │ │ └── builders │ │ │ ├── +page.ts │ │ │ └── [name] │ │ │ ├── +page.server.ts │ │ │ ├── +page.svelte │ │ │ └── +page.ts │ ├── repro │ │ └── +page.ts │ └── store.ts ├── stories │ ├── Collapsible │ │ ├── Collapsible.spec.ts │ │ ├── Collapsible.stories.ts │ │ └── Collapsible.svelte │ ├── DateField │ │ ├── DateField.stories.ts │ │ └── DateField.svelte │ ├── Dialog │ │ ├── BaseDialog.svelte │ │ ├── Dialog.stories.ts │ │ ├── Dialog.svelte │ │ ├── NestedDialog.svelte │ │ ├── Select.svelte │ │ └── WithSelect.svelte │ └── assets │ │ ├── code-brackets.svg │ │ ├── colors.svg │ │ ├── comments.svg │ │ ├── direction.svg │ │ ├── flow.svg │ │ ├── plugin.svg │ │ ├── repo.svg │ │ └── stackalt.svg └── tests │ ├── accordion │ ├── Accordion.spec.ts │ └── AccordionTest.svelte │ ├── avatar │ ├── Avatar.spec.ts │ └── AvatarTest.svelte │ ├── calendar │ ├── Calendar.spec.ts │ ├── CalendarMultiTest.svelte │ └── CalendarTest.svelte │ ├── checkbox │ ├── Checkbox.spec.ts │ └── CheckboxTest.svelte │ ├── combobox │ ├── Combobox.spec.ts │ ├── ComboboxForceVisibleTest.svelte │ └── ComboboxTest.svelte │ ├── context-menu │ ├── ContextMenu.spec.ts │ └── ContextMenuTest.svelte │ ├── date-field │ ├── DateField.spec.ts │ └── DateFieldTest.svelte │ ├── date-picker │ ├── DatePicker.spec.ts │ └── DatePickerTest.svelte │ ├── date-range-field │ ├── DateRangeField.spec.ts │ └── DateRangeFieldTest.svelte │ ├── dialog │ ├── Dialog.spec.ts │ ├── DialogNested.spec.ts │ ├── DialogNestedTest.svelte │ ├── DialogTest.svelte │ ├── DialogTransitionTest.svelte │ └── DialogTransitions.spec.ts │ ├── dropdown-menu │ ├── DropdownMenu.spec.ts │ ├── DropdownMenuForceVisibleTest.svelte │ └── DropdownMenuTest.svelte │ ├── escape-keydown │ ├── ComboboxTest.svelte │ ├── DialogTest.svelte │ ├── EscapeKeydown.spec.ts │ ├── EscapeKeydownRoot.svelte │ ├── LinkPreviewTest.svelte │ ├── MenuTest.svelte │ ├── MenubarTest.svelte │ ├── PopoverTest.svelte │ ├── SelectTest.svelte │ └── TooltipTest.svelte │ ├── hidden-input │ ├── HiddenInput.spec.ts │ └── HiddenInputTest.svelte │ ├── label │ ├── Label.spec.ts │ └── LabelTest.svelte │ ├── link-preview │ ├── LinkPreview.spec.ts │ └── LinkPreviewTest.svelte │ ├── pagination │ ├── cmp.spec.ts │ ├── cmp.svelte │ └── helpers.spec.ts │ ├── pin-input │ ├── PinInput.spec.ts │ └── PinInputTest.svelte │ ├── popover │ ├── Popover.spec.ts │ └── PopoverTest.svelte │ ├── portal │ ├── Dialog.svelte │ ├── DropdownMenu.svelte │ ├── Popover.svelte │ ├── PopoverSelect.svelte │ ├── PopoverTagsInput.svelte │ ├── PopoverTooltip.svelte │ ├── Portal.spec.ts │ ├── PortalNested.spec.ts │ ├── PortalNested.svelte │ ├── Select.svelte │ └── level.ts │ ├── radio-group │ ├── RadioGroup.spec.ts │ └── RadioGroupTest.svelte │ ├── range-calendar │ ├── RangeCalendar.spec.ts │ └── RangeCalendarTest.svelte │ ├── scroll-area │ ├── ScrollArea.spec.ts │ └── ScrollAreaTest.svelte │ ├── select │ ├── Select.spec.ts │ └── SelectTest.svelte │ ├── separator │ ├── Separator.spec.ts │ └── SeparatorTest.svelte │ ├── slider │ ├── RangeSlider.svelte │ ├── Slider.spec.ts │ └── Slider.svelte │ ├── switch │ ├── Switch.spec.ts │ └── SwitchTest.svelte │ ├── tabs │ ├── Tabs.spec.ts │ └── TabsTest.svelte │ ├── tags-input │ ├── TagsInput.spec.ts │ └── TagsInput.svelte │ ├── toggle-group │ ├── ToggleGroup.spec.ts │ └── ToggleGroupTest.svelte │ ├── toolbar │ ├── Toolbar.spec.ts │ └── ToolbarTest.svelte │ ├── tooltip │ ├── Tooltip.spec.ts │ └── Tooltip.svelte │ └── utils.ts ├── static ├── banner.png ├── favicon.png └── logo_mark.svg ├── svelte.config.js ├── tailwind.config.ts ├── tsconfig.json ├── vercel.json └── vite.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", 3 | "changelog": [ 4 | "@svitejs/changesets-changelog-github-compact", 5 | { "repo": "melt-ui/melt-ui" } 6 | ], 7 | "commit": false, 8 | "fixed": [], 9 | "linked": [], 10 | "access": "public", 11 | "baseBranch": "develop", 12 | "updateInternalDependencies": "patch", 13 | "ignore": [] 14 | } 15 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG NODE_MAJOR_VERSION 2 | ARG PNPM_VERSION 3 | 4 | FROM mcr.microsoft.com/devcontainers/javascript-node:${NODE_MAJOR_VERSION} 5 | 6 | ENV EDITOR="code -w" VISUAL="code -w" 7 | 8 | # install system dependencies for playwright 9 | RUN npx --yes playwright install-deps 10 | 11 | # install additional npm packages 12 | RUN su node -c 'npm i -g pnpm@${PNPM_VERSION}' 13 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "melt-ui", 3 | "dockerFile": "Dockerfile", 4 | "build": { 5 | "args": { "NODE_MAJOR_VERSION": "18", "PNPM_VERSION": "8.6.3" } 6 | }, 7 | "postCreateCommand": [".devcontainer/post-create.sh"], 8 | "portsAttributes": { 9 | "5173": { "label": "Melt UI" }, 10 | "6006": { "label": "Storybook" }, 11 | "9323": { "label": "Playwright Report" } 12 | }, 13 | "customizations": { 14 | "vscode": { 15 | "extensions": [ 16 | "bradlc.vscode-tailwindcss", 17 | "dbaeumer.vscode-eslint", 18 | "esbenp.prettier-vscode", 19 | "svelte.svelte-vscode" 20 | ] 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.devcontainer/post-create.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eo pipefail 4 | 5 | # when in a VS Code or GitHub Codespaces devcontainer 6 | if [ -n "${REMOTE_CONTAINERS}" ] || [ -n "${CODESPACES}" ]; then 7 | this_dir=$(cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P) 8 | workspace_root=$(realpath ${this_dir}/..) 9 | 10 | # perform additional one-time setup just after 11 | # the devcontainer is created 12 | pnpm config set store-dir /home/node/.local/share/pnpm/store 13 | pnpm install --dir "${workspace_root}" # install workspace node dependencies 14 | npx --yes playwright install # install playwright browsers 15 | 16 | fi 17 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | /dist 10 | 11 | # Ignore files for PNPM, NPM and YARN 12 | pnpm-lock.yaml 13 | package-lock.json 14 | yarn.lock 15 | 16 | CHANGELOG.md 17 | 18 | *.ignore-ts 19 | *.ignore-svelte 20 | src/docs/data/long-types/**/* 21 | 22 | 23 | storybook-static/**/* 24 | 25 | *.ignore-svelte 26 | *.ignore-ts 27 | 28 | playwright.config.ts 29 | playwright-report 30 | 31 | src/pagefind/**/* 32 | static/pagefind/**/* -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [tglide, huntabyte] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: thomasglopes 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: 🌟 Feature Request 4 | url: https://melt-ui.canny.io/ 5 | about: Request, vote and explore new features 6 | - name: 💬 Questions & Discussions 7 | url: https://github.com/melt-ui/melt-ui/discussions 8 | about: Ask questions and discuss topics with other developers 9 | - name: 👾 Chat about Melt UI with the community 10 | url: https://melt-ui.com/discord 11 | about: Chat with the community and the team behind Melt UI -------------------------------------------------------------------------------- /.github/workflows/reproduire-close.yml: -------------------------------------------------------------------------------- 1 | name: Close incomplete issues 2 | on: 3 | workflow_dispatch: 4 | schedule: 5 | - cron: "30 1 * * *" # run every day 6 | 7 | permissions: 8 | issues: write 9 | 10 | jobs: 11 | stale: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 15 | with: 16 | days-before-stale: -1 # Issues and PR will never be flagged stale automatically. 17 | stale-issue-label: "needs reproduction" # Label that flags an issue as stale. 18 | only-labels: "needs reproduction" # Only process these issues 19 | days-before-issue-close: 7 20 | ignore-updates: true 21 | remove-stale-when-updated: false 22 | close-issue-message: This issue was closed because it was open for 7 days without a reproduction. 23 | close-issue-label: closed-by-bot 24 | -------------------------------------------------------------------------------- /.github/workflows/reproduire.yml: -------------------------------------------------------------------------------- 1 | name: Reproduire 2 | on: 3 | issues: 4 | types: [labeled] 5 | 6 | permissions: 7 | issues: write 8 | 9 | jobs: 10 | reproduire: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 14 | - uses: Hebilicious/reproduire@4b686ae9cbb72dad60f001d278b6e3b2ce40a9ac # v0.0.9-mp 15 | with: 16 | label: needs reproduction 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /dist 5 | /.svelte-kit 6 | /package 7 | .env 8 | .env.* 9 | !.env.example 10 | vite.config.js.timestamp-* 11 | vite.config.ts.timestamp-* 12 | /test-results/ 13 | coverage/ 14 | storybook-static 15 | .vercel 16 | /test-results/ 17 | /playwright-report/ 18 | /playwright/.cache/ 19 | /.pnpm-store/ 20 | 21 | # Pagefind 22 | static/pagefind -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | # This configuration file was automatically generated by Gitpod. 2 | # Please adjust to your needs (see https://www.gitpod.io/docs/introduction/learn-gitpod/gitpod-yaml) 3 | # and commit this file to your remote git repository to share the goodness with others. 4 | 5 | # Learn more from ready-to-use templates: https://www.gitpod.io/docs/introduction/getting-started/quickstart 6 | 7 | tasks: 8 | - init: pnpm install 9 | command: pnpm run dev 10 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 18.15.0 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | /coverage 7 | vite.config.js.timestamp-* 8 | vite.config.ts.timestamp-* 9 | .env 10 | .env.* 11 | !.env.example 12 | dist/ 13 | .github/ 14 | .vscode/ 15 | static 16 | 17 | # Ignore files for PNPM, NPM and YARN 18 | pnpm-lock.yaml 19 | package-lock.json 20 | yarn.lock 21 | 22 | tsconfig.json 23 | 24 | CHANGELOG.md 25 | .changeset 26 | 27 | storybook-static/**/* 28 | 29 | *.ignore-svelte 30 | *.ignore-ts 31 | 32 | playwright.config.ts 33 | playwright-report 34 | .vercel 35 | 36 | src/pagefind/**/* 37 | 38 | # Don't format our pregenerated tailwind & globalcss highlighted snippets 39 | other/**/* -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "printWidth": 100, 6 | "pluginSearchDirs": ["."], 7 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 8 | "overrides": [ 9 | { 10 | "files": "*.svelte", 11 | "options": { 12 | "parser": "svelte" 13 | } 14 | }, 15 | { 16 | "files": "*.md", 17 | "options": { 18 | "parser": "markdown", 19 | "printWidth": 100, 20 | "proseWrap": "always", 21 | "tabWidth": 2, 22 | "useTabs": true, 23 | "semi": false, 24 | "trailingComma": "none", 25 | "bracketSameLine": true 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.storybook/main.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig } from '@storybook/sveltekit'; 2 | 3 | const config: StorybookConfig = { 4 | stories: ['../src/**/*.svelte', '../src/**/*.stories.@(js|ts|svelte)'], 5 | addons: [ 6 | '@storybook/addon-links', 7 | '@storybook/addon-essentials', 8 | '@storybook/addon-interactions', 9 | '@storybook/addon-styling', 10 | '@storybook/addon-a11y', 11 | ], 12 | framework: '@storybook/sveltekit', 13 | docs: { 14 | autodocs: 'tag', 15 | }, 16 | }; 17 | export default config; 18 | -------------------------------------------------------------------------------- /.storybook/preview.ts: -------------------------------------------------------------------------------- 1 | import type { Preview } from '@storybook/svelte'; 2 | import '../src/app.postcss'; 3 | 4 | const preview: Preview = { 5 | parameters: { 6 | actions: { argTypesRegex: '^on[A-Z].*' }, 7 | controls: { 8 | matchers: { 9 | color: /(background|color)$/i, 10 | date: /Date$/, 11 | }, 12 | }, 13 | }, 14 | }; 15 | 16 | export default preview; 17 | -------------------------------------------------------------------------------- /.versionrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bumpFiles: [ 3 | { 4 | filename: 'package.json', 5 | type: 'json', 6 | }, 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.ignore-svelte": "svelte", 4 | "*.ignore-ts": "typescript" 5 | } 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Thomas G. Lopes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /e2e/utils.ts: -------------------------------------------------------------------------------- 1 | import { Page } from '@playwright/test'; 2 | 3 | export const jsAvailable = async (page: Page) => { 4 | if (process.env.CI) { 5 | return await page.evaluate(() => { 6 | return new Promise((resolve) => setTimeout(resolve, 0)); 7 | }); 8 | } 9 | await page.waitForSelector('[data-browser]'); 10 | }; 11 | -------------------------------------------------------------------------------- /postcss.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'tailwindcss/nesting': {}, 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /scripts/move_previews.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | 4 | # Define your root directory 5 | root_dir = 'src/docs/previews' 6 | 7 | # Walk through the root directory 8 | for dir_path, dir_names, file_names in os.walk(root_dir): 9 | for file_name in file_names: 10 | # Check if the file is tailwind.svelte or css.svelte 11 | if file_name in ['tailwind.svelte', 'css.svelte']: 12 | # Create the new directory path 13 | new_dir = os.path.join(dir_path, file_name.split('.')[0]) 14 | # Create the new directory 15 | os.makedirs(new_dir, exist_ok=True) 16 | # Create the new file path 17 | new_file_path = os.path.join(new_dir, 'index.svelte') 18 | # Create the old file path 19 | old_file_path = os.path.join(dir_path, file_name) 20 | # Move and rename the file 21 | shutil.move(old_file_path, new_file_path) 22 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | /// <reference types="@sveltejs/kit" /> 3 | 4 | import type { TextDirection } from '$lib/internal/types.js'; 5 | 6 | // for information about these interfaces 7 | declare global { 8 | namespace App { 9 | // interface Error {} 10 | // interface Locals {} 11 | // interface PageData {} 12 | // interface Platform {} 13 | } 14 | 15 | namespace Intl { 16 | interface Locale { 17 | textInfo?: { 18 | direction: TextDirection; 19 | }; 20 | } 21 | } 22 | } 23 | 24 | export {}; 25 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const isDevelopment = process.env.NODE_ENV === 'development'; 2 | -------------------------------------------------------------------------------- /src/docs/components/api-section-heading.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { h3 as H3 } from '$docs/components/markdown/index.js'; 3 | import { createHeadingId } from '$docs/utils/index.js'; 4 | import { Hammer, Shapes } from '$icons/index.js'; 5 | import P from './markdown/p.svelte'; 6 | export let title: string; 7 | export let description: string; 8 | export let isBuilder = false; 9 | </script> 10 | 11 | <div 12 | class="absolute -left-[1px] -top-[1px] flex items-center justify-between gap-1.5 rounded-br-md rounded-tl-md border border-magnum-600 bg-magnum-600/25 px-3 py-1.5" 13 | > 14 | <H3 class="mb-0 mt-0" id={createHeadingId(title)}>{title}</H3> 15 | </div> 16 | {#if isBuilder} 17 | <Hammer class="absolute right-4 top-4 size-4 text-white" /> 18 | {:else} 19 | <Shapes class="absolute right-4 top-4 size-4 text-white" /> 20 | {/if} 21 | <P class="mb-6"> 22 | {@html description} 23 | </P> 24 | -------------------------------------------------------------------------------- /src/docs/components/callout.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { tv, type VariantProps } from 'tailwind-variants'; 3 | import { cn } from '$docs/utils/index.js'; 4 | const calloutVariants = tv({ 5 | base: 'relative rounded-tr-xl rounded-br-xl px-5 py-3 before:absolute before:left-0 before:top-0 before:h-full before:w-0.5 before:content-[""] my-6 ', 6 | variants: { 7 | type: { 8 | default: 'before:bg-magnum-700 bg-magnum-700/10 text-white border-magnum-700', 9 | info: 'before:bg-blue-500 bg-blue-500/10 text-white border-blue-500', 10 | warning: 'before:bg-yellow-500 bg-yellow-500/10 text-white border-yellow-500', 11 | danger: 'before:bg-red-500 bg-red-500/10 text-white border-red-500', 12 | success: 'before:bg-green-500 bg-green-500/10 text-white border-green-500', 13 | }, 14 | }, 15 | }); 16 | 17 | let className: string | undefined | null = undefined; 18 | export { className as class }; 19 | export let type: VariantProps<typeof calloutVariants>['type'] = 'default'; 20 | </script> 21 | 22 | <div class={cn(calloutVariants({ type, className }))} data-callout> 23 | <slot /> 24 | </div> 25 | -------------------------------------------------------------------------------- /src/docs/components/construction.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { Construction } from '$icons/index.js'; 3 | import { a as A } from '$docs/components/index.js'; 4 | </script> 5 | 6 | <div 7 | class="my-4 flex flex-col items-start gap-2 rounded-xl border border-magnum-400 bg-magnum-900/25 p-4 8 | lg:flex-row lg:items-center" 9 | > 10 | <p> 11 | <Construction class="size-8 shrink-0 text-magnum-400 lg:inline-block lg:size-6" /> 12 | <span class="font-bold">In Construction:</span> 13 | <slot> 14 | This page is still a WIP. Please check back later, or help us by contributing to 15 | <A href="https://github.com/melt-ui/melt-ui">Melt UI</A>. 16 | </slot> 17 | </p> 18 | </div> 19 | -------------------------------------------------------------------------------- /src/docs/components/contributors.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { page } from '$app/stores'; 3 | import type { FullContributor } from '$routes/docs/[...slug]/+layout.server.js'; 4 | 5 | import Contributor from './contributor.svelte'; 6 | 7 | const contributors = $page.data.contributors as FullContributor[] | undefined; 8 | </script> 9 | 10 | <ul class="ml-2 flex flex-wrap gap-y-4"> 11 | {#each contributors ?? [] as contributor} 12 | <li class="-ml-3"> 13 | <Contributor {contributor} /> 14 | </li> 15 | {/each} 16 | </ul> 17 | -------------------------------------------------------------------------------- /src/docs/components/description.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | let className: string | undefined | null = undefined; 4 | export { className as class }; 5 | </script> 6 | 7 | <p class={cn('mb-4 mt-2 text-balance text-xl text-neutral-400', className)}> 8 | <slot /> 9 | </p> 10 | -------------------------------------------------------------------------------- /src/docs/components/file-tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TabsList } from './list.svelte'; 2 | export { default as TabsRoot } from './root.svelte'; 3 | export { default as Tabs } from './tabs.svelte'; 4 | -------------------------------------------------------------------------------- /src/docs/components/file-tabs/list.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { melt } from '$lib/index.js'; 4 | import { getTabsContext } from './root.svelte'; 5 | import Tab from './tab.svelte'; 6 | 7 | const { list, tabs } = getTabsContext(); 8 | 9 | let className = ''; 10 | export { className as class }; 11 | </script> 12 | 13 | <div 14 | class={cn( 15 | 'flex w-full items-center rounded-b-none rounded-tl-lg rounded-tr-lg border-x border-t border-neutral-700/50 border-b-transparent bg-neutral-700 dark:bg-neutral-700/30', 16 | className 17 | )} 18 | use:melt={$list} 19 | > 20 | {#each $tabs as tab} 21 | <Tab {tab} /> 22 | {/each} 23 | </div> 24 | -------------------------------------------------------------------------------- /src/docs/components/file-tabs/tab.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { getTabsContext } from '$docs/components/tabs/root.svelte'; 3 | import { melt } from '$lib/index.js'; 4 | 5 | export let tab: string; 6 | 7 | const { trigger } = getTabsContext(); 8 | </script> 9 | 10 | <button 11 | use:melt={$trigger(tab)} 12 | class="border-neutral-700/50 bg-neutral-600 px-3 py-2 text-neutral-300 opacity-90 transition 13 | even:border-l first-of-type:rounded-tl-md last-of-type:border-r hover:opacity-100 focus-visible:!border-magnum-400 focus-visible:!text-magnum-400 14 | focus-visible:!ring-0 data-[state=active]:bg-neutral-800 data-[state=active]:py-2 data-[state=active]:text-magnum-600 data-[state=active]:opacity-100 data-[state=inactive]:hover:bg-neutral-700/40 dark:bg-neutral-700/30 dark:text-neutral-400 dark:data-[state=active]:bg-[#1E1E1E]" 15 | > 16 | <div class="flex items-center gap-2 px-1"> 17 | <span class="font-mono text-xs font-semibold">{tab}</span> 18 | </div> 19 | </button> 20 | -------------------------------------------------------------------------------- /src/docs/components/file-tabs/tabs.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import List from './list.svelte'; 3 | import Root from './root.svelte'; 4 | 5 | export let tabs: string[] = []; 6 | </script> 7 | 8 | <Root {tabs} let:tab> 9 | <List /> 10 | <slot {tab} /> 11 | </Root> 12 | -------------------------------------------------------------------------------- /src/docs/components/icons/discord.svelte: -------------------------------------------------------------------------------- 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36" {...$restProps}> 2 | <path 3 | fill="currentColor" 4 | d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z" 5 | /> 6 | </svg> 7 | -------------------------------------------------------------------------------- /src/docs/components/icons/npm.svelte: -------------------------------------------------------------------------------- 1 | <svg viewBox="0 0 24 24" {...$restProps}> 2 | <path 3 | d="M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z" 4 | fill="currentColor" 5 | /> 6 | </svg> 7 | -------------------------------------------------------------------------------- /src/docs/components/icons/pnpm.svelte: -------------------------------------------------------------------------------- 1 | <svg viewBox="0 0 24 24" {...$restProps}> 2 | <path 3 | d="M0 0v7.5h7.5V0zm8.25 0v7.5h7.498V0zm8.25 0v7.5H24V0zM8.25 8.25v7.5h7.498v-7.5zm8.25 0v7.5H24v-7.5zM0 16.5V24h7.5v-7.5zm8.25 0V24h7.498v-7.5zm8.25 0V24H24v-7.5z" 4 | fill="currentColor" 5 | /> 6 | </svg> 7 | -------------------------------------------------------------------------------- /src/docs/components/info-popover.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { createPopover, melt } from '$lib/index.js'; 4 | import { fade } from 'svelte/transition'; 5 | import { Info } from '$icons/index.js'; 6 | 7 | const { 8 | elements: { trigger, content, arrow }, 9 | states: { open }, 10 | } = createPopover(); 11 | 12 | export let iconClasses = ''; 13 | export let contentClasses = ''; 14 | </script> 15 | 16 | <button use:melt={$trigger} aria-label="More info"> 17 | <Info class={cn('size-4 text-white', iconClasses)} /> 18 | <span class="sr-only">Open popover</span> 19 | </button> 20 | {#if $open} 21 | <div 22 | use:melt={$content} 23 | transition:fade={{ duration: 100 }} 24 | class={cn( 25 | 'mdsvex z-30 max-w-[300px] rounded-md bg-zinc-800 px-4 py-3 shadow-sm shadow-neutral-800', 26 | contentClasses 27 | )} 28 | > 29 | <div use:melt={$arrow} /> 30 | <p class="text-sm leading-5 text-white"> 31 | <slot /> 32 | </p> 33 | </div> 34 | {/if} 35 | 36 | <style lang="postcss"> 37 | div { 38 | @apply focus:ring-0 !important; 39 | } 40 | </style> 41 | -------------------------------------------------------------------------------- /src/docs/components/install-tabs.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { Tabs } from '$docs/components/index.js'; 3 | </script> 4 | 5 | <Tabs tabs={['npm', 'yarn', 'pnpm']} let:tab> 6 | {#if tab === 'npm'} 7 | <slot name="npm" /> 8 | {:else if tab === 'yarn'} 9 | <slot name="yarn" /> 10 | {:else if tab === 'pnpm'} 11 | <slot name="pnpm" /> 12 | {/if} 13 | </Tabs> 14 | -------------------------------------------------------------------------------- /src/docs/components/js-indicator.svelte: -------------------------------------------------------------------------------- 1 | <script> 2 | import { browser } from '$app/environment'; 3 | </script> 4 | 5 | <!-- Dev mode only tailwind indicator help with making things more responsive --> 6 | 7 | <div 8 | class="fixed bottom-1 left-8 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-neutral-800 p-3 font-mono text-xs text-white" 9 | data-browser={browser ? '' : undefined} 10 | > 11 | {browser ? 'js' : 'ssr'} 12 | </div> 13 | -------------------------------------------------------------------------------- /src/docs/components/kbd.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <kbd class={cn(className)}><slot /></kbd> 9 | 10 | <style> 11 | kbd { 12 | display: inline-block; 13 | padding: theme('spacing[0.5]') theme('spacing[1.5]'); 14 | color: theme('colors.neutral.100'); 15 | white-space: nowrap; 16 | 17 | margin-block: theme('spacing.1'); 18 | 19 | background-color: theme('colors.neutral.800/0.8'); 20 | border: solid 1px theme('colors.neutral.500'); 21 | border-bottom-color: theme('colors.neutral.600'); 22 | border-radius: theme('borderRadius.DEFAULT'); 23 | box-shadow: inset 0 -1px 0 theme('colors.neutral.300/0.5'); 24 | font-size: theme('fontSize.xs'); 25 | } 26 | </style> 27 | -------------------------------------------------------------------------------- /src/docs/components/markdown/a.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { ExternalLink } from '$icons/index.js'; 3 | 4 | export let href: string; 5 | export let rel: string | undefined = undefined; 6 | 7 | $: internal = href.startsWith('/') || href.startsWith('#'); 8 | 9 | $: rel = !internal ? 'noopener noreferrer' : undefined; 10 | $: target = !internal ? '_blank' : undefined; 11 | </script> 12 | 13 | <a 14 | class="inline-flex items-center gap-1 underline underline-offset-2 transition-colors hover:text-neutral-100/80" 15 | {href} 16 | {target} 17 | {rel} 18 | > 19 | <slot /> 20 | {#if !internal} 21 | <ExternalLink class="size-4" /> 22 | {/if} 23 | </a> 24 | -------------------------------------------------------------------------------- /src/docs/components/markdown/blockquote.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <blockquote class={cn('mt-6 border-l-2 pl-6 italic', className)} {...$restProps}> 9 | <slot /> 10 | </blockquote> 11 | -------------------------------------------------------------------------------- /src/docs/components/markdown/code.svelte: -------------------------------------------------------------------------------- 1 | <code class="neutral inline"> 2 | <slot /> 3 | </code> 4 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h1.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | let className: string | undefined | null = undefined; 4 | export { className as class }; 5 | </script> 6 | 7 | <h1 class={cn('mt-2 scroll-m-20 text-4xl font-bold', className)} {...$restProps}><slot /></h1> 8 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h2.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <h2 9 | class={cn( 10 | 'mb-2.5 mt-11 scroll-m-20 border-b border-neutral-300/30 pb-1 text-[27px] font-semibold tracking-tight', 11 | className 12 | )} 13 | data-toc="" 14 | {...$restProps} 15 | > 16 | <slot /> 17 | </h2> 18 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h3.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <h3 9 | class={cn('mb-2 mt-11 scroll-m-20 text-xl font-bold tracking-tight', className)} 10 | data-toc="" 11 | {...$restProps} 12 | > 13 | <slot /> 14 | </h3> 15 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h4.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <h4 class={cn('mt-8 scroll-m-20 text-lg font-bold tracking-tight', className)} {...$restProps}> 9 | <slot /> 10 | </h4> 11 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h5.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <h5 class={cn('mt-8 scroll-m-20 text-lg font-semibold tracking-tight', className)} {...$restProps}> 9 | <slot /> 10 | </h5> 11 | -------------------------------------------------------------------------------- /src/docs/components/markdown/h6.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <h6 9 | class={cn('mt-8 scroll-m-20 text-base font-semibold tracking-tight', className)} 10 | {...$restProps} 11 | > 12 | <slot /> 13 | </h6> 14 | -------------------------------------------------------------------------------- /src/docs/components/markdown/hr.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <hr class={cn('my-4 md:my-8', className)} {...$restProps} /> 9 | -------------------------------------------------------------------------------- /src/docs/components/markdown/img.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import type { HTMLImgAttributes } from 'svelte/elements'; 3 | import { cn } from '$docs/utils/index.js'; 4 | 5 | let className: string | undefined | null = undefined; 6 | export { className as class }; 7 | export let src: HTMLImgAttributes['src'] = undefined; 8 | export let alt: HTMLImgAttributes['alt'] = undefined; 9 | </script> 10 | 11 | <img {src} {alt} class={cn('rounded-md', className)} {...$restProps} /> 12 | -------------------------------------------------------------------------------- /src/docs/components/markdown/kbd.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <kbd class={cn(className)}><slot /></kbd> 9 | 10 | <style> 11 | kbd { 12 | display: inline-block; 13 | padding: theme('spacing[0.5]') theme('spacing[1.5]'); 14 | color: theme('colors.neutral.100'); 15 | white-space: nowrap; 16 | 17 | margin-block: theme('spacing.1'); 18 | 19 | background-color: theme('colors.neutral.800/0.8'); 20 | border: solid 1px theme('colors.neutral.500'); 21 | border-bottom-color: theme('colors.neutral.600'); 22 | border-radius: theme('borderRadius.DEFAULT'); 23 | box-shadow: inset 0 -1px 0 theme('colors.neutral.300/0.5'); 24 | font-size: theme('fontSize.xs'); 25 | } 26 | </style> 27 | -------------------------------------------------------------------------------- /src/docs/components/markdown/layout.svelte: -------------------------------------------------------------------------------- 1 | <!-- MDsveX Layout Component --> 2 | <script context="module" lang="ts"> 3 | import '../../../markdown.postcss'; 4 | import { 5 | a, 6 | blockquote, 7 | h1, 8 | h2, 9 | h3, 10 | h4, 11 | h5, 12 | h6, 13 | hr, 14 | img, 15 | li, 16 | ol, 17 | p, 18 | pre, 19 | ul, 20 | } from '$docs/components/markdown/index.js'; 21 | export { a, blockquote, h1, h2, h3, h4, h5, h6, hr, img, li, ol, p, pre, ul }; 22 | </script> 23 | 24 | <script> 25 | // this gets rid of warnings in the console that the layout was created with unknown props 26 | // feels weird but we can't use TS in this mdsvex layout component (from my understanding) 27 | export let snippets = ''; 28 | export let schemas = ''; 29 | export let previews = ''; 30 | export let keyboard = ''; 31 | export let title = ''; 32 | export let description = ''; 33 | </script> 34 | 35 | <slot {snippets} {schemas} {previews} {keyboard} {title} {description} /> 36 | -------------------------------------------------------------------------------- /src/docs/components/markdown/li.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <li class={cn('mt-2', className)} {...$restProps}> 9 | <slot /> 10 | </li> 11 | -------------------------------------------------------------------------------- /src/docs/components/markdown/ol.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <ol class={cn('my-6 ml-6 list-decimal', className)} {...$restProps}> 9 | <slot /> 10 | </ol> 11 | -------------------------------------------------------------------------------- /src/docs/components/markdown/p.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | let className: string | undefined | null = undefined; 4 | export { className as class }; 5 | </script> 6 | 7 | <p class={cn('mb-4 leading-7', className)} {...$restProps}> 8 | <slot /> 9 | </p> 10 | -------------------------------------------------------------------------------- /src/docs/components/markdown/ul.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | 4 | let className: string | undefined | null = undefined; 5 | export { className as class }; 6 | </script> 7 | 8 | <ul class={cn(className)} {...$restProps}> 9 | <slot /> 10 | </ul> 11 | 12 | <style lang="postcss"> 13 | ul { 14 | list-style-type: disc; 15 | margin-block: theme('spacing.6'); 16 | margin-left: theme('spacing.6'); 17 | 18 | :global(ul) { 19 | list-style-type: circle; 20 | 21 | margin-block: theme('spacing.2'); 22 | margin-left: theme('spacing.6'); 23 | } 24 | } 25 | </style> 26 | -------------------------------------------------------------------------------- /src/docs/components/nav/index.ts: -------------------------------------------------------------------------------- 1 | export { default as MobileNav } from './mobile-nav.svelte'; 2 | export { default as MobileNavLink } from './mobile-nav-link.svelte'; 3 | export { default as SidebarNav } from './sidebar-nav.svelte'; 4 | -------------------------------------------------------------------------------- /src/docs/components/nav/mobile-nav-link.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { page } from '$app/stores'; 3 | import { cn } from '$docs/utils/index.js'; 4 | import type { Writable } from 'svelte/store'; 5 | import { buttonVariants } from '$docs/components/index.js'; 6 | 7 | export let href: string; 8 | export let open: Writable<boolean>; 9 | 10 | let className: string | undefined | null = undefined; 11 | export { className as class }; 12 | </script> 13 | 14 | <a 15 | {href} 16 | on:click={() => open.set(false)} 17 | class={cn(buttonVariants({ variant: 'ghost' }), 'justify-start', className)} 18 | {...$restProps} 19 | data-active={$page.url.pathname === href} 20 | > 21 | <slot /> 22 | </a> 23 | -------------------------------------------------------------------------------- /src/docs/components/nav/theme-switch/index.ts: -------------------------------------------------------------------------------- 1 | export { default } from './theme-switch.svelte'; 2 | -------------------------------------------------------------------------------- /src/docs/components/nav/theme-switch/options.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { melt } from '$lib/index.js'; 3 | import ThemeIcon from './theme-icon.svelte'; 4 | import { getThemeCtx, themes } from './theme-switch.svelte'; 5 | 6 | const { 7 | elements: { option }, 8 | } = getThemeCtx(); 9 | </script> 10 | 11 | {#each themes as { value, label }} 12 | <button 13 | use:melt={$option({ value, label })} 14 | class="flex items-center gap-2 rounded-md 15 | px-2 py-1 text-neutral-400 transition-colors 16 | data-[highlighted]:bg-neutral-800 data-[highlighted]:text-neutral-300 data-[selected]:!text-white" 17 | > 18 | <ThemeIcon theme={value} /> 19 | <span class="text-sm font-semibold">{label}</span> 20 | </button> 21 | {/each} 22 | -------------------------------------------------------------------------------- /src/docs/components/nav/theme-switch/theme-icon.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { Monitor, Moon, Sun } from '$icons/index.js'; 3 | import type { Theme } from './types.js'; 4 | 5 | export let theme: Theme = 'light'; 6 | export let size: 'sm' | 'md' | 'lg' = 'md'; 7 | 8 | const sizeMap = { 9 | sm: 'h-3 w-3', 10 | md: 'h-5 w-5', 11 | lg: 'h-7 w-7', 12 | }; 13 | 14 | $: component = theme === 'dark' ? Moon : theme === 'light' ? Sun : Monitor; 15 | </script> 16 | 17 | <svelte:component this={component} class={sizeMap[size]} /> 18 | -------------------------------------------------------------------------------- /src/docs/components/nav/theme-switch/types.ts: -------------------------------------------------------------------------------- 1 | export type Theme = 'light' | 'dark' | 'system'; 2 | -------------------------------------------------------------------------------- /src/docs/components/sections/api-reference.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import type { APISchema } from '$docs/types.js'; 3 | import { APITable, APIWrapper } from '$docs/components/index.js'; 4 | 5 | export let schemas: APISchema[]; 6 | </script> 7 | 8 | <APIWrapper> 9 | {#each schemas as schema} 10 | <APITable data={schema} /> 11 | {/each} 12 | </APIWrapper> 13 | -------------------------------------------------------------------------------- /src/docs/components/sections/features.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { CheckCircle } from '$icons/index.js'; 3 | import { h2 as H2 } from '$docs/components/markdown/index.js'; 4 | export let features: string[]; 5 | </script> 6 | 7 | <H2>Features</H2> 8 | <ul class="my-5 list-none"> 9 | {#each features as feature} 10 | <li class="mt-2.5 flex items-center gap-3" {...$restProps}> 11 | <CheckCircle class="size-5 shrink-0 text-green-400" /> 12 | {feature} 13 | </li> 14 | {/each} 15 | </ul> 16 | -------------------------------------------------------------------------------- /src/docs/components/sections/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Features } from './features.svelte'; 2 | export { default as APIReference } from './api-reference.svelte'; 3 | -------------------------------------------------------------------------------- /src/docs/components/table-of-contents/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TOC } from './table-of-contents.svelte'; 2 | 3 | export type TableOfContentsItem = { 4 | title: string; 5 | url: string; 6 | items?: TableOfContentsItem[]; 7 | }; 8 | 9 | export type TableOfContents = { 10 | items: TableOfContentsItem[]; 11 | }; 12 | -------------------------------------------------------------------------------- /src/docs/components/table-of-contents/table-of-contents.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import Tree from './tree.svelte'; 3 | 4 | import { createTableOfContents } from '$lib/index.js'; 5 | 6 | /** 7 | * The filter function is for removing headings from the ToC 8 | * docs page where we have a preview with lots of headings. 9 | */ 10 | const { 11 | elements: { item }, 12 | states: { activeHeadingIdxs, headingsTree }, 13 | } = createTableOfContents({ 14 | selector: '#mdsvex', 15 | exclude: ['h1', 'h4', 'h5', 'h6'], 16 | activeType: 'all-parents', 17 | scrollOffset: 80, 18 | scrollBehaviour: 'smooth', 19 | headingFilterFn: (heading) => 20 | heading.parentElement !== null && 21 | heading.parentElement.id !== 'toc-builder-preview' && 22 | !heading.parentElement.hasAttribute('data-melt-accordion-item'), 23 | }); 24 | </script> 25 | 26 | <div class="space-y-2"> 27 | <p class="font-medium">On This Page</p> 28 | <nav> 29 | <Tree tree={$headingsTree} activeHeadingIdxs={$activeHeadingIdxs} {item} /> 30 | </nav> 31 | </div> 32 | -------------------------------------------------------------------------------- /src/docs/components/table-of-contents/tree.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import type { TableOfContentsItem, TableOfContentsElements } from '$lib/index.js'; 3 | 4 | export let tree: TableOfContentsItem[] = []; 5 | export let activeHeadingIdxs: number[]; 6 | export let item: TableOfContentsElements['item']; 7 | export let level = 1; 8 | </script> 9 | 10 | <ul class="m-0 list-none {level !== 1 ? 'pl-4' : ''}"> 11 | {#if tree && tree.length} 12 | {#each tree as heading, i (i)} 13 | {@const active = activeHeadingIdxs.includes(heading.index)} 14 | <li class="mt-0 pt-2"> 15 | <a 16 | href="#{heading.id}" 17 | {...$item(heading.id)} 18 | use:item 19 | class="inline-block no-underline transition-colors hover:text-magnum-400 {active 20 | ? 'text-neutral-100' 21 | : 'text-neutral-500 dark:text-neutral-400'}" 22 | > 23 | {heading.title} 24 | </a> 25 | {#if heading.children && heading.children.length} 26 | <svelte:self tree={heading.children} level={level + 1} {activeHeadingIdxs} {item} /> 27 | {/if} 28 | </li> 29 | {/each} 30 | {/if} 31 | </ul> 32 | -------------------------------------------------------------------------------- /src/docs/components/tables/api-table-heading.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { h4 as H4 } from '$docs/components/markdown/index.js'; 3 | import { InfoPopover } from '$docs/components/index.js'; 4 | </script> 5 | 6 | <div class="mt-2 flex items-center gap-1.5"> 7 | <H4 class="mt-0"> 8 | <slot /> 9 | </H4> 10 | {#if $slots.info} 11 | <InfoPopover> 12 | <slot name="info" /> 13 | </InfoPopover> 14 | {/if} 15 | </div> 16 | -------------------------------------------------------------------------------- /src/docs/components/tables/api-wrapper.svelte: -------------------------------------------------------------------------------- 1 | <div class="mt-11 flex flex-col gap-16 overflow-x-visible"> 2 | <slot /> 3 | </div> 4 | -------------------------------------------------------------------------------- /src/docs/components/tables/index.ts: -------------------------------------------------------------------------------- 1 | export { default as DataAttrTable } from './data-attr-table.svelte'; 2 | export { default as KbdTable } from './kbd-table.svelte'; 3 | export { default as PropsTable } from './props-table.svelte'; 4 | export { default as APITable } from './api-table.svelte'; 5 | export { default as ReturnedPropsTable } from './returned-props-table.svelte'; 6 | export { default as APIWrapper } from './api-wrapper.svelte'; 7 | export { default as APITableHeading } from './api-table-heading.svelte'; 8 | -------------------------------------------------------------------------------- /src/docs/components/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export { default as TabsList } from './list.svelte'; 2 | export { default as TabsRoot } from './root.svelte'; 3 | export { default as Tabs } from './tabs.svelte'; 4 | -------------------------------------------------------------------------------- /src/docs/components/tabs/list.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { melt } from '$lib/index.js'; 4 | import { getTabsContext } from './root.svelte'; 5 | import Tab from './tab.svelte'; 6 | 7 | const { list, tabs } = getTabsContext(); 8 | 9 | let className = ''; 10 | export { className as class }; 11 | </script> 12 | 13 | <div class={cn('flex items-center gap-3', className)} use:melt={$list}> 14 | {#each $tabs as tab} 15 | <Tab {tab} /> 16 | {/each} 17 | </div> 18 | -------------------------------------------------------------------------------- /src/docs/components/tabs/root.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts" context="module"> 2 | type CreateTabs = ReturnType<typeof createTabs>; 3 | type Elements = CreateTabs['elements']; 4 | 5 | type TabsContext = Pick<Elements, 'content' | 'list' | 'trigger'> & { 6 | tabs: Writable<string[]>; 7 | }; 8 | 9 | const setTabsContext = (context: TabsContext) => { 10 | setContext('tabs', context); 11 | }; 12 | 13 | export const getTabsContext = () => getContext<TabsContext>('tabs'); 14 | </script> 15 | 16 | <script lang="ts"> 17 | import { createTabs, melt } from '$lib/index.js'; 18 | import { getContext, setContext } from 'svelte'; 19 | import { writable, type Writable } from 'svelte/store'; 20 | 21 | export let tabs: string[] = []; 22 | const value = writable(tabs[0]); 23 | 24 | const { 25 | elements: { root, content, list, trigger }, 26 | } = createTabs({ 27 | value, 28 | }); 29 | 30 | $: value.set(tabs[0]); 31 | 32 | const tabsStore = writable(tabs); 33 | $: tabsStore.update(() => tabs); 34 | 35 | setTabsContext({ content, list, trigger, tabs: tabsStore }); 36 | </script> 37 | 38 | <div use:melt={$root}> 39 | <slot tab={$value} /> 40 | </div> 41 | -------------------------------------------------------------------------------- /src/docs/components/tabs/tab.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { getTabsContext } from '$docs/components/tabs/root.svelte'; 3 | import { Npm, Yarn, Pnpm } from '$icons/index.js'; 4 | import { melt } from '$lib/index.js'; 5 | 6 | export let tab: string; 7 | 8 | const { trigger } = getTabsContext(); 9 | </script> 10 | 11 | <button 12 | use:melt={$trigger(tab)} 13 | class="rounded-lg border border-transparent bg-neutral-800 px-3 py-2 text-neutral-400 transition 14 | hover:opacity-100 focus-visible:!border-magnum-400 focus-visible:!text-magnum-400 focus-visible:!ring-0 15 | data-[state=active]:border-magnum-700 data-[state=active]:py-2 data-[state=active]:text-magnum-500 data-[state=active]:opacity-100 dark:data-[state=active]:text-magnum-600" 16 | > 17 | <div class="flex items-center gap-2 px-1"> 18 | {#if tab === 'npm'} 19 | <Npm class="size-4" /> 20 | {:else if tab === 'yarn'} 21 | <Yarn class="size-4" /> 22 | {:else if tab === 'pnpm'} 23 | <Pnpm class="size-4" /> 24 | {/if} 25 | <span class="font-mono text-sm font-semibold">{tab}</span> 26 | </div> 27 | </button> 28 | -------------------------------------------------------------------------------- /src/docs/components/tabs/tabs.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import List from './list.svelte'; 3 | import Root from './root.svelte'; 4 | 5 | export let tabs: string[] = []; 6 | </script> 7 | 8 | <Root {tabs} let:tab> 9 | <List /> 10 | <slot {tab} /> 11 | </Root> 12 | -------------------------------------------------------------------------------- /src/docs/components/tailwind-indicator.svelte: -------------------------------------------------------------------------------- 1 | <!-- Dev mode only tailwind indicator help with making things more responsive --> 2 | 3 | <div 4 | class="fixed bottom-1 left-1 z-50 flex h-6 w-6 items-center justify-center rounded-full bg-neutral-800 p-3 font-mono text-xs text-white" 5 | > 6 | <div class="block sm:hidden">xs</div> 7 | <div class="hidden sm:block md:hidden lg:hidden xl:hidden 2xl:hidden">sm</div> 8 | <div class="hidden md:block lg:hidden xl:hidden 2xl:hidden">md</div> 9 | <div class="hidden lg:block xl:hidden 2xl:hidden">lg</div> 10 | <div class="hidden xl:block 2xl:hidden">xl</div> 11 | <div class="hidden 2xl:block">2xl</div> 12 | </div> 13 | -------------------------------------------------------------------------------- /src/docs/components/tooltip.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createTooltip, melt } from '$lib/index.js'; 3 | import { fade } from 'svelte/transition'; 4 | 5 | const { 6 | elements: { trigger, content, arrow }, 7 | states: { open }, 8 | } = createTooltip({ 9 | forceVisible: true, 10 | openDelay: 500, 11 | positioning: { 12 | strategy: 'fixed', 13 | }, 14 | }); 15 | 16 | export let text = 'Tooltip text'; 17 | </script> 18 | 19 | <div use:melt={$trigger}> 20 | <slot /> 21 | </div> 22 | 23 | {#if $open} 24 | <div 25 | use:melt={$content} 26 | in:fade={{ duration: 150 }} 27 | class="z-50 rounded-md bg-neutral-700 px-2 py-1 text-sm text-neutral-50 shadow-sm" 28 | > 29 | <div use:melt={$arrow} /> 30 | {text} 31 | </div> 32 | {/if} 33 | 34 | <style lang="postcss"> 35 | [data-melt-tooltip-trigger] { 36 | display: grid; 37 | place-items: center; 38 | } 39 | </style> 40 | -------------------------------------------------------------------------------- /src/docs/components/ui/index.ts: -------------------------------------------------------------------------------- 1 | import { tv } from 'tailwind-variants'; 2 | export { default as Button } from './button.svelte'; 3 | 4 | export const buttonVariants = tv({ 5 | base: 'inline-flex items-center justify-center rounded font-semibold transition disabled:opacity-50 disabled:pointer-events-none active:translate-y-0.5', 6 | variants: { 7 | variant: { 8 | default: 'bg-magnum-700 text-white hover:bg-magnum-700/75 ', 9 | ghost: 10 | 'hover:bg-magnum-600/25 data-[active=true]:border-magnum-600 data-[active=true]:bg-magnum-600/25 hover:text-white border-transparent border', 11 | link: 'underline-offset-4 hover:underline text-primary', 12 | outline: 'border border-magnum-600/60 hover:bg-magnum-600/20 hover:text-white', 13 | faded: 'bg-magnum-900/50 text-white hover:bg-magnum-900', 14 | }, 15 | size: { 16 | default: 'px-5 h-11 py-3 rounded-md', 17 | sm: 'h-9 px-3', 18 | }, 19 | }, 20 | defaultVariants: { 21 | variant: 'default', 22 | size: 'default', 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /src/docs/content/builders/avatar.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Avatar 3 | description: An image element with a fallback for representing the user. 4 | --- 5 | 6 | <script> 7 | import { APIReference } from '$docs/components' 8 | export let schemas 9 | </script> 10 | 11 | ## Anatomy 12 | 13 | - **Image**: The image element that displays the user's profile picture 14 | - **Fallback**: The fallback element that displays while the image loads or if the image fails to 15 | load 16 | 17 | ## API Reference 18 | 19 | <APIReference {schemas} /> 20 | -------------------------------------------------------------------------------- /src/docs/content/builders/collapsible.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Collapsible 3 | description: An interactive component which expands/collapses a panel. 4 | --- 5 | 6 | <script> 7 | import { KbdTable, APIReference, Preview } from '$docs/components' 8 | export let keyboard 9 | export let schemas 10 | export let snippets 11 | export let previews 12 | </script> 13 | 14 | ## Anatomy 15 | 16 | - **Root**: The root container for the collapsible 17 | - **Trigger**: The element that triggers the collapsible to expand/collapse 18 | - **Content**: The element that is revealed when the collapsible is expanded 19 | 20 | ## Componentization 21 | 22 | If you want to create a `Collapsible` component with reactive props, you can use our sync utilities. 23 | 24 | <Preview code={snippets.sync}> 25 | <svelte:component this={previews.sync} /> 26 | </Preview> 27 | 28 | ## API Reference 29 | 30 | <APIReference {schemas} /> 31 | 32 | ## Accessibility 33 | 34 | Adheres to the 35 | [Disclosure WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) 36 | 37 | <KbdTable {keyboard} /> 38 | -------------------------------------------------------------------------------- /src/docs/content/builders/label.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Label 3 | description: A control that adds a label to an input element. 4 | --- 5 | 6 | <script> 7 | import { APIReference } from "$docs/components/index.js" 8 | export let schemas 9 | </script> 10 | 11 | ## Anatomy 12 | 13 | - **Root**: The root container for the label 14 | 15 | ## Usage 16 | 17 | To create a label, use the `createLabel` builder function and apply the root action to the label 18 | element. 19 | 20 | ```svelte 21 | <script lang="ts"> 22 | import { createLabel, melt } from '@melt-ui/svelte' 23 | 24 | const { 25 | elements: { root } 26 | } = createLabel() 27 | </script> 28 | 29 | <label for="name" use:melt={$root}>Name</label> 30 | <input type="text" id="name" /> 31 | ``` 32 | 33 | ## API Reference 34 | 35 | <APIReference {schemas} /> 36 | -------------------------------------------------------------------------------- /src/docs/content/builders/pin-input.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: PIN Input 3 | description: A sequence of one-character alphanumeric inputs. 4 | --- 5 | 6 | <script> 7 | import { APIReference, KbdTable } from '$docs/components' 8 | export let schemas 9 | export let keyboard 10 | </script> 11 | 12 | ## API Reference 13 | 14 | <APIReference {schemas} /> 15 | 16 | ## Accessibility 17 | 18 | <KbdTable {keyboard} /> 19 | -------------------------------------------------------------------------------- /src/docs/content/builders/progress.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Progress 3 | description: 4 | Displays an indicator showing the completion progress of a task, typically displayed as a progress 5 | bar. 6 | --- 7 | 8 | <script> 9 | import { APIReference } from '$docs/components' 10 | export let schemas 11 | </script> 12 | 13 | ## Anatomy 14 | 15 | - **Progress**: The progress component. 16 | 17 | ## Usage 18 | 19 | To create a progress bar component, use the `createProgress` builder function. Follow the anatomy or 20 | the example above to create your progress bar. 21 | 22 | ## API Reference 23 | 24 | <APIReference {schemas} /> 25 | -------------------------------------------------------------------------------- /src/docs/content/builders/radio-group.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Radio Group 3 | description: 4 | A set of checkable buttons — known as radio buttons — where no more than one of the buttons can be 5 | checked at a time. 6 | --- 7 | 8 | <script> 9 | import { APIReference, KbdTable } from '$docs/components' 10 | export let schemas 11 | export let keyboard 12 | </script> 13 | 14 | ## Anatomy 15 | 16 | - **Root**: The root container for the radio group 17 | - **Item**: The individual radio button items 18 | 19 | ## API Reference 20 | 21 | <APIReference {schemas} /> 22 | 23 | ## Accessibility 24 | 25 | Adheres to the 26 | [Radio Group WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/) 27 | 28 | <KbdTable {keyboard} /> 29 | -------------------------------------------------------------------------------- /src/docs/content/builders/separator.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Separator 3 | description: Displays a horizontal or vertical line to separate content. 4 | --- 5 | 6 | <script> 7 | import { APIReference } from '$docs/components' 8 | export let schemas 9 | </script> 10 | 11 | ## Anatomy 12 | 13 | - **Root**: The separator element 14 | 15 | ## API Reference 16 | 17 | <APIReference {schemas} /> 18 | 19 | ## Accessibility 20 | 21 | Adheres to the [Separator WAI-ARIA role](https://www.w3.org/TR/wai-aria-1.2/#separator) 22 | -------------------------------------------------------------------------------- /src/docs/content/builders/table-of-contents.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Table of Contents 3 | description: An organized list of the content on your page. 4 | --- 5 | 6 | <script> 7 | import { APIReference, KbdTable } from '$docs/components' 8 | export let schemas 9 | export let keyboard 10 | </script> 11 | 12 | ## Anatomy 13 | 14 | - **Item**: The anchor item for each content. 15 | 16 | ## API Reference 17 | 18 | <APIReference {schemas} /> 19 | 20 | ## Keyboard Navigation 21 | 22 | <KbdTable {keyboard} /> 23 | -------------------------------------------------------------------------------- /src/docs/content/builders/tabs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tabs 3 | description: 4 | A set of layered sections of content—known as tab panels—that are displayed one at a time. 5 | --- 6 | 7 | <script> 8 | import { APIReference, KbdTable } from '$docs/components' 9 | export let schemas 10 | export let keyboard 11 | </script> 12 | 13 | ## Anatomy 14 | 15 | - **Root**: The root container for the tab component 16 | - **List**: The container for the tab triggers 17 | - **Trigger**: The button(s) that open/close the tab panels 18 | - **Content**: The container for the tab panels 19 | 20 | ## API Reference 21 | 22 | <APIReference {schemas} /> 23 | 24 | ## Accessibility 25 | 26 | Adheres to the [Tabs WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/) 27 | 28 | <KbdTable {keyboard} /> 29 | -------------------------------------------------------------------------------- /src/docs/content/builders/toggle-group.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Toggle Group 3 | description: A set of two-state buttons that can be toggled on or off. 4 | --- 5 | 6 | <script> 7 | import { APIReference, KbdTable } from '$docs/components' 8 | export let schemas 9 | export let keyboard 10 | </script> 11 | 12 | ## Anatomy 13 | 14 | - **Root**: The toggle group container component 15 | - **Item**: A toggle group item component 16 | 17 | ## API Reference 18 | 19 | <APIReference {schemas} /> 20 | 21 | ## Accessibility 22 | 23 | Adheres to the [Button WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/) 24 | 25 | <KbdTable {keyboard} /> 26 | -------------------------------------------------------------------------------- /src/docs/content/builders/toolbar.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Toolbar 3 | description: 4 | A container for grouping a set of controls, such as buttons, toggle groups or dropdown menus. 5 | --- 6 | 7 | <script> 8 | import { APIReference, KbdTable } from '$docs/components' 9 | export let schemas 10 | export let keyboard 11 | </script> 12 | 13 | ## API Reference 14 | 15 | <APIReference {schemas} /> 16 | 17 | ## Accessibility 18 | 19 | Adheres to the [Toolbar WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/toolbar/) 20 | 21 | <KbdTable {keyboard} /> 22 | -------------------------------------------------------------------------------- /src/docs/content/builders/tree.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Tree View 3 | description: 4 | A hierarchical list of nested items, where each item can have additional children elements. 5 | --- 6 | 7 | <script> 8 | import { KbdTable, APIReference, Preview } from '$docs/components' 9 | export let schemas; 10 | export let keyboard; 11 | </script> 12 | 13 | ## Anatomy 14 | 15 | - **Tree**: The container in which the tree lies. 16 | - **Item**: The individual tree item element. 17 | - **Group**: An element where a subtree is nested. 18 | 19 | ## API Reference 20 | 21 | <APIReference {schemas} /> 22 | 23 | ## Accessibility 24 | 25 | Adheres to the 26 | [Tree View WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/) 27 | 28 | <KbdTable {keyboard} /> 29 | -------------------------------------------------------------------------------- /src/docs/data/builders/label.ts: -------------------------------------------------------------------------------- 1 | import { ATTRS } from '$docs/constants.js'; 2 | import { builderSchema, elementSchema } from '$docs/utils/index.js'; 3 | import { labelEvents } from '$lib/builders/label/events.js'; 4 | import type { BuilderData } from './index.js'; 5 | 6 | const BUILDER_NAME = 'label'; 7 | const builder = builderSchema(BUILDER_NAME, { 8 | title: 'createLabel', 9 | elements: [ 10 | { 11 | name: 'root', 12 | description: 'The builder store used to create the label root.', 13 | }, 14 | ], 15 | }); 16 | 17 | const root = elementSchema('root', { 18 | description: 'The label element', 19 | dataAttributes: [ 20 | { 21 | name: 'data-melt-label', 22 | value: ATTRS.MELT('label'), 23 | }, 24 | ], 25 | events: labelEvents['root'], 26 | }); 27 | 28 | const schemas = [builder, root]; 29 | 30 | const features = [ 31 | 'Supports nested controls', 32 | 'Disables text selection when double clicking the label', 33 | 'Can be used multiple times from a single instance of the builder', 34 | ]; 35 | 36 | export const labelData: BuilderData = { 37 | schemas, 38 | features, 39 | }; 40 | -------------------------------------------------------------------------------- /src/docs/data/long-types/focus-prop.ts: -------------------------------------------------------------------------------- 1 | type FocusTarget = string | HTMLElement | SVGElement | null; 2 | 3 | export type FocusProp = FocusTarget | ((defaultEl?: HTMLElement) => FocusTarget); 4 | -------------------------------------------------------------------------------- /src/docs/data/long-types/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/docs/data/long-types/index.ts -------------------------------------------------------------------------------- /src/docs/info-popover.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { createPopover, melt } from '$lib/index.js'; 4 | import { fade } from 'svelte/transition'; 5 | import { Info } from '$icons/index.js'; 6 | 7 | const { 8 | elements: { trigger, content, arrow }, 9 | states: { open }, 10 | } = createPopover(); 11 | 12 | export let iconClasses = ''; 13 | export let contentClasses = ''; 14 | </script> 15 | 16 | <button use:melt={$trigger} aria-label="More info"> 17 | <Info class={cn('size-4 text-white', iconClasses)} /> 18 | <span class="sr-only">Open popover</span> 19 | </button> 20 | {#if $open} 21 | <div 22 | use:melt={$content} 23 | transition:fade={{ duration: 100 }} 24 | class={cn( 25 | 'mdsvex z-30 max-w-[300px] rounded-md bg-zinc-800 px-4 py-3 shadow-sm shadow-neutral-800', 26 | contentClasses 27 | )} 28 | > 29 | <div use:melt={$arrow} /> 30 | <p class="text-sm leading-5 text-white"> 31 | <slot /> 32 | </p> 33 | </div> 34 | {/if} 35 | 36 | <style lang="postcss"> 37 | div { 38 | @apply focus:ring-0 !important; 39 | } 40 | </style> 41 | -------------------------------------------------------------------------------- /src/docs/previews/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "all", 5 | "printWidth": 80, 6 | "pluginSearchDirs": ["."], 7 | "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], 8 | "overrides": [ 9 | { 10 | "files": "*.svelte", 11 | "options": { 12 | "parser": "svelte" 13 | } 14 | }, 15 | { 16 | "files": "*.md", 17 | "options": { 18 | "parser": "markdown", 19 | "printWidth": 100, 20 | "proseWrap": "always", 21 | "tabWidth": 2, 22 | "useTabs": false, 23 | "semi": false, 24 | "trailingComma": "none", 25 | "bracketSameLine": true 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/docs/previews/calendar/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/checkbox/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createCheckbox, melt } from '$lib/index.js'; 3 | import { Check, Minus } from '$icons/index.js'; 4 | 5 | const { 6 | elements: { root, input }, 7 | helpers: { isChecked, isIndeterminate }, 8 | } = createCheckbox({ 9 | defaultChecked: 'indeterminate', 10 | }); 11 | </script> 12 | 13 | <form> 14 | <div class="flex items-center justify-center"> 15 | <button 16 | use:melt={$root} 17 | class="flex size-7 appearance-none items-center justify-center 18 | rounded-lg bg-white text-magnum-600 shadow hover:opacity-75" 19 | id="checkbox" 20 | > 21 | {#if $isIndeterminate} 22 | <Minus class="size-5" /> 23 | {:else if $isChecked} 24 | <Check class="size-5" /> 25 | {/if} 26 | <input use:melt={$input} /> 27 | </button> 28 | <label class="pl-4 font-medium text-magnum-900" for="checkbox"> 29 | Accept terms and conditions. 30 | </label> 31 | </div> 32 | </form> 33 | -------------------------------------------------------------------------------- /src/docs/previews/collapsible/sync/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import Collapsible from './Collapsible.svelte'; 3 | 4 | let open = false; 5 | let disabled = false; 6 | </script> 7 | 8 | <div class="mb-4 flex justify-center gap-4"> 9 | <button 10 | on:click={() => (open = !open)} 11 | class="rounded-xl bg-white px-4 py-3 12 | font-medium leading-none text-magnum-700 shadow hover:opacity-75" 13 | > 14 | Open prop: {open} 15 | </button> 16 | <button 17 | on:click={() => (disabled = !disabled)} 18 | class="rounded-xl bg-white px-4 py-3 19 | font-medium leading-none text-magnum-700 shadow hover:opacity-75" 20 | > 21 | Disabled prop: {disabled} 22 | </button> 23 | </div> 24 | 25 | <Collapsible bind:open bind:disabled /> 26 | -------------------------------------------------------------------------------- /src/docs/previews/date-field/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/date-field/tut6/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import DateField from './DateField.svelte'; 3 | import { parseDate } from '@internationalized/date'; 4 | 5 | const userBirthday = '1992-10-11'; 6 | const userBirthday2 = undefined; 7 | </script> 8 | 9 | <div> 10 | <DateField defaultValue={parseDate(userBirthday)} /> 11 | <DateField defaultValue={userBirthday2} /> 12 | </div> 13 | 14 | <style lang="postcss"> 15 | div { 16 | @apply flex flex-col gap-6; 17 | } 18 | </style> 19 | -------------------------------------------------------------------------------- /src/docs/previews/date-field/tut9/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { CalendarDateTime } from '@internationalized/date'; 3 | import DateField from './DateField.svelte'; 4 | 5 | const defaultPlaceholder = new CalendarDateTime(2023, 10, 11, 12, 30); 6 | </script> 7 | 8 | <div> 9 | <DateField locale="en-US" {defaultPlaceholder} /> 10 | <DateField locale="de" {defaultPlaceholder} /> 11 | <DateField locale="es" {defaultPlaceholder} /> 12 | <DateField locale="uk" {defaultPlaceholder} /> 13 | </div> 14 | 15 | <style lang="postcss"> 16 | div { 17 | @apply grid grid-cols-2 gap-12; 18 | } 19 | </style> 20 | -------------------------------------------------------------------------------- /src/docs/previews/date-field/zdtPlaceholder/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import DateField from './DateField.svelte'; 3 | import { now, getLocalTimeZone } from '@internationalized/date'; 4 | 5 | const withLocalTimeZone = now(getLocalTimeZone()); 6 | const withLosAngelesTimeZone = now('America/Los_Angeles'); 7 | </script> 8 | 9 | <div class="flex flex-col gap-8"> 10 | <DateField defaultPlaceholder={withLocalTimeZone} /> 11 | <DateField defaultPlaceholder={withLosAngelesTimeZone} /> 12 | </div> 13 | -------------------------------------------------------------------------------- /src/docs/previews/date-picker/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/date-range-field/locales/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import DateRangeField from './DateRangeField.svelte'; 3 | </script> 4 | 5 | <div> 6 | <DateRangeField locale="en-US" /> 7 | <DateRangeField locale="en-UK" /> 8 | <DateRangeField locale="de" /> 9 | <DateRangeField locale="fr" /> 10 | </div> 11 | 12 | <style lang="postcss"> 13 | div { 14 | @apply flex flex-col gap-6; 15 | } 16 | </style> 17 | -------------------------------------------------------------------------------- /src/docs/previews/date-range-field/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/date-range-field/valueAndPh/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { parseDateTime } from '@internationalized/date'; 3 | import DateRangeField from './DateRangeField.svelte'; 4 | 5 | const availability = { 6 | start: parseDateTime('2021-10-11T00:00:00'), 7 | end: parseDateTime('2021-10-15T00:00:00'), 8 | }; 9 | </script> 10 | 11 | <div> 12 | <DateRangeField /> 13 | <DateRangeField defaultValue={availability} /> 14 | </div> 15 | 16 | <style lang="postcss"> 17 | div { 18 | @apply flex flex-col gap-6; 19 | } 20 | </style> 21 | -------------------------------------------------------------------------------- /src/docs/previews/date-range-picker/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/label/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createLabel, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root }, 6 | } = createLabel(); 7 | </script> 8 | 9 | <form> 10 | <div class="flex flex-col items-start justify-center"> 11 | <label 12 | use:melt={$root} 13 | for="email" 14 | class="mb-0.5 font-medium text-magnum-900" 15 | data-melt-part="root" 16 | > 17 | <span>Email</span> 18 | </label> 19 | <input 20 | type="text" 21 | id="email" 22 | class="h-10 w-[240px] rounded-md bg-white px-3 py-2 text-magnum-700" 23 | placeholder="vanilla@melt-ui.com" 24 | /> 25 | </div> 26 | </form> 27 | -------------------------------------------------------------------------------- /src/docs/previews/pin-input/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createPinInput, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, input }, 6 | } = createPinInput({ 7 | defaultValue: ['1', '2', '3', '4', '5'], 8 | }); 9 | </script> 10 | 11 | <div use:melt={$root} class="flex items-center gap-2"> 12 | {#each Array.from({ length: 5 }) as _} 13 | <input 14 | class="size-12 rounded-md bg-white text-center text-lg text-magnum-900 shadow-sm" 15 | use:melt={$input()} 16 | /> 17 | {/each} 18 | </div> 19 | -------------------------------------------------------------------------------- /src/docs/previews/popover/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import Popover from './Popover.svelte'; 3 | </script> 4 | 5 | <Popover /> 6 | -------------------------------------------------------------------------------- /src/docs/previews/progress/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createProgress, melt } from '$lib/index.js'; 3 | import { writable } from 'svelte/store'; 4 | 5 | const value = writable(30); 6 | 7 | const { 8 | elements: { root }, 9 | options: { max }, 10 | } = createProgress({ 11 | value, 12 | max: 100, 13 | }); 14 | 15 | const sleep = (ms: number) => 16 | new Promise((resolve) => setTimeout(resolve, ms)); 17 | sleep(1000).then(() => { 18 | value.set(75); 19 | }); 20 | </script> 21 | 22 | <div 23 | use:melt={$root} 24 | class="relative h-6 w-[300px] overflow-hidden rounded-[99999px] bg-black/40" 25 | > 26 | <div 27 | class="h-full w-full bg-[white] transition-transform duration-[660ms] 28 | ease-[cubic-bezier(0.65,0,0.35,1)]" 29 | style={`transform: translateX(-${ 30 | 100 - (100 * ($value ?? 0)) / ($max ?? 1) 31 | }%)`} 32 | /> 33 | </div> 34 | -------------------------------------------------------------------------------- /src/docs/previews/range-calendar/main/tailwind/locales.ts: -------------------------------------------------------------------------------- 1 | // We support any locale that is supported by the `Int.DateTimeFormatter` constructor, 2 | // this is just a minimal list of locales used to generate the preview. 3 | export const localeOptions = { 4 | ar: 'Arabic', 5 | de: 'German', 6 | 'en-UK': 'English (UK)', 7 | 'en-US': 'English (US)', 8 | 'es-ES': 'Spanish (ES)', 9 | 'es-MX': 'Spanish (MX)', 10 | fr: 'French', 11 | it: 'Italian', 12 | ja: 'Japanese', 13 | ko: 'Korean', 14 | nl: 'Dutch', 15 | pt: 'Portuguese', 16 | ru: 'Russian', 17 | sv: 'Swedish', 18 | tr: 'Turkish', 19 | uk: 'Ukrainian', 20 | vi: 'Vietnamese', 21 | zh: 'Chinese', 22 | }; 23 | -------------------------------------------------------------------------------- /src/docs/previews/scroll-area/always/tailwind/flavors.ts: -------------------------------------------------------------------------------- 1 | export const flavors = [ 2 | 'Vanilla', 3 | 'Chocolate', 4 | 'Strawberry', 5 | 'Mint Chocolate Chip', 6 | 'Cookies and Cream', 7 | 'Rocky Road', 8 | 'Pistachio', 9 | 'Neapolitan', 10 | 'Butter Pecan', 11 | 'Salted Caramel', 12 | 'Coffee', 13 | 'Mango', 14 | 'Raspberry Ripple', 15 | 'Lemon Sorbet', 16 | 'Green Tea', 17 | 'Coconut', 18 | 'Black Cherry', 19 | 'Banana', 20 | 'Almond Fudge', 21 | 'Cinnamon', 22 | 'Blueberry Cheesecake', 23 | 'Tiramisu', 24 | 'Red Velvet', 25 | 'Matcha', 26 | 'Peanut Butter Cup', 27 | 'Cookie Dough', 28 | 'Rum Raisin', 29 | 'Birthday Cake', 30 | 'Lychee', 31 | 'Honey Lavender', 32 | ]; 33 | -------------------------------------------------------------------------------- /src/docs/previews/scroll-area/auto/tailwind/flavors.ts: -------------------------------------------------------------------------------- 1 | export const flavors = [ 2 | 'Vanilla', 3 | 'Chocolate', 4 | 'Strawberry', 5 | 'Mint Chocolate Chip', 6 | 'Cookies and Cream', 7 | 'Rocky Road', 8 | 'Pistachio', 9 | 'Neapolitan', 10 | 'Butter Pecan', 11 | 'Salted Caramel', 12 | 'Coffee', 13 | 'Mango', 14 | 'Raspberry Ripple', 15 | 'Lemon Sorbet', 16 | 'Green Tea', 17 | 'Coconut', 18 | 'Black Cherry', 19 | 'Banana', 20 | 'Almond Fudge', 21 | 'Cinnamon', 22 | 'Blueberry Cheesecake', 23 | 'Tiramisu', 24 | 'Red Velvet', 25 | 'Matcha', 26 | 'Peanut Butter Cup', 27 | 'Cookie Dough', 28 | 'Rum Raisin', 29 | 'Birthday Cake', 30 | 'Lychee', 31 | 'Honey Lavender', 32 | ]; 33 | -------------------------------------------------------------------------------- /src/docs/previews/scroll-area/hover/tailwind/flavors.ts: -------------------------------------------------------------------------------- 1 | export const flavors = [ 2 | 'Vanilla', 3 | 'Chocolate', 4 | 'Strawberry', 5 | 'Mint Chocolate Chip', 6 | 'Cookies and Cream', 7 | 'Rocky Road', 8 | 'Pistachio', 9 | 'Neapolitan', 10 | 'Butter Pecan', 11 | 'Salted Caramel', 12 | 'Coffee', 13 | 'Mango', 14 | 'Raspberry Ripple', 15 | 'Lemon Sorbet', 16 | 'Green Tea', 17 | 'Coconut', 18 | 'Black Cherry', 19 | 'Banana', 20 | 'Almond Fudge', 21 | 'Cinnamon', 22 | 'Blueberry Cheesecake', 23 | 'Tiramisu', 24 | 'Red Velvet', 25 | 'Matcha', 26 | 'Peanut Butter Cup', 27 | 'Cookie Dough', 28 | 'Rum Raisin', 29 | 'Birthday Cake', 30 | 'Lychee', 31 | 'Honey Lavender', 32 | ]; 33 | -------------------------------------------------------------------------------- /src/docs/previews/scroll-area/main/tailwind/flavors.ts: -------------------------------------------------------------------------------- 1 | export const flavors = [ 2 | 'Vanilla', 3 | 'Chocolate', 4 | 'Strawberry', 5 | 'Mint Chocolate Chip', 6 | 'Cookies and Cream', 7 | 'Rocky Road', 8 | 'Pistachio', 9 | 'Neapolitan', 10 | 'Butter Pecan', 11 | 'Salted Caramel', 12 | 'Coffee', 13 | 'Mango', 14 | 'Raspberry Ripple', 15 | 'Lemon Sorbet', 16 | 'Green Tea', 17 | 'Coconut', 18 | 'Black Cherry', 19 | 'Banana', 20 | 'Almond Fudge', 21 | 'Cinnamon', 22 | 'Blueberry Cheesecake', 23 | 'Tiramisu', 24 | 'Red Velvet', 25 | 'Matcha', 26 | 'Peanut Butter Cup', 27 | 'Cookie Dough', 28 | 'Rum Raisin', 29 | 'Birthday Cake', 30 | 'Lychee', 31 | 'Honey Lavender', 32 | ]; 33 | -------------------------------------------------------------------------------- /src/docs/previews/scroll-area/scroll/tailwind/flavors.ts: -------------------------------------------------------------------------------- 1 | export const flavors = [ 2 | 'Vanilla', 3 | 'Chocolate', 4 | 'Strawberry', 5 | 'Mint Chocolate Chip', 6 | 'Cookies and Cream', 7 | 'Rocky Road', 8 | 'Pistachio', 9 | 'Neapolitan', 10 | 'Butter Pecan', 11 | 'Salted Caramel', 12 | 'Coffee', 13 | 'Mango', 14 | 'Raspberry Ripple', 15 | 'Lemon Sorbet', 16 | 'Green Tea', 17 | 'Coconut', 18 | 'Black Cherry', 19 | 'Banana', 20 | 'Almond Fudge', 21 | 'Cinnamon', 22 | 'Blueberry Cheesecake', 23 | 'Tiramisu', 24 | 'Red Velvet', 25 | 'Matcha', 26 | 'Peanut Butter Cup', 27 | 'Cookie Dough', 28 | 'Rum Raisin', 29 | 'Birthday Cake', 30 | 'Lychee', 31 | 'Honey Lavender', 32 | ]; 33 | -------------------------------------------------------------------------------- /src/docs/previews/separator/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { 3 | createSeparator, 4 | melt, 5 | type CreateSeparatorProps, 6 | } from '$lib/index.js'; 7 | 8 | export let orientation: CreateSeparatorProps['orientation'] = 'vertical'; 9 | 10 | const { 11 | elements: { root: vertical }, 12 | } = createSeparator({ 13 | orientation, 14 | }); 15 | 16 | const { 17 | elements: { root: horizontal }, 18 | } = createSeparator({ 19 | orientation: 'horizontal', 20 | decorative: true, 21 | }); 22 | 23 | const icecreams = ['Caramel', 'Vanilla', 'Napolitan']; 24 | </script> 25 | 26 | <div class="text-magnum-900"> 27 | <h2 class="font-bold">Melt UI</h2> 28 | <p>Flavors for everyone</p> 29 | <div use:melt={$horizontal} class="my-3.5 h-[1px] w-full bg-magnum-900" /> 30 | <div class="flex items-center space-x-3.5"> 31 | {#each icecreams as icecream, i} 32 | <p>{icecream}</p> 33 | {#if i !== icecreams.length - 1} 34 | <div use:melt={$vertical} class="h-4 w-[1px] bg-magnum-900" /> 35 | {/if} 36 | {/each} 37 | </div> 38 | </div> 39 | -------------------------------------------------------------------------------- /src/docs/previews/slider/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | defaultValue: [30], 8 | min: 0, 9 | max: 100, 10 | step: 1, 11 | }); 12 | </script> 13 | 14 | <span use:melt={$root} class="relative flex h-[20px] w-[200px] items-center"> 15 | <span class="h-[3px] w-full bg-black/40"> 16 | <span use:melt={$range} class="h-[3px] bg-white" /> 17 | </span> 18 | 19 | <span 20 | use:melt={$thumbs[0]} 21 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 22 | /> 23 | </span> 24 | -------------------------------------------------------------------------------- /src/docs/previews/slider/multiple/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { writable } from 'svelte/store'; 3 | import Slider from './slider.svelte'; 4 | 5 | const value1 = writable([30, 40, 50, 60, 70]); 6 | const value2 = writable([30, 40, 50, 60, 70]); 7 | </script> 8 | 9 | <div class="flex flex-col gap-8"> 10 | <div class="flex flex-col gap-4 text-center"> 11 | <code>autoSort: false; value: [{$value1}]</code> 12 | <Slider value={value1} autoSort={false} /> 13 | </div> 14 | <div class="flex flex-col gap-4 text-center"> 15 | <code>autoSort: true; value: [{$value2}]</code> 16 | <Slider value={value2} /> 17 | </div> 18 | </div> 19 | -------------------------------------------------------------------------------- /src/docs/previews/slider/multiple/tailwind/slider.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | import type { Writable } from 'svelte/store'; 4 | 5 | export let value: Writable<number[]>; 6 | export let autoSort = true; 7 | 8 | const { 9 | elements: { root, range, thumbs }, 10 | } = createSlider({ 11 | value, 12 | max: 100, 13 | autoSort, 14 | }); 15 | </script> 16 | 17 | <span use:melt={$root} class="relative flex h-[20px] items-center"> 18 | <span class="h-[3px] w-full bg-white"> 19 | <span use:melt={$range} class="h-[3px] bg-white" /> 20 | </span> 21 | 22 | {#each $thumbs as thumb, i} 23 | <span 24 | use:melt={thumb} 25 | class="inline-flex h-5 w-5 cursor-grab items-center justify-center rounded-full bg-white font-semibold text-black focus:ring-4 focus:!ring-black/40" 26 | > 27 | {i} 28 | </span> 29 | {/each} 30 | </span> 31 | -------------------------------------------------------------------------------- /src/docs/previews/slider/range/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | defaultValue: [20, 80], 8 | max: 100, 9 | }); 10 | </script> 11 | 12 | <span use:melt={$root} class="relative flex h-[20px] w-[200px] items-center"> 13 | <span class="h-[3px] w-full bg-black/40"> 14 | <span use:melt={$range} class="h-[3px] bg-white" /> 15 | </span> 16 | 17 | {#each $thumbs as thumb} 18 | <span 19 | use:melt={thumb} 20 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 21 | /> 22 | {/each} 23 | </span> 24 | -------------------------------------------------------------------------------- /src/docs/previews/slider/rtl_horizontal/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | dir: 'rtl', 8 | defaultValue: [30], 9 | max: 100, 10 | }); 11 | </script> 12 | 13 | <span use:melt={$root} class="relative flex h-[20px] w-[200px] items-center"> 14 | <span class="h-[3px] w-full bg-black/40"> 15 | <span use:melt={$range} class="h-[3px] bg-white" /> 16 | </span> 17 | 18 | <span 19 | use:melt={$thumbs[0]} 20 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 21 | /> 22 | </span> 23 | -------------------------------------------------------------------------------- /src/docs/previews/slider/rtl_vertical/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | dir: 'rtl', 8 | orientation: 'vertical', 9 | defaultValue: [30], 10 | max: 100, 11 | }); 12 | </script> 13 | 14 | <span 15 | use:melt={$root} 16 | class="relative flex h-[200px] w-[20px] flex-col items-center" 17 | > 18 | <span class="h-full w-[3px] bg-black/40"> 19 | <span use:melt={$range} class="w-[3px] bg-white" /> 20 | </span> 21 | 22 | <span 23 | use:melt={$thumbs[0]} 24 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 25 | /> 26 | </span> 27 | -------------------------------------------------------------------------------- /src/docs/previews/slider/shadow/tailwind/Slider.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | export let componentRoot; 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | defaultValue: [30], 8 | min: 0, 9 | max: 100, 10 | step: 1, 11 | rootElement: componentRoot, 12 | }); 13 | </script> 14 | 15 | <span use:melt={$root} class="root"> 16 | <span class="range-wrapper"> 17 | <span use:melt={$range} class="range" /> 18 | </span> 19 | 20 | <span use:melt={$thumbs[0]} class="thumb" /> 21 | </span> 22 | -------------------------------------------------------------------------------- /src/docs/previews/slider/ticks/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs, ticks }, 6 | } = createSlider({ 7 | defaultValue: [5], 8 | min: 0, 9 | step: 1, 10 | max: 10, 11 | }); 12 | </script> 13 | 14 | <span use:melt={$root} class="relative flex h-[20px] w-[200px] items-center"> 15 | <span class="h-[3px] w-full bg-black/40"> 16 | <span use:melt={$range} class="h-[3px] bg-white" /> 17 | </span> 18 | 19 | {#each $ticks as tick} 20 | <span 21 | use:melt={tick} 22 | class="h-[3px] w-[3px] rounded-full bg-white/50 data-[bounded]:bg-magnum-800/75" 23 | /> 24 | {/each} 25 | 26 | <span 27 | use:melt={$thumbs[0]} 28 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 29 | /> 30 | </span> 31 | -------------------------------------------------------------------------------- /src/docs/previews/slider/vertical/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, range, thumbs }, 6 | } = createSlider({ 7 | defaultValue: [30], 8 | max: 100, 9 | orientation: 'vertical', 10 | }); 11 | </script> 12 | 13 | <span 14 | use:melt={$root} 15 | class="relative flex h-[200px] w-[3px] flex-col items-center" 16 | > 17 | <span class="h-[200px] w-full bg-black/40"> 18 | <span use:melt={$range} class="w-full bg-white" /> 19 | </span> 20 | 21 | <span 22 | use:melt={$thumbs[0]} 23 | class="h-5 w-5 rounded-full bg-white focus:ring-4 focus:!ring-black/40" 24 | /> 25 | </span> 26 | -------------------------------------------------------------------------------- /src/docs/previews/toggle/main/tailwind/index.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createToggle, melt } from '$lib/index.js'; 3 | import { Italic } from '$icons/index.js'; 4 | 5 | const { 6 | elements: { root }, 7 | } = createToggle(); 8 | </script> 9 | 10 | <button 11 | use:melt={$root} 12 | aria-label="Toggle italic" 13 | class="grid h-9 w-9 place-items-center items-center justify-center rounded-md 14 | bg-white text-base leading-4 text-magnum-800 shadow-lg hover:bg-magnum-100 15 | data-[disabled]:cursor-not-allowed data-[state=on]:bg-magnum-200 16 | data-[state=on]:text-magnum-900" 17 | > 18 | <Italic class="size-4" /> 19 | </button> 20 | -------------------------------------------------------------------------------- /src/docs/previews/tree/main/tailwind/icons/JS.svelte: -------------------------------------------------------------------------------- 1 | <svg 2 | class="h-4 w-4" 3 | xmlns="http://www.w3.org/2000/svg" 4 | viewBox="0 0 32 32" 5 | {...$props} 6 | ><path fill="#f5de19" d="M2 2h28v28H2z" /><path 7 | d="M20.809 23.875a2.866 2.866 0 0 0 2.6 1.6c1.09 0 1.787-.545 1.787-1.3c0-.9-.716-1.222-1.916-1.747l-.658-.282c-1.9-.809-3.16-1.822-3.16-3.964c0-1.973 1.5-3.476 3.853-3.476a3.889 3.889 0 0 1 3.742 2.107L25 18.128A1.789 1.789 0 0 0 23.311 17a1.145 1.145 0 0 0-1.259 1.128c0 .789.489 1.109 1.618 1.6l.658.282c2.236.959 3.5 1.936 3.5 4.133c0 2.369-1.861 3.667-4.36 3.667a5.055 5.055 0 0 1-4.795-2.691Zm-9.295.228c.413.733.789 1.353 1.693 1.353c.864 0 1.41-.338 1.41-1.653v-8.947h2.631v8.982c0 2.724-1.6 3.964-3.929 3.964a4.085 4.085 0 0 1-3.947-2.4Z" 8 | /></svg 9 | > 10 | -------------------------------------------------------------------------------- /src/docs/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './style.js'; 2 | export * from './content.js'; 3 | export * from './transition.js'; 4 | export * from './tree.js'; 5 | export * from './string.js'; 6 | export * from './preview.js'; 7 | -------------------------------------------------------------------------------- /src/docs/utils/string.ts: -------------------------------------------------------------------------------- 1 | export function formatStr(s: string) { 2 | // Capitalize and remove dashes 3 | return s 4 | .split('-') 5 | .map((word) => word[0].toUpperCase() + word.slice(1)) 6 | .join(' '); 7 | } 8 | 9 | export function toKebabCase(str: string) { 10 | return str.split(' ').join('-').toLowerCase(); 11 | } 12 | -------------------------------------------------------------------------------- /src/docs/utils/style.ts: -------------------------------------------------------------------------------- 1 | import { clsx, type ClassValue } from 'clsx'; 2 | import { twMerge } from 'tailwind-merge'; 3 | 4 | /** 5 | * Appends strings of classes. If non-truthy values are passed, they are ignored. 6 | * Uses tailwind-merge to merge tailwind classes. 7 | */ 8 | export function cn(...inputs: ClassValue[]): string { 9 | return twMerge(clsx(inputs)); 10 | } 11 | -------------------------------------------------------------------------------- /src/json/contributors.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /src/lib/builders/accordion/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const accordionEvents = { 4 | trigger: ['keydown', 'click'] as const, 5 | }; 6 | 7 | export type AccordionEvents = GroupedEvents<typeof accordionEvents>; 8 | export type AccordionComponentEvents = MeltComponentEvents<AccordionEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/accordion/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/avatar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/calendar/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const calendarEvents = { 4 | calendar: ['keydown'] as const, 5 | prevButton: ['click'] as const, 6 | nextButton: ['click'] as const, 7 | cell: ['click'] as const, 8 | }; 9 | 10 | export type CalendarEvents = GroupedEvents<typeof calendarEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/calendar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/checkbox/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const checkboxEvents = { 4 | root: ['keydown', 'click'] as const, 5 | }; 6 | 7 | export type CheckboxEvents = GroupedEvents<typeof checkboxEvents>; 8 | export type CheckboxComponentEvents = MeltComponentEvents<CheckboxEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/collapsible/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const collapsibleEvents = { 4 | trigger: ['click'] as const, 5 | }; 6 | 7 | export type CollapsibleEvents = GroupedEvents<typeof collapsibleEvents>; 8 | export type CollapsibleComponentEvents = MeltComponentEvents<CollapsibleEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/collapsible/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/combobox/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | import { listboxEvents } from '../listbox/events.js'; 3 | 4 | export const comboboxEvents = { 5 | ...listboxEvents, 6 | input: ['click', 'keydown', 'input'] as const, 7 | }; 8 | 9 | export type ComboboxEvents = GroupedEvents<typeof comboboxEvents>; 10 | export type ComboboxComponentEvents = MeltComponentEvents<ComboboxEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/combobox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/context-menu/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | import { menuEvents } from '../menu/events.js'; 3 | 4 | export const contextMenuEvents = { 5 | ...menuEvents, 6 | menu: ['keydown'] as const, 7 | trigger: ['contextmenu', 'pointerdown', 'pointermove', 'pointercancel', 'pointerup'] as const, 8 | }; 9 | 10 | export type ContextMenuEvents = GroupedEvents<typeof contextMenuEvents>; 11 | export type ContextMenuComponentEvents = MeltComponentEvents<ContextMenuEvents>; 12 | -------------------------------------------------------------------------------- /src/lib/builders/context-menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/date-field/_internal/parts.ts: -------------------------------------------------------------------------------- 1 | export const DATE_SEGMENT_PARTS = ['day', 'month', 'year'] as const; 2 | export const TIME_SEGMENT_PARTS = ['hour', 'minute', 'second', 'dayPeriod'] as const; 3 | export const NON_EDITABLE_SEGMENT_PARTS = ['literal', 'timeZoneName'] as const; 4 | export const EDITABLE_SEGMENT_PARTS = [...DATE_SEGMENT_PARTS, ...TIME_SEGMENT_PARTS] as const; 5 | export const ALL_SEGMENT_PARTS = [ 6 | ...EDITABLE_SEGMENT_PARTS, 7 | ...NON_EDITABLE_SEGMENT_PARTS, 8 | ] as const; 9 | export const ALL_EXCEPT_LITERAL_PARTS = ALL_SEGMENT_PARTS.filter((part) => part !== 'literal'); 10 | -------------------------------------------------------------------------------- /src/lib/builders/date-field/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const dateFieldEvents = { 4 | segment: ['keydown', 'focusout', 'click'] as const, 5 | }; 6 | 7 | export type DateFieldEvents = GroupedEvents<typeof dateFieldEvents>; 8 | -------------------------------------------------------------------------------- /src/lib/builders/date-field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/date-picker/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | import { dateFieldEvents } from '../date-field/events.js'; 3 | import { popoverEvents } from '../popover/events.js'; 4 | import { calendarEvents } from '../calendar/events.js'; 5 | 6 | export const datePickerEvents = { 7 | ...dateFieldEvents, 8 | ...popoverEvents, 9 | ...calendarEvents, 10 | }; 11 | 12 | export type DatePickerEvents = GroupedEvents<typeof datePickerEvents>; 13 | -------------------------------------------------------------------------------- /src/lib/builders/date-picker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/date-range-field/_internal/helpers.ts: -------------------------------------------------------------------------------- 1 | import { isBrowser } from '$lib/internal/helpers/index.js'; 2 | 3 | export function removeDescriptionElement(id: string) { 4 | if (!isBrowser) return; 5 | const el = document.getElementById(id); 6 | if (!el) return; 7 | document.body.removeChild(el); 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/builders/date-range-field/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const dateRangeFieldEvents = { 4 | startSegment: ['keydown', 'focusout', 'click'] as const, 5 | endSegment: ['keydown', 'focusout', 'click'] as const, 6 | }; 7 | 8 | export type DateRangeFieldEvents = GroupedEvents<typeof dateRangeFieldEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/date-range-field/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/date-range-picker/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | import { dateRangeFieldEvents } from '../date-range-field/events.js'; 3 | import { popoverEvents } from '../popover/events.js'; 4 | import { rangeCalendarEvents } from '../range-calendar/events.js'; 5 | 6 | export const dateRangePickerEvents = { 7 | ...dateRangeFieldEvents, 8 | ...popoverEvents, 9 | ...rangeCalendarEvents, 10 | }; 11 | 12 | export type DateRangePickerEvents = GroupedEvents<typeof dateRangePickerEvents>; 13 | -------------------------------------------------------------------------------- /src/lib/builders/date-range-picker/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/dialog/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | export const dialogEvents = { 3 | trigger: ['click', 'keydown'] as const, 4 | close: ['click', 'keydown'] as const, 5 | }; 6 | 7 | export type DialogEvents = GroupedEvents<typeof dialogEvents>; 8 | export type DialogComponentEvents = MeltComponentEvents<DialogEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/dialog/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/dropdown-menu/events.ts: -------------------------------------------------------------------------------- 1 | import type { MeltComponentEvents } from '$lib/internal/types.js'; 2 | import { menuEvents, type MenuEvents } from '../menu/events.js'; 3 | 4 | export const dropdownMenuEvents = menuEvents; 5 | export type DropdownMenuEvents = MenuEvents; 6 | export type DropdownMenuComponentEvents = MeltComponentEvents<DropdownMenuEvents>; 7 | -------------------------------------------------------------------------------- /src/lib/builders/dropdown-menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/hidden-input/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/hidden-input/types.ts: -------------------------------------------------------------------------------- 1 | import type { MaybeReadable } from '$lib/internal/types.js'; 2 | import type { HTMLInputAttributes } from 'svelte/elements'; 3 | 4 | export type CreateHiddenInputProps = { 5 | value: MaybeReadable<string>; 6 | disabled?: MaybeReadable<boolean>; 7 | name?: MaybeReadable<string | undefined> | undefined; 8 | required?: MaybeReadable<boolean>; 9 | prefix?: string; 10 | type?: MaybeReadable<HTMLInputAttributes['type']>; 11 | checked?: MaybeReadable<boolean | undefined | 'indeterminate'>; 12 | }; 13 | -------------------------------------------------------------------------------- /src/lib/builders/label/create.ts: -------------------------------------------------------------------------------- 1 | import { addMeltEventListener, makeElement } from '$lib/internal/helpers/index.js'; 2 | import type { MeltActionReturn } from '$lib/internal/types.js'; 3 | import type { LabelEvents } from './events.js'; 4 | 5 | export function createLabel() { 6 | const root = makeElement('label', { 7 | action: (node: HTMLElement): MeltActionReturn<LabelEvents['root']> => { 8 | const mouseDown = addMeltEventListener(node, 'mousedown', (e) => { 9 | if (!e.defaultPrevented && e.detail > 1) { 10 | e.preventDefault(); 11 | } 12 | }); 13 | 14 | return { 15 | destroy: mouseDown, 16 | }; 17 | }, 18 | }); 19 | 20 | return { 21 | elements: { 22 | root, 23 | }, 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/builders/label/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const labelEvents = { 4 | root: ['mousedown'] as const, 5 | }; 6 | 7 | export type LabelEvents = GroupedEvents<typeof labelEvents>; 8 | export type LabelComponentEvents = MeltComponentEvents<LabelEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/label/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/label/types.ts: -------------------------------------------------------------------------------- 1 | import type { BuilderReturn } from '$lib/internal/types.js'; 2 | import type { createLabel } from './create.js'; 3 | export type { LabelComponentEvents } from './events.js'; 4 | 5 | export type Label = BuilderReturn<typeof createLabel>; 6 | export type LabelElements = Label['elements']; 7 | -------------------------------------------------------------------------------- /src/lib/builders/link-preview/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const linkPreviewEvents = { 4 | trigger: ['pointerenter', 'pointerleave', 'focus', 'blur'] as const, 5 | content: ['pointerdown', 'pointerenter', 'pointerleave', 'focusout'] as const, 6 | }; 7 | 8 | export type LinkPreviewEvents = GroupedEvents<typeof linkPreviewEvents>; 9 | export type LinkPreviewComponentEvents = MeltComponentEvents<LinkPreviewEvents>; 10 | -------------------------------------------------------------------------------- /src/lib/builders/link-preview/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/listbox/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const listboxEvents = { 4 | trigger: ['click', 'keydown', 'input'] as const, 5 | menu: ['pointerleave'] as const, 6 | item: ['pointermove', 'click'] as const, 7 | }; 8 | 9 | export type ListboxEvents = GroupedEvents<typeof listboxEvents>; 10 | export type ListboxComponentEvents = MeltComponentEvents<ListboxEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/listbox/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/menu/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const menuEvents = { 4 | menu: ['keydown'] as const, 5 | trigger: ['pointerdown', 'keydown'] as const, 6 | item: [ 7 | 'pointerdown', 8 | 'click', 9 | 'keydown', 10 | 'pointermove', 11 | 'pointerleave', 12 | 'focusin', 13 | 'focusout', 14 | ] as const, 15 | checkboxItem: [ 16 | 'pointerdown', 17 | 'click', 18 | 'keydown', 19 | 'pointermove', 20 | 'pointerleave', 21 | 'focusin', 22 | 'focusout', 23 | ] as const, 24 | radioItem: [ 25 | 'pointerdown', 26 | 'click', 27 | 'keydown', 28 | 'pointermove', 29 | 'pointerleave', 30 | 'focusin', 31 | 'focusout', 32 | ] as const, 33 | submenu: ['keydown', 'pointermove', 'focusout'] as const, 34 | subTrigger: ['click', 'keydown', 'pointermove', 'pointerleave', 'focusin', 'focusout'] as const, 35 | }; 36 | 37 | export type MenuEvents = GroupedEvents<typeof menuEvents>; 38 | -------------------------------------------------------------------------------- /src/lib/builders/menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/menubar/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | import { menuEvents } from '../menu/events.js'; 3 | 4 | export const menubarEvents = { 5 | ...menuEvents, 6 | menu: ['keydown'] as const, 7 | trigger: ['click', 'keydown', 'pointerenter'] as const, 8 | }; 9 | 10 | export type MenubarEvents = GroupedEvents<typeof menubarEvents>; 11 | export type MenubarComponentEvents = MeltComponentEvents<MenubarEvents>; 12 | -------------------------------------------------------------------------------- /src/lib/builders/menubar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/pagination/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const paginationEvents = { 4 | pageTrigger: ['click', 'keydown'] as const, 5 | nextButton: ['click', 'keydown'] as const, 6 | prevButton: ['click', 'keydown'] as const, 7 | }; 8 | 9 | export type PaginationEvents = GroupedEvents<typeof paginationEvents>; 10 | export type PaginationComponentEvents = MeltComponentEvents<PaginationEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/pagination/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/pin-input/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const pinInputEvents = { 4 | input: ['keydown', 'input', 'paste', 'change', 'focus', 'blur'] as const, 5 | }; 6 | 7 | export type PinInputEvents = GroupedEvents<typeof pinInputEvents>; 8 | export type PinInputComponentEvents = MeltComponentEvents<PinInputEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/pin-input/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/popover/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const popoverEvents = { 4 | trigger: ['click', 'keydown'] as const, 5 | close: ['click', 'keydown'] as const, 6 | } as const; 7 | 8 | export type PopoverEvents = GroupedEvents<typeof popoverEvents>; 9 | export type PopoverComponentEvents = MeltComponentEvents<PopoverEvents>; 10 | -------------------------------------------------------------------------------- /src/lib/builders/popover/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/progress/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/radio-group/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const radioGroupEvents = { 4 | item: ['click', 'focus', 'keydown'] as const, 5 | }; 6 | 7 | export type RadioGroupEvents = GroupedEvents<typeof radioGroupEvents>; 8 | export type RadioGroupComponentEvents = MeltComponentEvents<RadioGroupEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/radio-group/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/range-calendar/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const rangeCalendarEvents = { 4 | calendar: ['keydown'] as const, 5 | prevButton: ['click'] as const, 6 | nextButton: ['click'] as const, 7 | cell: ['click', 'mouseenter', 'focusin'] as const, 8 | }; 9 | 10 | export type RangeCalendarEvents = GroupedEvents<typeof rangeCalendarEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/range-calendar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/scroll-area/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents } from '$lib/internal/types.js'; 2 | 3 | export const scrollAreaEvents = { 4 | scrollbar: ['pointerdown', 'pointerup', 'pointermove'], 5 | thumb: ['pointerdown', 'pointerup'], 6 | } as const; 7 | 8 | export type ScrollAreaEvents = GroupedEvents<typeof scrollAreaEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/scroll-area/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/scroll-area/types.ts: -------------------------------------------------------------------------------- 1 | import type { IdObj } from '$lib/internal/helpers/index.js'; 2 | import type { TextDirection } from '$lib/internal/types.js'; 3 | import type { ScrollAreaIdParts, createScrollArea } from './index.js'; 4 | 5 | export type ScrollAreaType = 'auto' | 'always' | 'scroll' | 'hover'; 6 | 7 | export type CreateScrollAreaProps = { 8 | /** 9 | * Determines when the scrollbar should be visible 10 | * 11 | * @default 'hover' 12 | */ 13 | type?: ScrollAreaType; 14 | 15 | /** 16 | * If the type is `"scroll"` or `"hover"`, this determines how long 17 | * (in milliseconds) the scrollbar should be visible after the user 18 | * either stops scrolling or stops hovering over the scroll area. 19 | * 20 | * @default 600 21 | */ 22 | hideDelay?: number; 23 | 24 | /** 25 | * The reading direction of the scroll area. 26 | * 27 | * @default 'ltr' 28 | */ 29 | dir?: TextDirection; 30 | 31 | /** 32 | * Optionally override the default ids assigned to the 33 | * elements. 34 | */ 35 | ids?: Partial<IdObj<ScrollAreaIdParts>>; 36 | }; 37 | 38 | export type ScrollArea = ReturnType<typeof createScrollArea>; 39 | -------------------------------------------------------------------------------- /src/lib/builders/select/create.ts: -------------------------------------------------------------------------------- 1 | import { derived } from 'svelte/store'; 2 | import { createListbox } from '../listbox/create.js'; 3 | import type { CreateSelectProps, SelectSelected } from './types.js'; 4 | 5 | export function createSelect< 6 | Value = unknown, 7 | Multiple extends boolean = false, 8 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 9 | S extends SelectSelected<Multiple, Value> = SelectSelected<Multiple, Value> 10 | >(props?: CreateSelectProps<Value, Multiple, S>) { 11 | const listbox = createListbox({ ...props, builder: 'select' }); 12 | 13 | const selectedLabel = derived(listbox.states.selected, ($selected) => { 14 | if (Array.isArray($selected)) { 15 | return $selected.map((o) => o.label).join(', '); 16 | } 17 | return $selected?.label ?? ''; 18 | }); 19 | 20 | return { 21 | ...listbox, 22 | 23 | elements: { 24 | ...listbox.elements, 25 | }, 26 | states: { 27 | ...listbox.states, 28 | selectedLabel, 29 | }, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/lib/builders/select/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const selectEvents = { 4 | menu: ['keydown'] as const, 5 | trigger: ['click', 'keydown'] as const, 6 | label: ['click'] as const, 7 | option: ['click', 'keydown', 'pointermove', 'pointerleave', 'focusin', 'focusout'] as const, 8 | }; 9 | 10 | export type SelectEvents = GroupedEvents<typeof selectEvents>; 11 | export type SelectComponentEvents = MeltComponentEvents<SelectEvents>; 12 | -------------------------------------------------------------------------------- /src/lib/builders/select/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/separator/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/separator/types.ts: -------------------------------------------------------------------------------- 1 | import type { BuilderReturn, Orientation } from '$lib/internal/types.js'; 2 | import type { createSeparator } from './create.js'; 3 | 4 | export type CreateSeparatorProps = { 5 | /* 6 | * The orientation of the separator. 7 | * 8 | * @default 'horizontal' 9 | */ 10 | orientation?: Orientation; 11 | 12 | /* 13 | * Whether the separator is purely decorative or not. If true, 14 | * the separator will have a role of 'none' and will be hidden from screen 15 | * readers and removed fro the accessibility tree. 16 | * 17 | * @default false 18 | */ 19 | decorative?: boolean; 20 | }; 21 | 22 | export type Separator = BuilderReturn<typeof createSeparator>; 23 | export type SeparatorElements = Separator['elements']; 24 | export type SeparatorOptions = Separator['options']; 25 | -------------------------------------------------------------------------------- /src/lib/builders/slider/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const sliderEvents = { 4 | thumb: ['keydown'] as const, 5 | }; 6 | 7 | export type SliderEvents = GroupedEvents<typeof sliderEvents>; 8 | export type SliderComponentEvents = MeltComponentEvents<SliderEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/slider/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/switch/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const switchEvents = { 4 | root: ['click', 'keydown'] as const, 5 | }; 6 | 7 | export type SwitchEvents = GroupedEvents<typeof switchEvents>; 8 | export type SwitchComponentEvents = MeltComponentEvents<SwitchEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/switch/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/table-of-contents/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const tableOfContentsEvents = { 4 | item: ['click'] as const, 5 | }; 6 | 7 | export type TableOfContentsEvents = GroupedEvents<typeof tableOfContentsEvents>; 8 | export type TableOfContentsComponentEvents = MeltComponentEvents<TableOfContentsEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/table-of-contents/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/tabs/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const tabsEvents = { 4 | trigger: ['focus', 'click', 'keydown'] as const, 5 | }; 6 | 7 | export type TabsEvents = GroupedEvents<typeof tabsEvents>; 8 | export type TabsComponentEvents = MeltComponentEvents<TabsEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/tabs/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/tags-input/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const tagsInputEvents = { 4 | root: ['mousedown'] as const, 5 | input: ['focus', 'blur', 'paste', 'keydown', 'input'] as const, 6 | tag: ['mousedown', 'click', 'dblclick'] as const, 7 | deleteTrigger: ['click', 'keydown'] as const, 8 | edit: ['blur', 'keydown', 'input'] as const, 9 | }; 10 | 11 | export type TagsInputEvents = GroupedEvents<typeof tagsInputEvents>; 12 | export type TagsInputComponentEvents = MeltComponentEvents<TagsInputEvents>; 13 | -------------------------------------------------------------------------------- /src/lib/builders/tags-input/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/toast/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const toastEvents = { 4 | content: ['pointerenter', 'pointerleave', 'focusout'] as const, 5 | close: ['click', 'keydown'] as const, 6 | }; 7 | 8 | export type ToastEvents = GroupedEvents<typeof toastEvents>; 9 | export type ToastComponentEvents = MeltComponentEvents<ToastEvents>; 10 | -------------------------------------------------------------------------------- /src/lib/builders/toast/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/toggle-group/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const toggleGroupEvents = { 4 | item: ['click', 'keydown'] as const, 5 | }; 6 | 7 | export type ToggleGroupEvents = GroupedEvents<typeof toggleGroupEvents>; 8 | export type ToggleGroupComponentEvents = MeltComponentEvents<ToggleGroupEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/toggle-group/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/toggle/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const toggleEvents = { 4 | root: ['click', 'keydown'] as const, 5 | }; 6 | export type ToggleEvents = GroupedEvents<typeof toggleEvents>; 7 | export type ToggleComponentEvents = MeltComponentEvents<ToggleEvents>; 8 | -------------------------------------------------------------------------------- /src/lib/builders/toggle/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/toggle/types.ts: -------------------------------------------------------------------------------- 1 | import type { BuilderReturn } from '$lib/internal/types.js'; 2 | import type { Writable } from 'svelte/store'; 3 | import type { createToggle } from './create.js'; 4 | import type { ChangeFn } from '$lib/internal/helpers/index.js'; 5 | export type { ToggleComponentEvents } from './events.js'; 6 | 7 | export type CreateToggleProps = { 8 | disabled?: boolean; 9 | defaultPressed?: boolean; 10 | pressed?: Writable<boolean>; 11 | onPressedChange?: ChangeFn<boolean>; 12 | }; 13 | 14 | export type Toggle = BuilderReturn<typeof createToggle>; 15 | export type ToggleElements = Toggle['elements']; 16 | export type ToggleOptions = Toggle['options']; 17 | export type ToggleBuilders = Toggle['states']; 18 | -------------------------------------------------------------------------------- /src/lib/builders/toolbar/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const toolbarEvents = { 4 | button: ['keydown'] as const, 5 | link: ['keydown'] as const, 6 | item: ['click', 'keydown'] as const, 7 | }; 8 | 9 | export type ToolbarEvents = GroupedEvents<typeof toolbarEvents>; 10 | export type ToolbarComponentEvents = MeltComponentEvents<ToolbarEvents>; 11 | -------------------------------------------------------------------------------- /src/lib/builders/toolbar/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/tooltip/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const tooltipEvents = { 4 | trigger: ['pointerdown', 'pointerenter', 'pointerleave', 'focus', 'blur', 'keydown'] as const, 5 | content: ['pointerenter', 'pointerdown'] as const, 6 | }; 7 | export type TooltipEvents = GroupedEvents<typeof tooltipEvents>; 8 | export type TooltipComponentEvents = MeltComponentEvents<TooltipEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/tooltip/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/builders/tree/events.ts: -------------------------------------------------------------------------------- 1 | import type { GroupedEvents, MeltComponentEvents } from '$lib/internal/types.js'; 2 | 3 | export const treeEvents = { 4 | item: ['keydown', 'click', 'focus'] as const, 5 | }; 6 | 7 | export type TreeEvents = GroupedEvents<typeof treeEvents>; 8 | export type TreeComponentEvents = MeltComponentEvents<TreeEvents>; 9 | -------------------------------------------------------------------------------- /src/lib/builders/tree/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './builders/index.js'; 2 | export * from './shared/index.js'; 3 | export { melt } from './internal/actions/index.js'; 4 | export { createSync } from './sync.js'; 5 | export type { AnyMeltElement } from './internal/helpers/makeElement.js'; 6 | export { emptyMeltElement } from './internal/helpers/makeElement.js'; 7 | -------------------------------------------------------------------------------- /src/lib/internal/actions/escape-keydown/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/floating/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types.js'; 2 | export * from './action.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/focus-trap/action.ts: -------------------------------------------------------------------------------- 1 | import type { FocusTrapConfig } from './types.js'; 2 | import { createFocusTrap as _createFocusTrap } from 'focus-trap'; 3 | import { noop } from '$lib/internal/helpers/callbacks.js'; 4 | import type { Action } from 'svelte/action'; 5 | 6 | export const useFocusTrap = ((node, config = {}) => { 7 | let unsub = noop; 8 | 9 | const update = (config: FocusTrapConfig) => { 10 | unsub(); 11 | const trap = _createFocusTrap(node, { 12 | returnFocusOnDeactivate: false, 13 | allowOutsideClick: true, 14 | escapeDeactivates: false, 15 | clickOutsideDeactivates: false, 16 | ...config, 17 | }); 18 | unsub = trap.deactivate; 19 | trap.activate(); 20 | }; 21 | 22 | update(config); 23 | 24 | return { destroy: unsub, update }; 25 | }) satisfies Action<HTMLElement, FocusTrapConfig>; 26 | -------------------------------------------------------------------------------- /src/lib/internal/actions/focus-trap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types.js'; 2 | export * from './action.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './escape-keydown/index.js'; 2 | export * from './floating/index.js'; 3 | export * from './focus-trap/index.js'; 4 | export * from './melt/index.js'; 5 | export * from './popper/index.js'; 6 | export * from './portal.js'; 7 | export * from './interact-outside/index.js'; 8 | -------------------------------------------------------------------------------- /src/lib/internal/actions/interact-outside/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/modal/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/modal/types.ts: -------------------------------------------------------------------------------- 1 | import type { InteractOutsideEvent } from '$lib/internal/actions/index.js'; 2 | 3 | export type ModalConfig = { 4 | /** 5 | * Handler called when the overlay closes. 6 | */ 7 | onClose?: () => void; 8 | /** 9 | * Whether the modal is able to be closed by interacting outside of it. 10 | * If true, the `onClose` callback will be called when the user interacts 11 | * outside of the modal. 12 | * 13 | * @default true 14 | */ 15 | closeOnInteractOutside?: boolean; 16 | 17 | /** 18 | * If `closeOnInteractOutside` is `true` and this function is provided, 19 | * it will be called with the element that the outside interaction occurred 20 | * on. Whatever is returned from this function will determine whether the 21 | * modal actually closes or not. 22 | * 23 | * This is useful to filter out interactions with certain elements from 24 | * closing the modal. If `closeOnInteractOutside` is `false`, this function 25 | * will not be called. 26 | */ 27 | shouldCloseOnInteractOutside?: (event: InteractOutsideEvent) => boolean; 28 | }; 29 | -------------------------------------------------------------------------------- /src/lib/internal/actions/popper/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/popper/types.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | FloatingConfig, 3 | FocusTrapConfig, 4 | PortalConfig, 5 | EscapeKeydownConfig, 6 | } from '$lib/internal/actions/index.js'; 7 | import type { VirtualElement } from '@floating-ui/core'; 8 | import type { Writable } from 'svelte/store'; 9 | import type { ModalConfig } from '../modal/types.js'; 10 | import type { PreventTextSelectionOverflowConfig } from '../prevent-text-selection-overflow/types.js'; 11 | 12 | export type PopperConfig = { 13 | floating?: FloatingConfig; 14 | focusTrap?: FocusTrapConfig | null; 15 | modal?: ModalConfig | null; 16 | portal?: PortalConfig | null; 17 | escapeKeydown?: EscapeKeydownConfig | null; 18 | preventTextSelectionOverflow?: PreventTextSelectionOverflowConfig | null; 19 | }; 20 | 21 | export type PopperArgs = { 22 | anchorElement: Element | VirtualElement; 23 | open: Writable<boolean>; 24 | options?: PopperConfig; 25 | }; 26 | -------------------------------------------------------------------------------- /src/lib/internal/actions/prevent-text-selection-overflow/index.ts: -------------------------------------------------------------------------------- 1 | export * from './action.js'; 2 | export * from './types.js'; 3 | -------------------------------------------------------------------------------- /src/lib/internal/actions/prevent-text-selection-overflow/types.ts: -------------------------------------------------------------------------------- 1 | import type { WithGet } from '$lib/internal/helpers/withGet.js'; 2 | import type { Readable } from 'svelte/store'; 3 | 4 | export type PreventTextSelectionOverflowConfig = { 5 | /** 6 | * Whether should prevent text selection overflowing the element when the element is the top layer. 7 | * 8 | * @defaultValue `true` 9 | */ 10 | enabled?: boolean | WithGet<Readable<boolean>>; 11 | }; 12 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/attr.ts: -------------------------------------------------------------------------------- 1 | import { styleToString } from './style.js'; 2 | 3 | export function disabledAttr(disabled: boolean | undefined) { 4 | return disabled ? true : undefined; 5 | } 6 | 7 | export const hiddenInputAttrs = { 8 | type: 'hidden', 9 | 'aria-hidden': true, 10 | hidden: true, 11 | tabIndex: -1, 12 | style: styleToString({ 13 | position: 'absolute', 14 | opacity: 0, 15 | 'pointer-events': 'none', 16 | margin: 0, 17 | transform: 'translateX(-100%)', 18 | }), 19 | }; 20 | 21 | /** 22 | * @param portal The value of the `portal` option store. 23 | * @returns the value of the `data-portal` attribute. 24 | */ 25 | export function portalAttr(portal: string | HTMLElement | null | undefined) { 26 | if (portal !== null) { 27 | return ''; 28 | } 29 | return undefined; 30 | } 31 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/callbacks.ts: -------------------------------------------------------------------------------- 1 | import type { NonEmptyArray } from '../types.js'; 2 | 3 | /** 4 | * A callback function that takes an array of arguments of type `T` and returns `void`. 5 | * @template T The types of the arguments that the callback function takes. 6 | */ 7 | export type Callback<T extends unknown[] = unknown[]> = (...args: T) => void; 8 | 9 | /** 10 | * Executes an array of callback functions with the same arguments. 11 | * @template T The types of the arguments that the callback functions take. 12 | * @param n array of callback functions to execute. 13 | * @returns A new function that executes all of the original callback functions with the same arguments. 14 | */ 15 | export function executeCallbacks<T extends unknown[]>( 16 | ...callbacks: NonEmptyArray<Callback<T>> 17 | ): (...args: T) => void { 18 | return (...args) => { 19 | for (const callback of callbacks) { 20 | if (typeof callback === 'function') { 21 | callback(...args); 22 | } 23 | } 24 | }; 25 | } 26 | 27 | /** 28 | * A no operation function (does nothing) 29 | */ 30 | export function noop() { 31 | // 32 | } 33 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/date/focus.ts: -------------------------------------------------------------------------------- 1 | import { isHTMLElement } from '$lib/internal/helpers/index.js'; 2 | 3 | export function pickerOpenFocus(defaultEl?: HTMLElement | null) { 4 | const el = document.querySelector('[data-melt-calendar-cell][data-focused]'); 5 | if (isHTMLElement(el)) { 6 | return el; 7 | } 8 | if (isHTMLElement(defaultEl)) { 9 | return defaultEl; 10 | } 11 | return null; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/date/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils.js'; 2 | export * from './types.js'; 3 | export * from './formatter.js'; 4 | export * from './store.js'; 5 | export * from './placeholders.js'; 6 | export * from './announcer.js'; 7 | export * from './field.js'; 8 | export * from './calendar.js'; 9 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/date/tests/FieldTest.svelte: -------------------------------------------------------------------------------- 1 | <div id="field" data-testid="field"> 2 | <div data-segment="day" /> 3 | <div data-segment="month" /> 4 | <div data-segment="year" /> 5 | <div data-segment="literal" /> 6 | <div data-segment="sknkndfkndknd"> 7 | <div data-segment="hour" /> 8 | <div data-segment="minute" /> 9 | <div data-segment="second" /> 10 | <div data-segment="dayPeriod" /> 11 | <div data-segment="timeZoneName" /> 12 | </div> 13 | </div> 14 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/debounce.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 2 | export function debounce<T extends (...args: any[]) => any>(fn: T, wait = 500) { 3 | let timeout: NodeJS.Timeout; 4 | 5 | const debounced = (...args: Parameters<T>) => { 6 | clearTimeout(timeout); 7 | const later = () => fn(...args); 8 | timeout = setTimeout(later, wait); 9 | }; 10 | 11 | debounced.destroy = () => clearTimeout(timeout); 12 | return debounced; 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/focus.ts: -------------------------------------------------------------------------------- 1 | import { isFunction, isHTMLElement, sleep } from '$lib/internal/helpers/index.js'; 2 | import { tick } from 'svelte'; 3 | 4 | export type FocusTarget = string | HTMLElement | SVGElement | null; 5 | export type FocusProp = FocusTarget | ((defaultEl?: HTMLElement | null) => FocusTarget); 6 | 7 | type HandleFocusArgs = { 8 | prop?: FocusProp; 9 | defaultEl: HTMLElement | null; 10 | }; 11 | 12 | export async function handleFocus(args: HandleFocusArgs): Promise<void> { 13 | const { prop, defaultEl } = args; 14 | 15 | await Promise.all([sleep(1), tick]); 16 | 17 | if (prop === undefined) { 18 | defaultEl?.focus(); 19 | return; 20 | } 21 | 22 | const returned = isFunction(prop) ? prop(defaultEl) : prop; 23 | 24 | if (typeof returned === 'string') { 25 | // Get el by selector, focus it 26 | const el = document.querySelector(returned); 27 | if (!isHTMLElement(el)) return; 28 | el.focus(); 29 | } else if (isHTMLElement(returned)) { 30 | // Focus it 31 | returned.focus(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/highlight.ts: -------------------------------------------------------------------------------- 1 | export function addHighlight(element: HTMLElement) { 2 | element.setAttribute('data-highlighted', ''); 3 | } 4 | 5 | export function removeHighlight(element: HTMLElement) { 6 | element.removeAttribute('data-highlighted'); 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/id.ts: -------------------------------------------------------------------------------- 1 | import { nanoid } from 'nanoid/non-secure'; 2 | import type { Expand } from '../types.js'; 3 | 4 | /** 5 | * A function that generates a random id 6 | * @returns An id 7 | */ 8 | export function generateId(): string { 9 | return nanoid(10); 10 | } 11 | 12 | export type IdObj<T extends readonly string[]> = Expand<{ [K in T[number]]: string }>; 13 | 14 | export function generateIds<T extends readonly string[]>(args: T): IdObj<T> { 15 | return args.reduce((acc, curr) => { 16 | acc[curr as keyof IdObj<T>] = generateId() as IdObj<T>[keyof IdObj<T>]; 17 | return acc; 18 | }, {} as IdObj<T>); 19 | } 20 | 21 | export function stringifiedIdObjType<T extends readonly string[]>(args: T): string { 22 | return `Record<${args.map((arg) => `"${arg}"`).join(' | ')}, string>`; 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/ignore.ts: -------------------------------------------------------------------------------- 1 | import { getElementByMeltId, isElement, isHTMLLabelElement } from '$lib/internal/helpers/index.js'; 2 | import type { InteractOutsideEvent } from '../actions/index.js'; 3 | 4 | export function createClickOutsideIgnore(meltId: string) { 5 | return (e: InteractOutsideEvent) => { 6 | const target = e.target; 7 | const triggerEl = getElementByMeltId(meltId); 8 | if (!triggerEl || !isElement(target)) return false; 9 | 10 | const id = triggerEl.id; 11 | 12 | if (isHTMLLabelElement(target) && id === target.htmlFor) { 13 | return true; 14 | } 15 | 16 | if (target.closest(`label[for="${id}"]`)) { 17 | return true; 18 | } 19 | 20 | return false; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './array.js'; 2 | export * from './attr.js'; 3 | export * from './callbacks.js'; 4 | export * from './makeElement.js'; 5 | export * from './dom.js'; 6 | export * from './event.js'; 7 | export * from './highlight.js'; 8 | export * from './is.js'; 9 | export * from './lifecycle.js'; 10 | export * from './list.js'; 11 | export * from './locale.js'; 12 | export * from './object.js'; 13 | export * from './overridable.js'; 14 | export * from './sleep.js'; 15 | export * from './style.js'; 16 | export * from './id.js'; 17 | export * from './keyboard.js'; 18 | export * from './debounce.js'; 19 | export * from './platform.js'; 20 | export * from './polygon/index.js'; 21 | export * from './scroll.js'; 22 | export * from './store/index.js'; 23 | export * from './rovingFocus.js'; 24 | export * from './typeahead.js'; 25 | export * from './elements.js'; 26 | export * from './ignore.js'; 27 | export * from './focus.js'; 28 | export * from './math.js'; 29 | export * from './withGet.js'; 30 | export * from './pointer.js'; 31 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/lifecycle.ts: -------------------------------------------------------------------------------- 1 | import { onDestroy, onMount } from 'svelte'; 2 | 3 | export const safeOnMount = (fn: (...args: unknown[]) => unknown) => { 4 | try { 5 | onMount(fn); 6 | } catch { 7 | return fn; 8 | } 9 | }; 10 | 11 | export const safeOnDestroy = (fn: (...args: unknown[]) => unknown) => { 12 | try { 13 | onDestroy(fn); 14 | } catch { 15 | return fn; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/list.ts: -------------------------------------------------------------------------------- 1 | import { isHTMLElement } from './is.js'; 2 | 3 | /** Retrieves all option descendants of a given element. */ 4 | export function getOptions(el: HTMLElement): HTMLElement[] { 5 | return Array.from(el.querySelectorAll('[role="option"]:not([data-disabled])')).filter( 6 | (el): el is HTMLElement => isHTMLElement(el) 7 | ); 8 | } 9 | 10 | /** Retrieves the first option descendant of a given element. */ 11 | export function getFirstOption(el: HTMLElement): HTMLElement | null { 12 | const firstOption = el.querySelector('[role="option"]:not([data-disabled])'); 13 | 14 | return isHTMLElement(firstOption) ? firstOption : null; 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/locale.ts: -------------------------------------------------------------------------------- 1 | import type { TextDirection } from '$lib/internal/types.js'; 2 | 3 | /** 4 | * Detects the text direction in the element. 5 | * @returns {TextDirection} The text direction ('ltr' for left-to-right or 'rtl' for right-to-left). 6 | */ 7 | export function getElemDirection(elem: HTMLElement): TextDirection { 8 | const style = window.getComputedStyle(elem); 9 | const direction = style.getPropertyValue('direction'); 10 | 11 | return direction as TextDirection; 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/overridable.ts: -------------------------------------------------------------------------------- 1 | import type { Updater, Writable } from 'svelte/store'; 2 | import { withGet } from './withGet.js'; 3 | 4 | export type ChangeFn<T> = (args: { curr: T; next: T }) => T; 5 | 6 | export const overridable = <T>(_store: Writable<T>, onChange?: ChangeFn<T>) => { 7 | const store = withGet(_store); 8 | 9 | const update = (updater: Updater<T>, sideEffect?: (newValue: T) => void) => { 10 | store.update((curr) => { 11 | const next = updater(curr); 12 | let res: T = next; 13 | if (onChange) { 14 | res = onChange({ curr, next }); 15 | } 16 | 17 | sideEffect?.(res); 18 | return res; 19 | }); 20 | }; 21 | 22 | const set: typeof store.set = (curr) => { 23 | update(() => curr); 24 | }; 25 | 26 | return { 27 | ...store, 28 | update, 29 | set, 30 | }; 31 | }; 32 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/platform.ts: -------------------------------------------------------------------------------- 1 | export const isDom = () => typeof window !== 'undefined'; 2 | export function getPlatform() { 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 4 | const agent = (navigator as any).userAgentData; 5 | return (agent?.platform ?? navigator.platform) as string; 6 | } 7 | const pt = (v: RegExp) => isDom() && v.test(getPlatform().toLowerCase()); 8 | const ua = (v: RegExp) => isDom() && v.test(navigator.userAgent); 9 | const vn = (v: RegExp) => isDom() && v.test(navigator.vendor); 10 | export const isTouchDevice = () => isDom() && !!navigator.maxTouchPoints; 11 | export const isMac = () => pt(/^mac/) && !isTouchDevice(); 12 | export const isIPhone = () => pt(/^iphone/); 13 | export const isSafari = () => isApple() && vn(/apple/i); 14 | export const isFirefox = () => ua(/firefox\//i); 15 | export const isApple = () => pt(/mac|iphone|ipad|ipod/i); 16 | export const isIos = () => isApple() && !isMac(); 17 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/pointer.ts: -------------------------------------------------------------------------------- 1 | import { pointInPolygon, type Polygon } from './index.js'; 2 | 3 | export function isPointerInGraceArea( 4 | e: Pick<PointerEvent, 'clientX' | 'clientY'>, 5 | area?: Polygon 6 | ): boolean { 7 | if (!area) return false; 8 | return pointInPolygon({ x: e.clientX, y: e.clientY }, area); 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/polygon/index.ts: -------------------------------------------------------------------------------- 1 | export * from './hull.js'; 2 | 3 | import { makeHull, type Point, type Polygon } from './hull.js'; 4 | 5 | export function getPointsFromEl(el: HTMLElement): Array<Point> { 6 | const rect = el.getBoundingClientRect(); 7 | return [ 8 | { x: rect.left, y: rect.top }, 9 | { x: rect.right, y: rect.top }, 10 | { x: rect.right, y: rect.bottom }, 11 | { x: rect.left, y: rect.bottom }, 12 | ]; 13 | } 14 | 15 | export function makeHullFromElements(els: Array<HTMLElement>): Array<Point> { 16 | const points = els.flatMap((el) => getPointsFromEl(el)); 17 | return makeHull(points); 18 | } 19 | 20 | export function pointInPolygon(point: Point, polygon: Polygon) { 21 | let inside = false; 22 | for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { 23 | const xi = polygon[i].x; 24 | const yi = polygon[i].y; 25 | const xj = polygon[j].x; 26 | const yj = polygon[j].y; 27 | 28 | const intersect = 29 | yi > point.y !== yj > point.y && point.x < ((xj - xi) * (point.y - yi)) / (yj - yi) + xi; 30 | if (intersect) inside = !inside; 31 | } 32 | return inside; 33 | } 34 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/sleep.ts: -------------------------------------------------------------------------------- 1 | export function sleep(ms: number) { 2 | return new Promise((resolve) => setTimeout(resolve, ms)); 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/store/derivedFromObject.ts: -------------------------------------------------------------------------------- 1 | import { derived, type Readable } from 'svelte/store'; 2 | 3 | type StoresObj = Record<string, Readable<unknown>>; 4 | type StoresObjValues<S extends StoresObj> = { 5 | [K in keyof S as `${K extends string ? K : never}`]: S[K] extends Readable<infer U> ? U : never; 6 | }; 7 | 8 | export function derivedFromObject< 9 | S extends StoresObj, 10 | Callback extends (values: StoresObjValues<S>) => unknown 11 | >(stores: S, fn: Callback): Readable<ReturnType<Callback>> { 12 | return derived(Object.values(stores), (values) => { 13 | // map the values back to the keys 14 | const valuesObj = Object.fromEntries( 15 | Object.keys(stores).map((key, i) => [`${key}`, values[i]]) 16 | ) as StoresObjValues<S>; 17 | return fn(valuesObj) as ReturnType<typeof fn>; 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/store/derivedVisible.ts: -------------------------------------------------------------------------------- 1 | import { derived, type Writable } from 'svelte/store'; 2 | 3 | type DerivedVisibleObj = { 4 | open: Writable<boolean>; 5 | forceVisible: Writable<boolean>; 6 | activeTrigger: Writable<HTMLElement | null>; 7 | }; 8 | 9 | /** 10 | * Helper function to standardize the way we derive a visible state for the 11 | * popper/floating elements. 12 | */ 13 | export function derivedVisible(obj: DerivedVisibleObj) { 14 | const { open, forceVisible, activeTrigger } = obj; 15 | return derived( 16 | [open, forceVisible, activeTrigger], 17 | ([$open, $forceVisible, $activeTrigger]) => ($open || $forceVisible) && $activeTrigger !== null 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/store/index.ts: -------------------------------------------------------------------------------- 1 | export * from './derivedFromObject.js'; 2 | export * from './derivedVisible.js'; 3 | export * from './effect.js'; 4 | export * from './lightable.js'; 5 | export * from './debounceable.js'; 6 | export * from './toWritableStores.js'; 7 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/store/lightable.ts: -------------------------------------------------------------------------------- 1 | import type { Readable, Subscriber, Unsubscriber } from 'svelte/store'; 2 | 3 | export function lightable<T>(value: T): Readable<T> { 4 | function subscribe(run: Subscriber<T>): Unsubscriber { 5 | run(value); 6 | return () => { 7 | // don't need to unsub from anything 8 | }; 9 | } 10 | return { subscribe }; 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/store/toWritableStores.ts: -------------------------------------------------------------------------------- 1 | import { type Writable, writable } from 'svelte/store'; 2 | import { withGet, type WithGet } from '../withGet.js'; 3 | 4 | export type ToWritableStores<T extends Record<string, unknown>> = { 5 | [K in keyof T]: WithGet<Writable<T[K]>>; 6 | }; 7 | 8 | /** 9 | * Given an object of properties, returns an object of writable stores 10 | * with the same properties and values. 11 | */ 12 | export function toWritableStores<T extends Record<string, unknown>>( 13 | properties: T 14 | ): ToWritableStores<T> { 15 | const result = {} as { [K in keyof T]: WithGet<Writable<T[K]>> }; 16 | 17 | Object.keys(properties).forEach((key) => { 18 | const propertyKey = key as keyof T; 19 | const value = properties[propertyKey]; 20 | result[propertyKey] = withGet(writable(value)); 21 | }); 22 | 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/style.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * A utility function that converts a style object to a string. 3 | * 4 | * @param style - The style object to convert 5 | * @returns The style object as a string 6 | */ 7 | export function styleToString(style: StyleObject): string { 8 | return Object.keys(style).reduce((str, key) => { 9 | if (style[key] === undefined) return str; 10 | return str + `${key}:${style[key]};`; 11 | }, ''); 12 | } 13 | 14 | export type StyleObject = Record<string, number | string | undefined>; 15 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/tests/DomTest.svelte: -------------------------------------------------------------------------------- 1 | <div role="form"> 2 | <input id="name" type="text" placeholder="Name" /> 3 | <hr /> 4 | <input id="email" type="email" placeholder="vanilla@melt-ui.com" /> 5 | </div> 6 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/tests/ListDisabledTest.svelte: -------------------------------------------------------------------------------- 1 | <ul> 2 | <li aria-selected="false" role="option" data-disabled>Caramel</li> 3 | <li aria-selected="false" role="option">Chocolate</li> 4 | <li aria-selected="false" role="option">Strawberry</li> 5 | <li aria-selected="false" role="option">Cookies & Cream</li> 6 | </ul> 7 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/tests/ListTest.svelte: -------------------------------------------------------------------------------- 1 | <ul> 2 | <li aria-selected="false" role="option">Caramel</li> 3 | <li aria-selected="false" role="option">Chocolate</li> 4 | <li aria-selected="false" role="option">Strawberry</li> 5 | <li aria-selected="false" role="option">Cookies & Cream</li> 6 | </ul> 7 | <ul role="menu" /> 8 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/tests/callbacks.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, it, vi } from 'vitest'; 2 | import { executeCallbacks } from '../callbacks.js'; 3 | 4 | describe('executeCallbacks', () => { 5 | it('groups callbacks and executes them together', () => { 6 | const functionMock = vi.fn(); 7 | const callbackMock = vi.fn(); 8 | /** 9 | * `functionMock` should be called immediately whereas `callbackMock` 10 | * should be called when the executeCallbacks function is invoked. 11 | */ 12 | function testFunction() { 13 | functionMock(); 14 | return () => { 15 | callbackMock(); 16 | }; 17 | } 18 | 19 | // Create a listener group. 20 | const cleanup = executeCallbacks(testFunction(), testFunction(), testFunction()); 21 | // Assert that `functionMock` was called 3x and `callbackMock` was not. 22 | expect(functionMock).toBeCalledTimes(3); 23 | expect(callbackMock).not.toBeCalled(); 24 | // Invoke the cleanup function, which should fire the callbacks. 25 | cleanup(); 26 | // Assert that `callbackMock` was called 3x. 27 | expect(callbackMock).toBeCalledTimes(3); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /src/lib/internal/helpers/tests/object.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from 'vitest'; 2 | import { omit } from '../object.js'; 3 | 4 | describe('omit', () => { 5 | it('omits keys from a given object', () => { 6 | expect( 7 | omit({ sweet: ['Caramel', 'Chocolate'], savory: ['Basil', 'Bacon'] }, 'sweet') 8 | ).toStrictEqual({ savory: ['Basil', 'Bacon'] }); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/lib/shared/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * When types or functions are shared between multiple builders 3 | * with the expectation that they will be exported for users to 4 | * use, they should be exported from this file to prevent conflicts 5 | * with other builders that may export the same types or functions. 6 | */ 7 | import type { SegmentPart, EditableSegmentPart } from '$lib/builders/date-field/_internal/types.js'; 8 | import type { Granularity, Matcher, DateRange, Month } from '$lib/internal/helpers/date/index.js'; 9 | import type { FocusProp, FocusTarget } from '$lib/internal/helpers/index.js'; 10 | import type { InteractOutsideEvent } from '$lib/internal/actions/index.js'; 11 | 12 | export type { 13 | Granularity, 14 | FocusProp, 15 | FocusTarget, 16 | Matcher, 17 | DateRange, 18 | Month, 19 | SegmentPart, 20 | EditableSegmentPart, 21 | InteractOutsideEvent, 22 | }; 23 | -------------------------------------------------------------------------------- /src/pagefind/fragment/en_16f1fe9.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_16f1fe9.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_1d46621.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_1d46621.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_1eec87d.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_1eec87d.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_1f88d81.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_1f88d81.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_253ea28.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_253ea28.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_2bd0579.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_2bd0579.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_2e237a4.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_2e237a4.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_321e343.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_321e343.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_34dd722.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_34dd722.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_35a7fed.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_35a7fed.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_415ef09.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_415ef09.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_4161acc.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_4161acc.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_4923d38.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_4923d38.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_4a8730c.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_4a8730c.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_4b19e66.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_4b19e66.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_4fcecaf.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_4fcecaf.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_5383a1d.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_5383a1d.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_56f028e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_56f028e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_5c106cb.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_5c106cb.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_5f32e6f.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_5f32e6f.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_606d683.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_606d683.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_61b54f5.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_61b54f5.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_6367aa6.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_6367aa6.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_6addd1e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_6addd1e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_6b8464c.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_6b8464c.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_749d563.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_749d563.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_77c1fa3.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_77c1fa3.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_787f19f.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_787f19f.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_79a771c.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_79a771c.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_79c1fd7.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_79c1fd7.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_7a6a4a4.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_7a6a4a4.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_7af1b43.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_7af1b43.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_7cb8111.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_7cb8111.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_7f1fe4e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_7f1fe4e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_7f5f5d6.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_7f5f5d6.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_80da96b.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_80da96b.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_84dca64.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_84dca64.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_862027d.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_862027d.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_86eb18e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_86eb18e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_86f4cb2.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_86f4cb2.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_87b486c.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_87b486c.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_88d7b94.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_88d7b94.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_8dee4ed.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_8dee4ed.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_8eead83.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_8eead83.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_9b23e84.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_9b23e84.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_9eb49a9.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_9eb49a9.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_9ee8ae6.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_9ee8ae6.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_a6cfcc7.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_a6cfcc7.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_a7cde16.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_a7cde16.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_a881cb1.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_a881cb1.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_aab8e97.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_aab8e97.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_b29e78a.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_b29e78a.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_b2f7e99.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_b2f7e99.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_b6f2f56.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_b6f2f56.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_bbd9fcd.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_bbd9fcd.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_bec59c6.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_bec59c6.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_bf89c03.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_bf89c03.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_c1771c1.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_c1771c1.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_c262815.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_c262815.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_c3b0e25.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_c3b0e25.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_cc9b37e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_cc9b37e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_ceb1ab4.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_ceb1ab4.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_d0dccd1.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_d0dccd1.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_d2d2dba.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_d2d2dba.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_d593b09.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_d593b09.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_e7ae582.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_e7ae582.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_eab52f7.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_eab52f7.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_f171c86.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_f171c86.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_f3c766e.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_f3c766e.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_f4e7e33.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_f4e7e33.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_f8b9234.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_f8b9234.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/fragment/en_fab61f9.pf_fragment: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/fragment/en_fab61f9.pf_fragment -------------------------------------------------------------------------------- /src/pagefind/index/en_18e7ecb.pf_index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/index/en_18e7ecb.pf_index -------------------------------------------------------------------------------- /src/pagefind/index/en_7d6f722.pf_index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/index/en_7d6f722.pf_index -------------------------------------------------------------------------------- /src/pagefind/index/en_a82e347.pf_index: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/index/en_a82e347.pf_index -------------------------------------------------------------------------------- /src/pagefind/pagefind-entry.json: -------------------------------------------------------------------------------- 1 | {"version":"1.0.3","languages":{"en":{"hash":"en_aff7732c1a","wasm":"en","page_count":36}}} -------------------------------------------------------------------------------- /src/pagefind/pagefind.en_055429da4e.pf_meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/pagefind.en_055429da4e.pf_meta -------------------------------------------------------------------------------- /src/pagefind/pagefind.en_aff7732c1a.pf_meta: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/pagefind.en_aff7732c1a.pf_meta -------------------------------------------------------------------------------- /src/pagefind/wasm.en.pagefind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/wasm.en.pagefind -------------------------------------------------------------------------------- /src/pagefind/wasm.unknown.pagefind: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/src/pagefind/wasm.unknown.pagefind -------------------------------------------------------------------------------- /src/routes/(landing-ui)/pin-input.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { createPinInput, melt } from '$lib/index.js'; 4 | 5 | const { 6 | elements: { root, input }, 7 | } = createPinInput({ 8 | placeholder: '•', 9 | defaultValue: ['1', '0', '4', '5', ''], 10 | }); 11 | 12 | let className = ''; 13 | export { className as class }; 14 | </script> 15 | 16 | <div use:melt={$root} class={cn('flex items-center gap-2', className)}> 17 | {#each Array.from({ length: 5 }) as _} 18 | <input 19 | class="size-12 rounded-xl bg-white text-center text-lg text-magnum-900 shadow-sm" 20 | use:melt={$input()} 21 | /> 22 | {/each} 23 | </div> 24 | -------------------------------------------------------------------------------- /src/routes/(landing-ui)/slider.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { cn } from '$docs/utils/index.js'; 3 | import { createSlider, melt } from '$lib/index.js'; 4 | 5 | const { 6 | elements: { root, range, thumbs }, 7 | } = createSlider({ 8 | defaultValue: [60], 9 | max: 100, 10 | }); 11 | 12 | let className = ''; 13 | export { className as class }; 14 | </script> 15 | 16 | <span use:melt={$root} class={cn('relative flex w-[15rem] items-center', className)}> 17 | <span class="block h-1.5 w-full rounded-full bg-neutral-400 dark:bg-neutral-700"> 18 | <span use:melt={$range} class="h-1.5 rounded-full bg-magnum-400" /> 19 | </span> 20 | <span 21 | use:melt={$thumbs[0]} 22 | class="block size-6 rounded-full bg-white shadow focus:ring-4 focus:ring-magnum-600 dark:bg-white dark:shadow-none" 23 | /> 24 | </span> 25 | -------------------------------------------------------------------------------- /src/routes/(landing-ui)/switch.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSwitch, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { root, input }, 6 | states: { checked }, 7 | } = createSwitch({ 8 | defaultChecked: true, 9 | }); 10 | 11 | let className = ''; 12 | export { className as class }; 13 | </script> 14 | 15 | <form class={className}> 16 | <div class="flex items-center"> 17 | <button 18 | use:melt={$root} 19 | class="relative h-10 w-[5rem] cursor-default rounded-full bg-magnum-800 20 | transition-colors" 21 | id="airplane-mode" 22 | aria-label="Switch" 23 | > 24 | <span 25 | class="block size-8 rounded-full transition will-change-transform 26 | {$checked ? 'translate-x-[2.75rem] bg-white' : 'translate-x-1 bg-white/50'}" 27 | /> 28 | </button> 29 | <input use:melt={$input} /> 30 | </div> 31 | </form> 32 | -------------------------------------------------------------------------------- /src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { page } from '$app/stores'; 3 | import { Button } from '$docs/components/index.js'; 4 | 5 | $: message = $page.status === 404 ? 'Page not found' : 'Something went wrong'; 6 | </script> 7 | 8 | <main class="grid min-h-full w-full place-items-center px-6 py-24 sm:py-32 lg:px-8"> 9 | <div class="text-center"> 10 | <p class="font-semibold text-magnum-500">{$page.status}</p> 11 | <h1 class="mt-4 text-4xl font-bold tracking-tight">{message}</h1> 12 | <div class="mt-10 flex items-center justify-center gap-x-6"> 13 | <Button href="/docs" class="mt-4">Back to docs</Button> 14 | </div> 15 | </div> 16 | </main> 17 | -------------------------------------------------------------------------------- /src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | import { getStoredHighlighter } from '$docs/highlighter.js'; 2 | import type { LayoutServerLoad } from './$types.js'; 3 | 4 | export const load: LayoutServerLoad = async () => { 5 | // initialize the highlighter 6 | await getStoredHighlighter(); 7 | }; 8 | -------------------------------------------------------------------------------- /src/routes/+layout.ts: -------------------------------------------------------------------------------- 1 | export const prerender = true; 2 | -------------------------------------------------------------------------------- /src/routes/discord/+page.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit'; 2 | import type { PageLoad } from './$types.js'; 3 | 4 | export const load: PageLoad = async () => { 5 | redirect(303, 'https://discord.gg/cee8gHrznd'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/routes/docs/+layout.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { SidebarNav } from '$docs/components/index.js'; 3 | import Switch from '$docs/components/switch.svelte'; 4 | import { getUsingPreprocessor } from '$routes/store.js'; 5 | 6 | const usingPreprocessor = getUsingPreprocessor(); 7 | </script> 8 | 9 | <div class="container flex-1 items-start md:grid md:grid-cols-[220px_minmax(0,1fr)] md:gap-6"> 10 | <aside 11 | class="fixed top-16 z-30 -ml-2 hidden h-[calc(100vh-4rem)] w-full shrink-0 12 | flex-col overflow-y-auto pb-2 md:sticky md:flex" 13 | > 14 | <div class="py-6 pr-6 lg:py-8"> 15 | <SidebarNav /> 16 | </div> 17 | <div class="sticky bottom-0 flex w-full justify-center rounded-xl bg-neutral-800 px-4 py-3"> 18 | <Switch id="preprocessor" bind:checked={$usingPreprocessor} keepState> 19 | <a href="/docs/preprocessor" class="underline transition hover:opacity-75"> 20 | Preprocessor 21 | </a> 22 | </Switch> 23 | </div> 24 | </aside> 25 | <div id="main" class="mx-auto w-full min-w-0"> 26 | <slot /> 27 | </div> 28 | </div> 29 | -------------------------------------------------------------------------------- /src/routes/docs/+page.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit'; 2 | import type { PageLoad } from './$types.js'; 3 | 4 | export const load: PageLoad = async () => { 5 | redirect(302, '/docs/introduction'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/routes/docs/[...slug]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { navConfig } from '$docs/config.js'; 2 | import type { EntryGenerator } from './$types.js'; 3 | 4 | export const entries = (() => { 5 | return navConfig.sidebarNav[0].items.map((item) => { 6 | return { slug: item.title.toLowerCase().replaceAll(' ', '-') }; 7 | }); 8 | }) satisfies EntryGenerator; 9 | -------------------------------------------------------------------------------- /src/routes/docs/[...slug]/+page.ts: -------------------------------------------------------------------------------- 1 | import type { EntryGenerator, PageLoad } from './$types.js'; 2 | import { getDoc } from '$docs/utils/index.js'; 3 | import { navConfig } from '$docs/config.js'; 4 | 5 | export const entries = (() => { 6 | return navConfig.sidebarNav[0].items.map((item) => { 7 | return { slug: item.title.toLowerCase().replaceAll(' ', '-') }; 8 | }); 9 | }) satisfies EntryGenerator; 10 | 11 | export const load: PageLoad = async (event) => { 12 | const doc = await getDoc(event.params.slug); 13 | 14 | return { 15 | component: doc.default, 16 | metadata: doc.metadata, 17 | title: doc.metadata.title, 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /src/routes/docs/builders/+page.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit'; 2 | import type { PageLoad } from './$types.js'; 3 | 4 | export const load: PageLoad = () => { 5 | redirect(302, '/docs/builders/accordion'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/routes/docs/builders/[name]/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { builderMap, isBuilderName } from '$docs/data/builders/index.js'; 2 | import { getAllPreviewSnippets, getBuilderData } from '$docs/utils/index.js'; 3 | import { error } from '@sveltejs/kit'; 4 | import type { EntryGenerator } from './$types.js'; 5 | 6 | export const entries = (() => { 7 | return Object.keys(builderMap).map((item) => { 8 | return { name: item.toLowerCase() }; 9 | }); 10 | }) satisfies EntryGenerator; 11 | 12 | export const load = async ({ params }) => { 13 | if (!isBuilderName(params.name)) { 14 | error(404); 15 | } 16 | 17 | return { 18 | snippets: await getAllPreviewSnippets(params.name), 19 | builderData: await getBuilderData(params.name), 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /src/routes/docs/builders/[name]/+page.ts: -------------------------------------------------------------------------------- 1 | import { builderMap, isBuilderName } from '$docs/data/builders/index.js'; 2 | import { getAllPreviewComponents, getDocData, getMainPreviewComponent } from '$docs/utils/index.js'; 3 | import { error } from '@sveltejs/kit'; 4 | import type { EntryGenerator } from './$types.js'; 5 | 6 | export const entries = (() => { 7 | return Object.keys(builderMap).map((item) => { 8 | return { name: item.toLowerCase() }; 9 | }); 10 | }) satisfies EntryGenerator; 11 | 12 | export const load = async ({ params, data }) => { 13 | if (!isBuilderName(params.name)) { 14 | error(404); 15 | } 16 | 17 | return { 18 | ...data, 19 | mainPreview: await getMainPreviewComponent(params.name), 20 | doc: await getDocData(params.name), 21 | previews: await getAllPreviewComponents(params.name), 22 | }; 23 | }; 24 | -------------------------------------------------------------------------------- /src/routes/repro/+page.ts: -------------------------------------------------------------------------------- 1 | import { redirect } from '@sveltejs/kit'; 2 | import type { PageLoad } from './$types.js'; 3 | 4 | export const load: PageLoad = async () => { 5 | redirect(303, 'https://stackblitz.com/github/melt-ui/template'); 6 | }; 7 | -------------------------------------------------------------------------------- /src/routes/store.ts: -------------------------------------------------------------------------------- 1 | import { browser } from '$app/environment'; 2 | import { get, writable, type Updater } from 'svelte/store'; 3 | 4 | const USING_PREPROCESSOR_KEY = 'melt-using-preprocessor'; 5 | 6 | const { subscribe, set } = writable(true); 7 | 8 | export function getUsingPreprocessor() { 9 | if (browser) { 10 | let parsedStored = true; 11 | try { 12 | parsedStored = JSON.parse(localStorage.getItem(USING_PREPROCESSOR_KEY) ?? 'true'); 13 | } catch (_e) { 14 | /** empty */ 15 | } 16 | set(parsedStored); 17 | } 18 | return { 19 | subscribe, 20 | set(newValue: boolean) { 21 | localStorage.setItem(USING_PREPROCESSOR_KEY, JSON.stringify(newValue)); 22 | set(newValue); 23 | }, 24 | update(updateFunction: Updater<boolean>) { 25 | const oldValue = get({ subscribe }); 26 | const newValue = updateFunction(oldValue); 27 | localStorage.setItem(USING_PREPROCESSOR_KEY, JSON.stringify(newValue)); 28 | set(newValue); 29 | }, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /src/stories/Collapsible/Collapsible.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/svelte'; 2 | 3 | import Collapsible from './Collapsible.svelte'; 4 | 5 | // More on how to set up stories at: https://storybook.js.org/docs/svelte/writing-stories/introduction 6 | const meta = { 7 | title: 'Components/Collapsible', 8 | component: Collapsible, 9 | argTypes: { 10 | defaultOpen: { control: 'boolean', defaultValue: false }, 11 | disabled: { control: 'boolean' }, 12 | }, 13 | } satisfies Meta<Collapsible>; 14 | 15 | export default meta; 16 | export type Story = StoryObj<typeof meta>; 17 | export type StoryProps = Story['args']; 18 | 19 | // More on writing stories with args: https://storybook.js.org/docs/svelte/writing-stories/args 20 | export const Example: Story = { 21 | args: { 22 | defaultOpen: false, 23 | disabled: false, 24 | onOpenChange: undefined, 25 | }, 26 | }; 27 | -------------------------------------------------------------------------------- /src/stories/Dialog/BaseDialog.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createDialog, melt } from '$lib/index.js'; 3 | 4 | const { 5 | elements: { overlay, content, title, description, close, portalled, trigger }, 6 | } = createDialog({ 7 | portal: '#preview', 8 | }); 9 | </script> 10 | 11 | <div use:melt={$portalled}> 12 | <div use:melt={$overlay} class="fixed inset-0 z-40 bg-black/50" /> 13 | <div 14 | class="fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-[90vw] max-w-[450px] 15 | -translate-x-1/2 -translate-y-1/2 rounded-md bg-white p-6 16 | shadow-lg" 17 | use:melt={$content} 18 | > 19 | <slot title={$title} description={$description} close={$close} name="content" /> 20 | </div> 21 | </div> 22 | <slot trigger={$trigger} /> 23 | -------------------------------------------------------------------------------- /src/stories/Dialog/Dialog.stories.ts: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from '@storybook/svelte'; 2 | 3 | import Dialog from './Dialog.svelte'; 4 | import NestedDialog from './NestedDialog.svelte'; 5 | import WithSelectCmp from './WithSelect.svelte'; 6 | 7 | // More on how to set up stories at: https://storybook.js.org/docs/svelte/writing-stories/introduction 8 | const meta = { 9 | title: 'Components/Dialog', 10 | component: Dialog, 11 | argTypes: {}, 12 | } satisfies Meta<Dialog>; 13 | 14 | export default meta; 15 | type Story = StoryObj<typeof meta>; 16 | 17 | // More on writing stories with args: https://storybook.js.org/docs/svelte/writing-stories/args 18 | export const Example: Story = { 19 | args: {}, 20 | }; 21 | 22 | export const Nested: Story = { 23 | render: () => ({ 24 | Component: NestedDialog, 25 | }), 26 | }; 27 | 28 | export const WithSelect: Story = { 29 | render: () => ({ 30 | Component: WithSelectCmp, 31 | }), 32 | }; 33 | -------------------------------------------------------------------------------- /src/tests/accordion/AccordionTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createAccordion, type CreateAccordionProps, melt } from '$lib/index.js'; 3 | 4 | export let multiple = false; 5 | export let disabled: CreateAccordionProps['disabled'] = undefined; 6 | export let items: { id: string; triggerId: string; title: string; description: string }[] = []; 7 | 8 | const { 9 | elements: { root, content, item, trigger }, 10 | helpers: { isSelected }, 11 | } = createAccordion({ multiple, disabled }); 12 | </script> 13 | 14 | <div use:melt={$root}> 15 | {#each items as { id, triggerId, title, description }} 16 | <div use:melt={$item(id)} data-testid={id}> 17 | <h2 class="flex"> 18 | <button data-testid={triggerId} use:melt={$trigger(id)}> 19 | {title} 20 | </button> 21 | </h2> 22 | {#if $isSelected(id)} 23 | <div use:melt={$content(id)}> 24 | {description} 25 | </div> 26 | {/if} 27 | </div> 28 | {/each} 29 | </div> 30 | -------------------------------------------------------------------------------- /src/tests/avatar/Avatar.spec.ts: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/svelte'; 2 | import { describe } from 'vitest'; 3 | import AvatarTest from './AvatarTest.svelte'; 4 | 5 | describe('Avatar', () => { 6 | test('renders the image with the correct src', () => { 7 | const { getByAltText } = render(AvatarTest, { 8 | props: { src: 'https://example.com/image.jpg' }, 9 | }); 10 | expect(getByAltText('Avatar')).toHaveAttribute('src', 'https://example.com/image.jpg'); 11 | }); 12 | 13 | test('renders the fallback with the correct text', () => { 14 | const { getByText } = render(AvatarTest, { 15 | props: { src: '' }, 16 | }); 17 | expect(getByText('RH')).toBeInTheDocument(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/tests/avatar/AvatarTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createAvatar, melt } from '$lib/index.js'; 3 | 4 | export let src = 'https://avatars.githubusercontent.com/u/1162160?v=4'; 5 | 6 | const { 7 | elements: { image, fallback }, 8 | } = createAvatar({ 9 | src, 10 | }); 11 | </script> 12 | 13 | <div class="flex h-24 w-24 items-center justify-center rounded-full bg-neutral-100"> 14 | <img use:melt={$image} alt="Avatar" class="h-full w-full rounded-[inherit]" data-testid="image" /> 15 | <span use:melt={$fallback} class="text-3xl font-medium text-black" data-testid="fallback">RH</span 16 | > 17 | </div> 18 | -------------------------------------------------------------------------------- /src/tests/checkbox/CheckboxTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createCheckbox, type CreateCheckboxProps, melt } from '$lib/index.js'; 3 | 4 | export let defaultChecked: CreateCheckboxProps['defaultChecked'] = 'indeterminate'; 5 | 6 | const { 7 | elements: { root }, 8 | helpers: { isChecked }, 9 | } = createCheckbox({ 10 | defaultChecked, 11 | }); 12 | </script> 13 | 14 | <main> 15 | <button use:melt={$root} data-testid="checkbox"> 16 | {#if $isChecked} 17 | checked 18 | {:else} 19 | not-checked 20 | {/if} 21 | </button> 22 | </main> 23 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/ComboboxTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createCombobox, melt, type CreateComboboxProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateComboboxProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { input, menu }, 9 | states: { open }, 10 | } = createCombobox({ ...$restProps, forceVisible: true }); 11 | </script> 12 | 13 | <input use:melt={$input} data-testid="combobox-trigger" /> 14 | {#if $open} 15 | <div use:melt={$menu} data-testid="combobox-content"> 16 | <button 17 | data-testid="combobox-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/DialogTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createDialog, melt, type CreateDialogProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateDialogProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | export let escapeBehavior: CreateDialogProps['escapeBehavior'] = 'close'; 8 | 9 | const { 10 | elements: { trigger, content, portalled }, 11 | states: { open }, 12 | } = createDialog({ escapeBehavior, forceVisible: true }); 13 | </script> 14 | 15 | <button use:melt={$trigger} data-testid="dialog-trigger">Open</button> 16 | {#if $open} 17 | <div use:melt={$portalled}> 18 | <div use:melt={$content} data-testid="dialog-content"> 19 | <button 20 | data-testid="dialog-set-parent-escape-behavior-ignore" 21 | on:click={setRootEscapeBehaviorIgnore} 22 | > 23 | set root escapeBehavior: ignore 24 | </button> 25 | </div> 26 | </div> 27 | {/if} 28 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/LinkPreviewTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createLinkPreview, melt, type CreateLinkPreviewProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateLinkPreviewProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { trigger, content }, 9 | states: { open }, 10 | } = createLinkPreview({ ...$restProps, forceVisible: true, openDelay: 0, closeDelay: 0 }); 11 | </script> 12 | 13 | <button use:melt={$trigger} data-testid="link-preview-trigger">trigger</button> 14 | {#if $open} 15 | <div use:melt={$content} data-testid="link-preview-content"> 16 | <button 17 | data-testid="link-preview-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/MenuTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createDropdownMenu, melt, type CreateDropdownMenuProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateDropdownMenuProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { trigger, menu }, 9 | states: { open }, 10 | } = createDropdownMenu({ ...$restProps, forceVisible: true }); 11 | </script> 12 | 13 | <button use:melt={$trigger} data-testid="menu-trigger">trigger</button> 14 | {#if $open} 15 | <div use:melt={$menu} data-testid="menu-content"> 16 | <button 17 | data-testid="menu-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/MenubarTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createMenubar, melt, type CreateMenubarMenuProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateMenubarMenuProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let escapeBehavior: CreateMenubarMenuProps['escapeBehavior'] = 'close'; 6 | export let setRootEscapeBehaviorIgnore: () => void; 7 | 8 | const { 9 | elements: { menubar }, 10 | builders: { createMenu }, 11 | } = createMenubar({ escapeBehavior }); 12 | 13 | const { 14 | elements: { trigger, menu }, 15 | states: { open }, 16 | } = createMenu({ ...$restProps, escapeBehavior, forceVisible: true }); 17 | </script> 18 | 19 | <div use:melt={$menubar}> 20 | <button use:melt={$trigger} data-testid="menubar-trigger">trigger</button> 21 | {#if $open} 22 | <div use:melt={$menu} data-testid="menubar-content"> 23 | <button 24 | data-testid="menubar-set-parent-escape-behavior-ignore" 25 | on:click={setRootEscapeBehaviorIgnore} 26 | > 27 | set root escapeBehavior: ignore 28 | </button> 29 | </div> 30 | {/if} 31 | </div> 32 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/PopoverTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createPopover, melt, type CreatePopoverProps } from '$lib/index.js'; 3 | 4 | type $Props = CreatePopoverProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { trigger, content }, 9 | states: { open }, 10 | } = createPopover({ ...$restProps, forceVisible: true }); 11 | </script> 12 | 13 | <button use:melt={$trigger} data-testid="popover-trigger">trigger</button> 14 | {#if $open} 15 | <div use:melt={$content} data-testid="popover-content"> 16 | <button 17 | data-testid="popover-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/SelectTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSelect, melt, type CreateSelectProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateSelectProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { trigger, menu }, 9 | states: { open }, 10 | } = createSelect({ ...$restProps, forceVisible: true }); 11 | </script> 12 | 13 | <button use:melt={$trigger} data-testid="select-trigger">trigger</button> 14 | {#if $open} 15 | <div use:melt={$menu} data-testid="select-content"> 16 | <button 17 | data-testid="select-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/escape-keydown/TooltipTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createTooltip, melt, type CreateTooltipProps } from '$lib/index.js'; 3 | 4 | type $Props = CreateTooltipProps & { setRootEscapeBehaviorIgnore: () => void }; 5 | export let setRootEscapeBehaviorIgnore: () => void; 6 | 7 | const { 8 | elements: { trigger, content }, 9 | states: { open }, 10 | } = createTooltip({ ...$restProps, forceVisible: true, openDelay: 0, closeDelay: 0 }); 11 | </script> 12 | 13 | <button use:melt={$trigger} data-testid="tooltip-trigger">trigger</button> 14 | {#if $open} 15 | <div use:melt={$content} data-testid="tooltip-content"> 16 | <button 17 | data-testid="tooltip-set-parent-escape-behavior-ignore" 18 | on:click={setRootEscapeBehaviorIgnore} 19 | > 20 | set root escapeBehavior: ignore 21 | </button> 22 | </div> 23 | {/if} 24 | -------------------------------------------------------------------------------- /src/tests/hidden-input/HiddenInputTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts" context="module"> 2 | export type HiddenInputProps = CreateHiddenInputProps & { 3 | onChange?: (event: Event) => void; 4 | }; 5 | </script> 6 | 7 | <script lang="ts"> 8 | import { melt } from '$lib/index.js'; 9 | import { 10 | createHiddenInput, 11 | type CreateHiddenInputProps, 12 | } from '$lib/builders/hidden-input/index.js'; 13 | import { noop } from '$lib/internal/helpers/callbacks.js'; 14 | 15 | type $Props = HiddenInputProps; 16 | export let name: $Props['name'] = undefined; 17 | export let value: $Props['value']; 18 | export let disabled: $Props['disabled'] = undefined; 19 | export let required: $Props['required'] = undefined; 20 | export let onChange: $Props['onChange'] = noop; 21 | 22 | const hiddenInput = createHiddenInput({ 23 | name, 24 | value, 25 | disabled, 26 | required, 27 | }); 28 | </script> 29 | 30 | <input use:melt={$hiddenInput} on:change={onChange} data-testid="input" /> 31 | -------------------------------------------------------------------------------- /src/tests/label/Label.spec.ts: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/svelte'; 2 | import { it, describe } from 'vitest'; 3 | import LabelTest from './LabelTest.svelte'; 4 | import { userEvent } from '@testing-library/user-event'; 5 | 6 | describe('LabelTest', () => { 7 | it('renders the label with the correct text', () => { 8 | const { getByText } = render(LabelTest, { props: { inputId: 'test' } }); 9 | expect(getByText('Test')).toBeInTheDocument(); 10 | }); 11 | 12 | it('focuses the input when the label is clicked', async () => { 13 | const { getByTestId } = render(LabelTest); 14 | const label = getByTestId('label'); 15 | const input = getByTestId('input'); 16 | await userEvent.click(label); 17 | expect(input).toHaveFocus(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/tests/label/LabelTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createLabel } from '$lib/index.js'; 3 | 4 | export let inputId = 'test'; 5 | 6 | const { 7 | elements: { root }, 8 | } = createLabel(); 9 | </script> 10 | 11 | <form> 12 | <div> 13 | <label use:root for={inputId} data-testid="label"> 14 | <span>Test</span> 15 | <input type="text" id={inputId} data-testid="input" /> 16 | </label> 17 | </div> 18 | </form> 19 | -------------------------------------------------------------------------------- /src/tests/pagination/cmp.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createPagination, melt } from '$lib/index.js'; 3 | import { ChevronLeft, ChevronRight } from '$icons/index.js'; 4 | 5 | const { 6 | elements: { prevButton, nextButton, pageTrigger, root }, 7 | states: { range, pages }, 8 | } = createPagination({ 9 | count: 100, 10 | perPage: 10, 11 | defaultPage: 1, 12 | siblingCount: 1, 13 | }); 14 | </script> 15 | 16 | <nav aria-label="pagination" use:melt={$root} data-testid="root"> 17 | <p> 18 | Showing items {$range.start} - {$range.end} 19 | </p> 20 | <div> 21 | <button use:melt={$prevButton} data-testid="prev"><ChevronLeft class="size-4" /></button> 22 | {#each $pages as page (page.key)} 23 | {#if page.type === 'ellipsis'} 24 | <span>...</span> 25 | {:else} 26 | <button use:melt={$pageTrigger(page)}>{page.value}</button> 27 | {/if} 28 | {/each} 29 | <button use:melt={$nextButton} data-testid="next"><ChevronRight class="size-4" /></button> 30 | </div> 31 | </nav> 32 | -------------------------------------------------------------------------------- /src/tests/pin-input/PinInputTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createPinInput, melt, type CreatePinInputProps } from '$lib/index.js'; 3 | 4 | export let placeholder: CreatePinInputProps['placeholder'] = '○'; 5 | export let name: CreatePinInputProps['name'] = undefined; 6 | export let disabled: CreatePinInputProps['disabled'] = false; 7 | export let type: CreatePinInputProps['type'] = 'text'; 8 | export let defaultValue: CreatePinInputProps['defaultValue'] = ['1', '2', '3', '4', '5']; 9 | export let value: CreatePinInputProps['value'] = undefined; 10 | export let onValueChange: CreatePinInputProps['onValueChange'] = undefined; 11 | 12 | const { 13 | elements: { root, input, hiddenInput }, 14 | } = createPinInput({ 15 | placeholder, 16 | name, 17 | disabled, 18 | type, 19 | defaultValue, 20 | value, 21 | onValueChange, 22 | }); 23 | </script> 24 | 25 | <main> 26 | <div use:melt={$root} data-testid="root"> 27 | {#each Array(5) as _, i} 28 | <input use:melt={$input()} data-testid="input-{i + 1}" /> 29 | {/each} 30 | <input use:melt={$hiddenInput} data-testid="hidden-input" /> 31 | </div> 32 | </main> 33 | -------------------------------------------------------------------------------- /src/tests/portal/DropdownMenu.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createDropdownMenu, melt, type CreateDropdownMenuProps } from '$lib/index.js'; 3 | import { initLevel } from './level.js'; 4 | 5 | type $Props = CreateDropdownMenuProps; 6 | 7 | export let portal: CreateDropdownMenuProps['portal'] = undefined; 8 | export let forceVisible: CreateDropdownMenuProps['forceVisible'] = false; 9 | 10 | const { 11 | elements: { trigger, menu, item }, 12 | states: { open }, 13 | } = createDropdownMenu({ forceVisible, portal, ...$restProps }); 14 | 15 | const level = initLevel(); 16 | </script> 17 | 18 | <button use:melt={$trigger} data-testid="dropdown-menu-trigger-{level}">Open Popover</button> 19 | 20 | {#if $open || !forceVisible} 21 | <div class="menu" use:melt={$menu} data-testid="dropdown-menu-content-{level}"> 22 | <div class="item" use:melt={$item}>Item 1</div> 23 | <div class="item" use:melt={$item}>Item 2</div> 24 | <slot /> 25 | </div> 26 | {/if} 27 | <div data-testid="dropdown-menu-outside-{level}" /> 28 | -------------------------------------------------------------------------------- /src/tests/portal/level.ts: -------------------------------------------------------------------------------- 1 | import { getContext, setContext } from 'svelte'; 2 | 3 | export const initLevel = () => { 4 | const level = (getContext('level') || 0) as number; 5 | setContext('level', level + 1); 6 | return level; 7 | }; 8 | -------------------------------------------------------------------------------- /src/tests/separator/Separator.spec.ts: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/svelte'; 2 | import { describe } from 'vitest'; 3 | import SeparatorTest from './SeparatorTest.svelte'; 4 | 5 | describe('Separator', async () => { 6 | it('should render an horizontal separator', async () => { 7 | const { getByTestId } = await render(SeparatorTest); 8 | await expect(getByTestId('horizontal')).toBeVisible(); 9 | }); 10 | 11 | it('should render a vertical separator', async () => { 12 | const { getByTestId } = await render(SeparatorTest, { orientation: 'vertical' }); 13 | await expect(getByTestId('vertical')).toBeVisible(); 14 | }); 15 | 16 | it('should have a role of separator', async () => { 17 | const { getByTestId } = await render(SeparatorTest, { orientation: 'vertical' }); 18 | await expect(getByTestId('vertical')).toHaveAttribute('role', 'separator'); 19 | }); 20 | 21 | it('should have a role of none when decorative is true', async () => { 22 | const { getByTestId } = await render(SeparatorTest); 23 | await expect(getByTestId('horizontal')).toHaveAttribute('role', 'none'); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/tests/separator/SeparatorTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import type { Orientation } from '$lib/internal/types.js'; 3 | import { createSeparator, melt } from '$lib/index.js'; 4 | 5 | export let orientation: Orientation = 'vertical'; 6 | 7 | const { 8 | elements: { root: vertical }, 9 | } = createSeparator({ 10 | orientation, 11 | }); 12 | 13 | const { 14 | elements: { root: horizontalSeparator }, 15 | } = createSeparator({ 16 | orientation: 'horizontal', 17 | decorative: true, 18 | }); 19 | </script> 20 | 21 | <div> 22 | <h2>Separator</h2> 23 | <div use:melt={$horizontalSeparator} data-testid="horizontal" /> 24 | <div> 25 | <p>Part 1</p> 26 | <div use:melt={$vertical} data-testid="vertical" /> 27 | <p>Part 2</p> 28 | </div> 29 | </div> 30 | -------------------------------------------------------------------------------- /src/tests/slider/RangeSlider.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSlider, melt } from '$lib/index.js'; 3 | 4 | export let values = [20, 80]; 5 | 6 | const { 7 | elements: { root, range, thumbs, ticks }, 8 | } = createSlider({ 9 | defaultValue: values, 10 | max: 100, 11 | }); 12 | </script> 13 | 14 | <main> 15 | <span use:melt={$root} class="relative flex h-[20px] w-[200px] items-center"> 16 | <span class="block h-[3px] w-full bg-black/40"> 17 | <span data-testid="range" use:melt={$range} class="h-[3px] bg-white" /> 18 | </span> 19 | 20 | {#each $ticks as tick} 21 | <span use:melt={tick} data-testid="tick" /> 22 | {/each} 23 | 24 | {#each $thumbs as thumb, i} 25 | <span 26 | aria-label="Volume" 27 | data-testid="thumb-{i}" 28 | use:melt={thumb} 29 | class="block h-5 w-5 rounded-full bg-white focus:ring-4 focus:ring-black/40" 30 | /> 31 | {/each} 32 | </span> 33 | </main> 34 | -------------------------------------------------------------------------------- /src/tests/switch/SwitchTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createSwitch, melt, type CreateSwitchProps } from '$lib/index.js'; 3 | 4 | export let checked: CreateSwitchProps['checked'] = undefined; 5 | export let defaultChecked: CreateSwitchProps['defaultChecked'] = undefined; 6 | export let disabled: CreateSwitchProps['disabled'] = undefined; 7 | export let name: CreateSwitchProps['name'] = undefined; 8 | export let onCheckedChange: CreateSwitchProps['onCheckedChange'] = undefined; 9 | export let required: CreateSwitchProps['required'] = undefined; 10 | export let value: CreateSwitchProps['value'] = undefined; 11 | 12 | const { 13 | elements: { root, input }, 14 | } = createSwitch({ 15 | checked, 16 | defaultChecked, 17 | disabled, 18 | name, 19 | onCheckedChange, 20 | required, 21 | value, 22 | }); 23 | </script> 24 | 25 | <main> 26 | <form> 27 | <label id="switch-label" for="switch" data-testid="label"> Airplane mode </label> 28 | <button use:melt={$root} id="switch" aria-labelledby="switch-label" data-testid="switch" /> 29 | <input use:melt={$input} data-testid="input" /> 30 | </form> 31 | </main> 32 | -------------------------------------------------------------------------------- /src/tests/tabs/TabsTest.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { type CreateTabsProps, melt, createTabs } from '$lib/index.js'; 3 | 4 | type $Props = CreateTabsProps & { 5 | tabValues: string[]; 6 | }; 7 | 8 | export let tabValues: string[] = []; 9 | 10 | const { 11 | elements: { content, root, list, trigger }, 12 | } = createTabs({ 13 | ...($restProps as $Props), 14 | }); 15 | </script> 16 | 17 | <main> 18 | <div use:melt={$root} data-testid="root"> 19 | <div use:melt={$list} data-testid="list"> 20 | {#each tabValues as tab} 21 | <button use:melt={$trigger(tab)} data-testid="{tab}-trigger"> 22 | {tab} 23 | </button> 24 | {/each} 25 | </div> 26 | {#each tabValues as tab} 27 | <div use:melt={$content(tab)} data-testid="{tab}-content"> 28 | {tab} 29 | </div> 30 | {/each} 31 | </div> 32 | </main> 33 | -------------------------------------------------------------------------------- /src/tests/tags-input/TagsInput.svelte: -------------------------------------------------------------------------------- 1 | <script lang="ts"> 2 | import { createTagsInput, melt, type AddTag } from '$lib/index.js'; 3 | 4 | export let defaultTags = ['Svelte', 'Typescript']; 5 | export let unique = true; 6 | export let trim = true; 7 | export let allowed: string[] | undefined = undefined; 8 | export let add: AddTag | undefined = undefined; 9 | const { 10 | elements: { root, input, tag, deleteTrigger, edit }, 11 | states: { tags }, 12 | } = createTagsInput({ 13 | defaultTags, 14 | unique, 15 | allowed, 16 | add, 17 | trim, 18 | }); 19 | </script> 20 | 21 | <main> 22 | <div use:melt={$root}> 23 | {#each $tags as t, i} 24 | <div data-testid="tag-{i}" use:melt={$tag(t)}> 25 | <span>{t.value}</span> 26 | <button data-testid="delete-tag-{i}" use:melt={$deleteTrigger(t)}> Delete </button> 27 | </div> 28 | <div data-testid="edit-tag-{i}" use:melt={$edit(t)} /> 29 | {/each} 30 | 31 | <input use:melt={$input} type="text" placeholder="Enter tags..." /> 32 | </div> 33 | </main> 34 | -------------------------------------------------------------------------------- /static/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/static/banner.png -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melt-ui/melt-ui/3ddf5f1c814801b376b1481b527e18f9f948e89f/static/favicon.png -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "module": "NodeNext", 13 | "moduleResolution": "NodeNext", 14 | }, 15 | "exclude": [ 16 | "*.ignore-ts", 17 | "*.ignore-svelte", 18 | "src/routes/old/builders/**/(css)/*", 19 | "src/routes/old/builders/**/(tailwind)/*", 20 | "src/pagefind/**/*", 21 | "static/pagefind/**/*", 22 | ] 23 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 24 | // 25 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 26 | // from the referenced tsconfig.json - TypeScript does not merge them in 27 | } -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "github": { 3 | "silent": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vitest/config'; 3 | import { pagefind } from 'vite-plugin-pagefind'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | sveltekit(), 8 | pagefind({ publicDir: 'static', buildDir: 'build', buildScript: 'deploy' }), 9 | ], 10 | test: { 11 | include: ['src/**/*.spec.{js,ts}'], 12 | // jest like globals 13 | globals: true, 14 | environment: 'jsdom', 15 | // in-source testing 16 | includeSource: ['src/**/*.{js,ts,svelte}'], 17 | // Add @testing-library/jest-dom matchers & mocks of SvelteKit modules 18 | setupFiles: ['./scripts/setupTest.ts'], 19 | // Exclude files in v8 20 | coverage: { 21 | exclude: ['setupTest.ts'], 22 | }, 23 | alias: [{ find: /^svelte$/, replacement: 'svelte/internal' }], 24 | deps: { 25 | inline: ['clsx'], 26 | }, 27 | retry: 5, 28 | allowOnly: !process.env.CI, 29 | }, 30 | }); 31 | --------------------------------------------------------------------------------