@uxf/core-react 11.125.0 → 11.126.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/README.md CHANGED
@@ -1,28 +1,27 @@
1
1
  # UXF Core-React
2
2
 
3
3
  ## Components
4
+
4
5
  ---
5
6
 
6
7
  ### Hide
7
8
 
8
9
  Conditionally hide some jsx content.
10
+
9
11
  ```tsx
10
12
  import { Hide } from "@uxf/core-react/components/hide";
11
13
 
12
- <Hide when={SOME_CONDITION}>
13
- ...some content
14
- </Hide>
14
+ <Hide when={SOME_CONDITION}>...some content</Hide>;
15
15
  ```
16
16
 
17
17
  ### Show
18
18
 
19
19
  Conditionally show some jsx content.
20
+
20
21
  ```tsx
21
22
  import { Show } from "@uxf/core-react/components/show";
22
23
 
23
- <Show when={SOME_CONDITION}>
24
- ...some content
25
- </Show>
24
+ <Show when={SOME_CONDITION}>...some content</Show>;
26
25
  ```
27
26
 
28
27
  ### ViewportHeightPolyfill
@@ -30,13 +29,15 @@ import { Show } from "@uxf/core-react/components/show";
30
29
  Polyfill for custom css variable `--viewport-height` to mimic functionality of browser's [dynamic viewport height](https://web.dev/blog/viewport-units).
31
30
 
32
31
  Add component to react app root (eg. `_app.tsx`).
32
+
33
33
  ```tsx
34
34
  import { ViewportHeightPolyfill } from "@uxf/core-react/components/viewport-height-polyfill";
35
35
 
36
- <ViewportHeightPolyfill />
36
+ <ViewportHeightPolyfill />;
37
37
  ```
38
38
 
39
39
  Add css variable declaration with fallback to app global styles (eg. `base.css`) if already not there.
40
+
40
41
  ```css
41
42
  :root {
42
43
  --viewport-height: 100vh;
@@ -48,10 +49,13 @@ Add css variable declaration with fallback to app global styles (eg. `base.css`)
48
49
  ```
49
50
 
50
51
  ## Hooks
52
+
51
53
  ---
54
+
52
55
  ### useBodyScrollLock
53
56
 
54
57
  Lock scrolling on body element. Useful for modals, popovers, etc.
58
+
55
59
  ```tsx
56
60
  import { useBodyScrollLock } from "@uxf/core-react/hooks/use-body-scroll-lock";
57
61
  import { useState } from "react";
@@ -62,32 +66,49 @@ const [isOpen, setIsOpen] = useState<boolean>();
62
66
  const clearAllOnclose = false;
63
67
 
64
68
  useBodyScrollLock<HTMLDivElement>(innerRef, isOpen, {
65
- allowTouchMove: undefined, // https://github.com/willmcpo/body-scroll-lock#allowtouchmove
66
- clearAllOnClose: false, // optionally call clearAllBodyScrollLocks method on unmount
67
- reserveScrollBarGap: undefined, // https://github.com/willmcpo/body-scroll-lock#reservescrollbargap
69
+ allowTouchMove: undefined, // https://github.com/willmcpo/body-scroll-lock#allowtouchmove
70
+ clearAllOnClose: false, // optionally call clearAllBodyScrollLocks method on unmount
71
+ reserveScrollBarGap: undefined, // https://github.com/willmcpo/body-scroll-lock#reservescrollbargap
68
72
  });
69
73
 
70
- <div ref={innerRef}>Element which activates scroll lock on its parent elements.</div>
74
+ <div ref={innerRef}>Element which activates scroll lock on its parent elements.</div>;
71
75
  ```
76
+
72
77
  ---
78
+
73
79
  ### isMounted
80
+
74
81
  Check if component is mounted.
82
+
75
83
  ```tsx
76
84
  import { useIsMounted } from "@uxf/core-react/hooks/use-is-mounted";
77
85
 
78
86
  const isMounted = useIsMounted();
79
87
  ```
88
+
80
89
  ---
90
+
81
91
  ### useIsomorphicLayoutEffect
92
+
82
93
  Returns `useEffect` on client and `useLayoutEffect` on server.
94
+
83
95
  ```tsx
84
96
  import { useIsomorphicLayoutEffect } from "@uxf/core-react/hooks/use-isomorphic-layout-effect";
85
97
 
86
- useIsomorphicLayoutEffect(() => {/* code */}, [/* deps */]);
98
+ useIsomorphicLayoutEffect(
99
+ () => {
100
+ /* code */
101
+ },
102
+ [/* deps */],
103
+ );
87
104
  ```
