diff --git a/README.md b/README.md index 1341bbb..ec3dcf4 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ **@svelte-atoms/core** is a comprehensive Svelte component library that provides fundamental building blocks ("atoms") for creating sophisticated, interactive design systems. Each component is designed with accessibility, type safety, and developer experience in mind. Built with Svelte 5 runes for optimal reactivity and performance. [![npm version](https://img.shields.io/npm/v/@svelte-atoms/core.svg)](https://www.npmjs.com/package/@svelte-atoms/core) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/svelte-atoms/core) [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/) --- diff --git a/src/app.css b/src/app.css index a765faa..a8b856e 100644 --- a/src/app.css +++ b/src/app.css @@ -41,18 +41,18 @@ --secondary-foreground: oklch(0.205 0 0); --muted: oklch(0.97 0 0); --muted-foreground: oklch(0.556 0 0); - --accent: var(--palette-proton); + --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); - --destructive-foreground: oklch(1 0 0); --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); - --chart-1: oklch(0.81 0.1 252); - --chart-2: oklch(0.62 0.19 260); - --chart-3: oklch(0.55 0.22 263); - --chart-4: oklch(0.49 0.22 264); - --chart-5: oklch(0.42 0.18 266); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); @@ -70,24 +70,22 @@ ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; --radius: 0.625rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --shadow-x: 0px; + --shadow-y: 1px; + --shadow-blur: 2px; + --shadow-spread: 0px; + --shadow-opacity: 0.18; + --shadow-color: hsl(0 0% 0%); --tracking-normal: 0em; --spacing: 0.25rem; } .dark { - --background: var(--palette-carbon); + --background: oklch(0.145 0 0); --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.269 0 0); + --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); @@ -95,26 +93,25 @@ --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); - --accent: var(--palette-proton); + --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); - --destructive-foreground: oklch(0.985 0 0); - --border: oklch(0.275 0 0); - --input: oklch(0.325 0 0); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); - --chart-1: oklch(0.81 0.1 252); - --chart-2: oklch(0.62 0.19 260); - --chart-3: oklch(0.55 0.22 263); - --chart-4: oklch(0.49 0.22 264); - --chart-5: oklch(0.42 0.18 266); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(0.275 0 0); - --sidebar-ring: oklch(0.439 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); --font-sans: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', @@ -123,15 +120,7 @@ --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; - --radius: 0.625rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --shadow-color: hsl(0, 0%, 100%); } @theme inline { diff --git a/src/docs/components/README.md b/src/docs/components/README.md new file mode 100644 index 0000000..281832e --- /dev/null +++ b/src/docs/components/README.md @@ -0,0 +1,290 @@ +# Documentation Components + +Reusable components for creating consistent, rich, and easy-to-maintain component documentation pages. + +## Components + +### PageHeader + +Displays the component title, description, and status badge. + +```svelte + +``` + +**Props:** + +- `title: string` - Component name +- `description: string` - Component description +- `status?: 'stable' | 'beta' | 'experimental' | 'deprecated'` - Status badge (default: 'stable') +- `children?: Snippet` - Optional additional content + +--- + +### Breadcrumb + +Navigation breadcrumb trail. + +```svelte + +``` + +**Props:** + +- `items: Array<{ label: string; href?: string }>` - Breadcrumb items + +--- + +### Section + +Section container with title and optional description. + +```svelte +
+ +
+``` + +**Props:** + +- `title: string` - Section title +- `description?: string` - Optional section description +- `children: Snippet` - Section content +- `class?: string` - Optional CSS classes + +--- + +### Installation + +Installation and import instructions with copy functionality. + +```svelte + +``` + +**Props:** + +- `packageName: string` - NPM package name +- `importCode: string` - Import statement code + +--- + +### FeatureGrid + +Grid display of component features with icons. + +```svelte +...' + } + ]} +/> +``` + +**Props:** + +- `features: Array` - Array of features +- `columns?: 1 | 2 | 3 | 4` - Grid columns (default: 2) + +**Feature Object:** + +- `title: string` - Feature title +- `description: string` - Feature description +- `color: 'purple' | 'blue' | 'green' | 'pink' | 'yellow' | 'red'` - Color theme +- `icon?: Snippet` - Optional icon snippet +- `iconPath?: string` - Optional icon SVG string (easier to use) + +--- + +### AccessibilityInfo + +Accessibility features information panel. + +```svelte + +``` + +**Props:** + +- `features: string[]` - List of accessibility features +- `title?: string` - Optional custom title (default: 'Built-in Accessibility Features') + +--- + +### PageNavigation + +Previous/next page navigation links. + +```svelte + +``` + +**Props:** + +- `prev?: { label: string; href: string }` - Previous page link +- `next?: { label: string; href: string }` - Next page link + +--- + +### DemoExample + +Interactive component example with preview and code display. + +```svelte + + + + + +``` + +**Props:** + +- `title: string` - Example title +- `description?: string` - Optional example description +- `code: string` - Code to display +- `children: Snippet` - Component preview/demo + +--- + +### Props + +API reference table for component props. + +```svelte + +``` + +**Props:** + +- `data: Array` - Array of prop definitions + +**PropItem Object:** + +- `name: string` - Prop name +- `type: string` - TypeScript type +- `default: string` - Default value +- `description: string` - Prop description + +--- + +## Usage Example + +```svelte + + + + YourComponent - Atomic SV + + + +
+ + + + +
+ +
+ +
+ + Demo + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + +
+``` + +## Benefits + +✅ **Consistency** - All component pages follow the same structure +✅ **Maintainability** - Update one component, all pages benefit +✅ **Speed** - Create new documentation pages quickly +✅ **Rich Features** - Copy buttons, syntax highlighting, responsive design +✅ **Easy Updates** - Simple props interface for customization + +## See Also + +- [Component Documentation Template](../COMPONENT_DOCUMENTATION_TEMPLATE.md) - Full template and guidelines +- [Accordion Example](../../src/routes/components/accordion/+page.svelte) - Complete working example +- [Button Example](../../src/routes/components/button/+page.svelte) - Another example implementation diff --git a/src/docs/components/accessibility-info.svelte b/src/docs/components/accessibility-info.svelte new file mode 100644 index 0000000..e30eff3 --- /dev/null +++ b/src/docs/components/accessibility-info.svelte @@ -0,0 +1,34 @@ + + +
+
+ + + +
+

{title}

+
    + {#each features as feature} +
  • • {feature}
  • + {/each} +
+
+
+
diff --git a/src/docs/components/breadcrumb.svelte b/src/docs/components/breadcrumb.svelte new file mode 100644 index 0000000..4992bfc --- /dev/null +++ b/src/docs/components/breadcrumb.svelte @@ -0,0 +1,26 @@ + + + diff --git a/src/docs/components/demo-example.svelte b/src/docs/components/demo-example.svelte new file mode 100644 index 0000000..04f17eb --- /dev/null +++ b/src/docs/components/demo-example.svelte @@ -0,0 +1,74 @@ + + +
+ +
+

{title}

+ {#if description} +

{description}

+ {/if} +
+ + +
+
+ {@render children()} +
+
+ + +
+
+ Code + +
+
{code}
+
+
diff --git a/src/docs/components/feature-grid.svelte b/src/docs/components/feature-grid.svelte new file mode 100644 index 0000000..e0fb05d --- /dev/null +++ b/src/docs/components/feature-grid.svelte @@ -0,0 +1,75 @@ + + +
+ {#each features as feature} +
+
+ {#if feature.icon} + {@render feature.icon()} + {:else if feature.iconPath} + {@html feature.iconPath} + {/if} +
+

{feature.title}

+

{feature.description}

+
+ {/each} +
diff --git a/src/docs/components/index.ts b/src/docs/components/index.ts new file mode 100644 index 0000000..c2d5269 --- /dev/null +++ b/src/docs/components/index.ts @@ -0,0 +1,9 @@ +export { default as PageHeader } from './page-header.svelte'; +export { default as Breadcrumb } from './breadcrumb.svelte'; +export { default as Section } from './section.svelte'; +export { default as Installation } from './installation.svelte'; +export { default as FeatureGrid } from './feature-grid.svelte'; +export { default as AccessibilityInfo } from './accessibility-info.svelte'; +export { default as PageNavigation } from './page-navigation.svelte'; +export { default as DemoExample } from './demo-example.svelte'; +export { default as Props } from '../props-datagrid.svelte'; diff --git a/src/docs/components/installation.svelte b/src/docs/components/installation.svelte new file mode 100644 index 0000000..e85ae54 --- /dev/null +++ b/src/docs/components/installation.svelte @@ -0,0 +1,60 @@ + + +
+ +
+
+ Install Package + +
+ + npm install + {packageName} + +
+ + +
+
+ Import + +
+
{importCode}
+
+
diff --git a/src/docs/components/page-header.svelte b/src/docs/components/page-header.svelte new file mode 100644 index 0000000..c60d7d0 --- /dev/null +++ b/src/docs/components/page-header.svelte @@ -0,0 +1,35 @@ + + +
+
+

{title}

+ {status} +
+

+ {description} +

+ {#if children} +
+ {@render children()} +
+ {/if} +
diff --git a/src/docs/components/page-navigation.svelte b/src/docs/components/page-navigation.svelte new file mode 100644 index 0000000..879ddc5 --- /dev/null +++ b/src/docs/components/page-navigation.svelte @@ -0,0 +1,36 @@ + + +
+ {#if prev} + + + + + {prev.label} + + {:else} +
+ {/if} + + {#if next} + + {next.label} + + + + + {/if} +
diff --git a/src/docs/components/section.svelte b/src/docs/components/section.svelte new file mode 100644 index 0000000..e17500f --- /dev/null +++ b/src/docs/components/section.svelte @@ -0,0 +1,22 @@ + + +
+
+

{title}

+ {#if description} +

{description}

+ {/if} +
+ {@render children()} +
diff --git a/src/docs/index.ts b/src/docs/index.ts index e69de29..1ba17a2 100644 --- a/src/docs/index.ts +++ b/src/docs/index.ts @@ -0,0 +1,2 @@ +export * as Preview from './preview'; +export * from './components'; diff --git a/src/docs/props-datagrid.svelte b/src/docs/props-datagrid.svelte index 72d5295..6b56133 100644 --- a/src/docs/props-datagrid.svelte +++ b/src/docs/props-datagrid.svelte @@ -4,24 +4,24 @@ let { data = [] } = $props(); -
+
- + Prop Type Default Description @@ -30,16 +30,16 @@ {#each data as item (item)} - {item.name} - {item.type} - {item.default} - {item.description} diff --git a/src/knowledge/philosophy.md b/src/knowledge/philosophy.md deleted file mode 100644 index fbf049b..0000000 --- a/src/knowledge/philosophy.md +++ /dev/null @@ -1,23 +0,0 @@ -The Atomic Svelte philosophy is centered around creating a modular, composable UI library that treats components as fundamental building blocks. Here are the core principles: - -# 🧱 Atomic Architecture - -The philosophy is built around the concept of "atoms" - self-contained, reusable UI components that encapsulate their own state and DOM management. Think of it like chemistry: components are the basic elements that can be combined to create more complex molecules (UI patterns). - -# Core Structure - -Atoms: The smallest composable UI pieces - fundamental building blocks -Bonds: The logic that holds atoms together and enables synchronization between them -Protons, Neutrons, Electrons: Functions that can be attached to atoms to add incremental functionality - -# Key Philosophy Points - -🔗 Context-Driven Communication: Components communicate through Svelte's context API, enabling powerful parent-child relationships without prop drilling. - -- ♿ Accessibility First: Every component includes proper ARIA attributes, keyboard navigation, and focus management out of the box. -- 🎨 Headless & Stylable: Components are headless by default, giving you complete control over styling while providing sensible defaults. -- ⚡ Reactive by Design: Leverages Svelte's fine-grained reactivity system for optimal performance and smooth user interactions. -- 🔧 Highly Extensible: Easily extend components with custom behaviors, animations, and styling while maintaining core functionality. -- 🎯 Type Safety: Fully written in TypeScript with comprehensive type definitions for a robust development experience. - -The philosophy treats the library as "raw material" - providing low-level, customizable, scalable UI components that teams can use to build their own custom design systems rather than prescriptive, opinionated components. This approach gives developers maximum flexibility while ensuring consistency and accessibility across their applications. diff --git a/src/knowledge/usage.md b/src/knowledge/usage.md deleted file mode 100644 index 32a83df..0000000 --- a/src/knowledge/usage.md +++ /dev/null @@ -1,46 +0,0 @@ -# Component Usage Patterns - -## Namespace.Atom Pattern - -Components follow a hierarchical naming pattern using dot notation: - -```svelte - - - - - - -``` - -## Naming Convention - -- **Namespace** = Component family (e.g., `Form`, `Button`, `Dropdown`) -- **Atom** = Specific component within the family (e.g., `Root`, `Field`, `Label`) - -## Import Pattern - -```javascript -import { Form } from '$lib/components/form'; - -// Usage - - - Username - - -; -``` - -## Benefits - -- **Clear hierarchy** - Components group logically -- **Namespace isolation** - Prevents naming conflicts -- **Discoverable API** - IDE autocomplete shows related components -- **Consistent patterns** - Same structure across all component families - -## Examples - -- `Button.Root`, `Button.Icon`, `Button.Text` -- `Dropdown.Root`, `Dropdown.Trigger`, `Dropdown.Content` -- `Form.Root`, `Form.Field`, `Form.Label`, `Form.Control` diff --git a/src/lib/components/atom/html-atom.svelte b/src/lib/components/atom/html-atom.svelte index 6b1f40b..2d0e0c5 100644 --- a/src/lib/components/atom/html-atom.svelte +++ b/src/lib/components/atom/html-atom.svelte @@ -96,7 +96,9 @@ }; }); - const _klass = $derived([compilePresetPlaceholder(klass), mergedVariants?.class ?? '']); + const _klass = $derived( + cn(klass, mergedVariants?.class ?? '').replaceAll('$preset', cn(preset?.class)) + ); const _base = $derived(base ?? preset?.base); const _as = $derived(as ?? preset?.as); @@ -121,24 +123,6 @@ const Component = $derived(base ?? atom) as ComponentBase; - function compilePresetPlaceholder(klass: ClassValue): ReturnType { - if (Array.isArray(klass)) { - return klass.map((k) => compilePresetPlaceholder(k)); - } - - const compiled = toClassValue.apply(bond, [klass, bond]); - - if (Array.isArray(compiled)) { - return compiled.map((c) => compilePresetPlaceholder(c)); - } - - if (typeof compiled === 'string') { - return compiled.replace('$preset', cn(preset?.class)); - } - - return compiled; - } - /** * Resolve variant definition to props */ diff --git a/src/lib/components/button/types.ts b/src/lib/components/button/types.ts index b20fc7b..bda24d0 100644 --- a/src/lib/components/button/types.ts +++ b/src/lib/components/button/types.ts @@ -1,4 +1,4 @@ -import type { HtmlAtomProps } from '$lib/helpers'; +import type { HtmlAtomProps } from '$svelte-atoms/core/components/atom/types'; import type { Snippet } from 'svelte'; export type ButtonProps = HtmlAtomProps<'button'> & { diff --git a/src/lib/components/checkbox/checkbox.svelte b/src/lib/components/checkbox/checkbox.svelte index 96a0fcf..b2ef9d6 100644 --- a/src/lib/components/checkbox/checkbox.svelte +++ b/src/lib/components/checkbox/checkbox.svelte @@ -1,21 +1,22 @@ @@ -71,15 +79,16 @@ { - checkboxElement = node; - }} + tabindex="-1" /> - {#if indeterminate} + {#if isIndeterminate} {#if indeterminateContent} {:else}
{/if} - {:else if checked === true} + {:else if showCheckmark} {#if checkedContent} import { animate as motion } from 'motion'; - import { DialogBond } from './bond.svelte'; + import { DURATION } from '$svelte-atoms/core/shared'; import { HtmlAtom, type HtmlAtomProps, type Base } from '$svelte-atoms/core/components/atom'; + import { DialogBond } from './bond.svelte'; const bond = DialogBond.get(); @@ -32,20 +33,16 @@ const open = $derived(bond?.state?.props?.open ?? false); function _animate(node: HTMLElement) { + if (open) { + bond?.elements.root?.show?.(); + } + motion( node, { scale: 0.9 + 0.1 * +open, opacity: +open }, { - duration: 0.3, - ease: 'anticipate', - onComplete: () => { - if (!open) { - const root = bond?.elements.root; - - root?.close?.(); - console.log(root); - } - } + duration: DURATION.normal / 1000, + ease: 'anticipate' } ); } diff --git a/src/lib/components/dialog/dialog-root.svelte b/src/lib/components/dialog/dialog-root.svelte index 3b8f3f3..2756221 100644 --- a/src/lib/components/dialog/dialog-root.svelte +++ b/src/lib/components/dialog/dialog-root.svelte @@ -13,10 +13,11 @@ diff --git a/src/lib/components/dropdown/item/bond.svelte.ts b/src/lib/components/dropdown/item/bond.svelte.ts index 0351608..252f106 100644 --- a/src/lib/components/dropdown/item/bond.svelte.ts +++ b/src/lib/components/dropdown/item/bond.svelte.ts @@ -2,6 +2,7 @@ import type { PopoverStateProps } from '$svelte-atoms/core/components/popover/bo import { getContext, setContext } from 'svelte'; import { Bond, BondState, type BondStateProps } from '$svelte-atoms/core/shared/bond.svelte'; import { DropdownBond, DropdownBondState } from '../bond.svelte'; +import { createAttachmentKey } from 'svelte/attachments'; export type DropdownItemBondProps = BondStateProps & { value: string; @@ -62,6 +63,15 @@ export class DropdownItemBond extends Bond< return DropdownItemBond.set(this) as this; } + root() { + return { + 'data-selected': this.state.isSelected, + [createAttachmentKey()]: (node: HTMLElement) => { + this.elements.root = node; + } + }; + } + static get(): DropdownItemBond | undefined { return getContext(DropdownItemBond.CONTEXT_KEY); } diff --git a/src/lib/components/dropdown/item/dropdown-item.svelte b/src/lib/components/dropdown/item/dropdown-item.svelte index f30f7ff..f94b87d 100644 --- a/src/lib/components/dropdown/item/dropdown-item.svelte +++ b/src/lib/components/dropdown/item/dropdown-item.svelte @@ -41,6 +41,11 @@ const unmount = bond.mount(); $effect(() => unmount); + const rootProps = $derived({ + ...bond?.root?.(), + ...restProps + }); + function _factory() { const item = dropdown?.state.item(value); @@ -56,7 +61,7 @@ return new DropdownItemBond(bondState); } - function _onclick(ev: MouseEvent) { + function handleClick(ev: MouseEvent) { onclick?.(ev); if (ev.defaultPrevented) { @@ -76,12 +81,11 @@ (bond.elements.root = node)} {bond} {preset} class={[ - bond.state.isHighlighted && 'bg-foreground/10', - bond.state.isSelected && 'bg-accent/10', + bond.state.isHighlighted && 'bg-foreground/5', + bond.state.isSelected && 'bg-primary/5 hover:bg-primary/10 active:bg-primary/15', '$preset', klass ]} @@ -91,8 +95,8 @@ animate={animate?.bind(bond.state)} onmount={onmount?.bind(bond.state)} ondestroy={ondestroy?.bind(bond.state)} - onclick={_onclick} - {...restProps} + onclick={handleClick} + {...rootProps} > {@render children?.({ dropdownItem: bond })} diff --git a/src/lib/components/form/field/bond.svelte.ts b/src/lib/components/form/field/bond.svelte.ts index b186496..e8dbe23 100644 --- a/src/lib/components/form/field/bond.svelte.ts +++ b/src/lib/components/form/field/bond.svelte.ts @@ -76,6 +76,10 @@ export type FieldStateProps< readonly: boolean; name?: string; value?: Value; + files?: File[]; + date?: Date | null; + number?: number; + checked?: boolean; schema?: Schema; validator?: ValidationAdapter; onvalidation?: (errors: ValidationError[]) => void; @@ -158,7 +162,7 @@ export class FieldBondState< constructor(props: () => Props) { super(props); - this.#form = FormBond.get().state; + this.#form = FormBond.get()?.state; if (!this.#form) { throw new Error( @@ -171,6 +175,22 @@ export class FieldBondState< return this.props.value; } + get files() { + return this.props.files; + } + + get date() { + return this.props.date; + } + + get number() { + return this.props.number; + } + + get checked() { + return this.props.checked; + } + get errors() { return [...this.#errors]; } diff --git a/src/lib/components/form/field/field-control.svelte b/src/lib/components/form/field/field-control.svelte index 33e3f9b..e8ef4b6 100644 --- a/src/lib/components/form/field/field-control.svelte +++ b/src/lib/components/form/field/field-control.svelte @@ -26,6 +26,9 @@ class: klass = '', value = $bindable(), checked = $bindable(), + number = $bindable(), + date = $bindable(), + files = $bindable(), children = undefined, oninput = undefined, ...restProps @@ -41,6 +44,10 @@ } bond.state.props.value = value = detail?.value; + bond.state.props.files = files = detail?.files ?? []; + bond.state.props.date = date = detail?.date ?? null; + bond.state.props.number = number = detail?.number ?? null; + bond.state.props.checked = checked = detail?.checked ?? false; } diff --git a/src/lib/components/form/form.stories.svelte b/src/lib/components/form/form.stories.svelte index f5ba2be..79ea79f 100644 --- a/src/lib/components/form/form.stories.svelte +++ b/src/lib/components/form/form.stories.svelte @@ -72,7 +72,7 @@
- Is Admin + Is Admin?
diff --git a/src/lib/components/input/input-root.svelte b/src/lib/components/input/input-root.svelte index a98d235..af4a8e8 100644 --- a/src/lib/components/input/input-root.svelte +++ b/src/lib/components/input/input-root.svelte @@ -1,17 +1,9 @@ @@ -130,7 +131,7 @@ {bond} preset="popover.content" class={[ - 'popover-content bg-background border-border rounded-md border p-2 opacity-0 shadow-lg', + 'popover-content bg-popover text-popover-foreground border-border rounded-md border p-2 opacity-0 shadow-lg', '$preset', klass ]} diff --git a/src/lib/components/radio/radio-group.stories.svelte b/src/lib/components/radio/radio-group.stories.svelte index 96d6711..241e084 100644 --- a/src/lib/components/radio/radio-group.stories.svelte +++ b/src/lib/components/radio/radio-group.stories.svelte @@ -20,22 +20,22 @@
diff --git a/src/lib/components/radio/radio.svelte b/src/lib/components/radio/radio.svelte index 8e204d9..23dbc9a 100644 --- a/src/lib/components/radio/radio.svelte +++ b/src/lib/components/radio/radio.svelte @@ -72,7 +72,7 @@ {:else} - + {/if} {/if} diff --git a/src/lib/components/root/root.css b/src/lib/components/root/root.css index 5b5f183..b29485f 100644 --- a/src/lib/components/root/root.css +++ b/src/lib/components/root/root.css @@ -20,11 +20,12 @@ --border: oklch(0.922 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); - --chart-1: oklch(0.81 0.1 252); - --chart-2: oklch(0.62 0.19 260); - --chart-3: oklch(0.55 0.22 263); - --chart-4: oklch(0.49 0.22 264); - --chart-5: oklch(0.42 0.18 266); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); @@ -33,23 +34,13 @@ --sidebar-accent-foreground: oklch(0.205 0 0); --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); - --font-sans: - ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; - --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif; - --font-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; --radius: 0.625rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --shadow-x: 0px; + --shadow-y: 1px; + --shadow-blur: 2px; + --shadow-spread: 0px; + --shadow-opacity: 0.18; + --shadow-color: hsl(0 0% 0%); --tracking-normal: 0em; --spacing: 0.25rem; } @@ -59,7 +50,7 @@ --foreground: oklch(0.985 0 0); --card: oklch(0.205 0 0); --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.269 0 0); + --popover: oklch(0.205 0 0); --popover-foreground: oklch(0.985 0 0); --primary: oklch(0.922 0 0); --primary-foreground: oklch(0.205 0 0); @@ -67,43 +58,27 @@ --secondary-foreground: oklch(0.985 0 0); --muted: oklch(0.269 0 0); --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.371 0 0); + --accent: oklch(0.269 0 0); --accent-foreground: oklch(0.985 0 0); --destructive: oklch(0.704 0.191 22.216); --destructive-foreground: oklch(0.985 0 0); - --border: oklch(0.275 0 0); - --input: oklch(0.325 0 0); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); --ring: oklch(0.556 0 0); - --chart-1: oklch(0.81 0.1 252); - --chart-2: oklch(0.62 0.19 260); - --chart-3: oklch(0.55 0.22 263); - --chart-4: oklch(0.49 0.22 264); - --chart-5: oklch(0.42 0.18 266); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.985 0 0); --sidebar-primary: oklch(0.488 0.243 264.376); --sidebar-primary-foreground: oklch(0.985 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(0.275 0 0); - --sidebar-ring: oklch(0.439 0 0); - --font-sans: - ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; - --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif; - --font-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; - --radius: 0.625rem; - --shadow-2xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-xs: 0 1px 3px 0px hsl(0 0% 0% / 0.05); - --shadow-sm: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 1px 2px -1px hsl(0 0% 0% / 0.1); - --shadow-md: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 2px 4px -1px hsl(0 0% 0% / 0.1); - --shadow-lg: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 4px 6px -1px hsl(0 0% 0% / 0.1); - --shadow-xl: 0 1px 3px 0px hsl(0 0% 0% / 0.1), 0 8px 10px -1px hsl(0 0% 0% / 0.1); - --shadow-2xl: 0 1px 3px 0px hsl(0 0% 0% / 0.25); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); + --shadow-color: hsl(0, 0%, 100%); } @theme inline { @@ -140,22 +115,5 @@ --color-sidebar-border: var(--sidebar-border); --color-sidebar-ring: var(--sidebar-ring); - --font-sans: var(--font-sans); - --font-mono: var(--font-mono); - --font-serif: var(--font-serif); - - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); --radius-inherit: inherit; - - --shadow-2xs: var(--shadow-2xs); - --shadow-xs: var(--shadow-xs); - --shadow-sm: var(--shadow-sm); - --shadow: var(--shadow); - --shadow-md: var(--shadow-md); - --shadow-lg: var(--shadow-lg); - --shadow-xl: var(--shadow-xl); - --shadow-2xl: var(--shadow-2xl); } diff --git a/src/lib/components/sidebar/sidebar-content.svelte b/src/lib/components/sidebar/sidebar-content.svelte index a12463e..176cd62 100644 --- a/src/lib/components/sidebar/sidebar-content.svelte +++ b/src/lib/components/sidebar/sidebar-content.svelte @@ -1,21 +1,7 @@ - - - @@ -18,275 +51,126 @@
- - - - -
-
-

