@tiny-design/react 1.2.0 → 1.4.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 (75) hide show
  1. package/es/button/style/_index.scss +16 -11
  2. package/es/button/style/index.css +26 -5
  3. package/es/drawer/drawer.js +3 -2
  4. package/es/drawer/drawer.js.map +1 -1
  5. package/es/message/message.js +3 -2
  6. package/es/message/message.js.map +1 -1
  7. package/es/modal/modal.js +3 -2
  8. package/es/modal/modal.js.map +1 -1
  9. package/es/overlay/overlay.js +2 -2
  10. package/es/overlay/overlay.js.map +1 -1
  11. package/es/pop-confirm/style/_index.scss +4 -0
  12. package/es/pop-confirm/style/index.css +4 -0
  13. package/es/slider/style/_index.scss +1 -9
  14. package/es/slider/style/index.css +1 -6
  15. package/es/speed-dial/style/_index.scss +6 -7
  16. package/es/speed-dial/style/index.css +5 -5
  17. package/es/style/base.css +24 -3
  18. package/es/tag/style/_index.scss +24 -0
  19. package/es/tag/style/index.css +20 -0
  20. package/es/tag/types.d.ts +2 -1
  21. package/es/tag/types.js +7 -2
  22. package/es/tag/types.js.map +1 -1
  23. package/es/time-picker/style/_index.scss +13 -0
  24. package/es/time-picker/style/index.css +10 -0
  25. package/es/time-picker/time-panel.js +28 -28
  26. package/es/time-picker/time-panel.js.map +1 -1
  27. package/es/time-picker/time-picker.js +50 -29
  28. package/es/time-picker/time-picker.js.map +1 -1
  29. package/es/transition/index.js +1 -0
  30. package/es/transition/index.js.map +1 -1
  31. package/es/transition/transition.d.ts +20 -5
  32. package/es/transition/transition.js +33 -8
  33. package/es/transition/transition.js.map +1 -1
  34. package/es/transition/use-transition.js +137 -0
  35. package/es/transition/use-transition.js.map +1 -0
  36. package/es/waterfall/waterfall.js +62 -39
  37. package/es/waterfall/waterfall.js.map +1 -1
  38. package/lib/button/style/_index.scss +16 -11
  39. package/lib/button/style/index.css +26 -5
  40. package/lib/drawer/drawer.js +5 -4
  41. package/lib/drawer/drawer.js.map +1 -1
  42. package/lib/message/message.js +3 -2
  43. package/lib/message/message.js.map +1 -1
  44. package/lib/modal/modal.js +5 -4
  45. package/lib/modal/modal.js.map +1 -1
  46. package/lib/overlay/overlay.js +3 -3
  47. package/lib/overlay/overlay.js.map +1 -1
  48. package/lib/pop-confirm/style/_index.scss +4 -0
  49. package/lib/pop-confirm/style/index.css +4 -0
  50. package/lib/slider/style/_index.scss +1 -9
  51. package/lib/slider/style/index.css +1 -6
  52. package/lib/speed-dial/style/_index.scss +6 -7
  53. package/lib/speed-dial/style/index.css +5 -5
  54. package/lib/style/base.css +24 -3
  55. package/lib/tag/style/_index.scss +24 -0
  56. package/lib/tag/style/index.css +20 -0
  57. package/lib/tag/types.d.ts +2 -1
  58. package/lib/tag/types.js +7 -2
  59. package/lib/tag/types.js.map +1 -1
  60. package/lib/time-picker/style/_index.scss +13 -0
  61. package/lib/time-picker/style/index.css +10 -0
  62. package/lib/time-picker/time-panel.js +28 -28
  63. package/lib/time-picker/time-panel.js.map +1 -1
  64. package/lib/time-picker/time-picker.js +50 -29
  65. package/lib/time-picker/time-picker.js.map +1 -1
  66. package/lib/transition/index.js +1 -0
  67. package/lib/transition/index.js.map +1 -1
  68. package/lib/transition/transition.d.ts +20 -5
  69. package/lib/transition/transition.js +32 -7
  70. package/lib/transition/transition.js.map +1 -1
  71. package/lib/transition/use-transition.js +138 -0
  72. package/lib/transition/use-transition.js.map +1 -0
  73. package/lib/waterfall/waterfall.js +61 -38
  74. package/lib/waterfall/waterfall.js.map +1 -1
  75. package/package.json +3 -5
@@ -88,6 +88,26 @@
88
88
  background: var(--ty-tag-purple-bg);
89
89
  border-color: var(--ty-tag-purple-border);
90
90
  }
91
+ .ty-tag_success {
92
+ color: var(--ty-color-success);
93
+ background: var(--ty-color-success-bg);
94
+ border-color: var(--ty-color-success-border);
95
+ }
96
+ .ty-tag_info {
97
+ color: var(--ty-color-info);
98
+ background: var(--ty-color-info-bg);
99
+ border-color: var(--ty-color-info-border);
100
+ }
101
+ .ty-tag_warning {
102
+ color: var(--ty-color-warning);
103
+ background: var(--ty-color-warning-bg);
104
+ border-color: var(--ty-color-warning-border);
105
+ }
106
+ .ty-tag_danger {
107
+ color: var(--ty-color-danger);
108
+ background: var(--ty-color-danger-bg);
109
+ border-color: var(--ty-color-danger-border);
110
+ }
91
111
 