105
+
88
106
  ---
107
+
89
108
  ### useKey
109
+
90
110
  Trigger callback on given key.
111
+
91
112
  ```tsx
92
113
  import { useKey } from "@uxf/core-react/hooks/use-key";
93
114
  import { useRef } from "react";
@@ -96,19 +117,24 @@ const targetRef = useRef<HTMLDivElement>(null);
96
117
  const disabled = false; // eg. for passing disabled state
97
118
 
98
119
  useKey<HTMLDivElement>("Enter", () => console.log("callback"), {
99
- disabled,
100
- targetRef, // if not provided, then `document` will be used
101
- type: "keydown"
120
+ disabled,
121
+ targetRef, // if not provided, then `document` will be used
122
+ type: "keydown",
102
123
  });
103
124
 
104
- <div ref={targetRef} tabIndex={0}>Element with callback triggerable by enter key.</div>
125
+ <div ref={targetRef} tabIndex={0}>
126
+ Element with callback triggerable by enter key.
127
+ </div>;
105
128
  ```
129
+
106
130
  ---
131
+
107
132
  ### useMinWindowWidth
108
133
 
109
134
  > **Deprecated** — Use `useMediaQuery` instead.
110
135
 
111
136
  Returns boolean if window width is equal or greater than given value.
137
+
112
138
  ```tsx
113
139
  import { useMinWindowWidth } from "@uxf/core-react/hooks/use-min-window-width";
114
140
 
@@ -118,25 +144,37 @@ const isDesktopWithDebounce = useMinWindowWidth(1200, 200); // will be updated e
118
144
  const example = isDesktop ? "desktop" : "tablet";
119
145
  const debouncedExample = isDesktopWithDebounce ? "debouncedDesktop" : "debouncedTablet";
120
146
  ```
147
+
121
148
  ---
149
+
122
150
  ### usePagination
151
+
123
152
  Returns array of pagination items.
153
+
124
154
  ```ts
125
155
  import { usePagination } from "@uxf/core-react/hooks/use-pagination";
126
156
 
127
- const paginationItems = usePagination({ page: 1, count: 10 })
157
+ const paginationItems = usePagination({ page: 1, count: 10 });
128
158
  ```
159
+
129
160
  ---
161
+
130
162
  ### useRafState
163
+
131
164
  Updates state only in the callback of `requestAnimationFrame`.
165
+
132
166
  ```tsx
133
167
  import { useRafState } from "@uxf/core-react/hooks/use-raf-state";
134
168
 
135
169
  const [state, setState] = useRafState<boolean>(false);
136
170
  ```
171
+
137
172
  ---
173
+
138
174
  ### useOnMount
175
+
139
176
  Calls the callback on component mount.
177
+
140
178
  ```tsx
141
179
  import { useOnUnmount } from "@uxf/core-react/hooks/use-on-unmount";
142
180
 
@@ -144,17 +182,30 @@ const exampleCallback = () => {};
144
182
 
145
183
  useOnUnmount(exampleCallback());
146
184
  ```
185
+
147
186
  ---
187
+
148
188
  ### useOnUpdate
189
+
149
190
  Calls the callback only on component update, except initial mount.
191
+
150
192
  ```tsx
151
193
  import { useOnUpdate } from "@uxf/core-react/hooks/use-on-update";
152
194
 
153
- useOnUpdate(() => {/* code */}, [/* deps */]);
195
+ useOnUpdate(
196
+ () => {
197
+ /* code */
198
+ },
199
+ [/* deps */],
200
+ );
154
201
  ```
202
+
155
203
  ---
204
+
156
205
  ### useWindowScroll
206
+
157
207
  Returns x and y scroll coordinates of window on scroll.
208
+
158
209
  ```tsx
159
210
  import { useWindowScroll } from "@uxf/core-react/hooks/use-window-scroll";
160
211
 
@@ -162,9 +213,13 @@ const windowScroll = useWindowScroll();
162
213
 
163
214
  const example = windowScroll && windowScroll.y > 100 ? "scroled" : "on top";
164
215
  ```
216
+
165
217
  ---
218
+
166
219
  ### useWindowSize
220
+
167
221
  Returns window width and height.
222
+
168
223
  ```tsx
169
224
  import { useWindowSize } from "@uxf/core-react/hooks/use-window-size";
170
225
 
@@ -172,9 +227,13 @@ const windowSize = useWindowSize();
172
227
 
173
228
  const example = windowSize && windowSize.width > 1200 ? "desktop" : "tablet";
174
229
  ```
230
+
175
231
  ---
232
+
176
233
  ### useFocusTrap