Accordion

- Stable -
-

- Collapsible content sections for organizing information. Perfect for FAQs, settings panels, - and content organization. -

-
+ - -
-

Installation

-
-
- Installation - -
- - import - { - Accordion - , - AccordionItem - } - from - 'atomic-sv/accordion'; - -
-
+ - -
-

Examples

+
+ +
+
- -
-
-

Basic Accordion

-

Simple accordion with collapsible sections

-
- -
-
- - - - - What is Atomic SV? - - - - - - - - Atomic SV is a modular, accessible, and extensible Svelte UI component library - built with Svelte 5. - - - - - - How do I install it? - - - - - - - - Simply run npm install atomic-sv to add it to your project. Import components as - needed. - - - - - + + + + What is Atomic SV? + + - Is it accessible? - - - - - - - - Yes, all Atomic SV components are built with accessibility in mind. They include - proper ARIA attributes, keyboard navigation, and screen reader support out of the - box. - - - -
-
+ + + + + + Atomic SV is a modular, accessible, and extensible Svelte UI component library built + with Svelte 5. + + -
-
- Code - -
-
{`
-  
-    What is Atomic SV?
-    
-      Atomic SV is a modular, accessible, and extensible 
-      Svelte UI component library built with Svelte 5.
-    
-  
-  
-    How do I install it?
-    
-      Simply run npm install atomic-sv
-    
-  
-`}
-
-
+ + + + Opening this section won't close the others. + + + +
-
- - -
-

