@melt-ui/svelte
Advanced tools
Comparing version 0.42.0 to 0.43.0
/// <reference types="svelte" /> | ||
import type { MeltActionReturn } from '../../internal/types.js'; | ||
import { type Writable } from 'svelte/store'; | ||
import { type Readable, type Writable } from 'svelte/store'; | ||
import type { ComboboxEvents } from './events.js'; | ||
@@ -41,2 +41,3 @@ import type { ComboboxItemProps, ComboboxOption, CreateComboboxProps } from './types.js'; | ||
readonly 'aria-labelledby': string; | ||
readonly 'data-melt-id': string; | ||
readonly autocomplete: "off"; | ||
@@ -94,3 +95,3 @@ readonly id: string; | ||
}, string>; | ||
menu: import("../../internal/helpers/index.js").ExplicitBuilderReturn<[import("svelte/store").Readable<boolean>], (node: HTMLElement) => MeltActionReturn<ComboboxEvents['menu']>, ([$isVisible]: [boolean]) => { | ||
menu: import("../../internal/helpers/index.js").ExplicitBuilderReturn<[Readable<boolean>], (node: HTMLElement) => MeltActionReturn<ComboboxEvents['menu']>, ([$isVisible]: [boolean]) => { | ||
readonly hidden: true | undefined; | ||
@@ -117,2 +118,3 @@ readonly id: string; | ||
}; | ||
highlighted: Readable<ComboboxOption<Value> | undefined>; | ||
inputValue: { | ||
@@ -131,6 +133,7 @@ debouncedSet: (value: string) => void; | ||
}; | ||
isEmpty: import("svelte/store").Readable<boolean>; | ||
isEmpty: Readable<boolean>; | ||
}; | ||
helpers: { | ||
isSelected: import("svelte/store").Readable<(item: Value) => boolean>; | ||
isSelected: Readable<(item: Value) => boolean>; | ||
isHighlighted: Readable<(item: Value) => boolean>; | ||
}; | ||
@@ -137,0 +140,0 @@ options: { |
import { useEscapeKeydown, usePopper } from '../../internal/actions/index.js'; | ||
import { FIRST_LAST_KEYS, addHighlight, addMeltEventListener, back, builder, createElHelpers, derivedVisible, effect, executeCallbacks, forward, generateId, getOptions, getPortalDestination, isBrowser, isElementDisabled, isHTMLElement, isHTMLInputElement, kbd, last, next, noop, omit, overridable, prev, removeHighlight, removeScroll, sleep, styleToString, toWritableStores, } from '../../internal/helpers/index.js'; | ||
import { FIRST_LAST_KEYS, addHighlight, addMeltEventListener, back, builder, createClickOutsideIgnore, createElHelpers, derivedVisible, effect, executeCallbacks, forward, generateId, getElementByMeltId, getOptions, getPortalDestination, isBrowser, isElementDisabled, isHTMLElement, isHTMLInputElement, kbd, last, next, noop, omit, overridable, prev, removeHighlight, removeScroll, sleep, styleToString, toWritableStores, } from '../../internal/helpers/index.js'; | ||
import { debounceable } from '../../internal/helpers/store/index.js'; | ||
@@ -43,2 +43,3 @@ import { dequal as deepEqual } from 'dequal'; | ||
const selected = overridable(selectedWritable, withDefaults?.onSelectedChange); | ||
const highlighted = derived(highlightedItem, ($highlightedItem) => $highlightedItem ? getOptionProps($highlightedItem) : undefined); | ||
// The current value of the input element. | ||
@@ -91,3 +92,3 @@ const inputValue = debounceable(withDefaults.defaultSelected?.label ?? '', withDefaults.debounce); | ||
selected.set(props); | ||
const activeTrigger = document.getElementById(ids.input); | ||
const activeTrigger = getElementByMeltId(ids.input); | ||
if (activeTrigger) { | ||
@@ -131,3 +132,3 @@ activeTrigger.focus(); | ||
} | ||
const triggerEl = document.getElementById(ids.input); | ||
const triggerEl = getElementByMeltId(ids.input); | ||
if (!triggerEl) | ||
@@ -165,2 +166,11 @@ return; | ||
}); | ||
/** | ||
* Determines if a given item is highlighted. | ||
* This is useful for displaying additional markup on the highlighted item. | ||
*/ | ||
const isHighlighted = derived([highlighted], ([$value]) => { | ||
return (item) => { | ||
return deepEqual($value?.value, item); | ||
}; | ||
}); | ||
/** -------- */ | ||
@@ -179,2 +189,3 @@ /** ELEMENTS */ | ||
'aria-labelledby': ids.label, | ||
'data-melt-id': ids.input, | ||
autocomplete: 'off', | ||
@@ -373,2 +384,3 @@ id: ids.input, | ||
} | ||
const ignoreHandler = createClickOutsideIgnore(ids.input); | ||
const popper = usePopper(node, { | ||
@@ -389,2 +401,3 @@ anchorElement: $activeTrigger, | ||
}, | ||
ignore: ignoreHandler, | ||
} | ||
@@ -489,3 +502,3 @@ : null, | ||
return; | ||
const triggerEl = document.getElementById(ids.input); | ||
const triggerEl = getElementByMeltId(ids.input); | ||
if (triggerEl) { | ||
@@ -538,3 +551,4 @@ activeTrigger.set(triggerEl); | ||
selected, | ||
inputValue: inputValue, | ||
highlighted, | ||
inputValue, | ||
isEmpty: readonly(isEmpty), | ||
@@ -544,2 +558,3 @@ }, | ||
isSelected, | ||
isHighlighted, | ||
}, | ||
@@ -546,0 +561,0 @@ options, |
@@ -29,2 +29,3 @@ /// <reference types="svelte" /> | ||
readonly 'aria-labelledby': string; | ||
readonly 'data-melt-id': string; | ||
readonly disabled: boolean; | ||
@@ -31,0 +32,0 @@ readonly id: string; |
import { createLabel, createSeparator } from '../index.js'; | ||
import { usePopper } from '../../internal/actions/index.js'; | ||
import { FIRST_LAST_KEYS, SELECTION_KEYS, addEventListener, addHighlight, addMeltEventListener, back, builder, createElHelpers, createTypeaheadSearch, derivedVisible, effect, executeCallbacks, forward, generateId, getFirstOption, getNextFocusable, getOptions, getPortalDestination, getPreviousFocusable, handleRovingFocus, isBrowser, isElementDisabled, isHTMLElement, kbd, last, next, noop, omit, overridable, prev, removeHighlight, removeScroll, sleep, styleToString, toWritableStores, toggle, } from '../../internal/helpers/index.js'; | ||
import { FIRST_LAST_KEYS, SELECTION_KEYS, addEventListener, addHighlight, addMeltEventListener, back, builder, createClickOutsideIgnore, createElHelpers, createTypeaheadSearch, derivedVisible, effect, executeCallbacks, forward, generateId, getFirstOption, getNextFocusable, getOptions, getPortalDestination, getPreviousFocusable, handleRovingFocus, isBrowser, isElementDisabled, isHTMLElement, kbd, last, next, noop, omit, overridable, prev, removeHighlight, removeScroll, sleep, styleToString, toWritableStores, toggle, } from '../../internal/helpers/index.js'; | ||
import { dequal as deepEqual } from 'dequal'; | ||
import { onMount, tick } from 'svelte'; | ||
import { derived, get, writable } from 'svelte/store'; | ||
import { getElementByMeltId } from '../../internal/helpers/builder'; | ||
const defaults = { | ||
@@ -66,3 +68,3 @@ arrowSize: 8, | ||
} | ||
return $selected?.value === value; | ||
return deepEqual($selected?.value, value); | ||
}; | ||
@@ -191,2 +193,3 @@ }); | ||
} | ||
const ignoreHandler = createClickOutsideIgnore(ids.trigger); | ||
tick().then(() => { | ||
@@ -198,3 +201,7 @@ const popper = usePopper(node, { | ||
floating: $positioning, | ||
clickOutside: $closeOnOutsideClick ? undefined : null, | ||
clickOutside: $closeOnOutsideClick | ||
? { | ||
ignore: ignoreHandler, | ||
} | ||
: null, | ||
escapeKeydown: $closeOnEscape | ||
@@ -266,2 +273,3 @@ ? { | ||
'aria-labelledby': ids.label, | ||
'data-melt-id': ids.trigger, | ||
disabled: $disabled, | ||
@@ -415,3 +423,3 @@ id: ids.trigger, | ||
? $selected.map((o) => o.value).includes(props.value) | ||
: $selected?.value === props?.value; | ||
: deepEqual($selected?.value, props?.value); | ||
return { | ||
@@ -521,3 +529,3 @@ role: 'option', | ||
onMount(() => { | ||
const triggerEl = document.getElementById(ids.trigger); | ||
const triggerEl = getElementByMeltId(ids.trigger); | ||
if (triggerEl) { | ||
@@ -524,0 +532,0 @@ activeTrigger.set(triggerEl); |
@@ -20,10 +20,14 @@ import { type Writable } from 'svelte/store'; | ||
export declare function createTableOfContents(args: CreateTableOfContentsArgs): { | ||
activeHeadingIdxs: Writable<number[]>; | ||
headingsTree: Writable<TableOfContentsItem[]>; | ||
item: import("../../internal/helpers").ExplicitBuilderReturn<Writable<number[]>, (node: HTMLAnchorElement) => { | ||
destroy: () => void; | ||
}, ($activeHeadingIdxs: number[]) => (id: string) => { | ||
'data-id': string; | ||
'data-active': string | undefined; | ||
}, string>; | ||
elements: { | ||
item: import("../../internal/helpers").ExplicitBuilderReturn<Writable<number[]>, (node: HTMLAnchorElement) => { | ||
destroy: () => void; | ||
}, ($activeHeadingIdxs: number[]) => (id: string) => { | ||
'data-id': string; | ||
'data-active': string | undefined; | ||
}, string>; | ||
}; | ||
states: { | ||
activeHeadingIdxs: Writable<number[]>; | ||
headingsTree: Writable<TableOfContentsItem[]>; | ||
}; | ||
}; |
import { addEventListener, builder, createElHelpers, executeCallbacks, } from '../../internal/helpers'; | ||
import { onMount } from 'svelte'; | ||
import { get, writable } from 'svelte/store'; | ||
import { dequal } from 'dequal'; | ||
const defaults = { | ||
@@ -35,5 +36,5 @@ exclude: ['h1'], | ||
/** Lookup to see which heading an element belongs to. */ | ||
const elementHeadingLU = {}; | ||
let elementHeadingLU = {}; | ||
/** Lookup to see which parent headings a heading has. */ | ||
const headingParentsLU = {}; | ||
let headingParentsLU = {}; | ||
/** List of the active parent indexes. */ | ||
@@ -43,2 +44,4 @@ const activeParentIdxs = writable([]); | ||
const visibleElementIdxs = writable([]); | ||
let elementTarget = null; | ||
let mutationObserver = null; | ||
let observer = null; | ||
@@ -62,2 +65,3 @@ const observer_threshold = 0.25; | ||
id: arr[i].id, | ||
node: arr[i], | ||
children: [], | ||
@@ -77,5 +81,6 @@ }; | ||
} | ||
function generateInitialLists() { | ||
function generateInitialLists(elementTarget) { | ||
let headingsList = []; | ||
let elementsList = []; | ||
const includedHeadings = possibleHeadings.filter((h) => !exclude.includes(h)); | ||
const elementTarget = document.querySelector(selector); | ||
const targetHeaders = elementTarget?.querySelectorAll(includedHeadings.join(', ')); | ||
@@ -103,2 +108,6 @@ // Create a unique ID for each heading which doesn't have one. | ||
elementsList.splice(0, elementsList.indexOf(headingsList[0])); | ||
return { | ||
headingsList, | ||
elementsList | ||
}; | ||
} | ||
@@ -246,5 +255,18 @@ function findParentIdxs() { | ||
}); | ||
onMount(() => { | ||
// Init | ||
generateInitialLists(); | ||
function mutationHandler() { | ||
const newElementTarget = document.querySelector(selector); | ||
if (!newElementTarget) | ||
return; | ||
const { headingsList: newHeadingsList, elementsList: newElementsList } = generateInitialLists(newElementTarget); | ||
if (dequal(headingsList, newHeadingsList)) | ||
return; | ||
// Update lists and LUs and re-run initialization. | ||
headingsList = newHeadingsList; | ||
elementsList = newElementsList; | ||
headingParentsLU = {}; | ||
elementHeadingLU = {}; | ||
initialization(); | ||
} | ||
function initialization() { | ||
observer?.disconnect(); | ||
findParentIdxs(); | ||
@@ -261,11 +283,25 @@ createElementHeadingLU(); | ||
} | ||
} | ||
onMount(() => { | ||
elementTarget = document.querySelector(selector); | ||
if (!elementTarget) | ||
return; | ||
({ headingsList, elementsList } = generateInitialLists(elementTarget)); | ||
initialization(); | ||
mutationObserver = new MutationObserver(mutationHandler); | ||
mutationObserver.observe(elementTarget, { childList: true, subtree: true }); | ||
return () => { | ||
observer?.disconnect(); | ||
mutationObserver?.disconnect(); | ||
}; | ||
}); | ||
return { | ||
activeHeadingIdxs, | ||
headingsTree, | ||
item, | ||
elements: { | ||
item | ||
}, | ||
states: { | ||
activeHeadingIdxs, | ||
headingsTree | ||
} | ||
}; | ||
} |
@@ -38,4 +38,7 @@ import type { createTableOfContents } from './create'; | ||
id: string; | ||
node: HTMLHeadingElement; | ||
children?: TableOfContentsItem[]; | ||
}; | ||
export type CreateTableOfContentsReturn = ReturnType<typeof createTableOfContents>; | ||
export type TableOfContents = ReturnType<typeof createTableOfContents>; | ||
export type TableOfContentsElements = TableOfContents['elements']; | ||
export type TableOfContentsStates = TableOfContents['states']; |
@@ -24,1 +24,2 @@ export * from './array.js'; | ||
export * from './elements.js'; | ||
export * from './ignore.js'; |
@@ -24,1 +24,2 @@ export * from './array.js'; | ||
export * from './elements.js'; | ||
export * from './ignore.js'; |
@@ -6,2 +6,3 @@ export declare const isBrowser: boolean; | ||
export declare function isHTMLInputElement(element: unknown): element is HTMLInputElement; | ||
export declare function isHTMLLabelElement(element: unknown): element is HTMLLabelElement; | ||
export declare function isElementDisabled(element: HTMLElement): boolean; | ||
@@ -8,0 +9,0 @@ export declare function isTouch(event: PointerEvent): boolean; |
@@ -13,2 +13,5 @@ export const isBrowser = typeof document !== 'undefined'; | ||
} | ||
export function isHTMLLabelElement(element) { | ||
return element instanceof HTMLLabelElement; | ||
} | ||
export function isElementDisabled(element) { | ||
@@ -15,0 +18,0 @@ const ariaDisabled = element.getAttribute('aria-disabled'); |
{ | ||
"name": "@melt-ui/svelte", | ||
"version": "0.42.0", | ||
"version": "0.43.0", | ||
"license": "MIT", | ||
@@ -5,0 +5,0 @@ "exports": { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
597469
342
13850