234
+
177
235
  Locks focus inside given element.
236
+
178
237
  ```tsx
179
238
  import { useFocusTrap } from "@uxf/core-react/hooks/use-focus-trap";
180
239
  import { useState } from "react";
@@ -183,11 +242,15 @@ const [active, setActive] = useState<boolean>();
183
242
 
184
243
  const focusTrapRef = useFocusTrap(active);
185
244
 
186
- <div ref={focusTrapRef}>Element which trap focus inside if `active` is truthy.</div>
245
+ <div ref={focusTrapRef}>Element which trap focus inside if `active` is truthy.</div>;
187
246
  ```
247
+
188
248
  ---
249
+
189
250
  ### useFocusReturn
251
+
190
252
  Returns focus to last active element.
253
+
191
254
  ```tsx
192
255
  import { useFocusReturn } from "@uxf/core-react/hooks/use-focus-return";
193
256
  import { useState } from "react";
@@ -197,113 +260,128 @@ const [active, setActive] = useState<boolean>();
197
260
  // Returns focus to last active element, e.g. in Modal or Popover
198
261
  useFocusReturn(active);
199
262
  ```
263
+
200
264
  ---
265
+
201
266
  ### useAnchorProps
267
+
202
268
  Returns props for anchor element.
269
+
203
270
  ```tsx
204
271
  import { useAnchorProps } from "@uxf/core-react/clickable/use-anchor-props";
205
272
  import { AnchorHTMLAttributes } from "react";
206
273
 
207
274
  // extends <a /> by `analyticsCallback`, `disabled`, `loading`, `submit` props
208
275
  const anchorProps = useAnchorProps<AnchorHTMLAttributes<HTMLAnchorElement>>({
209
- analyticsCallback: () => console.log("analytics"),
210
- disabled: false,
211
- href: "https://www.google.com/",
212
- loading: false,
213
- onClick: () => console.log("success"),
214
- type: "submit", // simulate <button type="submit" /> function
276
+ analyticsCallback: () => console.log("analytics"),
277
+ disabled: false,
278
+ href: "https://www.google.com/",
279
+ loading: false,
280
+ onClick: () => console.log("success"),
281
+ type: "submit", // simulate <button type="submit" /> function
215
282
  });
216
283
 
217
- <a {...anchorProps}>Click me</a>
284
+ <a {...anchorProps}>Click me</a>;
218
285
 
219
286
  // example with generics
220
287
  import { UseAnchorProps, useAnchorProps } from "@uxf/core-react/clickable/use-anchor-props";
221
288
  import { AnchorHTMLAttributes } from "react";
222
289
 
223
290
  interface Props extends UseAnchorProps, AnchorHTMLAttributes<HTMLAnchorElement> {
224
- customProp?: boolean;
291
+ customProp?: boolean;
225
292
  }
226
293
 
227
294
  const anchorProps = useAnchorProps<Props>({
228
- customProp: true,
229
- loading: false,
230
- href: "https://www.google.com/",
295
+ customProp: true,
296
+ loading: false,
297
+ href: "https://www.google.com/",
231
298
  });
232
299
 
233
- <a {...anchorProps}>Click me</a>
234
-
300
+ <a {...anchorProps}>Click me</a>;
235
301
  ```
302
+
236
303
  ---
304
+
237
305
  ### useButtonProps
306
+
238
307
  Returns props for button element.
308
+
239
309
  ```tsx
240
310
  import { useButtonProps } from "@uxf/core-react/clickable/use-button-props";
241
311
  import { ButtonHTMLAttributes } from "react";
242
312
 
243
313
  // extends <button /> by `analyticsCallback` and `loading` props
244
314
  const buttonProps = useButtonProps<ButtonHTMLAttributes<HTMLButtonElement>>({
245
- analyticsCallback: () => console.log("analytics"),
246
- disabled: false,
247
- loading: false,
248
- onClick: () => console.log("success"),
249
- type: "submit",
315
+ analyticsCallback: () => console.log("analytics"),
316
+ disabled: false,
317
+ loading: false,
318
+ onClick: () => console.log("success"),
319
+ type: "submit",
250
320
  });
251
321
 
252
- <button {...buttonProps}>Click me</button>
322
+ <button {...buttonProps}>Click me</button>;
253
323
 
254
324
  // example with generics
255
325
  import { UseButtonProps, useButtonProps } from "@uxf/core-react/clickable/use-button-props";
256
326
  import { ButtonHTMLAttributes } from "react";
257
327
 
258
328
  interface Props extends UseButtonProps, ButtonHTMLAttributes<HTMLButtonElement> {
259
- customProp?: boolean;
329
+ customProp?: boolean;
260
330
  }
261
331
 
262
332
  const buttonProps = useButtonProps<Props>({
263
- customProp: true,
264
- loading: false,
265
- type: "submit",
333
+ customProp: true,
334
+ loading: false,
335
+ type: "submit",
266
336
  });
267
337
 
268
- <button {...buttonProps}>Click me</button>
338
+ <button {...buttonProps}>Click me</button>;
269
339
  ```