Features

-
-
-
- - - -
-

Fully Accessible

-

- Built with ARIA best practices, keyboard navigation, and screen reader support. -

-
- -
-
- - - - -
-

Customizable

-

- Style with Tailwind CSS or your own CSS. Full control over appearance and behavior. -

-
- -
-
- - - -
-

Smooth Animations

-

- Built-in smooth expand/collapse animations with respect for reduced motion preferences. -

-
- -
-
- - - -
-

Flexible Modes

-

- Supports single or multiple panel expansion modes for different use cases. -

-
-
-
- - -
-

API Reference

+
+
-
-

Accordion Props

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropTypeDefaultDescription
multiplebooleanfalseAllow multiple panels to be open simultaneously
collapsiblebooleantrueAllow panels to be collapsed when in single mode
classstring''Additional CSS classes
-
+

Accordion Props

+
-
-
- -
-

Accessibility

-
-
- - - -
-

Built-in Accessibility Features

-
    -
  • • Proper ARIA attributes (aria-expanded, aria-controls, etc.)
  • -
  • • Keyboard navigation (Enter, Space, Arrow keys)
  • -
  • • Focus management with visible indicators
  • -
  • • Screen reader announcements for state changes
  • -
  • • Semantic HTML structure
  • -
  • • Respects prefers-reduced-motion setting
  • -
