توضیحات

باید بگم تنظیم کردن موقعیت تقویم در دیت پیکر خیلی منو اذیت کرد جوری که مجبور شدم براش یک پکیج جدا بنویسم! ولی هنوزم نمیتونم بگم 100% جواب میده، اگر مشکلی با پوزیشن تقویم داشتید میتونید در این قسمت مطرح کنید.

تو نسخه های اولیه برای کانتینر دیتپیکر از پوزیشن ریلیتیو استفاده میکردم که خوب راحته و محاسباتی لازم نداره ولی به مرور مشخص شد که پوزیشن ریلیتیو اصلا جوابگو نیست، یعنی ممکنه برای یکسری کارا جوابگو باشه ولی برای لیات های پیچیده تر صد در صد به مشکل میخوره.

اینجوری شد که تو ورژن های بعدی پوزیشن کانتینر رو به همون استاتیک تغییر دادم سعی کردم موقعیت تقویم رو با محاسبات جاوااسکریپت مشخص کنم ولی کاشف به عمل اومد که قضیه اونجوریم که ادم فکر میکنه ساده نیست و با چهارتا جمع و تفریق نمیشه موقعیت رو تنظیم کرد! محاسبات همینجوری پیچیده و پیچیده تر شد تا آخر تصمیم گرفتم کلشو به پکیج المنت پاپر منتقل کنم تا بشه ازش تو پروژه های دیگه هم استفاده کرد.

موقعیت تقویم

روش مشخص کردن موقعیت تقویم اینجوری که شما باید دوتا موقعیت اصلی و نسبی رو به صورت 'موقعیت اصلی-موقعیت نسبی' برای دیت پیکرتون تعریف کنید، موقعیت اصلی برای اینه که مشخص کنه تقویم باید کجای اینپوت باشه، که براش میتونید چهار تا مقدار بالا، پایین، چپ و راست رو در نظر بگیرید. موقعیت نسبی هم برای اینه که مشخص کنه تقویم کجای موقعیت اصلی قرار بگیره. که خودش از سه قسمت ابتدا، وسط و انتها تشکیل شده.

در زیر تمام موقعیت هایی که میشه برای دیت پیکر تعریف کنید رو آوردم :

  • top یا top-center
  • top-start یا top-left
  • top-end یا top-right
  • bottom یا bottom-center
  • bottom-start یا bottom-left
  • bottom-end یا bottom-right
  • left یا left-center
  • left-start یا left-top
  • left-end یا left-bottom
  • right یا right-center
  • right-start یا right-top
  • right-end یا right-bottom

نکات مهم

  1. مهم ترین نکته اینه که این پکیج فقط سعی میکنه در موقعیتی که براش مشخص کردید قرار بگیره ! چون ممکنه چینش المنت های در بر گیرنده دیت پیکر جوری باشه که تقویم در اون موقعیت جا نشه، یا کاربر شروع به اسکرول کردن یا ریسایز کردن صفحه کنه که در اون صورت هم باز موقعیت تقویم عوض میشه. البته شما میتونید دیت پیکر رو مجبور کنید تا موقعیت تقویم رو دقیقا همونجا که شما میخواید نشون بده، که در این صورت باید از پراپرتی های fixMainPosition و fixRelativePosition استفاده کنید.
  2. برای ایجاد فاصله بین تقویم و اینپوت از مارجین و پدینگ استفاده نکنید و به جاش از پراپرتی های offsetY و offsetX که در دیت پیکر قرار داده شده استفاده کنید.
  3. همونطور که در قسمت توضیحات گفتم پوزیشن ریلیتیو جوابگو نیست پس سعی نکنید پوزیشن کانتینر رو با سی اس اس به ریلیتیو تغییر بدید چون باعث اخلال تو محاسبات موقعیت میشه.
  4. برای فیکس کردن موقعیت اصلی مقدار fixMainPosition رو برابر true و برای فیکس کردن موقعیت نسبی مقدار fixRelativePosition رو برابر true قرار بدید.
  5. موقعیت پیشفرض تقویم برای چینش چپ به راست بهینه شده و مقدار آن برابر bottom-left هست، پس برای دایرکشن های راست به چپ که در زبان های فارسی و عربی کاربرد داره لازمه از موقعیت bottom-right استفاده کنید.
  6. اگر میخواید اندازه اینپوت رو تغییر بدید مقدار box-sizing اینپوت رو border-box بزارید.
  7. اگر دیت پیکر داخل کانتینر با پوزیشن فلکس و فلکس داریکشن column باشه (مثل نمونه پایین)، بهتره برای کانتینر دیتپیکرتون طول تعریف کنید.
  8. مقدار offsetY زمانی اعمال میشه که پوزیشن اصلی، بالا یا پایین باشه و مقدار offsetX هم، زمانی اعمال میشه که پوزیشن اصلی، چپ یا راست باشه.

