@emporix/component-library 1.8.2 → 1.11.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.
Files changed (41) hide show
  1. package/README.md +533 -24
  2. package/dist/components/autocomplete/AutoComplete.d.ts +40 -0
  3. package/dist/components/autocomplete/AutoComplete.d.ts.map +1 -0
  4. package/dist/components/autocomplete/index.d.ts +3 -0
  5. package/dist/components/autocomplete/index.d.ts.map +1 -0
  6. package/dist/components/buttons/PrimaryButton.d.ts +1 -1
  7. package/dist/components/buttons/PrimaryButton.d.ts.map +1 -1
  8. package/dist/components/buttons/SecondaryButton.d.ts +1 -1
  9. package/dist/components/buttons/SecondaryButton.d.ts.map +1 -1
  10. package/dist/components/checkbox/Checkbox.d.ts +50 -0
  11. package/dist/components/checkbox/Checkbox.d.ts.map +1 -0
  12. package/dist/components/checkbox/index.d.ts +3 -0
  13. package/dist/components/checkbox/index.d.ts.map +1 -0
  14. package/dist/components/datatable/DataTable.d.ts +6 -0
  15. package/dist/components/datatable/DataTable.d.ts.map +1 -0
  16. package/dist/components/datatable/index.d.ts +5 -0
  17. package/dist/components/datatable/index.d.ts.map +1 -0
  18. package/dist/components/datatable/types.d.ts +60 -0
  19. package/dist/components/datatable/types.d.ts.map +1 -0
  20. package/dist/components/datatable/useDataTablePagination.d.ts +17 -0
  21. package/dist/components/datatable/useDataTablePagination.d.ts.map +1 -0
  22. package/dist/components/dialog/Dialog.d.ts +34 -0
  23. package/dist/components/dialog/Dialog.d.ts.map +1 -0
  24. package/dist/components/dialog/index.d.ts +3 -0
  25. package/dist/components/dialog/index.d.ts.map +1 -0
  26. package/dist/components/dropdown/Dropdown.d.ts +19 -1
  27. package/dist/components/dropdown/Dropdown.d.ts.map +1 -1
  28. package/dist/components/menu/Menu.d.ts +27 -0
  29. package/dist/components/menu/Menu.d.ts.map +1 -0
  30. package/dist/components/menu/index.d.ts +3 -0
  31. package/dist/components/menu/index.d.ts.map +1 -0
  32. package/dist/components/message/Message.d.ts +31 -0
  33. package/dist/components/message/Message.d.ts.map +1 -0
  34. package/dist/components/radiobutton/RadioButton.d.ts +46 -0
  35. package/dist/components/radiobutton/RadioButton.d.ts.map +1 -0
  36. package/dist/index.d.ts +15 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.es.js +1566 -6019
  39. package/dist/index.umd.js +1 -553
  40. package/dist/style.css +1 -1
  41. package/package.json +13 -4
package/README.md CHANGED
@@ -132,6 +132,237 @@ import { InputText } from '@emporix/component-library'
132
132
 
133
133
  All standard HTML input attributes (placeholder, value, onChange, etc.) are supported.
134
134
 
