From 30ee5c877e42f98c4bdca3bb93710be4a132703a Mon Sep 17 00:00:00 2001 From: Mats Bosson Date: Sun, 29 Mar 2026 08:13:45 +0700 Subject: [PATCH] Fix Accordion per-item disabled - Add disabled accessor to AccordionItemContextValue and itemCtx so per-item disabled prop disables the trigger button - Use getter for itemCtx.value to stay reactive with the local proxy - Guard onClick toggle against itemCtx.disabled() in addition to rootCtx.disabled() - Add one-liner JSDoc to all six exported accordion interfaces --- .../core/src/components/accordion/accordion-content.tsx | 1 + packages/core/src/components/accordion/accordion-context.ts | 3 +++ packages/core/src/components/accordion/accordion-header.tsx | 1 + packages/core/src/components/accordion/accordion-item.tsx | 6 +++++- packages/core/src/components/accordion/accordion-root.tsx | 1 + .../core/src/components/accordion/accordion-trigger.tsx | 5 +++-- 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/core/src/components/accordion/accordion-content.tsx b/packages/core/src/components/accordion/accordion-content.tsx index da019a1..df0fffd 100644 --- a/packages/core/src/components/accordion/accordion-content.tsx +++ b/packages/core/src/components/accordion/accordion-content.tsx @@ -2,6 +2,7 @@ import type { JSX } from "solid-js"; import { splitProps } from "solid-js"; import { useAccordionItemContext } from "./accordion-context"; +/** Props for the collapsible content panel of an Accordion item. */ export interface AccordionContentProps extends JSX.HTMLAttributes { children?: JSX.Element; } diff --git a/packages/core/src/components/accordion/accordion-context.ts b/packages/core/src/components/accordion/accordion-context.ts index 2c54638..b8507a5 100644 --- a/packages/core/src/components/accordion/accordion-context.ts +++ b/packages/core/src/components/accordion/accordion-context.ts @@ -1,17 +1,20 @@ import type { Accessor } from "solid-js"; import { createContext, useContext } from "solid-js"; +/** Shared state provided by AccordionRoot to all descendant accordion parts. */ export interface AccordionRootContextValue { isExpanded: (value: string) => boolean; toggleItem: (value: string) => void; disabled: Accessor; } +/** Per-item state provided by AccordionItem to its trigger and content. */ export interface AccordionItemContextValue { value: string; isExpanded: Accessor; triggerId: string; contentId: string; + disabled: Accessor; } const AccordionRootContext = createContext(); diff --git a/packages/core/src/components/accordion/accordion-header.tsx b/packages/core/src/components/accordion/accordion-header.tsx index 40ab31f..b0d876d 100644 --- a/packages/core/src/components/accordion/accordion-header.tsx +++ b/packages/core/src/components/accordion/accordion-header.tsx @@ -2,6 +2,7 @@ import type { JSX } from "solid-js"; import { splitProps } from "solid-js"; import { Dynamic } from "solid-js/web"; +/** Props for the heading wrapper rendered around an Accordion trigger. */ export interface AccordionHeaderProps extends JSX.HTMLAttributes { /** Heading level element. @default "h3" */ as?: string; diff --git a/packages/core/src/components/accordion/accordion-item.tsx b/packages/core/src/components/accordion/accordion-item.tsx index fdb202d..c80210e 100644 --- a/packages/core/src/components/accordion/accordion-item.tsx +++ b/packages/core/src/components/accordion/accordion-item.tsx @@ -2,6 +2,7 @@ import type { JSX } from "solid-js"; import { createUniqueId, splitProps } from "solid-js"; import { AccordionItemContextProvider, useAccordionRootContext } from "./accordion-context"; +/** Props for a single collapsible item within an Accordion. */ export interface AccordionItemProps extends JSX.HTMLAttributes { value: string; disabled?: boolean; @@ -16,10 +17,13 @@ export function AccordionItem(props: AccordionItemProps): JSX.Element { const contentId = createUniqueId(); const itemCtx = { - value: local.value, + get value() { + return local.value; + }, isExpanded: () => rootCtx.isExpanded(local.value), triggerId, contentId, + disabled: () => local.disabled ?? false, }; return ( diff --git a/packages/core/src/components/accordion/accordion-root.tsx b/packages/core/src/components/accordion/accordion-root.tsx index 62cbd01..81383bb 100644 --- a/packages/core/src/components/accordion/accordion-root.tsx +++ b/packages/core/src/components/accordion/accordion-root.tsx @@ -2,6 +2,7 @@ import type { JSX } from "solid-js"; import { createSignal, splitProps } from "solid-js"; import { AccordionRootContextProvider, type AccordionRootContextValue } from "./accordion-context"; +/** Props for the root accordion container that manages expanded state. */ export interface AccordionRootProps extends JSX.HTMLAttributes { /** "single" allows one item open at a time; "multiple" allows any number. @default "single" */ type?: "single" | "multiple"; diff --git a/packages/core/src/components/accordion/accordion-trigger.tsx b/packages/core/src/components/accordion/accordion-trigger.tsx index d73ff9a..dc77cf8 100644 --- a/packages/core/src/components/accordion/accordion-trigger.tsx +++ b/packages/core/src/components/accordion/accordion-trigger.tsx @@ -2,6 +2,7 @@ import type { JSX } from "solid-js"; import { splitProps } from "solid-js"; import { useAccordionItemContext, useAccordionRootContext } from "./accordion-context"; +/** Props for the button that toggles an Accordion item open/closed. */ export interface AccordionTriggerProps extends JSX.ButtonHTMLAttributes { children?: JSX.Element; } @@ -20,11 +21,11 @@ export function AccordionTrigger(props: AccordionTriggerProps): JSX.Element { aria-controls={itemCtx.contentId} data-state={itemCtx.isExpanded() ? "open" : "closed"} data-accordion-trigger - disabled={rootCtx.disabled()} + disabled={rootCtx.disabled() || itemCtx.disabled()} {...rest} onClick={(e) => { if (typeof rest.onClick === "function") rest.onClick(e); - if (!rootCtx.disabled()) rootCtx.toggleItem(itemCtx.value); + if (!rootCtx.disabled() && !itemCtx.disabled()) rootCtx.toggleItem(itemCtx.value); }} onKeyDown={(e) => { if (typeof rest.onKeyDown === "function") rest.onKeyDown(e);