# Halo Widgets - Svelte Guide

A complete guide for using Halo Widgets in Svelte applications.

---

## 📦 Installation

### Using npm
```bash
npm install halo-widgets
```

### Using yarn
```bash
yarn add halo-widgets
```

### Using pnpm
```bash
pnpm add halo-widgets
```

---

## 🚀 Quick Start

### 1. Import CSS Styles

In SvelteKit, import the widget styles in your root layout (`src/routes/+layout.svelte`):

```svelte
<script lang="ts">
  import 'halo-widgets/css';
  let { children } = $props();
</script>

{@render children?.()}
```

For non-Kit projects, import it once in your main entry (e.g., `main.ts`).

### 2. Import Widgets

Import the widgets you need from `halo-widgets/svelte`:

```typescript
import { TextInput, PasswordInput, EmailInput } from 'halo-widgets/svelte';
```

### 3. Use in Components

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  let username = '';
</script>

<TextInput
  label="Username"
  placeholder="Enter your username"
  value={username}
  onChange={(val) => (username = val)}
  required={true}
/>
```

---

## 📚 Available Widgets

All widgets are imported from `halo-widgets/svelte`:

```typescript
import {
  TextInput,        // Text input with validation & suggestions
  PasswordInput,    // Password with strength meter & generator
  EmailInput,       // Email with domain suggestions
  PhoneInput,       // International phone with country picker
  DateInput,        // Date picker (single, range, month)
  LocationInput,    // Google Places autocomplete
  NumberInput,      // Numeric input with formatting
  SliderInput,      // Range slider
  RadioInput,       // Radio button group
  CheckboxInput,    // Checkbox group (single or multi-select)
  DropdownInput,    // Searchable dropdown
  TextareaInput,    // Multi-line text input
} from 'halo-widgets/svelte';
```

---

## 💡 Complete Examples

### TextInput - Basic Usage

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  let username = '';
  const handleValidate = (isValid: boolean, error?: string) => {
    console.log('Valid:', isValid, error);
  };
</script>

<TextInput
  label="Username"
  placeholder="Enter your username"
  helperText="3-20 characters, lowercase only"
  value={username}
  onChange={(val) => (username = val)}
  required={true}
  minLength={3}
  maxLength={20}
  counter={true}
  clearable={true}
  allowSpaces={false}
  caseTransform="lowercase"
  onValidate={handleValidate}
/>
```

### PasswordInput - With Strength Meter

```svelte
<script lang="ts">
  import { PasswordInput } from 'halo-widgets/svelte';
  let password = '';
  const handleStrengthChange = (score: number, feedback: string) => {
    console.log('Password strength:', feedback, 'Score:', score);
  };
</script>

<PasswordInput
  label="Password"
  placeholder="Enter a strong password"
  helperText="At least 8 characters with uppercase, lowercase, number, and symbol"
  value={password}
  onChange={(val) => (password = val)}
  required={true}
  minLength={8}
  showToggle={true}
  showStrength={true}
  showRequirements={true}
  showGenerator={true}
  showCopy={false}
  requireLowercase={true}
  requireUppercase={true}
  requireNumber={true}
  requireSymbol={true}
  onStrengthChange={handleStrengthChange}
/>
```

### EmailInput - With Domain Suggestions

```svelte
<script lang="ts">
  import { EmailInput } from 'halo-widgets/svelte';
  let email = '';
</script>

<EmailInput
  label="Email Address"
  placeholder="you@example.com"
  helperText="We'll never share your email"
  value={email}
  onChange={(val) => {
    if (typeof val === 'string') {
      email = val;
    }
  }}
  required={true}
  showDomainSuggestions={true}
  lowercase={true}
  trim={true}
  clearable={true}
/>
```

### PhoneInput - International

```svelte
<script lang="ts">
  import { PhoneInput } from 'halo-widgets/svelte';
  let phone = '';
</script>

<PhoneInput
  label="Phone Number"
  placeholder="Enter phone number"
  helperText="International format"
  value={phone}
  onChange={(e164) => (phone = e164)}
  required={true}
  allowCountrySelect={true}
  country="US"
  format="international"
  separateDialCode={true}
  clearable={true}
/>
```

### DateInput - Single & Range

```svelte
<script lang="ts">
  import { DateInput } from 'halo-widgets/svelte';
  let date = '';
  let dateRange: [string, string] = ['', ''];
</script>

<!-- Single Date -->
<DateInput
  label="Select Date"
  placeholder="Pick a date"
  value={date}
  onChange={(val) => {
    if (typeof val === 'string') {
      date = val;
    }
  }}
  mode="single"
  format="MM/DD/YYYY"
  clearable={true}
/>

<!-- Date Range -->
<DateInput
  label="Select Date Range"
  placeholder="Pick start and end dates"
  value={dateRange}
  onChange={(val) => {
    if (Array.isArray(val)) {
      dateRange = val as [string, string];
    }
  }}
  mode="range"
  format="MM/DD/YYYY"
  clearable={true}
/>
```

