# GroupCheckBox

A flexible group checkbox component that allows users to select multiple options from a predefined list. Supports string-based and bit-based value storage, custom styling variants, and comprehensive state management with focus/blur event handling.

## Installation

```bash
npm install @ticatec/uniface-element
```

## Import

```typescript
import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
import { DisplayMode } from "@ticatec/uniface-element";
import type { OnChangeHandler } from "@ticatec/uniface-element";
```

## Basic Usage

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  
  const options = [
    { code: "js", text: "JavaScript" },
    { code: "ts", text: "TypeScript" },
    { code: "py", text: "Python" },
    { code: "go", text: "Go" }
  ];
  
  let selectedLanguages = "";
  
  function handleChange(value) {
    console.log('Selected languages:', value);
  }
</script>

<GroupCheckBox 
  {options} 
  bind:value={selectedLanguages}
  onchange={handleChange}
/>
```

## Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `string \| number` | required | Selected values (string with delimiter or bit value) |
| `options` | `Array<any>` | required | Array of option objects |
| `keyField` | `string` | `"code"` | Field name for option keys/values |
| `textField` | `string` | `"text"` | Field name for option display text |
| `delimiter` | `string` | `";"` | Delimiter for string-based values |
| `bitBase` | `boolean` | `false` | Whether to use bit-based value storage |
| `disabled` | `boolean` | `false` | Whether the component is disabled |
| `readonly` | `boolean` | `false` | Whether the component is read-only |
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode (Edit or View) |
| `variant` | `"" \| "plain" \| "outlined" \| "filled"` | `""` | Visual variant |
| `compact` | `boolean` | `false` | Whether to use compact spacing |
| `disabledOptions` | `Array<string>` | `[]` | Array of option keys to disable |
| `hideOptions` | `Array<string>` | `[]` | Array of option keys to hide |
| `style` | `string` | `""` | Additional CSS styles |
| `item$style` | `string` | `""` | CSS styles for individual checkbox items |
| `onchange` | `OnChangeHandler<string \| number>` | `null` | Change event handler |
| `onfocus` | `(() => void) \| null` | `null` | Focus event handler |
| `onblur` | `(() => void) \| null` | `null` | Blur event handler |

## Methods

| Method | Description |
|--------|-------------|
| `setFocus()` | Programmatically focus the first enabled checkbox |

## Examples

### Basic String-Based Selection

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const technologies = [
    { code: "react", text: "React" },
    { code: "vue", text: "Vue.js" },
    { code: "svelte", text: "Svelte" },
    { code: "angular", text: "Angular" }
  ];
  
  let selectedTech = "";
  
  function handleTechChange(value) {
    console.log('Selected technologies:', value);
    console.log('As array:', value ? value.split(';') : []);
  }
</script>

<div class="demo-section">
  <FormField label="Select Your Preferred Technologies">
    <GroupCheckBox 
      options={technologies}
      bind:value={selectedTech}
      onchange={handleTechChange}
      onfocus={() => console.log('Focus gained')}
      onblur={() => console.log('Focus lost')}
    />
  </FormField>
  
  <p>Selected: {selectedTech || 'None'}</p>
</div>

<style>
  .demo-section {
    margin: 20px;
    padding: 20px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
</style>
```

### Bit-Based Selection for Performance

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const permissions = [
    { code: "read", text: "Read" },      // Bit 0 (value 1)
    { code: "write", text: "Write" },    // Bit 1 (value 2)
    { code: "delete", text: "Delete" },  // Bit 2 (value 4)
    { code: "admin", text: "Admin" }     // Bit 3 (value 8)
  ];
  
  let userPermissions = 0;
  
  function handlePermissionChange(value) {
    console.log('Permission bits:', value);
    console.log('Binary representation:', value.toString(2));
    
    // Decode permissions
    const activePermissions = [];
    permissions.forEach((perm, index) => {
      if (value & (1 << index)) {
        activePermissions.push(perm.text);
      }
    });
    console.log('Active permissions:', activePermissions);
  }
  
  // Helper function to check if specific permission is enabled
  function hasPermission(permissionBit) {
    return (userPermissions & (1 << permissionBit)) !== 0;
  }
</script>

