UNPKG

@kobalte/core

Version:

Unstyled components and primitives for building accessible web apps and design systems with SolidJS.

263 lines (257 loc) 9.01 kB
import { createSelectableList } from './GLKC2QFF.js'; import { createListState, createSelectableItem } from './H6DSIDEC.js'; import { CollapsibleContent, useCollapsibleContext, CollapsibleRoot, CollapsibleTrigger } from './IN725QRS.js'; import { createDomCollection, createDomCollectionItem } from './7CVNMTYF.js'; import { createRegisterId } from './E4R2EMM4.js'; import { Polymorphic } from './6Y7B2NEO.js'; import { __export } from './5ZKAE4VZ.js'; import { createComponent, mergeProps } from 'solid-js/web'; import { mergeDefaultProps, createGenerateId, mergeRefs, composeEventHandlers, callHandler } from '@kobalte/utils'; import { createContext, splitProps, createEffect, onCleanup, useContext, createUniqueId, createSignal } from 'solid-js'; import { combineStyle } from '@solid-primitives/props'; // src/accordion/index.tsx var accordion_exports = {}; __export(accordion_exports, { Accordion: () => Accordion, Content: () => AccordionContent, Header: () => AccordionHeader, Item: () => AccordionItem, Root: () => AccordionRoot, Trigger: () => AccordionTrigger, useAccordionContext: () => useAccordionContext }); var AccordionItemContext = createContext(); function useAccordionItemContext() { const context = useContext(AccordionItemContext); if (context === void 0) { throw new Error("[kobalte]: `useAccordionItemContext` must be used within a `Accordion.Item` component"); } return context; } // src/accordion/accordion-content.tsx function AccordionContent(props) { const itemContext = useAccordionItemContext(); const defaultId = itemContext.generateId("content"); const mergedProps = mergeDefaultProps({ id: defaultId }, props); const [local, others] = splitProps(mergedProps, ["id", "style"]); createEffect(() => onCleanup(itemContext.registerContentId(local.id))); return createComponent(CollapsibleContent, mergeProps({ role: "region", get ["aria-labelledby"]() { return itemContext.triggerId(); }, get style() { return combineStyle({ "--kb-accordion-content-height": "var(--kb-collapsible-content-height)", "--kb-accordion-content-width": "var(--kb-collapsible-content-width)" }, local.style); } }, others)); } function AccordionHeader(props) { const context = useCollapsibleContext(); return createComponent(Polymorphic, mergeProps({ as: "h3" }, () => context.dataset(), props)); } var AccordionContext = createContext(); function useAccordionContext() { const context = useContext(AccordionContext); if (context === void 0) { throw new Error("[kobalte]: `useAccordionContext` must be used within a `Accordion.Root` component"); } return context; } // src/accordion/accordion-item.tsx function AccordionItem(props) { const accordionContext = useAccordionContext(); const defaultId = `${accordionContext.generateId("item")}-${createUniqueId()}`; const mergedProps = mergeDefaultProps({ id: defaultId }, props); const [local, others] = splitProps(mergedProps, ["value", "disabled"]); const [triggerId, setTriggerId] = createSignal(); const [contentId, setContentId] = createSignal(); const selectionManager = () => accordionContext.listState().selectionManager(); const isExpanded = () => { return selectionManager().isSelected(local.value); }; const context = { value: () => local.value, triggerId, contentId, generateId: createGenerateId(() => others.id), registerTriggerId: createRegisterId(setTriggerId), registerContentId: createRegisterId(setContentId) }; return createComponent(AccordionItemContext.Provider, { value: context, get children() { return createComponent(CollapsibleRoot, mergeProps({ get open() { return isExpanded(); }, get disabled() { return local.disabled; } }, others)); } }); } function AccordionRoot(props) { let ref; const defaultId = `accordion-${createUniqueId()}`; const mergedProps = mergeDefaultProps({ id: defaultId, multiple: false, collapsible: false, shouldFocusWrap: true }, props); const [local, others] = splitProps(mergedProps, [ "id", "ref", "value", "defaultValue", "onChange", "multiple", "collapsible", "shouldFocusWrap", "onKeyDown", "onMouseDown", "onFocusIn", // TODO: remove next breaking "onFocusOut" ]); const [items, setItems] = createSignal([]); const { DomCollectionProvider } = createDomCollection({ items, onItemsChange: setItems }); const listState = createListState({ selectedKeys: () => local.value, defaultSelectedKeys: () => local.defaultValue, onSelectionChange: (value) => local.onChange?.(Array.from(value)), disallowEmptySelection: () => !local.multiple && !local.collapsible, selectionMode: () => local.multiple ? "multiple" : "single", dataSource: items }); listState.selectionManager().setFocusedKey("item-1"); const selectableList = createSelectableList({ selectionManager: () => listState.selectionManager(), collection: () => listState.collection(), disallowEmptySelection: () => listState.selectionManager().disallowEmptySelection(), shouldFocusWrap: () => local.shouldFocusWrap, disallowTypeAhead: true, allowsTabNavigation: true }, () => ref); const context = { listState: () => listState, generateId: createGenerateId(() => local.id) }; return createComponent(DomCollectionProvider, { get children() { return createComponent(AccordionContext.Provider, { value: context, get children() { return createComponent(Polymorphic, mergeProps({ as: "div", get id() { return local.id; }, ref(r$) { const _ref$ = mergeRefs((el) => ref = el, local.ref); typeof _ref$ === "function" && _ref$(r$); }, get onKeyDown() { return composeEventHandlers([local.onKeyDown, selectableList.onKeyDown]); }, get onMouseDown() { return composeEventHandlers([local.onMouseDown, selectableList.onMouseDown]); }, get onFocusIn() { return composeEventHandlers([ local.onFocusIn // TODO: remove next breaking ]); }, get onFocusOut() { return composeEventHandlers([local.onFocusOut, selectableList.onFocusOut]); } }, others)); } }); } }); } function AccordionTrigger(props) { let ref; const accordionContext = useAccordionContext(); const itemContext = useAccordionItemContext(); const collapsibleContext = useCollapsibleContext(); const defaultId = itemContext.generateId("trigger"); const mergedProps = mergeDefaultProps({ id: defaultId }, props); const [local, others] = splitProps(mergedProps, ["ref", "onPointerDown", "onPointerUp", "onClick", "onKeyDown", "onMouseDown", "onFocus"]); createDomCollectionItem({ getItem: () => ({ ref: () => ref, type: "item", key: itemContext.value(), textValue: "", // not applicable here disabled: collapsibleContext.disabled() }) }); const selectableItem = createSelectableItem({ key: () => itemContext.value(), selectionManager: () => accordionContext.listState().selectionManager(), disabled: () => collapsibleContext.disabled(), shouldSelectOnPressUp: true }, () => ref); const onKeyDown = (e) => { if (["Enter", " "].includes(e.key)) { e.preventDefault(); } callHandler(e, local.onKeyDown); callHandler(e, selectableItem.onKeyDown); }; createEffect(() => onCleanup(itemContext.registerTriggerId(others.id))); return createComponent(CollapsibleTrigger, mergeProps({ ref(r$) { const _ref$ = mergeRefs((el) => ref = el, local.ref); typeof _ref$ === "function" && _ref$(r$); }, get ["data-key"]() { return selectableItem.dataKey(); }, get onPointerDown() { return composeEventHandlers([local.onPointerDown, selectableItem.onPointerDown]); }, get onPointerUp() { return composeEventHandlers([local.onPointerUp, selectableItem.onPointerUp]); }, get onClick() { return composeEventHandlers([local.onClick, selectableItem.onClick]); }, onKeyDown, get onMouseDown() { return composeEventHandlers([local.onMouseDown, selectableItem.onMouseDown]); }, get onFocus() { return composeEventHandlers([local.onFocus, selectableItem.onFocus]); } }, others)); } // src/accordion/index.tsx var Accordion = Object.assign(AccordionRoot, { Content: AccordionContent, Header: AccordionHeader, Item: AccordionItem, Trigger: AccordionTrigger }); export { Accordion, AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger, accordion_exports, useAccordionContext };