@dgshahr/ui-kit 1.9.8 → 1.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/INTEGRATION.md +1034 -0
  2. package/README.md +4 -0
  3. package/dist/Alert/index.d.ts +1 -1
  4. package/dist/Alert/index.d.ts.map +1 -1
  5. package/dist/Badge/index.d.ts +1 -1
  6. package/dist/Badge/index.d.ts.map +1 -1
  7. package/dist/Breadcrumb/index.d.ts +1 -1
  8. package/dist/Breadcrumb/index.d.ts.map +1 -1
  9. package/dist/Button/index.d.ts.map +1 -1
  10. package/dist/{DateAndTimePickerFooter-O7VW4RUW.cjs → DateAndTimePickerFooter-D-DVvBp_.cjs} +1 -1
  11. package/dist/{DateAndTimePickerFooter-DvYgk9Qh.js → DateAndTimePickerFooter-D5-DDqkr.js} +1 -1
  12. package/dist/Divider/index.d.ts +1 -1
  13. package/dist/Divider/index.d.ts.map +1 -1
  14. package/dist/Form/Checkbox/index.d.ts +1 -1
  15. package/dist/Form/Checkbox/index.d.ts.map +1 -1
  16. package/dist/Form/Common/FieldBottomInfo/FieldBottomInfo.d.ts +1 -1
  17. package/dist/Form/Common/FieldBottomInfo/FieldBottomInfo.d.ts.map +1 -1
  18. package/dist/Form/Datepicker/index.cjs +1 -1
  19. package/dist/Form/Datepicker/index.mjs +1 -1
  20. package/dist/Form/FileUploader/Preview/utils.d.ts +1 -1
  21. package/dist/Form/FileUploader/Preview/utils.d.ts.map +1 -1
  22. package/dist/Form/FileUploader/types.d.ts.map +1 -1
  23. package/dist/Form/Input/index.cjs +1 -1
  24. package/dist/Form/Input/index.d.ts.map +1 -1
  25. package/dist/Form/Input/index.mjs +2 -2
  26. package/dist/Form/OtpInput/index.cjs +1 -1
  27. package/dist/Form/OtpInput/index.mjs +2 -2
  28. package/dist/Form/RadioButton/index.d.ts +1 -1
  29. package/dist/Form/RadioButton/index.d.ts.map +1 -1
  30. package/dist/Form/RangeInput/Thumb.d.ts.map +1 -1
  31. package/dist/Form/RangeInput/index.d.ts +1 -1
  32. package/dist/Form/RangeInput/index.d.ts.map +1 -1
  33. package/dist/Form/Select/OptionItem.d.ts +1 -1
  34. package/dist/Form/Select/OptionItem.d.ts.map +1 -1
  35. package/dist/Form/Select/Options.d.ts +1 -1
  36. package/dist/Form/Select/Options.d.ts.map +1 -1
  37. package/dist/Form/Select/index.cjs +1 -1
  38. package/dist/Form/Select/index.d.ts +1 -1
  39. package/dist/Form/Select/index.d.ts.map +1 -1
  40. package/dist/Form/Select/index.mjs +2 -2
  41. package/dist/Form/Textarea/index.cjs +1 -1
  42. package/dist/Form/Textarea/index.d.ts.map +1 -1
  43. package/dist/Form/Textarea/index.mjs +1 -1
  44. package/dist/Form/Timepicker/index.cjs +1 -1
  45. package/dist/Form/Timepicker/index.mjs +2 -2
  46. package/dist/Form/Wrappers/TextFieldWrapper/TextFieldWrapper.d.ts +1 -0
  47. package/dist/Form/Wrappers/TextFieldWrapper/TextFieldWrapper.d.ts.map +1 -1
  48. package/dist/Pagination/index.d.ts +1 -1
  49. package/dist/Pagination/index.d.ts.map +1 -1
  50. package/dist/Pagination/utils.d.ts.map +1 -1
  51. package/dist/{PickerWrapper-DkRUahWD.cjs → PickerWrapper-DGyaWUvQ.cjs} +1 -1
  52. package/dist/{PickerWrapper-Bwdfzr3U.js → PickerWrapper-Dh1cWCNJ.js} +1 -1
  53. package/dist/Progress/Step/index.cjs +1 -0
  54. package/dist/Progress/Step/index.d.ts +18 -0
  55. package/dist/Progress/Step/index.d.ts.map +1 -0
  56. package/dist/Progress/Step/index.mjs +161 -0
  57. package/dist/Sidebar/Profile.d.ts +1 -1
  58. package/dist/Sidebar/Profile.d.ts.map +1 -1
  59. package/dist/Sidebar/index.cjs +1 -1
  60. package/dist/Sidebar/index.mjs +1 -1
  61. package/dist/Sidebar/utils.d.ts +1 -1
  62. package/dist/Sidebar/utils.d.ts.map +1 -1
  63. package/dist/{Slide-CV7KzC_T.js → Slide-D-2O9kS6.js} +5 -5
  64. package/dist/Slider/NavigationDot.d.ts +1 -1
  65. package/dist/Slider/NavigationDot.d.ts.map +1 -1
  66. package/dist/Slider/index.mjs +1 -1
  67. package/dist/{Step-DB73tIkY.js → Step-BQAozGAS.js} +5 -5
  68. package/dist/Stepper/Horizontal/index.mjs +1 -1
  69. package/dist/Table/context.d.ts +1 -1
  70. package/dist/Table/context.d.ts.map +1 -1
  71. package/dist/Table/index.d.ts +2 -1
  72. package/dist/Table/index.d.ts.map +1 -1
  73. package/dist/Table/utils.d.ts +1 -1
  74. package/dist/Table/utils.d.ts.map +1 -1
  75. package/dist/{TextFieldWrapper-3DRVoeki.js → TextFieldWrapper-CXoA32wk.js} +24 -22
  76. package/dist/TextFieldWrapper-OdBa53gf.cjs +1 -0
  77. package/dist/Tooltip/Content.d.ts.map +1 -1
  78. package/dist/assets/styles.css +1 -1
  79. package/dist/index-B00RqlIS.cjs +1 -0
  80. package/dist/{index-Ccf1HAfZ.js → index-mNB7iXgB.js} +6 -5
  81. package/dist/index.cjs +1 -1
  82. package/dist/index.mjs +3 -3
  83. package/package.json +9 -2
  84. package/dist/TextFieldWrapper-DKMhxMuC.cjs +0 -1
  85. package/dist/index-IPoPOLW2.cjs +0 -1