340
+
270
341
  ---
342
+
271
343
  ### useClickableProps
344
+
272
345
  Returns props for clickable element.
346
+
273
347
  ```tsx
274
348
  import { useClickableProps } from "@uxf/core-react/clickable/use-clickable-props";
275
349
  import { HTMLAttributes } from "react";
276
350
 
277
351
  // extends any HTML element by `analyticsCallback`, `disabled`, `loading`, `submit` props
278
352
  const clickableProps = useClickableProps<HTMLAttributes<HTMLDivElement>>({
279
- analyticsCallback: () => console.log("analytics"),
280
- disabled: false,
281
- loading: false,
282
- onClick: () => console.log("success"),
283
- type: "submit", // simulate <button type="submit" /> function
353
+ analyticsCallback: () => console.log("analytics"),
354
+ disabled: false,
355
+ loading: false,
356
+ onClick: () => console.log("success"),
357
+ type: "submit", // simulate <button type="submit" /> function
284
358
  });
285
359
 
286
- <div {...clickableProps}>Click me</div>
360
+ <div {...clickableProps}>Click me</div>;
287
361
 
288
362
  // example with generics
289
363
  import { UseClickableProps, useClickableProps } from "@uxf/core-react/clickable/use-clickable-props";
290
364
  import { HTMLAttributes } from "react";
291
365
 
292
366
  interface Props extends UseClickableProps, HTMLAttributes<HTMLDivElement> {
293
- customProp?: boolean;
367
+ customProp?: boolean;
294
368
  }
295
369
 
296
370
  const buttonProps = useClickableProps<Props>({
297
- customProp: true,
298
- hidden: false,
299
- loading: false,
371
+ customProp: true,
372
+ hidden: false,
373
+ loading: false,
300
374
  });
301
375
 
302
- <button {...buttonProps}>Click me</button>
376
+ <button {...buttonProps}>Click me</button>;
303
377
  ```
378
+
304
379
  ---
380
+
305
381
  ### useMouseDragToScroll
382
+
306
383
  Allow to scroll element by dragging mouse.
384
+
307
385
  ```tsx
308
386
  import { useMouseDragToScroll } from "@uxf/core-react/hooks/use-mouse-drag-to-scroll";
309
387
 
@@ -311,11 +389,15 @@ const targetRef = useRef<HTMLDivElement>(null);
311
389
 
312
390
  const style = useMouseDragToScroll(scrollRef);
313
391
 
314
- <div style={style}>Drag to scroll</div>
392
+ <div style={style}>Drag to scroll</div>;
315
393
  ```
394
+
316
395
  ---
396
+
317
397
  ### useInputFocus
398
+
318
399
  Manage focus states of input element.
400
+
319
401
  ```tsx
320
402
  import { useInputFocus } from "@uxf/core-react/hooks/use-input-focus";
321
403
 
@@ -328,53 +410,73 @@ const input = useInputFocus(focusRef, onBlur, onFocus);
328
410
  <button onClick={input.focus}>Focus input</button>
329
411
  <input onBlur={input.onBlur} onFocus={input.onFocus} ref={focusRef} />
330
412
  ```
413
+
331
414
  ---
415
+
332
416
  ### useLatest
417
+
333
418
  Allways returns latest value of given variable.
419
+
334
420
  ```tsx
335
421
  import { useLatest } from "@uxf/core-react/hooks/use-latest";
336
422
 
337
423
  const latestState = useLatest(someUnstableWhatever);
338
424
 
339
425
  useEffect(() => {
340
- latestState.current(); // use newest state of 'someUnstableWhatever' without affecting this effetct update
341
- }, [latestState])
426
+ latestState.current(); // use newest state of 'someUnstableWhatever' without affecting this effetct update
427
+ }, [latestState]);
342
428
  ```
429
+
343
430
  ---
431
+
344
432
  ### usePrevious
433
+
345
434
  Returns previous value of given variable.
