@bfrs/agentic-components 0.3.7 → 0.3.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.
@@ -36,7 +36,31 @@ import "@bfrs/agentic-components/fonts.css";
36
36
  Import components by name:
37
37
 
38
38
  ```tsx
39
- import { BfrsProvider, Button, Input, Slider, ColorPicker, ColorSwatchGroup, OptionCardGroup, NumberStepper, SuggestInput, FileDropzone, RevealField, RevealAndCopy, Modal, DataTable, DateRangePicker, ToastProvider, useToast } from "@bfrs/agentic-components";
39
+ import {
40
+ BfrsProvider,
41
+ Button,
42
+ FormField,
43
+ Input,
44
+ Slider,
45
+ ColorPicker,
46
+ ColorSwatchGroup,
47
+ OptionCardGroup,
48
+ SelectableChipGroup,
49
+ NumberStepper,
50
+ SuggestInput,
51
+ FileDropzone,
52
+ RevealField,
53
+ RevealAndCopy,
54
+ HorizontalStepper,
55
+ Modal,
56
+ DataTable,
57
+ TableColumnVisibility,
58
+ TableSaveView,
59
+ TableToolbar,
60
+ DateRangePicker,
61
+ ToastProvider,
62
+ useToast
63
+ } from "@bfrs/agentic-components";
40
64
  ```
41
65
 
42
66
  React consumers should wrap BFRS surfaces in `BfrsProvider`; the provider owns `--bfrs-*` variables, color scheme, and portal inheritance.
@@ -119,9 +143,9 @@ Registered tags cover the documented component surface, including
119
143
  `bfrs-button-group`, `bfrs-toast-provider`, `bfrs-table-toolbar`,
120
144
  `bfrs-table-empty-state`, `bfrs-table-error-state`, `bfrs-table-skeleton`,
121
145
  `bfrs-table-row-actions`, `bfrs-table-bulk-actions`, and
122
- `bfrs-table-column-visibility` in addition to the existing component tags.
146
+ `bfrs-table-column-visibility`, and `bfrs-table-save-view` in addition to the existing component tags.
123
147
  Existing form and pattern tags include `bfrs-date-range-picker`,
124
- `bfrs-multi-select`, `bfrs-step-progress-card`, `bfrs-data-table`,
148
+ `bfrs-multi-select`, `bfrs-horizontal-stepper`, `bfrs-step-progress-card`, `bfrs-data-table`,
125
149
  `bfrs-modal`, `bfrs-tabs`, and the rest of the documented `bfrs-*` surface.
126
150
 
127
151
  ReactNode-based composition is exposed through native named slots. Angular
@@ -162,9 +186,9 @@ Mount `bfrs-toast-provider` once when Angular needs the equivalent of
162
186
 
163
187
  Use attributes for simple props: `variant`, `size`, `tone`, `label`, `loading`, `disabled`, `required`, `error-message`, `error-text`, `helper-text`, `prefix`, `suffix`, `min`, `max`, `step`, and `value`. Use `[props]` or the `props` JSON attribute for structured props like `options`, palette arrays, `items`, `columns`, `data`, `sections`, `steps`, and `toasts`.
164
188
 
165
- Common component events: `(value-change)`, `(checked-change)`, `(open-change)`, `(reveal-change)`, `(copy)`, `(copy-error)`, `(close)`, `(confirm)`, `(cancel)`, `(cell-action)`, `(cell-event)`, `(row-click)`, `(sort-change)`, `(page-change)`, `(page-size-change)`, `(action-select)`, `(dropdown-select)`, `(date-range-change)`, `(search-change)`, `(open-filters)`, `(apply)`, `(reset)`, and `(submit)`. Payloads are available on `$event.detail`.
189
+ Common component events: `(value-change)`, `(checked-change)`, `(open-change)`, `(reveal-change)`, `(copy)`, `(copy-error)`, `(close)`, `(step-select)`, `(confirm)`, `(cancel)`, `(cell-action)`, `(cell-event)`, `(row-click)`, `(sort-change)`, `(page-change)`, `(page-size-change)`, `(action-select)`, `(dropdown-select)`, `(date-range-change)`, `(search-change)`, `(open-filters)`, `(apply)`, `(reset)`, and `(submit)`. Payloads are available on `$event.detail`.
166
190
 