-
+
+

AccordionItem.Header Props

+
-
+
- - +
diff --git a/src/routes/components/button/+page.svelte b/src/routes/components/button/+page.svelte index e32aae0..d2d29ff 100644 --- a/src/routes/components/button/+page.svelte +++ b/src/routes/components/button/+page.svelte @@ -1,176 +1,191 @@ - Button | Atomic SV + Button - Atomic SV -
-
- -
- - - - -
-
-

Button

- Stable -
-

- Interactive element for triggering actions. Supports various styles, sizes, and states. -

-
+
+ + + + +
+ +
-
-

Simple Usage

- - -
- - - - -
-

Preview

- - - - - - -
- - -
-

Props

- -
- - -
-

Accessibility

- -
- - - - - - Built-in Accessibility Features +
+
+ + + + + +
+ + +
- -
    -
  • • Proper semantic button element with role
  • -
  • • Keyboard navigation support (Enter and Space keys)
  • -
  • • Focus management with visible focus indicators
  • -
  • • Screen reader compatible with proper ARIA attributes
  • -
  • • Disabled state handling
  • -
-
- -
- - - + + + - Next: Checkbox - - - - + +
-
- - + +
+ +
+ +
+ +
+ +
- - diff --git a/src/routes/components/checkbox/+page.svelte b/src/routes/components/checkbox/+page.svelte index e55b5e5..779dbe2 100644 --- a/src/routes/components/checkbox/+page.svelte +++ b/src/routes/components/checkbox/+page.svelte @@ -1,14 +1,40 @@ @@ -17,258 +43,126 @@
- - - - -
-
-