435
+
346
436
  ```tsx
347
437
  import { usePrevious } from "@uxf/core-react/hooks/use-previous";
348
438
 
349
439
  const previousState = usePrevious(someUnstableWhatever);
350
440
 
351
441
  useEffect(() => {
352
- previousState.current(); // use state of 'someUnstableWhatever' from previous render without affecting this effetct update
353
- }, [previousState])
442
+ previousState.current(); // use state of 'someUnstableWhatever' from previous render without affecting this effetct update
443
+ }, [previousState]);
354
444
  ```
445
+
355
446
  ---
447
+
356
448
  ### useToggle
449
+
357
450
  Returns boolean state and methods to toggle it.
451
+
358
452
  ```tsx
359
453
  import { useToggle } from "@uxf/core-react/hooks/use-toggle";
360
454
 
361
455
  const [isVisible, toggleIsVisible, setVisible, setInvisible] = useToggle(false);
362
456
 
363
- <button onClick={toggleIsVisible}>Toggle visibility</button>
457
+ <button onClick={toggleIsVisible}>Toggle visibility</button>;
364
458
  ```
459
+
365
460
  ---
461
+
366
462
  ### useIncrement
463
+
367
464
  Returns number state and methods to increment, decrement and reset.
465
+
368
466
  ```tsx
369
467
  import { useIncrement } from "@uxf/core-react/hooks/use-increment";
370
468
 
371
469
  const [count, increment, decrement, reset] = useIncrement(5, 1);
372
470
 
373
- <button onClick={increment}>Toggle visibility</button>
471
+ <button onClick={increment}>Toggle visibility</button>;
374
472
  ```
473
+
375
474
  ---
475
+
376
476
  ### useDebounce
477
+
377
478
  Returns the latest value after given delay.
479
+
378
480
  ```tsx
379
481
  import { useDebounce } from "@uxf/core-react/hooks/use-debounce";
380
482
 
@@ -386,10 +488,13 @@ const debouncedValue = useDebounce<string>("some value", 300);
386
488
  ```tsx
387
489
  import { nl2br } from "@uxf/core-react/string/nl2br";
388
490
 
389
- <div>{nl2br("Hello\nWorld")}</div>
491
+ <div>{nl2br("Hello\nWorld")}</div>;
390
492
  ```
493
+
391
494
  ---
495
+
392
496
  ### useMediaQuery
497
+
393
498
  Returns whether the given media query is currently matched. Optionally accepts a callback that is called on every change.
394
499
 
395
500
  Uses `window.matchMedia` with a `change` event listener (via `AbortController`) for efficient updates.
@@ -415,9 +520,10 @@ const isDesktopClientOnly = useMediaQuery(`(min-width: ${twScreens.sm})`, undefi
415
520
  ```
416
521
 
417
522
  **Parameters:**
523
+
418
524
  - `mediaQueryString` – CSS media query string
419
- - `callback` *(optional)* – called with `(isMatching, mediaQueryString)` on every match change
420
- - `isSSR` *(optional, default: `true`)* – when `true`, initial state is `false` to avoid SSR/hydration mismatch; when `false`, initial state is read directly from `window.matchMedia` (use only in client-only components)
525
+ - `callback` _(optional)_ – called with `(isMatching, mediaQueryString)` on every match change
526
+ - `isSSR` _(optional, default: `true`)_ – when `true`, initial state is `false` to avoid SSR/hydration mismatch; when `false`, initial state is read directly from `window.matchMedia` (use only in client-only components)
421
527
 
422
528
  ## Drag and Drop (DND) Hooks
423
529
 
@@ -431,16 +537,17 @@ Low-level hook that provides the core drag-and-drop functionality. Used as a bui
431
537
  import { useSortableCore } from "@uxf/core-react/dnd/hooks/use-sortable-core";
432
538
 
433
539
  const {
434
- activeElement, // Currently dragged element
435
- setActiveElement, // Set active element manually
436
- onDragStart, // Drag start handler
437
- onDragCancel, // Drag cancel handler
438
- sensors, // DND sensors (pointer, keyboard)
439
- dropAnimationConfig // Animation configuration for drop
540
+ activeElement, // Currently dragged element
541
+ setActiveElement, // Set active element manually
542
+ onDragStart, // Drag start handler
543
+ onDragCancel, // Drag cancel handler
544
+ sensors, // DND sensors (pointer, keyboard)
545
+ dropAnimationConfig, // Animation configuration for drop
440
546
  } = useSortableCore();
