Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
284356c
feat: implement calendar component
ryu-man Nov 14, 2025
5a136ca
feat: add date picker component
ryu-man Nov 14, 2025
43d234d
fix: refactor html-atom component and add snippet renderer
ryu-man Nov 14, 2025
a83769c
fix: optimize animation logic in popover content component
ryu-man Nov 14, 2025
9de10f6
fix: refactor bondProps definition in popover-root component for clarity
ryu-man Nov 14, 2025
b4adb06
fix: remove unused animation logic from popover content component
ryu-man Nov 14, 2025
bf2baaf
feat: add QR code component and update exports in package.json
ryu-man Nov 14, 2025
1dc6d13
fix: simplify BondStateProps type definition
ryu-man Nov 14, 2025
09c94c1
fix: update defineProperty type definition for clarity and add enumer…
ryu-man Nov 14, 2025
bf9db8c
fix: update dependencies in bun.lock for improved compatibility
ryu-man Nov 14, 2025
6fc3143
fix: add missing class property to button preset in Theme.svelte
ryu-man Nov 14, 2025
b233fc9
fix: rename QR code export path to match component naming convention
ryu-man Nov 14, 2025
4bda8d2
fix: enhance configuration files for improved build and testing perfo…
ryu-man Nov 14, 2025
402e7b0
fix: update implementation status for DatePicker and Calendar compone…
ryu-man Nov 14, 2025
69c751a
fix: update Button component story to include argTypes and refine gho…
ryu-man Nov 14, 2025
b852137
fix: enhance variant system documentation with usage examples and int…
ryu-man Nov 14, 2025
e7caadf
fix: add preset attributes to calendar components for improved struct…
ryu-man Nov 14, 2025
880d944
fix: add preset attributes to DatePicker components for improved stru…
ryu-man Nov 14, 2025
89684d7
fix: add preset attributes to calendar components for improved struct…
ryu-man Nov 14, 2025
06f9f03
fix: remove calendar-event component for codebase cleanup
ryu-man Nov 14, 2025
7c7df44
fix: remove unused compilerOptions from svelte.config.js for cleaner …
ryu-man Nov 14, 2025
1419a0a
fix: add preset attributes to alert components for improved structure…
ryu-man Nov 14, 2025
c8f75e7
fix: adjust gap in alert component for improved layout consistency
ryu-man Nov 14, 2025
cf53053
fix: enhance alert component stories with additional variants
ryu-man Nov 14, 2025
e16e4de
fix: add alert component with variants and styles for improved user f…
ryu-man Nov 14, 2025
514234b
fix: update alert close button styles for improved layout and consist…
ryu-man Nov 14, 2025
7040f8e
fix: remove unnecessary focus styles from alert close button for clea…
ryu-man Nov 14, 2025
611066d
fix: refactor alert close button to improve structure and maintainabi…
ryu-man Nov 14, 2025
22be5fb
fix: update alert close button padding for improved appearance
ryu-man Nov 14, 2025
8003d98
fix: refactor alert component stories for improved structure and cons…
ryu-man Nov 14, 2025
2c56b7c
fix: update alert & button components styles
ryu-man Nov 14, 2025
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
215 changes: 213 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Our comprehensive collection of UI components with implementation status:
| **Switch** | Toggle controls | ❌ |
| [**Textarea**](docs/components/textarea.md) | Multi-line text inputs | ✅ |
| [**Form**](docs/components/form.md) | Form validation and state management | ✅ |
| **DatePicker** | Date selection component | |
| **DatePicker** | Date selection component | |
| **TimePicker** | Time selection component | ❌ |
| **FileUpload** | File upload component | ❌ |
| **ColorPicker** | Color selection component | ❌ |
Expand All @@ -99,7 +99,8 @@ Our comprehensive collection of UI components with implementation status:
| **Progress** | Progress indicators | ❌ |
| **Skeleton** | Loading placeholders | ❌ |
| **Timeline** | Event timeline display | ❌ |
| **Calendar** | Date display component | ❌ |
| **Calendar** | Date display component | ✅ |
| **QRCode** | QR code generator | ✅ |

### Overlays & Feedback

Expand Down Expand Up @@ -351,6 +352,216 @@ This example demonstrates the power of component composition by combining `Dropd
- **Smooth Animations**: Using Svelte's `flip` animation for seamless list transitions
- **Multi-Select State**: Managing complex selection state through the Bond pattern

### Creating Custom Variants

@svelte-atoms/core provides a powerful variant system using `defineVariants()` that allows you to create type-safe, reusable component variations with support for compound variants, defaults, and bond state integration.

#### Basic Variant Definition

```typescript
import { defineVariants, type VariantPropsType } from '@svelte-atoms/core/utils';

const buttonVariants = defineVariants({
class: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
variants: {
variant: {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-200 text-gray-900 hover:bg-gray-300',
ghost: 'hover:bg-gray-100'
},
size: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4',
lg: 'h-12 px-6 text-lg'
}
},
compounds: [
{
variant: 'primary',
size: 'lg',
class: 'shadow-md font-semibold'
}
],
defaults: {
variant: 'primary',
size: 'md'
}
});

// Extract type-safe props
type ButtonVariantProps = VariantPropsType<typeof buttonVariants>;
```

#### Local vs Global Variants

**Local Variants** - Define variants directly in your component:

```svelte
<script lang="ts">
import { HtmlAtom } from '@svelte-atoms/core';
import { defineVariants, type VariantPropsType } from '@svelte-atoms/core/utils';