مثال

import persian from "react-date-object/calendars/persian"
import persian_fa from "react-date-object/locales/persian_fa"
.
.
.
const containerRef = useRef()
const datePickerRef = useRef()

const [state, setState] = useState({
  mainPosition: "bottom",
  relativePosition: "center",
  fixMainPosition: false,
  fixRelativePosition: false,
  offsetY: 0,
  offsetX: 0
})

const updateState = (key, value) => setState({ 
  ...state, 
  [key]: value
})

useEffect(() => {
  containerRef.current.scrollTo(
    (containerRef.current.clientWidth * -1),
    (containerRef.current.clientHeight / 2)
  )

  datePickerRef.current.openCalendar()
}, [])

const {
  mainPosition,
  relativePosition,
  fixMainPosition,
  fixRelativePosition,
  offsetY,
  offsetX
} = state
.
.
.
<div>
  <div 
    style={{ 
      display: "flex", 
      justifyContent: "space-around",
      flexWrap: "wrap",
      margin: "10px 0" 
    }}
  >
    <label>
      موقعیت اصلی:
      <select
        value={mainPosition}
        onChange={e => updateState("mainPosition", e.target.value)}
        className="select"
      >
        <option value="top">بالا</option>
        <option value="bottom">پایین</option>
        <option value="left">چپ</option>
        <option value="right">راست</option>
      </select>
    </label>
    <label>
      <input
        type="checkbox"
        value={fixMainPosition}
        onChange={e => updateState("fixMainPosition", e.target.checked)}
      />
      فیکس شدن موقعیت اصلی
    </label>
    <label>
      موقعیت نسبی:
      <select
        value={relativePosition}
        onChange={e => updateState("relativePosition", e.target.value)}
        className="select"
      >
        <option value="start">شروع</option>
        <option value="center">وسط</option>
        <option value="end">پایان</option>
      </select>
    </label>
    <label>
      <input
        type="checkbox"
        value={fixRelativePosition}
        onChange={e => updateState("fixRelativePosition", e.target.checked)}
      />
      فیکس شدن موقعیت نسبی
    </label>
    <label>
      فاصله عمودی:
      <input
        type="number"
        className="input"
        style={{ width: "30px" }}
        value={offsetY}
        onChange={e => updateState("offsetY", Number(e.target.value))}
      />
    </label>
    <label>
      فاصله افقی:
      <input
        type="number"
        className="input"
        style={{ width: "30px" }}
        value={offsetX}
        onChange={e => updateState("offsetX", Number(e.target.value))}
      />
    </label>
  </div>
  <div
    ref={containerRef}
    style={{ 
      backgroundColor: "whitesmoke", 
      height: "500px", 
      overflow: "auto", 
      position: "relative",
      borderRadius: "5px",
      boxShadow: "inset 0 0 6px 0 #888" 
    }}
  >
    <div
      style={{ 
        width: "300%", 
        height: "200%", 
        display: "flex", 
        flexDirection: "column", 
        justifyContent: "center" 
      }}
    >
      <DatePicker
        ref={datePickerRef}
        containerStyle={{ //datepicker container style
          width: "180px",
          margin: "auto"
        }}
        style={{ //input style
          width: "100%",
          height: "26px",
          boxSizing: "border-box"
        }}
        calendarPosition={`${mainPosition}-${relativePosition}`}
        fixMainPosition={fixMainPosition}
        fixRelativePosition={fixRelativePosition}
        offsetY={offsetY}
        offsetX={offsetX}
        onClose={() => false}
        calendar={persian}
        locale={persian_fa}
      />
    </div>
  </div>
</div>
،،،،،

مثال های دیگر

دو مثال دیگر که مربوط به موقعیت تقویم میشوند هم وجود دارند که ممکن است بخواهید آنها را مشاهده کنید :

  1. Event ها #onPositionChange
  2. Ref تقویم و دیت پیکر #رفرش-کردن-موقعیت-تقویم