@ssa-ui-kit/core 3.16.2 → 3.16.3

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.
@@ -23,12 +23,22 @@ export declare const usePaginationContext: () => PaginationContextProps;
23
23
  *
24
24
  * @example
25
25
  * ```tsx
26
+ * // Uncontrolled
26
27
  * <PaginationContextProvider selectedPage={1} defaultPerPage={25}>
27
28
  * <Pagination pagesCount={10} />
28
29
  * </PaginationContextProvider>
29
30
  * ```
30
31
  *
32
+ * @example
33
+ * ```tsx
34
+ * // Controlled - parent owns page/perPage state
35
+ * const [page, setPage] = useState(1);
36
+ * <PaginationContextProvider page={page} onPageChange={setPage}>
37
+ * <Pagination pagesCount={10} />
38
+ * </PaginationContextProvider>
39
+ * ```
40
+ *
31
41
  * @see {@link Pagination} - Child component that uses this context
32
42
  * @see {@link usePaginationContext} - Hook to access context values
33
43
  */
34
- export declare const PaginationContextProvider: ({ selectedPage, defaultPerPage, children, }: PaginationContextProviderProps) => import("@emotion/react/jsx-runtime").JSX.Element;
44
+ export declare const PaginationContextProvider: ({ selectedPage, defaultPerPage, page: controlledPage, perPage: controlledPerPage, onPageChange, onPerPageChange, children, }: PaginationContextProviderProps) => import("@emotion/react/jsx-runtime").JSX.Element;
@@ -30,6 +30,7 @@ export interface RowsPerPageDropdownProps extends CommonProps {
30
30
  /**
31
31
  * Currently selected number of rows per page
32
32
  * Must match a value in rowsPerPageList
33
+ * @default the `perPage` value from PaginationContextProvider
33
34
  */
34
35
  selectedItem?: number;
35
36
  /**
@@ -0,0 +1 @@
1
+ export * from './useControllableState';
@@ -0,0 +1,37 @@
1
+ import { Dispatch, SetStateAction } from 'react';
2
+ interface UseControllableStateProps<T> {
3
+ /**
4
+ * Controlled value. When provided (not `undefined`), the hook always
5
+ * reflects this value and never writes to its own internal state.
6
+ */
7
+ value?: T;
8
+ /**
9
+ * Initial value used for internal state when `value` is `undefined`
10
+ * (uncontrolled mode).
11
+ */
12
+ defaultValue: T;
13
+ /**
14
+ * Called with the next value whenever the setter is invoked, whether
15
+ * controlled or uncontrolled.
16
+ */
17
+ onChange?: (value: T) => void;
18
+ /**
19
+ * Name used in the dev-mode warning when a component switches between
20
+ * controlled and uncontrolled across renders.
21
+ */
22
+ name?: string;
23
+ }
24
+ /**
25
+ * useControllableState - Backs a value that can be either controlled by a
26
+ * parent (via `value`/`onChange`) or managed internally (via `defaultValue`).
27
+ *
28
+ * Mirrors the standard React controlled/uncontrolled input pattern: passing
29
+ * `value` opts into controlled mode, where the returned value always matches
30
+ * the prop and the setter only calls `onChange` (no internal state is
31
+ * written). Omitting `value` falls back to internal state seeded from
32
+ * `defaultValue`.
33
+ *
34
+ * @internal
35
+ */
36
+ export declare const useControllableState: <T>({ value: controlledValue, defaultValue, onChange, name, }: UseControllableStateProps<T>) => [T, Dispatch<SetStateAction<T>>];
37
+ export {};
@@ -210,21 +210,59 @@ export interface PaginationContextProps {
210
210
  *
211
211
  * @example
212
212
  * ```tsx
213
+ * // Uncontrolled - provider manages its own state
213
214
  * <PaginationContextProvider selectedPage={1} defaultPerPage={25}>
214
215
  * <Pagination pagesCount={10} />
215
216
  * </PaginationContextProvider>
216
217
  * ```
218
+ *
219
+ * @example
220
+ * ```tsx
221
+ * // Controlled - parent owns page/perPage state
222
+ * const [page, setPage] = useState(1);
223
+ * <PaginationContextProvider page={page} onPageChange={setPage}>
224
+ * <Pagination pagesCount={10} />
225
+ * </PaginationContextProvider>
226
+ * ```
217
227
  */
218
228
  export interface PaginationContextProviderProps {
219
229
  /**
220
230
  * Initial selected page number (1-indexed)
231
+ * Ignored once `page` is provided (controlled mode)
221
232
  */
222
233
  selectedPage?: number;
223
234
  /**
224
235
  * Default number of items per page
236
+ * Ignored once `perPage` is provided (controlled mode)
225
237
  * @default 10
226
238
  */
227
239
  defaultPerPage?: number;
240
+ /**
241
+ * Controlled current page number (1-indexed)
242
+ * When provided, the provider stops managing page state internally and
243
+ * always reflects this value; pair with `onPageChange` to react to
244
+ * navigation.
245
+ */
246
+ page?: number;
247
+ /**
248
+ * Controlled number of items per page
249
+ * When provided, the provider stops managing perPage state internally and
250
+ * always reflects this value; pair with `onPerPageChange` to react to
251
+ * changes.
252
+ */
253
+ perPage?: number;
254
+ /**
255
+ * Called whenever the page changes (arrow clicks, page buttons, manual
256
+ * page input). Required to actually change the page when `page` is
257
+ * controlled, since the provider no longer updates its own state.
258
+ */
259
+ onPageChange?: (page: number) => void;
260
+ /**
261
+ * Called whenever perPage changes (rows per page dropdown). Required to
262
+ * actually change perPage when `perPage` is controlled, since the
263
+ * provider no longer updates its own state.
264
+ */
265
+ onPerPageChange?: (perPage: number) => void;
228
266
  /**
229
267
  * Child components that use pagination context
230
268
  * Must include Pagination component
package/dist/index.js CHANGED
@@ -54353,10 +54353,47 @@ const ROWS_PER_PAGE_LIST = [{
54353
54353
  }];
54354
54354
  const DEFAULT_SELECTED_INDEX = 1;
54355
54355
  const DEFAULT_PER_PAGE_VALUE = ROWS_PER_PAGE_LIST[DEFAULT_SELECTED_INDEX].value;
54356
+ ;// ./src/components/Pagination/hooks/useControllableState.ts
54357
+
54358
+ /**
54359
+ * useControllableState - Backs a value that can be either controlled by a
54360
+ * parent (via `value`/`onChange`) or managed internally (via `defaultValue`).
54361
+ *
54362
+ * Mirrors the standard React controlled/uncontrolled input pattern: passing
54363
+ * `value` opts into controlled mode, where the returned value always matches
54364
+ * the prop and the setter only calls `onChange` (no internal state is
54365
+ * written). Omitting `value` falls back to internal state seeded from
54366
+ * `defaultValue`.
54367
+ *
54368
+ * @internal
54369
+ */
54370
+ const useControllableState = ({
54371
+ value: controlledValue,
54372
+ defaultValue,
54373
+ onChange,
54374
+ name = 'value'
54375
+ }) => {
54376
+ const [uncontrolledValue, setUncontrolledValue] = (0,external_react_namespaceObject.useState)(defaultValue);
54377
+ const isControlled = controlledValue !== undefined;
54378
+ const value = isControlled ? controlledValue : uncontrolledValue;
54379
+ const isControlledRef = (0,external_react_namespaceObject.useRef)(isControlled);
54380
+ if (false) // removed by dead control flow
54381
+ {}
54382
+ isControlledRef.current = isControlled;
54383
+ const setValue = (0,external_react_namespaceObject.useCallback)(next => {
54384
+ const resolved = typeof next === 'function' ? next(value) : next;
54385
+ if (!isControlled) {
54386
+ setUncontrolledValue(resolved);
54387
+ }
54388
+ onChange?.(resolved);
54389
+ }, [isControlled, onChange, value]);
54390
+ return [value, setValue];
54391
+ };
54356
54392
  ;// ./src/components/Pagination/PaginationContext.tsx
54357
54393
 
54358
54394
 
54359
54395
 
54396
+
54360
54397
  /**
54361
54398
  * Pagination context
54362
54399
  * Provides page state and navigation functions to child components
@@ -54384,21 +54421,53 @@ const usePaginationContext = () => (0,external_react_namespaceObject.useContext)
54384
54421
  *
54385
54422
  * @example
54386
54423
  * ```tsx
54424
+ * // Uncontrolled
54387
54425
  * <PaginationContextProvider selectedPage={1} defaultPerPage={25}>
54388
54426
  * <Pagination pagesCount={10} />
54389
54427
  * </PaginationContextProvider>
54390
54428
  * ```
54391
54429
  *
54430
+ * @example
54431
+ * ```tsx
54432
+ * // Controlled - parent owns page/perPage state
54433
+ * const [page, setPage] = useState(1);
54434
+ * <PaginationContextProvider page={page} onPageChange={setPage}>
54435
+ * <Pagination pagesCount={10} />
54436
+ * </PaginationContextProvider>
54437
+ * ```
54438
+ *
54392
54439
  * @see {@link Pagination} - Child component that uses this context
54393
54440
  * @see {@link usePaginationContext} - Hook to access context values
54394
54441
  */
54395
54442
  const PaginationContextProvider = ({
54396
54443
  selectedPage,
54397
54444
  defaultPerPage = DEFAULT_PER_PAGE_VALUE,
54445
+ page: controlledPage,
54446
+ perPage: controlledPerPage,
54447
+ onPageChange,
54448
+ onPerPageChange,
54398
54449
  children
54399
54450
  }) => {
54400
- const [perPage, setPerPage] = (0,external_react_namespaceObject.useState)(defaultPerPage);
54401
- const [page, setPage] = (0,external_react_namespaceObject.useState)(selectedPage);
54451
+ // `page` can be `undefined` (no page selected yet), but the public
54452
+ // `onPageChange` callback only ever needs to handle real page numbers -
54453
+ // Pagination never navigates to an undefined page.
54454
+ const handlePageChange = (0,external_react_namespaceObject.useCallback)(value => {
54455
+ if (value !== undefined) {
54456
+ onPageChange?.(value);
54457
+ }
54458
+ }, [onPageChange]);
54459
+ const [page, setPage] = useControllableState({
54460
+ value: controlledPage,
54461
+ defaultValue: selectedPage,
54462
+ onChange: handlePageChange,
54463
+ name: 'page'
54464
+ });
54465
+ const [perPage, setPerPage] = useControllableState({
54466
+ value: controlledPerPage,
54467
+ defaultValue: defaultPerPage,
54468
+ onChange: onPerPageChange,
54469
+ name: 'perPage'
54470
+ });
54402
54471
  return (0,jsx_runtime_namespaceObject.jsx)(PaginationContext.Provider, {
54403
54472
  value: {
54404
54473
  page,
@@ -54461,7 +54530,7 @@ const PaginationContextProvider = ({
54461
54530
  */
54462
54531
 
54463
54532
  const RowsPerPageDropdown = ({
54464
- selectedItem = DEFAULT_PER_PAGE_VALUE,
54533
+ selectedItem,
54465
54534
  rowsPerPageList = ROWS_PER_PAGE_LIST,
54466
54535
  rowsPerPageText = 'Rows per page',
54467
54536
  dropdownPosition,
@@ -54469,11 +54538,12 @@ const RowsPerPageDropdown = ({
54469
54538
  }) => {
54470
54539
  const theme = (0,react_namespaceObject.useTheme)();
54471
54540
  const {
54541
+ perPage,
54472
54542
  setPerPage
54473
54543
  } = usePaginationContext();
54474
54544
  const selectedItemForDropdown = rowsPerPageList.find(({
54475
54545
  value
54476
- }) => value === selectedItem) || rowsPerPageList[0];
54546
+ }) => value === (selectedItem ?? perPage)) || rowsPerPageList[0];
54477
54547
  const onChange = ({
54478
54548
  value
54479
54549
  }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssa-ui-kit/core",
3
- "version": "3.16.2",
3
+ "version": "3.16.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {
@@ -39,8 +39,8 @@
39
39
  "luxon": "3.5.0",
40
40
  "plotly.js": "3.0.0",
41
41
  "react-plotly.js": "2.6.0",
42
- "@ssa-ui-kit/utils": "^3.16.2",
43
- "@ssa-ui-kit/hooks": "^3.16.2"
42
+ "@ssa-ui-kit/hooks": "^3.16.3",
43
+ "@ssa-ui-kit/utils": "^3.16.3"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@emotion/css": "11.13.5",