Checkbox

- Stable -
-

- Selection control for multiple choices. Allows users to select one or more options from a set. -

-
+ - -
-

Installation

-
-
- Installation - -
- - import Checkbox - from - 'atomic-sv/checkbox'; - -
-
+ - -
-

Examples

+
+ +
+
- -
-
-

Basic Checkbox

-

Simple checkbox with label

+ +
+ +
+
-
-
-
- - -
+ +
+
+ +
-
- -
-
- Code - +
+ +
-
{`
-`}
-
-
- - -
-
-

Checkbox Group

-

- Multiple checkboxes for selecting multiple options -

-
- -
-
-
-
- - -
-
- - -
-
- - -
-
+
+ +
+ -
-
- Code - -
-
{`
-
- - -
-
- - -
-
- - -
-
`}
+ +
+ +
-
+
-
+
+ +
+ +
- - +
diff --git a/src/routes/components/form/+page.svelte b/src/routes/components/form/+page.svelte index 1caa0e7..118e6c7 100644 --- a/src/routes/components/form/+page.svelte +++ b/src/routes/components/form/+page.svelte @@ -1,85 +1,17 @@ - Form & Field Components - Atomic SV + Form & Field - Atomic SV -
-
- -
- - +
+ - -
-
-

Form & Field

- Stable -
-