<div class="permissions-demo">
  <FormField label="User Permissions">
    <GroupCheckBox 
      options={permissions}
      bitBase={true}
      bind:value={userPermissions}
      onchange={handlePermissionChange}
    />
  </FormField>
  
  <div class="permission-info">
    <p>Permission Value: {userPermissions}</p>
    <p>Binary: {userPermissions.toString(2).padStart(4, '0')}</p>
    <div class="permission-checks">
      <p>Can Read: {hasPermission(0) ? '✓' : '✗'}</p>
      <p>Can Write: {hasPermission(1) ? '✓' : '✗'}</p>
      <p>Can Delete: {hasPermission(2) ? '✓' : '✗'}</p>
      <p>Is Admin: {hasPermission(3) ? '✓' : '✗'}</p>
    </div>
  </div>
</div>

<style>
  .permissions-demo {
    margin: 20px;
    padding: 20px;
    background: #f8fafc;
    border-radius: 8px;
  }
  
  .permission-info {
    margin-top: 16px;
    padding: 12px;
    background: white;
    border-radius: 6px;
  }
  
  .permission-checks {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-top: 8px;
  }
</style>
```

### Different Visual Variants

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const colors = [
    { code: "red", text: "Red" },
    { code: "blue", text: "Blue" },
    { code: "green", text: "Green" },
    { code: "yellow", text: "Yellow" }
  ];
  
  let selectedColors = "";
</script>

<div class="variants-demo">
  <div class="variant-section">
    <h3>Default Variant</h3>
    <FormField label="Select Colors">
      <GroupCheckBox options={colors} bind:value={selectedColors} />
    </FormField>
  </div>
  
  <div class="variant-section">
    <h3>Outlined Variant</h3>
    <FormField label="Select Colors">
      <GroupCheckBox 
        options={colors} 
        variant="outlined"
        bind:value={selectedColors} 
      />
    </FormField>
  </div>
  
  <div class="variant-section">
    <h3>Filled Variant</h3>
    <FormField label="Select Colors">
      <GroupCheckBox 
        options={colors} 
        variant="filled"
        bind:value={selectedColors} 
      />
    </FormField>
  </div>
  
  <div class="variant-section">
    <h3>Compact Variant</h3>
    <FormField label="Select Colors">
      <GroupCheckBox 
        options={colors} 
        compact={true}
        bind:value={selectedColors} 
      />
    </FormField>
  </div>
</div>

<style>
  .variants-demo {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin: 20px;
  }
  
  .variant-section {
    padding: 16px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
</style>
```

### Conditional Options and Dynamic Behavior

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const airlines = [
    { code: "none", text: "None" },
    { code: "aa", text: "American Airlines" },
    { code: "ua", text: "United Airlines" },
    { code: "dl", text: "Delta Airlines" },
    { code: "sw", text: "Southwest Airlines" }
  ];
  
  let selectedAirlines = "";
  let disabledOptions = [];
  let hideOptions = [];
  
  function handleAirlineChange(value) {
    const selected = value ? value.split(';') : [];
    
    // If "None" is selected, disable all other options
    if (selected.includes('none')) {
      if (selected.length > 1) {
        // If other options were selected with "None", keep only "None"
        selectedAirlines = "none";
      }
      disabledOptions = airlines
        .filter(airline => airline.code !== 'none')
        .map(airline => airline.code);
    } else {
      disabledOptions = [];
    }
    
    // Hide Southwest on weekends (demo logic)
    const today = new Date();
    if (today.getDay() === 0 || today.getDay() === 6) {
      hideOptions = ['sw'];
    } else {
      hideOptions = [];
    }
  }
  
  // Handle special "None" selection logic
  function handleSpecialLogic(value) {
    const selected = value ? value.split(';') : [];
    
    if (selected.includes('none') && selected.length > 1) {
      // Remove "none" if other options are selected
      const filteredSelected = selected.filter(option => option !== 'none');
      selectedAirlines = filteredSelected.join(';');
    } else {
      handleAirlineChange(value);
    }
  }
</script>