92
112
  .ty-checkable-tag {
93
113
  background-color: var(--ty-tag-checkable-bg);
package/es/tag/types.d.ts CHANGED
@@ -8,8 +8,9 @@ interface CheckableTagProps extends BaseProps {
8
8
  onChange?: (checked: boolean, e: React.MouseEvent) => void;
9
9
  children?: React.ReactNode;
10
10
  }
11
+ type StatusColor = 'success' | 'warning' | 'info' | 'danger';
11
12
  interface TagProps extends BaseProps, React.PropsWithoutRef<JSX.IntrinsicElements['div']> {
12
- color?: string;
13
+ color?: string | StatusColor;
13
14
  closable?: boolean;
14
15
  onClose?: React.MouseEventHandler;
15
16
  onClick?: React.MouseEventHandler;
package/es/tag/types.js CHANGED
@@ -1,4 +1,3 @@
1
- //#region src/tag/types.ts
2
1
  const PresetColors = [
3
2
  "magenta",
4
3
  "red",
@@ -10,7 +9,13 @@ const PresetColors = [
10
9
  "cyan",
11
10
  "blue",
12
11
  "geekblue",
13
- "purple"
12
+ "purple",
13
+ ...[
14
+ "success",
15
+ "info",
16
+ "warning",
17
+ "danger"
18
+ ]
14
19
  ];
15
20
  //#endregion
16
21
  export { PresetColors };
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/tag/types.ts"],"sourcesContent":["import React from 'react';\nimport { BaseProps } from '../_utils/props';\n\nexport interface CheckableTagProps extends BaseProps {\n defaultChecked?: boolean;\n checked?: boolean;\n onChange?: (checked: boolean, e: React.MouseEvent) => void;\n children?: React.ReactNode;\n}\n\nexport const PresetColors = [\n 'magenta',\n 'red',\n 'volcano',\n 'orange',\n 'gold',\n 'lime',\n 'green',\n 'cyan',\n 'blue',\n 'geekblue',\n 'purple',\n];\n\nexport interface TagProps extends BaseProps, React.PropsWithoutRef<JSX.IntrinsicElements['div']> {\n color?: string;\n closable?: boolean;\n onClose?: React.MouseEventHandler;\n onClick?: React.MouseEventHandler;\n defaultVisible?: boolean;\n visible?: boolean;\n children?: React.ReactNode;\n}\n"],"mappings":";AAUA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/tag/types.ts"],"sourcesContent":["import React from 'react';\nimport { BaseProps } from '../_utils/props';\n\nexport interface CheckableTagProps extends BaseProps {\n defaultChecked?: boolean;\n checked?: boolean;\n onChange?: (checked: boolean, e: React.MouseEvent) => void;\n children?: React.ReactNode;\n}\n\nexport type StatusColor = 'success' | 'warning' | 'info' | 'danger';\n\nexport const StatusColors: StatusColor[] = ['success', 'info', 'warning', 'danger'];\n\nexport const PresetColors = [\n 'magenta',\n 'red',\n 'volcano',\n 'orange',\n 'gold',\n 'lime',\n 'green',\n 'cyan',\n 'blue',\n 'geekblue',\n 'purple',\n ...StatusColors,\n];\n\nexport interface TagProps extends BaseProps, React.PropsWithoutRef<JSX.IntrinsicElements['div']> {\n color?: string | StatusColor;\n closable?: boolean;\n onClose?: React.MouseEventHandler;\n onClick?: React.MouseEventHandler;\n defaultVisible?: boolean;\n visible?: boolean;\n children?: React.ReactNode;\n}\n"],"mappings":"AAcA,MAAa,eAAe;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAdyC;EAAC;EAAW;EAAQ;EAAW;EAAS;CAelF"}
@@ -29,6 +29,10 @@ $tp: #{$prefix}-time-picker;
29
29
  box-shadow: var(--ty-input-focus-shadow);
30
30
  }
31
31
 
32
+ &_pending &__input-field {
33
+ color: var(--ty-color-text-tertiary);
34
+ }
35
+
32
36
  &__input-field {
33
37
  flex: 1;
34
38
  border: none;
@@ -191,6 +195,15 @@ $tp: #{$prefix}-time-picker;
191
195
  }
192
196
  }
193
197
 
198
+ &_pending {
199
+ background: var(--ty-color-primary-bg);
200
+ color: var(--ty-color-text-tertiary);
201
+
202
+ &:hover {
203
+ background: var(--ty-color-primary-bg-hover);
204
+ }
205
+ }
206
+
194
207
  &_disabled {
195
208
  color: var(--ty-color-text-quaternary);
196
209
  cursor: not-allowed;
@@ -21,6 +21,9 @@
21
21
  border-color: var(--ty-color-primary);
22
22
  box-shadow: var(--ty-input-focus-shadow);
23
23
  }
24
+ .ty-time-picker_pending .ty-time-picker__input-field {
25
+ color: var(--ty-color-text-tertiary);
26
+ }
24
27
  .ty-time-picker__input-field {
25
28
  flex: 1;
26
29
  border: none;
@@ -157,6 +160,13 @@
157
160
  .ty-time-picker__cell_selected:hover {
158
161
  background: var(--ty-color-primary-bg-hover);
159
162
  }
163
+ .ty-time-picker__cell_pending {
164
+ background: var(--ty-color-primary-bg);
165
+ color: var(--ty-color-text-tertiary);
166
+ }
167
+ .ty-time-picker__cell_pending:hover {
168
+ background: var(--ty-color-primary-bg-hover);
169
+ }
160
170
  .ty-time-picker__cell_disabled {
161
171
  color: var(--ty-color-text-quaternary);
162
172
  cursor: not-allowed;
@@ -4,14 +4,16 @@ import { jsx } from "react/jsx-runtime";
4
4
  //#region src/time-picker/time-panel.tsx
5
5
  const ITEM_HEIGHT = 28;
6
6
  const TimePanel = (props) => {
7
- const { prefixCls, value, items, disabledItems = [], loop = false, onChange } = props;
7
+ const { prefixCls, value, pendingValue, items, disabledItems = [], loop = false, onChange } = props;
8
8
  const panelRef = useRef(null);
9
9
  const itemRefs = useRef(/* @__PURE__ */ new Map());
10
10
  const isResetting = useRef(false);
11
11
  const clickedRef = useRef(false);
12
12
  const scrollToItemRef = useRef(null);
13
13
  const oneGroupHeight = items.length * ITEM_HEIGHT;
14
+ const displayValue = pendingValue ?? value;
14
15
  scrollToItemRef.current = (val) => {
16
+ if (val === null) return;
15
17
  const panel = panelRef.current;
16
18
  if (!panel) return;
17
19
  if (loop) {
@@ -39,8 +41,8 @@ const TimePanel = (props) => {
39
41
  clickedRef.current = false;
40
42
  return;
41
43
  }
42
- scrollToItemRef.current?.(value);
43
- }, [value]);
44
+ scrollToItemRef.current?.(displayValue);
45
+ }, [displayValue]);
44
46
  const handleScroll = useCallback(() => {
45
47
  if (!loop || isResetting.current) return;
46
48
  const panel = panelRef.current;
@@ -62,6 +64,16 @@ const TimePanel = (props) => {
62
64
  clickedRef.current = true;
63
65
  onChange(num);
64
66
  };
67
+ const isPending = pendingValue !== null;
68
+ const isCommitted = value !== null && pendingValue === null;
69
+ const cellCls = (num) => {
70
+ const isSelected = num === displayValue;
71
+ return classNames(`${prefixCls}__cell`, {
72
+ [`${prefixCls}__cell_selected`]: isSelected && isCommitted,
73
+ [`${prefixCls}__cell_pending`]: isSelected && isPending,
74
+ [`${prefixCls}__cell_disabled`]: disabledItems.includes(num)
75
+ });
76
+ };
65
77
  if (loop) return /* @__PURE__ */ jsx("div", {
66
78
  className: `${prefixCls}__column`,
67
79
  ref: panelRef,
@@ -72,17 +84,11 @@ const TimePanel = (props) => {
72
84
  0,
73
85
  1,
74
86
  2
75
- ].map((copyIdx) => items.map((num, i) => {
76
- const isDisabled = disabledItems.includes(num);
77
- return /* @__PURE__ */ jsx("li", {
78
- className: classNames(`${prefixCls}__cell`, {
79
- [`${prefixCls}__cell_selected`]: num === value,
80
- [`${prefixCls}__cell_disabled`]: isDisabled
81
- }),
82
- onClick: () => handleClick(num),
83
- children: String(num).padStart(2, "0")
84
- }, `c${copyIdx}-${i}`);
85
- }))
87
+ ].map((copyIdx) => items.map((num, i) => /* @__PURE__ */ jsx("li", {
88
+ className: cellCls(num),
89
+ onClick: () => handleClick(num),
90
+ children: String(num).padStart(2, "0")
91
+ }, `c${copyIdx}-${i}`)))
86
92
  })
87
93
  });
88
94
  return /* @__PURE__ */ jsx("div", {
@@ -90,20 +96,14 @@ const TimePanel = (props) => {
90
96
  ref: panelRef,
91
97
  children: /* @__PURE__ */ jsx("ul", {
92
98
  className: `${prefixCls}__column-list`,
93
- children: items.map((num) => {
94
- const isDisabled = disabledItems.includes(num);
95
- return /* @__PURE__ */ jsx("li", {
96
- ref: (el) => {
97
- if (el) itemRefs.current.set(num, el);
98
- },
99
- className: classNames(`${prefixCls}__cell`, {
100
- [`${prefixCls}__cell_selected`]: num === value,
101
- [`${prefixCls}__cell_disabled`]: isDisabled
102
- }),
103
- onClick: () => handleClick(num),
104
- children: String(num).padStart(2, "0")
105
- }, num);
106
- })
99
+ children: items.map((num) => /* @__PURE__ */ jsx("li", {
100
+ ref: (el) => {
101
+ if (el) itemRefs.current.set(num, el);
102
+ },
103
+ className: cellCls(num),
104
+ onClick: () => handleClick(num),
105
+ children: String(num).padStart(2, "0")
106
+ }, num))
107
107
  })
108
108
  });
109
109
  };
@@ -1 +1 @@
1
- {"version":3,"file":"time-panel.js","names":[],"sources":["../../src/time-picker/time-panel.tsx"],"sourcesContent":["import { useRef, useEffect, useCallback } from 'react';\nimport classNames from 'classnames';\n\nexport interface TimePanelProps {\n value: number;\n items: number[];\n disabledItems?: number[];\n loop?: boolean;\n onChange: (num: number) => void;\n prefixCls: string;\n}\n\nconst ITEM_HEIGHT = 28; // 4px padding-top + 20px line-height + 4px padding-bottom\n\nconst TimePanel = (props: TimePanelProps): React.ReactElement => {\n const { prefixCls, value, items, disabledItems = [], loop = false, onChange } = props;\n const panelRef = useRef<HTMLDivElement>(null);\n const itemRefs = useRef<Map<number, HTMLLIElement>>(new Map());\n const isResetting = useRef(false);\n const clickedRef = useRef(false);\n const scrollToItemRef = useRef<((val: number) => void) | null>(null);\n\n const oneGroupHeight = items.length * ITEM_HEIGHT;\n\n scrollToItemRef.current = (val: number) => {\n const panel = panelRef.current;\n if (!panel) return;\n\n if (loop) {\n const idx = items.indexOf(val);\n if (idx === -1) return;\n const top = oneGroupHeight + idx * ITEM_HEIGHT;\n isResetting.current = true;\n panel.scrollTo({ top, behavior: 'auto' });\n requestAnimationFrame(() => { isResetting.current = false; });\n } else {\n const el = itemRefs.current.get(val);\n if (el) {\n panel.scrollTo({ top: el.offsetTop, behavior: 'auto' });\n }\n }\n };\n\n useEffect(() => {\n if (clickedRef.current) {\n clickedRef.current = false;\n return;\n }\n scrollToItemRef.current?.(value);\n }, [value]);\n\n // Scroll reset for loop mode\n const handleScroll = useCallback(() => {\n if (!loop || isResetting.current) return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const st = panel.scrollTop;\n if (st < oneGroupHeight || st >= 2 * oneGroupHeight) {\n isResetting.current = true;\n panel.scrollTo({ top: (st % oneGroupHeight) + oneGroupHeight, behavior: 'auto' });\n requestAnimationFrame(() => { isResetting.current = false; });\n }\n }, [loop, oneGroupHeight]);\n\n const handleClick = (num: number) => {\n if (disabledItems.includes(num)) return;\n clickedRef.current = true;\n onChange(num);\n };\n\n if (loop) {\n const copies = [0, 1, 2];\n return (\n <div className={`${prefixCls}__column`} ref={panelRef} onScroll={handleScroll}>\n <ul className={`${prefixCls}__column-list`}>\n {copies.map((copyIdx) =>\n items.map((num, i) => {\n const isDisabled = disabledItems.includes(num);\n const cls = classNames(`${prefixCls}__cell`, {\n [`${prefixCls}__cell_selected`]: num === value,\n [`${prefixCls}__cell_disabled`]: isDisabled,\n });\n return (\n <li\n key={`c${copyIdx}-${i}`}\n className={cls}\n onClick={() => handleClick(num)}>\n {String(num).padStart(2, '0')}\n </li>\n );\n })\n )}\n </ul>\n </div>\n );\n }\n\n return (\n <div className={`${prefixCls}__column`} ref={panelRef}>\n <ul className={`${prefixCls}__column-list`}>\n {items.map((num) => {\n const isDisabled = disabledItems.includes(num);\n const cls = classNames(`${prefixCls}__cell`, {\n [`${prefixCls}__cell_selected`]: num === value,\n [`${prefixCls}__cell_disabled`]: isDisabled,\n });\n return (\n <li\n key={num}\n ref={(el) => {\n if (el) itemRefs.current.set(num, el);\n }}\n className={cls}\n onClick={() => handleClick(num)}>\n {String(num).padStart(2, '0')}\n </li>\n );\n })}\n </ul>\n </div>\n );\n};\n\nexport default TimePanel;\n"],"mappings":";;;;AAYA,MAAM,cAAc;AAEpB,MAAM,aAAa,UAA8C;CAC/D,MAAM,EAAE,WAAW,OAAO,OAAO,gBAAgB,EAAE,EAAE,OAAO,OAAO,aAAa;CAChF,MAAM,WAAW,OAAuB,KAAK;CAC7C,MAAM,WAAW,uBAAmC,IAAI,KAAK,CAAC;CAC9D,MAAM,cAAc,OAAO,MAAM;CACjC,MAAM,aAAa,OAAO,MAAM;CAChC,MAAM,kBAAkB,OAAuC,KAAK;CAEpE,MAAM,iBAAiB,MAAM,SAAS;AAEtC,iBAAgB,WAAW,QAAgB;EACzC,MAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,MAAO;AAEZ,MAAI,MAAM;GACR,MAAM,MAAM,MAAM,QAAQ,IAAI;AAC9B,OAAI,QAAQ,GAAI;GAChB,MAAM,MAAM,iBAAiB,MAAM;AACnC,eAAY,UAAU;AACtB,SAAM,SAAS;IAAE;IAAK,UAAU;IAAQ,CAAC;AACzC,+BAA4B;AAAE,gBAAY,UAAU;KAAS;SACxD;GACL,MAAM,KAAK,SAAS,QAAQ,IAAI,IAAI;AACpC,OAAI,GACF,OAAM,SAAS;IAAE,KAAK,GAAG;IAAW,UAAU;IAAQ,CAAC;;;AAK7D,iBAAgB;AACd,MAAI,WAAW,SAAS;AACtB,cAAW,UAAU;AACrB;;AAEF,kBAAgB,UAAU,MAAM;IAC/B,CAAC,MAAM,CAAC;CAGX,MAAM,eAAe,kBAAkB;AACrC,MAAI,CAAC,QAAQ,YAAY,QAAS;EAClC,MAAM,QAAQ,SAAS;AACvB,MAAI,CAAC,MAAO;EAEZ,MAAM,KAAK,MAAM;AACjB,MAAI,KAAK,kBAAkB,MAAM,IAAI,gBAAgB;AACnD,eAAY,UAAU;AACtB,SAAM,SAAS;IAAE,KAAM,KAAK,iBAAkB;IAAgB,UAAU;IAAQ,CAAC;AACjF,+BAA4B;AAAE,gBAAY,UAAU;KAAS;;IAE9D,CAAC,MAAM,eAAe,CAAC;CAE1B,MAAM,eAAe,QAAgB;AACnC,MAAI,cAAc,SAAS,IAAI,CAAE;AACjC,aAAW,UAAU;AACrB,WAAS,IAAI;;AAGf,KAAI,KAEF,QACE,oBAAC,OAAD;EAAK,WAAW,GAAG,UAAU;EAAW,KAAK;EAAU,UAAU;YAC/D,oBAAC,MAAD;GAAI,WAAW,GAAG,UAAU;aAHjB;IAAC;IAAG;IAAG;IAAE,CAIV,KAAK,YACX,MAAM,KAAK,KAAK,MAAM;IACpB,MAAM,aAAa,cAAc,SAAS,IAAI;AAK9C,WACE,oBAAC,MAAD;KAEE,WAPQ,WAAW,GAAG,UAAU,SAAS;OAC1C,GAAG,UAAU,mBAAmB,QAAQ;OACxC,GAAG,UAAU,mBAAmB;MAClC,CAAC;KAKE,eAAe,YAAY,IAAI;eAC9B,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI;KAC1B,EAJE,IAAI,QAAQ,GAAG,IAIjB;KAEP,CACH;GACE,CAAA;EACD,CAAA;AAIV,QACE,oBAAC,OAAD;EAAK,WAAW,GAAG,UAAU;EAAW,KAAK;YAC3C,oBAAC,MAAD;GAAI,WAAW,GAAG,UAAU;aACzB,MAAM,KAAK,QAAQ;IAClB,MAAM,aAAa,cAAc,SAAS,IAAI;AAK9C,WACE,oBAAC,MAAD;KAEE,MAAM,OAAO;AACX,UAAI,GAAI,UAAS,QAAQ,IAAI,KAAK,GAAG;;KAEvC,WAVQ,WAAW,GAAG,UAAU,SAAS;OAC1C,GAAG,UAAU,mBAAmB,QAAQ;OACxC,GAAG,UAAU,mBAAmB;MAClC,CAAC;KAQE,eAAe,YAAY,IAAI;eAC9B,OAAO,IAAI,CAAC,SAAS,GAAG,IAAI;KAC1B,EAPE,IAOF;KAEP;GACC,CAAA;EACD,CAAA"}
1
+ {"version":3,"file":"time-panel.js","names":[],"sources":["../../src/time-picker/time-panel.tsx"],"sourcesContent":["import { useRef, useEffect, useCallback } from 'react';\nimport classNames from 'classnames';\n\nexport interface TimePanelProps {\n value: number | null;\n pendingValue: number | null;\n items: number[];\n disabledItems?: number[];\n loop?: boolean;\n onChange: (num: number) => void;\n prefixCls: string;\n}\n\nconst ITEM_HEIGHT = 28; // 4px padding-top + 20px line-height + 4px padding-bottom\n\nconst TimePanel = (props: TimePanelProps): React.ReactElement => {\n const { prefixCls, value, pendingValue, items, disabledItems = [], loop = false, onChange } = props;\n const panelRef = useRef<HTMLDivElement>(null);\n const itemRefs = useRef<Map<number, HTMLLIElement>>(new Map());\n const isResetting = useRef(false);\n const clickedRef = useRef(false);\n const scrollToItemRef = useRef<((val: number | null) => void) | null>(null);\n\n const oneGroupHeight = items.length * ITEM_HEIGHT;\n\n // The displayed value: pending takes priority, then committed\n const displayValue = pendingValue ?? value;\n\n scrollToItemRef.current = (val: number | null) => {\n if (val === null) return;\n const panel = panelRef.current;\n if (!panel) return;\n\n if (loop) {\n const idx = items.indexOf(val);\n if (idx === -1) return;\n const top = oneGroupHeight + idx * ITEM_HEIGHT;\n isResetting.current = true;\n panel.scrollTo({ top, behavior: 'auto' });\n requestAnimationFrame(() => { isResetting.current = false; });\n } else {\n const el = itemRefs.current.get(val);\n if (el) {\n panel.scrollTo({ top: el.offsetTop, behavior: 'auto' });\n }\n }\n };\n\n useEffect(() => {\n if (clickedRef.current) {\n clickedRef.current = false;\n return;\n }\n scrollToItemRef.current?.(displayValue);\n }, [displayValue]);\n\n // Scroll reset for loop mode\n const handleScroll = useCallback(() => {\n if (!loop || isResetting.current) return;\n const panel = panelRef.current;\n if (!panel) return;\n\n const st = panel.scrollTop;\n if (st < oneGroupHeight || st >= 2 * oneGroupHeight) {\n isResetting.current = true;\n panel.scrollTo({ top: (st % oneGroupHeight) + oneGroupHeight, behavior: 'auto' });\n requestAnimationFrame(() => { isResetting.current = false; });\n }\n }, [loop, oneGroupHeight]);\n\n const handleClick = (num: number) => {\n if (disabledItems.includes(num)) return;\n clickedRef.current = true;\n onChange(num);\n };\n\n const isPending = pendingValue !== null;\n const isCommitted = value !== null && pendingValue === null;\n\n const cellCls = (num: number) => {\n const isSelected = num === displayValue;\n return classNames(`${prefixCls}__cell`, {\n [`${prefixCls}__cell_selected`]: isSelected && isCommitted,\n [`${prefixCls}__cell_pending`]: isSelected && isPending,\n [`${prefixCls}__cell_disabled`]: disabledItems.includes(num),\n });\n };\n\n if (loop) {\n const copies = [0, 1, 2];\n return (\n <div className={`${prefixCls}__column`} ref={panelRef} onScroll={handleScroll}>\n <ul className={`${prefixCls}__column-list`}>\n {copies.map((copyIdx) =>\n items.map((num, i) => (\n <li\n key={`c${copyIdx}-${i}`}\n className={cellCls(num)}\n onClick={() => handleClick(num)}>\n {String(num).padStart(2, '0')}\n </li>\n ))\n )}\n </ul>\n </div>\n );\n }\n\n return (\n <div className={`${prefixCls}__column`} ref={panelRef}>\n <ul className={`${prefixCls}__column-list`}>\n {items.map((num) => (\n <li\n key={num}\n ref={(el) => {\n if (el) itemRefs.current.set(num, el);\n }}\n className={cellCls(num)}\n onClick={() => handleClick(num)}>\n {String(num).padStart(2, '0')}\n </li>\n ))}\n </ul>\n </div>\n );\n};\n\nexport default TimePanel;\n"],"mappings":"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"}
@@ -8,6 +8,11 @@ import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "r
8
8
  import classNames from "classnames";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
10
  //#region src/time-picker/time-picker.tsx
11
+ const EMPTY_PENDING = {
12
+ h: null,
13
+ m: null,
14
+ s: null
15
+ };
11
16
  function formatTime(date, format, use12Hours) {
12
17
  let h = date.getHours();
13
18
  const m = String(date.getMinutes()).padStart(2, "0");
@@ -35,6 +40,7 @@ const TimePicker = (props) => {
35
40
  const { defaultValue, value, open: controlledOpen, format = "HH:mm:ss", use12Hours = false, hourStep = 1, minuteStep = 1, secondStep = 1, disabled = false, placeholder = locale.TimePicker.selectTime, allowClear = true, size = "md", inputReadOnly = true, disabledTime, hideDisabledOptions = false, loop = false, showNow = true, renderExtraFooter, suffixIcon, onChange, onOpenChange, className, style, prefixCls: customisedCls } = props;
36
41
  const prefixCls = getPrefixCls("time-picker", useContext(ConfigContext).prefixCls, customisedCls);
37
42
  const [date, setDate] = useState(value ?? defaultValue ?? null);
43
+ const [pending, setPending] = useState(EMPTY_PENDING);
38
44
  const [open, setOpen] = useState(false);
39
45
  const wrapperRef = useRef(null);
40
46
  const dropdownRef = useRef(null);
@@ -51,6 +57,7 @@ const TimePicker = (props) => {
51
57
  if (wrapperRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;
52
58
  if (controlledOpen === void 0) setOpen(false);
53
59
  onOpenChange?.(false);
60
+ setPending(EMPTY_PENDING);
54
61
  };
55
62
  document.addEventListener("click", listener);
56
63
  return () => document.removeEventListener("click", listener);
@@ -58,43 +65,51 @@ const TimePicker = (props) => {
58
65
  const toggleOpen = useCallback((val) => {
59
66
  if (controlledOpen === void 0) setOpen(val);
60
67
  onOpenChange?.(val);
68
+ if (!val) setPending(EMPTY_PENDING);
61
69
  }, [controlledOpen, onOpenChange]);
62
- const updateTime = useCallback((type, num) => {
70
+ /** Build a Date from committed date + pending overrides */
71
+ const buildDate = useCallback((p) => {
63
72
  const base = date ? new Date(date) : new Date(0, 0, 0, 0, 0, 0, 0);
64
- if (type === "h") base.setHours(num);
65
- else if (type === "m") base.setMinutes(num);
66
- else base.setSeconds(num);
67
- if (value === void 0) setDate(base);
68
- onChange?.(base);
69
- }, [
70
- date,
71
- value,
72
- onChange
73
- ]);
73
+ if (p.h !== null) base.setHours(p.h);
74
+ if (p.m !== null) base.setMinutes(p.m);
75
+ if (p.s !== null) base.setSeconds(p.s);
76
+ return base;
77
+ }, [date]);
78
+ const updatePending = useCallback((type, num) => {
79
+ setPending((prev) => ({
80
+ ...prev,
81
+ [type]: num
82
+ }));
83
+ }, []);
84
+ const commit = useCallback((newDate) => {
85
+ if (value === void 0) setDate(newDate);
86
+ onChange?.(newDate);
87
+ setPending(EMPTY_PENDING);
88
+ }, [value, onChange]);
74
89
  const handleClear = (e) => {
75
90
  e.stopPropagation();
76
91
  if (value === void 0) setDate(null);
77
92
  onChange?.(null);
93
+ setPending(EMPTY_PENDING);
78
94
  toggleOpen(false);
79
95
  };
80
96
  const handleNow = () => {
81
- const now = /* @__PURE__ */ new Date();
82
- if (value === void 0) setDate(now);
83
- onChange?.(now);
97
+ commit(/* @__PURE__ */ new Date());
84
98
  toggleOpen(false);
85
99
  };
86
100
  const handleOk = () => {
101
+ if (pending.h !== null || pending.m !== null || pending.s !== null) commit(buildDate(pending));
87
102
  toggleOpen(false);
88
103
  };
104
+ const effectiveHour = pending.h ?? date?.getHours() ?? 0;
105
+ const effectiveMinute = pending.m ?? date?.getMinutes() ?? 0;
89
106
  const disabled12 = useMemo(() => disabledTime?.() ?? {}, [disabledTime]);
90
107
  const disabledHours = useMemo(() => disabled12.disabledHours?.() ?? [], [disabled12]);
91
- const currentHour = date?.getHours() ?? 0;
92
- const disabledMinutes = useMemo(() => disabled12.disabledMinutes?.(currentHour) ?? [], [disabled12, currentHour]);
93
- const currentMinute = date?.getMinutes() ?? 0;
94
- const disabledSeconds = useMemo(() => disabled12.disabledSeconds?.(currentHour, currentMinute) ?? [], [
108
+ const disabledMinutes = useMemo(() => disabled12.disabledMinutes?.(effectiveHour) ?? [], [disabled12, effectiveHour]);
109
+ const disabledSeconds = useMemo(() => disabled12.disabledSeconds?.(effectiveHour, effectiveMinute) ?? [], [
95
110
  disabled12,
96
- currentHour,
97
- currentMinute
111
+ effectiveHour,
112
+ effectiveMinute
98
113
  ]);
99
114
  const hours = generateSteps(24, hourStep);
100
115
  const minutes = generateSteps(60, minuteStep);
@@ -102,12 +117,15 @@ const TimePicker = (props) => {
102
117
  const filteredHours = hideDisabledOptions ? hours.filter((h) => !disabledHours.includes(h)) : hours;
103
118
  const filteredMinutes = hideDisabledOptions ? minutes.filter((m) => !disabledMinutes.includes(m)) : minutes;
104
119
  const filteredSeconds = hideDisabledOptions ? seconds.filter((s) => !disabledSeconds.includes(s)) : seconds;
105
- const hasValue = date !== null;
106
- const displayValue = hasValue ? formatTime(date, format, use12Hours) : "";
120
+ const hasPending = pending.h !== null || pending.m !== null || pending.s !== null;
121
+ const effectiveDate = (hasPending ? buildDate(pending) : null) ?? date;
122
+ const hasValue = effectiveDate !== null;
123
+ const displayValue = hasValue ? formatTime(effectiveDate, format, use12Hours) : "";
107
124
  const cls = classNames(prefixCls, className, `${prefixCls}_${size}`, {
108
125
  [`${prefixCls}_disabled`]: disabled,
109
126
  [`${prefixCls}_open`]: isOpen,
110
- [`${prefixCls}_has-value`]: hasValue
127
+ [`${prefixCls}_has-value`]: hasValue,
128
+ [`${prefixCls}_pending`]: hasPending
111
129
  });
112
130
  const renderOverlay = () => /* @__PURE__ */ jsxs("div", {
113
131
  className: `${prefixCls}__dropdown`,
@@ -117,27 +135,30 @@ const TimePicker = (props) => {
117
135
  children: [
118
136
  /* @__PURE__ */ jsx(TimePanel, {
119
137
  prefixCls,
120
- value: date?.getHours() ?? 0,
138
+ value: date?.getHours() ?? null,
139
+ pendingValue: pending.h,
121
140
  items: filteredHours,
122
141
  disabledItems: hideDisabledOptions ? [] : disabledHours,
123
142
  loop,
124
- onChange: (h) => updateTime("h", h)
143
+ onChange: (h) => updatePending("h", h)
125
144
  }),
126
145
  showsMinutes(format) && /* @__PURE__ */ jsx(TimePanel, {
127
146
  prefixCls,
128
- value: date?.getMinutes() ?? 0,
147
+ value: date?.getMinutes() ?? null,
148
+ pendingValue: pending.m,
129
149
  items: filteredMinutes,
130
150
  disabledItems: hideDisabledOptions ? [] : disabledMinutes,
131
151
  loop,
132
- onChange: (m) => updateTime("m", m)
152
+ onChange: (m) => updatePending("m", m)
133
153
  }),
134
154
  showsSeconds(format) && /* @__PURE__ */ jsx(TimePanel, {
135
155
  prefixCls,
136
- value: date?.getSeconds() ?? 0,
156
+ value: date?.getSeconds() ?? null,
157
+ pendingValue: pending.s,
137
158
  items: filteredSeconds,
138
159
  disabledItems: hideDisabledOptions ? [] : disabledSeconds,
139
160
  loop,
140
- onChange: (s) => updateTime("s", s)
161
+ onChange: (s) => updatePending("s", s)
141
162
  })
142
163
  ]
143
164
  }), /* @__PURE__ */ jsxs("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"time-picker.js","names":["Popup"],"sources":["../../src/time-picker/time-picker.tsx"],"sourcesContent":["import { useEffect, useState, useRef, useCallback, useContext, useMemo } from 'react';\nimport classNames from 'classnames';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { useLocale } from '../_utils/use-locale';\nimport { ClockIcon, ClearIcon } from '../_utils/components';\nimport Popup from '../popup';\nimport TimePanel from './time-panel';\nimport { TimePickerProps } from './types';\n\nfunction formatTime(date: Date, format: string, use12Hours: boolean): string {\n let h = date.getHours();\n const m = String(date.getMinutes()).padStart(2, '0');\n const s = String(date.getSeconds()).padStart(2, '0');\n let period = '';\n\n if (use12Hours) {\n period = h >= 12 ? ' PM' : ' AM';\n h = h % 12 || 12;\n }\n\n return format\n .replace('HH', String(h).padStart(2, '0'))\n .replace('H', String(h))\n .replace('mm', m)\n .replace('ss', s) + period;\n}\n\nfunction generateSteps(count: number, step: number): number[] {\n const items: number[] = [];\n for (let i = 0; i < count; i += step) {\n items.push(i);\n }\n return items;\n}\n\nfunction showsSeconds(format: string): boolean {\n return format.includes('ss') || format.includes('s');\n}\n\nfunction showsMinutes(format: string): boolean {\n return format.includes('mm') || format.includes('m');\n}\n\nconst TimePicker = (props: TimePickerProps): React.ReactElement => {\n const locale = useLocale();\n const {\n defaultValue,\n value,\n open: controlledOpen,\n format = 'HH:mm:ss',\n use12Hours = false,\n hourStep = 1,\n minuteStep = 1,\n secondStep = 1,\n disabled = false,\n placeholder = locale.TimePicker.selectTime,\n allowClear = true,\n size = 'md',\n inputReadOnly = true,\n disabledTime,\n hideDisabledOptions = false,\n loop = false,\n showNow = true,\n renderExtraFooter,\n suffixIcon,\n onChange,\n onOpenChange,\n className,\n style,\n prefixCls: customisedCls,\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('time-picker', configContext.prefixCls, customisedCls);\n\n const [date, setDate] = useState<Date | null>(value ?? defaultValue ?? null);\n const [open, setOpen] = useState(false);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const isOpen = controlledOpen ?? open;\n\n // Controlled value\n useEffect(() => {\n if (value !== undefined) setDate(value);\n }, [value]);\n\n useEffect(() => {\n if (controlledOpen !== undefined) setOpen(controlledOpen);\n }, [controlledOpen]);\n\n useEffect(() => {\n const listener = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (wrapperRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;\n if (controlledOpen === undefined) setOpen(false);\n onOpenChange?.(false);\n };\n document.addEventListener('click', listener);\n return () => document.removeEventListener('click', listener);\n }, [controlledOpen, onOpenChange]);\n\n const toggleOpen = useCallback((val: boolean) => {\n if (controlledOpen === undefined) setOpen(val);\n onOpenChange?.(val);\n }, [controlledOpen, onOpenChange]);\n\n const updateTime = useCallback((type: 'h' | 'm' | 's', num: number) => {\n const base = date ? new Date(date) : new Date(0, 0, 0, 0, 0, 0, 0);\n if (type === 'h') base.setHours(num);\n else if (type === 'm') base.setMinutes(num);\n else base.setSeconds(num);\n\n if (value === undefined) setDate(base);\n onChange?.(base);\n }, [date, value, onChange]);\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (value === undefined) setDate(null);\n onChange?.(null);\n toggleOpen(false);\n };\n\n const handleNow = () => {\n const now = new Date();\n if (value === undefined) setDate(now);\n onChange?.(now);\n toggleOpen(false);\n };\n\n const handleOk = () => {\n toggleOpen(false);\n };\n\n // Disabled time calculation\n const disabled12 = useMemo(() => disabledTime?.() ?? {}, [disabledTime]);\n const disabledHours = useMemo(() => disabled12.disabledHours?.() ?? [], [disabled12]);\n const currentHour = date?.getHours() ?? 0;\n const disabledMinutes = useMemo(\n () => disabled12.disabledMinutes?.(currentHour) ?? [],\n [disabled12, currentHour]\n );\n const currentMinute = date?.getMinutes() ?? 0;\n const disabledSeconds = useMemo(\n () => disabled12.disabledSeconds?.(currentHour, currentMinute) ?? [],\n [disabled12, currentHour, currentMinute]\n );\n\n const hours = generateSteps(24, hourStep);\n const minutes = generateSteps(60, minuteStep);\n const seconds = generateSteps(60, secondStep);\n\n const filteredHours = hideDisabledOptions ? hours.filter((h) => !disabledHours.includes(h)) : hours;\n const filteredMinutes = hideDisabledOptions ? minutes.filter((m) => !disabledMinutes.includes(m)) : minutes;\n const filteredSeconds = hideDisabledOptions ? seconds.filter((s) => !disabledSeconds.includes(s)) : seconds;\n\n const hasValue = date !== null;\n const displayValue = hasValue ? formatTime(date, format, use12Hours) : '';\n\n const cls = classNames(prefixCls, className, `${prefixCls}_${size}`, {\n [`${prefixCls}_disabled`]: disabled,\n [`${prefixCls}_open`]: isOpen,\n [`${prefixCls}_has-value`]: hasValue,\n });\n\n const renderOverlay = () => (\n <div className={`${prefixCls}__dropdown`} ref={dropdownRef}>\n <div className={`${prefixCls}__panel`}>\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getHours() ?? 0}\n items={filteredHours}\n disabledItems={hideDisabledOptions ? [] : disabledHours}\n loop={loop}\n onChange={(h) => updateTime('h', h)}\n />\n {showsMinutes(format) && (\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getMinutes() ?? 0}\n items={filteredMinutes}\n disabledItems={hideDisabledOptions ? [] : disabledMinutes}\n loop={loop}\n onChange={(m) => updateTime('m', m)}\n />\n )}\n {showsSeconds(format) && (\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getSeconds() ?? 0}\n items={filteredSeconds}\n disabledItems={hideDisabledOptions ? [] : disabledSeconds}\n loop={loop}\n onChange={(s) => updateTime('s', s)}\n />\n )}\n </div>\n <div className={`${prefixCls}__footer`}>\n {renderExtraFooter && <div className={`${prefixCls}__extra-footer`}>{renderExtraFooter()}</div>}\n <div className={`${prefixCls}__footer-actions`}>\n {showNow && <a className={`${prefixCls}__now-btn`} onClick={handleNow}>{locale.TimePicker.now}</a>}\n <button type=\"button\" className={`${prefixCls}__ok-btn`} onClick={handleOk}>{locale.TimePicker.okText}</button>\n </div>\n </div>\n </div>\n );\n\n return (\n <div className={cls} style={style} ref={wrapperRef}>\n <Popup\n trigger=\"manual\"\n placement=\"bottom-start\"\n arrow={false}\n visible={isOpen}\n content={renderOverlay()}>\n <div\n className={`${prefixCls}__input`}\n onClick={() => !disabled && toggleOpen(!isOpen)}>\n <input\n className={`${prefixCls}__input-field`}\n readOnly={inputReadOnly}\n disabled={disabled}\n placeholder={placeholder}\n value={displayValue}\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n onKeyDown={(e) => {\n if (e.key === 'Escape' && isOpen) toggleOpen(false);\n }}\n />\n <span className={`${prefixCls}__suffix`}>\n {allowClear && hasValue && !disabled ? (\n <button type=\"button\" className={`${prefixCls}__clear`} onClick={handleClear} aria-label=\"Clear time\">\n <ClearIcon size=\"1em\" />\n </button>\n ) : null}\n <span className={`${prefixCls}__icon`}>\n {suffixIcon ?? <ClockIcon size=\"1em\" />}\n </span>\n </span>\n </div>\n </Popup>\n </div>\n );\n};\n\nTimePicker.displayName = 'TimePicker';\n\nexport default TimePicker;\n"],"mappings":"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"}
1
+ {"version":3,"file":"time-picker.js","names":["Popup"],"sources":["../../src/time-picker/time-picker.tsx"],"sourcesContent":["import { useEffect, useState, useRef, useCallback, useContext, useMemo } from 'react';\nimport classNames from 'classnames';\nimport { ConfigContext } from '../config-provider/config-context';\nimport { getPrefixCls } from '../_utils/general';\nimport { useLocale } from '../_utils/use-locale';\nimport { ClockIcon, ClearIcon } from '../_utils/components';\nimport Popup from '../popup';\nimport TimePanel from './time-panel';\nimport { TimePickerProps } from './types';\n\ninterface PendingTime {\n h: number | null;\n m: number | null;\n s: number | null;\n}\n\nconst EMPTY_PENDING: PendingTime = { h: null, m: null, s: null };\n\nfunction formatTime(date: Date, format: string, use12Hours: boolean): string {\n let h = date.getHours();\n const m = String(date.getMinutes()).padStart(2, '0');\n const s = String(date.getSeconds()).padStart(2, '0');\n let period = '';\n\n if (use12Hours) {\n period = h >= 12 ? ' PM' : ' AM';\n h = h % 12 || 12;\n }\n\n return format\n .replace('HH', String(h).padStart(2, '0'))\n .replace('H', String(h))\n .replace('mm', m)\n .replace('ss', s) + period;\n}\n\nfunction generateSteps(count: number, step: number): number[] {\n const items: number[] = [];\n for (let i = 0; i < count; i += step) {\n items.push(i);\n }\n return items;\n}\n\nfunction showsSeconds(format: string): boolean {\n return format.includes('ss') || format.includes('s');\n}\n\nfunction showsMinutes(format: string): boolean {\n return format.includes('mm') || format.includes('m');\n}\n\nconst TimePicker = (props: TimePickerProps): React.ReactElement => {\n const locale = useLocale();\n const {\n defaultValue,\n value,\n open: controlledOpen,\n format = 'HH:mm:ss',\n use12Hours = false,\n hourStep = 1,\n minuteStep = 1,\n secondStep = 1,\n disabled = false,\n placeholder = locale.TimePicker.selectTime,\n allowClear = true,\n size = 'md',\n inputReadOnly = true,\n disabledTime,\n hideDisabledOptions = false,\n loop = false,\n showNow = true,\n renderExtraFooter,\n suffixIcon,\n onChange,\n onOpenChange,\n className,\n style,\n prefixCls: customisedCls,\n } = props;\n\n const configContext = useContext(ConfigContext);\n const prefixCls = getPrefixCls('time-picker', configContext.prefixCls, customisedCls);\n\n const [date, setDate] = useState<Date | null>(value ?? defaultValue ?? null);\n const [pending, setPending] = useState<PendingTime>(EMPTY_PENDING);\n const [open, setOpen] = useState(false);\n const wrapperRef = useRef<HTMLDivElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n const isOpen = controlledOpen ?? open;\n\n // Controlled value\n useEffect(() => {\n if (value !== undefined) setDate(value);\n }, [value]);\n\n useEffect(() => {\n if (controlledOpen !== undefined) setOpen(controlledOpen);\n }, [controlledOpen]);\n\n useEffect(() => {\n const listener = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (wrapperRef.current?.contains(target) || dropdownRef.current?.contains(target)) return;\n if (controlledOpen === undefined) setOpen(false);\n onOpenChange?.(false);\n setPending(EMPTY_PENDING);\n };\n document.addEventListener('click', listener);\n return () => document.removeEventListener('click', listener);\n }, [controlledOpen, onOpenChange]);\n\n const toggleOpen = useCallback((val: boolean) => {\n if (controlledOpen === undefined) setOpen(val);\n onOpenChange?.(val);\n if (!val) setPending(EMPTY_PENDING);\n }, [controlledOpen, onOpenChange]);\n\n /** Build a Date from committed date + pending overrides */\n const buildDate = useCallback((p: PendingTime): Date => {\n const base = date ? new Date(date) : new Date(0, 0, 0, 0, 0, 0, 0);\n if (p.h !== null) base.setHours(p.h);\n if (p.m !== null) base.setMinutes(p.m);\n if (p.s !== null) base.setSeconds(p.s);\n return base;\n }, [date]);\n\n const updatePending = useCallback((type: 'h' | 'm' | 's', num: number) => {\n setPending((prev) => ({ ...prev, [type]: num }));\n }, []);\n\n const commit = useCallback((newDate: Date) => {\n if (value === undefined) setDate(newDate);\n onChange?.(newDate);\n setPending(EMPTY_PENDING);\n }, [value, onChange]);\n\n const handleClear = (e: React.MouseEvent) => {\n e.stopPropagation();\n if (value === undefined) setDate(null);\n onChange?.(null);\n setPending(EMPTY_PENDING);\n toggleOpen(false);\n };\n\n const handleNow = () => {\n const now = new Date();\n commit(now);\n toggleOpen(false);\n };\n\n const handleOk = () => {\n if (pending.h !== null || pending.m !== null || pending.s !== null) {\n commit(buildDate(pending));\n }\n toggleOpen(false);\n };\n\n // Disabled time calculation — use pending values when available\n const effectiveHour = pending.h ?? date?.getHours() ?? 0;\n const effectiveMinute = pending.m ?? date?.getMinutes() ?? 0;\n\n const disabled12 = useMemo(() => disabledTime?.() ?? {}, [disabledTime]);\n const disabledHours = useMemo(() => disabled12.disabledHours?.() ?? [], [disabled12]);\n const disabledMinutes = useMemo(\n () => disabled12.disabledMinutes?.(effectiveHour) ?? [],\n [disabled12, effectiveHour]\n );\n const disabledSeconds = useMemo(\n () => disabled12.disabledSeconds?.(effectiveHour, effectiveMinute) ?? [],\n [disabled12, effectiveHour, effectiveMinute]\n );\n\n const hours = generateSteps(24, hourStep);\n const minutes = generateSteps(60, minuteStep);\n const seconds = generateSteps(60, secondStep);\n\n const filteredHours = hideDisabledOptions ? hours.filter((h) => !disabledHours.includes(h)) : hours;\n const filteredMinutes = hideDisabledOptions ? minutes.filter((m) => !disabledMinutes.includes(m)) : minutes;\n const filteredSeconds = hideDisabledOptions ? seconds.filter((s) => !disabledSeconds.includes(s)) : seconds;\n\n const hasPending = pending.h !== null || pending.m !== null || pending.s !== null;\n const previewDate = hasPending ? buildDate(pending) : null;\n const effectiveDate = previewDate ?? date;\n const hasValue = effectiveDate !== null;\n const displayValue = hasValue ? formatTime(effectiveDate, format, use12Hours) : '';\n\n const cls = classNames(prefixCls, className, `${prefixCls}_${size}`, {\n [`${prefixCls}_disabled`]: disabled,\n [`${prefixCls}_open`]: isOpen,\n [`${prefixCls}_has-value`]: hasValue,\n [`${prefixCls}_pending`]: hasPending,\n });\n\n const renderOverlay = () => (\n <div className={`${prefixCls}__dropdown`} ref={dropdownRef}>\n <div className={`${prefixCls}__panel`}>\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getHours() ?? null}\n pendingValue={pending.h}\n items={filteredHours}\n disabledItems={hideDisabledOptions ? [] : disabledHours}\n loop={loop}\n onChange={(h) => updatePending('h', h)}\n />\n {showsMinutes(format) && (\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getMinutes() ?? null}\n pendingValue={pending.m}\n items={filteredMinutes}\n disabledItems={hideDisabledOptions ? [] : disabledMinutes}\n loop={loop}\n onChange={(m) => updatePending('m', m)}\n />\n )}\n {showsSeconds(format) && (\n <TimePanel\n prefixCls={prefixCls}\n value={date?.getSeconds() ?? null}\n pendingValue={pending.s}\n items={filteredSeconds}\n disabledItems={hideDisabledOptions ? [] : disabledSeconds}\n loop={loop}\n onChange={(s) => updatePending('s', s)}\n />\n )}\n </div>\n <div className={`${prefixCls}__footer`}>\n {renderExtraFooter && <div className={`${prefixCls}__extra-footer`}>{renderExtraFooter()}</div>}\n <div className={`${prefixCls}__footer-actions`}>\n {showNow && <a className={`${prefixCls}__now-btn`} onClick={handleNow}>{locale.TimePicker.now}</a>}\n <button type=\"button\" className={`${prefixCls}__ok-btn`} onClick={handleOk}>{locale.TimePicker.okText}</button>\n </div>\n </div>\n </div>\n );\n\n return (\n <div className={cls} style={style} ref={wrapperRef}>\n <Popup\n trigger=\"manual\"\n placement=\"bottom-start\"\n arrow={false}\n visible={isOpen}\n content={renderOverlay()}>\n <div\n className={`${prefixCls}__input`}\n onClick={() => !disabled && toggleOpen(!isOpen)}>\n <input\n className={`${prefixCls}__input-field`}\n readOnly={inputReadOnly}\n disabled={disabled}\n placeholder={placeholder}\n value={displayValue}\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n onKeyDown={(e) => {\n if (e.key === 'Escape' && isOpen) toggleOpen(false);\n }}\n />\n <span className={`${prefixCls}__suffix`}>\n {allowClear && hasValue && !disabled ? (\n <button type=\"button\" className={`${prefixCls}__clear`} onClick={handleClear} aria-label=\"Clear time\">\n <ClearIcon size=\"1em\" />\n </button>\n ) : null}\n <span className={`${prefixCls}__icon`}>\n {suffixIcon ?? <ClockIcon size=\"1em\" />}\n </span>\n </span>\n </div>\n </Popup>\n </div>\n );\n};\n\nTimePicker.displayName = 'TimePicker';\n\nexport default TimePicker;\n"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import '../style/base.css';
2
2
  import './style/index.css';
3
+ import "./use-transition.js";
3
4
  import Transition from "./transition.js";
4
5
  //#region src/transition/index.tsx
5
6
  var transition_default = Transition;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/transition/index.tsx"],"sourcesContent":["import Transition from './transition';\n\nexport type { AnimationName, TransitionProps } from './transition';\nexport default Transition;\n"],"mappings":";;AAGA,IAAA,qBAAe"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/transition/index.tsx"],"sourcesContent":["import Transition from './transition';\n\nexport type { AnimationName, TransitionProps } from './transition';\nexport { default as useTransition } from './use-transition';\nexport type { TransitionState, UseTransitionOptions, UseTransitionResult } from './use-transition';\nexport default Transition;\n"],"mappings":";;;AAKA,IAAA,qBAAe"}
@@ -1,16 +1,31 @@
1
1
  import React from "react";
2
- import { CSSTransitionProps } from "react-transition-group/CSSTransition";
3
2
 
4
3
  //#region src/transition/transition.d.ts
5
4
  type AnimationName = 'zoom-center-top' | 'zoom-center-bottom' | 'zoom-center-left' | 'zoom-center-right' | 'zoom-top-start' | 'zoom-top' | 'zoom-top-end' | 'zoom-bottom-start' | 'zoom-bottom' | 'zoom-bottom-end' | 'zoom-left-start' | 'zoom-left' | 'zoom-left-end' | 'zoom-right-start' | 'zoom-right' | 'zoom-right-end' | 'slide-up' | 'slide-down';
6
5
  type TransitionProps = {
7
- /** Animation prefix */prefix?: string; /** Preset animation name */
8
- animation?: AnimationName; /** Prevent the transition conflict with the inner component */
6
+ in?: boolean;
7
+ timeout?: number | {
8
+ enter: number;
9
+ exit: number;
10
+ };
11
+ appear?: boolean;
12
+ unmountOnExit?: boolean;
13
+ mountOnEnter?: boolean; /** Animation prefix */
14
+ prefix?: string; /** Preset animation name */
15
+ animation?: AnimationName; /** Custom class name base (overrides prefix + animation) */
16
+ classNames?: string; /** Prevent the transition conflict with the inner component */
9
17
  wrapper?: boolean;
18
+ nodeRef?: React.RefObject<HTMLElement | null>;
19
+ onEnter?: () => void;
20
+ onEntering?: () => void;
21
+ onEntered?: () => void;
22
+ onExit?: () => void;
23
+ onExiting?: () => void;
24
+ onExited?: () => void;
10
25
  children?: React.ReactNode;
11
- } & Partial<CSSTransitionProps<HTMLElement>>;
26
+ };
12
27
  declare const Transition: {
13
- (props: TransitionProps): React.ReactElement;
28
+ (props: TransitionProps): React.ReactElement | null;
14
29
  displayName: string;
15
30
  };
16
31
  //#endregion
@@ -1,18 +1,43 @@
1
- import "react";
1
+ import useTransition from "./use-transition.js";
2
+ import React from "react";
2
3
  import { jsx } from "react/jsx-runtime";
3
- import { CSSTransition } from "react-transition-group";
4
4
  //#region src/transition/transition.tsx
5
+ function getTransitionClasses(base, state) {
6
+ switch (state) {
7
+ case "enter": return `${base}-enter`;
8
+ case "entering": return `${base}-enter ${base}-enter-active`;
9
+ case "entered": return `${base}-enter-done`;
10
+ case "exit": return `${base}-exit`;
11
+ case "exiting": return `${base}-exit ${base}-exit-active`;
12
+ case "exited": return `${base}-exit-done`;
13
+ default: return "";
14
+ }
15
+ }
5
16
  const Transition = (props) => {
6
- const { timeout = 300, unmountOnExit = true, appear = true, prefix = "ty", animation, classNames, nodeRef, children, wrapper, ...otherProps } = props;
7
- return /* @__PURE__ */ jsx(CSSTransition, {
8
- ...otherProps,
17
+ const { in: inProp = false, timeout = 300, unmountOnExit = true, mountOnEnter, appear = true, prefix = "ty", animation, classNames: classNamesProp, nodeRef, children, wrapper, onEnter, onEntering, onEntered, onExit, onExiting, onExited } = props;
18
+ const { state, shouldMount } = useTransition({
19
+ in: inProp,
9
20
  timeout,
10
21
  appear,
11
22
  unmountOnExit,
12
- nodeRef,
13
- classNames: classNames ? classNames : `${prefix}-${animation}`,
14
- children: wrapper ? /* @__PURE__ */ jsx("div", { children }) : children
23
+ mountOnEnter,
24
+ onEnter,
25
+ onEntering,
26
+ onEntered,
27
+ onExit,
28
+ onExiting,
29
+ onExited,
30
+ nodeRef
15
31
  });
32
+ if (!shouldMount) return null;
33
+ const transitionClasses = getTransitionClasses(classNamesProp ? classNamesProp : `${prefix}-${animation}`, state);
34
+ const child = wrapper ? /* @__PURE__ */ jsx("div", { children }) : children;
35
+ if (React.isValidElement(child)) {
36
+ const existingClassName = child.props.className || "";
37
+ const mergedClassName = existingClassName ? `${existingClassName} ${transitionClasses}`.trim() : transitionClasses;
38
+ return React.cloneElement(child, { className: mergedClassName || void 0 });
39
+ }
40
+ return child;
16
41
  };
17
42
  Transition.displayName = "Transition";
18
43
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"transition.js","names":[],"sources":["../../src/transition/transition.tsx"],"sourcesContent":["import React from 'react';\nimport { CSSTransition } from 'react-transition-group';\nimport { CSSTransitionProps } from 'react-transition-group/CSSTransition';\n\nexport type AnimationName =\n | 'zoom-center-top'\n | 'zoom-center-bottom'\n | 'zoom-center-left'\n | 'zoom-center-right'\n | 'zoom-top-start'\n | 'zoom-top'\n | 'zoom-top-end'\n | 'zoom-bottom-start'\n | 'zoom-bottom'\n | 'zoom-bottom-end'\n | 'zoom-left-start'\n | 'zoom-left'\n | 'zoom-left-end'\n | 'zoom-right-start'\n | 'zoom-right'\n | 'zoom-right-end'\n | 'slide-up'\n | 'slide-down';\n\nexport type TransitionProps = {\n /** Animation prefix */\n prefix?: string;\n\n /** Preset animation name */\n animation?: AnimationName;\n\n /** Prevent the transition conflict with the inner component */\n wrapper?: boolean;\n children?: React.ReactNode;\n} & Partial<CSSTransitionProps<HTMLElement>>;\n\nconst Transition = (props: TransitionProps): React.ReactElement => {\n const {\n timeout = 300,\n unmountOnExit = true,\n appear = true,\n prefix = 'ty',\n animation,\n classNames,\n nodeRef,\n children,\n wrapper,\n ...otherProps\n } = props;\n\n return (\n <CSSTransition\n {...(otherProps as CSSTransitionProps<HTMLElement>)}\n timeout={timeout}\n appear={appear}\n unmountOnExit={unmountOnExit}\n nodeRef={nodeRef}\n classNames={classNames ? classNames : `${prefix}-${animation}`}>\n {wrapper ? <div>{children}</div> : (children as React.ReactElement)}\n </CSSTransition>\n );\n};\n\nTransition.displayName = 'Transition';\n\nexport default Transition;\n"],"mappings":";;;;AAoCA,MAAM,cAAc,UAA+C;CACjE,MAAM,EACJ,UAAU,KACV,gBAAgB,MAChB,SAAS,MACT,SAAS,MACT,WACA,YACA,SACA,UACA,SACA,GAAG,eACD;AAEJ,QACE,oBAAC,eAAD;EACE,GAAK;EACI;EACD;EACO;EACN;EACT,YAAY,aAAa,aAAa,GAAG,OAAO,GAAG;YAClD,UAAU,oBAAC,OAAD,EAAM,UAAe,CAAA,GAAI;EACtB,CAAA;;AAIpB,WAAW,cAAc"}
1
+ {"version":3,"file":"transition.js","names":[],"sources":["../../src/transition/transition.tsx"],"sourcesContent":["import React from 'react';\nimport useTransition, { TransitionState } from './use-transition';\n\nexport type AnimationName =\n | 'zoom-center-top'\n | 'zoom-center-bottom'\n | 'zoom-center-left'\n | 'zoom-center-right'\n | 'zoom-top-start'\n | 'zoom-top'\n | 'zoom-top-end'\n | 'zoom-bottom-start'\n | 'zoom-bottom'\n | 'zoom-bottom-end'\n | 'zoom-left-start'\n | 'zoom-left'\n | 'zoom-left-end'\n | 'zoom-right-start'\n | 'zoom-right'\n | 'zoom-right-end'\n | 'slide-up'\n | 'slide-down';\n\nexport type TransitionProps = {\n in?: boolean;\n timeout?: number | { enter: number; exit: number };\n appear?: boolean;\n unmountOnExit?: boolean;\n mountOnEnter?: boolean;\n\n /** Animation prefix */\n prefix?: string;\n\n /** Preset animation name */\n animation?: AnimationName;\n\n /** Custom class name base (overrides prefix + animation) */\n classNames?: string;\n\n /** Prevent the transition conflict with the inner component */\n wrapper?: boolean;\n\n nodeRef?: React.RefObject<HTMLElement | null>;\n\n onEnter?: () => void;\n onEntering?: () => void;\n onEntered?: () => void;\n onExit?: () => void;\n onExiting?: () => void;\n onExited?: () => void;\n\n children?: React.ReactNode;\n};\n\nfunction getTransitionClasses(base: string, state: TransitionState): string {\n switch (state) {\n case 'enter':\n return `${base}-enter`;\n case 'entering':\n return `${base}-enter ${base}-enter-active`;\n case 'entered':\n return `${base}-enter-done`;\n case 'exit':\n return `${base}-exit`;\n case 'exiting':\n return `${base}-exit ${base}-exit-active`;\n case 'exited':\n return `${base}-exit-done`;\n default:\n return '';\n }\n}\n\nconst Transition = (props: TransitionProps): React.ReactElement | null => {\n const {\n in: inProp = false,\n timeout = 300,\n unmountOnExit = true,\n mountOnEnter,\n appear = true,\n prefix = 'ty',\n animation,\n classNames: classNamesProp,\n nodeRef,\n children,\n wrapper,\n onEnter,\n onEntering,\n onEntered,\n onExit,\n onExiting,\n onExited,\n } = props;\n\n const { state, shouldMount } = useTransition({\n in: inProp,\n timeout,\n appear,\n unmountOnExit,\n mountOnEnter,\n onEnter,\n onEntering,\n onEntered,\n onExit,\n onExiting,\n onExited,\n nodeRef,\n });\n\n if (!shouldMount) {\n return null;\n }\n\n const base = classNamesProp ? classNamesProp : `${prefix}-${animation}`;\n const transitionClasses = getTransitionClasses(base, state);\n\n const child = wrapper ? <div>{children}</div> : children;\n\n if (React.isValidElement(child)) {\n const existingClassName = (child.props as { className?: string }).className || '';\n const mergedClassName = existingClassName\n ? `${existingClassName} ${transitionClasses}`.trim()\n : transitionClasses;\n\n return React.cloneElement(child as React.ReactElement<{ className?: string }>, {\n className: mergedClassName || undefined,\n });\n }\n\n return child as React.ReactElement;\n};\n\nTransition.displayName = 'Transition';\n\nexport default Transition;\n"],"mappings":";;;;AAsDA,SAAS,qBAAqB,MAAc,OAAgC;AAC1E,SAAQ,OAAR;EACE,KAAK,QACH,QAAO,GAAG,KAAK;EACjB,KAAK,WACH,QAAO,GAAG,KAAK,SAAS,KAAK;EAC/B,KAAK,UACH,QAAO,GAAG,KAAK;EACjB,KAAK,OACH,QAAO,GAAG,KAAK;EACjB,KAAK,UACH,QAAO,GAAG,KAAK,QAAQ,KAAK;EAC9B,KAAK,SACH,QAAO,GAAG,KAAK;EACjB,QACE,QAAO;;;AAIb,MAAM,cAAc,UAAsD;CACxE,MAAM,EACJ,IAAI,SAAS,OACb,UAAU,KACV,gBAAgB,MAChB,cACA,SAAS,MACT,SAAS,MACT,WACA,YAAY,gBACZ,SACA,UACA,SACA,SACA,YACA,WACA,QACA,WACA,aACE;CAEJ,MAAM,EAAE,OAAO,gBAAgB,cAAc;EAC3C,IAAI;EACJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CAAC;AAEF,KAAI,CAAC,YACH,QAAO;CAIT,MAAM,oBAAoB,qBADb,iBAAiB,iBAAiB,GAAG,OAAO,GAAG,aACP,MAAM;CAE3D,MAAM,QAAQ,UAAU,oBAAC,OAAD,EAAM,UAAe,CAAA,GAAG;AAEhD,KAAI,MAAM,eAAe,MAAM,EAAE;EAC/B,MAAM,oBAAqB,MAAM,MAAiC,aAAa;EAC/E,MAAM,kBAAkB,oBACpB,GAAG,kBAAkB,GAAG,oBAAoB,MAAM,GAClD;AAEJ,SAAO,MAAM,aAAa,OAAqD,EAC7E,WAAW,mBAAmB,KAAA,GAC/B,CAAC;;AAGJ,QAAO;;AAGT,WAAW,cAAc"}