- Composable form and field components for building accessible, validated forms with powerful - state management. -

-
+ - -
-

Installation

-
-
- Installation - -
- - import - {{ Form, Field }} - from - 'atomic-sv/form'; - -
-
+
+ +
- +
+
+ +
e.preventDefault()}> + + + Name + + + + + - -
-

Examples

+
+ + +
-
- {#each examples as example, i} - -
-

{example.title}

-

{example.description}

-
+ + + - - -
- {#if i === 0} - -
e.preventDefault()}> - - - Name - - - - - -
- - -
- -
- {:else if i === 1} - -
e.preventDefault()}> -
- - -
-
- - -
- -
- {:else if i === 2} - -
e.preventDefault()}> -
- - -
-
- - -
-
- - -
- -
- {/if} -
-
+ +
e.preventDefault()}> +
+ + +
- - - - {/each} -
-
+
+ + +

Password must be at least 8 characters

+
- -
-

Form Component Props

- ', - default: '-', - description: 'Content to render with access to form state' - }, - { - name: 'class', - type: 'string', - default: '', - description: 'Additional CSS classes to apply to the form element' - } - ]} - > -
+ + +
+
+
- -
-

Field Component Props

+
+
+
+

Form Props

+
+ + + + Prop + Type + Default + Description + + -
-
-

