x-ui-design 0.7.57 → 0.7.59

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,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { TRangePickerProps } from '../../../types/datepicker';
3
3
  import './style.css';
4
- declare const RangePicker: ({ prefixCls, value, onChange, placeholder, disabled, error, format, prefix, allowClear, inputReadOnly, size, picker, locale, disabledDate, onOpenChange, onCalendarChange, style, className, separator, defaultValue, bordered }: TRangePickerProps) => React.JSX.Element;
4
+ declare const RangePicker: ({ prefixCls, value, onChange, placeholder, disabled, error, format, prefix, allowClear, inputReadOnly, size, picker, locale, disabledDate, onOpenChange, onCalendarChange, style, className, separator, defaultValue, bordered, getPopupContainer }: TRangePickerProps) => React.JSX.Element;
5
5
  export default RangePicker;
package/dist/index.esm.js CHANGED
@@ -2304,6 +2304,12 @@ var DatePicker$1 = /*#__PURE__*/Object.freeze({
2304
2304
  default: DatePicker
2305
2305
  });
2306
2306
 
2307
+ const ConditionalWrapper = ({
2308
+ condition,
2309
+ wrapper,
2310
+ children
2311
+ }) => condition ? wrapper(children) : children;
2312
+
2307
2313
  var css_248z$e = ".xUi-rangepicker-range-container{font-size:14px;position:relative;user-select:none}.xUi-rangepicker-range-input-wrapper{background-color:#fff;border-radius:6px;display:flex;transition:all .3s;width:100%}.xUi-rangepicker-range-input-wrapper:hover{border-color:#4096ff}.xUi-rangepicker-range-input{align-items:center;border-right:1px solid var(--xui-border-color);cursor:pointer;display:flex;flex:1;padding:4px 11px}.xUi-rangepicker-range-input:last-child{border-right:none}.xUi-rangepicker-range-input input{background:transparent;border:none;color:#000;cursor:pointer;font-size:14px;outline:none;width:100%}.xUi-rangepicker-range-input input::placeholder{color:#bfbfbf}.xUi-rangepicker-range-clear,.xUi-rangepicker-range-icon{align-items:center;display:flex;margin-left:8px;transition:color .3s}.xUi-rangepicker-range-icon{color:rgba(0,0,0,.25)}.xUi-rangepicker-range-clear{color:rgba(0,0,0,.45);cursor:pointer}.xUi-rangepicker-range-clear:hover{color:#000}.xUi-rangepicker-range-dropdown-wrapper{background:#fff;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);display:none;left:0;margin-top:4px;min-width:560px;opacity:1;padding:8px;position:absolute;top:100%;transform:translateY(4px);transition:opacity .2s ease,transform .2s ease;z-index:1050}.xUi-rangepicker-range-dropdown-wrapper.show{display:flex}.xUi-rangepicker-dropdown-range,.xUi-rangepicker-range-dropdown{background-color:#fff;border:1px solid var(--xui-border-color);border-radius:6px;display:flex;margin-top:2px;overflow:hidden}.xUi-rangepicker-calendar{background:#fff;border-radius:6px;margin:12px}.xUi-rangepicker-calendar.month,.xUi-rangepicker-calendar.year{width:280px}.xUi-rangepicker-calendar-header{align-items:center;display:flex;font-weight:500;justify-content:space-between}.xUi-rangepicker-month,.xUi-rangepicker-year{background:none;border:none;border-radius:4px;color:var(--xui-text-color);cursor:pointer;height:30px;line-height:30px;margin:7px;min-width:30px;text-align:center;transition:all .2s}.xUi-rangepicker-day:disabled,.xUi-rangepicker-month:disabled,.xUi-rangepicker-select:disabled,.xUi-rangepicker-year:disabled{background-color:var(--xui-color-disabled);cursor:not-allowed;opacity:.5}.xUi-rangepicker-day:not(:disabled):hover,.xUi-rangepicker-month:not(:disabled):hover,.xUi-rangepicker-year:not(:disabled):hover{background:var(--xui-primary-color-light);color:#fff}.xUi-rangepicker-calendar-header button,.xUi-rangepicker-dropdown-selects button,.xUi-rangepicker-nav-buttons button{background:transparent;border:none;color:#595959;cursor:pointer;font-size:14px;font-weight:600;line-height:1;padding:0 6px;transition:color .2s ease}.xUi-rangepicker-nav-buttons button{font-size:20px;font-weight:400}.xUi-rangepicker-calendar-header button:hover,.xUi-rangepicker-dropdown-selects button:hover,.xUi-rangepicker-nav-buttons button:hover{color:var(--xui-primary-color)}.xUi-rangepicker-input{align-items:center;background-color:transparent;border:1px solid var(--xui-border-color);border-radius:6px;color:var(--xui-text-color);cursor:pointer;display:flex;gap:8px;justify-content:space-between;padding:3px 7px;transition:all .3s}.xUi-rangepicker-input.noBordered{border:none!important}.xUi-rangepicker-input input{border:none;color:var(--xui-text-color);font-size:var(--xui-font-size-sm);outline:none;padding:0}.xUi-rangepicker-input:placeholder-shown{text-overflow:ellipsis}.xUi-rangepicker-input:hover{border-color:var(--xui-primary-color)}.xUi-rangepicker-weekday-row{background-color:#fff;box-shadow:0 1px 0 rgba(0,0,0,.1);display:grid;gap:4px;grid-template-columns:repeat(7,1fr);position:sticky;top:0;z-index:1}.xUi-rangepicker-weekday{align-items:center;color:var(--xui-text-color);display:flex;font-size:12px;font-weight:500;font-weight:600;height:30px;justify-content:center;text-align:center}.xUi-rangepicker-days-grid,.xUi-rangepicker-grid{display:grid;gap:2px;grid-template-columns:repeat(3,1fr)}.xUi-rangepicker-days-grid.day{grid-template-columns:repeat(7,0fr)}.xUi-rangepicker-day{background-color:transparent;border:1px solid transparent;border-radius:4px;cursor:pointer;height:30px;line-height:30px;text-align:center;transition:background-color .3s,color .3s;width:30px}.xUi-rangepicker-day:hover{background-color:var(--xui-primary-color);border-radius:4px;color:#fff}.xUi-rangepicker-day.xUi-rangepicker-other-month:hover{background-color:var(--xui-color-disabled)!important;color:var(--xui-text-color)}.xUi-rangepicker-range-end:not(.xUi-rangepicker-other-month),.xUi-rangepicker-range-start:not(.xUi-rangepicker-other-month),.xUi-rangepicker-selected:not(.xUi-rangepicker-other-month){background-color:var(--xui-primary-color)!important;color:#fff;font-weight:600}.xUi-rangepicker-in-range:not(.xUi-rangepicker-other-month){background-color:#f0f5ff}.xUi-rangepicker-hover-end{background-color:var(--xui-primary-color)!important;color:#fff}.xUi-rangepicker-disabled,.xUi-rangepicker-other-month{color:#ccc}.xUi-rangepicker-disabled{cursor:not-allowed}.xUi-rangepicker-footer{display:flex;grid-column:span 7;justify-content:center;padding-top:6px}.xUi-rangepicker-select{background:none;border:none;color:var(--xui-primary-color);cursor:pointer}.xUi-rangepicker-input.sm{font-size:var(--xui-font-size-sm);padding:4px 8px}.xUi-rangepicker-input.md{font-size:var(--xui-font-size-md);padding:8px 12px}.xUi-rangepicker-input.lg{font-size:var(--xui-font-size-lg);padding:10px 16px}.xUi-rangepicker-dropdown-wrapper{opacity:0;pointer-events:none;position:absolute;transform:scale(.95);transition:opacity .2s ease,transform .2s ease;z-index:1000}.xUi-rangepicker-dropdown-wrapper.bottomLeft{left:0;margin-top:4px;top:100%}.xUi-rangepicker-dropdown-wrapper.bottomRight{margin-top:4px;right:0;top:100%}.xUi-rangepicker-dropdown-wrapper.topLeft{bottom:100%;left:0;margin-bottom:4px}.xUi-rangepicker-dropdown-wrapper.topRight{bottom:100%;margin-bottom:4px;right:0}.xUi-rangepicker-dropdown-wrapper.show{opacity:1;pointer-events:auto;transform:scale(1)}.xUi-rangepicker-large .xUi-rangepicker-selected-date{font-size:16px}.xUi-rangepicker-large .xUi-rangepicker-input{padding:11px}.xUi-rangepicker-middle .xUi-rangepicker-input{padding:6px 11px}.xUi-rangepicker-dropdown-trigger{background-color:#fff;border:1px solid var(--xui-border-color);border-radius:2px;cursor:pointer;line-height:32px;padding:0 8px}.xUi-rangepicker-dropdown-menu{background:#fff;border:1px solid var(--xui-border-color);box-shadow:0 2px 8px rgba(0,0,0,.15);max-height:200px;overflow-y:auto;position:absolute;z-index:1000}.xUi-rangepicker-dropdown-item{cursor:pointer;padding:4px 12px}.xUi-rangepicker-dropdown-item:hover{background:#f5f5f5}.xUi-rangepicker-dropdown-item.active{background-color:#e6f7ff;font-weight:700}.xUi-rangepicker-header{align-items:center;border-bottom:1px solid var(--xui-border-color);display:flex;gap:8px;justify-content:space-between;margin-bottom:8px;padding-bottom:12px;width:100%}.xUi-rangepicker-in-hover-range:not(.xUi-rangepicker-other-month){background-color:#f0f5ff;border:1px dashed var(--xui-primary-color);border-radius:4px}";