167
- For validated forms, keep client validation, API validation, and submit side effects in the consuming app. In React, pass field errors through `FormField errorText` and set `Input error`. In Angular, use `bfrs-input` with `[attr.error]` and `[attr.error-message]`, listen to `(value-change)`, and manage success/failure notifications with `bfrs-toast-manager`.
191
+ For validated forms, keep client validation, API validation, and submit side effects in the consuming app. In React, wrap controls in `FormField`, pass field errors through `errorText`, and set the control's `error` prop when supported. In Angular, wrap controls that do not render their own label in `bfrs-form-field`; pass `error-text` and `helper-text` there, listen to the control's `(value-change)`, and manage success/failure notifications with `bfrs-toast-manager`.
168
192
 
169
193
  ```html
170
194
  <bfrs-select
@@ -398,7 +422,7 @@ Square button for icon-only actions. Always provide `aria-label`.
398
422
 
399
423
  ### Forms
400
424
 
401
- > **Rule:** Always wrap form controls in `FormField` — it handles label, helper text, error text, and aria wiring automatically.
425
+ > **Rule:** Always wrap form controls in `FormField` — it handles label, helper text, error text, consistent spacing, and aria wiring automatically.
402
426
 
403
427
  ---
404
428
 
@@ -406,6 +430,8 @@ Square button for icon-only actions. Always provide `aria-label`.
406
430
 
407
431
  Wraps any form control with label, helper, and error text. Connects them via `aria-describedby`.
408
432
 
433
+ The label always renders on its own block row with a `6px` vertical gap before the control. This applies consistently to full-width controls such as `Input` and inline controls such as `NumberStepper`; do not add manual margins between the label and control.
434
+
409
435
  ```tsx
410
436
  <FormField
411
437
  label="Email address"
@@ -415,6 +441,28 @@ Wraps any form control with label, helper, and error text. Connects them via `ar
415
441
  >
416
442
  <Input type="email" value={email} onChange={…} />
417
443
  </FormField>
444
+
445
+ <FormField label="Quantity">
446
+ <NumberStepper
447
+ value={quantity}
448
+ min={1}
449
+ max={10}
450
+ onValueChange={setQuantity}
451
+ />
452
+ </FormField>
453
+ ```
454
+
455
+ Angular / Custom Elements:
456
+
457
+ ```html
458
+ <bfrs-form-field label="Quantity" helper-text="Choose between 1 and 10 items.">
459
+ <bfrs-number-stepper
460
+ [value]="quantity"
461
+ min="1"
462
+ max="10"
463
+ (value-change)="quantity = $event.detail.value">
464
+ </bfrs-number-stepper>
465
+ </bfrs-form-field>
418
466
  ```
419
467
 
420
468
  | Prop | Type | Default |