Field.Root

- ', - default: '-', - description: 'Content to render with access to field state' - } - ]} - > + + + class + string + '' + Additional CSS classes to apply + + + onsubmit + function + - + Form submission handler + + + children + Snippet + - + Form content + + +
+
-
-

Field.Label

- -
+
+

Field.Root Props

+
+ + + + Prop + Type + Default + Description + + -
-

Field.Control

- + + + name + string + - + Field name for form data + + + value + any + '' + Field value + + + class + string + '' + Additional CSS classes + + +
-
- -
-

Accessibility

-
-
- - - -
-

- Built-in Accessibility Features -

-
    -
  • • Automatic label-control association with proper `for` attributes
  • -
  • • Semantic form structure with proper roles and ARIA attributes
  • -
  • • Keyboard navigation support for all form controls
  • -
  • • Screen reader compatibility with descriptive labels
  • -
  • • Focus management with visible focus indicators
  • -
  • • Form validation states communicated to assistive technologies
  • -
  • • Proper fieldset and legend usage for grouped controls
  • -
-
+
+

Field.Label Props

+
+ + + + Prop + Type + Default + Description + + + + + + for + string + - + ID of the associated form control + + + class + string + '' + Additional CSS classes + + + children + Snippet + - + Label content + + +
-
- -
-

Usage Patterns

-
-
-

Simple Form

-

- Use standard HTML form elements for basic forms without complex state management needs. -

-
- - <form>
-   <input type="text" />
-   <button>Submit</button>
- </form> -
-
-
+
+

Field.Control Props

+
+ + + + Prop + Type + Default + Description + + -
-

Advanced Form

-

- Use Form and Field components for complex forms with validation, state management, and - dynamic behavior. -

-
- - <Form>
-   <Field.Root>
-     <Field.Label />
-     <Field.Control />
-   </Field.Root>
- </Form> -
-
+ + + component + Component + - + Component to use for the control + + + class + string + '' + Additional CSS classes + + + ...props + any + - + All other props passed to control component + + +
-
- - - -
+ - + + + +
- - diff --git a/src/routes/header.svelte b/src/routes/header.svelte index a99ba83..97aa8ce 100644 --- a/src/routes/header.svelte +++ b/src/routes/header.svelte @@ -27,12 +27,12 @@