<div class="conditional-demo">
  <FormField label="Select Preferred Airlines">
    <GroupCheckBox 
      options={airlines}
      bind:value={selectedAirlines}
      {disabledOptions}
      {hideOptions}
      onchange={handleSpecialLogic}
    />
  </FormField>
  
  <div class="info-panel">
    <p><strong>Selected:</strong> {selectedAirlines || 'None'}</p>
    <p><strong>Disabled:</strong> {disabledOptions.join(', ') || 'None'}</p>
    <p><strong>Hidden:</strong> {hideOptions.join(', ') || 'None'}</p>
    <p class="hint">💡 Select "None" to disable other options</p>
    {#if hideOptions.includes('sw')}
      <p class="weekend-notice">🚫 Southwest Airlines is not available on weekends</p>
    {/if}
  </div>
</div>

<style>
  .conditional-demo {
    margin: 20px;
    padding: 20px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
  
  .info-panel {
    margin-top: 16px;
    padding: 12px;
    background: #f8fafc;
    border-radius: 6px;
  }
  
  .hint {
    color: #6b7280;
    font-style: italic;
  }
  
  .weekend-notice {
    color: #dc2626;
    font-weight: 500;
  }
</style>
```

### Read-Only and Display Modes

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  import { DisplayMode } from "@ticatec/uniface-element";
  
  const skills = [
    { code: "js", text: "JavaScript" },
    { code: "ts", text: "TypeScript" },
    { code: "react", text: "React" },
    { code: "node", text: "Node.js" }
  ];
  
  let userSkills = "js;react;node";  // Pre-selected skills
</script>

<div class="readonly-demo">
  <div class="mode-section">
    <h3>Editable Mode</h3>
    <FormField label="Edit Your Skills">
      <GroupCheckBox 
        options={skills}
        bind:value={userSkills}
      />
    </FormField>
  </div>
  
  <div class="mode-section">
    <h3>Read-Only Mode</h3>
    <FormField label="Your Skills (Read-Only)">
      <GroupCheckBox 
        options={skills}
        value={userSkills}
        readonly={true}
      />
    </FormField>
  </div>
  
  <div class="mode-section">
    <h3>Disabled Mode</h3>
    <FormField label="Your Skills (Disabled)">
      <GroupCheckBox 
        options={skills}
        value={userSkills}
        disabled={true}
      />
    </FormField>
  </div>
  
  <div class="mode-section">
    <h3>Display-Only Mode</h3>
    <FormField label="Your Skills (Display)">
      <GroupCheckBox 
        options={skills}
        value={userSkills}
        displayMode={DisplayMode.View}
      />
    </FormField>
  </div>
</div>

<style>
  .readonly-demo {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin: 20px;
  }
  
  .mode-section {
    padding: 16px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
</style>
```

### Custom Styling and Field Configuration

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const departments = [
    { id: "eng", name: "Engineering", active: true },
    { id: "sales", name: "Sales", active: true },
    { id: "marketing", name: "Marketing", active: false },
    { id: "hr", name: "Human Resources", active: true }
  ];
  
  let selectedDepartments = "";
</script>

<div class="custom-demo">
  <FormField label="Select Departments">
    <GroupCheckBox 
      options={departments}
      keyField="id"
      textField="name"
      delimiter=","
      bind:value={selectedDepartments}
      variant="outlined"
      style="border: 2px solid #3b82f6; border-radius: 12px; padding: 16px;"
      item$style="margin: 8px 0; padding: 4px 8px; background: #f0f9ff; border-radius: 6px;"
    />
  </FormField>
  
  <div class="result">
    <p><strong>Selected Departments:</strong></p>
    <p>Raw value: {selectedDepartments}</p>
    <p>As array: {JSON.stringify(selectedDepartments ? selectedDepartments.split(',') : [])}</p>
  </div>
</div>

<style>
  .custom-demo {
    margin: 20px;
    padding: 20px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
  
  .result {
    margin-top: 16px;
    padding: 12px;
    background: #f8fafc;
    border-radius: 6px;
  }
</style>
```

### Form Integration with Validation

```svelte
<script>
  import GroupCheckBox from "@ticatec/uniface-element/GroupCheckBox";
  import FormField from "@ticatec/uniface-element/FormField";
  
  const interests = [
    { code: "sports", text: "Sports" },
    { code: "music", text: "Music" },
    { code: "travel", text: "Travel" },
    { code: "cooking", text: "Cooking" },
    { code: "reading", text: "Reading" },
    { code: "gaming", text: "Gaming" }
  ];
  
  let formData = {
    name: '',
    interests: '',
    newsletter: false
  };
  
  let errors = {};
  let groupCheckBoxRef;
  
  function validateForm() {
    errors = {};
    
    if (!formData.name.trim()) {
      errors.name = 'Name is required';
    }
    
    if (!formData.interests) {
      errors.interests = 'Please select at least one interest';
    } else {
      const selectedCount = formData.interests.split(';').length;
      if (selectedCount > 3) {
        errors.interests = 'Please select no more than 3 interests';
      }
    }
    
    return Object.keys(errors).length === 0;
  }
  
  function handleSubmit() {
    if (validateForm()) {
      console.log('Form submitted:', formData);
      alert('Form submitted successfully!');
    } else {
      console.log('Validation errors:', errors);
      // Focus first error field
      if (errors.interests) {
        groupCheckBoxRef.setFocus();
      }
    }
  }
  
  function handleInterestChange(value) {
    formData.interests = value;
    // Clear error when user makes a selection
    if (errors.interests && value) {
      delete errors.interests;
      errors = { ...errors };
    }
  }
</script>

<div class="form-demo">
  <form on:submit|preventDefault={handleSubmit}>
    <FormField label="Your Name" error={errors.name}>
      <input 
        type="text" 
        bind:value={formData.name}
        class="form-input"
        class:error={errors.name}
      />
    </FormField>
    
    <FormField label="Your Interests (Select 1-3)" error={errors.interests}>
      <GroupCheckBox 
        bind:this={groupCheckBoxRef}
        options={interests}
        bind:value={formData.interests}
        onchange={handleInterestChange}
        variant="outlined"
      />
      <p class="field-hint">Choose up to 3 interests that best describe you</p>
    </FormField>
    
    <FormField label="Newsletter">
      <label class="checkbox-label">
        <input type="checkbox" bind:checked={formData.newsletter} />
        Subscribe to our newsletter
      </label>
    </FormField>
    
    <div class="form-actions">
      <button type="submit" class="submit-btn">Submit</button>
      <button type="button" on:click={() => console.log(formData)} class="preview-btn">
        Preview Data
      </button>
    </div>
  </form>
</div>

<style>
  .form-demo {
    max-width: 500px;
    margin: 20px;
    padding: 24px;
    border: 1px solid #e2e8f0;
    border-radius: 8px;
  }
  
  .form-input {
    width: 100%;
    padding: 8px 12px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
  }
  
  .form-input.error {
    border-color: #dc2626;
  }
  
  .field-hint {
    margin-top: 4px;
    font-size: 0.875rem;
    color: #6b7280;
  }
  
  .checkbox-label {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
  }
  
  .form-actions {
    display: flex;
    gap: 12px;
    margin-top: 20px;
  }
  
  .submit-btn, .preview-btn {
    padding: 10px 20px;
    border-radius: 6px;
    border: none;
    cursor: pointer;
  }
  
  .submit-btn {
    background: #3b82f6;
    color: white;
  }
  
  .preview-btn {
    background: #f3f4f6;
    color: #374151;
    border: 1px solid #d1d5db;
  }
</style>
```

## Value Format

### String-Based Values
When `bitBase` is `false` (default), selected values are stored as a delimited string:
- Single selection: `"option1"`
- Multiple selections: `"option1;option2;option3"`
- Empty selection: `""`

### Bit-Based Values
When `bitBase` is `true`, selected values are stored as a number where each bit represents an option:
- First option (index 0): bit 0 (value 1)
- Second option (index 1): bit 1 (value 2)
- Third option (index 2): bit 2 (value 4)
- Combined: first + third options = 1 + 4 = 5

## Styling

The GroupCheckBox component can be styled using CSS custom properties:

```css
.uniface-group-box {
  --checkbox-spacing: 8px;
  --checkbox-padding: 4px 8px;
  --border-color: #e2e8f0;
  --background-color: #ffffff;
  --hover-background: #f9fafb;
}

/* Variant-specific styling */
.uniface-group-box.outlined {
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: 12px;
}

.uniface-group-box.filled {
  background-color: #f8fafc;
  border-radius: 6px;
  padding: 12px;
}

.uniface-group-box.compact {
  --checkbox-spacing: 4px;
  --checkbox-padding: 2px 4px;
}
```

## Accessibility

The GroupCheckBox component includes several accessibility features:

- Keyboard navigation between checkboxes
- Focus management with `setFocus()` method
- ARIA labels and descriptions
- Screen reader announcements for state changes
- Proper tab order management

## Best Practices

1. **Option Management**: Keep option arrays stable to prevent unnecessary re-renders
2. **Performance**: Use bit-based values for large datasets or when performance is critical
3. **Validation**: Implement proper validation for required selections
4. **User Experience**: Provide clear feedback for disabled/hidden options
5. **Accessibility**: Always provide meaningful labels and descriptions
6. **State Management**: Handle focus/blur events appropriately for form validation