2308
2314
  styleInject(css_248z$e);
2309
2315
 
@@ -2328,7 +2334,8 @@ const RangePicker = ({
2328
2334
  className = '',
2329
2335
  separator,
2330
2336
  defaultValue,
2331
- bordered = true
2337
+ bordered = true,
2338
+ getPopupContainer
2332
2339
  }) => {
2333
2340
  const containerRef = useRef(null);
2334
2341
  const [isOpen, setIsOpen] = useState(false);
@@ -2336,10 +2343,12 @@ const RangePicker = ({
2336
2343
  useEffect(() => {
2337
2344
  setSelectedDates([value?.[0] || defaultValue?.[0] || null, value?.[1] || defaultValue?.[1] || null]);
2338
2345
  }, [value]);
2346
+ const popupRef = useRef(null);
2339
2347
  const [hoveredDate, setHoveredDate] = useState(null);
2340
2348
  const [currentMonth, setCurrentMonth] = useState(new Date().getMonth());
2341
2349
  const [currentYear, setCurrentYear] = useState(new Date().getFullYear());
2342
2350
  const [viewMode, setViewMode] = useState(picker === 'month' ? 'month' : picker === 'year' ? 'year' : 'day');
2351
+ const [dropdownPosition, setDropdownPosition] = useState({});
2343
2352
  const localeMonths = locale?.shortMonths || Array.from({
2344
2353
  length: 12
2345
2354
  }, (_, i) => new Date(0, i).toLocaleString(locale?.locale || 'default', {
@@ -2348,7 +2357,7 @@ const RangePicker = ({
2348
2357
  const localeWeekdays = locale?.shortWeekDays || ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
2349
2358
  useEffect(() => {
2350
2359
  const handleClickOutside = event => {
2351
- if (containerRef.current && !containerRef.current.contains(event.target)) {
2360
+ if (popupRef.current && !popupRef.current.contains(event.target) && containerRef.current && !containerRef.current.contains(event.target)) {
2352
2361
  setIsOpen(false);
2353
2362
  onOpenChange?.(false);
2354
2363
  }
@@ -2356,6 +2365,71 @@ const RangePicker = ({
2356
2365
  document.addEventListener('mousedown', handleClickOutside);
2357
2366
  return () => document.removeEventListener('mousedown', handleClickOutside);
2358
2367
  }, []);
2368
+ const dropdownPossition = useCallback(() => {
2369
+ if (!containerRef.current) return {};
2370
+ const inputRect = containerRef.current.getBoundingClientRect();
2371
+ const popupEl = popupRef.current;
2372
+ const dropdownHeight = popupEl?.offsetHeight || 290;
2373
+ const popupContainer = getPopupContainer ? getPopupContainer(document.body) : getScrollParent(containerRef.current, true) || document.body;
2374
+ const containerRect = popupContainer.getBoundingClientRect();
2375
+ const spaceAbove = inputRect.top - containerRect.top;
2376
+ const spaceBelow = containerRect.bottom - inputRect.bottom;
2377
+ const shouldShowAbove = spaceBelow < dropdownHeight && spaceAbove > dropdownHeight;
2378
+ if (getPopupContainer) {
2379
+ if (shouldShowAbove) {
2380
+ setDropdownPosition({
2381
+ top: (containerRef.current?.getBoundingClientRect().top || 0) + document.documentElement.scrollTop - 290,
2382
+ left: (containerRef.current?.getBoundingClientRect().left || 0) + document.documentElement.scrollLeft
2383
+ });
2384
+ } else {
2385
+ setDropdownPosition({
2386
+ top: (containerRef.current?.getBoundingClientRect().top || 0) + document.documentElement.scrollTop + (containerRef.current?.offsetHeight || 0),
2387
+ left: (containerRef.current?.getBoundingClientRect().left || 0) + document.documentElement.scrollLeft
2388
+ });
2389
+ }
2390
+ } else {
2391
+ setDropdownPosition({
2392
+ top: shouldShowAbove ? containerRef.current.offsetTop - (popupEl?.offsetHeight || dropdownHeight) - 8 : containerRef.current.offsetTop + containerRef.current.offsetHeight,
2393
+ left: containerRef.current.offsetLeft
2394
+ });
2395
+ }
2396
+ }, [isOpen, getPopupContainer]);
2397
+ function getScrollParent(el, includeSelf = false) {
2398
+ if (!el) return null;
2399
+ let current = includeSelf ? el : el.parentElement;
2400
+ while (current) {
2401
+ const style = getComputedStyle(current);
2402
+ const overflowY = style.overflowY;
2403
+ const overflowX = style.overflowX;
2404
+ const canScroll = overflowY === 'auto' || overflowY === 'scroll' || overflowX === 'auto' || overflowX === 'scroll';
2405
+ if (canScroll) {
2406
+ return current;
2407
+ }
2408
+ current = current.parentElement;
2409
+ }
2410
+ return document.scrollingElement;
2411
+ }
2412
+ useEffect(() => {
2413
+ if (!isOpen) return;
2414
+ const _dropdownPossition = () => dropdownPossition();
2415
+ _dropdownPossition();
2416
+ const controller = new AbortController();
2417
+ const scrollableParents = getScrollParent(containerRef.current, true);
2418
+ scrollableParents?.addEventListener('scroll', _dropdownPossition, {
2419
+ passive: true,
2420
+ signal: controller.signal
2421
+ });
2422
+ window.addEventListener('scroll', _dropdownPossition, {
2423
+ passive: true,
2424
+ signal: controller.signal
2425
+ });
2426
+ window.addEventListener('resize', _dropdownPossition, {
2427
+ signal: controller.signal
2428
+ });
2429
+ return () => {
2430
+ controller.abort();
2431
+ };
2432
+ }, [isOpen, getPopupContainer, dropdownPossition]);
2359
2433
  const isInHoverRange = date => {
2360
2434
  const [start, end] = selectedDates;
2361
2435
  if (!start || end || !hoveredDate) return false;
@@ -2550,14 +2624,14 @@ const RangePicker = ({
2550
2624
  onChange?.(null, ['', '']);
2551
2625
  };
2552
2626
  return /*#__PURE__*/React.createElement("div", {
2553
- ref: containerRef,
2554
2627
  style: style,
2555
2628
  className: clsx([`${prefixCls}-range-container`, {
2556
2629
  [`${prefixCls}-${size}`]: size,
2557
2630
  [className]: className
2558
2631
  }])
2559
2632
  }, /*#__PURE__*/React.createElement("div", {
2560
- className: `${prefixCls}-range-input-wrapper`
2633
+ className: `${prefixCls}-range-input-wrapper`,
2634
+ ref: containerRef
2561
2635
  }, /*#__PURE__*/React.createElement("button", {
2562
2636
  type: "button",
2563
2637
  className: clsx([`${prefixCls}-input`, {
@@ -2569,14 +2643,16 @@ const RangePicker = ({
2569
2643
  onClick: e => {
2570
2644
  e.preventDefault();
2571
2645
  e.stopPropagation();
2572
- setIsOpen(!isOpen);
2573
- onOpenChange?.(!isOpen);
2646
+ if (!isOpen) {
2647
+ setIsOpen(!isOpen);
2648
+ onOpenChange?.(!isOpen);
2649
+ }
2574
2650
  }
2575
2651
  }, prefix, /*#__PURE__*/React.createElement("input", {
2576
2652
  readOnly: inputReadOnly,
2577
2653
  className: `${prefixCls}-selected-date`,
2578
2654
  placeholder: placeholder[0],
2579
- key: selectedDates[0]?.toUTCString(),
2655
+ key: `0_${selectedDates[0]?.toUTCString()}`,
2580
2656
  [inputReadOnly ? 'value' : 'defaultValue']: selectedDates[0] ? formatDate(selectedDates[0]) : ''
2581
2657
  }), /*#__PURE__*/React.createElement("span", {
2582
2658
  className: `${prefixCls}-range-separator`
@@ -2584,18 +2660,25 @@ const RangePicker = ({
2584
2660
  readOnly: inputReadOnly,
2585
2661
  className: `${prefixCls}-selected-date`,
2586
2662
  placeholder: placeholder[1],
2587
- key: selectedDates[1]?.toUTCString(),
2663
+ key: `1_${selectedDates[1]?.toUTCString()}`,
2588
2664
  [inputReadOnly ? 'value' : 'defaultValue']: selectedDates[1] ? formatDate(selectedDates[1]) : ''
2589
2665
  }), /*#__PURE__*/React.createElement("span", {
2590
2666
  className: `${prefixCls}-icon`
2591
2667
  }, allowClear && (selectedDates[0] || selectedDates[1]) ? /*#__PURE__*/React.createElement("span", {
2592
2668
  className: `${prefixCls}-clear`,
2593
2669
  onClick: handleClear
2594
- }, /*#__PURE__*/React.createElement(ClearIcon, null)) : /*#__PURE__*/React.createElement(CalendarIcon, null)))), isOpen && /*#__PURE__*/React.createElement("div", {
2595
- className: `${prefixCls}-dropdown-wrapper show`
2670
+ }, /*#__PURE__*/React.createElement(ClearIcon, null)) : /*#__PURE__*/React.createElement(CalendarIcon, null)))), isOpen && /*#__PURE__*/React.createElement(ConditionalWrapper, {
2671
+ condition: getPopupContainer !== undefined,
2672
+ wrapper: element => getPopupContainer ? /*#__PURE__*/createPortal(element, getPopupContainer(popupRef.current)) : /*#__PURE__*/React.createElement(React.Fragment, null, element)
2673
+ }, /*#__PURE__*/React.createElement("div", {
2674
+ ref: popupRef,
2675
+ className: `${prefixCls}-dropdown-wrapper show`,
2676
+ style: {
2677
+ ...dropdownPosition
2678
+ }
2596
2679
  }, /*#__PURE__*/React.createElement("div", {
2597
2680
  className: `${prefixCls}-dropdown-range`
2598
- }, renderCalendar(0, viewMode !== 'day'), viewMode === 'day' && renderCalendar(1, viewMode !== 'day'))));
2681
+ }, renderCalendar(0, viewMode !== 'day'), viewMode === 'day' && renderCalendar(1, viewMode !== 'day')))));
2599
2682
  };
2600
2683
 
2601
2684
  var RangePicker$1 = /*#__PURE__*/Object.freeze({
@@ -2603,12 +2686,6 @@ var RangePicker$1 = /*#__PURE__*/Object.freeze({
2603
2686
  default: RangePicker
2604
2687
  });
2605
2688
 
2606
- const ConditionalWrapper = ({
2607
- condition,
2608
- wrapper,
2609
- children
2610
- }) => condition ? wrapper(children) : children;
2611
-
2612
2689
  var css_248z$d = ".xUi-timepicker-wrapper{display:inline-block;font-size:14px;position:relative}.xUi-timepicker-input-wrapper{position:relative;width:100%}.xUi-timepicker-input{border:1px solid var(--xui-border-color);border-radius:6px;box-sizing:border-box;font-size:14px;height:32px;line-height:32px;padding:4px 11px;transition:all .3s;width:100%}.xUi-timepicker-input:focus,.xUi-timepicker-input:hover{border-color:var(--xui-primary-color-light)}.xUi-timepicker-input:focus{outline:none}.xUi-timepicker-input::placeholder{opacity:.6}.xUi-timepicker-clear{color:rgba(0,0,0,.45);cursor:pointer;font-size:12px;position:absolute;right:8px;top:50%;transform:translateY(-50%);z-index:2}.xUi-timepicker-clear:hover{color:rgba(0,0,0,.75)}.xUi-timepicker-popup{background:#fff;border:1px solid var(--xui-border-color);border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,.15);display:flex;left:0;padding:8px 0;z-index:1}.xUi-timepicker-panel{display:flex;width:100%}.xUi-timepicker-column{align-items:center;display:flex;flex:1;flex-direction:column;margin-bottom:5px;max-height:169px;overflow-x:hidden;overflow-y:auto;padding-left:4px;width:52px}.xUi-timepicker-column::-webkit-scrollbar,.xUi-timepicker-column::-webkit-scrollbar-thumb{width:4px}.xUi-timepicker-column:nth-child(2){border-left:1px solid var(--xui-border-color);border-right:1px solid var(--xui-border-color)}.xUi-timepicker-cell{align-items:center;border-radius:4px;cursor:pointer;display:flex;font-size:14px;justify-content:center;margin-bottom:2px;padding:6px 0;text-align:center;transition:background .3s;width:44px}.xUi-timepicker-cell:hover{background-color:#e6f4ff}.xUi-timepicker-cell-selected{background-color:#e6f4ff;font-weight:500}.xUi-timepicker-cell-disabled{color:rgba(0,0,0,.25);pointer-events:none;user-select:none}.xUi-timepicker-now-btn{color:#4096ff;cursor:pointer;font-weight:500;margin-top:10px;padding:0 0 4px;text-align:center;transition:background .3s}.xUi-timepicker-icons{align-items:center;display:flex;gap:4px;position:absolute;right:8px;top:50%;transform:translateY(-50%)}.xUi-timepicker-suffix{align-items:center;cursor:pointer;display:flex;justify-content:center}.xUi-timepicker-suffix svg{color:#999;height:14px;width:14px}.xUi-timepicker-clear{right:0;top:1px}.xUi-timepicker-actions{align-items:center;border-top:1px solid var(--xui-border-color);display:flex;justify-content:space-between;padding:0 4px}.xUi-timepicker-ok-btn{background-color:var(--xui-primary-color);border:none;border-radius:4px;color:#fff;cursor:pointer;margin-top:7px;outline:none;padding:4px 8px;transition:.3s ease}.xUi-timepicker-ok-btn:disabled{background-color:var(--xui-color-disabled);color:grey;font-size:13px}.xUi-timepicker-ok-btn:not(:disabled):hover{background-color:var(--xui-primary-color-light)}.xUi-timepicker-popup{margin-top:4px;position:absolute;top:100%}";
2613
2690
  styleInject(css_248z$d);
2614
2691
 
@@ -2638,7 +2715,6 @@ const TimePicker = ({
2638
2715
  }) => {
2639
2716
  const [open, setOpen] = useState(false);
2640
2717
  const [innerValue, setInnerValue] = useState(propValue || defaultValue ? new Date(propValue || defaultValue) : null);
2641
- useState(false);
2642
2718
  const [[showHour, showMinutes, showSeconds]] = useState(`${format}`.split(':'));
2643
2719
  const [tempValue, setTempValue] = useState(null);
2644
2720
  const inputRef = useRef(null);