@@ -548,6 +596,7 @@ const [range, setRange] = useState<DateRangeValue>({
548
596
  | `maxRangeDays` | `number` | — |
549
597
  | `months` | `1 \| 2` | `2` |
550
598
  | `open` / `onOpenChange` | controlled popover state | — |
599
+ | `defaultOpen` | `boolean` | `false` |
551
600
 
552
601
  Keep API date formatting, route updates, and business limits in the consuming app.
553
602
 
@@ -580,6 +629,7 @@ Combobox with search. Use when options list is long (10+).
580
629
  | `disabled` | `boolean` | `false` |
581
630
  | `error` | `boolean` | `false` |
582
631
  | `clearable` | `boolean` | `true` |
632
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
583
633
 
584
634
  ---
585
635
 
@@ -621,6 +671,7 @@ Angular custom element:
621
671
  | `error` | `boolean` | `false` |
622
672
  | `clearable` | `boolean` | `true` |
623
673
  | `maxVisibleValues` | `number` | `2` |
674
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` |
624
675
 
625
676
  ---
626
677
 
@@ -657,25 +708,73 @@ Angular: `<bfrs-selectable-chip-group multiple [props]="{ options, value }" (val
657
708
 
658
709
  #### `NumberStepper`
659
710
 
660
- Quantity input rendered as decrement, value, increment controls.
711
+ Quantity input rendered as decrement, value, increment controls. It is an inline-width control, so use `FormField` for its visible label and consistent label-to-control spacing.
661
712
 
662
713
  ```tsx
663
- <NumberStepper value={quantity} min={1} max={10} onValueChange={setQuantity} />
714
+ <FormField label="Quantity">
715
+ <NumberStepper
716
+ value={quantity}
717
+ min={1}
718
+ max={10}
719
+ step={1}
720
+ onValueChange={setQuantity}
721
+ />
722
+ </FormField>
664
723
  ```
665
724
 
666
- Angular: `<bfrs-number-stepper [value]="quantity" min="1" max="10" (value-change)="quantity = $event.detail.value"></bfrs-number-stepper>`.
725
+ | Prop | Type | Default |
726
+ |------|------|---------|
727
+ | `value` | `number` | — |
728
+ | `defaultValue` | `number` | `0` |
729
+ | `onValueChange` | `(value: number) => void` | — |
730
+ | `min` | `number` | — |
731
+ | `max` | `number` | — |
732
+ | `step` | `number` | `1` |
733
+ | `size` | `"sm" \| "md"` | `"md"` |
734
+ | `error` | `boolean` | `false` |
735
+ | `disabled` | `boolean` | `false` |
736
+
737
+ Angular:
738
+
739
+ ```html
740
+ <bfrs-form-field label="Quantity">
741
+ <bfrs-number-stepper
742
+ [value]="quantity"
743
+ min="1"
744
+ max="10"
745
+ step="1"
746
+ (value-change)="quantity = $event.detail.value">
747
+ </bfrs-number-stepper>
748
+ </bfrs-form-field>
749
+ ```
667
750
 
668
751
  ---
669
752
 
670
753
  #### `SuggestInput`
671
754
 
672
- Free-text input with async-friendly suggestions dropdown. Use when the user may type arbitrary text; use `SearchableSelect` when the final value must be from a bounded option list.
755
+ Free-text input with async-friendly suggestions dropdown. Use when the user may type arbitrary text; use `SearchableSelect` when the final value must be from a bounded option list. Wrap it in `FormField` when it needs a visible label, helper text, or validation message.
673
756
 
674
757
  ```tsx
675
- <SuggestInput value={city} suggestions={citySuggestions} onValueChange={setCity} onSuggestionSelect={setSelectedCity} />
758
+ <FormField label="City">
759
+ <SuggestInput
760
+ value={city}
761
+ suggestions={citySuggestions}
762
+ onValueChange={setCity}
763
+ onSuggestionSelect={setSelectedCity}
764
+ />
765
+ </FormField>
676
766
  ```
677
767
 
678
- Angular: `<bfrs-suggest-input [props]="{ suggestions, value }" (value-change)="value = $event.detail.value"></bfrs-suggest-input>`.
768
+ Angular:
769
+
770
+ ```html
771
+ <bfrs-form-field label="City">
772
+ <bfrs-suggest-input
773
+ [props]="{ suggestions: citySuggestions, value: city }"
774
+ (value-change)="city = $event.detail.value">
775
+ </bfrs-suggest-input>
776
+ </bfrs-form-field>
777
+ ```
679
778
 
680
779
  ---
681
780
 
@@ -703,6 +802,82 @@ Angular: `<bfrs-reveal-field label="Phone" value="9876543210"></bfrs-reveal-fiel
703
802
 
704
803
  ---
705
804
 
805
+ #### Additional form controls composition
806
+
807
+ Use `FormField` around controls that do not own a label. This keeps Quantity and City aligned in the same grid and preserves the standard `6px` label-to-control gap without demo-specific margins.
808
+
809
+ ```tsx
810
+ <Stack gap={5}>
811
+ <OptionCardGroup
812
+ value={fulfillmentMode}
813
+ onValueChange={setFulfillmentMode}
814
+ options={fulfillmentOptions}
815
+ />
816
+
817
+ <SelectableChipGroup
818
+ multiple
819
+ value={channels}
820
+ options={channelOptions}
821
+ addAction={{ label: "Add" }}
822
+ onValueChange={setChannels}
823
+ />
824
+
825
+ <Grid columns={2} gap={4}>
826
+ <FormField label="Quantity">
827
+ <NumberStepper
828
+ value={quantity}
829
+ min={1}
830
+ max={10}
831
+ onValueChange={setQuantity}
832
+ />
833
+ </FormField>
834
+
835
+ <FormField label="City">
836
+ <SuggestInput
837
+ value={city}
838
+ suggestions={citySuggestions}
839
+ onValueChange={setCity}
840
+ />
841
+ </FormField>
842
+ </Grid>
843
+
844
+ <FileDropzone
845
+ title="Upload invoice"
846
+ onFilesChange={setFiles}
847
+ />
848
+
849
+ <RevealField
850
+ label="Masked account field"
851
+ value="9876543210"
852
+ allowCopy
853
+ />
854
+ </Stack>
855
+ ```
856
+
857
+ Angular / Custom Elements:
858
+
859
+ ```html
860
+ <bfrs-grid columns="2" gap="4">
861
+ <bfrs-form-field label="Quantity">
862
+ <bfrs-number-stepper
863
+ [value]="quantity"
864
+ min="1"
865
+ max="10"
866
+ (value-change)="quantity = $event.detail.value">
867
+ </bfrs-number-stepper>
868
+ </bfrs-form-field>
869
+
870
+ <bfrs-form-field label="City">
871
+ <bfrs-suggest-input
872
+ [props]="{ suggestions: citySuggestions, value: city }"
873
+ (value-change)="city = $event.detail.value">
874
+ </bfrs-suggest-input>
875
+ </bfrs-form-field>
876
+ </bfrs-grid>
877
+ ```
878
+
879
+ ---
880
+
706
881
  #### `Slider`
707
882
 
708
883
  Controlled numeric range control. Use instead of raw `<input type="range">`.
@@ -866,20 +1041,22 @@ Radio group. Renders a list of mutually exclusive options.
866
1041
  value={plan}
867
1042
  onValueChange={setPlan}
868
1043
  options={[
869
- { value: "free", label: "Free" },
870
- { value: "pro", label: "Pro" },
871
- { value: "enterprise", label: "Enterprise" },
1044
+ { value: "free", label: "Free", description: "For testing basic workflows." },
1045
+ { value: "pro", label: "Pro", description: "For growing teams that need automation." },
1046
+ { value: "enterprise", label: "Enterprise", description: "For custom limits and support." },
872
1047
  ]}
873
1048
  />
874
1049
  ```
875
1050
 
876
1051
  | Prop | Type | Default |
877
1052
  |------|------|---------|
878
- | `options` | `{ value: string; label: string }[]` | **required** |
1053
+ | `options` | `{ value: string; label: ReactNode; description?: ReactNode; disabled?: boolean }[]` | **required** |
879
1054
  | `value` | `string` | — |
880
1055
  | `onValueChange` | `(value: string) => void` | — |
881
1056
  | `error` | `boolean` | `false` |
882
1057
 
1058
+ Each option renders `label` as the primary text and optional `description` as secondary text below it, matching the Checkbox label stack.
1059
+
883
1060
  ---
884
1061
 
885
1062
  #### `Switch`
@@ -915,6 +1092,12 @@ Small inline status label.
915
1092
  <Badge tone="warning">Pending</Badge>
916
1093
  <Badge tone="danger">Blocked</Badge>
917
1094
  <Badge count={3} aria-label="3 active filters" />
1095
+
1096
+ {/* Sizes: xs | sm (default) | md | lg */}
1097
+ <Badge size="xs" tone="success">xs</Badge>
1098
+ <Badge size="sm" tone="success">sm</Badge>
1099
+ <Badge size="md" tone="success">md</Badge>
1100
+ <Badge size="lg" tone="success">lg</Badge>
918
1101
  ```
919
1102
 
920
1103
  | Prop | Type | Default |
@@ -941,6 +1124,12 @@ Removable tag. Use in filter bars and multi-select UIs.
941
1124
  >
942
1125
  Status: Active
943
1126
  </Chip>
1127
+
1128
+ {/* Sizes: xs | sm (default) | md | lg */}
1129
+ <Chip size="xs" tone="primary">xs</Chip>
1130
+ <Chip size="sm" tone="primary">sm</Chip>
1131
+ <Chip size="md" tone="primary">md</Chip>
1132
+ <Chip size="lg" tone="primary">lg</Chip>
944
1133
  ```
945
1134
 
946
1135
  | Prop | Type | Default |
@@ -949,10 +1138,13 @@ Removable tag. Use in filter bars and multi-select UIs.
949
1138
  | `tone` | `"neutral" \| "primary" \| "brand" \| "success" \| "warning" \| "danger" \| "info"` | `"neutral"` |
950
1139
  | `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"sm"` |
951
1140
  | `leftIcon` | `ReactNode` | — |
1141
+ | `rightIcon` | `ReactNode` | — |
952
1142
  | `removable` | `boolean` | `false` |
953
1143
  | `onRemove` | `() => void` | — |
954
1144
  | `removeLabel` | `string` | `"Remove"` |
955
1145
 
1146
+ Angular: use `left-icon="package"` / `right-icon="arrow-right"` for named Phosphor icons, or use named slots `<span slot="left-icon">…</span>`.
1147
+
956
1148
  ---
957
1149
 
958
1150
  #### `Alert`
@@ -967,11 +1159,18 @@ Contextual message banner. Auto-selects an icon based on tone.
967
1159
  >
968
1160
  Upgrade to keep access to all features.
969
1161
  </Alert>
1162
+
1163
+ {/* Sizes: xs | sm | md (default) | lg */}
1164
+ <Alert size="xs" tone="info" title="XSmall">Ultra-compact inline alert.</Alert>
1165
+ <Alert size="sm" tone="info" title="Small">Compact alert for dense layouts.</Alert>
1166
+ <Alert size="md" tone="info" title="Medium">Default alert size.</Alert>
1167
+ <Alert size="lg" tone="info" title="Large">Spacious alert for prominent messages.</Alert>
970
1168
  ```
971
1169
 
972
1170
  | Prop | Type | Default |
973
1171
  |------|------|---------|
974
1172
  | `tone` | `"info" \| "success" \| "warning" \| "danger"` | `"info"` |
1173
+ | `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` |
975
1174
  | `title` | `ReactNode` | — |
976
1175
  | `action` | `ReactNode` | — |
977
1176
  | `icon` | `ReactNode` | auto (from tone) |
@@ -1130,6 +1329,11 @@ Centered modal. Use for confirmations, forms, and focused tasks.
1130
1329
  | `size` | `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"md"` |
1131
1330
  | `open` | `boolean` | — |
1132
1331
  | `onOpenChange` | `(open: boolean) => void` | — |
1332
+ | `contentClassName` | `string` | — |
1333
+ | `headerClassName` | `string` | — |
1334
+ | `footerClassName` | `string` | — |
1335
+
1336
+ Angular: `content-class-name`, `header-class-name`, `footer-class-name` attributes.
1133
1337
 
1134
1338
  `Dialog` is a deprecated compatibility alias. Use `Modal` in new code.
1135
1339
 
@@ -1160,6 +1364,11 @@ Slide-out panel. Use for detail views, settings, and secondary flows.
1160
1364
  | `description` | `ReactNode` | — |
1161
1365
  | `open` | `boolean` | — |
1162
1366
  | `onOpenChange` | `(open: boolean) => void` | — |
1367
+ | `contentClassName` | `string` | — |
1368
+ | `headerClassName` | `string` | — |
1369
+ | `footerClassName` | `string` | — |
1370
+
1371
+ Angular: `content-class-name`, `header-class-name`, `footer-class-name` attributes.
1163
1372
 
1164
1373
  ---
1165
1374
 
@@ -1204,6 +1413,7 @@ Floating label on hover. Provide `content` as the tooltip text.
1204
1413
  | `children` | `ReactNode` | **required** |
1205
1414
  | `side` | `"top" \| "right" \| "bottom" \| "left"` | `"top"` |
1206
1415
  | `delayDuration` | `number` | `350` |
1416
+ | `disabled` | `boolean` | `false` |
1207
1417
 
1208
1418
  ---
1209
1419
 
@@ -1228,6 +1438,43 @@ Floating content panel. Use for filters, pickers, and inline forms.
1228
1438
 
1229
1439
  ---
1230
1440
 
1441
+ #### `FilterDrawer`
1442
+
1443
+ Slide-out drawer pre-wired for filter forms. Manages its own Apply / Reset footer; the consumer owns filter state and the apply logic.
1444
+
1445
+ ```tsx
1446
+ <FilterDrawer
1447
+ title="Filter shipments"
1448
+ open={filtersOpen}
1449
+ onOpenChange={setFiltersOpen}
1450
+ onApply={handleApply}
1451
+ onReset={handleReset}
1452
+ activeFiltersCount={activeCount}
1453
+ footerActions={<Button variant="ghost">Save as preset</Button>}
1454
+ >
1455
+ <StatusFilter />
1456
+ <DateFilter />
1457
+ </FilterDrawer>
1458
+ ```
1459
+
1460
+ | Prop | Type | Default |
1461
+ |------|------|---------|
1462
+ | `open` | `boolean` | — |
1463
+ | `onOpenChange` | `(open: boolean) => void` | — |
1464
+ | `onApply` | `() => void` | — |
1465
+ | `onReset` | `() => void` | — |
1466
+ | `title` | `ReactNode` | `"Filters"` |
1467
+ | `description` | `ReactNode` | — |
1468
+ | `applyLabel` | `ReactNode` | `"Apply filters"` |
1469
+ | `resetLabel` | `ReactNode` | `"Reset all"` |
1470
+ | `activeFiltersCount` | `number` | `0` |
1471
+ | `applying` | `boolean` | `false` |
1472
+ | `footerActions` | `ReactNode` | — |
1473
+
1474
+ Angular: `(apply)`, `(reset)`, `(close)` events; `<span slot="footer-actions">…</span>` for extra footer content.
1475
+
1476
+ ---
1477
+
1231
1478
  ### Data Display
1232
1479
 
1233
1480
  ---
@@ -1259,12 +1506,13 @@ User avatar with image, initials fallback, and online status.
1259
1506
 
1260
1507
  #### `TablePagination`
1261
1508
 
1262
- Table page navigation. Handles ellipsis, edge pages, and optional page-size controls.
1509
+ Table page navigation. Handles ellipsis, edge pages, optional page-size controls, and two navigation variants: `indexed` (Prev, page indexes like `1 2 3 ... 10`, Next) and `simple` (Prev / Next only).
1263
1510
 
1264
1511
  ```tsx
1265
1512
  <TablePagination
1266
1513
  page={currentPage}
1267
1514
  totalPages={totalPages}
1515
+ variant="indexed"
1268
1516
  pageSize={pageSize}
1269
1517
  onPageChange={setCurrentPage}
1270
1518
  onPageSizeChange={setPageSize}
@@ -1276,8 +1524,14 @@ Table page navigation. Handles ellipsis, edge pages, and optional page-size cont
1276
1524
  | `page` | `number` | **required** |
1277
1525
  | `totalPages` | `number` | **required** |
1278
1526
  | `onPageChange` | `(page: number) => void` | **required** |
1527
+ | `variant` | `"indexed" \| "simple"` | `"indexed"` |
1279
1528
  | `pageSize` | `number` | — |
1280
1529
  | `onPageSizeChange` | `(pageSize: number) => void` | — |
1530
+ | `itemsPerPageLabel` | `string` | `"Items per page:"` |
1531
+
1532
+ Angular: `items-per-page-label` attribute.
1533
+
1534
+ > Pass `pagination={{ page, totalPages, variant: "simple", onPageChange }}` to `DataTable` when the built-in footer should show only Prev and Next.
1281
1535
 
1282
1536
  ---
1283
1537
 
@@ -1320,6 +1574,11 @@ Generic data table with sorting, loading skeleton, row actions, selection, pagin
1320
1574
  | `density` | `"compact" \| "default" \| "comfortable"` | `"default"` |
1321
1575
  | `emptyTitle` | `ReactNode` | `"No records found"` |
1322
1576
  | `emptyDescription` | `ReactNode` | — |
1577
+ | `defaultSorting` | `{ columnId: string; direction: "asc" \| "desc" } \| null` | `null` |
1578
+ | `maxHeight` | `number \| string` | — |
1579
+ | `stickyHeader` | `boolean` | `true` |
1580
+
1581
+ Angular: pass `sorting` as JSON attribute `[sorting]='{"columnId":"name","direction":"asc"}'`; `default-sorting`, `max-height`, `sticky-header` attributes are fully supported. `show-all-label` and `(show-all)` event are supported on `bfrs-table-column-visibility`.
1323
1582
 
1324
1583
  `DataTableColumn<T>`:
1325
1584
  ```ts
@@ -1337,6 +1596,33 @@ Generic data table with sorting, loading skeleton, row actions, selection, pagin
1337
1596
 
1338
1597
  When `loading` is true, `DataTable` renders built-in table-row skeleton placeholders rather than a spinner. The consumer app only owns the loading boolean.
1339
1598
 
1599
+ Use `TableSaveView` with `TableColumnVisibility` when the user changes columns or filters and needs to save the draft as a named view. It opens the "Save this view" modal, collects the view name, summarizes settings like hidden columns, and calls `onSave({ name, visibleColumnIds, hiddenColumnCount, filtersCount, appliedSettingLabels })`; persistence remains app-owned.
1600
+
1601
+ ```tsx
1602
+ <TableToolbar
1603
+ title="Orders"
1604
+ actions={
1605
+ <div className="bfrs-flex bfrs-items-center bfrs-gap-2">
1606
+ {dirty && (
1607
+ <TableSaveView
1608
+ columns={visibilityColumns}
1609
+ visibleColumnIds={visibleColumnIds}
1610
+ onSave={({ visibleColumnIds: nextSavedIds }) => setSavedColumnIds(nextSavedIds)}
1611
+ />
1612
+ )}
1613
+ <TableColumnVisibility
1614
+ columns={visibilityColumns}
1615
+ visibleColumnIds={visibleColumnIds}
1616
+ onVisibleColumnIdsChange={setVisibleColumnIds}
1617
+ onReset={() => setVisibleColumnIds(savedColumnIds)}
1618
+ />
1619
+ </div>
1620
+ }
1621
+ />
1622
+ ```
1623
+
1624
+ Angular custom-element consumers can use `<bfrs-table-save-view>` and listen for `(save-view)` with the same payload.
1625
+
1340
1626
  Custom-element DataTable action cells must be declarative because Angular/HTML cannot pass React `cell` functions through JSON. Use `cellType: "button"` for one inline button, `cellType: "buttons"` for multiple inline buttons, or `cellType: "actions"` for an action menu. Action clicks emit `cell-action` with `{ actionId, columnId, row, rowId, rowIndex }` and do not trigger `row-click`.
1341
1627
 
1342
1628
  ```html
@@ -1429,6 +1715,68 @@ not rendered. Listed custom-element events are re-emitted as `cell-event` with
1429
1715
 
1430
1716
  ---
1431
1717
 
1718
+ #### `TableColumnVisibility`
1719
+
1720
+ Column show/hide control used inside `TableToolbar`. Emits `visible-column-ids-change` and exposes a "Show all" reset button.
1721
+
1722
+ ```tsx
1723
+ <TableColumnVisibility
1724
+ columns={visibilityColumns}
1725
+ visibleColumnIds={visibleColumnIds}
1726
+ onVisibleColumnIdsChange={setVisibleColumnIds}
1727
+ onReset={() => setVisibleColumnIds(savedColumnIds)}
1728
+ showAllLabel="Show all columns"
1729
+ />
1730
+ ```
1731
+
1732
+ | Prop | Type | Default |
1733
+ |------|------|---------|
1734
+ | `columns` | `{ id: string; label: string }[]` | **required** |
1735
+ | `visibleColumnIds` | `string[]` | — |
1736
+ | `onVisibleColumnIdsChange` | `(ids: string[]) => void` | — |
1737
+ | `onReset` | `() => void` | — |
1738
+ | `onShowAll` | `() => void` | — |
1739
+ | `showAllLabel` | `string` | `"Show all"` |
1740
+ | `resetLabel` | `string` | `"Reset"` |
1741
+ | `label` | `ReactNode` | `"Columns"` |
1742
+
1743
+ Angular: `show-all-label` attribute; `(show-all)` event.
1744
+
1745
+ ---
1746
+
1747
+ #### `MetricCard`
1748
+
1749
+ KPI display card with trend indicator, optional subtitle, description, icon slot, and action slot.
1750
+
1751
+ ```tsx
1752
+ <MetricCard
1753
+ title="Total shipments"
1754
+ value="12,480"
1755
+ trendValue="+8.2%"
1756
+ trendDirection="up"
1757
+ subtitle="vs last month"
1758
+ icon={<Icon icon={Package} />}
1759
+ action={<Button size="sm" variant="ghost">View all</Button>}
1760
+ />
1761
+ ```
1762
+
1763
+ | Prop | Type | Default |
1764
+ |------|------|---------|
1765
+ | `title` | `ReactNode` | `"Metric"` |
1766
+ | `value` | `ReactNode` | — |
1767
+ | `subtitle` | `ReactNode` | — |
1768
+ | `description` | `ReactNode` | — |
1769
+ | `trendValue` | `ReactNode` | — |
1770
+ | `trendDirection` | `"up" \| "down" \| "neutral"` | `"neutral"` |
1771
+ | `icon` | `ReactNode` | — |
1772
+ | `action` | `ReactNode` | — |
1773
+ | `loading` | `boolean` | `false` |
1774
+ | `compact` | `boolean` | `false` |
1775
+
1776
+ Angular: `icon="package"` for a named Phosphor icon; use `<span slot="action">…</span>` for the action slot.
1777
+
1778
+ ---
1779
+
1432
1780
  ### Navigation
1433
1781
 
1434
1782
  ---
@@ -1742,7 +2090,7 @@ Grouped expandable sections. Use `type="single"` (default) to keep one panel ope
1742
2090
 
1743
2091
  For `type="single"`, `value`/`defaultValue`/`onValueChange` use a string; for `type="multiple"` they use a string array.
1744
2092
 
1745
- Angular: `<bfrs-accordion type="single" [props]="{ items: sections }" (value-change)="openSection = $event.detail.value"></bfrs-accordion>`. Pass each item's `content` as a string in custom-element usage.
2093
+ Angular: `<bfrs-accordion type="single" value="pickup" [props]="{ items: sections }" (value-change)="openSection = $event.detail.value"></bfrs-accordion>`. The `value` attribute supports controlled mode; use a JSON array string for `type="multiple"`. Pass each item's `content` as a string in custom-element usage.
1746
2094
 
1747
2095
  ---
1748
2096
 
@@ -1888,6 +2236,72 @@ Built-in loading behavior:
1888
2236
 
1889
2237
  ---
1890
2238
 
2239
+ #### `HorizontalStepper`
2240
+
2241
+ Compact horizontal flow stepper matching the activation-panel layout: optional announcement banner, centered connected steps, and heading/subheading copy below. Uses semantic theme tokens instead of hardcoded screenshot colors. Actions remain parent-owned: React passes `onClose` / `onStepSelect`; custom elements emit `(close)` / `(step-select)`.
2242
+
2243
+ For custom elements, add `selectable` when steps should be clickable and emit `(step-select)`.
2244
+
2245
+ Variants:
2246
+ - `primary` — default theme-colored activation or plan-selection flow.
2247
+ - `success` — completed or positive-confirmation flows.
2248
+ - `info` — informational setup or guidance flows.
2249
+ - `warning` — pending verification or caution flows.
2250
+ - `neutral` — low-emphasis wizard progress where status color should stay quiet.
2251
+
2252
+ ```tsx
2253
+ <HorizontalStepper
2254
+ announcement="Great Choice! Early COD Remittance activation in progress.."
2255
+ closeButton
2256
+ onClose={handleClose}
2257
+ currentStep={0}
2258
+ title="Select a Plan"
2259
+ subheading="Get guaranteed remittance from the shipment delivered date."
2260
+ size="sm"
2261
+ variant="primary"
2262
+ steps={[
2263
+ { label: "Select Plan", secondaryText: "Choose payout speed" },
2264
+ { label: "Verify OTP", secondaryText: "Confirm activation" },
2265
+ ]}
2266
+ />
2267
+ ```
2268
+
2269
+ ```html
2270
+ <bfrs-horizontal-stepper
2271
+ announcement="Great Choice! Early COD Remittance activation in progress.."
2272
+ title="Select a Plan"
2273
+ subheading="Get guaranteed remittance from the shipment delivered date."
2274
+ current-step="0"
2275
+ close-button
2276
+ size="sm"
2277
+ selectable
2278
+ variant="primary"
2279
+ [props]="{ steps: remittanceSteps }"
2280
+ (close)="dismissStepper()"
2281
+ (step-select)="selectStep($event.detail)">
2282
+ </bfrs-horizontal-stepper>
2283
+ ```
2284
+
2285
+ | Prop | Type | Default |
2286
+ |------|------|---------|
2287
+ | `steps` | `{ label: ReactNode; secondaryText?: ReactNode; description?: ReactNode; status?: "done" \| "active" \| "pending" \| "disabled"; disabled?: boolean }[]` | **required** |
2288
+ | `currentStep` | `number` | `0` |
2289
+ | `title` | `ReactNode` | — |
2290
+ | `subheading` | `ReactNode` | — |
2291
+ | `description` | `ReactNode` | — alias for `subheading` |
2292
+ | `announcement` | `ReactNode` | — |
2293
+ | `closeButton` | `boolean` | `false` |
2294
+ | `closeLabel` | `string` | `"Close"` |
2295
+ | `onClose` | `() => void` | — |
2296
+ | `onStepSelect` | `(step, index) => void` | — |
2297
+ | `size` | `"sm" \| "md"` | `"sm"` |
2298
+ | `surface` | `"card" \| "plain"` | `"card"` |
2299
+ | `variant` | `"primary" \| "success" \| "info" \| "warning" \| "neutral"` | `"primary"` |
2300
+
2301
+ Each step renders `label` as the primary text and optional `secondaryText` below it. `description` is kept as a backwards-compatible alias for `secondaryText`.
2302
+
2303
+ ---
2304
+
1891
2305
  #### `StepProgressCard`
1892
2306
 
1893
2307
  Step-by-step progress indicator. Calculates `done` / `active` / `pending` state automatically from `currentStep` and preserves the green completed-dot, active-star, and rail-fill transitions. Defaults to the Figma-derived plain progress block; pass `surface="card"` for the standard card wrapper.
@@ -1954,7 +2368,7 @@ Step-by-step progress indicator. Calculates `done` / `active` / `pending` state
1954
2368
  loading={isLoading}
1955
2369
  sorting={sorting}
1956
2370
  onSortingChange={setSorting}
1957
- pagination={{ page, totalPages, onPageChange: setPage }}
2371
+ pagination={{ page, totalPages, variant: "indexed", onPageChange: setPage }}
1958
2372
  />
1959
2373
  </Card>
1960
2374
  </Container>
@@ -2002,6 +2416,6 @@ Step-by-step progress indicator. Calculates `done` / `active` / `pending` state
2002
2416
 
2003
2417
  - Do not use raw Tailwind classes for spacing, color, or typography — use `Stack`, `Text`, and component props instead
2004
2418
  - Do not build custom modals, drawers, or dropdowns — use `Modal`, `ConfirmDialog`, `Drawer`, and `ActionMenu`
2005
- - Do not render form labels manually — use `FormField` which wires aria attributes automatically
2419
+ - Do not render form labels or add label margins manually — use `FormField`, which keeps labels on their own row, applies the standard gap, and wires aria attributes automatically
2006
2420
  - Do not use `<h1>`–`<h6>` or `<p>` directly — use `<Text variant="h1">` etc.
2007
2421
  - Do not add `loading` spinners manually — all interactive components accept a `loading` prop