# ബട്ടൺ

> മൂന്ന് സൈസുകളിൽ പ്രൈമറി, സെക്കൻഡറി, ഔട്ട്‌ലൈൻ, ഗോസ്റ്റ്, ഡേഞ്ചർ, ലിങ്ക് ബട്ടണുകൾ, സ്വയം കൈകാര്യം ചെയ്യുന്ന ഒരു ലോഡിംഗ് സ്റ്റേറ്റോടുകൂടി.

GramproKit 2.0.0-beta · General · ബീറ്റ (പരീക്ഷണാത്മകം; API-കൾ മാറാം) · ഉറവിടം: https://gramprokit.vercel.app/2.0.0-beta/ml/button

## ഇൻസ്റ്റലേഷൻ

```bash
npx gbs-add-block@latest -a Button -beta
```

എല്ലാ കമ്പോണന്റുകളും ഇംപോർട്ട് ചെയ്യുന്ന ചെറിയ `shared` ഫോൾഡറിനൊപ്പം, `button` ഫോൾഡർ ഈ ബ്ലോക്ക് നിങ്ങളുടെ പ്രോജക്ടിലേക്ക് കോപ്പി ചെയ്യുന്നു. കോഡ് നിങ്ങളുടേതാണ്, സ്വതന്ത്രമായി മാറ്റം വരുത്താം.
React അല്ലാതെ **peer dependencies** ഒന്നും ഇല്ല.

**ആവശ്യകതകൾ**

- React 19-ഉം `@types/react` 19-ഉം
- TypeScript ടാർഗെറ്റ് ES2022 അല്ലെങ്കിൽ അതിനു ശേഷമുള്ളത്, `"jsx": "react-jsx"` എന്നതോടെ
- 2024-നു ശേഷമുള്ള ബ്രൗസറുകൾ (സ്റ്റൈലുകൾ `light-dark()`, `color-mix()` ഉപയോഗിക്കുന്നു)

സ്റ്റൈൽഷീറ്റ് ഒരു തവണ ഇംപോർട്ട് ചെയ്യുക, ഉദാഹരണത്തിന് നിങ്ങളുടെ ഗ്ലോബൽ CSS-ൽ:

```css
@import "../components/button/styles.css";
```

അല്ലെങ്കിൽ നിങ്ങളുടെ റൂട്ട് ലേഔട്ട് / എൻട്രി ഫയലിൽ:

```ts
import "@/components/button/styles.css";
```

ദൈനംദിന ഓരോ പ്രവർത്തനവും ബട്ടൺ ഉൾക്കൊള്ളുന്നു: പ്രൈമറിയും സെക്കൻഡറിയും പ്രവർത്തനങ്ങൾ, ഔട്ട്‌ലൈനുകൾ, ശാന്തമായ ഗോസ്റ്റ് ബട്ടണുകൾ, വിനാശകരമായ (destructive) പ്രവർത്തനങ്ങൾ, ലിങ്ക്-സ്റ്റൈൽ ബട്ടണുകൾ, മൂന്ന് സൈസുകളിൽ, ഐക്കണുകളോടുകൂടി. അതിന്റെ ലോഡിംഗ് സ്റ്റേറ്റ് സ്വയം കൈകാര്യം ചെയ്യുന്നു: `onClick`-ൽ നിന്ന് ഒരു പ്രോമിസ് (promise) റിട്ടേൺ ചെയ്യുക, അല്ലെങ്കിൽ ഒരു Server Action ഉപയോഗിച്ച് ഫോം സമർപ്പിക്കുക, ജോലി പൂർത്തിയാകുന്നതുവരെ ബട്ടൺ ഒരു സ്പിന്നർ കാണിക്കും. ഇതിനിടയിൽ അതിന്റെ വീതിയും കീബോർഡ് ഫോക്കസും നിലനിർത്തുന്നു. ഒരു റൗട്ടർ ലിങ്ക് പോലുള്ള മറ്റൊരു എലമെന്റ് ആയും, അതേ രൂപത്തോടെ, ഇത് റെൻഡർ ചെയ്യാൻ കഴിയും.