441
547
  ```
442
548
 
443
549
  ---
550
+
444
551
  ### useSortableSingle
445
552
 
446
553
  Hook for implementing drag-and-drop sorting within a single list. Manages item reordering and state internally.
@@ -452,58 +559,51 @@ import { useSortableSingle } from "@uxf/core-react/dnd/hooks/use-sortable-single
452
559
  import { SortableItem } from "./sortable-item"; // Your sortable item component
453
560
 
454
561
  interface Task {
455
- id: string;
456
- title: string;
562
+ id: string;
563
+ title: string;
457
564
  }
458
565
 
459
566
  function TaskList() {
460
- const initialTasks: Task[] = [
461
- { id: "1", title: "Write documentation" },
462
- { id: "2", title: "Review PR" },
463
- { id: "3", title: "Deploy to production" }
464
- ];
465
-
466
- const {
467
- items, // Current items state
468
- setItems, // Update items manually
469
- activeItem, // Currently dragged item
470
- onDragStart,
471
- onDragEnd,
472
- onDragCancel,
473
- sensors,
474
- dropAnimationConfig
475
- } = useSortableSingle(
476
- initialTasks,
477
- (fromIndex, toIndex, updatedList) => {
478
- // Optional callback when items are reordered
479
- console.log(`Moved from ${fromIndex} to ${toIndex}`, updatedList);
480
- }
481
- );
482
-
483
- return (
484
- <DndContext
485
- sensors={sensors}
486
- onDragStart={onDragStart}
487
- onDragEnd={onDragEnd}
488
- onDragCancel={onDragCancel}
489
- >
490
- <SortableContext items={items.map(item => item.id)} strategy={verticalListSortingStrategy}>
491
- {items.map(task => (
492
- <SortableItem key={task.id} id={task.id}>
493
- {task.title}
494
- </SortableItem>
495
- ))}
496
- </SortableContext>
497
-
498
- <DragOverlay dropAnimation={dropAnimationConfig}>
499
- {activeItem ? <div>{activeItem.title}</div> : null}
500
- </DragOverlay>
501
- </DndContext>
502
- );
567
+ const initialTasks: Task[] = [
568
+ { id: "1", title: "Write documentation" },
569
+ { id: "2", title: "Review PR" },
570
+ { id: "3", title: "Deploy to production" },
571
+ ];
572
+
573
+ const {
574
+ items, // Current items state
575
+ setItems, // Update items manually
576
+ activeItem, // Currently dragged item
577
+ onDragStart,
578
+ onDragEnd,
579
+ onDragCancel,
580
+ sensors,
581
+ dropAnimationConfig,
582
+ } = useSortableSingle(initialTasks, (fromIndex, toIndex, updatedList) => {
583
+ // Optional callback when items are reordered
584
+ console.log(`Moved from ${fromIndex} to ${toIndex}`, updatedList);
585
+ });
586
+
587
+ return (
588
+ <DndContext sensors={sensors} onDragStart={onDragStart} onDragEnd={onDragEnd} onDragCancel={onDragCancel}>
589
+ <SortableContext items={items.map((item) => item.id)} strategy={verticalListSortingStrategy}>
590
+ {items.map((task) => (
591
+ <SortableItem key={task.id} id={task.id}>
592
+ {task.title}
593
+ </SortableItem>
594
+ ))}
595
+ </SortableContext>
596
+
597
+ <DragOverlay dropAnimation={dropAnimationConfig}>
598
+ {activeItem ? <div>{activeItem.title}</div> : null}
599
+ </DragOverlay>
600
+ </DndContext>
601
+ );
503
602
  }
504
603
  ```
505
604
 
506
605
  ---
606
+
507
607
  ### useSortableMulti
508
608
 
509
609
  Hook for implementing drag-and-drop between multiple sections/lists. Ideal for kanban boards, categorized lists, or visible/hidden column management.
@@ -515,89 +615,80 @@ import { useSortableMulti } from "@uxf/core-react/dnd/hooks/use-sortable-multi";
515
615
  import { SortableItem } from "./sortable-item"; // Your sortable item component
516
616
 
517
617
  interface Task {
518
- id: string;
519
- title: string;
618
+ id: string;
619
+ title: string;
520
620
  }
521
621
 
522
622
  interface Sections {
523
- todo: Task[];
524
- inProgress: Task[];
525
- done: Task[];
623
+ todo: Task[];
624
+ inProgress: Task[];
625
+ done: Task[];
526
626
  }
527
627
 