const buttonVariants = defineVariants({
class: 'rounded-md font-medium',
variants: {
variant: {
primary: 'bg-blue-500 text-white',
secondary: 'bg-gray-500 text-white'
},
size: {
sm: 'px-2 py-1 text-sm',
md: 'px-4 py-2 text-base'
}
},
defaults: {
variant: 'primary',
size: 'md'
}
});

type ButtonProps = VariantPropsType<typeof buttonVariants> & {
disabled?: boolean;
class?: string;
};

let { variant, size, disabled = false, class: klass = '', ...props }: ButtonProps = $props();

const variantProps = $derived(buttonVariants(null, { variant, size }));
</script>

<HtmlAtom
as="button"
variants={variantProps}
{disabled}
class={[variantProps.class, klass]}
{...props}
>
{@render children?.()}
</HtmlAtom>
```

**Global Variants** - Define variants in your theme/preset configuration:

```typescript
// +layout.svelte or theme configuration
import { setPreset } from '@svelte-atoms/core/context';

setPreset({
button: () => ({
class: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
variants: {
variant: {
default: {
class: 'bg-primary text-primary-foreground hover:bg-primary/90'
},
destructive: {
class: 'bg-destructive text-destructive-foreground hover:bg-destructive/90'
},
outline: {
class: 'border border-input bg-background hover:bg-accent'
}
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 px-3',
lg: 'h-11 px-8'
}
},
compounds: [
{
variant: 'default',
size: 'lg',
class: 'text-base font-semibold'
}
],
defaults: {
variant: 'default',
size: 'default'
}
})
});
```

#### Extending Global Variants

Combine global presets with local extensions:

```svelte
<script lang="ts">
import { HtmlAtom } from '@svelte-atoms/core';
import { defineVariants } from '@svelte-atoms/core/utils';

// Extend preset variants with local additions
const extendedVariants = defineVariants({
variants: {
variant: {
// Add new variants not in preset
gradient: {
class: 'bg-gradient-to-r from-purple-500 to-pink-500 text-white'
},
neon: {
class: 'bg-black text-green-400 border-2 border-green-400'
}
},
// Add new variant dimension
animated: {
true: 'animate-pulse',
false: ''
}
},
defaults: {
animated: false
}
});

let { variant, size, animated, ...props } = $props();
</script>

<HtmlAtom
preset="button"
variants={extendedVariants}
as="button"
{variant}
{size}
{animated}
{...props}
>
{@render children?.()}
</HtmlAtom>
```

#### Bond-Reactive Variants

Variants can react to component state through the Bond pattern:

```typescript
const accordionVariants = defineVariants({
class: 'border rounded-md transition-all',
variants: {
state: {
open: (bond) => ({
class: bond?.state?.isOpen ? 'bg-blue-50 border-blue-200' : 'bg-white',
'aria-expanded': bond?.state?.isOpen,
'data-state': bond?.state?.isOpen ? 'open' : 'closed'
})
}
}
});

// Usage with bond
const bond = AccordionBond.get();
const variantProps = $derived(accordionVariants(bond, { state: 'open' }));
```

**Variant Features:**

- ✅ **Type Safety** - Automatic TypeScript inference
- ✅ **Compound Variants** - Apply styles when multiple conditions match
- ✅ **Default Values** - Specify fallback variant values
- ✅ **Bond Integration** - Access component state for reactive styling
- ✅ **Return Attributes** - Not just classes, any HTML attributes
- ✅ **Extensible** - Combine global presets with local variants

---

## 📖 Documentation
Expand Down
13 changes: 10 additions & 3 deletions bun.lock
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "@svelte-atoms/core",
"dependencies": {
"@floating-ui/dom": "^1.7.0",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
"es-toolkit": "^1.37.2",
"gsap": "^3.13.0",
"motion": "^12.23.22",
"nanoid": "^5.1.5",
"tailwind-merge": "^3.2.0",
"uqr": "^0.1.2",
},
"devDependencies": {
"@chromatic-com/storybook": "^4.1.1",
Expand Down Expand Up @@ -455,6 +458,8 @@

"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],

"date-fns": ["date-fns@4.1.0", "", {}, "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg=="],

"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],

"dedent": ["dedent@1.7.0", "", { "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, "optionalPeers": ["babel-plugin-macros"] }, "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ=="],
Expand Down Expand Up @@ -593,7 +598,7 @@

"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],

"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
"js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],

"js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],

Expand Down Expand Up @@ -899,6 +904,8 @@

"unplugin": ["unplugin@1.16.1", "", { "dependencies": { "acorn": "^8.14.0", "webpack-virtual-modules": "^0.6.2" } }, "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w=="],

"uqr": ["uqr@0.1.2", "", {}, "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA=="],

"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],

"util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="],
Expand Down Expand Up @@ -943,6 +950,8 @@

"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],

"@babel/code-frame/js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],

"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],

"@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
Expand Down Expand Up @@ -989,8 +998,6 @@

"rollup/fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],

"strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="],

"svelte/esrap": ["esrap@2.1.0", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" } }, "sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA=="],

"svelte-ast-print/esrap": ["esrap@1.2.2", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1" } }, "sha512-F2pSJklxx1BlQIQgooczXCPHmcWpn6EsP5oo73LQfonG9fIlIENQ8vMmfGXeojP9MrkzUNAfyU5vdFlR9shHAw=="],
Expand Down
Loading