135
+ ### AutoComplete
136
+
137
+ Search input with async suggestions. API inspired by [PrimeReact AutoComplete](https://primereact.org/autocomplete/).
138
+
139
+ ```tsx
140
+ import { AutoComplete } from '@emporix/component-library'
141
+ ;<AutoComplete
142
+ value={query}
143
+ suggestions={vendors}
144
+ field='name'
145
+ dropdown
146
+ completeMethod={({ query }) => searchVendors(query)}
147
+ onChange={e => setQuery(e.value)}
148
+ onSelect={e => setSelectedVendor(e.value)}
149
+ label='Vendor'
150
+ placeholder='Search vendor...'
151
+ />
152
+ ```
153
+
154
+ | Prop | Type | Description |
155
+ | -------------- | -------- | ---------------------------------- |
156
+ | value | string | Controlled input text |
157
+ | suggestions | T[] | Suggestion list from parent |
158
+ | completeMethod | function | Called (debounced) when user types |
159
+ | onChange | function | Input text changes |
160
+ | onSelect | function | Suggestion selected |
161
+ | dropdown | boolean | Show dropdown trigger button |
162
+ | field | string | Suggestion label property |
163
+
164
+ ### Checkbox
165
+
166
+ A checkbox built on a native `input type="checkbox"` with PrimeReact-compatible `onChange` events (`{ checked, originalEvent }`). API inspired by [PrimeReact Checkbox](https://primereact.org/checkbox/).
167
+
168
+ ```tsx
169
+ import { useState } from 'react'
170
+ import { Checkbox } from '@emporix/component-library'
171
+
172
+ // Controlled single checkbox
173
+ const [checked, setChecked] = useState(false)
174
+ <Checkbox checked={checked} onChange={e => setChecked(e.checked)} />
175
+
176
+ // With label (associate via inputId + htmlFor)
177
+ <Checkbox inputId="remember-me" checked={checked} onChange={e => setChecked(e.checked)} />
178
+ <label htmlFor="remember-me">Remember me</label>
179
+
180
+ // Role toggles (single selection)
181
+ const roles = ['viewer', 'editor', 'manager', 'administrator']
182
+ const [selectedRole, setSelectedRole] = useState<string | null>(null)
183
+ {roles.map(role => (
184
+ <div key={role}>
185
+ <Checkbox
186
+ inputId={role}
187
+ value={role}
188
+ checked={selectedRole === role}
189
+ onChange={e => setSelectedRole(e.checked ? role : null)}
190
+ />
191
+ <label htmlFor={role}>{role}</label>
192
+ </div>
193
+ ))}
194
+ ```
195
+
196
+ #### Props
197
+
198
+ | Prop | Type | Default | Description |
199
+ | ----------- | -------------------------------- | ------- | ----------------------------------------------- |
200
+ | checked | boolean | false | Whether the checkbox is checked (controlled) |
201
+ | onChange | (e: CheckboxChangeEvent) => void | - | Fired when checked state changes |
202
+ | value | unknown | - | Value associated with the checkbox |
203
+ | inputId | string | - | id for the native input (for label association) |
204
+ | disabled | boolean | false | Whether the checkbox is disabled |
205
+ | invalid | boolean | false | Invalid state for validation styling |
206
+ | name | string | - | Name attribute for form submission |
207
+ | readOnly | boolean | false | Prevents user interaction |
208
+ | required | boolean | false | Marks the field as required |
209
+ | className | string | - | Additional CSS class for the root |
210
+ | data-testid | string | - | Test ID for root and input (suffix `-input`) |
211
+
212
+ Standard HTML input attributes (`aria-label`, `aria-labelledby`, `tabIndex`, etc.) are supported on the native input.
213
+
214
+ ### Dialog
215
+
216
+ A modal dialog built on [PrimeReact Dialog](https://primereact.org/dialog/). Use for focused tasks that need a decision or confirmation. Wraps PrimeReact internally with scoped Emporix styles.
217
+
218
+ ```tsx
219
+ import { useState } from 'react'
220
+ import {
221
+ Dialog,
222
+ PrimaryButton,
223
+ SecondaryButton,
224
+ } from '@emporix/component-library'
225
+
226
+ function ConfirmDialogExample() {
227
+ const [visible, setVisible] = useState(false)
228
+
229
+ return (
230
+ <>
231
+ <PrimaryButton onClick={() => setVisible(true)}>
232
+ Open dialog
233
+ </PrimaryButton>
234
+ <Dialog
235
+ visible={visible}
236
+ onHide={() => setVisible(false)}
237
+ header='Confirm changes'
238
+ footer={
239
+ <>
240
+ <SecondaryButton onClick={() => setVisible(false)}>
241
+ Cancel
242
+ </SecondaryButton>
243
+ <PrimaryButton onClick={() => setVisible(false)}>
244
+ Save
245
+ </PrimaryButton>
246
+ </>
247
+ }
248
+ style={{ width: '100%', maxWidth: '480px' }}
249
+ >
250
+ <p>Your changes will be applied immediately.</p>
251
+ </Dialog>
252
+ </>
253
+ )
254
+ }
255
+ ```
256
+
257
+ #### Props
258
+
259
+ | Prop | Type | Default | Description |
260
+ | --------------- | ------------- | ------- | -------------------------------------------------------- |
261
+ | visible | boolean | - | Whether the dialog is visible |
262
+ | onHide | () => void | - | Called when the dialog closes (overlay, Escape, or icon) |
263
+ | header | ReactNode | - | Dialog title area |
264
+ | footer | ReactNode | - | Footer slot (e.g. action buttons) |
265
+ | children | ReactNode | - | Dialog body content |
266
+ | className | string | - | Additional CSS class on the dialog root |
267
+ | style | CSSProperties | - | Inline styles on the dialog root (e.g. width) |
268
+ | modal | boolean | true | Blocks interaction with the page behind the dialog |
269
+ | dismissableMask | boolean | modal | When true, clicking the mask closes the dialog |
270
+ | closable | boolean | true | Shows the header close icon |
271
+ | draggable | boolean | false | Allows dragging the dialog by its header |
272
+ | data-testid | string | - | Test ID on the dialog root |
273
+
274
+ Requires PrimeReact base CSS and a theme in the host app.
275
+
276
+ ### DataTable
277
+
278
+ Encapsulated data table built on [PrimeReact DataTable](https://primereact.org/datatable/). Styles are scoped via CSS modules. Pass `columns`, optional controlled `pagination`, selection, `rowActions`, and an `emptyTemplate` for empty results.
279
+
280
+ Import `@emporix/component-library/styles` once in your app entry, plus PrimeReact base CSS, a theme, and `primeicons` (required for paginator/sort icons).
281
+
282
+ ```tsx
283
+ import { useMemo, useState } from 'react'
284
+ import { FilterMatchMode } from 'primereact/api'
285
+ import { DataTable } from '@emporix/component-library'
286
+ import type { DataTablePaginationState } from '@emporix/component-library'
287
+ import '@emporix/component-library/styles'
288
+ import 'primereact/resources/primereact.css'
289
+ import 'primereact/resources/themes/lara-light-cyan/theme.css'
290
+ import 'primeicons/primeicons.css'
291
+
292
+ const columns = [
293
+ {
294
+ columnKey: 'name',
295
+ field: 'name',
296
+ header: 'Name',
297
+ sortable: true,
298
+ filter: true,
299
+ filterMatchMode: FilterMatchMode.CONTAINS,
300
+ showFilterMenu: false,
301
+ showClearButton: false,
302
+ },
303
+ { columnKey: 'email', field: 'email', header: 'Email', sortable: true },
304
+ ]
305
+
306
+ function UsersTable({
307
+ users,
308
+ totalCount,
309
+ loading,
310
+ paginationParams,
311
+ onPage,
312
+ onSort,
313
+ onFilter,
314
+ }) {
315
+ const [selected, setSelected] = useState([])
316
+
317
+ const pagination = useMemo<DataTablePaginationState>(
318
+ () => ({
319
+ ...paginationParams,
320
+ totalRecords: totalCount,
321
+ }),
322
+ [paginationParams, totalCount]
323
+ )
324
+
325
+ return (
326
+ <DataTable
327
+ value={users}
328
+ columns={columns}
329
+ dataKey='id'
330
+ loading={loading}
331
+ pagination={pagination}
332
+ onPage={onPage}
333
+ onSort={onSort}
334
+ onFilter={onFilter}
335
+ selectionMode='multiple'
336
+ selection={selected}
337
+ onSelectionChange={setSelected}
338
+ rowActions={user => <button type='button'>Edit</button>}
339
+ currentPageReportTemplate='{first} - {last} of {totalRecords}'
340
+ emptyTemplate={<span>No users found</span>}
341
+ />
342
+ )
343
+ }
344
+ ```
345
+
346
+ #### Props
347
+
348
+ | Prop | Type | Default | Description |
349
+ | ----------------------------- | --------------------------------- | ------- | ---------------------------------------------------------- |
350
+ | value | T[] | - | Row data array (required) |
351
+ | columns | ColumnProps[] | - | Column definitions; `rowActions` appends an actions column |
352
+ | dataKey | string | - | Unique row identifier field |
353
+ | loading | boolean | false | Shows loading overlay |
354
+ | pagination | DataTablePaginationState | - | Controlled pagination/sort/filter state |
355
+ | onPage / onSort / onFilter | function | - | Pagination, sort, and filter event handlers |
356
+ | selectionMode | `'single' \| 'multiple' \| null` | null | Row selection mode |
357
+ | selection / onSelectionChange | T \| T[number] \| null / function | - | Controlled selection state |
358
+ | rowActions | (item) => ReactNode | - | Renders an actions column per row |
359
+ | emptyTemplate | ReactNode \| () => ReactNode | - | Content when `value` is empty |
360
+ | lazy / totalRecords | boolean / number | - | Server-driven data with external total count |
361
+ | className / style | string / CSSProperties | - | Root table styling |
362
+ | data-testid | string | - | Test ID on the table root |
363
+
364
+ Omit `pagination` to use the built-in `useDataTablePagination` hook for local client-side paging.
365
+
135
366
  ### Dropdown
136
367
 
137
368
  A select-style dropdown for choosing one or more items from a list. Supports optional filter/search, editable input, label, required indicator, and validation errors. Hover and focus styles match the InputText component. API inspired by [PrimeReact Dropdown](https://primereact.org/dropdown/).
@@ -179,33 +410,49 @@ const options = [
179
410
  multiple
180
411
  filter
181
412
  />
413
+
414
+ // Multi-select with removable chips (PrimeReact MultiSelect display="chip" parity)
415
+ <Dropdown
416
+ value={groupIds}
417
+ onChange={e => setGroupIds(Array.isArray(e.value) ? e.value : [])}
418
+ options={groupOptions}
419
+ multiple
420
+ display="chip"
421
+ filter
422
+ placeholder="Select groups"
423
+ label="User groups"
424
+ />
182
425
  ```
183
426
 
184
427
  #### Props
185
428
 
186
- | Prop | Type | Default | Description |
187
- | -------------- | ------------------------- | ---------- | --------------------------------------------- |
188
- | value | unknown | - | Selected value (array when `multiple`) |
189
- | onChange | (e: ChangeEvent) => void | - | Callback when selection changes |
190
- | options | T[] | - | Array of options |
191
- | optionLabel | string | `"label"` | Property name for option label |
192
- | optionValue | string | `"value"` | Property name for option value |
193
- | optionDisabled | string | - | Property name for disabled flag on options |
194
- | placeholder | string | `"Select"` | Placeholder when no value selected |
195
- | filter | boolean | false | Enable search filter in the overlay |
196
- | editable | boolean | false | Allow typing in the trigger to filter/select |
197
- | onEditEnd | (e: EditEndEvent) => void | - | Fired when Enter is pressed in editable mode |
198
- | multiple | boolean | false | Allow multiple selection |
199
- | label | ReactNode | - | Label text above the trigger |
200
- | error | ReactNode | - | Error text displayed below the trigger |
201
- | required | boolean | false | Shows asterisk on label |
202
- | inputId | string | - | id for the trigger (for label association) |
203
- | disabled | boolean | false | Whether the dropdown is disabled |
204
- | valueTemplate | (option) => ReactNode | - | Custom render for selected value in trigger |
205
- | itemTemplate | (option) => ReactNode | - | Custom render for each option in the list |
206
- | className | string | - | Additional CSS class for the root |
207
- | panelClassName | string | - | Additional CSS class for the overlay panel |
208
- | data-testid | string | - | Test ID for root, trigger, panel, and options |
429
+ | Prop | Type | Default | Description |
430
+ | ------------------ | ------------------------- | ---------------------- | --------------------------------------------- |
431
+ | value | unknown | - | Selected value (array when `multiple`) |
432
+ | onChange | (e: ChangeEvent) => void | - | Callback when selection changes |
433
+ | options | T[] | - | Array of options |
434
+ | optionLabel | string | `"label"` | Property name for option label |
435
+ | optionValue | string | `"value"` | Property name for option value |
436
+ | optionDisabled | string | - | Property name for disabled flag on options |
437
+ | placeholder | string | `"Select"` | Placeholder when no value selected |
438
+ | filter | boolean | false | Enable search filter in the overlay |
439
+ | editable | boolean | false | Allow typing in the trigger to filter/select |
440
+ | onEditEnd | (e: EditEndEvent) => void | - | Fired when Enter is pressed in editable mode |
441
+ | multiple | boolean | false | Allow multiple selection |
442
+ | display | `'comma' \| 'chip'` | `'comma'` | Multi-select trigger display mode |
443
+ | maxSelectedLabels | number | - | Max chips before showing `selectedItemsLabel` |
444
+ | selectedItemsLabel | string | `'{0} items selected'` | Overflow label; `{0}` = count |
445
+ | removeIcon | ReactNode | - | Custom icon for chip remove buttons |
446
+ | label | ReactNode | - | Label text above the trigger |
447
+ | error | ReactNode | - | Error text displayed below the trigger |
448
+ | required | boolean | false | Shows asterisk on label |
449
+ | inputId | string | - | id for the trigger (for label association) |
450
+ | disabled | boolean | false | Whether the dropdown is disabled |
451
+ | valueTemplate | (option) => ReactNode | - | Custom render for selected value in trigger |
452
+ | itemTemplate | (option) => ReactNode | - | Custom render for each option in the list |
453
+ | className | string | - | Additional CSS class for the root |
454
+ | panelClassName | string | - | Additional CSS class for the overlay panel |
455
+ | data-testid | string | - | Test ID for root, trigger, panel, and options |
209
456
 
210
457
  ### SelectButton
211
458
 
@@ -252,6 +499,70 @@ const options = [
252
499
  | className | string | - | Additional CSS class |
253
500
  | data-testid | string | - | Test ID for root and option buttons |
254
501
 
502
+ ### RadioButton
503
+
504
+ Single-choice selection using native `input[type="radio"]`. API inspired by [PrimeReact RadioButton](https://primereact.org/radiobutton/). Compose multiple `RadioButton` instances with the same `name` to form a group.
505
+
506
+ ```tsx
507
+ import { useState } from 'react'
508
+ import { RadioButton } from '@emporix/component-library'
509
+
510
+ function ContentTypePicker() {
511
+ const [contentType, setContentType] = useState('standard')
512
+
513
+ return (
514
+ <div style={{ display: 'flex', gap: '1.5rem' }}>
515
+ <RadioButton
516
+ name='content-type'
517
+ inputId='content-standard'
518
+ value='standard'
519
+ label='Standard'
520
+ checked={contentType === 'standard'}
521
+ onChange={e => setContentType(String(e.value))}
522
+ />
523
+ <RadioButton
524
+ name='content-type'
525
+ inputId='content-templates'
526
+ value='templates'
527
+ label='Templates'
528
+ checked={contentType === 'templates'}
529
+ onChange={e => setContentType(String(e.value))}
530
+ />
531
+ <RadioButton
532
+ name='content-type'
533
+ inputId='content-service'
534
+ value='service'
535
+ label='Service'
536
+ checked={contentType === 'service'}
537
+ onChange={e => setContentType(String(e.value))}
538
+ />
539
+ <RadioButton
540
+ name='content-type'
541
+ inputId='content-vendor'
542
+ value='vendor'
543
+ label='Vendor'
544
+ checked={contentType === 'vendor'}
545
+ onChange={e => setContentType(String(e.value))}
546
+ />
547
+ </div>
548
+ )
549
+ }
550
+ ```
551
+
552
+ #### Props
553
+
554
+ | Prop | Type | Default | Description |
555
+ | ----------- | ------------------------ | ------- | -------------------------------------------------------- |
556
+ | inputId | string | - | id for the native input (auto-generated if omitted) |
557
+ | name | string | - | Shared name for radios in the same group (required) |
558
+ | value | unknown | - | Value of this radio option |
559
+ | checked | boolean | false | Whether this option is selected (controlled) |
560
+ | onChange | (e: ChangeEvent) => void | - | Callback when selected; `e.value` is this option's value |
561
+ | disabled | boolean | false | Whether the radio is disabled |
562
+ | label | ReactNode | - | Optional label beside the control |
563
+ | className | string | - | Additional CSS class for the root |
564
+ | data-testid | string | - | Test ID for root and input |
565
+
255
566
  ### Tabs
256
567
 
257
568
  A flexible tabs component for organizing content into multiple panels.
@@ -307,6 +618,35 @@ const tabs: TabItem[] = [
307
618
  | label | string | Display label for the tab |
308
619
  | content | ReactNode | Content to display when active |
309
620
 
621
+ ### Menu
622
+
623
+ Popup and inline action menus. Wraps [PrimeReact Menu](https://primereact.org/menu/) with scoped Emporix styles.
624
+
625
+ ```tsx
626
+ import { useRef } from 'react'
627
+ import { Menu, type MenuRef, PrimaryButton } from '@emporix/component-library'
628
+
629
+ function RowActionsMenu() {
630
+ const menuRef = useRef<MenuRef>(null)
631
+
632
+ return (
633
+ <>
634
+ <PrimaryButton onClick={e => menuRef.current?.toggle(e)}>
635
+ Actions
636
+ </PrimaryButton>
637
+ <Menu
638
+ ref={menuRef}
639
+ popup
640
+ model={[
641
+ { label: 'Edit', command: () => onEdit() },
642
+ { label: 'Delete', disabled: true },
643
+ ]}
644
+ />
645
+ </>
646
+ )
647
+ }
648
+ ```
649
+
310
650
  ### Tooltip
311
651
 
312
652
  Floating overlays on hover or focus, similar to [PrimeReact Tooltip](https://primereact.org/tooltip/). Use **children mode** to wrap a button, input, or other component, or **selector mode** with a CSS `target` and `data-pr-tooltip` / `data-pr-position` on matching elements.
@@ -356,6 +696,43 @@ import { Tooltip } from '@emporix/component-library'
356
696
 
357
697
  Selector targets can override position per element with `data-pr-position`. Escape closes the tooltip.
358
698
 
699
+ ### Message
700
+
701
+ Inline alert banners for contextual feedback, similar to [PrimeReact Message](https://primereact.org/message/). Use `text` for plain copy or `children` for richer content. Default severity icons come from `react-icons`.
702
+
703
+ ```tsx
704
+ import { Message } from '@emporix/component-library'
705
+
706
+ // Predefined entity warning (management-dashboard pattern)
707
+ {isPredefined && (
708
+ <Message
709
+ severity="info"
710
+ text="This group is predefined and cannot be modified."
711
+ />
712
+ )}
713
+
714
+ // Other severities
715
+ <Message severity="success" text="Your changes were saved." />
716
+ <Message severity="warn" text="Review settings before continuing." />
717
+ <Message severity="error" text="Unable to complete the request." />
718
+
719
+ // Rich content
720
+ <Message severity="info">
721
+ <strong>Note:</strong> editing is disabled for system groups.
722
+ </Message>
723
+ ```
724
+
725
+ #### Props
726
+
727
+ | Prop | Type | Default | Description |
728
+ | ----------- | ---------------------------------------- | ------- | ----------------------------------------------- |
729
+ | severity | `info` \| `success` \| `warn` \| `error` | `info` | Visual severity of the banner |
730
+ | text | string | - | Plain text content; ignored when `children` set |
731
+ | children | ReactNode | - | Rich message body |
732
+ | icon | ReactNode | - | Custom icon; default icon shown per severity |
733
+ | className | string | - | Additional CSS class on the root element |
734
+ | data-testid | string | - | Test ID for testing |
735
+
359
736
  ### Accordion
360
737
 
361
738
  Collapsible content panels grouped in tabs.
@@ -485,7 +862,7 @@ The component library provides a minimal set of CSS variables that are actually
485
862
 
486
863
  #### Focus Ring
487
864
 
488
- Reusable focus outline for inputs, dropdowns, SelectButton, etc. Override to change focus appearance globally.
865
+ Reusable focus outline for inputs, dropdowns, SelectButton, RadioButton, etc. Override to change focus appearance globally.
489
866
 
490
867
  ```css
491
868
  --focus-ring-box-shadow: 0 0 0 2px rgba(38, 101, 183, 0.35);
@@ -498,6 +875,23 @@ Reusable focus outline for inputs, dropdowns, SelectButton, etc. Override to cha
498
875
  --color-tooltip-text: #ffffff;
499
876
  ```
500
877
 
878
+ #### Message
879
+
880
+ ```css
881
+ --color-message-info-bg: #e9e9ff;
882
+ --color-message-info-border: #696cff;
883
+ --color-message-info-icon: #696cff;
884
+ --color-message-success-bg: #e4f8f0;
885
+ --color-message-success-border: #1ea97c;
886
+ --color-message-success-icon: #1ea97c;
887
+ --color-message-warn-bg: #fff2e2;
888
+ --color-message-warn-border: #cc8925;
889
+ --color-message-warn-icon: #cc8925;
890
+ --color-message-error-bg: #ffe7e6;
891
+ --color-message-error-border: #ff5757;
892
+ --color-message-error-icon: #ff5757;
893
+ ```
894
+
501
895
  #### Spacing
502
896
 
503
897
  ```css
@@ -611,6 +1005,7 @@ npm run storybook
611
1005
  - `npm run test:coverage` - Run tests with coverage
612
1006
  - `npm run storybook` - Start Storybook
613
1007
  - `npm run build-storybook` - Build Storybook
1008
+ - `npm run build:pages` - Build showcase and Storybook for GitHub Pages
614
1009
  - `npm run lint` - Run ESLint
615
1010
  - `npm run lint:fix` - Fix ESLint issues
616
1011
  - `npm run type-check` - Run TypeScript type checking
@@ -660,6 +1055,54 @@ The build output includes:
660
1055
  - TypeScript declarations (`index.d.ts`)
661
1056
  - CSS styles (`styles.css`)
662
1057
 
1058
+ ## Publishing
1059
+
1060
+ Releases are automated via GitHub Actions when you push a version tag. Pushing a tag triggers:
1061
+
1062
+ 1. **npm publish** — builds the library (`npm run build:lib`) and publishes `@emporix/component-library` to the npm registry
1063
+ 2. **GitHub Pages** — builds the showcase app (`npm run dev`) and static Storybook, then deploys both sites
1064
+
1065
+ ### Live sites
1066
+
1067
+ After a successful release:
1068
+
1069
+ | Site | URL |
1070
+ | ------------------ | ------------------------------------------------------ |
1071
+ | Showcase (dev app) | https://emporix.github.io/component-library/ |
1072
+ | Storybook | https://emporix.github.io/component-library/storybook/ |
1073
+
1074
+ ### One-time setup
1075
+
1076
+ In the GitHub repository, go to **Settings → Pages** and set **Source** to **GitHub Actions**.
1077
+
1078
+ npm publishing uses [trusted publishing](https://docs.npmjs.com/trusted-publishers) (OIDC) — ensure the npm package is configured to trust this repository’s `publish.yml` workflow.
1079
+
1080
+ ### Release steps
1081
+
1082
+ 1. **Bump the version** in `package.json` (and `package-lock.json` via `npm install` if needed):
1083
+ - **Minor** (`1.7.1` → `1.8.0`) for backward-compatible features
1084
+ - **Major** (`1.7.1` → `2.0.0`) for breaking changes
1085
+ - **Patch** (`1.7.1` → `1.7.2`) for bug fixes only
1086
+ 2. **Merge** the version bump to the default branch.
1087
+ 3. **Create and push a tag** that matches `package.json` exactly (prefix with `v`):
1088
+
1089
+ ```bash
1090
+ # Example: package.json version is 1.10.0
1091
+ git tag v1.10.0
1092
+ git push origin v1.10.0
1093
+ ```
1094
+
1095
+ The tag must match the format `v{semver}` (e.g. `v1.2.3`). CI rejects tags that do not match `package.json`.
1096
+
1097
+ ### Preview GitHub Pages locally
1098
+
1099
+ ```bash
1100
+ npm run build:pages
1101
+ npx serve gh-pages
1102
+ ```
1103
+
1104
+ Open http://localhost:3000/component-library/ (showcase) and http://localhost:3000/component-library/storybook/ (Storybook).
1105
+
663
1106
  ## Code Formatting
664
1107
 
665
1108
  This project uses Prettier for consistent code formatting. The configuration is defined in `.prettierrc`.
@@ -674,6 +1117,72 @@ npm run format:check
674
1117
 
675
1118
  The project also includes pre-commit hooks that automatically format staged files before commits.
676
1119
 
1120
+ ## Migrating components from management-dashboard (Cursor skill)
1121
+
1122
+ This repository includes a **Cursor Agent Skill** that guides extracting shared UI from [management-dashboard](https://github.com/emporix/management-dashboard) into `@emporix/component-library`. It covers audits, implementation patterns, CSS encapsulation, MD thin wrappers, tests, and rollout.
1123
+
1124
+ **Skill location:** [`.cursor/skills/migrate-to-component-library/`](.cursor/skills/migrate-to-component-library/)
1125
+
1126
+ | File | Purpose |
1127
+ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
1128
+ | [`SKILL.md`](.cursor/skills/migrate-to-component-library/SKILL.md) | Step-by-step workflow (phases, checklists, anti-patterns) |
1129
+ | [`reference.md`](.cursor/skills/migrate-to-component-library/reference.md) | Code templates, token mapping, Jira ticket outline, verification checklist |
1130
+
1131
+ Related Cursor rules: [`.cursor/rules/component-development.mdc`](.cursor/rules/component-development.mdc), [`.cursor/rules/version-bump-for-features.mdc`](.cursor/rules/version-bump-for-features.mdc).
1132
+
1133
+ ### When to use it
1134
+
1135
+ Use the skill when you:
1136
+
1137
+ - Move or extract a component from management-dashboard into this library
1138
+ - Migrate PrimeReact-based MD components (e.g. tables, dialogs) with scoped styles
1139
+ - Work on [COP-5597 MD Modularization](https://emporix.atlassian.net/browse/COP-5597) stories
1140
+
1141
+ **Reference migration:** `DataTable` (from MD `MdDataTable`) — library export is `DataTable`; MD keeps the existing `MdDataTable` implementation unchanged. Pilot screens import `DataTable` directly from `@emporix/component-library` (or use a thin `Md*` wrapper if preferred).
1142
+
1143
+ ### How to invoke the skill in Cursor
1144
+
1145
+ **Option 1 — Mention the skill in chat (recommended)**
1146
+
1147
+ ```
1148
+ Migrate [ComponentName] from management-dashboard to component-library
1149
+ using the migrate-to-component-library skill.
1150
+ ```
1151
+
1152
+ **Option 2 — Reference by name**
1153
+
1154
+ Ask Cursor to read and follow `migrate-to-component-library` before starting the task.
1155
+
1156
+ **Option 3 — Explicit file reference**
1157
+
1158
+ ```
1159
+ Follow .cursor/skills/migrate-to-component-library/SKILL.md to migrate X.
1160
+ ```
1161
+
1162
+ Cursor loads the skill automatically when your request matches its description (component extraction, MD → library migration, COP modularization).
1163
+
1164
+ ### What the skill walks you through
1165
+
1166
+ 1. **Audit** — find consumers, related SCSS, and PrimeReact dependencies in MD
1167
+ 2. **Ask you to choose a pattern** (required before any implementation)
1168
+ - **Pattern A (custom):** boilerplate + SCSS modules + **same API as PrimeReact** — e.g. `Dropdown`, `InputText`, `SelectButton` (no `primereact` dependency)
1169
+ - **Pattern B (PrimeReact wrapper):** encapsulated `primereact/*` + scoped overrides — e.g. `Toast`, `DataTable`
1170
+ 3. **Implement in component-library** — component folder, tests, Storybook, exports, version bump
1171
+ 4. **Wire consumer app** — import library component directly in pilot views **or** add a thin `Md*` wrapper; leave existing `Md*` unchanged for unmigrated screens; import `@emporix/component-library/styles`
1172
+ 5. **Verify** — `npm run lint`, `npm run test -- --run`, `npm run build:lib` (library); build and manual QA in MD
1173
+
1174
+ See [`reference.md`](.cursor/skills/migrate-to-component-library/reference.md) for copy-paste templates (`MdDataTable.tsx` wrapper, `PrimeDataTableOverrides.module.scss`, Jira acceptance criteria).
1175
+
1176
+ ### Naming convention (library vs MD)
1177
+
1178
+ | Layer | Name | Example |
1179
+ | ----------------------- | --------------------------------------- | ---------------------------------------------------------------------- |
1180
+ | Component library | Generic, reusable name | `DataTable`, `PrimaryButton` |
1181
+ | Consumer app (existing) | Keep original `Md*` component unchanged | `MdDataTable` (legacy implementation) |
1182
+ | Consumer app (pilot) | Direct library import or thin wrapper | `import { DataTable } from '@emporix/component-library'` in pilot view |
1183
+
1184
+ This keeps existing import paths stable (`import MdDataTable from 'components/MdDataTable'`) while pilot screens opt in via direct library import or an optional wrapper.
1185
+
677
1186
  ## Contributing
678
1187
 
679
1188
  1. Fork the repository
@@ -0,0 +1,40 @@
1
+ import { default as React } from 'react';
2
+ export interface AutoCompleteCompleteEvent {
3
+ query: string;
4
+ }
5
+ export interface AutoCompleteChangeEvent {
6
+ value: string;
7
+ originalEvent: React.SyntheticEvent;
8
+ }
9
+ export interface AutoCompleteSelectEvent<T> {
10
+ value: T;
11
+ originalEvent: React.SyntheticEvent;
12
+ }
13
+ export interface AutoCompleteProps<T extends Record<string, unknown>> {
14
+ /** Display text in the input (controlled). */
15
+ value: string;
16
+ /** Suggestion list from the parent (updated via completeMethod). */
17
+ suggestions: T[];
18
+ /** Called when the user types; parent should fetch/filter suggestions. */
19
+ completeMethod: (e: AutoCompleteCompleteEvent) => void;
20
+ /** Property on suggestion objects used for display (default: first string field). */
21
+ field?: keyof T | string;
22
+ /** Fired when the input text changes. */
23
+ onChange: (e: AutoCompleteChangeEvent) => void;
24
+ /** Fired when a suggestion is selected. */
25
+ onSelect?: (e: AutoCompleteSelectEvent<T>) => void;
26
+ /** Show dropdown button to open suggestions. */
27
+ dropdown?: boolean;
28
+ disabled?: boolean;
29
+ placeholder?: string;
30
+ label?: React.ReactNode;
31
+ error?: React.ReactNode;
32
+ className?: string;
33
+ inputId?: string;
34
+ 'data-testid'?: string;
35
+ }
36
+ export declare const AutoComplete: {
37
+ <T extends Record<string, unknown>>({ value, suggestions, completeMethod, field, onChange, onSelect, dropdown, disabled, placeholder, label, error, className, inputId: inputIdProp, "data-testid": testId, }: AutoCompleteProps<T>): import("react/jsx-runtime").JSX.Element;
38
+ displayName: string;
39
+ };
40
+ //# sourceMappingURL=AutoComplete.d.ts.map