528
628
  function KanbanBoard() {
529
- const [sections, setSections] = useState<Sections>({
530
- todo: [
531
- { id: "1", title: "Design UI" },
532
- { id: "2", title: "Write tests" }
533
- ],
534
- inProgress: [
535
- { id: "3", title: "Implement feature" }
536
- ],
537
- done: [
538
- { id: "4", title: "Setup project" }
539
- ]
540
- });
541
-
542
- const {
543
- getSectionItemsIds, // Get IDs for a section (handles empty sections)
544
- activeItem, // Currently dragged item
545
- onDragStart,
546
- onDragEnd,
547
- onDragCancel,
548
- sensors,
549
- dropAnimationConfig
550
- } = useSortableMulti<Task, Sections>(
551
- sections,
552
- setSections,
553
- (sourceKey, destKey, fromIndex, toIndex, nextState) => {
554
- // Optional callback when items are moved between sections
555
- console.log(`Moved from ${String(sourceKey)} to ${String(destKey)}`);
556
- // Save to backend, analytics, etc.
557
- }
558
- );
559
-
560
- return (
561
- <DndContext
562
- sensors={sensors}
563
- collisionDetection={rectIntersection}
564
- onDragStart={onDragStart}
565
- onDragEnd={onDragEnd}
566
- onDragCancel={onDragCancel}
567
- >
568
- <div className="kanban-board">
569
- {(Object.keys(sections) as Array<keyof Sections>).map((sectionKey) => (
570
- <div key={sectionKey} className="kanban-column">
571
- <h3>{sectionKey}</h3>
572
- <SortableContext
573
- items={getSectionItemsIds(sectionKey)}
574
- strategy={verticalListSortingStrategy}
575
- >
576
- {sections[sectionKey].map(task => (
577
- <SortableItem key={task.id} id={task.id}>
578
- {task.title}
579
- </SortableItem>
580
- ))}
581
- </SortableContext>
582
- </div>
583
- ))}
584
- </div>
585
-
586
- <DragOverlay dropAnimation={dropAnimationConfig}>
587
- {activeItem ? <div>{activeItem.title}</div> : null}
588
- </DragOverlay>
589
- </DndContext>
590
- );
629
+ const [sections, setSections] = useState<Sections>({
630
+ todo: [
631
+ { id: "1", title: "Design UI" },
632
+ { id: "2", title: "Write tests" },
633
+ ],
634
+ inProgress: [{ id: "3", title: "Implement feature" }],
635
+ done: [{ id: "4", title: "Setup project" }],
636
+ });
637
+
638
+ const {
639
+ getSectionItemsIds, // Get IDs for a section (handles empty sections)
640
+ activeItem, // Currently dragged item
641
+ onDragStart,
642
+ onDragEnd,
643
+ onDragCancel,
644
+ sensors,
645
+ dropAnimationConfig,
646
+ } = useSortableMulti<Task, Sections>(sections, setSections, (sourceKey, destKey, fromIndex, toIndex, nextState) => {
647
+ // Optional callback when items are moved between sections
648
+ console.log(`Moved from ${String(sourceKey)} to ${String(destKey)}`);
649
+ // Save to backend, analytics, etc.
650
+ });
651
+
652
+ return (
653
+ <DndContext
654
+ sensors={sensors}
655
+ collisionDetection={rectIntersection}
656
+ onDragStart={onDragStart}
657
+ onDragEnd={onDragEnd}
658
+ onDragCancel={onDragCancel}
659
+ >
660
+ <div className="kanban-board">
661
+ {(Object.keys(sections) as Array<keyof Sections>).map((sectionKey) => (
662
+ <div key={sectionKey} className="kanban-column">
663
+ <h3>{sectionKey}</h3>
664
+ <SortableContext items={getSectionItemsIds(sectionKey)} strategy={verticalListSortingStrategy}>
665
+ {sections[sectionKey].map((task) => (
666
+ <SortableItem key={task.id} id={task.id}>
667
+ {task.title}
668
+ </SortableItem>
669
+ ))}
670
+ </SortableContext>
671
+ </div>
672
+ ))}
673
+ </div>
674
+
675
+ <DragOverlay dropAnimation={dropAnimationConfig}>
676
+ {activeItem ? <div>{activeItem.title}</div> : null}
677
+ </DragOverlay>
678
+ </DndContext>
679
+ );
591
680
  }
592
681
  ```
593
682
 
594
683
  **Notes:**
684
+
595
685
  - Items must have an `id: string` property
596
686
  - `getSectionItemsIds` automatically handles empty sections by returning placeholder IDs
597
687
  - Use `rectIntersection` collision detection for better multi-section behavior
598
688
  - The hook manages item movement between sections automatically
599
689
 
600
690
  ---
691
+
601
692
  ### useSortableItems
602
693
 
603
694
  Legacy hook for drag-and-drop sorting. Consider using `useSortableSingle` for new implementations.
@@ -605,20 +696,13 @@ Legacy hook for drag-and-drop sorting. Consider using `useSortableSingle` for ne
605
696
  ```tsx