### LocationInput - Google Places

```svelte
<script lang="ts">
  import { LocationInput } from 'halo-widgets/svelte';
  let location = '';
</script>

<LocationInput
  label="Location"
  placeholder="Search for a location"
  helperText="Start typing to search"
  value={location}
  onChange={(val) => {
    location = val.label;
    console.log('Full location data:', val);
  }}
  apiKey="YOUR_GOOGLE_MAPS_API_KEY"
  allowCoordinates={true}
  countryCodes={["US", "CA"]}
  clearable={true}
/>
```

### NumberInput - Currency & Percentage

```svelte
<script lang="ts">
  import { NumberInput } from 'halo-widgets/svelte';
  let price = 0;
  let percentage = 50;
</script>

<!-- Currency -->
<NumberInput
  label="Price"
  placeholder="0.00"
  value={price}
  onChange={(val) => {
    if (val !== null) {
      price = val;
    }
  }}
  prefix="$"
  precision={2}
  min={0}
  thousandSeparator={true}
/>

<!-- Percentage -->
<NumberInput
  label="Discount"
  value={percentage}
  onChange={(val) => {
    if (val !== null) {
      percentage = val;
    }
  }}
  suffix="%"
  min={0}
  max={100}
  precision={0}
/>
```

### SliderInput - Volume & Range

```svelte
<script lang="ts">
  import { SliderInput } from 'halo-widgets/svelte';
  let volume = 50;
  let priceRange: [number, number] = [20, 80];
</script>

<!-- Single Value -->
<SliderInput
  label="Volume"
  value={volume}
  onChange={(val) => (volume = val as number)}
  min={0}
  max={100}
  suffix="%"
  showValueBubble={true}
/>

<!-- Range -->
<SliderInput
  label="Price Range"
  value={priceRange}
  onChange={(val) => (priceRange = val as [number, number])}
  mode="range"
  min={0}
  max={100}
  prefix="$"
  showValueBubble={true}
/>
```

### RadioInput - Single Selection

```svelte
<script lang="ts">
  import { RadioInput } from 'halo-widgets/svelte';
  let plan = 'basic';
</script>

<RadioInput
  label="Choose a Plan"
  helperText="Select your subscription tier"
  options={[
    { label: 'Basic - $9/mo', value: 'basic' },
    { label: 'Pro - $29/mo', value: 'pro' },
    { label: 'Enterprise - $99/mo', value: 'enterprise' },
  ]}
  value={plan}
  onChange={(val) => (plan = val || 'basic')}
  required={true}
/>
```

### CheckboxInput - Multi-Select

```svelte
<script lang="ts">
  import { CheckboxInput } from 'halo-widgets/svelte';
  let interests: string[] = [];
</script>

<CheckboxInput
  label="Select Your Interests"
  helperText="Choose at least one"
  options={[
    { label: 'AI & Machine Learning', value: 'ai' },
    { label: 'Web Development', value: 'web' },
    { label: 'Mobile Apps', value: 'mobile' },
    { label: 'Data Science', value: 'data' },
    { label: 'DevOps', value: 'devops' },
  ]}
  value={interests}
  onChange={(vals) => (interests = vals)}
  required={true}
  minSelected={1}
/>
```

### DropdownInput - Searchable

```svelte
<script lang="ts">
  import { DropdownInput } from 'halo-widgets/svelte';
  let country = 'us';
  let countries: string[] = [];
</script>

<!-- Single select -->
<DropdownInput
  label="Select Country"
  placeholder="Choose a country..."
  helperText="Select your country of residence"
  options={[
    { label: 'United States', value: 'us' },
    { label: 'Canada', value: 'ca' },
    { label: 'United Kingdom', value: 'uk' },
    { label: 'Germany', value: 'de' },
    { label: 'France', value: 'fr' },
  ]}
  value={country}
  onChange={(val) => (country = val as string)}
  searchable={true}
  clearable={true}
  required={true}
/>

<!-- Multi-Select Dropdown -->
<DropdownInput
  label="Select Countries"
  placeholder="Choose multiple countries..."
  options={[
    { label: 'United States', value: 'us' },
    { label: 'Canada', value: 'ca' },
    { label: 'United Kingdom', value: 'uk' },
  ]}
  value={countries}
  onChange={(val) => (countries = val as string[])}
  multiple={true}
  searchable={true}
  maxSelected={3}
/>
```

### TextareaInput - Multi-Line

