@gateweb/react-utils 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,5 @@
1
- import React, { ReactNode } from 'react';
1
+ import * as React from 'react';
2
+ import React__default, { ReactNode } from 'react';
2
3
  import { AtLeastOne } from './types.js';
3
4
 
4
5
  type TStoreProps<S> = {
@@ -88,7 +89,7 @@ type TInitialProps$1<S> = TStoreProps<S> & {
88
89
  * ```
89
90
  */
90
91
  declare const createStoreContext: <S>() => {
91
- StoreProvider: ({ children, store, handleChangeStore, defaultMerge, }: React.PropsWithChildren<Partial<TInitialProps$1<S>>>) => React.JSX.Element;
92
+ StoreProvider: ({ children, store, handleChangeStore, defaultMerge, }: React__default.PropsWithChildren<Partial<TInitialProps$1<S>>>) => React__default.JSX.Element;
92
93
  useStore: <T>(selector: (state: TStoreState<S>) => T, equalityFn?: (left: T, right: T) => boolean) => T;
93
94
  };
94
95
 
@@ -121,7 +122,7 @@ type TInitialProps<Q> = Partial<TQueryProps<Q> & {
121
122
  *
122
123
  * @deprecated use `StoreProvider` from `core/store` instead
123
124
  */
124
- declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React.PropsWithChildren<TInitialProps<Q>>) => React.JSX.Element;
125
+ declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React__default.PropsWithChildren<TInitialProps<Q>>) => React__default.JSX.Element;
125
126
  /**
126
127
  * hook to get the store from the context
127
128
  *
@@ -180,7 +181,7 @@ declare const createDataContext: <T>() => {
180
181
  readonly DataProvider: ({ children, value }: {
181
182
  children: ReactNode;
182
183
  value: T;
183
- }) => React.JSX.Element;
184
+ }) => React__default.JSX.Element;
184
185
  };
185
186
 
186
187
  type TCountdownActions = {
@@ -227,6 +228,27 @@ type UseDisclosureReturn = {
227
228
  */
228
229
  declare function useDisclosure(initialState?: boolean): UseDisclosureReturn;
229
230
 
231
+ type Options = {
232
+ /** 滾輪轉成水平位移的倍率(觸控板通常較小,滑鼠滾輪較大) */
233
+ speed?: number;
234
+ /** 是否在按住 Shift 時改走瀏覽器原生(通常 Shift+滾輪就是橫向) */
235
+ respectShiftKey?: boolean;
236
+ };
237
+ /**
238
+ * 將 element 的垂直滾輪事件轉成水平捲動的 hook
239
+ *
240
+ * @example
241
+ *
242
+ * ```tsx
243
+ * const ref = useHorizontalWheel();
244
+ *
245
+ * return <div ref={ref}>...</div>;
246
+ *
247
+ * // 你將可以用垂直滾輪來水平捲動這個 div 了!
248
+ * ```
249
+ */
250
+ declare const useHorizontalWheel: <T extends HTMLElement>({ speed, respectShiftKey, }?: Options) => React.RefObject<T | null>;
251
+
230
252
  type TValueOptions<T> = AtLeastOne<{
231
253
  /**
232
254
  * The controlled value.
@@ -250,7 +272,7 @@ type TValueOptions<T> = AtLeastOne<{
250
272
  */
251
273
  declare const useValue: <T>({ value, defaultValue }: TValueOptions<T>) => readonly [T, (newValue: T) => void];
252
274
 
253
- declare function mergeRefs<T = any>(refs: Array<React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null>): React.RefCallback<T>;
275
+ declare function mergeRefs<T = any>(refs: Array<React__default.MutableRefObject<T> | React__default.LegacyRef<T> | undefined | null>): React__default.RefCallback<T>;
254
276
 
255
277
  /**
256
278
  * Downloads a file from a given source.
@@ -285,5 +307,5 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
285
307
  */
286
308
  declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
287
309
 
288
- export { QueryProvider, createDataContext, createStoreContext, downloadFile, getLocalStorage, mergeRefs, setLocalStorage, useCountdown, useDisclosure, useQueryContext, useValue };
310
+ export { QueryProvider, createDataContext, createStoreContext, downloadFile, getLocalStorage, mergeRefs, setLocalStorage, useCountdown, useDisclosure, useHorizontalWheel, useQueryContext, useValue };
289
311
  export type { TCountdownActions, UseDisclosureReturn };
@@ -5,6 +5,7 @@ var queryStore12s = require('./queryStore-12s-JzzXvjJC.js');
5
5
  var React = require('react');
6
6
  var useCountdown12s = require('./useCountdown-12s-uiqhgllY.js');
7
7
  var useDisclosure12s = require('./useDisclosure-12s-SZtbSE4A.js');
8
+ var useHorizontalWheel12s = require('./useHorizontalWheel-12s-bwbWVJeM.js');
8
9
  var download12s = require('./download-12s-DKxkL92w.js');
9
10
  var webStorage12s = require('./webStorage-12s-0RtNO_uc.js');
10
11
 
@@ -111,6 +112,7 @@ exports.QueryProvider = queryStore12s.QueryProvider;
111
112
  exports.useQueryContext = queryStore12s.useQueryContext;
112
113
  exports.useCountdown = useCountdown12s.useCountdown;
113
114
  exports.useDisclosure = useDisclosure12s.useDisclosure;
115
+ exports.useHorizontalWheel = useHorizontalWheel12s.useHorizontalWheel;
114
116
  exports.downloadFile = download12s.downloadFile;
115
117
  exports.getLocalStorage = webStorage12s.getLocalStorage;
116
118
  exports.setLocalStorage = webStorage12s.setLocalStorage;
@@ -463,14 +463,14 @@ type ScenesList<T extends Record<string, {
463
463
  type NormalReturn<T extends Record<string, any>, VK extends string> = {
464
464
  Enum: EnumMap<T, VK>;
465
465
  List: NormalList<T>;
466
- getLabel: (value: ValueAtKey<T, VK>) => string;
466
+ getLabel: (value: ValueAtKey<T, VK>, keep?: boolean) => string | undefined;
467
467
  };
468
468
  type ScenesReturn<T extends Record<string, {
469
469
  scenes: Record<string, Record<string, any>>;
470
470
  }>, Scene extends keyof T[keyof T]['scenes'] & string, VK extends string> = {
471
471
  Enum: EnumMap<T, VK>;
472
472
  List: ScenesList<T, Scene, VK>;
473
- getLabel: (value: ValueAtKey<T, VK>) => string;
473
+ getLabel: (value: ValueAtKey<T, VK>, keep?: boolean) => string | undefined;
474
474
  };
475
475
  type AsNamed<R, N extends string> = {
476
476
  [K in keyof R as K extends 'Enum' ? `Enum${N}` : K extends 'List' ? `${N}List` : K extends 'getLabel' ? `get${N}Label` : never]: R[K];
package/dist/cjs/index.js CHANGED
@@ -274,9 +274,10 @@ function createEnumLikeObject(obj, options) {
274
274
  ...item
275
275
  }));
276
276
  }
277
- function getLabel(value) {
277
+ function getLabel(value, keep = true) {
278
278
  const targetItem = list.find((item)=>// 如果 list 項目內含有 valueKey 對應欄位,優先以該欄位比對;否則以 value 欄位比對
279
279
  valueKey in item ? item[valueKey] === value : item.value === value);
280
+ if (!targetItem && !keep) return undefined;
280
281
  if (!targetItem) return String(value);
281
282
  if ('label' in targetItem) return targetItem.label;
282
283
  return String(value);
@@ -137,6 +137,8 @@ type OnlyOne<T> = {
137
137
  [P in Exclude<keyof T, K>]?: never;
138
138
  };
139
139
  }[keyof T];
140
+ type Builtin = string | number | boolean | bigint | symbol | null | undefined;
141
+ type NonRecursive = Builtin | Function | Date | RegExp | Map<any, any> | Set<any> | WeakMap<any, any> | WeakSet<any> | Promise<any>;
140
142
  /**
141
143
  * A utility type that makes all properties in the generic type `T` optional. Also, it makes all nested properties optional.
142
144
  *
@@ -154,9 +156,9 @@ type OnlyOne<T> = {
154
156
  *
155
157
  * const obj2: ExampleDeepPartial = { a: { b: 'world' } }; // OK
156
158
  */
157
- type DeepPartial<T> = (T extends (infer U)[] ? DeepPartial<U>[] : {
158
- [P in keyof T]?: DeepPartial<T[P]>;
159
- }) | T;
159
+ type DeepPartial<T> = T extends NonRecursive ? T : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? {
160
+ [K in keyof T]?: DeepPartial<T[K]>;
161
+ } : T;
160
162
  /**
161
163
  * 將 Obj 指定的 key 轉換成指定的型別
162
164
  *
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+ var React = require('react');
3
+
4
+ /**
5
+ * 將 element 的垂直滾輪事件轉成水平捲動的 hook
6
+ *
7
+ * @example
8
+ *
9
+ * ```tsx
10
+ * const ref = useHorizontalWheel();
11
+ *
12
+ * return <div ref={ref}>...</div>;
13
+ *
14
+ * // 你將可以用垂直滾輪來水平捲動這個 div 了!
15
+ * ```
16
+ */ const useHorizontalWheel = ({ speed = 1, respectShiftKey = true } = {})=>{
17
+ const ref = React.useRef(null);
18
+ React.useEffect(()=>{
19
+ const el = ref.current;
20
+ if (!el) return undefined;
21
+ const onWheel = (e)=>{
22
+ if (respectShiftKey && e.shiftKey) return;
23
+ // deltaY 是「想往下滾」的意圖,我們把它轉成 scrollLeft
24
+ const delta = e.deltaY * speed;
25
+ const maxScrollLeft = el.scrollWidth - el.clientWidth;
26
+ const next = el.scrollLeft + delta;
27
+ const canScrollHorizontally = el.scrollWidth > el.clientWidth;
28
+ if (!canScrollHorizontally) return;
29
+ const willScroll = delta < 0 && el.scrollLeft > 0 || delta > 0 && el.scrollLeft < maxScrollLeft;
30
+ // 只在「容器還能橫向捲」時攔截,避免卡住頁面垂直捲動
31
+ if (willScroll) {
32
+ e.preventDefault();
33
+ el.scrollLeft = Math.max(0, Math.min(maxScrollLeft, next));
34
+ }
35
+ };
36
+ el.addEventListener('wheel', onWheel, {
37
+ passive: false
38
+ });
39
+ return ()=>el.removeEventListener('wheel', onWheel);
40
+ }, [
41
+ speed,
42
+ respectShiftKey
43
+ ]);
44
+ return ref;
45
+ };
46
+
47
+ exports.useHorizontalWheel = useHorizontalWheel;
@@ -1,4 +1,5 @@
1
- import React, { ReactNode } from 'react';
1
+ import * as React from 'react';
2
+ import React__default, { ReactNode } from 'react';
2
3
  import { AtLeastOne } from './types.mjs';
3
4
 
4
5
  type TStoreProps<S> = {
@@ -88,7 +89,7 @@ type TInitialProps$1<S> = TStoreProps<S> & {
88
89
  * ```
89
90
  */
90
91
  declare const createStoreContext: <S>() => {
91
- StoreProvider: ({ children, store, handleChangeStore, defaultMerge, }: React.PropsWithChildren<Partial<TInitialProps$1<S>>>) => React.JSX.Element;
92
+ StoreProvider: ({ children, store, handleChangeStore, defaultMerge, }: React__default.PropsWithChildren<Partial<TInitialProps$1<S>>>) => React__default.JSX.Element;
92
93
  useStore: <T>(selector: (state: TStoreState<S>) => T, equalityFn?: (left: T, right: T) => boolean) => T;
93
94
  };
94
95
 
@@ -121,7 +122,7 @@ type TInitialProps<Q> = Partial<TQueryProps<Q> & {
121
122
  *
122
123
  * @deprecated use `StoreProvider` from `core/store` instead
123
124
  */
124
- declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React.PropsWithChildren<TInitialProps<Q>>) => React.JSX.Element;
125
+ declare const QueryProvider: <Q>({ children, query, handleChangeQuery, }: React__default.PropsWithChildren<TInitialProps<Q>>) => React__default.JSX.Element;
125
126
  /**
126
127
  * hook to get the store from the context
127
128
  *
@@ -180,7 +181,7 @@ declare const createDataContext: <T>() => {
180
181
  readonly DataProvider: ({ children, value }: {
181
182
  children: ReactNode;
182
183
  value: T;
183
- }) => React.JSX.Element;
184
+ }) => React__default.JSX.Element;
184
185
  };
185
186
 
186
187
  type TCountdownActions = {
@@ -227,6 +228,27 @@ type UseDisclosureReturn = {
227
228
  */
228
229
  declare function useDisclosure(initialState?: boolean): UseDisclosureReturn;
229
230
 
231
+ type Options = {
232
+ /** 滾輪轉成水平位移的倍率(觸控板通常較小,滑鼠滾輪較大) */
233
+ speed?: number;
234
+ /** 是否在按住 Shift 時改走瀏覽器原生(通常 Shift+滾輪就是橫向) */
235
+ respectShiftKey?: boolean;
236
+ };
237
+ /**
238
+ * 將 element 的垂直滾輪事件轉成水平捲動的 hook
239
+ *
240
+ * @example
241
+ *
242
+ * ```tsx
243
+ * const ref = useHorizontalWheel();
244
+ *
245
+ * return <div ref={ref}>...</div>;
246
+ *
247
+ * // 你將可以用垂直滾輪來水平捲動這個 div 了!
248
+ * ```
249
+ */
250
+ declare const useHorizontalWheel: <T extends HTMLElement>({ speed, respectShiftKey, }?: Options) => React.RefObject<T | null>;
251
+
230
252
  type TValueOptions<T> = AtLeastOne<{
231
253
  /**
232
254
  * The controlled value.
@@ -250,7 +272,7 @@ type TValueOptions<T> = AtLeastOne<{
250
272
  */
251
273
  declare const useValue: <T>({ value, defaultValue }: TValueOptions<T>) => readonly [T, (newValue: T) => void];
252
274
 
253
- declare function mergeRefs<T = any>(refs: Array<React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null>): React.RefCallback<T>;
275
+ declare function mergeRefs<T = any>(refs: Array<React__default.MutableRefObject<T> | React__default.LegacyRef<T> | undefined | null>): React__default.RefCallback<T>;
254
276
 
255
277
  /**
256
278
  * Downloads a file from a given source.
@@ -285,5 +307,5 @@ declare const getLocalStorage: <T>(key: string, deCode?: boolean) => T | undefin
285
307
  */
286
308
  declare const setLocalStorage: (key: string, value: Record<string, any>, enCode?: boolean) => void;
287
309
 
288
- export { QueryProvider, createDataContext, createStoreContext, downloadFile, getLocalStorage, mergeRefs, setLocalStorage, useCountdown, useDisclosure, useQueryContext, useValue };
310
+ export { QueryProvider, createDataContext, createStoreContext, downloadFile, getLocalStorage, mergeRefs, setLocalStorage, useCountdown, useDisclosure, useHorizontalWheel, useQueryContext, useValue };
289
311
  export type { TCountdownActions, UseDisclosureReturn };
@@ -3,6 +3,7 @@ export { Q as QueryProvider, u as useQueryContext } from './queryStore-12s-Dkb-A
3
3
  import React, { useMemo, createContext, useContext, useState, useCallback } from 'react';
4
4
  export { u as useCountdown } from './useCountdown-12s-t52WIHfq.mjs';
5
5
  export { u as useDisclosure } from './useDisclosure-12s-BQAHpAXK.mjs';
6
+ export { u as useHorizontalWheel } from './useHorizontalWheel-12s-D3IfutV9.mjs';
6
7
  export { d as downloadFile } from './download-12s-CnaJ0p_f.mjs';
7
8
  export { g as getLocalStorage, s as setLocalStorage } from './webStorage-12s-Bo7x8q5t.mjs';
8
9
 
@@ -463,14 +463,14 @@ type ScenesList<T extends Record<string, {
463
463
  type NormalReturn<T extends Record<string, any>, VK extends string> = {
464
464
  Enum: EnumMap<T, VK>;
465
465
  List: NormalList<T>;
466
- getLabel: (value: ValueAtKey<T, VK>) => string;
466
+ getLabel: (value: ValueAtKey<T, VK>, keep?: boolean) => string | undefined;
467
467
  };
468
468
  type ScenesReturn<T extends Record<string, {
469
469
  scenes: Record<string, Record<string, any>>;
470
470
  }>, Scene extends keyof T[keyof T]['scenes'] & string, VK extends string> = {
471
471
  Enum: EnumMap<T, VK>;
472
472
  List: ScenesList<T, Scene, VK>;
473
- getLabel: (value: ValueAtKey<T, VK>) => string;
473
+ getLabel: (value: ValueAtKey<T, VK>, keep?: boolean) => string | undefined;
474
474
  };
475
475
  type AsNamed<R, N extends string> = {
476
476
  [K in keyof R as K extends 'Enum' ? `Enum${N}` : K extends 'List' ? `${N}List` : K extends 'getLabel' ? `get${N}Label` : never]: R[K];
package/dist/es/index.mjs CHANGED
@@ -268,9 +268,10 @@ function createEnumLikeObject(obj, options) {
268
268
  ...item
269
269
  }));
270
270
  }
271
- function getLabel(value) {
271
+ function getLabel(value, keep = true) {
272
272
  const targetItem = list.find((item)=>// 如果 list 項目內含有 valueKey 對應欄位,優先以該欄位比對;否則以 value 欄位比對
273
273
  valueKey in item ? item[valueKey] === value : item.value === value);
274
+ if (!targetItem && !keep) return undefined;
274
275
  if (!targetItem) return String(value);
275
276
  if ('label' in targetItem) return targetItem.label;
276
277
  return String(value);
@@ -137,6 +137,8 @@ type OnlyOne<T> = {
137
137
  [P in Exclude<keyof T, K>]?: never;
138
138
  };
139
139
  }[keyof T];
140
+ type Builtin = string | number | boolean | bigint | symbol | null | undefined;
141
+ type NonRecursive = Builtin | Function | Date | RegExp | Map<any, any> | Set<any> | WeakMap<any, any> | WeakSet<any> | Promise<any>;
140
142
  /**
141
143
  * A utility type that makes all properties in the generic type `T` optional. Also, it makes all nested properties optional.
142
144
  *
@@ -154,9 +156,9 @@ type OnlyOne<T> = {
154
156
  *
155
157
  * const obj2: ExampleDeepPartial = { a: { b: 'world' } }; // OK
156
158
  */
157
- type DeepPartial<T> = (T extends (infer U)[] ? DeepPartial<U>[] : {
158
- [P in keyof T]?: DeepPartial<T[P]>;
159
- }) | T;
159
+ type DeepPartial<T> = T extends NonRecursive ? T : T extends Array<infer U> ? Array<DeepPartial<U>> : T extends object ? {
160
+ [K in keyof T]?: DeepPartial<T[K]>;
161
+ } : T;
160
162
  /**
161
163
  * 將 Obj 指定的 key 轉換成指定的型別
162
164
  *
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+ import { useRef, useEffect } from 'react';
3
+
4
+ /**
5
+ * 將 element 的垂直滾輪事件轉成水平捲動的 hook
6
+ *
7
+ * @example
8
+ *
9
+ * ```tsx
10
+ * const ref = useHorizontalWheel();
11
+ *
12
+ * return <div ref={ref}>...</div>;
13
+ *
14
+ * // 你將可以用垂直滾輪來水平捲動這個 div 了!
15
+ * ```
16
+ */ const useHorizontalWheel = ({ speed = 1, respectShiftKey = true } = {})=>{
17
+ const ref = useRef(null);
18
+ useEffect(()=>{
19
+ const el = ref.current;
20
+ if (!el) return undefined;
21
+ const onWheel = (e)=>{
22
+ if (respectShiftKey && e.shiftKey) return;
23
+ // deltaY 是「想往下滾」的意圖,我們把它轉成 scrollLeft
24
+ const delta = e.deltaY * speed;
25
+ const maxScrollLeft = el.scrollWidth - el.clientWidth;
26
+ const next = el.scrollLeft + delta;
27
+ const canScrollHorizontally = el.scrollWidth > el.clientWidth;
28
+ if (!canScrollHorizontally) return;
29
+ const willScroll = delta < 0 && el.scrollLeft > 0 || delta > 0 && el.scrollLeft < maxScrollLeft;
30
+ // 只在「容器還能橫向捲」時攔截,避免卡住頁面垂直捲動
31
+ if (willScroll) {
32
+ e.preventDefault();
33
+ el.scrollLeft = Math.max(0, Math.min(maxScrollLeft, next));
34
+ }
35
+ };
36
+ el.addEventListener('wheel', onWheel, {
37
+ passive: false
38
+ });
39
+ return ()=>el.removeEventListener('wheel', onWheel);
40
+ }, [
41
+ speed,
42
+ respectShiftKey
43
+ ]);
44
+ return ref;
45
+ };
46
+
47
+ export { useHorizontalWheel as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gateweb/react-utils",
3
- "version": "2.1.0",
3
+ "version": "2.3.0",
4
4
  "description": "React Utils for GateWeb",
5
5
  "homepage": "https://github.com/GatewebSolutions/react-utils",
6
6
  "files": [