NumberWithUnit.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import React from 'react';
  2. import { InputNumber, Select, Space, SpaceProps } from 'antd';
  3. import type { InputNumberProps } from 'antd/es/input-number';
  4. import type { SelectProps } from 'antd/es/select';
  5. const { Option } = Select;
  6. export interface NumberUnitOption {
  7. label: React.ReactNode;
  8. value: string;
  9. }
  10. export interface NumberUnitValue {
  11. number?: number;
  12. unit?: string;
  13. }
  14. export type NumberWithUnitProps = SpaceProps & {
  15. value?: NumberUnitValue;
  16. onChange?: (next: NumberUnitValue) => void;
  17. numberClassName?: string;
  18. unitClassName?: string;
  19. className?: string;
  20. options: NumberUnitOption[];
  21. defaultUnit?: string;
  22. defaultNumber?: number;
  23. numberProps?: Partial<InputNumberProps>;
  24. selectProps?: Partial<SelectProps>;
  25. };
  26. const NumberWithUnit: React.FC<NumberWithUnitProps> = ({
  27. value = {},
  28. onChange,
  29. numberClassName,
  30. unitClassName,
  31. className,
  32. options,
  33. defaultUnit,
  34. defaultNumber,
  35. numberProps,
  36. selectProps,
  37. onBlur,
  38. ...rest // ← 这里会收到、style 等
  39. }) => {
  40. const unit = value?.unit ?? defaultUnit ?? undefined;
  41. const triggerChange = (changed: Partial<NumberUnitValue>) => {
  42. onChange?.({ ...value, ...changed });
  43. };
  44. return (
  45. <>
  46. <style>{`
  47. .my-space .ant-space-item:nth-child(1) {
  48. width: 70%;
  49. }
  50. .my-space .ant-space-item:nth-child(2) {
  51. width: 30%;
  52. }
  53. `}</style>
  54. <Space {...rest} className={`${className} my-space`}>
  55. <InputNumber
  56. className={numberClassName}
  57. value={value?.number}
  58. onChange={(n) =>
  59. triggerChange({ number: typeof n === 'number' ? n : undefined })
  60. }
  61. {...numberProps}
  62. defaultValue={defaultNumber}
  63. onBlur={onBlur}
  64. />
  65. <Select
  66. className={unitClassName}
  67. value={unit}
  68. onChange={(u) => triggerChange({ unit: u })}
  69. {...selectProps}
  70. >
  71. {options.map((opt) => (
  72. <Option key={opt.value} value={opt.value}>
  73. {opt.label}
  74. </Option>
  75. ))}
  76. </Select>
  77. </Space>
  78. </>
  79. );
  80. };
  81. export default NumberWithUnit;