@ratio-ui/core 0.2.0 → 0.3.0
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.
- package/dist/catalogue.json +1091 -10
- package/dist/components/alert/Alert.d.ts +18 -0
- package/dist/components/alert/Alert.js +67 -0
- package/dist/components/alert/index.d.ts +2 -0
- package/dist/components/alert/index.js +1 -0
- package/dist/components/alert-dialog/AlertDialog.d.ts +48 -0
- package/dist/components/alert-dialog/AlertDialog.js +76 -0
- package/dist/components/alert-dialog/index.d.ts +2 -0
- package/dist/components/alert-dialog/index.js +1 -0
- package/dist/components/app-shell/AppShell.js +1 -1
- package/dist/components/calendar/Calendar.d.ts +20 -0
- package/dist/components/calendar/Calendar.js +119 -0
- package/dist/components/calendar/index.d.ts +2 -0
- package/dist/components/calendar/index.js +1 -0
- package/dist/components/checkbox-list/CheckboxList.d.ts +36 -0
- package/dist/components/checkbox-list/CheckboxList.js +93 -0
- package/dist/components/checkbox-list/index.d.ts +2 -0
- package/dist/components/checkbox-list/index.js +1 -0
- package/dist/components/collapsible/Collapsible.d.ts +24 -0
- package/dist/components/collapsible/Collapsible.js +58 -0
- package/dist/components/collapsible/index.d.ts +2 -0
- package/dist/components/collapsible/index.js +1 -0
- package/dist/components/data-table/DataTable.js +1 -1
- package/dist/components/date-picker/DatePicker.d.ts +33 -0
- package/dist/components/date-picker/DatePicker.js +104 -0
- package/dist/components/date-picker/index.d.ts +2 -0
- package/dist/components/date-picker/index.js +1 -0
- package/dist/components/date-range-picker/DateRangePicker.d.ts +39 -0
- package/dist/components/date-range-picker/DateRangePicker.js +142 -0
- package/dist/components/date-range-picker/index.d.ts +2 -0
- package/dist/components/date-range-picker/index.js +1 -0
- package/dist/components/field/Field.d.ts +35 -0
- package/dist/components/field/Field.js +67 -0
- package/dist/components/field/Label.d.ts +8 -0
- package/dist/components/field/Label.js +13 -0
- package/dist/components/field/index.d.ts +3 -0
- package/dist/components/field/index.js +3 -0
- package/dist/components/filter-tabs/FilterTabs.js +1 -1
- package/dist/components/global-search/GlobalSearch.js +1 -1
- package/dist/components/icon/registry.d.ts +2 -2
- package/dist/components/icon/registry.js +5 -1
- package/dist/components/input-group/InputGroup.js +1 -1
- package/dist/components/link/Link.d.ts +22 -0
- package/dist/components/link/Link.js +31 -0
- package/dist/components/link/index.d.ts +2 -0
- package/dist/components/link/index.js +1 -0
- package/dist/components/media-grid/MediaGrid.d.ts +49 -0
- package/dist/components/media-grid/MediaGrid.js +303 -0
- package/dist/components/media-grid/index.d.ts +2 -0
- package/dist/components/media-grid/index.js +1 -0
- package/dist/components/money-input/MoneyInput.d.ts +30 -0
- package/dist/components/money-input/MoneyInput.js +72 -0
- package/dist/components/money-input/index.d.ts +2 -0
- package/dist/components/money-input/index.js +1 -0
- package/dist/components/page-header/PageHeader.js +1 -1
- package/dist/components/save-bar/SaveBar.d.ts +27 -0
- package/dist/components/save-bar/SaveBar.js +37 -0
- package/dist/components/save-bar/index.d.ts +2 -0
- package/dist/components/save-bar/index.js +1 -0
- package/dist/components/search-field/SearchField.js +1 -1
- package/dist/components/select/Select.d.ts +40 -0
- package/dist/components/select/Select.js +84 -0
- package/dist/components/select/index.d.ts +2 -0
- package/dist/components/select/index.js +1 -0
- package/dist/components/side-nav/SideNav.js +3 -3
- package/dist/components/summary-chips/SummaryChips.d.ts +17 -0
- package/dist/components/summary-chips/SummaryChips.js +19 -0
- package/dist/components/summary-chips/index.d.ts +2 -0
- package/dist/components/summary-chips/index.js +1 -0
- package/dist/components/switch/Switch.d.ts +10 -0
- package/dist/components/switch/Switch.js +20 -0
- package/dist/components/switch/index.d.ts +2 -0
- package/dist/components/switch/index.js +1 -0
- package/dist/components/table/Table.js +1 -1
- package/dist/components/tag-input/TagInput.d.ts +44 -0
- package/dist/components/tag-input/TagInput.js +102 -0
- package/dist/components/tag-input/index.d.ts +2 -0
- package/dist/components/tag-input/index.js +1 -0
- package/dist/components/textarea/Textarea.d.ts +15 -0
- package/dist/components/textarea/Textarea.js +21 -0
- package/dist/components/textarea/index.d.ts +2 -0
- package/dist/components/textarea/index.js +1 -0
- package/dist/components/top-bar/StoreSwitcher.js +1 -1
- package/dist/components/top-bar/TopBar.js +2 -2
- package/dist/components/unit-input/UnitInput.d.ts +33 -0
- package/dist/components/unit-input/UnitInput.js +47 -0
- package/dist/components/unit-input/index.d.ts +2 -0
- package/dist/components/unit-input/index.js +1 -0
- package/dist/index.d.ts +43 -6
- package/dist/index.js +26 -7
- package/dist/lib/cn.js +7 -1
- package/dist/lib/format.d.ts +65 -4
- package/dist/lib/format.js +163 -6
- package/dist/styles.css +1 -1
- package/package.json +78 -1
package/dist/catalogue.json
CHANGED
|
@@ -1,6 +1,146 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.3.0",
|
|
3
3
|
"components": [
|
|
4
|
+
{
|
|
5
|
+
"name": "Alert",
|
|
6
|
+
"import": "import { Alert } from '@ratio-ui/core'",
|
|
7
|
+
"description": "A message that stays in the page: a tone glyph, an optional title and description, and an optional action.",
|
|
8
|
+
"props": [
|
|
9
|
+
{
|
|
10
|
+
"name": "tone",
|
|
11
|
+
"type": "\"critical\" | \"info\" | \"success\" | \"warning\"",
|
|
12
|
+
"required": false,
|
|
13
|
+
"default": "info",
|
|
14
|
+
"description": "The tone. Defaults to info."
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "title",
|
|
18
|
+
"type": "ReactNode",
|
|
19
|
+
"required": false,
|
|
20
|
+
"description": "An optional bold first line."
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "description",
|
|
24
|
+
"type": "ReactNode",
|
|
25
|
+
"required": false,
|
|
26
|
+
"description": "An optional second line."
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "action",
|
|
30
|
+
"type": "ReactNode",
|
|
31
|
+
"required": false,
|
|
32
|
+
"description": "An optional action on the right, usually one Button."
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "ref",
|
|
36
|
+
"type": "Ref<HTMLDivElement>",
|
|
37
|
+
"required": false,
|
|
38
|
+
"description": "Receives the rendered div."
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"usage": {
|
|
42
|
+
"whenToUse": "- A message that sits in the page and stays until the cause is gone: a banner above a form, a notice in a card\n- Four tones: info, success, warning, critical (question 1 tokens: no fill, strong border, warning glyph)",
|
|
43
|
+
"whenNotToUse": "- A message that disappears by itself: use Toaster\n- A confirmation before a destructive step: use AlertDialog\n- A field error: say it in one clause under the field",
|
|
44
|
+
"example": "```tsx\n<Alert\n tone=\"critical\"\n title=\"Payment failed\"\n description=\"Try another method.\"\n action={<Button>Retry</Button>}\n/>\n```\n\nInfo and success have role status (polite); warning and critical have role alert (assertive)."
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "AlertDialog",
|
|
49
|
+
"import": "import { AlertDialog } from '@ratio-ui/core'",
|
|
50
|
+
"description": "The root of a confirmation. It holds the open state and renders nothing itself. Pass `open` and `onOpenChange` to control it, or `defaultOpen` to leave it uncontrolled. Escape closes it; a click outside does not.",
|
|
51
|
+
"props": [],
|
|
52
|
+
"usage": {
|
|
53
|
+
"whenToUse": "- A confirm step before deleting something, or before a money action such as a refund\n- An answer that must be given: Escape closes it, a click outside does not\n- A short question that fits in 480px: the panel is fixed at that width, with a ring outline and no scrim",
|
|
54
|
+
"whenNotToUse": "- A form or any input: use Dialog\n- A message after an action: use toast()\n- A reversible action: do it and offer undo instead",
|
|
55
|
+
"example": "```tsx\n<AlertDialog>\n <AlertDialogTrigger>Delete product</AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Delete this product?</AlertDialogTitle>\n <AlertDialogDescription>It leaves the storefront at once.</AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction>Delete</AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n</AlertDialog>\n```\n\n- `AlertDialogAction` is the Button's destructive variant and closes the dialog after `onClick` runs. Pass `variant=\"main\"` for a non-destructive confirmation such as a refund. For an async action that must stay open until it finishes, control the dialog with `open` and `onOpenChange`.\n- `AlertDialogCancel` is the secondary Button and closes the dialog.\n- Name the action with the verb (\"Delete\", \"Refund\"), never \"OK\". Put the amount in the title for money actions, formatted with the format helpers."
|
|
56
|
+
},
|
|
57
|
+
"parts": [
|
|
58
|
+
{
|
|
59
|
+
"name": "AlertDialogAction",
|
|
60
|
+
"import": "import { AlertDialogAction } from '@ratio-ui/core'",
|
|
61
|
+
"description": "The confirming button. It is the Button's destructive variant and closes the dialog after its onClick runs.",
|
|
62
|
+
"props": [
|
|
63
|
+
{
|
|
64
|
+
"name": "variant",
|
|
65
|
+
"type": "\"destructive\" | \"main\"",
|
|
66
|
+
"required": false,
|
|
67
|
+
"default": "destructive",
|
|
68
|
+
"description": "The Button look. Defaults to destructive; use main for a confirmation that deletes nothing."
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"name": "AlertDialogCancel",
|
|
74
|
+
"import": "import { AlertDialogCancel } from '@ratio-ui/core'",
|
|
75
|
+
"description": "The secondary button that closes the dialog without doing anything.",
|
|
76
|
+
"props": []
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"name": "AlertDialogContent",
|
|
80
|
+
"import": "import { AlertDialogContent } from '@ratio-ui/core'",
|
|
81
|
+
"description": "The panel: 480px wide, white, drawn with the ring outline and no shadow, with no scrim behind it. Put AlertDialogHeader and AlertDialogFooter inside.",
|
|
82
|
+
"props": [
|
|
83
|
+
{
|
|
84
|
+
"name": "render",
|
|
85
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogPopupState>",
|
|
86
|
+
"required": false,
|
|
87
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "AlertDialogDescription",
|
|
93
|
+
"import": "import { AlertDialogDescription } from '@ratio-ui/core'",
|
|
94
|
+
"description": "What will happen, in subdued body text.",
|
|
95
|
+
"props": [
|
|
96
|
+
{
|
|
97
|
+
"name": "render",
|
|
98
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogDescriptionState>",
|
|
99
|
+
"required": false,
|
|
100
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"name": "AlertDialogFooter",
|
|
106
|
+
"import": "import { AlertDialogFooter } from '@ratio-ui/core'",
|
|
107
|
+
"description": "The row of actions at the bottom, aligned to the end.",
|
|
108
|
+
"props": []
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "AlertDialogHeader",
|
|
112
|
+
"import": "import { AlertDialogHeader } from '@ratio-ui/core'",
|
|
113
|
+
"description": "The title and description, stacked.",
|
|
114
|
+
"props": []
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "AlertDialogTitle",
|
|
118
|
+
"import": "import { AlertDialogTitle } from '@ratio-ui/core'",
|
|
119
|
+
"description": "The question, in the b4 style. It names the dialog for assistive technology.",
|
|
120
|
+
"props": [
|
|
121
|
+
{
|
|
122
|
+
"name": "render",
|
|
123
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTitleState>",
|
|
124
|
+
"required": false,
|
|
125
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "AlertDialogTrigger",
|
|
131
|
+
"import": "import { AlertDialogTrigger } from '@ratio-ui/core'",
|
|
132
|
+
"description": "The button that opens the confirmation.",
|
|
133
|
+
"props": [
|
|
134
|
+
{
|
|
135
|
+
"name": "render",
|
|
136
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, DialogTriggerState>",
|
|
137
|
+
"required": false,
|
|
138
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
]
|
|
143
|
+
},
|
|
4
144
|
{
|
|
5
145
|
"name": "AppShell",
|
|
6
146
|
"import": "import { AppShell } from '@ratio-ui/core'",
|
|
@@ -138,6 +278,17 @@
|
|
|
138
278
|
"example": "<Stack gap={8}>\n <Button><Icon name=\"plus\" />Add customer</Button>\n <Button variant=\"secondary\">Export</Button>\n <Button iconOnly variant=\"ghost\" aria-label=\"Add\"><Icon name=\"plus\" /></Button>\n</Stack>"
|
|
139
279
|
}
|
|
140
280
|
},
|
|
281
|
+
{
|
|
282
|
+
"name": "Calendar",
|
|
283
|
+
"import": "import { Calendar } from '@ratio-ui/core'",
|
|
284
|
+
"description": "A month grid to pick a day or a range of days, drawn by the design system: 28px days with a 6px radius, today in the accent ink, the selected day filled with the accent, a range as accent ends on a tinted band, disabled days at 50% and the days of the months around it in the muted ink. Every day is named in the format module's date order (28/10/2026). Arrow keys move between days and the previous and next buttons between months. It has no fill of its own, so it sits in a popover or a container as drawn.",
|
|
285
|
+
"props": [],
|
|
286
|
+
"usage": {
|
|
287
|
+
"whenToUse": "- Picking one day, such as a \"Best before\" date, inside a popover or a form: `mode=\"single\"`\n- Picking a range of days, such as an analytics period: `mode=\"range\"`, with `numberOfMonths={2}` for a wide range\n- Limiting the days that can be picked: `disabled` (for example `{ before: today }`), `startMonth` and `endMonth`",
|
|
288
|
+
"whenNotToUse": "- A date field people type into: use DatePicker or DateRangePicker, which open this calendar in a popover\n- Showing a date as text: write it with the format module, never with a calendar\n- Styling: Calendar takes no `className`, `classNames`, `style`, `components` or `formatters`; dates are written in the format module's order (28/10/2026)",
|
|
289
|
+
"example": "const [day, setDay] = useState<Date | undefined>()\n\n<Calendar mode=\"single\" selected={day} onSelect={setDay} disabled={{ before: new Date() }} />"
|
|
290
|
+
}
|
|
291
|
+
},
|
|
141
292
|
{
|
|
142
293
|
"name": "Card",
|
|
143
294
|
"import": "import { Card } from '@ratio-ui/core'",
|
|
@@ -200,6 +351,129 @@
|
|
|
200
351
|
"example": "<Checkbox aria-label=\"Select row\" checked={selected} onCheckedChange={setSelected} />"
|
|
201
352
|
}
|
|
202
353
|
},
|
|
354
|
+
{
|
|
355
|
+
"name": "CheckboxList",
|
|
356
|
+
"import": "import { CheckboxList } from '@ratio-ui/core'",
|
|
357
|
+
"description": "A titled list of checkboxes with the count of chosen items in the heading (\"4 of 6\"), an optional description under each label and an optional select-all.",
|
|
358
|
+
"props": [
|
|
359
|
+
{
|
|
360
|
+
"name": "title",
|
|
361
|
+
"type": "string",
|
|
362
|
+
"required": true,
|
|
363
|
+
"description": "The heading. The count of chosen items sits beside it."
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"name": "items",
|
|
367
|
+
"type": "CheckboxListItem[]",
|
|
368
|
+
"required": true,
|
|
369
|
+
"description": "The options."
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
"name": "value",
|
|
373
|
+
"type": "string[]",
|
|
374
|
+
"required": false,
|
|
375
|
+
"description": "The chosen values, when controlled."
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"name": "defaultValue",
|
|
379
|
+
"type": "string[]",
|
|
380
|
+
"required": false,
|
|
381
|
+
"description": "The chosen values to start with, when not controlled."
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"name": "onValueChange",
|
|
385
|
+
"type": "((value: string[]) => void)",
|
|
386
|
+
"required": false,
|
|
387
|
+
"description": "Called with the new list of chosen values."
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"name": "selectAll",
|
|
391
|
+
"type": "boolean",
|
|
392
|
+
"required": false,
|
|
393
|
+
"description": "Adds a \"Select all\" box that is mixed while only some are chosen."
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
"name": "selectAllLabel",
|
|
397
|
+
"type": "string",
|
|
398
|
+
"required": false,
|
|
399
|
+
"default": "Select all",
|
|
400
|
+
"description": "The label of the select-all box. Defaults to \"Select all\"."
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"name": "countLabel",
|
|
404
|
+
"type": "((chosen: string, total: string) => string)",
|
|
405
|
+
"required": false,
|
|
406
|
+
"default": "(c, t) => `${c} of ${t}`",
|
|
407
|
+
"description": "Writes the count in the heading from the chosen and total counts, already formatted. Defaults to \"4 of 6\"."
|
|
408
|
+
}
|
|
409
|
+
],
|
|
410
|
+
"usage": {
|
|
411
|
+
"whenToUse": "- A titled list where several options can be on and the heading should say how many (\"Sales channels 4 of 6\")\n- Add `selectAll` for a long list; it shows a mixed box while only some are on",
|
|
412
|
+
"whenNotToUse": "- One choice among several: use radio buttons or FilterTabs\n- A single yes or no: use Checkbox\n- Styling: CheckboxList takes no `className` and no `style`",
|
|
413
|
+
"example": "<CheckboxList title=\"Sales channels\" items={channels} value={on} onValueChange={setOn} selectAll />"
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"name": "Collapsible",
|
|
418
|
+
"import": "import { Collapsible } from '@ratio-ui/core'",
|
|
419
|
+
"description": "A section that opens and closes on its heading and, while closed, still shows its values as chips. The panel appears and disappears with no height animation.",
|
|
420
|
+
"props": [
|
|
421
|
+
{
|
|
422
|
+
"name": "title",
|
|
423
|
+
"type": "string",
|
|
424
|
+
"required": true,
|
|
425
|
+
"description": "The section heading, shown on the trigger."
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
"name": "summary",
|
|
429
|
+
"type": "readonly SummaryChip[]",
|
|
430
|
+
"required": false,
|
|
431
|
+
"description": "The values to show as chips while the section is closed."
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
"name": "open",
|
|
435
|
+
"type": "boolean",
|
|
436
|
+
"required": false,
|
|
437
|
+
"description": "Whether the section is open, when controlled."
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
"name": "defaultOpen",
|
|
441
|
+
"type": "boolean",
|
|
442
|
+
"required": false,
|
|
443
|
+
"default": "false",
|
|
444
|
+
"description": "Whether the section starts open, when uncontrolled. Defaults to closed."
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"name": "onOpenChange",
|
|
448
|
+
"type": "((open: boolean) => void)",
|
|
449
|
+
"required": false,
|
|
450
|
+
"description": "Called when the section opens or closes."
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
"name": "disabled",
|
|
454
|
+
"type": "boolean",
|
|
455
|
+
"required": false,
|
|
456
|
+
"description": "Stops the section from opening or closing."
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
"name": "children",
|
|
460
|
+
"type": "ReactNode",
|
|
461
|
+
"required": true,
|
|
462
|
+
"description": "The section's content, shown when open."
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
"name": "ref",
|
|
466
|
+
"type": "Ref<HTMLDivElement>",
|
|
467
|
+
"required": false,
|
|
468
|
+
"description": "Receives the rendered root."
|
|
469
|
+
}
|
|
470
|
+
],
|
|
471
|
+
"usage": {
|
|
472
|
+
"whenToUse": "- A form section that is rarely edited and can stay closed, such as the pricing details under the price\n- A closed section that must still show its values: pass `summary` and the chips show while it is closed",
|
|
473
|
+
"whenNotToUse": "- Content the person must see to finish the task: leave it open\n- Switching between peer views: use Tabs",
|
|
474
|
+
"example": "```tsx\n<Collapsible title=\"More pricing\" summary={[{ label: 'Cost price', value: '₹450.00' }, { label: 'HSN code', value: '6109' }]}>\n ...fields...\n</Collapsible>\n```\n\nThe panel appears and disappears at once; the library has no height animation."
|
|
475
|
+
}
|
|
476
|
+
},
|
|
203
477
|
{
|
|
204
478
|
"name": "DataTable",
|
|
205
479
|
"import": "import { DataTable } from '@ratio-ui/core'",
|
|
@@ -303,6 +577,130 @@
|
|
|
303
577
|
"example": "<DataTable\n aria-label=\"Products\"\n columns={[\n { id: 'name', header: 'Product', cell: (p) => p.name, essential: true, sortable: true, truncate: true },\n { id: 'stock', header: 'Stock', cell: (p) => p.stock, numeric: true },\n ]}\n data={products}\n getRowId={(p) => p.id}\n rowHref={(p) => `/products/${p.id}`}\n sort={sort}\n onSortChange={setSort}\n page={page}\n pageSize={20}\n total={84}\n onPageChange={setPage}\n empty=\"No products match this filter\"\n/>"
|
|
304
578
|
}
|
|
305
579
|
},
|
|
580
|
+
{
|
|
581
|
+
"name": "DatePicker",
|
|
582
|
+
"import": "import { DatePicker } from '@ratio-ui/core'",
|
|
583
|
+
"description": "A field that shows a day as DD/MM/YYYY, reads a typed date through the format module and opens a calendar in a popover from the button at its end. Text that is not a date is marked invalid when the field loses focus, and reports nothing. Under a name, a form submits the day as YYYY-MM-DD (empty when there is none), never the text on screen.",
|
|
584
|
+
"props": [
|
|
585
|
+
{
|
|
586
|
+
"name": "value",
|
|
587
|
+
"type": "Date | null",
|
|
588
|
+
"required": false,
|
|
589
|
+
"description": "The day, or null for an empty field. Pass it to control the field."
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
"name": "defaultValue",
|
|
593
|
+
"type": "Date | null",
|
|
594
|
+
"required": false,
|
|
595
|
+
"default": "null",
|
|
596
|
+
"description": "The starting day when the field is not controlled. Defaults to empty."
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
"name": "onValueChange",
|
|
600
|
+
"type": "((value: Date | null) => void)",
|
|
601
|
+
"required": false,
|
|
602
|
+
"description": "Called with the day when a typed date is complete or a day is picked, and with null when the text is cleared."
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
"name": "disabledDays",
|
|
606
|
+
"type": "Matcher | Matcher[]",
|
|
607
|
+
"required": false,
|
|
608
|
+
"description": "The days that cannot be picked in the calendar, for example { before: new Date() }."
|
|
609
|
+
},
|
|
610
|
+
{
|
|
611
|
+
"name": "startMonth",
|
|
612
|
+
"type": "Date",
|
|
613
|
+
"required": false,
|
|
614
|
+
"description": "The first month the calendar can show."
|
|
615
|
+
},
|
|
616
|
+
{
|
|
617
|
+
"name": "endMonth",
|
|
618
|
+
"type": "Date",
|
|
619
|
+
"required": false,
|
|
620
|
+
"description": "The last month the calendar can show."
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
"name": "size",
|
|
624
|
+
"type": "32 | 36",
|
|
625
|
+
"required": false,
|
|
626
|
+
"default": "36",
|
|
627
|
+
"description": "The height in px: 36 for forms, 32 for fields inside a table. Defaults to 36."
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"name": "ref",
|
|
631
|
+
"type": "Ref<HTMLInputElement>",
|
|
632
|
+
"required": false,
|
|
633
|
+
"description": "Receives the input element."
|
|
634
|
+
}
|
|
635
|
+
],
|
|
636
|
+
"usage": {
|
|
637
|
+
"whenToUse": "- One day a person types or picks, such as a \"Best before\" custom field: `value` and `onValueChange` take a `Date` (or null when empty)\n- A date inside a table: `size` 32\n- Limiting the days: `disabledDays` (for example `{ before: new Date() }`), `startMonth` and `endMonth`, which limit the calendar (a typed date is not checked against them)",
|
|
638
|
+
"whenNotToUse": "- A period of days, such as an analytics range: use DateRangePicker\n- A calendar shown on the page, not behind a field: use Calendar\n- Showing a date as text: write it with the format module (`formatDate`)\n- Custom classes or inline styles: DatePicker takes neither `className` nor `style`",
|
|
639
|
+
"example": "```tsx\nconst [bestBefore, setBestBefore] = useState<Date | null>(null)\n\n<DatePicker aria-label=\"Best before\" value={bestBefore} onValueChange={setBestBefore} />\n<DatePicker aria-label=\"Expiry\" size={32} aria-invalid aria-describedby=\"expiry-error\" />\n```\n\nThe field shows DD/MM/YYYY and reads typed dates through the format module (\"3/1/2026\" is 3 January). Text that is not a date turns the field invalid when it loses focus and is never reported.\n\nUnder a `name`, a form submits the committed day as `YYYY-MM-DD` (an empty string when the field is empty), not the text on screen: `<DatePicker name=\"bestBefore\" />` posts `bestBefore=2026-10-28`. A disabled field posts nothing."
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
"name": "DateRangePicker",
|
|
644
|
+
"import": "import { DateRangePicker } from '@ratio-ui/core'",
|
|
645
|
+
"description": "A field that shows a range as two DD/MM/YYYY days, reads a typed range through the format module and opens a calendar in a popover from the button at its end, for analytics periods. Pick the first day, then the last. Text that is not a range in order is marked invalid when the field loses focus, and reports nothing. Under a name, a form submits two fields, `name.from` and `name.to`, each as YYYY-MM-DD (empty when there is no range), never the text on screen.",
|
|
646
|
+
"props": [
|
|
647
|
+
{
|
|
648
|
+
"name": "value",
|
|
649
|
+
"type": "DateRangeValue | null",
|
|
650
|
+
"required": false,
|
|
651
|
+
"description": "The range, or null for an empty field. Pass it to control the field."
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
"name": "defaultValue",
|
|
655
|
+
"type": "DateRangeValue | null",
|
|
656
|
+
"required": false,
|
|
657
|
+
"default": "null",
|
|
658
|
+
"description": "The starting range when the field is not controlled. Defaults to empty."
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"name": "onValueChange",
|
|
662
|
+
"type": "((value: DateRangeValue | null) => void)",
|
|
663
|
+
"required": false,
|
|
664
|
+
"description": "Called with the range when a typed range is complete or two days are picked, and with null when the text is cleared."
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
"name": "disabledDays",
|
|
668
|
+
"type": "Matcher | Matcher[]",
|
|
669
|
+
"required": false,
|
|
670
|
+
"description": "The days that cannot be picked in the calendar, for example { after: new Date() } for an analytics period."
|
|
671
|
+
},
|
|
672
|
+
{
|
|
673
|
+
"name": "startMonth",
|
|
674
|
+
"type": "Date",
|
|
675
|
+
"required": false,
|
|
676
|
+
"description": "The first month the calendar can show."
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
"name": "endMonth",
|
|
680
|
+
"type": "Date",
|
|
681
|
+
"required": false,
|
|
682
|
+
"description": "The last month the calendar can show."
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
"name": "size",
|
|
686
|
+
"type": "32 | 36",
|
|
687
|
+
"required": false,
|
|
688
|
+
"default": "36",
|
|
689
|
+
"description": "The height in px: 36 for forms, 32 for fields inside a table. Defaults to 36."
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
"name": "ref",
|
|
693
|
+
"type": "Ref<HTMLInputElement>",
|
|
694
|
+
"required": false,
|
|
695
|
+
"description": "Receives the input element."
|
|
696
|
+
}
|
|
697
|
+
],
|
|
698
|
+
"usage": {
|
|
699
|
+
"whenToUse": "- A period of days a person types or picks, such as an analytics range: `value` and `onValueChange` take `{ from, to }` (or null when empty)\n- Limiting the days: `disabledDays` (for example `{ after: new Date() }` for reports), `startMonth` and `endMonth`, which limit the calendar (a typed range is not checked against them)\n- A range inside a table: `size` 32",
|
|
700
|
+
"whenNotToUse": "- One day: use DatePicker\n- A calendar shown on the page, not behind a field: use Calendar\n- Showing a range as text: write both days with the format module (`formatDate`)\n- Custom classes or inline styles: DateRangePicker takes neither `className` nor `style`",
|
|
701
|
+
"example": "```tsx\nconst [period, setPeriod] = useState<DateRangeValue | null>(null)\n\n<DateRangePicker aria-label=\"Period\" value={period} onValueChange={setPeriod} disabledDays={{ after: new Date() }} />\n```\n\nThe field shows `28/10/2026 – 03/11/2026`. Pick the first day, then the last (an earlier second day swaps them). A typed range with the end before the start, or one day only, turns the field invalid when it loses focus and is never reported.\n\nUnder a `name`, a form submits two fields, `name.from` and `name.to`, each the committed day as `YYYY-MM-DD` (empty strings when the field is empty), not the text on screen: `<DateRangePicker name=\"period\" />` posts `period.from=2026-10-28` and `period.to=2026-11-03`. A disabled field posts nothing."
|
|
702
|
+
}
|
|
703
|
+
},
|
|
306
704
|
{
|
|
307
705
|
"name": "Definition",
|
|
308
706
|
"import": "import { Definition } from '@ratio-ui/core'",
|
|
@@ -698,6 +1096,75 @@
|
|
|
698
1096
|
"example": "<EmptyState title=\"No products match this filter\" action={<Button>Clear filter</Button>} />"
|
|
699
1097
|
}
|
|
700
1098
|
},
|
|
1099
|
+
{
|
|
1100
|
+
"name": "Field",
|
|
1101
|
+
"import": "import { Field } from '@ratio-ui/core'",
|
|
1102
|
+
"description": "A form row: label, control, hint and error. It wires the label to the control by id, links the hint and error with aria-describedby, and sets aria-invalid when there is an error. The control keeps an id it already has.",
|
|
1103
|
+
"props": [
|
|
1104
|
+
{
|
|
1105
|
+
"name": "label",
|
|
1106
|
+
"type": "ReactNode",
|
|
1107
|
+
"required": true,
|
|
1108
|
+
"description": "The label text."
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
"name": "hint",
|
|
1112
|
+
"type": "ReactNode",
|
|
1113
|
+
"required": false,
|
|
1114
|
+
"description": "Help text under the control. An error replaces it."
|
|
1115
|
+
},
|
|
1116
|
+
{
|
|
1117
|
+
"name": "error",
|
|
1118
|
+
"type": "ReactNode",
|
|
1119
|
+
"required": false,
|
|
1120
|
+
"description": "The error message. It shows under the control beside the alert glyph and marks the control invalid."
|
|
1121
|
+
},
|
|
1122
|
+
{
|
|
1123
|
+
"name": "info",
|
|
1124
|
+
"type": "ReactNode",
|
|
1125
|
+
"required": false,
|
|
1126
|
+
"description": "An explanation of the field, opened from a small info icon beside the label by keyboard, touch or hover."
|
|
1127
|
+
},
|
|
1128
|
+
{
|
|
1129
|
+
"name": "required",
|
|
1130
|
+
"type": "boolean",
|
|
1131
|
+
"required": false,
|
|
1132
|
+
"description": "Shows a star after the label and marks the control aria-required."
|
|
1133
|
+
},
|
|
1134
|
+
{
|
|
1135
|
+
"name": "disabled",
|
|
1136
|
+
"type": "boolean",
|
|
1137
|
+
"required": false,
|
|
1138
|
+
"description": "Dims the label and disables the control."
|
|
1139
|
+
},
|
|
1140
|
+
{
|
|
1141
|
+
"name": "children",
|
|
1142
|
+
"type": "ReactElement<Record<string, unknown>, string | JSXElementConstructor<any>> | ((props: FieldControlProps) => ReactNode)",
|
|
1143
|
+
"required": true,
|
|
1144
|
+
"description": "The control: one element, such as Input, which gets an id, aria-describedby, aria-invalid, aria-required and disabled. When the control sits inside a wrapper such as InputGroup, pass a function instead and spread the props it receives onto the input itself."
|
|
1145
|
+
}
|
|
1146
|
+
],
|
|
1147
|
+
"usage": {
|
|
1148
|
+
"whenToUse": "- Every form row: a label, one control, and optional hint, error, info tooltip and required mark\n- Wiring: Field sets the control's id, aria-describedby, aria-invalid, aria-required and disabled, so you do not",
|
|
1149
|
+
"whenNotToUse": "- A heading for a group of controls: use a fieldset with a legend\n- A label with no control beside it: use Label alone, with `htmlFor`\n- Long help that must be read to finish the task: put it on the screen as the hint",
|
|
1150
|
+
"example": "```tsx\n<Field label=\"Title\" hint=\"Shown in search results\" error={errors.title} required>\n <Input />\n</Field>\n<Field label=\"MRP\" info=\"Maximum retail price, with tax\">\n <Input inputMode=\"decimal\" />\n</Field>\n```\n\nFor an input inside an InputGroup, pass a function child and spread its props onto the input: `<Field label=\"MRP\">{(props) => <InputGroup>…<InputGroupInput {...props} /></InputGroup>}</Field>`.\n\nFor a Select, which renders no element of its own, spread the props onto its trigger: `<Field label=\"GST rate\">{(props) => <Select items={rates}><SelectTrigger {...props}><SelectValue /></SelectTrigger><SelectContent>…</SelectContent></Select>}</Field>`.\n\nThe error shows beside the alert glyph in the error ink (question 1) and replaces the hint. Label is the same label as a separate part."
|
|
1151
|
+
},
|
|
1152
|
+
"parts": [
|
|
1153
|
+
{
|
|
1154
|
+
"name": "Label",
|
|
1155
|
+
"import": "import { Label } from '@ratio-ui/core'",
|
|
1156
|
+
"description": "The text that names a control, in the 12px medium label type. Point htmlFor at the control's id; Field does this for you.",
|
|
1157
|
+
"props": [
|
|
1158
|
+
{
|
|
1159
|
+
"name": "ref",
|
|
1160
|
+
"type": "Ref<HTMLLabelElement>",
|
|
1161
|
+
"required": false,
|
|
1162
|
+
"description": "Receives the label element."
|
|
1163
|
+
}
|
|
1164
|
+
]
|
|
1165
|
+
}
|
|
1166
|
+
]
|
|
1167
|
+
},
|
|
701
1168
|
{
|
|
702
1169
|
"name": "FilterTabs",
|
|
703
1170
|
"import": "import { FilterTabs } from '@ratio-ui/core'",
|
|
@@ -816,7 +1283,7 @@
|
|
|
816
1283
|
"props": [
|
|
817
1284
|
{
|
|
818
1285
|
"name": "name",
|
|
819
|
-
"type": "\"alert-triangle\" | \"check\" | \"chevron-left\" | \"chevron-right\" | \"export\" | \"import\" | \"info-circle\" | \"menu\" | \"more\" | \"nav-analytics\" | \"nav-apps\" | \"nav-caret-down\" | \"nav-chevron\" | \"nav-content\" | \"nav-customers\" | \"nav-discounts\" | \"nav-growth\" | \"nav-home\" | \"nav-markets\" | \"nav-orders\" | \"nav-product\" | \"nav-product-2\" | \"nav-sales-channels\" | \"nav-settings\" | \"nav-shortcut\" | \"plus\" | \"search\" | \"x\"",
|
|
1286
|
+
"type": "\"alert-triangle\" | \"calendar\" | \"check\" | \"chevron-left\" | \"chevron-right\" | \"export\" | \"import\" | \"info-circle\" | \"menu\" | \"more\" | \"nav-analytics\" | \"nav-apps\" | \"nav-caret-down\" | \"nav-chevron\" | \"nav-content\" | \"nav-customers\" | \"nav-discounts\" | \"nav-growth\" | \"nav-home\" | \"nav-markets\" | \"nav-orders\" | \"nav-product\" | \"nav-product-2\" | \"nav-sales-channels\" | \"nav-settings\" | \"nav-shortcut\" | \"plus\" | \"search\" | \"x\"",
|
|
820
1287
|
"required": true,
|
|
821
1288
|
"description": "Which icon to draw, by name."
|
|
822
1289
|
},
|
|
@@ -842,7 +1309,7 @@
|
|
|
842
1309
|
}
|
|
843
1310
|
],
|
|
844
1311
|
"usage": {
|
|
845
|
-
"whenToUse": "- A glyph beside a label inside a control: the plus on a main button, the magnifier in a search field, the export tray on a secondary button. Use size 12\n- The side navigation: the nav glyphs at size 16 (nav-home and nav-product are the design system's own; nav-orders, nav-customers, nav-growth, nav-discounts, nav-content, nav-markets, nav-analytics, nav-sales-channels, nav-apps and nav-settings are Tabler stand-ins for the dashboard's sections, question 7), and the disclosure caret (nav-chevron or nav-caret-down, one glyph under two names) at size 8\n- Pagination: chevron-left and chevron-right at size 8\n- A mark that Tabler supplies: check, x, alert-triangle, info-circle, import, more (three dots) and menu (the phone menu button). They are drawn with a 1.5px line at every size, so they sit beside the design system's own glyphs without looking heavier\n- Meaning that lives only in the icon: pass label. The icon is then an image that assistive technology announces under that name. Without a label it is decoration and is hidden from assistive technology\n- Colour: tone current, the default, takes the colour of the text around the icon. icon is the design system's icon ink, subdued is its subdued text ink and primary is the accent\n- Chevron geometry (design question 9): the design system has no vector for its pagination chevrons, only a 1.5px CSS caret in an 8px box, so chevron-left and chevron-right stand in. Each is the outline of a line 1.5 units wide with round ends, two legs at 45 degrees, each 2.5 units across and 2.5 down, through (2.75, 1.5), (5.25, 4) and (2.75, 6.5) in an 8 unit box. They scale like every filled glyph, so draw them at size 8, and expect them to be replaced when the designer sends real vectors",
|
|
1312
|
+
"whenToUse": "- A glyph beside a label inside a control: the plus on a main button, the magnifier in a search field, the export tray on a secondary button. Use size 12\n- The side navigation: the nav glyphs at size 16 (nav-home and nav-product are the design system's own; nav-orders, nav-customers, nav-growth, nav-discounts, nav-content, nav-markets, nav-analytics, nav-sales-channels, nav-apps and nav-settings are Tabler stand-ins for the dashboard's sections, question 7), and the disclosure caret (nav-chevron or nav-caret-down, one glyph under two names) at size 8\n- The date pickers' open button: calendar (Tabler) at size 12\n- Pagination: chevron-left and chevron-right at size 8\n- A mark that Tabler supplies: check, x, alert-triangle, info-circle, import, more (three dots) and menu (the phone menu button). They are drawn with a 1.5px line at every size, so they sit beside the design system's own glyphs without looking heavier\n- Meaning that lives only in the icon: pass label. The icon is then an image that assistive technology announces under that name. Without a label it is decoration and is hidden from assistive technology\n- Colour: tone current, the default, takes the colour of the text around the icon. icon is the design system's icon ink, subdued is its subdued text ink and primary is the accent\n- Chevron geometry (design question 9): the design system has no vector for its pagination chevrons, only a 1.5px CSS caret in an 8px box, so chevron-left and chevron-right stand in. Each is the outline of a line 1.5 units wide with round ends, two legs at 45 degrees, each 2.5 units across and 2.5 down, through (2.75, 1.5), (5.25, 4) and (2.75, 6.5) in an 8 unit box. They scale like every filled glyph, so draw them at size 8, and expect them to be replaced when the designer sends real vectors",
|
|
846
1313
|
"whenNotToUse": "- Decoration that adds no meaning. An icon next to text that already says the same thing is hidden from assistive technology, so leave the label off, and leave the icon out when it adds nothing\n- An icon the registry does not have. Components accept no className or style, and icons come from the registry only, so a new one is a registry entry: the design system's glyph first, Tabler for the rest\n- An icon-only control without a name. Pass label, or give the control its own accessible name\n- A size other than 8, 12 or 16, or a colour other than the four tones. There is no red, no destructive colour and no third accent: an error is marked with the alert-triangle glyph beside its message, not with a colour\n- Emoji, or unicode arrows and symbols, as icons. Inter's web subsets do not hold them and the design system bans them",
|
|
847
1314
|
"example": "import { Icon } from '@ratio-ui/core'\n\n// Beside text that names it: decoration, hidden from assistive technology\n<button type=\"button\">\n <Icon name=\"plus\" />\n Add product\n</button>\n\n// Alone: the label is the accessible name\n<Icon name=\"search\" tone=\"icon\" label=\"Search\" />\n\n// Pagination chevrons are drawn for an 8px box\n<Icon name=\"chevron-right\" size={8} />"
|
|
848
1315
|
}
|
|
@@ -1016,6 +1483,50 @@
|
|
|
1016
1483
|
}
|
|
1017
1484
|
]
|
|
1018
1485
|
},
|
|
1486
|
+
{
|
|
1487
|
+
"name": "Link",
|
|
1488
|
+
"import": "import { Link } from '@ratio-ui/core'",
|
|
1489
|
+
"description": "A text link to another page, such as \"← Products\" or \"View all variants →\". It is drawn by the app's LinkProvider, so a router navigates without a reload; without one it is a plain <a href>. The arrows are decoration and are hidden from screen readers.",
|
|
1490
|
+
"props": [
|
|
1491
|
+
{
|
|
1492
|
+
"name": "href",
|
|
1493
|
+
"type": "string",
|
|
1494
|
+
"required": true,
|
|
1495
|
+
"description": "Where the link goes."
|
|
1496
|
+
},
|
|
1497
|
+
{
|
|
1498
|
+
"name": "children",
|
|
1499
|
+
"type": "ReactNode",
|
|
1500
|
+
"required": true,
|
|
1501
|
+
"description": "The link text."
|
|
1502
|
+
},
|
|
1503
|
+
{
|
|
1504
|
+
"name": "back",
|
|
1505
|
+
"type": "boolean",
|
|
1506
|
+
"required": false,
|
|
1507
|
+
"default": "false",
|
|
1508
|
+
"description": "Shows a back arrow before the text, as in \"← Products\". Screen readers skip it."
|
|
1509
|
+
},
|
|
1510
|
+
{
|
|
1511
|
+
"name": "forward",
|
|
1512
|
+
"type": "boolean",
|
|
1513
|
+
"required": false,
|
|
1514
|
+
"default": "false",
|
|
1515
|
+
"description": "Shows a forward arrow after the text, as in \"View all variants →\". Screen readers skip it."
|
|
1516
|
+
},
|
|
1517
|
+
{
|
|
1518
|
+
"name": "ref",
|
|
1519
|
+
"type": "Ref<HTMLAnchorElement>",
|
|
1520
|
+
"required": false,
|
|
1521
|
+
"description": "Receives the anchor element."
|
|
1522
|
+
}
|
|
1523
|
+
],
|
|
1524
|
+
"usage": {
|
|
1525
|
+
"whenToUse": "- A text link to another page: \"← Products\", \"View all variants →\"\n- A back link in a detail page's body (the page header has its own back link)",
|
|
1526
|
+
"whenNotToUse": "- An action that changes something: use Button\n- A whole table row: use DataTable's `rowHref`\n- A navigation row in the side navigation: use SideNav",
|
|
1527
|
+
"example": "<Link href=\"/products\" back>Products</Link>\n<Link href=\"/products/blue-shirt/variants\" forward>View all variants</Link>"
|
|
1528
|
+
}
|
|
1529
|
+
},
|
|
1019
1530
|
{
|
|
1020
1531
|
"name": "LinkProvider",
|
|
1021
1532
|
"import": "import { LinkProvider } from '@ratio-ui/core'",
|
|
@@ -1040,6 +1551,93 @@
|
|
|
1040
1551
|
"example": "import { Link as RouterLink } from 'react-router-dom'\n\n<LinkProvider render={({ href, ...props }) => <RouterLink to={href} {...props} />}>\n <App />\n</LinkProvider>"
|
|
1041
1552
|
}
|
|
1042
1553
|
},
|
|
1554
|
+
{
|
|
1555
|
+
"name": "MediaGrid",
|
|
1556
|
+
"import": "import { MediaGrid } from '@ratio-ui/core'",
|
|
1557
|
+
"description": "The media of a product: a row of square thumbs with an add tile that opens the file picker and takes dropped files. Thumbs reorder by drag (pointer, touch or keyboard) and by the Move left, Move right and Make cover buttons, so no drag is needed. The first image is the cover and carries a badge. Uploads show a thin progress bar and failures an error under the thumb. Every move, cover change and removal is announced to screen readers.",
|
|
1558
|
+
"props": [
|
|
1559
|
+
{
|
|
1560
|
+
"name": "items",
|
|
1561
|
+
"type": "MediaGridItem[]",
|
|
1562
|
+
"required": true,
|
|
1563
|
+
"description": "The images in order. The first one is the cover."
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
"name": "onAdd",
|
|
1567
|
+
"type": "(files: File[]) => void",
|
|
1568
|
+
"required": true,
|
|
1569
|
+
"description": "Called with the files chosen in the add tile or dropped on the grid."
|
|
1570
|
+
},
|
|
1571
|
+
{
|
|
1572
|
+
"name": "onReorder",
|
|
1573
|
+
"type": "(ids: string[]) => void",
|
|
1574
|
+
"required": true,
|
|
1575
|
+
"description": "Called with every id in the new order after a drag, Move left, Move right or Make cover."
|
|
1576
|
+
},
|
|
1577
|
+
{
|
|
1578
|
+
"name": "onRemove",
|
|
1579
|
+
"type": "(id: string) => void",
|
|
1580
|
+
"required": true,
|
|
1581
|
+
"description": "Called with the id of the item to take off the grid."
|
|
1582
|
+
},
|
|
1583
|
+
{
|
|
1584
|
+
"name": "onMakeCover",
|
|
1585
|
+
"type": "((id: string) => void)",
|
|
1586
|
+
"required": false,
|
|
1587
|
+
"description": "Called with the id after Make cover has moved it first through onReorder, for an app that saves the cover on its own."
|
|
1588
|
+
},
|
|
1589
|
+
{
|
|
1590
|
+
"name": "accept",
|
|
1591
|
+
"type": "Accept",
|
|
1592
|
+
"required": false,
|
|
1593
|
+
"default": "{ 'image/*': [] }",
|
|
1594
|
+
"description": "The file types the add tile takes, as react-dropzone's accept map. Defaults to every image type."
|
|
1595
|
+
},
|
|
1596
|
+
{
|
|
1597
|
+
"name": "disabled",
|
|
1598
|
+
"type": "boolean",
|
|
1599
|
+
"required": false,
|
|
1600
|
+
"default": "false",
|
|
1601
|
+
"description": "Stops adding, dragging and every button."
|
|
1602
|
+
},
|
|
1603
|
+
{
|
|
1604
|
+
"name": "addLabel",
|
|
1605
|
+
"type": "string",
|
|
1606
|
+
"required": false,
|
|
1607
|
+
"default": "Add media",
|
|
1608
|
+
"description": "The accessible name of the add tile. Defaults to \"Add media\"."
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
"name": "id",
|
|
1612
|
+
"type": "string",
|
|
1613
|
+
"required": false,
|
|
1614
|
+
"description": "The id of the grid."
|
|
1615
|
+
},
|
|
1616
|
+
{
|
|
1617
|
+
"name": "aria-label",
|
|
1618
|
+
"type": "string",
|
|
1619
|
+
"required": false,
|
|
1620
|
+
"description": "The accessible name of the grid. Defaults to \"Media\" when there is no aria-labelledby."
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
"name": "aria-labelledby",
|
|
1624
|
+
"type": "string",
|
|
1625
|
+
"required": false,
|
|
1626
|
+
"description": "The id of the visible label that names the grid, such as a Field label."
|
|
1627
|
+
},
|
|
1628
|
+
{
|
|
1629
|
+
"name": "aria-describedby",
|
|
1630
|
+
"type": "string",
|
|
1631
|
+
"required": false,
|
|
1632
|
+
"description": "The id of help text for the grid."
|
|
1633
|
+
}
|
|
1634
|
+
],
|
|
1635
|
+
"usage": {
|
|
1636
|
+
"whenToUse": "- The images of a product or any ordered set of images, with an add tile that opens the file picker and takes dropped files\n- The app uploads: MediaGrid reports `onAdd(files)`, `onReorder(ids)`, `onRemove(id)` and `onMakeCover(id)`, and shows each item's `progress` (0 to 100) and `error`\n- The first image is the cover; Make cover moves an image first through `onReorder`, then calls `onMakeCover`\n- Images reorder by drag (pointer, touch or keyboard) and by the Move left and Move right buttons, so no drag is needed",
|
|
1637
|
+
"whenNotToUse": "- A single image such as a logo or an avatar: use Avatar or a single file input\n- Files that are not images in a visual order (documents, CSV imports): use a list\n- Remove has no confirm step, because the save bar's Discard brings an image back; confirm in `onRemove` with AlertDialog when the removal is final\n- Styling: MediaGrid takes no `className` and no `style`",
|
|
1638
|
+
"example": "<MediaGrid\n items={media}\n onAdd={(files) => upload(files)}\n onReorder={(ids) => setMedia(ids.map((id) => media.find((m) => m.id === id)!))}\n onRemove={(id) => setMedia(media.filter((m) => m.id !== id))}\n/>"
|
|
1639
|
+
}
|
|
1640
|
+
},
|
|
1043
1641
|
{
|
|
1044
1642
|
"name": "MetricStrip",
|
|
1045
1643
|
"import": "import { MetricStrip } from '@ratio-ui/core'",
|
|
@@ -1064,6 +1662,62 @@
|
|
|
1064
1662
|
"example": "<MetricStrip\n label=\"Product metrics\"\n segments={[\n {\n id: 'rate',\n title: 'Average sell-through rate',\n definition: 'Share of stock sold',\n value: '9.95%',\n },\n { id: 'days', title: 'Days of inventory remaining', value: null },\n { id: 'abc', title: 'ABC product analysis', value: 0, format: 'money' },\n ]}\n/>"
|
|
1065
1663
|
}
|
|
1066
1664
|
},
|
|
1665
|
+
{
|
|
1666
|
+
"name": "MoneyInput",
|
|
1667
|
+
"import": "import { MoneyInput } from '@ratio-ui/core'",
|
|
1668
|
+
"description": "A money field: the currency symbol before the amount, inside one ring. It takes and gives integer paise, shows the amount grouped as India groups it with two decimals (1,23,456.50) once the field loses focus, and reads a pasted amount written with the currency symbol or with either grouping. Under a name, a form submits paise.",
|
|
1669
|
+
"props": [
|
|
1670
|
+
{
|
|
1671
|
+
"name": "value",
|
|
1672
|
+
"type": "number | null",
|
|
1673
|
+
"required": false,
|
|
1674
|
+
"description": "The amount in integer paise (12345650 is 1,23,456 rupees and 50 paise), or null for an empty field. Pass it to control the field."
|
|
1675
|
+
},
|
|
1676
|
+
{
|
|
1677
|
+
"name": "defaultValue",
|
|
1678
|
+
"type": "number | null",
|
|
1679
|
+
"required": false,
|
|
1680
|
+
"default": "null",
|
|
1681
|
+
"description": "The starting amount in integer paise when the field is not controlled. Defaults to empty."
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
"name": "onValueChange",
|
|
1685
|
+
"type": "((paise: number | null) => void)",
|
|
1686
|
+
"required": false,
|
|
1687
|
+
"description": "Called with the amount in integer paise as it is typed, pasted or cleared (null when empty)."
|
|
1688
|
+
},
|
|
1689
|
+
{
|
|
1690
|
+
"name": "min",
|
|
1691
|
+
"type": "number",
|
|
1692
|
+
"required": false,
|
|
1693
|
+
"description": "The smallest amount in integer paise; the field moves a smaller one up to it on blur. Leave it out to allow negatives."
|
|
1694
|
+
},
|
|
1695
|
+
{
|
|
1696
|
+
"name": "max",
|
|
1697
|
+
"type": "number",
|
|
1698
|
+
"required": false,
|
|
1699
|
+
"description": "The largest amount in integer paise; the field moves a larger one down to it on blur."
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
"name": "size",
|
|
1703
|
+
"type": "32 | 36",
|
|
1704
|
+
"required": false,
|
|
1705
|
+
"default": "36",
|
|
1706
|
+
"description": "The height in px: 36 for forms, 32 for prices inside a table. Defaults to 36."
|
|
1707
|
+
},
|
|
1708
|
+
{
|
|
1709
|
+
"name": "ref",
|
|
1710
|
+
"type": "Ref<HTMLInputElement>",
|
|
1711
|
+
"required": false,
|
|
1712
|
+
"description": "Receives the input element."
|
|
1713
|
+
}
|
|
1714
|
+
],
|
|
1715
|
+
"usage": {
|
|
1716
|
+
"whenToUse": "- Any amount of money a person types: MRP, selling price, cost price, variant prices\n- Values stored as integer paise: `value` and `onValueChange` take and give paise, and under a `name` a form submits paise\n- A price inside a table: `size` 32\n- Amounts people paste from a spreadsheet or another page: a pasted amount with the rupee sign or either grouping is read as paise",
|
|
1717
|
+
"whenNotToUse": "- Showing an amount that is not edited: write it with the format module (`formatPaise`) in text\n- A number that is not money, such as a weight or a length: use UnitInput\n- A count of items: use Input with `inputMode=\"numeric\"`\n- Custom classes or inline styles: MoneyInput takes neither `className` nor `style`",
|
|
1718
|
+
"example": "const [mrp, setMrp] = useState<number | null>(129900)\n\n<MoneyInput aria-label=\"MRP\" value={mrp} onValueChange={setMrp} min={0} />\n<MoneyInput aria-label=\"Price of L\" size={32} defaultValue={44900} name=\"price\" />\n<MoneyInput aria-label=\"Selling price\" aria-invalid aria-describedby=\"price-error\" />"
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1067
1721
|
{
|
|
1068
1722
|
"name": "PageHeader",
|
|
1069
1723
|
"import": "import { PageHeader } from '@ratio-ui/core'",
|
|
@@ -1216,12 +1870,6 @@
|
|
|
1216
1870
|
"import": "import { PopoverTrigger } from '@ratio-ui/core'",
|
|
1217
1871
|
"description": "The element that opens the popover on click or Enter. It renders a button unless render says otherwise.",
|
|
1218
1872
|
"props": [
|
|
1219
|
-
{
|
|
1220
|
-
"name": "render",
|
|
1221
|
-
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>",
|
|
1222
|
-
"required": false,
|
|
1223
|
-
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
1224
|
-
},
|
|
1225
1873
|
{
|
|
1226
1874
|
"name": "handle",
|
|
1227
1875
|
"type": "PopoverHandle<unknown>",
|
|
@@ -1234,6 +1882,12 @@
|
|
|
1234
1882
|
"required": false,
|
|
1235
1883
|
"description": "A payload to pass to the popover when it is opened."
|
|
1236
1884
|
},
|
|
1885
|
+
{
|
|
1886
|
+
"name": "render",
|
|
1887
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, PopoverTriggerState>",
|
|
1888
|
+
"required": false,
|
|
1889
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
1890
|
+
},
|
|
1237
1891
|
{
|
|
1238
1892
|
"name": "delay",
|
|
1239
1893
|
"type": "number",
|
|
@@ -1257,7 +1911,78 @@
|
|
|
1257
1911
|
}
|
|
1258
1912
|
]
|
|
1259
1913
|
}
|
|
1260
|
-
]
|
|
1914
|
+
]
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
"name": "SaveBar",
|
|
1918
|
+
"import": "import { SaveBar } from '@ratio-ui/core'",
|
|
1919
|
+
"description": "The bar that appears under the top bar when a form is dirty: a message, Discard and Save. It renders in flow, so the page (AppShell) decides where it sits. While saving, Save is disabled; Discard only calls onDiscard.",
|
|
1920
|
+
"props": [
|
|
1921
|
+
{
|
|
1922
|
+
"name": "dirty",
|
|
1923
|
+
"type": "boolean",
|
|
1924
|
+
"required": true,
|
|
1925
|
+
"description": "Whether the form has unsaved changes. The bar renders nothing when false."
|
|
1926
|
+
},
|
|
1927
|
+
{
|
|
1928
|
+
"name": "saving",
|
|
1929
|
+
"type": "boolean",
|
|
1930
|
+
"required": false,
|
|
1931
|
+
"default": "false",
|
|
1932
|
+
"description": "True while the save is running: Save is disabled and reads the saving label."
|
|
1933
|
+
},
|
|
1934
|
+
{
|
|
1935
|
+
"name": "onSave",
|
|
1936
|
+
"type": "() => void",
|
|
1937
|
+
"required": true,
|
|
1938
|
+
"description": "Called by Save."
|
|
1939
|
+
},
|
|
1940
|
+
{
|
|
1941
|
+
"name": "onDiscard",
|
|
1942
|
+
"type": "() => void",
|
|
1943
|
+
"required": true,
|
|
1944
|
+
"description": "Called by Discard. The bar asks nothing itself: confirm in the caller if you need to."
|
|
1945
|
+
},
|
|
1946
|
+
{
|
|
1947
|
+
"name": "message",
|
|
1948
|
+
"type": "ReactNode",
|
|
1949
|
+
"required": false,
|
|
1950
|
+
"default": "Unsaved changes",
|
|
1951
|
+
"description": "The message. Defaults to \"Unsaved changes\"."
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
"name": "saveLabel",
|
|
1955
|
+
"type": "ReactNode",
|
|
1956
|
+
"required": false,
|
|
1957
|
+
"default": "Save",
|
|
1958
|
+
"description": "The Save label. Defaults to \"Save\"."
|
|
1959
|
+
},
|
|
1960
|
+
{
|
|
1961
|
+
"name": "savingLabel",
|
|
1962
|
+
"type": "ReactNode",
|
|
1963
|
+
"required": false,
|
|
1964
|
+
"default": "Saving…",
|
|
1965
|
+
"description": "The Save label while saving. Defaults to \"Saving…\"."
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
"name": "discardLabel",
|
|
1969
|
+
"type": "ReactNode",
|
|
1970
|
+
"required": false,
|
|
1971
|
+
"default": "Discard",
|
|
1972
|
+
"description": "The Discard label. Defaults to \"Discard\"."
|
|
1973
|
+
},
|
|
1974
|
+
{
|
|
1975
|
+
"name": "ref",
|
|
1976
|
+
"type": "Ref<HTMLDivElement>",
|
|
1977
|
+
"required": false,
|
|
1978
|
+
"description": "Receives the rendered div."
|
|
1979
|
+
}
|
|
1980
|
+
],
|
|
1981
|
+
"usage": {
|
|
1982
|
+
"whenToUse": "- Under the top bar of a form page, when the form has unsaved changes: \"Unsaved changes\", Discard, Save\n- Drive `dirty` from the form's dirty state and `saving` from the pending save",
|
|
1983
|
+
"whenNotToUse": "- A confirmation: Discard only calls `onDiscard`; open an AlertDialog yourself if the loss needs confirming\n- Per-field saving: save on change or use the field's own action",
|
|
1984
|
+
"example": "```tsx\n<SaveBar dirty={form.isDirty} saving={form.isSaving} onSave={form.save} onDiscard={form.reset} />\n```\n\nIt renders in flow and nothing when not dirty; the app shell decides where it sits. While saving, Save is disabled."
|
|
1985
|
+
}
|
|
1261
1986
|
},
|
|
1262
1987
|
{
|
|
1263
1988
|
"name": "SearchField",
|
|
@@ -1309,6 +2034,117 @@
|
|
|
1309
2034
|
"example": "<SearchField label=\"Search products\" placeholder=\"Search by name, SKU\" value={query} onValueChange={setQuery} />"
|
|
1310
2035
|
}
|
|
1311
2036
|
},
|
|
2037
|
+
{
|
|
2038
|
+
"name": "Select",
|
|
2039
|
+
"import": "import { Select } from '@ratio-ui/core'",
|
|
2040
|
+
"description": "A choice from a fixed list. Pass items ({ label, value }[]) so the trigger shows the label of the chosen value. Put a SelectTrigger and a SelectContent inside it.",
|
|
2041
|
+
"props": [],
|
|
2042
|
+
"usage": {
|
|
2043
|
+
"whenToUse": "- A choice from a short, fixed list in a form, such as a GST rate (0, 5, 12, 18, 28%), a return window or a status\n- A field in a table cell: `size={32}` on the trigger\n- A form row with a label, hint, error or required mark: put the Select inside a Field with a function child (see below)",
|
|
2044
|
+
"whenNotToUse": "- A long list, or one the user searches: use a combobox\n- Free text or several values (tags): use Input or TagInput\n- A menu of actions: use DropdownMenu\n- Custom classes or inline styles: no part takes `className` or `style`",
|
|
2045
|
+
"example": "```tsx\nconst rates = [\n { label: '0%', value: '0' },\n { label: '18%', value: '18' },\n]\n\n<Select items={rates} defaultValue=\"18\">\n <SelectTrigger aria-label=\"GST rate\">\n <SelectValue placeholder=\"Choose a rate\" />\n </SelectTrigger>\n <SelectContent>\n <SelectGroup>\n <SelectLabel>Rates</SelectLabel>\n <SelectItem value=\"0\">0%</SelectItem>\n <SelectItem value=\"18\">18%</SelectItem>\n </SelectGroup>\n </SelectContent>\n</Select>\n```\n\nPass `items` to `Select` so the trigger shows the label, not the raw value."
|
|
2046
|
+
},
|
|
2047
|
+
"parts": [
|
|
2048
|
+
{
|
|
2049
|
+
"name": "SelectContent",
|
|
2050
|
+
"import": "import { SelectContent } from '@ratio-ui/core'",
|
|
2051
|
+
"description": "The list: the popover look (8px radius, outline, no shadow, 6px 0 padding), as wide as the trigger. It opens below the trigger.",
|
|
2052
|
+
"props": [
|
|
2053
|
+
{
|
|
2054
|
+
"name": "render",
|
|
2055
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectPopupState>",
|
|
2056
|
+
"required": false,
|
|
2057
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2058
|
+
}
|
|
2059
|
+
]
|
|
2060
|
+
},
|
|
2061
|
+
{
|
|
2062
|
+
"name": "SelectGroup",
|
|
2063
|
+
"import": "import { SelectGroup } from '@ratio-ui/core'",
|
|
2064
|
+
"description": "Groups related options under a SelectLabel.",
|
|
2065
|
+
"props": [
|
|
2066
|
+
{
|
|
2067
|
+
"name": "render",
|
|
2068
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectGroupState>",
|
|
2069
|
+
"required": false,
|
|
2070
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2071
|
+
}
|
|
2072
|
+
]
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
"name": "SelectItem",
|
|
2076
|
+
"import": "import { SelectItem } from '@ratio-ui/core'",
|
|
2077
|
+
"description": "One option. The highlighted one has the accent background, the chosen one a check at its end, a disabled one is dimmed and cannot be chosen.",
|
|
2078
|
+
"props": [
|
|
2079
|
+
{
|
|
2080
|
+
"name": "render",
|
|
2081
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectItemState>",
|
|
2082
|
+
"required": false,
|
|
2083
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2084
|
+
}
|
|
2085
|
+
]
|
|
2086
|
+
},
|
|
2087
|
+
{
|
|
2088
|
+
"name": "SelectLabel",
|
|
2089
|
+
"import": "import { SelectLabel } from '@ratio-ui/core'",
|
|
2090
|
+
"description": "The heading of a group, in the muted colour.",
|
|
2091
|
+
"props": [
|
|
2092
|
+
{
|
|
2093
|
+
"name": "render",
|
|
2094
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectGroupLabelState>",
|
|
2095
|
+
"required": false,
|
|
2096
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2097
|
+
}
|
|
2098
|
+
]
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
"name": "SelectSeparator",
|
|
2102
|
+
"import": "import { SelectSeparator } from '@ratio-ui/core'",
|
|
2103
|
+
"description": "A hairline between groups.",
|
|
2104
|
+
"props": [
|
|
2105
|
+
{
|
|
2106
|
+
"name": "render",
|
|
2107
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectSeparatorState>",
|
|
2108
|
+
"required": false,
|
|
2109
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2110
|
+
}
|
|
2111
|
+
]
|
|
2112
|
+
},
|
|
2113
|
+
{
|
|
2114
|
+
"name": "SelectTrigger",
|
|
2115
|
+
"import": "import { SelectTrigger } from '@ratio-ui/core'",
|
|
2116
|
+
"description": "The closed field: the chosen value (or the placeholder) and a chevron at the right. Put a SelectValue inside it.",
|
|
2117
|
+
"props": [
|
|
2118
|
+
{
|
|
2119
|
+
"name": "render",
|
|
2120
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectTriggerState>",
|
|
2121
|
+
"required": false,
|
|
2122
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2123
|
+
},
|
|
2124
|
+
{
|
|
2125
|
+
"name": "size",
|
|
2126
|
+
"type": "32 | 36",
|
|
2127
|
+
"required": false,
|
|
2128
|
+
"default": "36",
|
|
2129
|
+
"description": "The height in px: 36 for forms, 32 inside a table. Defaults to 36."
|
|
2130
|
+
}
|
|
2131
|
+
]
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
"name": "SelectValue",
|
|
2135
|
+
"import": "import { SelectValue } from '@ratio-ui/core'",
|
|
2136
|
+
"description": "Shows the label of the chosen option inside the trigger, or the placeholder while nothing is chosen.",
|
|
2137
|
+
"props": [
|
|
2138
|
+
{
|
|
2139
|
+
"name": "render",
|
|
2140
|
+
"type": "ReactElement<unknown, string | JSXElementConstructor<any>> | ComponentRenderFn<HTMLProps, SelectValueState>",
|
|
2141
|
+
"required": false,
|
|
2142
|
+
"description": "Allows you to replace the component's HTML element with a different tag, or compose it with another component.\n\nAccepts a `ReactElement` or a function that returns the element to render."
|
|
2143
|
+
}
|
|
2144
|
+
]
|
|
2145
|
+
}
|
|
2146
|
+
]
|
|
2147
|
+
},
|
|
1312
2148
|
{
|
|
1313
2149
|
"name": "SideNav",
|
|
1314
2150
|
"import": "import { SideNav } from '@ratio-ui/core'",
|
|
@@ -1470,6 +2306,41 @@
|
|
|
1470
2306
|
"example": "<StatusPill tone=\"success\">Active</StatusPill>"
|
|
1471
2307
|
}
|
|
1472
2308
|
},
|
|
2309
|
+
{
|
|
2310
|
+
"name": "SummaryChips",
|
|
2311
|
+
"import": "import { SummaryChips } from '@ratio-ui/core'",
|
|
2312
|
+
"description": "A row of 20px chips that summarise values, such as the ones a collapsed section still shows.",
|
|
2313
|
+
"props": [
|
|
2314
|
+
{
|
|
2315
|
+
"name": "items",
|
|
2316
|
+
"type": "readonly SummaryChip[]",
|
|
2317
|
+
"required": true,
|
|
2318
|
+
"description": "The chips, in order. Nothing is rendered when empty."
|
|
2319
|
+
},
|
|
2320
|
+
{
|
|
2321
|
+
"name": "ref",
|
|
2322
|
+
"type": "Ref<HTMLUListElement>",
|
|
2323
|
+
"required": false,
|
|
2324
|
+
"description": "Receives the rendered list."
|
|
2325
|
+
}
|
|
2326
|
+
],
|
|
2327
|
+
"usage": {
|
|
2328
|
+
"whenToUse": "- A collapsed section that still shows its values: \"Cost price · HSN code · Includes GST Yes\"\n- A short read-only summary of a record's settings",
|
|
2329
|
+
"whenNotToUse": "- Values the person can edit or remove: use a tag input\n- A status of a row: use StatusPill",
|
|
2330
|
+
"example": "<SummaryChips items={[{ label: 'Cost price', value: '₹450.00' }, { label: 'Includes GST', value: 'Yes' }]} />"
|
|
2331
|
+
}
|
|
2332
|
+
},
|
|
2333
|
+
{
|
|
2334
|
+
"name": "Switch",
|
|
2335
|
+
"import": "import { Switch } from '@ratio-ui/core'",
|
|
2336
|
+
"description": "An on/off switch, 32px by 18px. Off it is drawn with the control hairline; on it is filled in the primary colour. In forced-colours mode the thumb keeps a system-colour outline, and its side shows the state. The thumb jumps to the other end with no slide, and colours fade over 120ms.",
|
|
2337
|
+
"props": [],
|
|
2338
|
+
"usage": {
|
|
2339
|
+
"whenToUse": "- An on/off setting that takes effect as soon as it changes, such as \"Inventory tracked\" or \"Cash on delivery\"\n- Give it an `aria-label`, or a label that points to it",
|
|
2340
|
+
"whenNotToUse": "- A choice that is sent with a form and several others: use Checkbox\n- Custom classes or inline styles: Switch takes no `className` and no `style`",
|
|
2341
|
+
"example": "<Switch aria-label=\"Inventory tracked\" defaultChecked />"
|
|
2342
|
+
}
|
|
2343
|
+
},
|
|
1473
2344
|
{
|
|
1474
2345
|
"name": "Table",
|
|
1475
2346
|
"import": "import { Table } from '@ratio-ui/core'",
|
|
@@ -1651,6 +2522,123 @@
|
|
|
1651
2522
|
}
|
|
1652
2523
|
]
|
|
1653
2524
|
},
|
|
2525
|
+
{
|
|
2526
|
+
"name": "TagInput",
|
|
2527
|
+
"import": "import { TagInput } from '@ratio-ui/core'",
|
|
2528
|
+
"description": "Several values as chips in one field in the input's look. The picker offers the existing values (typing filters them), a small field below adds a new one on Enter, and a chip goes with its remove button or with Backspace in the empty picker. Base UI's combobox cannot accept a value it does not list, which is why new values have their own field.",
|
|
2529
|
+
"props": [
|
|
2530
|
+
{
|
|
2531
|
+
"name": "options",
|
|
2532
|
+
"type": "readonly string[]",
|
|
2533
|
+
"required": true,
|
|
2534
|
+
"description": "The existing values the picker offers, such as S, M, L, XL and XXL."
|
|
2535
|
+
},
|
|
2536
|
+
{
|
|
2537
|
+
"name": "value",
|
|
2538
|
+
"type": "readonly string[]",
|
|
2539
|
+
"required": false,
|
|
2540
|
+
"description": "The chosen values, in order, when the owner holds the state."
|
|
2541
|
+
},
|
|
2542
|
+
{
|
|
2543
|
+
"name": "defaultValue",
|
|
2544
|
+
"type": "readonly string[]",
|
|
2545
|
+
"required": false,
|
|
2546
|
+
"description": "The values chosen at first, when the component holds the state."
|
|
2547
|
+
},
|
|
2548
|
+
{
|
|
2549
|
+
"name": "onValueChange",
|
|
2550
|
+
"type": "((value: string[]) => void)",
|
|
2551
|
+
"required": false,
|
|
2552
|
+
"description": "Called with every new list of values: after a pick, an added value or a removal."
|
|
2553
|
+
},
|
|
2554
|
+
{
|
|
2555
|
+
"name": "creatable",
|
|
2556
|
+
"type": "boolean",
|
|
2557
|
+
"required": false,
|
|
2558
|
+
"default": "true",
|
|
2559
|
+
"description": "Shows a small field that adds a typed value on Enter. Defaults to true."
|
|
2560
|
+
},
|
|
2561
|
+
{
|
|
2562
|
+
"name": "addLabel",
|
|
2563
|
+
"type": "string",
|
|
2564
|
+
"required": false,
|
|
2565
|
+
"default": "Add value",
|
|
2566
|
+
"description": "The placeholder and accessible name of the small field. Defaults to \"Add value\"."
|
|
2567
|
+
},
|
|
2568
|
+
{
|
|
2569
|
+
"name": "placeholder",
|
|
2570
|
+
"type": "string",
|
|
2571
|
+
"required": false,
|
|
2572
|
+
"description": "The placeholder of the picker, shown while nothing is chosen."
|
|
2573
|
+
},
|
|
2574
|
+
{
|
|
2575
|
+
"name": "emptyText",
|
|
2576
|
+
"type": "string",
|
|
2577
|
+
"required": false,
|
|
2578
|
+
"default": "No matching values",
|
|
2579
|
+
"description": "The line the list shows when no value matches the typed text. Defaults to \"No matching values\"."
|
|
2580
|
+
},
|
|
2581
|
+
{
|
|
2582
|
+
"name": "name",
|
|
2583
|
+
"type": "string",
|
|
2584
|
+
"required": false,
|
|
2585
|
+
"description": "The form field name: one hidden input per chosen value is submitted under it."
|
|
2586
|
+
},
|
|
2587
|
+
{
|
|
2588
|
+
"name": "disabled",
|
|
2589
|
+
"type": "boolean",
|
|
2590
|
+
"required": false,
|
|
2591
|
+
"description": "Dims the component and stops every change."
|
|
2592
|
+
},
|
|
2593
|
+
{
|
|
2594
|
+
"name": "id",
|
|
2595
|
+
"type": "string",
|
|
2596
|
+
"required": false,
|
|
2597
|
+
"description": "The id of the picker's input, which a label points to."
|
|
2598
|
+
},
|
|
2599
|
+
{
|
|
2600
|
+
"name": "aria-label",
|
|
2601
|
+
"type": "string",
|
|
2602
|
+
"required": false,
|
|
2603
|
+
"description": "The accessible name of the picker, when no label points to it."
|
|
2604
|
+
},
|
|
2605
|
+
{
|
|
2606
|
+
"name": "aria-labelledby",
|
|
2607
|
+
"type": "string",
|
|
2608
|
+
"required": false,
|
|
2609
|
+
"description": "The id of the element that names the picker."
|
|
2610
|
+
},
|
|
2611
|
+
{
|
|
2612
|
+
"name": "aria-describedby",
|
|
2613
|
+
"type": "string",
|
|
2614
|
+
"required": false,
|
|
2615
|
+
"description": "The ids of the hint or error that describe the component."
|
|
2616
|
+
},
|
|
2617
|
+
{
|
|
2618
|
+
"name": "aria-invalid",
|
|
2619
|
+
"type": "boolean | \"true\" | \"false\"",
|
|
2620
|
+
"required": false,
|
|
2621
|
+
"description": "Marks the values as invalid, which draws the error ring."
|
|
2622
|
+
},
|
|
2623
|
+
{
|
|
2624
|
+
"name": "aria-required",
|
|
2625
|
+
"type": "boolean | \"true\" | \"false\"",
|
|
2626
|
+
"required": false,
|
|
2627
|
+
"description": "Marks the values as required."
|
|
2628
|
+
},
|
|
2629
|
+
{
|
|
2630
|
+
"name": "ref",
|
|
2631
|
+
"type": "Ref<HTMLInputElement>",
|
|
2632
|
+
"required": false,
|
|
2633
|
+
"description": "Receives the picker's input element."
|
|
2634
|
+
}
|
|
2635
|
+
],
|
|
2636
|
+
"usage": {
|
|
2637
|
+
"whenToUse": "- Several values in one field, such as a product's tags or a variant option's values (S, M, L, XL, XXL)\n- Picking from existing values, with typing to filter them, and adding a new one in the small field below (Enter adds it)\n- Inside a Field: the label, hint, error and required mark land on the picker",
|
|
2638
|
+
"whenNotToUse": "- One value from a fixed list: use Select\n- A read-only summary of values: use SummaryChips\n- Only existing values and no new ones: keep TagInput and set `creatable={false}`\n- Custom classes or inline styles: TagInput takes no `className` and no `style`",
|
|
2639
|
+
"example": "```tsx\nconst [sizes, setSizes] = useState(['S', 'M'])\n\n<Field label=\"Size\" error={errors.size}>\n <TagInput options={['S', 'M', 'L', 'XL', 'XXL']} value={sizes} onValueChange={setSizes} placeholder=\"Choose sizes\" />\n</Field>\n```\n\nA chip goes with its remove button, or with Backspace in the empty picker. A new value is trimmed, takes the spelling of an existing value that differs only in letter case, and is not added twice. Base UI's combobox cannot accept a value it does not list, so new values have their own field."
|
|
2640
|
+
}
|
|
2641
|
+
},
|
|
1654
2642
|
{
|
|
1655
2643
|
"name": "Text",
|
|
1656
2644
|
"import": "import { Text } from '@ratio-ui/core'",
|
|
@@ -1697,6 +2685,31 @@
|
|
|
1697
2685
|
"example": "<Text as=\"h1\" variant=\"h1\">Settlements</Text>\n<Text tone=\"subdued\">Paid out every weekday</Text>"
|
|
1698
2686
|
}
|
|
1699
2687
|
},
|
|
2688
|
+
{
|
|
2689
|
+
"name": "Textarea",
|
|
2690
|
+
"import": "import { Textarea } from '@ratio-ui/core'",
|
|
2691
|
+
"description": "A multi-line text field in the input's look: 8px radius, 1px ring that turns blue on focus, 10px 12px padding, 88px tall (64px compact).",
|
|
2692
|
+
"props": [
|
|
2693
|
+
{
|
|
2694
|
+
"name": "size",
|
|
2695
|
+
"type": "64 | 88",
|
|
2696
|
+
"required": false,
|
|
2697
|
+
"default": "88",
|
|
2698
|
+
"description": "The height in px: 88 by default, 64 compact. The field can still be dragged taller."
|
|
2699
|
+
},
|
|
2700
|
+
{
|
|
2701
|
+
"name": "ref",
|
|
2702
|
+
"type": "Ref<HTMLTextAreaElement>",
|
|
2703
|
+
"required": false,
|
|
2704
|
+
"description": "Receives the textarea element."
|
|
2705
|
+
}
|
|
2706
|
+
],
|
|
2707
|
+
"usage": {
|
|
2708
|
+
"whenToUse": "- A multi-line text field such as a product description: 88px tall by default, `size={64}` for a compact one\n- A field with an error: set `aria-invalid` and the ring changes, and put the error message beside it in text",
|
|
2709
|
+
"whenNotToUse": "- A single line of text: use Input\n- Custom classes or inline styles: Textarea takes no `className` and no `style`",
|
|
2710
|
+
"example": "<Textarea aria-label=\"Description\" placeholder=\"Describe the product\" />\n<Textarea aria-label=\"Note\" size={64} />"
|
|
2711
|
+
}
|
|
2712
|
+
},
|
|
1700
2713
|
{
|
|
1701
2714
|
"name": "Toaster",
|
|
1702
2715
|
"import": "import { Toaster } from '@ratio-ui/core'",
|
|
@@ -1850,6 +2863,74 @@
|
|
|
1850
2863
|
]
|
|
1851
2864
|
}
|
|
1852
2865
|
]
|
|
2866
|
+
},
|
|
2867
|
+
{
|
|
2868
|
+
"name": "UnitInput",
|
|
2869
|
+
"import": "import { UnitInput } from '@ratio-ui/core'",
|
|
2870
|
+
"description": "A number field with its unit after it, inside one ring: a weight in kg, a length in cm. It takes and gives a number, written without thousands separators as counts are, and keeps at most `decimals` decimals.",
|
|
2871
|
+
"props": [
|
|
2872
|
+
{
|
|
2873
|
+
"name": "unit",
|
|
2874
|
+
"type": "string",
|
|
2875
|
+
"required": true,
|
|
2876
|
+
"description": "The unit after the number, such as kg or cm. Screen readers read it as the field's description."
|
|
2877
|
+
},
|
|
2878
|
+
{
|
|
2879
|
+
"name": "value",
|
|
2880
|
+
"type": "number | null",
|
|
2881
|
+
"required": false,
|
|
2882
|
+
"description": "The number, or null for an empty field. Pass it to control the field."
|
|
2883
|
+
},
|
|
2884
|
+
{
|
|
2885
|
+
"name": "defaultValue",
|
|
2886
|
+
"type": "number | null",
|
|
2887
|
+
"required": false,
|
|
2888
|
+
"description": "The starting number when the field is not controlled. Defaults to empty."
|
|
2889
|
+
},
|
|
2890
|
+
{
|
|
2891
|
+
"name": "onValueChange",
|
|
2892
|
+
"type": "((value: number | null) => void)",
|
|
2893
|
+
"required": false,
|
|
2894
|
+
"description": "Called with the number as it is typed or cleared (null when empty), and with the rounded number on blur."
|
|
2895
|
+
},
|
|
2896
|
+
{
|
|
2897
|
+
"name": "decimals",
|
|
2898
|
+
"type": "number",
|
|
2899
|
+
"required": false,
|
|
2900
|
+
"default": "3",
|
|
2901
|
+
"description": "The most decimals the number keeps; the field rounds to them on blur. Defaults to 3 (grams in kg)."
|
|
2902
|
+
},
|
|
2903
|
+
{
|
|
2904
|
+
"name": "min",
|
|
2905
|
+
"type": "number",
|
|
2906
|
+
"required": false,
|
|
2907
|
+
"description": "The smallest number; the field moves a smaller one up to it on blur."
|
|
2908
|
+
},
|
|
2909
|
+
{
|
|
2910
|
+
"name": "max",
|
|
2911
|
+
"type": "number",
|
|
2912
|
+
"required": false,
|
|
2913
|
+
"description": "The largest number; the field moves a larger one down to it on blur."
|
|
2914
|
+
},
|
|
2915
|
+
{
|
|
2916
|
+
"name": "size",
|
|
2917
|
+
"type": "32 | 36",
|
|
2918
|
+
"required": false,
|
|
2919
|
+
"default": "36",
|
|
2920
|
+
"description": "The height in px: 36 for forms, 32 for fields inside a table. Defaults to 36."
|
|
2921
|
+
},
|
|
2922
|
+
{
|
|
2923
|
+
"name": "ref",
|
|
2924
|
+
"type": "Ref<HTMLInputElement>",
|
|
2925
|
+
"required": false,
|
|
2926
|
+
"description": "Receives the input element."
|
|
2927
|
+
}
|
|
2928
|
+
],
|
|
2929
|
+
"usage": {
|
|
2930
|
+
"whenToUse": "- A number with a unit after it: weight in kg, length in cm, a lead time in days\n- Values stored as numbers: `value` and `onValueChange` take and give a number, null when empty\n- A field inside a table: `size` 32",
|
|
2931
|
+
"whenNotToUse": "- Money: use MoneyInput, which takes and gives paise\n- A unit before the number, or an icon: use InputGroup with an addon\n- Text that is not a number: use Input\n- Custom classes or inline styles: UnitInput takes neither `className` nor `style`",
|
|
2932
|
+
"example": "const [weight, setWeight] = useState<number | null>(0.24)\n\n<UnitInput aria-label=\"Weight\" unit=\"kg\" value={weight} onValueChange={setWeight} min={0} />\n<UnitInput aria-label=\"Length\" unit=\"cm\" decimals={0} defaultValue={30} name=\"length\" />"
|
|
2933
|
+
}
|
|
1853
2934
|
}
|
|
1854
2935
|
]
|
|
1855
2936
|
}
|