```svelte
<script lang="ts">
  import { TextareaInput } from 'halo-widgets/svelte';
  let description = '';
</script>

<TextareaInput
  label="Description"
  placeholder="Tell us about your project..."
  helperText="Minimum 20 characters"
  value={description}
  onChange={(val) => (description = val)}
  required={true}
  minLength={20}
  maxLength={500}
  rows={4}
  autoGrow={true}
  counter={true}
  clearable={true}
/>
```

---

## 🎨 Styling & Theming

### Using CSS Variables

Customize widget appearance with CSS variables:

```css
:root {
  --halo-color-primary: #6366f1;
  --halo-color-accent: #8b5cf6;
  --halo-color-surface: #ffffff;
  --halo-color-bg: #f9fafb;
  --halo-color-text: #111827;
  --halo-color-muted: #6b7280;
  --halo-color-border: #e5e7eb;
  --halo-color-error: #ef4444;
  --halo-color-success: #10b981;
  --halo-color-warning: #f59e0b;
  --halo-font-family: system-ui, -apple-system, sans-serif;
  --halo-radius: 8px;
  --halo-border: 1px solid var(--halo-color-border);
}
```

### Using className Prop

Add custom styles to any widget:

```svelte
<TextInput
  className="my-custom-input"
  label="Username"
  value={username}
  onChange={(val) => (username = val)}
/>
```

```css
.my-custom-input {
  max-width: 400px;
  margin-bottom: 1rem;
}
```

### Size Variants

Most widgets support size variants:

```svelte
<TextInput size="sm" label="Small" />
<TextInput size="md" label="Medium (default)" />
<TextInput size="lg" label="Large" />
```

### Style Variants

Some widgets support style variants:

```svelte
<TextInput variant="outlined" label="Outlined (default)" />
<TextInput variant="filled" label="Filled" />
```

---

## 🎯 TypeScript Support

All widgets are fully typed. Import types for better IDE support:

```typescript
import { 
  TextInput, 
  type TextInputProps 
} from 'halo-widgets/svelte';

// Use in your component props
interface MyFormProps {
  textInputProps?: Partial<TextInputProps>;
}

function MyForm({ textInputProps }: MyFormProps) {
  return <TextInput {...textInputProps} />;
}
```

### Available Types

```typescript
import type {
  TextInputProps,
  PasswordInputProps,
  EmailInputProps,
  PhoneInputProps,
  DateInputProps,
  LocationInputProps,
  NumberInputProps,
  SliderInputProps,
  RadioInputProps,
  CheckboxInputProps,
  DropdownInputProps,
  TextareaInputProps,
} from 'halo-widgets/svelte';
```

---

## 🔧 Common Patterns

### Form with Multiple Widgets

```svelte
<script lang="ts">
  import { 
    TextInput, 
    EmailInput, 
    PasswordInput, 
    CheckboxInput 
  } from 'halo-widgets/svelte';

  let formData = {
    username: '',
    email: '',
    password: '',
    interests: [] as string[],
  };

  const handleSubmit = (e: Event) => {
    e.preventDefault();
    console.log('Form submitted:', formData);
  };
</script>

<form on:submit={handleSubmit}>
  <TextInput
    label="Username"
    value={formData.username}
    onChange={(val) => (formData.username = val)}
    required={true}
  />

  <EmailInput
    label="Email"
    value={formData.email}
    onChange={(val) => {
      if (typeof val === 'string') {
        formData.email = val;
      }
    }}
    required={true}
  />

  <PasswordInput
    label="Password"
    value={formData.password}
    onChange={(val) => (formData.password = val)}
    required={true}
    showStrength={true}
  />

  <CheckboxInput
    label="Interests"
    options={[
      { label: 'Web Dev', value: 'web' },
      { label: 'Mobile', value: 'mobile' },
    ]}
    value={formData.interests}
    onChange={(vals) => (formData.interests = vals)}
  />

  <button type="submit">Register</button>
</form>
```

### Validation Handling

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  let value = '';
  let isValid = true;
  let error = '';
</script>

<TextInput
  label="Username"
  value={value}
  onChange={(val) => (value = val)}
  minLength={3}
  maxLength={20}
  pattern="^[a-zA-Z0-9_]+$"
  onValidate={(valid, errorMsg) => {
    isValid = valid;
    error = errorMsg || '';
  }}
  invalid={!isValid}
/>
```

### Controlled vs Uncontrolled

```svelte
<!-- Controlled (recommended) -->
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  let value = '';
</script>

<TextInput
  value={value}
  onChange={(val) => (value = val)}
/>

<!-- Uncontrolled -->
<TextInput
  defaultValue="initial value"
  onChange={(val) => console.log('Value:', val)}
