Skip to content

Commit 17dbf51

Browse files
authored
version-2 part-5 (#1896)
* fix(ThemeSelector): remove the manual onclick handler from the Button, isOpen state variable, bind:isOpen from Dropdown, aria-exapanded attribute * tests: fix ThemeSelector.test.ts * tests: radio, label, input-field, input-addon, helper * feat: CloseButton update, phoneinput unit tests, colors update, etc. * fix: remove duplicate test:all * feat: data-scope and data-part
1 parent b0f47f5 commit 17dbf51

File tree

242 files changed

+3004
-1476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

242 files changed

+3004
-1476
lines changed

CLAUDE.md

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,75 @@
1-
You can use the Flowbite-Svelte MCP server, where you have access to comprehensive Flowbite-Svelte component documentation. Here's how to use the available tools effectively:
1+
# Claude MCP Server Documentation
22

3-
## Available MCP Tools:
3+
This project uses multiple MCP servers to provide comprehensive documentation access.
44

5-
### 1. findComponent
5+
## Available MCP Servers
66

7-
Use this FIRST to discover components by name or category. Returns component information including the documentation path.
8-
When asked about Flowbite-Svelte components, ALWAYS use this tool to locate the correct component before fetching documentation.
9-
Example queries: 'Button', 'CardPlaceholder', 'form checkbox'
7+
### Svelte MCP Server
108

11-
### 2. getComponentList
9+
You have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
1210

13-
Lists all available Flowbite-Svelte components with their categories.
14-
Use this to discover what components are available or to help users explore component options.
11+
#### Available Tools:
1512

16-
### 3. getComponentDoc
13+
**1. list-sections**
14+
- Use this FIRST to discover all available documentation sections
15+
- Returns a structured list with titles, use_cases, and paths
16+
- When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start to find relevant sections
1717

18-
Retrieves full documentation content for a specific component. Accepts the component path found using findComponent.
19-
After calling findComponent, use this tool to fetch the complete documentation including usage examples, props, and best practices.
18+
**2. get-documentation**
19+
- Retrieves full documentation content for specific sections
20+
- Accepts single or multiple sections
21+
- After calling list-sections, you MUST analyze the returned documentation (especially the use_cases field) and then fetch ALL relevant sections for the user's task
2022

21-
### 4. searchDocs
23+
**3. svelte-autofixer**
24+
- Analyzes Svelte code and returns issues and suggestions
25+
- You MUST use this tool whenever writing Svelte code before sending it to the user
26+
- Keep calling it until no issues or suggestions are returned
2227

23-
Performs full-text search across all Flowbite-Svelte documentation.
24-
Use this when you need to find specific information that might span multiple components or when the user asks about features or patterns.
28+
**4. playground-link**
29+
- Generates a Svelte Playground link with the provided code
30+
- After completing the code, ask the user if they want a playground link
31+
- NEVER call this if code was written to files in their project
32+
33+
### Flowbite-Svelte MCP Server
34+
35+
You have access to comprehensive Flowbite-Svelte component documentation. Here's how to use the available tools effectively:
36+
37+
#### Available Tools:
38+
39+
**1. findComponent**
40+
- Use this FIRST to discover components by name or category
41+
- Returns component information including the documentation path
42+
- When asked about Flowbite-Svelte components, ALWAYS use this tool to locate the correct component before fetching documentation
43+
- Example queries: 'Button', 'CardPlaceholder', 'form checkbox'
44+
45+
**2. getComponentList**
46+
- Lists all available Flowbite-Svelte components with their categories
47+
- Use this to discover what components are available or to help users explore component options
48+
49+
**3. getComponentDoc**
50+
- Retrieves full documentation content for a specific component
51+
- Accepts the component path found using findComponent
52+
- After calling findComponent, use this tool to fetch complete documentation including usage examples, props, and best practices
53+
54+
**4. searchDocs**
55+
- Performs full-text search across all Flowbite-Svelte documentation
56+
- Use this when you need to find specific information that might span multiple components or when the user asks about features or patterns
57+
58+
## Workflow Guidelines
59+
60+
### When building Svelte components with Flowbite-Svelte:
61+
62+
1. **Start with Svelte documentation**: Use `list-sections` to understand which Svelte concepts are needed
63+
2. **Fetch relevant Svelte docs**: Use `get-documentation` to get all necessary Svelte sections
64+
3. **Find Flowbite-Svelte components**: Use `findComponent` to locate the UI components needed
65+
4. **Get component details**: Use `getComponentDoc` to fetch usage examples and props
66+
5. **Write the code**: Combine Svelte patterns with Flowbite-Svelte components
67+
6. **Validate the code**: Use `svelte-autofixer` to check for issues
68+
7. **Offer playground**: Ask if the user wants a playground link (only if not writing to files)
69+
70+
### Best Practices:
71+
72+
- Always prioritize Svelte 5 runes and modern patterns
73+
- Use Flowbite-Svelte components for consistent UI design
74+
- Validate all code with svelte-autofixer before delivering
75+
- Keep documentation lookups efficient by fetching multiple sections at once

design-system.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Flowbite Svelte Design System
2+
3+
## Anatomical Selectors: data-scope and data-part
4+
To provide a consistent API for styling, testing, and DOM inspection, every component uses a standardized data-attribute pattern.
5+
6+
1. `data-scope`
7+
Definition: Identifies the component boundary.
8+
9+
Format: Always kebab-case (e.g., breadcrumb-item for BreadcrumbItem, button-group for ButtonGroup).
10+
11+
Usage: Applied to the root element of the component. It acts as a namespace to prevent CSS leakage and helps in end-to-end testing (Playwright/Vitest).
12+
13+
2. `data-part`
14+
Definition: Identifies a specific sub-element (slot) within the component.
15+
16+
Requirement: The value must strictly match a key defined in the component's theme.ts slots.
17+
18+
Usage: Acts as a stable "Public API" for CSS selectors. Instead of targeting unstable utility classes, consumers can target:
19+
20+
```css
21+
/* Targeted styling without touching component internals */
22+
[data-scope="breadcrumb-item"] [data-part="link"]:hover {
23+
text-decoration: underline;
24+
}
25+
```
26+
27+
## Slot Naming
28+
29+
In Flowbite-Svelte, we use `camelCase` for slot names.
30+
31+
Each slot represents a distinct part of a component and follows standard JavaScript naming conventions to ensure consistency and readability across the codebase.
32+
33+
### Example
34+
35+
```ts
36+
const card = tv({
37+
slots: {
38+
base: '...',
39+
columnHeader: '...',
40+
infoWrapper: '...',
41+
monthButton: '...',
42+
}
43+
});
44+
```
45+
Using camelCase makes slot names predictable, easy to reference, and consistent with how component APIs are written throughout Flowbite-Svelte.
46+
47+
| Usage context | Example | Naming style | Notes |
48+
| ---------------------- | ------------------------- | ------------ | --------------------------------------------------------------- |
49+
| Slot name | `leftTop` | camelCase | Used in component APIs and `tailwind-variants` slot definitions |
50+
| theme access | `theme.component.leftTop` | camelCase | Follows standard JavaScript property naming |
51+
| classes/styling access | `classes={{leftTop: ""}}` | camelCase | Follows standard JavaScript property naming |
52+
| HTML data attribute | `data-part="left-top"` | kebab-case | Follows HTML attribute conventions |
53+
| CSS selector | `[data-part="left-top"]` | kebab-case | Matches HTML and Tailwind conventions |
54+
55+
56+
## **✅ The 5 most common `data-part` categories**
57+
58+
These show up across almost all well-designed component libraries (Radix, Ark, Shoelace, Adobe Spectrum, etc.)
59+
60+
---
61+
62+
### **1️⃣ Structural parts (layout / grouping)**
63+
64+
| Name | Meaning |
65+
| :---------- | :-------------------------------------------- |
66+
| `base` | Root element of the component |
67+
| `content` | Main content area |
68+
| `container` | Layout wrapper (less semantic than `content`) |
69+
| `wrapper` | Structural wrapper (use sparingly) |
70+
| `body` | Main content body (dialogs, cards) |
71+
72+
---
73+
74+
### **2️⃣ Interactive parts**
75+
76+
| Name | Use case |
77+
| :-------- | :------------------------ |
78+
| `trigger` | Opens/toggles something |
79+
| `button` | Clickable control |
80+
| `item` | Repeated interactive item |
81+
| `option` | Selectable option |
82+
| `tab` | Tab element |
83+
84+
Example:
85+
86+
`<button data-part="trigger">`
87+
88+
---
89+
90+
### **3️⃣ Textual parts**
91+
92+
| Name | Use case |
93+
| :------------ | :------------------------ |
94+
| `label` | Visible text label |
95+
| `title` | Heading or title |
96+
| `description` | Supporting text |
97+
| `value` | Dynamic or selected value |
98+
99+
You already used this correctly:
100+
101+
`<span data-part="label">Home</span>`
102+
103+
---
104+
105+
### **4️⃣ Icon & media parts**
106+
107+
| Name | Use case |
108+
| :------- | :-------------- |
109+
| `icon` | Icon glyph |
110+
| `avatar` | User image |
111+
| `image` | Generic image |
112+
| `badge` | Small indicator |
113+
114+
Example:
115+
116+
`<Icon data-part="icon" />`
117+
118+
---
119+
120+
### **5️⃣ State / utility parts**
121+
122+
| Name | Use case |
123+
| :---------- | :----------------- |
124+
| `overlay` | Backdrop / overlay |
125+
| `backdrop` | Modal background |
126+
| `indicator` | Status indicator |
127+
| `separator` | Divider line |
128+

src/lib/accordion/Accordion.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
const base = $derived(accordion({ flush, class: clsx(theme, className) }));
3838
</script>
3939

40-
<div {...restProps} class={base}>
40+
<div data-scope="accordion" data-part="base" {...restProps} class={base}>
4141
{@render children()}
4242
</div>
4343

src/lib/accordion/AccordionItem.svelte

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// Theme is applied in template via clsx with lowest priority.
1717
const finalClasses = $derived({
1818
button: classes?.button || ctx?.classes?.button,
19-
contentWrapper: classes?.contentWrapper || ctx?.classes?.contentWrapper,
19+
contentWrapper: classes?.container || ctx?.classes?.contentWrapper,
2020
content: classes?.content || ctx?.classes?.content,
2121
active: classes?.active || ctx?.classes?.active,
2222
inactive: classes?.inactive || ctx?.classes?.inactive
@@ -50,15 +50,15 @@
5050
open = !open;
5151
};
5252
53-
const { base, button, contentWrapper, content, active, inactive } = $derived(accordionItem({ flush: ctx?.flush, open }));
53+
const { base, button, container, content, active, inactive } = $derived(accordionItem({ flush: ctx?.flush, open }));
5454
5555
let buttonClass = $derived(clsx(open && !ctx?.flush && (finalClasses.active || active()), !open && !ctx?.flush && (finalClasses.inactive || inactive())));
5656
57-
let contentWrapperCls = $derived(clsx(contentWrapper(), open ? "block" : "hidden", finalClasses.contentWrapper));
57+
let contentWrapperCls = $derived(clsx(container(), open ? "block" : "hidden", finalClasses.contentWrapper));
5858
</script>
5959

60-
<h2 class={base({ class: clsx(theme?.base, className) })}>
61-
<button type="button" onclick={handleToggle} class={button({ class: clsx(buttonClass, theme?.button, finalClasses.button) })} aria-expanded={open}>
60+
<h2 data-scope="accordion-item" data-part="base" class={base({ class: clsx(theme?.base, className) })}>
61+
<button data-part="button" type="button" onclick={handleToggle} class={button({ class: clsx(buttonClass, theme?.button, finalClasses.button) })} aria-expanded={open}>
6262
{#if header}
6363
{@render header()}
6464
{#if open}
@@ -82,15 +82,15 @@
8282

8383
{#if useTransition}
8484
{#if open && transitionType !== "none"}
85-
<div class={contentWrapperCls} transition:transitionType={effectiveTransitionParams as ParamsType}>
86-
<div class={content({ class: clsx(theme?.content, finalClasses.content) })}>
85+
<div data-part="content-wrapper" class={contentWrapperCls} transition:transitionType={effectiveTransitionParams as ParamsType}>
86+
<div data-part="content" class={content({ class: clsx(theme?.content, finalClasses.content) })}>
8787
{@render children()}
8888
</div>
8989
</div>
9090
{/if}
9191
{:else}
92-
<div class={contentWrapperCls}>
93-
<div class={content({ class: clsx(theme?.content, finalClasses.content) })}>
92+
<div data-part="content-wrapper" class={contentWrapperCls}>
93+
<div data-part="content" class={content({ class: clsx(theme?.content, finalClasses.content) })}>
9494
{@render children()}
9595
</div>
9696
</div>

src/lib/accordion/theme.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const accordionItem = tv({
3333
slots: {
3434
base: "group",
3535
button: "flex items-center justify-between w-full p-5 font-medium rtl:text-right text-body group-first:rounded-t-base border border-t-0 border-x-0 border-b-default gap-3",
36-
contentWrapper: "",
36+
container: "",
3737
content: "p-4 md:p-5 group-last:border group-last:border-t-default group-last:border-x-0",
3838
active: "",
3939
inactive: ""

src/lib/alert/Alert.svelte

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
alertStatus = $bindable(true),
1515
closeIcon: CloseIcon,
1616
color = "brand",
17-
closeColor,
1817
rounded = true,
1918
border,
2019
class: className,
@@ -23,6 +22,7 @@
2322
params,
2423
listContent,
2524
borderAccent,
25+
closeButtonProps,
2626
...restProps
2727
}: AlertProps = $props();
2828
@@ -57,10 +57,20 @@
5757
}
5858
5959
createDismissableContext(close);
60+
61+
const finalCloseProps = $derived({
62+
class: clsx("-my-1.5 ms-auto -me-1.5", closeButtonProps?.class),
63+
color: closeButtonProps?.color ?? color,
64+
ariaLabel: closeButtonProps?.ariaLabel ?? "Remove alert",
65+
size: closeButtonProps?.size,
66+
classes: closeButtonProps?.classes,
67+
name: closeButtonProps?.name,
68+
onclick: closeButtonProps?.onclick
69+
});
6070
</script>
6171

6272
{#if alertStatus}
63-
<div role="alert" bind:this={ref} {...restProps} transition:transition={effectiveParams as ParamsType} class={divCls}>
73+
<div data-scope="alert" data-part="base" role="alert" bind:this={ref} {...restProps} transition:transition={effectiveParams as ParamsType} class={divCls}>
6474
{#if icon}
6575
{@render icon()}
6676
{/if}
@@ -75,11 +85,11 @@
7585

7686
{#if dismissable}
7787
{#if CloseIcon}
78-
<CloseButton class="-my-1.5 ms-auto -me-1.5" color={closeColor ?? color} ariaLabel="Remove alert">
88+
<CloseButton {...finalCloseProps}>
7989
<CloseIcon />
8090
</CloseButton>
8191
{:else}
82-
<CloseButton class="-my-1.5 ms-auto -me-1.5" color={closeColor ?? color} ariaLabel="Remove alert" />
92+
<CloseButton {...finalCloseProps} />
8393
{/if}
8494
{/if}
8595
</div>

0 commit comments

Comments
 (0)