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
This commit is contained in:
parent
94822186c2
commit
30ee5c877e
@ -2,6 +2,7 @@ import type { JSX } from "solid-js";
|
|||||||
import { splitProps } from "solid-js";
|
import { splitProps } from "solid-js";
|
||||||
import { useAccordionItemContext } from "./accordion-context";
|
import { useAccordionItemContext } from "./accordion-context";
|
||||||
|
|
||||||
|
/** Props for the collapsible content panel of an Accordion item. */
|
||||||
export interface AccordionContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
export interface AccordionContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
import type { Accessor } from "solid-js";
|
import type { Accessor } from "solid-js";
|
||||||
import { createContext, useContext } from "solid-js";
|
import { createContext, useContext } from "solid-js";
|
||||||
|
|
||||||
|
/** Shared state provided by AccordionRoot to all descendant accordion parts. */
|
||||||
export interface AccordionRootContextValue {
|
export interface AccordionRootContextValue {
|
||||||
isExpanded: (value: string) => boolean;
|
isExpanded: (value: string) => boolean;
|
||||||
toggleItem: (value: string) => void;
|
toggleItem: (value: string) => void;
|
||||||
disabled: Accessor<boolean>;
|
disabled: Accessor<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Per-item state provided by AccordionItem to its trigger and content. */
|
||||||
export interface AccordionItemContextValue {
|
export interface AccordionItemContextValue {
|
||||||
value: string;
|
value: string;
|
||||||
isExpanded: Accessor<boolean>;
|
isExpanded: Accessor<boolean>;
|
||||||
triggerId: string;
|
triggerId: string;
|
||||||
contentId: string;
|
contentId: string;
|
||||||
|
disabled: Accessor<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AccordionRootContext = createContext<AccordionRootContextValue>();
|
const AccordionRootContext = createContext<AccordionRootContextValue>();
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { JSX } from "solid-js";
|
|||||||
import { splitProps } from "solid-js";
|
import { splitProps } from "solid-js";
|
||||||
import { Dynamic } from "solid-js/web";
|
import { Dynamic } from "solid-js/web";
|
||||||
|
|
||||||
|
/** Props for the heading wrapper rendered around an Accordion trigger. */
|
||||||
export interface AccordionHeaderProps extends JSX.HTMLAttributes<HTMLHeadingElement> {
|
export interface AccordionHeaderProps extends JSX.HTMLAttributes<HTMLHeadingElement> {
|
||||||
/** Heading level element. @default "h3" */
|
/** Heading level element. @default "h3" */
|
||||||
as?: string;
|
as?: string;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { JSX } from "solid-js";
|
|||||||
import { createUniqueId, splitProps } from "solid-js";
|
import { createUniqueId, splitProps } from "solid-js";
|
||||||
import { AccordionItemContextProvider, useAccordionRootContext } from "./accordion-context";
|
import { AccordionItemContextProvider, useAccordionRootContext } from "./accordion-context";
|
||||||
|
|
||||||
|
/** Props for a single collapsible item within an Accordion. */
|
||||||
export interface AccordionItemProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
export interface AccordionItemProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
value: string;
|
value: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -16,10 +17,13 @@ export function AccordionItem(props: AccordionItemProps): JSX.Element {
|
|||||||
const contentId = createUniqueId();
|
const contentId = createUniqueId();
|
||||||
|
|
||||||
const itemCtx = {
|
const itemCtx = {
|
||||||
value: local.value,
|
get value() {
|
||||||
|
return local.value;
|
||||||
|
},
|
||||||
isExpanded: () => rootCtx.isExpanded(local.value),
|
isExpanded: () => rootCtx.isExpanded(local.value),
|
||||||
triggerId,
|
triggerId,
|
||||||
contentId,
|
contentId,
|
||||||
|
disabled: () => local.disabled ?? false,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { JSX } from "solid-js";
|
|||||||
import { createSignal, splitProps } from "solid-js";
|
import { createSignal, splitProps } from "solid-js";
|
||||||
import { AccordionRootContextProvider, type AccordionRootContextValue } from "./accordion-context";
|
import { AccordionRootContextProvider, type AccordionRootContextValue } from "./accordion-context";
|
||||||
|
|
||||||
|
/** Props for the root accordion container that manages expanded state. */
|
||||||
export interface AccordionRootProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
export interface AccordionRootProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
/** "single" allows one item open at a time; "multiple" allows any number. @default "single" */
|
/** "single" allows one item open at a time; "multiple" allows any number. @default "single" */
|
||||||
type?: "single" | "multiple";
|
type?: "single" | "multiple";
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { JSX } from "solid-js";
|
|||||||
import { splitProps } from "solid-js";
|
import { splitProps } from "solid-js";
|
||||||
import { useAccordionItemContext, useAccordionRootContext } from "./accordion-context";
|
import { useAccordionItemContext, useAccordionRootContext } from "./accordion-context";
|
||||||
|
|
||||||
|
/** Props for the button that toggles an Accordion item open/closed. */
|
||||||
export interface AccordionTriggerProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
export interface AccordionTriggerProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
}
|
}
|
||||||
@ -20,11 +21,11 @@ export function AccordionTrigger(props: AccordionTriggerProps): JSX.Element {
|
|||||||
aria-controls={itemCtx.contentId}
|
aria-controls={itemCtx.contentId}
|
||||||
data-state={itemCtx.isExpanded() ? "open" : "closed"}
|
data-state={itemCtx.isExpanded() ? "open" : "closed"}
|
||||||
data-accordion-trigger
|
data-accordion-trigger
|
||||||
disabled={rootCtx.disabled()}
|
disabled={rootCtx.disabled() || itemCtx.disabled()}
|
||||||
{...rest}
|
{...rest}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
if (typeof rest.onClick === "function") 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) => {
|
onKeyDown={(e) => {
|
||||||
if (typeof rest.onKeyDown === "function") rest.onKeyDown(e);
|
if (typeof rest.onKeyDown === "function") rest.onKeyDown(e);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user