606
697
  import { useSortableItems } from "@uxf/core-react/dnd/hooks/use-sortable-items";
607
698
 
608
- const {
609
- memoizedSensors,
610
- dropAnimationConfig,
611
- itemsIds,
612
- activeItem,
613
- onDragStart,
614
- onDragEnd,
615
- onDragCancel
616
- } = useSortableItems({
617
- items: myItems,
618
- handleDragEnd: (activeIndex, overIndex) => {
619
- // Handle reorder
620
- }
621
- });
699
+ const { memoizedSensors, dropAnimationConfig, itemsIds, activeItem, onDragStart, onDragEnd, onDragCancel } =
700
+ useSortableItems({
701
+ items: myItems,
702
+ handleDragEnd: (activeIndex, overIndex) => {
703
+ // Handle reorder
704
+ },
705
+ });
622
706
  ```
623
707
 
624
708
  ---
@@ -686,16 +770,12 @@ import formTranslations from "@uxf/form/translations/cs.json";
686
770
  // Create a translation function for your language
687
771
  const t = createDefaultT({
688
772
  ...uiTranslations,
689
- ...formTranslations
773
+ ...formTranslations,
690
774
  });
691
775
 
692
776
  // Provide the translation function to your app
693
777
  function App() {
694
- return (
695
- <TranslationsProvider value={t}>
696
- {/* Your app content */}
697
- </TranslationsProvider>
698
- );
778
+ return <TranslationsProvider value={t}>{/* Your app content */}</TranslationsProvider>;
699
779
  }
700
780
  ```
701
781
 
@@ -708,14 +788,10 @@ import { TranslationsProvider } from "@uxf/core-react/translations";
708
788
  import useTranslation from "next-translate/useTranslation"; // Or any other translation library
709
789
 
710
790
  function App() {
711
- // Get the translation function from your translation library
712
- const { t } = useTranslation();
713
-
714
- return (
715
- <TranslationsProvider value={t}>
716
- {/* Your app content */}
717
- </TranslationsProvider>
718
- );
791
+ // Get the translation function from your translation library
792
+ const { t } = useTranslation();
793
+
794
+ return <TranslationsProvider value={t}>{/* Your app content */}</TranslationsProvider>;
719
795
  }
720
796
  ```
721
797
 
@@ -727,13 +803,8 @@ To use translations in your components, use the `useUxfTranslation` hook:
727
803
  import { useUxfTranslation } from "@uxf/core-react/translations";
728
804
 
729
805
  function MyComponent() {
730
- const t = useUxfTranslation();
806
+ const t = useUxfTranslation();
731
807
 
732
- return (
733
- <div>
734
- {t("form:validation.required")}
735
- </div>
736
- );
808
+ return <div>{t("form:validation.required")}</div>;
737
809
  }
738
810
  ```
739
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/core-react",
3
- "version": "11.125.0",
3
+ "version": "11.126.0",
4
4
  "description": "UXF Core",
5
5
  "author": "UX Fans s.r.o",
6
6
  "license": "MIT",
@@ -14,7 +14,7 @@
14
14
  "peerDependencies": {
15
15
  "@dnd-kit/core": "^6.3.1",
16
16
  "@dnd-kit/sortable": "^10.0.0",
17
- "@uxf/core": "11.124.0",
17
+ "@uxf/core": "11.126.0",
18
18
  "react": ">=18.2.0",
19
19
  "react-dom": ">=18.2.0"
20
20
  },
@@ -23,7 +23,7 @@
23
23
  "@dnd-kit/sortable": "^10.0.0",
24
24
  "@types/react": "18.3.31",
25
25
  "@types/react-dom": "18.3.7",
26
- "@uxf/core": "11.124.0",
26
+ "@uxf/core": "11.126.0",
27
27
  "react": "18.3.1",
28
28
  "react-dom": "18.3.1"
29
29
  }
@@ -134,8 +134,8 @@ export interface ConfigurationOptions {
134
134
  export type SwipeableProps = Partial<SwipeableCallbacks & ConfigurationOptions>;
135
135
  export type SwipeablePropsWithDefaultOptions = Partial<SwipeableCallbacks> & ConfigurationOptions;
136
136
  export interface SwipeableHandlers {
137
- ref(element: HTMLElement | null): void;
138
- onMouseDown?(event: React.MouseEvent): void;
137
+ ref: (element: HTMLElement | null) => void;
138
+ onMouseDown?: (event: React.MouseEvent) => void;
139
139
  }
140
140
  export type SwipeableState = {
141
141
  cleanUpTouch?: () => void;