/>
```

### Debounced API Calls

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  let query = '';

  const handleSearch = (value: string) => {
    query = value;
    // This will be debounced automatically
    console.log('Searching for:', value);
  };
</script>

<TextInput
  label="Search"
  placeholder="Type to search..."
  value={query}
  onChange={handleSearch}
  debounceMs={500}
/>
```

---

## ⚙️ Advanced Usage

### API-Based Suggestions

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
</script>

<TextInput
  label="Search Words"
  placeholder="Type to get suggestions..."
  suggestionsSource="api"
  suggestionsApi="https://api.datamuse.com/sug?s="
  minCharsForSuggestions={2}
  debounceMs={300}
/>
```

### Custom Validation

```svelte
<script lang="ts">
  import { TextInput } from 'halo-widgets/svelte';
  
  const validateUsername = (value: string): string | null => {
    if (value.includes('admin')) {
      return "Username cannot contain 'admin'";
    }
    if (value.length < 3) {
      return 'Username must be at least 3 characters';
    }
    return null; // null means valid
  };
</script>

<TextInput
  label="Username"
  validate={validateUsername}
  validateOn="change"
/>
```

### Password with Breach Check

```svelte
<script lang="ts">
  import { PasswordInput } from 'halo-widgets/svelte';
</script>

<PasswordInput
  label="Password"
  checkPwned={true}
  minLengthForPwned={8}
  showRequirements={true}
  requireLowercase={true}
  requireUppercase={true}
  requireNumber={true}
  requireSymbol={true}
/>
```

---

## 🐛 Troubleshooting

### Styles Not Applied

**Problem:** Widgets appear unstyled

**Solution:** Make sure you imported the CSS:
```typescript
import 'halo-widgets/css';
```

### TypeScript Errors

**Problem:** Type errors on props

**Solution:** Check the prop names in `PROPS_REFERENCE.md`. Common mistakes:
- ❌ `showCounter` → ✅ `counter`
- ❌ `showCopyButton` → ✅ `showCopy`
- ❌ `showVisibilityToggle` → ✅ `showToggle`

### SSR Error: Unknown file extension ".svelte"

**Problem:** In SvelteKit SSR, you see `Unknown file extension ".svelte"` from `node_modules/halo-widgets/...`.

**Solution:** Configure Vite to bundle the library during SSR:
```typescript
// vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [sveltekit()],
  ssr: {
    noExternal: ['halo-widgets']
  }
});
```

### LocationInput Not Working

**Problem:** LocationInput doesn't show suggestions

**Solution:** You need a valid Google Maps API key:
```svelte
<LocationInput apiKey="YOUR_ACTUAL_API_KEY" />
```

---

## 📋 Requirements

- Svelte 4 or 5
- SvelteKit (recommended)
- TypeScript 5.0+ (optional, but recommended)

---

## 🔗 Additional Resources

- **Props Reference:** See `PROPS_REFERENCE.md` for complete prop documentation
- **Examples:** Check `src/routes/+page.svelte` for working examples
- **Package Version:** v1.1.5

---

## 💪 Best Practices

1. **Always import CSS** in your root layout
2. **Use controlled components** with reactive variables
3. **Validate user input** using built-in validation props
4. **Handle null values** for NumberInput onChange
5. **Type check arrays** for EmailInput with multiple emails
6. **Use TypeScript types** for better IDE support
7. **Debounce API calls** to reduce server load
8. **Provide helper text** to guide users
9. **Mark required fields** with `required={true}`
10. **Test validation** with `onValidate` callback

---

## 🎉 Quick Start Template

Copy this template to get started quickly:

```svelte
<script lang="ts">
  import { TextInput, EmailInput, PasswordInput } from 'halo-widgets/svelte';
  let username = '';
  let email = '';
  let password = '';

  const handleSubmit = (e: Event) => {
    e.preventDefault();
    console.log({ username, email, password });
  };
</script>

<form on:submit={handleSubmit}>
  <TextInput
    label="Username"
    placeholder="Enter username"
    value={username}
    onChange={(val) => (username = val)}
    required={true}
    minLength={3}
    maxLength={20}
    counter={true}
  />

  <EmailInput
    label="Email"
    placeholder="you@example.com"
    value={email}
    onChange={(val) => {
      if (typeof val === 'string') email = val;
    }}
    required={true}
    showDomainSuggestions={true}
  />

  <PasswordInput
    label="Password"
    placeholder="Enter password"
    value={password}
    onChange={(val) => (password = val)}
    required={true}
    minLength={8}
    showStrength={true}
    showToggle={true}
  />

  <button type="submit">Submit</button>
</form>
```

---

**Happy coding with Halo Widgets! 🚀**