> **ശ്രദ്ധിക്കുക:** എല്ലാ കമ്പോണന്റുകളും ഒരുമിച്ച് തീം ചെയ്യാൻ :root-ൽ --gbs-* വേരിയബിളുകൾ സെറ്റ് ചെയ്യുക, ഗ്രിഡ് ഉൾപ്പെടെ. ഓരോ കമ്പോണന്റിന്റെയും സ്വന്തം വേരിയബിളുകൾ ഇവയിലേക്കും, പിന്നീട് ബിൽറ്റ്-ഇൻ പാലറ്റിലേക്കും ഫാൾബാക്ക് ചെയ്യുന്നു, അതിനാൽ ഡിഫോൾട്ടായി കമ്പോണന്റുകൾ ഒരേ പോലെ കാണപ്പെടുന്നു.

#### ഡിഫോൾട്ട്

_ഇന്ററാക്ടീവ് ഡെമോ:_ [തത്സമയ ഉദാഹരണം കാണുക](https://gramprokit.vercel.app/2.0.0-beta/ml/button)

## ക്വിക്ക് സ്റ്റാർട്ട്

```tsx
"use client";

import { Button } from "@/components/button";

export function SaveBar({ onSave }: { onSave(): Promise<void> }) {
  return (
    <div>
      <Button variant="outline">Cancel</Button>
      <Button onClick={onSave}>Save changes</Button>
    </div>
  );
}
```

`onSave` ഒരു പ്രോമിസ് റിട്ടേൺ ചെയ്യുന്നു, അതിനാൽ Save ബട്ടൺ ഒരു സ്പിന്നർ കാണിക്കുകയും, അത് ഫലം കാണിക്കുന്നതുവരെ കൂടുതൽ ക്ലിക്കുകൾ അവഗണിക്കുകയും ചെയ്യുന്നു.

> **ശ്രദ്ധിക്കുക:** ഡിഫോൾട്ട് ടൈപ്പ് 'button' ആണ്, ബ്രൗസറിന്റെ 'submit' അല്ല, അതിനാൽ ഒരു ഫോമിനുള്ളിലെ ബട്ടൺ അബദ്ധത്തിൽ അത് സമർപ്പിക്കുന്നില്ല. അങ്ങനെ ചെയ്യേണ്ട ബട്ടണിന് type='submit' നൽകുക.

## പ്രോപ്സ് ടേബിൾ

എല്ലാ `<button>` ആട്രിബ്യൂട്ടുകളും, കൂടാതെ:

| Prop          | Type                                                                               | Default     | Description                                                                                    |
| ------------- | ---------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------- |
| `variant`     | `"primary"` \| `"secondary"` \| `"outline"` \| `"ghost"` \| `"danger"` \| `"link"` | `"primary"` | ദൃശ്യപരമായ ഭാരം (visual weight).                                                               |
| `size`        | `"sm"` \| `"md"` \| `"lg"`                                                         | `"md"`      | ഉയരം 30 / 36 / 44 px.                                                                          |
| `type`        | `"button"` \| `"submit"` \| `"reset"`                                              | `"button"`  | നേറ്റീവ് ബട്ടൺ ടൈപ്പ്.                                                                         |
| `loading`     | `boolean`                                                                          | `false`     | ബിസി സ്റ്റേറ്റ്: സ്പിന്നർ, `aria-busy`, ക്ലിക്കുകൾ അവഗണിക്കപ്പെടുന്നു.                         |
| `loadingText` | `ReactNode`                                                                        | —           | ബിസി ആയിരിക്കുമ്പോൾ ലേബലിനു പകരം സ്പിന്നറിനടുത്തുള്ള ടെക്സ്റ്റ്.                               |
| `leading`     | `ReactNode`                                                                        | —           | ലേബലിനു മുമ്പുള്ള ഐക്കൺ.                                                                       |
| `trailing`    | `ReactNode`                                                                        | —           | ലേബലിനു ശേഷമുള്ള ഐക്കൺ.                                                                        |
| `icon`        | `ReactNode`                                                                        | —           | ഒരു സ്ക്വയർ ഐക്കൺ-മാത്രം ബട്ടൺ ഉണ്ടാക്കുന്നു. എപ്പോഴും `aria-label` ചേർക്കുക.                  |
| `fullWidth`   | `boolean`                                                                          | `false`     | കണ്ടെയ്നറിന്റെ വീതി നിറയ്ക്കുക.                                                                |
| `disabled`    | `boolean`                                                                          | `false`     | നേറ്റീവായി ഡിസേബിൾ ചെയ്തത്.                                                                    |
| `onClick`     | `(event) => unknown`                                                               | —           | ഫലം കാണുന്നതുവരെ ലോഡിംഗ് കാണിക്കാൻ ഒരു പ്രോമിസ് റിട്ടേൺ ചെയ്യുക.                               |
| `render`      | `(props: ButtonRenderProps) => ReactElement`                                       | —           | ബട്ടണിന്റെ രൂപത്തോടെ മറ്റൊരു എലമെന്റ് റെൻഡർ ചെയ്യുക. [Links](#links-and-other-elements) കാണുക. |
| `className`   | `string`                                                                           | —           | ബട്ടണിനുള്ള ക്ലാസ്.                                                                            |
| `classNames`  | `Partial<Record<ButtonSlot, string>>`                                              | —           | സ്ലോട്ടുകൾ: `root`, `content`, `spinner`, `icon`.                                              |
| `localeText`  | `Partial<ButtonLocaleText>`                                                        | ഇംഗ്ലീഷ്    | [Locale Text](#locale-text) കാണുക.                                                             |
| `ref`         | `Ref<HTMLButtonElement>`                                                           | —           | `<button>` എലമെന്റ്.                                                                           |

## വേരിയന്റുകൾ

```tsx
<Button>Primary</Button>                     {/* the main action on a screen */}
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>       {/* toolbars, tables, low-emphasis actions */}
<Button variant="danger">Delete</Button>     {/* destructive actions */}
<Button variant="link">Learn more</Button>   {/* looks like a link, behaves like a button */}
```

## ഐക്കണുകൾ

```tsx
<Button leading={<PlusIcon />}>New invoice</Button>
<Button variant="outline" trailing={<ArrowRightIcon />}>Next</Button>
<Button variant="ghost" icon={<TrashIcon />} aria-label="Delete row" />
```

ഐക്കണുകൾ ടെക്സ്റ്റിന് അനുസൃതമായ വലുപ്പത്തിലാണ് (1.15 em). `leading`, `trailing` ഐക്കണുകൾ സ്ക്രീൻ റീഡറുകളിൽ നിന്ന് മറച്ചിരിക്കുന്നു, കാരണം ലേബൽ ബട്ടൺ എന്താണ് ചെയ്യുന്നതെന്ന് പറയുന്നു. ഒരു ഐക്കൺ-മാത്രം ബട്ടണിന് ദൃശ്യമായ ടെക്സ്റ്റ് ഇല്ല, അതിനാൽ അതിന്റെ `aria-label` മാത്രമാണ് അതിന്റെ പേര്.

## ലോഡിംഗ്

ലോഡിംഗ് സ്റ്റേറ്റിന് മൂന്ന് സ്രോതസ്സുകളുണ്ട്:

| Source               | How                                                                                                                              |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **ഏസിൻക് `onClick`** | ഒരു പ്രോമിസ് റിട്ടേൺ ചെയ്യുക: `onClick={async () => { await save(); }}`                                                          |
| **ഫോം സമർപ്പണം**     | `<form action={serverAction}>`-നുള്ളിലെ ഒരു `type="submit"` ബട്ടൺ, ആക്ഷൻ പ്രവർത്തിക്കുമ്പോൾ ബിസി ആണ് (React 19 `useFormStatus`). |
| **മാനുവൽ**           | `loading={isPending}`                                                                                                            |

```tsx
<form action={createInvoice}>
  <Input name="customer" label="Customer" required />
  <Button type="submit">Create invoice</Button>
</form>
```

- **ഫോക്കസ് ചെയ്യാവുന്നതായി തുടരുന്നു:** ബിസി ആയിരിക്കുമ്പോൾ, ബട്ടൺ `disabled`-ന് പകരം `aria-disabled` ഉപയോഗിക്കുന്നു, അതിനാൽ കീബോർഡ് ഫോക്കസ് മറ്റെവിടെയും പോകുന്നില്ല.
- **സ്ഥാനം മാറ്റുന്നില്ല:** ലേബൽ മറഞ്ഞിരിക്കുന്നു, പക്ഷേ അതിന്റെ സ്ഥലം നിലനിർത്തുന്നു, അതിനാൽ ബട്ടണിന്റെ വീതി മാറുന്നില്ല. `loadingText` ലേബലിന് പകരം ടെക്സ്റ്റ് വെക്കുന്നു, അപ്പോൾ വീതി മാറാം.
- **ആവർത്തനങ്ങൾ അവഗണിക്കുന്നു:** ജോലി പൂർത്തിയാകുന്നതുവരെ കൂടുതൽ ക്ലിക്കുകളും ഫോം സമർപ്പണങ്ങളും തടയപ്പെടുന്നു.
- **പിശകുകൾ ദൃശ്യമായി നിലനിർത്തുന്നു:** പ്രോമിസ് നിരസിക്കപ്പെട്ടാൽ (reject), ലോഡിംഗ് സ്റ്റേറ്റ് അവസാനിക്കുകയും, പിശക് ഒരു കൈകാര്യം ചെയ്യപ്പെടാത്ത റിജക്ഷനായി ഇപ്പോഴും ഉയർന്നുവരികയും ചെയ്യുന്നു. ഒരു സന്ദേശം കാണിക്കാൻ നിങ്ങളുടെ ഹാൻഡ്‌ലറിൽ അത് പിടിക്കുക (catch).

## ലിങ്കുകളും മറ്റ് എലമെന്റുകളും

ഒരു ലിങ്കിനെ ബട്ടൺ പോലെ കാണിക്കാൻ, `render` ഉപയോഗിക്കുക. ഇതിന് ബട്ടണിന്റെ ക്ലാസ് നെയിമുകൾ, ഡാറ്റ ആട്രിബ്യൂട്ടുകൾ, ക്ലിക്ക് ഹാൻഡ്‌ലിംഗ്, കണ്ടന്റ് എന്നിവ ലഭിക്കുന്നു:

```tsx
import Link from "next/link";

<Button
  variant="outline"
  render={(props) => <Link href="/billing" {...props} />}
>
  Go to billing
</Button>;
```

```tsx
<Button
  variant="link"
  render={(props) => (
    <a href="/docs" target="_blank" rel="noreferrer" {...props} />
  )}
>
  Documentation
</Button>
```

ബട്ടൺ-മാത്രമായ ആട്രിബ്യൂട്ടുകൾ (`type`, `form`, `name`, `value`) റെൻഡർ ചെയ്ത എലമെന്റിൽ നിന്ന് ഒഴിവാക്കപ്പെടുന്നു. ഡിസേബിൾ ചെയ്തതോ ബിസി ആയതോ ആയ ഒരു ലിങ്കിന് `aria-disabled` ലഭിക്കുകയും ക്ലിക്കുകൾ അവഗണിക്കുകയും ചെയ്യുന്നു.

## കീബോർഡ്

| Keys                  | Action                                                              |
| --------------------- | ------------------------------------------------------------------- |
| **Enter** / **Space** | ബട്ടൺ ആക്ടിവേറ്റ് ചെയ്യുക.                                          |
| **Tab**               | അടുത്ത കൺട്രോളിലേക്ക് നീങ്ങുക; ബിസി ബട്ടണുകൾ ടാബ് ഓർഡറിൽ തുടരുന്നു. |

ആക്സസിബിലിറ്റി: ഡിഫോൾട്ടായി ഒരു യഥാർത്ഥ `<button>`. ബിസി ആയിരിക്കുമ്പോൾ, ഇതിന് `aria-busy="true"` ഉണ്ട്, കൂടാതെ ദൃശ്യപരമായി മറച്ച ടെക്സ്റ്റിലൂടെ "Loading" അറിയിക്കുന്നു. `leading`, `trailing` ഐക്കണുകൾ `aria-hidden` ആണ്. കീബോർഡ് ഫോക്കസിൽ മാത്രം (`:focus-visible`) ഫോക്കസ് 2 px റിംഗായി കാണിക്കുന്നു.

## സ്റ്റൈലിംഗും തീമിംഗും

എല്ലാ റൂളുകളും CSS `components` ലെയറിലാണ്, അതിനാൽ `className` / `classNames` വഴി കടന്നുപോകുന്ന യൂട്ടിലിറ്റി ക്ലാസുകൾ അവയെ ഓവർറൈഡ് ചെയ്യുന്നു.

```tsx
<Button className="rounded-full px-6" />
```

#### CSS വേരിയബിളുകൾ

`.bt-root`-ലോ, `:root`-ലോ, അല്ലെങ്കിൽ `style`-ലൂടെയോ ഇവ ഓവർറൈഡ് ചെയ്യുക. ഓരോ വേരിയബിളും അതേ പേരിലുള്ള ഷെയേർഡ് `--gbs-*`-ലേക്ക് ഫാൾബാക്ക് ചെയ്യുന്നു, പിന്നീട് ആ സ്റ്റൈൽഷീറ്റ് ലോഡ് ചെയ്തിട്ടുണ്ടെങ്കിൽ DataGrid-ന്റെ `--dg-*`-ലേക്കും, അവസാനം ബിൽറ്റ്-ഇൻ പാലറ്റിലേക്കും.

| Variable                                                | Used for                                                                               |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `--bt-height`, `--bt-px`, `--bt-gap`, `--bt-font-size`  | സൈസ് (`size` സെറ്റ് ചെയ്യുന്നത്).                                                      |
| `--bt-fill`, `--bt-fill-hover`, `--bt-ink`, `--bt-line` | ബാക്ക്ഗ്രൗണ്ട്, ഹോവർ ബാക്ക്ഗ്രൗണ്ട്, ടെക്സ്റ്റ്, ബോർഡർ (`variant` സെറ്റ് ചെയ്യുന്നത്). |
| `--bt-accent`, `--bt-accent-fg`                         | `primary` വേരിയന്റും `link` ടെക്സ്റ്റും.                                               |
| `--bt-danger`, `--bt-danger-fg`                         | `danger` വേരിയന്റ്.                                                                    |
| `--bt-subtle`                                           | `secondary` ബാക്ക്ഗ്രൗണ്ട്.                                                            |
| `--bt-border`, `--bt-hover`                             | `outline` ബോർഡറും ഹോവർ ബാക്ക്ഗ്രൗണ്ടും.                                                |
| `--bt-focus`                                            | ഫോക്കസ് റിംഗ്.                                                                         |
| `--bt-radius`                                           | കോർണർ റേഡിയസ്.                                                                         |

```css
/* A brand variant, without touching the component */
.bt-root.brand {
  --bt-fill: #7c3aed;
  --bt-fill-hover: #6d28d9;
  --bt-line: #7c3aed;
  --bt-ink: white;
}
```

#### ഡാറ്റ ആട്രിബ്യൂട്ടുകൾ

| Element           | Attributes                                                                                                  |
| ----------------- | ----------------------------------------------------------------------------------------------------------- |
| Root (`.bt-root`) | `data-variant`, `data-size`, `data-busy`, `data-icon-only`, `data-full-width`, `aria-busy`, `aria-disabled` |

## ലോക്കൽ ടെക്സ്റ്റ്

```tsx
<Button localeText={{ loading: "Wird geladen" }} />
```

| Key       | Default                                                                                 |
| --------- | --------------------------------------------------------------------------------------- |
| `loading` | `"Loading"` — ബിസി ആയിരിക്കുമ്പോൾ അറിയിക്കപ്പെടുന്നു, `loadingText` നൽകിയിട്ടില്ലെങ്കിൽ |

## ഹെഡ്‌ലെസ് ഉപയോഗം

| Export                                        | Description                                                                                |
| --------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `buttonState({ disabled, loading, pending })` | ബട്ടൺ ബിസി ആണോ, ആക്ടിവേഷൻ അവഗണിക്കുന്നുണ്ടോ, നേറ്റീവ് `disabled` ഉപയോഗിക്കുന്നുണ്ടോ എന്ന്. |
| `isPromiseLike(value)`                        | ഒരു ഏസിൻക് ക്ലിക്ക് ഹാൻഡ്‌ലറിന്റെ ഫലം കണ്ടെത്തുന്നു.                                       |

## Next.js

ബട്ടൺ ഒരു ക്ലയന്റ് കമ്പോണന്റ് ആണ്, അതിന്റെ ഫയലിന്റെ മുകളിൽ `"use client"` ഉള്ളത്.

- **Server Components-ൽ:** ഫംഗ്ഷൻ പ്രോപ്‌സ് ഒന്നും കൈമാറാത്തിടത്തോളം ഇത് പ്രവർത്തിക്കും. `<form action={serverAction}>`-നുള്ളിലെ ഒരു `type="submit"` ബട്ടണിന് അതൊന്നും ആവശ്യമില്ല, കൂടാതെ അത് സ്വയം പുരോഗതി കാണിക്കുന്നു, അതിനാൽ ഇത് ഒരു Server Component പേജിൽ പ്രവർത്തിക്കും.
- **`onClick` അല്ലെങ്കിൽ `render` ഉപയോഗിച്ച്:** ഇവ ഫംഗ്ഷനുകളാണ്, ഒരു Server Component-ന് ഒരു ക്ലയന്റ് കമ്പോണന്റിലേക്ക് ഇവ കൈമാറാൻ കഴിയില്ല. ഒരു ക്ലയന്റ് കമ്പോണന്റിനുള്ളിൽ ഇവ ഉപയോഗിക്കുക, ഉദാഹരണത്തിന് `render` ഉപയോഗിച്ച് `next/link` റാപ്പ് ചെയ്യാൻ.

## മുമ്പത്തെ കസ്റ്റം ബട്ടണിൽ നിന്ന് മൈഗ്രേറ്റ് ചെയ്യുന്നത്

| മുമ്പത്തേത്                                                                                                          | പുതിയത്                                                                                              |
| -------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| `CustomBtn`                                                                                                          | `Button`                                                                                             |
| `value="Submit"` (ലേബൽ)                                                                                              | `children`: `<Button>Submit</Button>`                                                                |
| `id`, `name`, `className`, `disabled`, `onClick`                                                                     | അതേ പേരുകൾ                                                                                           |
| `type` (ബ്രൗസറിൽ ഡിഫോൾട്ട് `submit`)                                                                                 | `type`, ഇപ്പോൾ ഡിഫോൾട്ടായി `button`; ആവശ്യമുള്ളിടത്ത് `type="submit"` നൽകുക                          |
| `globalStyle.ts`-ൽ നിന്നുള്ള `buttonStyles` (`primary`, `secondary`, `outline`, `ghost`, `danger`; `sm`, `md`, `lg`) | അതേ പേരുകളിലുള്ള `variant`-ഉം `size`-ഉം, കൂടാതെ `link`                                               |
| —                                                                                                                    | പുതിയത്: `loading`, ഏസിൻക് `onClick`, ഫോം-ആക്ഷൻ പെൻഡിംഗ് സ്റ്റേറ്റ്, ഐക്കണുകൾ, `fullWidth`, `render` |

#### കുറിപ്പുകൾ

- ഐക്കൺ-മാത്രം ബട്ടണുകൾക്ക് ഒരു `aria-label` ആവശ്യമാണ്; ഒരു ഐക്കണിൽ നിന്ന് കമ്പോണന്റിന് ഒന്ന് ഊഹിക്കാൻ കഴിയില്ല.
- `render`, അതിന് ലഭിക്കുന്ന പ്രോപ്‌സ് എലമെന്റിൽ സ്പ്രെഡ് ചെയ്യണം, അല്ലെങ്കിൽ രൂപവും ക്ലിക്ക് ഹാൻഡ്‌ലിംഗും നഷ്ടപ്പെടും.
