Skip to content

classes: accordion #1616

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/lib/accordion/Accordion.svelte
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I mentioned it here, I think classes?.activeCtx and classes?.inactiveCtx make it clear to users that we are using them for context. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Not a problem to change the slots names as above, however why that's important? That's the implementation detail.

Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
import { setContext, getContext } from "svelte";
import { writable } from "svelte/store";
import { accordion } from "./";
import {type AccordionProps, type BaseThemes, cn } from "$lib";
import { type AccordionProps, type BaseThemes, cn } from "$lib";

let { children, flush, activeClass, inactiveClass, multiple = false, class: className, transitionType, ...restProps }: AccordionProps = $props();
let { children, flush, multiple = false, class: className, classes, transitionType, ...restProps }: AccordionProps = $props();

// Get merged theme from context
const context = getContext<BaseThemes>("themeConfig");
Expand All @@ -13,8 +13,8 @@

const ctx = {
flush,
activeClass,
inactiveClass,
activeClass: classes?.active,
inactiveClass: classes?.inactive,
selected: multiple ? undefined : writable()
};

Expand Down
11 changes: 6 additions & 5 deletions src/lib/accordion/AccordionItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import { writable } from "svelte/store";
import { accordionitem } from ".";
import { type AccordionCtxType, type AccordionItemProps, type ParamsType, type BaseThemes, cn } from "$lib";
import clsx from "clsx";

let { children, header, arrowup, arrowdown, open = $bindable(false), activeClass, inactiveClass, transitionType = slide, transitionParams, class: className, headerClass, contentClass }: AccordionItemProps = $props();
let { children, header, arrowup, arrowdown, open = $bindable(false), classes, transitionType = slide, transitionParams, class: className }: AccordionItemProps = $props();

const ctxTransitionType = getContext("ctxTransitionType");
// Check if transitionType is explicitly set to undefined in props
Expand All @@ -30,10 +31,10 @@

const { base, button, content, active, inactive } = $derived(accordionitemTheme({ flush: ctx.flush, open }));

let buttonClass = $derived(cn(button(), open && !ctx.flush && (activeClass || ctx.activeClass || active()), !open && !ctx.flush && (inactiveClass || ctx.inactiveClass || inactive()), className));
let buttonClass = $derived(cn(button(), open && !ctx.flush && (classes?.active || ctx.activeClass || active()), !open && !ctx.flush && (classes?.inactive || ctx.inactiveClass || inactive()), className));
</script>

<h2 class={base({ class: headerClass })}>
<h2 class={base({ class: clsx(classes?.base, className) })}>
<button type="button" onclick={handleToggle} class={buttonClass} aria-expanded={open}>
{#if header}
{@render header()}
Expand All @@ -59,14 +60,14 @@
{#if useTransition}
{#if open && transitionType !== "none"}
<div transition:transitionType={transitionParams as ParamsType}>
<div class={content({ class: contentClass })}>
<div class={content({ class: clsx(classes?.content) })}>
{@render children()}
</div>
</div>
{/if}
{:else}
<div class={open ? "block" : "hidden"}>
<div class={content({ class: contentClass })}>
<div class={content({ class: clsx(classes?.content) })}>
{@render children()}
</div>
</div>
Expand Down
13 changes: 11 additions & 2 deletions src/lib/accordion/theme.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { tv } from "tailwind-variants";
import type { ComponentVariants } from "$lib/types";
import { tv, type VariantProps } from "tailwind-variants";

export type AccordionVariants = ComponentVariants<typeof accordion>;

export const accordion = tv({
base: "w-full text-gray-500 dark:text-gray-400",
slots: {
base: "w-full text-gray-500 dark:text-gray-400",
active: "",
inactive: ""
},
variants: {
flush: {
true: "",
Expand All @@ -10,6 +17,8 @@ export const accordion = tv({
}
});

export type AccordionItemVariants = ComponentVariants<typeof accordionitem>;

export const accordionitem = tv({
slots: {
base: "group",
Expand Down
22 changes: 9 additions & 13 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import type { ImgVariants } from "$lib/typography/img/theme";
import type { ListVariants } from "$lib/typography/list/theme";
import type { ParagraphVariants } from "$lib/typography/paragraph/theme";
import type { SpanVariants } from "$lib/typography/span/theme";
import type { AccordionItemVariants, AccordionVariants } from "./accordion/theme";

// end of component variants

Expand All @@ -69,6 +70,11 @@ export interface ThemeType {
[key: string]: ReturnType<typeof tv>;
}

// Generic type definition for ComponentVariants
export type ComponentVariants<T extends ((...args: any) => any) & { slots: object }> = (
VariantProps<T> & { classes?: Partial<{ [K in keyof T["slots"]]: ClassValue }> }
);

export declare const xs = "xs";
export declare const sm = "sm";
export declare const md = "md";
Expand Down Expand Up @@ -162,30 +168,20 @@ export interface AccordionCtxType {
multiple?: boolean;
}

export interface AccordionProps extends HTMLAttributes<HTMLDivElement> {
export interface AccordionProps extends AccordionVariants, HTMLAttributes<HTMLDivElement> {
children: Snippet;
flush?: boolean;
multiple?: boolean;
activeClass?: string;
inactiveClass?: string;
defaultClass?: string;
classActive?: string;
classInactive?: string;
transitionType?: TransitionFunc | "none";
transitionParams?: ParamsType;
}

export interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {
export interface AccordionItemProps extends AccordionItemVariants, HTMLAttributes<HTMLDivElement> {
children: Snippet;
header?: Snippet;
arrowup?: Snippet;
arrowdown?: Snippet;
open?: boolean;
activeClass?: string;
inactiveClass?: string;
transitionType?: TransitionFunc | "none";
transitionParams?: ParamsType;
headerClass?: string;
contentClass?: string;
}

// alert
Expand Down
7 changes: 5 additions & 2 deletions src/routes/docs/components/accordion.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,17 @@ Use the `open` prop to make an item open on mount.

## Color option

You can control the look and feel of `AccordionItems` by overwriting the `activeClass` and `inactiveClass` properties. You can define them in `Accordion` so that they will apply to all children or set them individually on each `AccordionItem`.
You can control the look and feel of `AccordionItems` by overwriting the `classes` props: `active` and `inactive`. You can define them in `Accordion` so that they will apply to all children or set them individually on each `AccordionItem`.

```svelte example
<script>
import { AccordionItem, Accordion } from "flowbite-svelte";
</script>

<Accordion activeClass="bg-blue-100 dark:bg-gray-800 text-blue-600 dark:text-white focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-800" inactiveClass="text-gray-500 dark:text-gray-400 hover:bg-blue-100 dark:hover:bg-gray-800">
<Accordion classes={{
active: "bg-blue-100 dark:bg-gray-800 text-blue-600 dark:text-white focus:ring-4 focus:ring-blue-200 dark:focus:ring-blue-800",
inactive:"text-gray-500 dark:text-gray-400 hover:bg-blue-100 dark:hover:bg-gray-800"
}}>
<AccordionItem>
{#snippet header()}Header 2-1{/snippet}
<p class="mb-2 text-gray-500 dark:text-gray-400">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illo ab necessitatibus sint explicabo ...</p>
Expand Down