package/INTEGRATION.md ADDED
@@ -0,0 +1,1034 @@
1
+ # @dgshahr/ui-kit — Integration Guide
2
+
3
+ Reference for integrating `@dgshahr/ui-kit` into a React project. Written for both humans and AI coding agents (Claude Code, Cursor, Copilot, Windsurf, etc.). This file ships inside the npm package at `node_modules/@dgshahr/ui-kit/INTEGRATION.md`.
4
+
5
+ - Storybook (live demos): https://dgshahr.github.io/uikit/
6
+ - Source: https://github.com/dgshahr/uikit
7
+ - TypeScript declarations (source of truth for props): `node_modules/@dgshahr/ui-kit/dist/**/index.d.ts`
8
+
9
+ ## Contents
10
+
11
+ 1. [Overview](#overview)
12
+ 2. [Installation](#installation)
13
+ 3. [Imports](#imports)
14
+ 4. [Next.js / SSR](#nextjs--ssr)
15
+ 5. [Theming](#theming)
16
+ 6. [Component reference](#component-reference)
17
+ 7. [Rules for AI agents](#rules-for-ai-agents)
18
+ 8. [Agent setup snippets](#agent-setup-snippets)
19
+
20
+ ---
21
+
22
+ ## Overview
23
+
24
+ - React component library written in TypeScript.
25
+ - Styled with Tailwind CSS v4 using the scoped prefix `dgsuikit:`. Styles are **pre-compiled and auto-injected** when a component is imported — no Tailwind, PostCSS or global CSS import needed in the consumer project.
26
+ - RTL-first: text inputs default to `dir="rtl"`; the Datepicker uses the Jalali (Persian) calendar.
27
+ - Colors are driven by CSS variables (`--dgs-color-*`) and can be overridden globally.
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install @dgshahr/ui-kit
33
+ # or
34
+ yarn add @dgshahr/ui-kit
35
+ # or
36
+ pnpm add @dgshahr/ui-kit
37
+ ```
38
+
39
+ Peer dependencies: `react >= 18.2.0`, `react-dom >= 18.2.0`.
40
+
41
+ ## Imports
42
+
43
+ Two equivalent styles:
44
+
45
+ ```tsx
46
+ // 1. Root named import
47
+ import { Button, Input, Select } from '@dgshahr/ui-kit';
48
+
49
+ // 2. Per-component subpath (default export) — smaller bundles
50
+ import Button from '@dgshahr/ui-kit/Button';
51
+ import Input from '@dgshahr/ui-kit/Form/Input';
52
+ ```
53
+
54
+ | Component | Root named export | Subpath |
55
+ | ---------------- | ------------------------------------- | -------------------------------------------- |
56
+ | Accordion | `AccordionGroup`, `AccordionItem` | `@dgshahr/ui-kit/Accordion` (named) |
57
+ | Alert | `Alert` | `@dgshahr/ui-kit/Alert` |
58
+ | Badge | `Badge` | `@dgshahr/ui-kit/Badge` |
59
+ | Breadcrumb | `Breadcrumb` | `@dgshahr/ui-kit/Breadcrumb` |
60
+ | Button | `Button` | `@dgshahr/ui-kit/Button` |
61
+ | Card | `Card` | `@dgshahr/ui-kit/Card` |
62
+ | Chip | `Chip` | `@dgshahr/ui-kit/Chip` |
63
+ | Divider | `Divider` | `@dgshahr/ui-kit/Divider` |
64
+ | Drawer | `Drawer` | `@dgshahr/ui-kit/Drawer` |
65
+ | Checkbox | `Checkbox` | `@dgshahr/ui-kit/Form/Checkbox` |
66
+ | Datepicker | `Datepicker` | `@dgshahr/ui-kit/Form/Datepicker` |
67
+ | FileUploader | `FileUploader` | `@dgshahr/ui-kit/Form/FileUploader` |
68
+ | Input | `Input` | `@dgshahr/ui-kit/Form/Input` |
69
+ | OtpInput | `OtpInput` | `@dgshahr/ui-kit/Form/OtpInput` |
70
+ | RadioButton | `RadioButton` | `@dgshahr/ui-kit/Form/RadioButton` |
71
+ | RangeInput | `RangeInput` | `@dgshahr/ui-kit/Form/RangeInput` |
72
+ | Select | `Select` | `@dgshahr/ui-kit/Form/Select` |
73
+ | Switch | `Switch` | `@dgshahr/ui-kit/Form/Switch` |
74
+ | Textarea | `Textarea` | `@dgshahr/ui-kit/Form/Textarea` |
75
+ | Timepicker | `Timepicker` | `@dgshahr/ui-kit/Form/Timepicker` |
76
+ | Menu | `Menu` (+ `Menu.Item`) | `@dgshahr/ui-kit/Menu` |
77
+ | Pagination | `Pagination` | `@dgshahr/ui-kit/Pagination` |
78
+ | ProgressBar | `ProgressBar` | `@dgshahr/ui-kit/Progress/Bar` |
79
+ | ProgressDoughnut | `ProgressDoughnut` | `@dgshahr/ui-kit/Progress/Doughnut` |
80
+ | ProgressStep | — (subpath only) | `@dgshahr/ui-kit/Progress/Step` |
81
+ | Rate | `Rate` | `@dgshahr/ui-kit/Rate` |
82
+ | Sidebar | `Sidebar` | `@dgshahr/ui-kit/Sidebar` |
83
+ | Slider | `Slider`, `Slide` | `@dgshahr/ui-kit/Slider` (named) |
84
+ | Stepper | `HorizontalStepper`, `HorizontalStep` | `@dgshahr/ui-kit/Stepper/Horizontal` (named) |
85
+ | Table | `Table` | `@dgshahr/ui-kit/Table` |
86
+ | Tabs | `Tabs` | `@dgshahr/ui-kit/Tabs` |
87
+ | Tooltip | `Tooltip` | `@dgshahr/ui-kit/Tooltip` |
88
+
89
+ Form components live under `Form/` in subpaths (`@dgshahr/ui-kit/Form/Input`, **not** `@dgshahr/ui-kit/Input`).
90
+
91
+ Prop types are exported from the component modules, e.g. `import type { ButtonProps } from '@dgshahr/ui-kit/Button'`.
92
+
93
+ ## Next.js / SSR
94
+
95
+ - Works with the Next.js App Router and Pages Router. No `transpilePackages` needed.
96
+ - Interactive components (inputs, pickers, Select, Drawer, Tooltip, Menu, Slider, Table, Tabs, Switch, etc.) use React state/effects. In the App Router, render them from a Client Component (`'use client'` at the top of your file).
97
+ - Portal-based components (Drawer, pickers in popover/drawer mode, Tooltip with `attachToBody`) access `document` only on the client.
98
+
99
+ ## Theming
100
+
101
+ Every color is a CSS variable holding **space-separated RGB numbers** (not hex):
102
+
103
+ ```
104
+ --dgs-color-{palette}-{shade}: {r} {g} {b};
105
+ ```
106
+
107
+ Palettes: `primary`, `secondary`, `gray`, `success`, `error`, `warning`, `sky`, `violet`, `flamingo`.
108
+ Shades: `50 100 200 300 400 500 600 700 800 900`.
109
+
110
+ Override in your global CSS:
111
+
112
+ ```css
113
+ :root {
114
+ --dgs-color-primary-500: 16 185 143;
115
+ --dgs-color-primary-600: 12 160 124;
116
+ }
117
+ ```
118
+
119
+ Scope overrides to a subtree by setting the variables on any ancestor selector instead of `:root`.
120
+
121
+ Styling individual components: nearly every component accepts `className` and often more specific slots (`wrapperClassName`, `containerClassName`, `popoverClassName`, …). Use your own CSS/Tailwind classes there.
122
+
123
+ ---
124
+
125
+ ## Component reference
126
+
127
+ Legend: **bold** prop name = required. `Default` column shows the runtime default when one exists. Unless stated otherwise, `className` applies to the outermost element.
128
+
129
+ ### AccordionGroup / AccordionItem
130
+
131
+ ```tsx
132
+ import { AccordionGroup, AccordionItem } from '@dgshahr/ui-kit';
133
+
134
+ <AccordionGroup defaultActiveKey="a">
135
+ <AccordionItem
136
+ accordionKey="a"
137
+ title="Shipping"
138
+ >
139
+ …
140
+ </AccordionItem>
141
+ <AccordionItem
142
+ accordionKey="b"
143
+ title="Returns"
144
+ >
145
+ …
146
+ </AccordionItem>
147
+ </AccordionGroup>;
148
+ ```
149
+
150
+ `AccordionGroup`
151
+
152
+ | Prop | Type | Default | Notes |
153
+ | ---------------- | -------------------- | ------- | -------------------------------- |
154
+ | defaultActiveKey | `string \| string[]` | | Initially open item key(s) |
155
+ | disableAccordion | `boolean` | `false` | Allow several items open at once |
156
+ | className | `string` | | |
157
+ | children | `ReactNode` | | `AccordionItem` elements |
158
+
159
+ `AccordionItem`
160
+
161
+ | Prop | Type | Default |
162
+ | ---------------- | ----------- | ------- |
163
+ | **title** | `ReactNode` | |
164
+ | accordionKey | `string` | |
165
+ | disable | `boolean` | |
166
+ | hideDivider | `boolean` | `false` |
167
+ | hideArrow | `boolean` | `false` |
168
+ | className | `string` | |
169
+ | titleClassName | `string` | |
170
+ | contentClassName | `string` | |
171
+ | children | `ReactNode` | |
172
+
173
+ ### Alert
174
+
175
+ ```tsx
176
+ <Alert
177
+ variant="warning"
178
+ title="Heads up"
179
+ text="Your session expires in 5 minutes."
180
+ primaryButton={{ text: 'Extend', onClick: extend }}
181
+ closable
182
+ />
183
+ ```
184
+
185
+ | Prop | Type | Default |
186
+ | ------------- | ------------------------------------------------------------------------ | ----------- |
187
+ | **text** | `ReactNode` | |
188
+ | variant | `'warning' \| 'primary' \| 'error' \| 'success' \| 'gray'` | `'primary'` |
189
+ | size | `'large' \| 'small'` | `'small'` |
190
+ | title | `string` | |
191
+ | primaryButton | `ButtonProps` (without variant/color/size/children) & `{ text: string }` | |
192
+ | outlineButton | same as `primaryButton` | |
193
+ | closable | `boolean` | |
194
+ | showTitleIcon | `boolean` | `true` |
195
+ | className | `string` | |
196
+
197
+ ### Badge
198
+
199
+ ```tsx
200
+ <Badge value="New" color="success" type="twoTone" />
201
+ <Badge valueType="number" value={12} />
202
+ ```
203
+
204
+ | Prop | Type | Default |
205
+ | -------------------- | ------------------------------------------------------------------------------------------------------------ | ----------- |
206
+ | **value** | `string \| number` | |
207
+ | type | `'twoTone' \| 'solid'` | `'solid'` |
208
+ | color | `'primary' \| 'secondary' \| 'gray' \| 'success' \| 'error' \| 'warning' \| 'sky' \| 'violet' \| 'flamingo'` | `'primary'` |
209
+ | size | `'small' \| 'medium' \| 'large'` | `'medium'` |
210
+ | valueType | `'text' \| 'number'` | `'text'` |
211
+ | width | `string \| number` | |
212
+ | leftIcon / rightIcon | `ReactNode` — only when `valueType` is `'text'` | |
213
+ | icon | `ReactNode` — **deprecated**, use `leftIcon`/`rightIcon` | |
214
+ | className | `string` | `''` |
215
+
216
+ ### Breadcrumb
217
+
218
+ ```tsx
219
+ <Breadcrumb
220
+ pageTitle="Order #123"
221
+ items={[
222
+ { title: 'Home', link: '/' },
223
+ { title: 'Orders', onClick: () => router.push('/orders') },
224
+ ]}
225
+ />
226
+ ```
227
+
228
+ | Prop | Type |
229
+ | --------- | ------------------ |
230
+ | **items** | `BreadcrumbItem[]` |
231
+ | pageTitle | `string` |
232
+ | className | `string` |
233
+
234
+ `BreadcrumbItem = { title: string; icon?: ReactNode } & ({ link: string } | { onClick: () => void })` — provide exactly one of `link` / `onClick`.
235
+
236
+ ### Button
237
+
238
+ Extends all native `<button>` attributes.
239
+
240
+ ```tsx
241
+ <Button
242
+ variant="outline"
243
+ color="error"
244
+ size="small"
245
+ leftIcon={<TrashIcon />}
246
+ isLoading={pending}
247
+ >
248
+ Delete
249
+ </Button>
250
+ ```
251
+
252
+ | Prop | Type | Default |
253
+ | -------------------- | ---------------------------------------------------------- | ----------- |
254
+ | variant | `'primary' \| 'secondary' \| 'outline' \| 'text'` | `'primary'` |
255
+ | color | `'primary' \| 'warning' \| 'error' \| 'success' \| 'gray'` | `'primary'` |
256
+ | size | `'small' \| 'medium' \| 'large'` | |
257
+ | isFullWidth | `boolean` | |
258
+ | isLoading | `boolean` | |
259
+ | leftIcon / rightIcon | `JSX.Element` | |
260
+ | …native | `ButtonHTMLAttributes<HTMLButtonElement>` | |
261
+
262
+ ### Card
263
+
264
+ ```tsx
265
+ <Card
266
+ color="primary"
267
+ header={{ title: 'Summary', icon: <InfoIcon />, Element: <Button size="small">Edit</Button> }}
268
+ >
269
+ …
270
+ </Card>
271
+ ```
272
+
273
+ | Prop | Type | Default |
274
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
275
+ | **children** | `ReactNode` | |
276
+ | size | `'small' \| 'medium'` | `'medium'` |
277
+ | color | `'primary' \| 'warning' \| 'error' \| 'success' \| 'gray' \| 'white'` | `'white'` |
278
+ | header | `{ title?: string; icon?: ReactNode; variant?: 'primary' \| 'default'; Element?: ReactNode; color?: CardColor; className?: string }` | |
279
+ | className | `string` | |
280
+ | wrapperClassName | `string` | |
281
+
282
+ ### Chip
283
+
284
+ ```tsx
285
+ <Chip
286
+ label="Filter"
287
+ clickable
288
+ isActive={active}
289
+ onClick={toggle}
290
+ />
291
+ ```
292
+
293
+ | Prop | Type | Default |
294
+ | -------------------- | --------------------------------------------------------------------------------------- | ----------- |
295
+ | **label** | `string \| ReactNode` | |
296
+ | size | `'xsmall' \| 'small' \| 'large'` | `'small'` |
297
+ | color | `'primary' \| 'gray'` | `'primary'` |
298
+ | filled | `boolean` | |
299
+ | isActive | `boolean` | |
300
+ | disabled | `boolean` | |
301
+ | badgeNumber | `number` | |
302
+ | leftIcon / rightIcon | `ReactNode` | `null` |
303
+ | clickable | `boolean` — `true` renders a `<button>` (button attrs); otherwise a `<div>` (div attrs) | |
304
+
305
+ ### Divider
306
+
307
+ | Prop | Type | Default |
308
+ | --------- | ---------------------------- | -------- |
309
+ | **type** | `'horizontal' \| 'vertical'` | |
310
+ | size | `'thin' \| 'thick'` | `'thin'` |
311
+ | color | `'white' \| 'gray'` | `'gray'` |
312
+ | className | `string` | |
313
+
314
+ ### Drawer
315
+
316
+ ```tsx
317
+ <Drawer
318
+ open={open}
319
+ onClose={() => setOpen(false)}
320
+ position="right"
321
+ header={{ title: 'Filters', haveCloseIcon: true }}
322
+ footer={{ element: <Button isFullWidth>Apply</Button> }}
323
+ >
324
+ …
325
+ </Drawer>
326
+ ```
327
+
328
+ | Prop | Type | Default |
329
+ | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ---------- |
330
+ | **open** | `boolean` | |
331
+ | **onClose** | `() => void` | |
332
+ | position | `'bottom' \| 'top' \| 'right' \| 'left' \| 'center'` | `'bottom'` |
333
+ | persist | `boolean` — clicking the mask does not close the drawer | |
334
+ | padding | `number` | `8` |
335
+ | width | `CSSProperties['width']` | |
336
+ | header | `{ title?: string; description?: string; haveCloseIcon?: boolean; actionElement?: ReactNode; containerClassName?: string }` | |
337
+ | footer | `{ element?: ReactNode; containerClassName?: string }` | |
338
+ | containerElement | `Element \| null` — portal target | |
339
+ | havePopover | `boolean` | |
340
+ | className / maskClassName / containerClassName | `string` | |
341
+ | children | `ReactNode` | |
342
+
343
+ ---
344
+
345
+ ### Form: shared field props
346
+
347
+ `Input`, `Textarea`, `OtpInput` (and `inputProps` of pickers/Select) share these **text-field props**:
348
+
349
+ | Prop | Type | Default | Notes |
350
+ | -------------------- | ----------------------------------- | ------- | --------------------------------------------------- |
351
+ | labelContent | `string` | | Label text |
352
+ | labelAddon | `ReactNode` | | Extra node next to label |
353
+ | link | `{ cnotent: string; href: string }` | | Link next to label (note: key is spelled `cnotent`) |
354
+ | required | `boolean` | | Shows required marker |
355
+ | disabled | `boolean` | | |
356
+ | isError | `boolean` | | Error styling |
357
+ | errorMessage | `ReactNode` | | |
358
+ | hintMessage | `ReactNode` | | |
359
+ | hintMessageClassName | `string` | | |
360
+ | showMaxLength | `boolean` | | Shows `value.length / maxLength` counter |
361
+ | rightIcon | `JSX.Element` | | |
362
+ | dir | `'rtl' \| 'ltr'` | `'rtl'` | |
363
+ | placeholderDir | `'rtl' \| 'ltr'` | = `dir` | |
364
+ | containerClassName | `string` | | Field box |
365
+ | wrapperClassName | `string` | | Outer wrapper (label + field + info) |
366
+
367
+ `Checkbox` and `RadioButton` share **choice props**:
368
+
369
+ | Prop | Type | Default | Notes |
370
+ | ------------------ | ------------------------------------- | ----------- | -------------------------------- |
371
+ | label | `string \| ReactNode` | | |
372
+ | variant | `'default' \| 'bordered'` | `'default'` | |
373
+ | icon | `ReactNode` | | Only with `variant="bordered"` |
374
+ | isError | `boolean` | | |
375
+ | errorMessage | `string` | | |
376
+ | helperMessage | `string` | | |
377
+ | containerClassName | `string` | | |
378
+ | …native | `InputHTMLAttributes` (except `type`) | | `checked`, `onChange`, `name`, … |
379
+
380
+ ### Input
381
+
382
+ `forwardRef<HTMLInputElement>`. Extends native input attributes (except `dir`, `prefix`) + text-field props.
383
+
384
+ ```tsx
385
+ <Input
386
+ labelContent="Email"
387
+ dir="ltr"
388
+ value={email}
389
+ onChange={(e) => setEmail(e.target.value)}
390
+ onClear={() => setEmail('')}
391
+ errorMessage={errors.email}
392
+ />
393
+ ```
394
+
395
+ | Prop | Type | Notes |
396
+ | ---------------------------------- | ------------------------ | ------------------------------------------- |
397
+ | leftIcon | `JSX.Element` | |
398
+ | prefix / postfix | `ReactNode` | Inline adornments |
399
+ | prefixClassName / postfixClassName | `string` | |
400
+ | onClear | `() => void` | Shows a clear button when provided |
401
+ | onInput | `(e) => void \| boolean` | Return `true` to stop the built-in handling |
402
+ | type="password" | | Adds a show/hide toggle |
403
+
404
+ ### Textarea
405
+
406
+ `forwardRef<HTMLTextAreaElement>`. Native textarea attributes (except `dir`, `onClick`) + text-field props.
407
+
408
+ ```tsx
409
+ <Textarea
410
+ labelContent="Description"
411
+ maxLength={300}
412
+ showMaxLength
413
+ value={v}
414
+ onChange={(e) => setV(e.target.value)}
415
+ />
416
+ ```
417
+
418
+ ### OtpInput
419
+
420
+ | Prop | Type | Default |
421
+ | ------------------------ | ------------------------- | ------- | -------------------------------- |
422
+ | **value** | `string` | |
423
+ | **onChange** | `(value: string) => void` | |
424
+ | onEnd | `(value: string) => void` | | Fired when all digits are filled |
425
+ | inputsNumber | `number` | `4` |
426
+ | inputsContainerClassName | `string` | |
427
+ | className | `string` | |
428
+ | … | other `InputProps` | |
429
+
430
+ ### Checkbox
431
+
432
+ Choice props + `isIndeterminate?: boolean`.
433
+
434
+ ```tsx
435
+ <Checkbox
436
+ label="Accept terms"
437
+ checked={ok}
438
+ onChange={(e) => setOk(e.target.checked)}
439
+ />
440
+ ```
441
+
442
+ ### RadioButton
443
+
444
+ Choice props.
445
+
446
+ ```tsx
447
+ <RadioButton
448
+ name="plan"
449
+ value="pro"
450
+ label="Pro"
451
+ checked={plan === 'pro'}
452
+ onChange={() => setPlan('pro')}
453
+ />
454
+ ```
455
+
456
+ ### Switch
457
+
458
+ | Prop | Type | Default |
459
+ | ------------------------------ | ---------------------------- | --------- |
460
+ | **checked** | `boolean` | |
461
+ | **onChange** | `(checked: boolean) => void` | |
462
+ | label | `string` | |
463
+ | description | `string` | |
464
+ | size | `'large' \| 'small'` | `'large'` |
465
+ | disabled | `boolean` | |
466
+ | isIntermediate | `boolean` | |
467
+ | className / containerClassName | `string` | |
468
+
469
+ ### RangeInput
470
+
471
+ Generic: `number` for a single thumb, `number[]` for a range.
472
+
473
+ ```tsx
474
+ <RangeInput
475
+ min={0}
476
+ max={100}
477
+ value={[20, 80]}
478
+ onChange={setRange}
479
+ startTitle="Min"
480
+ endTitle="Max"
481
+ />
482
+ ```
483
+
484
+ | Prop | Type | Default |
485
+ | --------------------- | -------------------------------------------- | ----------- |
486
+ | **value** | `number \| number[]` | |
487
+ | **onChange** | `(value) => void` (same type as `value`) | |
488
+ | **min** | `number` | |
489
+ | **max** | `number` | |
490
+ | step | `number` | `1` |
491
+ | color | `'primary' \| 'secondary'` | `'primary'` |
492
+ | tooltip | `boolean \| ReactNode` | `true` |
493
+ | tooltipSize | `'small' \| 'medium' \| 'large' \| 'xLarge'` | `'medium'` |
494
+ | tooltipClassName | `string` | |
495
+ | startTitle / endTitle | `string` | |
496
+ | disabled | `boolean` | |
497
+ | wrapperClassName | `string` | |
498
+
499
+ ### Picker wrapper props (Select, Datepicker, Timepicker)
500
+
501
+ | Prop | Type | Default | Notes |
502
+ | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------- | -------------------------------------- |
503
+ | dropdownType | `'popover' \| 'drawer'` | `'popover'` | |
504
+ | popoverPosition | `'top' \| 'bottom' \| 'top-left' \| 'top-center' \| 'top-right' \| 'bottom-left' \| 'bottom-center' \| 'bottom-right'` | | Popover only |
505
+ | popoverClassName | `string` | | Popover only |
506
+ | drawerProps | `DrawerProps` without `children`/`open`/`onClose` | | Drawer only |
507
+ | inputProps | `InputProps` without `leftIcon` | | Props for the built-in trigger input |
508
+ | customInput | `(isOpen: boolean) => ReactNode` | | Replace trigger; excludes `inputProps` |
509
+ | isLoading | `boolean` | | |
510
+ | disabled | `boolean` | | |
511
+ | wrapperClassName | `string` | | |
512
+
513
+ ### Select
514
+
515
+ Generic over option value `T`. Single or multiple mode.
516
+
517
+ ```tsx
518
+ <Select
519
+ options={[{ value: 1, label: 'Tehran' }, { value: 2, label: 'Shiraz' }]}
520
+ value={city}
521
+ onChange={setCity}
522
+ searchable
523
+ inputProps={{ labelContent: 'City', placeholder: 'Choose…' }}
524
+ />
525
+
526
+ <Select mode="multiple" options={tags} value={selected} onChange={setSelected} optionsTitle="Tags" />
527
+ ```
528
+
529
+ | Prop | Type | Notes |
530
+ | ---------------------------- | --------------------------------------------------- | ---------------------- |
531
+ | **options** | `{ value: T; label: string; disabled?: boolean }[]` | |
532
+ | **value** | `T` (single) / `T[]` (multiple) | |
533
+ | **onChange** | `(value: T) => void` / `(value: T[]) => void` | |
534
+ | mode | `'single' \| 'multiple'` | default single |
535
+ | searchable | `boolean \| InputProps` (without `onChange`) | |
536
+ | optionCell | `(option, isActive: boolean) => ReactNode` | Custom option renderer |
537
+ | optionCellClassName | `string` | |
538
+ | beforeOptions / afterOptions | `ReactNode` | |
539
+ | emptyContent | `ReactNode` | |
540
+ | showClearButtonOnEmpty | `boolean` | |
541
+ | optionsTitle | `string` | Multiple mode only |
542
+ | separateSelectedOptions | `boolean` | Multiple mode only |
543
+ | … | picker wrapper props | |
544
+
545
+ ### Datepicker
546
+
547
+ Jalali (Persian) calendar. Values are native JS `Date` objects.
548
+
549
+ ```tsx
550
+ <Datepicker value={date} onChange={setDate} inputProps={{ labelContent: 'Birth date' }} />
551
+
552
+ <Datepicker acceptRange value={{ start, end }} onChange={({ start, end }) => …} />
553
+ ```
554
+
555
+ | Prop | Type | Default | Notes |
556
+ | -------------------- | ----------------------------------------------------------------------------------- | ------- | ------------------------------------------- |
557
+ | **value** | `Date \| null` — or `{ start: Date \| null; end: Date \| null }` with `acceptRange` | | |
558
+ | **onChange** | `(value: Date) => void` — or `(value: { start; end }) => void` with `acceptRange` | | |
559
+ | acceptRange | `boolean` | | Range selection |
560
+ | mode | `'input' \| 'calendar'` | | `'calendar'` renders inline calendar |
561
+ | startDate / endDate | `Date` | | Selectable bounds |
562
+ | disableDates | `Date[]` | | |
563
+ | holidays | `Date[]` | | |
564
+ | highlightWeekends | `boolean` | | |
565
+ | showExtraDays | `boolean` | | Show adjacent-month days |
566
+ | showTodayButton | `boolean` | `true` | |
567
+ | showSubmitButton | `boolean` | `true` | |
568
+ | onSubmit | `() => void` | | Only when `showSubmitButton` is not `false` |
569
+ | onInternalDateChange | `(date: Date) => void` | | Visible month/year changes |
570
+ | dayHoverAction | `{ onClick: (day: DayItem) => void; element: (day: DayItem) => ReactNode }` | | |
571
+ | … | picker wrapper props | | |
572
+
573
+ ### Timepicker
574
+
575
+ Values are `Date` objects (hour/minute are read from them).
576
+
577
+ ```tsx
578
+ <Timepicker
579
+ value={time}
580
+ onChange={setTime}
581
+ minuteStep={15}
582
+ />
583
+ ```
584
+
585
+ | Prop | Type | Default |
586
+ | ------------------------ | -------------------------------------------------- | ------- |
587
+ | **value** / **onChange** | same shape as Datepicker (single or `acceptRange`) | |
588
+ | acceptRange | `boolean` | |
589
+ | mode | `'input' \| 'time'` | |
590
+ | minuteStep | `number` | `1` |
591
+ | showNowButton | `boolean` | `true` |
592
+ | showSubmitButton | `boolean` | `true` |
593
+ | onSubmit | `() => void` | |
594
+ | … | picker wrapper props | |
595
+
596
+ ### FileUploader
597
+
598
+ ```tsx
599
+ <FileUploader
600
+ files={file ? { file } : undefined}
601
+ onChange={(f) => setFile(f)}
602
+ fileInputProps={{ title: 'Upload avatar', accept: 'image/*' }}
603
+ />
604
+
605
+ <FileUploader
606
+ mode="multiple"
607
+ files={files.map((file) => ({ file }))}
608
+ onChange={(_, list) => setFiles(Array.from(list ?? []))}
609
+ previewProps={{ type: 'grid' }}
610
+ />
611
+ ```
612
+
613
+ | Prop | Type | Notes |
614
+ | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------- |
615
+ | **onChange** | `(file: File \| undefined, files: FileList \| null) => void` | |
616
+ | mode | `'single' \| 'multiple'` | default single |
617
+ | files | `FileType` (single) / `FileType[]` (multiple) | Controlled preview list |
618
+ | previewProps | `{ type?: 'default' \| 'compact' }` (single) / `{ type?: 'list' \| 'grid' }` (multiple), plus `leftButton`, `rightButton`, `exteraButton`, `wrapperClassName`, `previewClassName` | |
619
+ | hideFileInput | `boolean` | Multiple mode only |
620
+ | fileInputProps | `{ title?; description?; hideIcon?; button?: boolean \| ButtonProps; helperProps?; …native file input attrs }` | |
621
+ | isError | `boolean` | |
622
+ | disabled | `boolean` | |
623
+ | className | `string` | |
624
+
625
+ `FileType = { file: File } | { src: string }` plus optional `loading?: boolean | number` (number = upload %), `status?: 'warning' | 'error' | 'default'`, `title?`, `errorMessage?`, `hintMessage?`.
626
+
627
+ ---
628
+
629
+ ### Menu
630
+
631
+ ```tsx
632
+ <Menu
633
+ trigger={(toggle, ref) => (
634
+ <button
635
+ ref={ref as React.Ref<HTMLButtonElement>}
636
+ type="button"
637
+ onClick={toggle}
638
+ >
639
+ Actions
640
+ </button>
641
+ )}
642
+ >
643
+ <Menu.Item
644
+ icon={<EditIcon />}
645
+ onClick={edit}
646
+ >
647
+ Edit
648
+ </Menu.Item>
649
+ <Menu.Item disabled>Archive</Menu.Item>
650
+ </Menu>
651
+ ```
652
+
653
+ `Menu`
654
+
655
+ | Prop | Type | Default |
656
+ | ---------------- | ---------------------------------------------------------------- | ---------------- |
657
+ | **trigger** | `(toggle: () => void, ref: React.Ref<HTMLElement>) => ReactNode` | |
658
+ | **children** | `ReactNode` | |
659
+ | position | popper position (see picker wrapper) | `'bottom-right'` |
660
+ | className | `string` | `''` |
661
+ | popoverClassName | `string` | `''` |
662
+
663
+ `Menu.Item`: **children** `ReactNode`, `onClick?`, `icon?`, `endElement?`, `disabled?`, `className?`. Clicking an item closes the menu.
664
+
665
+ ### Pagination
666
+
667
+ ```tsx
668
+ <Pagination
669
+ totalCount={240}
670
+ pageSize={20}
671
+ onPageChange={setPage}
672
+ />
673
+ ```
674
+
675
+ | Prop | Type | Default |
676
+ | ------------------------- | ------------------------ | ------- |
677
+ | **totalCount** | `number` | |
678
+ | **pageSize** | `number` | |
679
+ | onPageChange | `(page: number) => void` | |
680
+ | defaultCurrent | `number` | `1` |
681
+ | siblingCount | `number` | `1` |
682
+ | navigationButtonsWithText | `boolean` | `true` |
683
+ | hideOnSinglePage | `boolean` | |
684
+ | className | `string` | |
685
+
686
+ ### ProgressBar
687
+
688
+ | Prop | Type | Default |
689
+ | --------------- | -------------------------- | -------------- |
690
+ | **title** | `string` | |
691
+ | **current** | `number` | |
692
+ | total | `number` | `100` |
693
+ | color | `'primary' \| 'secondary'` | `'primary'` |
694
+ | currentShowType | `'percentage' \| 'value'` | `'percentage'` |
695
+ | className | `string` | |
696
+
697
+ ### ProgressDoughnut
698
+
699
+ | Prop | Type | Default |
700
+ | ------------- | ------------------------------------------------- | ----------- |
701
+ | **current** | `number` | |
702
+ | **total** | `number` | |
703
+ | color | `'primary' \| 'secondary' \| 'gray' \| 'warning'` | `'primary'` |
704
+ | size | `number` (px) | `48` |
705
+ | strokeSize | `number` | `6` |
706
+ | showText | `boolean` | |
707
+ | textClassName | `string` — only with `showText` | |
708
+ | svgProps | `SVGProps<SVGSVGElement>` | |
709
+
710
+ ### ProgressStep
711
+
712
+ Subpath import only: `import ProgressStep from '@dgshahr/ui-kit/Progress/Step'`.
713
+
714
+ ```tsx
715
+ <ProgressStep
716
+ type="rtl"
717
+ size="large"
718
+ color="primary"
719
+ title="Profile"
720
+ currentStep={2}
721
+ totalSteps={4}
722
+ showStepsCount
723
+ />
724
+ ```
725
+
726
+ | Prop | Type | Default |
727
+ | ------------------------------ | ---------------------------------------- | ----------- |
728
+ | **type** | `'rtl' \| 'center'` | `'rtl'` |
729
+ | **size** | `'small' \| 'large'` | `'large'` |
730
+ | **color** | `'primary' \| 'secondary'` | `'primary'` |
731
+ | **title** | `string` | |
732
+ | **currentStep** | `number` (1-based) | |
733
+ | **totalSteps** | `number` | `5` |
734
+ | progress | `number` 0–100, fill within current step | `100` |
735
+ | subtitle | `string` | |
736
+ | showSubtitle | `boolean` | |
737
+ | showStepsCount | `boolean` | |
738
+ | className / containerClassName | `string` | |
739
+
740
+ ### Rate
741
+
742
+ ```tsx
743
+ <Rate
744
+ value={4}
745
+ total={5}
746
+ showTotalStars
747
+ onChange={setRating}
748
+ />
749
+ ```
750
+
751
+ | Prop | Type | Default | Notes |
752
+ | --------------- | ------------------------- | --------- | ---------------------------------------- |
753
+ | **value** | `number` | | |
754
+ | **total** | `number` | | |
755
+ | onChange | `(value: number) => void` | | Makes it interactive |
756
+ | size | `'small' \| 'large'` | `'large'` | |
757
+ | showTotalStars | `boolean` | | At least one of these two must be `true` |
758
+ | showRateNumber | `boolean` | `true` | |
759
+ | showStarsNumber | `boolean` | | |
760
+ | className | `string` | | |
761
+
762
+ ### Sidebar
763
+
764
+ ```tsx
765
+ <Sidebar
766
+ isOpen={open}
767
+ setIsOpen={setOpen}
768
+ logo={{ open: '/logo.svg', close: '/logo-mini.svg', alt: 'Logo' }}
769
+ items={[
770
+ {
771
+ title: 'Main',
772
+ children: [{ title: 'Dashboard', icon: <HomeIcon />, link: '/', active: true }],
773
+ },
774
+ ]}
775
+ userProfile={{ image: '/me.png', name: 'Jane' }}
776
+ onLogout={logout}
777
+ />
778
+ ```
779
+
780
+ | Prop | Type | Notes |
781
+ | ----------------- | ----------------------------------------------------------------------- | ------------------------------------- |
782
+ | **isOpen** | `boolean` | |
783
+ | **setIsOpen** | `(isOpen: boolean) => void` | |
784
+ | items | `FirstLevelSidebarItem[]` | 3 levels, see below |
785
+ | logo | `{ open: string; close: string } & img attrs (except src)` | |
786
+ | searchInput | `boolean \| InputProps` (without value/onChange) | |
787
+ | userProfile | `{ image: string; name?: string; description?: string; link?: string }` | |
788
+ | onLogout | `() => void` | |
789
+ | logOutButtonProps | `ButtonProps` without `onClick` | |
790
+ | extraComponent | `ReactNode` | |
791
+ | hideOnClose | `boolean` | Fully hide when closed |
792
+ | openOnHover | `boolean` | Only when `hideOnClose` is not `true` |
793
+ | showMask | `boolean` | |
794
+ | className | `string` | |
795
+
796
+ Items: `FirstLevelSidebarItem { title; children?: SecondLevelSidebarItem[] }` → `SecondLevelSidebarItem { title; icon: ReactNode; link?; badgeCount?; disabled?; active?; children?: ThirdLevelSidebarItem[] }` → `ThirdLevelSidebarItem { title; link: string; badgeCount?; disabled?; active? }`.
797
+
798
+ ### Slider / Slide
799
+
800
+ `Slider` is `forwardRef<SliderRef>`; `SliderRef = { navigate(index: number): void; element: HTMLDivElement | null }`. `Slide` accepts native div attributes.
801
+
802
+ ```tsx
803
+ <Slider
804
+ slidesPerView={1.2}
805
+ spaceBetween={12}
806
+ autoplay={{ delay: 4000 }}
807
+ responsive={{ 768: { slidesPerView: 3 } }}
808
+ >
809
+ {items.map((i) => (
810
+ <Slide key={i.id}>…</Slide>
811
+ ))}
812
+ </Slider>
813
+ ```
814
+
815
+ | Prop | Type | Default |
816
+ | ----------------------------------------------------------------------------- | ----------------------------------------------------- | -------- |
817
+ | slidesPerView | `number` | `1` |
818
+ | spaceBetween | `number` (px) | `0` |
819
+ | centerMode | `boolean` | |
820
+ | autoplay | `boolean \| { delay?: number \| null }` | |
821
+ | initialSlide | `number` | |
822
+ | onSlideIndexChange | `(index: number) => void` | |
823
+ | showNavigationDots | `boolean` | `true` |
824
+ | showPaginationText | `boolean` | |
825
+ | navigationVariant | `'inside' \| 'outside'` | |
826
+ | navigationButtonsShowType | `'hide' \| 'hover' \| 'permanent' \| 'onSides'` | `'hide'` |
827
+ | responsive | `Record<minWidthPx, Omit<SliderProps, 'responsive'>>` | |
828
+ | containerXPadding | `number` | `0` |
829
+ | className / containerClassName / dotsClassName / navigationContainerClassName | `string` | |
830
+
831
+ ### HorizontalStepper / HorizontalStep
832
+
833
+ ```tsx
834
+ <HorizontalStepper activeStep={1}>
835
+ <HorizontalStep
836
+ title="Cart"
837
+ icon={<CartIcon />}
838
+ />
839
+ <HorizontalStep
840
+ title="Shipping"
841
+ icon={<TruckIcon />}
842
+ />
843
+ <HorizontalStep
844
+ title="Pay"
845
+ icon={<CardIcon />}
846
+ />
847
+ </HorizontalStepper>
848
+ ```
849
+
850
+ `HorizontalStepper`: `activeStep?: number` (0-based, default `0`), `size?: 'small' | 'medium'` (default `'medium'`), `stepOrientation?: 'horizontal' | 'vertical'` (default `'horizontal'`), `classname?: string` (lowercase `n`).
851
+
852
+ `HorizontalStep`: **title** `string`, **icon** `ReactNode`, `activeTitle?`, `completeTitle?`, `subTitle?`, `activeIcon?`, `completeIcon?`, `classname?`. `index` is injected by the stepper.
853
+
854
+ ### Table
855
+
856
+ Generic over row type `T`. `dataIndex` accepts a key or a deep path (type-safe when `T` is known).
857
+
858
+ ```tsx
859
+ type User = { id: string; name: string; address: { city: string } };
860
+
861
+ <Table<User>
862
+ data={users}
863
+ rowKey="id"
864
+ columns={[
865
+ { title: 'Name', dataIndex: 'name', sort: { active: sort, onSort: setSort } },
866
+ { title: 'City', dataIndex: ['address', 'city'] },
867
+ {
868
+ key: 'actions',
869
+ title: '',
870
+ render: (u) => <Button size="small">Edit</Button>,
871
+ sticky: 'left',
872
+ },
873
+ ]}
874
+ pagination={{ totalCount, pageSize: 20, onPageChange: setPage }}
875
+ loading={isFetching}
876
+ />;
877
+ ```
878
+
879
+ | Prop | Type | Default |
880
+ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------- |
881
+ | **data** | `T[]` | |
882
+ | **columns** | `ColumnsType<T>[]` | |
883
+ | **rowKey** | `keyof T` | |
884
+ | header | `{ title?; showTotal?; extraElement?; className?; pageCountSelector?: { options; defaultValue?; onPageCountChange?; selectProps? } }` | |
885
+ | pagination | `PaginationProps` | |
886
+ | rowSelection | `{ selectedRowKeys: string[]; onSelectRow: (e, key: string \| string[], record?) => void; align?; sticky?; className? }` | |
887
+ | loading | `boolean \| { size: number }` (loader size in px) | |
888
+ | emptyContent | `ReactNode` | |
889
+ | stickyTableHeader | `boolean` | |
890
+ | layout | `'fixed' \| 'auto'` | `'auto'` |
891
+ | getRowClassName | `(record: T) => string \| undefined` | |
892
+ | className / containerClassName / wrapperClassName | `string` | |
893
+
894
+ `ColumnsType<T>`: one of `key` / `dataIndex` required; `title?`, `align?: 'start' | 'center' | 'end'`, `render?: (record, index) => ReactNode`, `sort?: { active?: 'ascend' | 'descend'; onSort(value) }`, `sticky?: 'left' | 'right'`, `ellipsis?: boolean | { hideTooltip?: boolean }`, `tooltip?: TooltipProps & { anchorIcon? }`, `className?`.
895
+
896
+ ### Tabs
897
+
898
+ ```tsx
899
+ <Tabs
900
+ activeKey={tab}
901
+ onChange={setTab}
902
+ items={[
903
+ { key: 'info', title: 'Info' },
904
+ { key: 'orders', title: 'Orders', badgeNumber: 3 },
905
+ ]}
906
+ />
907
+ ```
908
+
909
+ | Prop | Type |
910
+ | ---------------- | -------------------------------------------------------------------------------------------------------- |
911
+ | **activeKey** | `string \| number` |
912
+ | **onChange** | `(key: string \| number) => void` |
913
+ | **items** | `{ key: string \| number; title: string; icon?: ReactNode; badgeNumber?: number; disabled?: boolean }[]` |
914
+ | fullWidth | `boolean` |
915
+ | fullWidthButtons | `boolean` — only when `fullWidth` is `true` |
916
+ | className | `string` |
917
+ | tabItemClassName | `string` |
918
+
919
+ Tabs renders only the tab bar; render the active panel yourself.
920
+
921
+ ### Tooltip
922
+
923
+ ```tsx
924
+ <Tooltip
925
+ title="VAT"
926
+ content="9% value added tax is included."
927
+ position="bottom-center"
928
+ >
929
+ <InfoIcon />
930
+ </Tooltip>
931
+ ```
932
+
933
+ | Prop | Type | Default |
934
+ | ---------------- | ------------------------------------- | -------------- |
935
+ | **content** | `ReactNode` | |
936
+ | **children** | `ReactNode` — the anchor | |
937
+ | position | popper position (see picker wrapper) | `'top-center'` |
938
+ | title | `string` | |
939
+ | icon | `ReactNode` | |
940
+ | footer | `ReactNode` | |
941
+ | disabled | `boolean` | |
942
+ | attachToBody | `boolean` — portal to `document.body` | |
943
+ | className | `string` | |
944
+ | wrapperClassName | `string` | |
945
+
946
+ Position auto-flips when there is no room.
947
+
948
+ ---
949
+
950
+ ## Rules for AI agents
951
+
952
+ When writing code in a project that depends on `@dgshahr/ui-kit`:
953
+
954
+ 1. **Prefer kit components.** Before building a button, input, select, date/time picker, modal/drawer, tabs, table, tooltip, badge, alert, pagination, etc., use the kit component from this guide.
955
+ 2. **Use the documented props** for variants, sizes and colors (`variant`, `color`, `size`). Do not recreate these looks with custom CSS.
956
+ 3. **Imports:** use `@dgshahr/ui-kit` or the subpaths listed in [Imports](#imports). Form components are under `Form/`. Never import from `@dgshahr/ui-kit/dist/...` or internal paths.
957
+ 4. **No Tailwind setup for the kit.** Styles are bundled; do not add Tailwind, PostCSS or a CSS import for the kit.
958
+ 5. **Do not use `dgsuikit:`-prefixed classes** in app code — they are internal to the kit and may not be generated.
959
+ 6. **Theme via CSS variables** (`--dgs-color-{palette}-{shade}: r g b`), never by overriding internal class names.
960
+ 7. **Customize via slot class props** (`className`, `wrapperClassName`, `containerClassName`, …).
961
+ 8. **Controlled components:** `Switch`, `Tabs`, `Select`, `Datepicker`, `Timepicker`, `OtpInput`, `RangeInput`, `Drawer` require `value`/`checked`/`activeKey`/`open` + change handler.
962
+ 9. **RTL:** text fields default to `dir="rtl"`; pass `dir="ltr"` for emails, URLs, numbers, codes.
963
+ 10. **Dates:** Datepicker shows the Jalali calendar but reads/writes plain JS `Date`s — no conversion needed.
964
+ 11. **Next.js App Router:** place interactive kit components inside a `'use client'` component.
965
+ 12. **When unsure about a prop,** read `node_modules/@dgshahr/ui-kit/dist/<Component>/index.d.ts` — it is the source of truth; this guide may lag behind.
966
+
967
+ ---
968
+
969
+ ## Agent setup snippets
970
+
971
+ ### Reference-by-path (shortest)
972
+
973
+ Add one line to your agent instructions file:
974
+
975
+ ```md
976
+ This project uses @dgshahr/ui-kit. Before writing UI code, read node_modules/@dgshahr/ui-kit/INTEGRATION.md and follow its "Rules for AI agents".
977
+ ```
978
+
979
+ ### Generic block (AGENTS.md / CLAUDE.md / any agent)
980
+
981
+ ```md
982
+ ## UI components: @dgshahr/ui-kit
983
+
984
+ - Full reference: node_modules/@dgshahr/ui-kit/INTEGRATION.md (read it before building UI).
985
+ - Always use kit components (Button, Input, Select, Datepicker, Timepicker, Drawer, Tabs, Table, Tooltip, Badge, Alert, Pagination, …) instead of custom ones.
986
+ - Imports: `import { X } from '@dgshahr/ui-kit'` or subpath `@dgshahr/ui-kit/X`; form components are `@dgshahr/ui-kit/Form/X`. Never import from dist/ internals.
987
+ - Styles are bundled: do not configure Tailwind/PostCSS for the kit; never use `dgsuikit:` classes in app code.
988
+ - Use `variant`/`color`/`size` props for looks; use `className`/`*ClassName` props for layout tweaks.
989
+ - Theme colors only via CSS vars `--dgs-color-{palette}-{shade}: r g b` (space-separated RGB).
990
+ - Text fields default to RTL; pass `dir="ltr"` for emails/URLs/numbers.
991
+ - Datepicker is Jalali but uses plain JS Date values.
992
+ - Next.js App Router: interactive kit components go inside 'use client' files.
993
+ - Unsure about a prop? Check node_modules/@dgshahr/ui-kit/dist/<Component>/index.d.ts.
994
+ ```
995
+
996
+ ### Claude Code — `CLAUDE.md`
997
+
998
+ Paste the generic block into the project's `CLAUDE.md` (repo root). Alternatively import the full guide so it is always loaded:
999
+
1000
+ ```md
1001
+ @node_modules/@dgshahr/ui-kit/INTEGRATION.md
1002
+ ```
1003
+
1004
+ ### Cursor — `.cursor/rules/dgshahr-ui-kit.mdc`
1005
+
1006
+ ```md
1007
+ ---
1008
+ description: Use @dgshahr/ui-kit components for all UI
1009
+ globs: ['**/*.tsx', '**/*.jsx']
1010
+ alwaysApply: false
1011
+ ---
1012
+
1013
+ <paste the generic block here>
1014
+ ```
1015
+
1016
+ ### GitHub Copilot — `.github/copilot-instructions.md`
1017
+
1018
+ Paste the generic block into `.github/copilot-instructions.md`. For path-scoped rules use `.github/instructions/ui-kit.instructions.md` with:
1019
+
1020
+ ```md
1021
+ ---
1022
+ applyTo: '**/*.tsx,**/*.jsx'
1023
+ ---
1024
+
1025
+ <paste the generic block here>
1026
+ ```
1027
+
1028
+ ### Windsurf — `.windsurfrules`
1029
+
1030
+ Paste the generic block into `.windsurfrules` at the repo root (or `.windsurf/rules/ui-kit.md`).
1031
+
1032
+ ### Other agents (Codex, Gemini CLI, Aider, …)
1033
+
1034
+ Paste the generic block into `AGENTS.md` (Codex and many others), `GEMINI.md` (Gemini CLI), or the tool's conventions file.