본문으로 건너뛰기

PlDateRangePicker

두 날 사이의 구간입니다. 달 두 개를 나란히 두고, 양 끝 사이의 띠는 두 번째 클릭이 닿기 전에 포인터를 따라 그려집니다.

React
tsx
import { PlDateRangePicker } from 'plass-ui';

<PlDateRangePicker label="Stay" startPlaceholder="Check in" endPlaceholder="Check out" />;
dart
import 'package:plass_ui/plass_ui.dart';

PlDateRangePicker(
  label: const Text('Stay'),
  startPlaceholder: const Text('Check in'),
  endPlaceholder: const Text('Check out'),
  value: stay,
  onChanged: (PlDateRange next) => setState(() => stay = next),
);

달력은 트리 밖으로 자기를 들어 올리므로 picker 위에 Overlay가 필요합니다.

Props

Prop타입기본값설명
valuePlDateRange | null선택된 구간. onValueChange와 함께 controlled로 씁니다
defaultValuePlDateRange | nulluncontrolled일 때 시작하는 구간
onValueChange(value: PlDateRange) => void언제나 객체와 함께 호출됩니다. 비워진 구간은 { start: null, end: null }입니다
minDateDate | null고를 수 있는 가장 이른 날. 일 단위입니다 — 시각은 무시됩니다
maxDateDate | null고를 수 있는 가장 늦은 날
shouldDisableDate(date: Date) => boolean범위 안이지만 그래도 쓸 수 없는 날을 막습니다 — 주말, 공휴일, 이미 예약된 방
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6한 주가 시작하는 요일. 기본은 locale이 말하는 대로이고, 0이 일요일입니다
defaultMonthDate값이 없을 때 달력이 열리는 달
monthCount1 | 22한 번에 보여 줄 달의 수. 달을 넘나드는 구간이 예외가 아니라 보통이라 2가 기본입니다
startPlaceholderReactNode아직 정하지 않은 쪽에 보이는 내용. trigger의 각 반쪽마다 하나씩
endPlaceholderReactNodestartPlaceholder를 보세요
presetsreadonly PlDateRangePreset[]달력 옆에 놓이는 지름길 — "지난 7일", "이번 달"
variant공통'solid' | 'glass' | 'ghost''glass'trigger의 재질. PlTextField와 같은 껍데기를 씁니다. solid는 시트에 파인 우물
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'높이와 타입 스케일
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30trigger의 그림자 깊이. 팝업은 3으로 고정입니다 — 팝업은 정말로 페이지 위에 떠 있습니다
openboolean팝업이 열려 있는지. onOpenChange와 함께 controlled로 씁니다
defaultOpenbooleanfalse팝업이 열린 채로 시작할지
onOpenChange(open: boolean) => void팝업이 열리고 닫힐 때 호출됩니다
localestringBCP 47 태그. 월과 요일 이름, 헤더 두 버튼의 순서, trigger가 날짜를 쓰는 방식을 정합니다. 기본은 브라우저의 것
formatIntl.DateTimeFormatOptions{ dateStyle: 'medium' }trigger가 양 끝을 쓰는 방식. Intl로 그대로 넘어갑니다
placeholderReactNode아무것도 고르지 않았을 때 trigger에 보이는 내용
clearablebooleanfalse값을 비우는 ×를 보여 줍니다
closeOnSelectbooleantrue양 끝이 다 정해지면 팝업을 닫습니다
labelsPartial<PlPickerLabels>picker가 스스로 말하는 문자열들. 전부 영어 기본값이 있습니다. 날짜 이름은 여기 없습니다 — 그건 Intl이 압니다
labelReactNodetrigger 위 라벨
descriptionReactNodetrigger 아래 보조 설명
errorReactNode오류 메시지. 존재 자체가 invalid 상태를 만듭니다
invalidboolean메시지 없이 invalid로 만듭니다
startIconReactNode값 앞의 글리프. 기본은 달력(또는 시계)입니다
fullWidthbooleanfalse컨테이너 너비만큼 확장
readOnlybooleanfalse값은 보이지만 바꿀 수 없고, 팝업도 열리지 않습니다
disabledbooleanfalse사용 불가
requiredbooleanfalse폼 제출 전에 값이 있어야 하는지
namestring폼 제출 시 필드를 식별합니다. 같은 이름의 hidden input 둘이라 양 끝이 FormData.getAll(name)으로 옵니다
classNames{ label?, control?, description?, error?: string }className이 닿지 않는 부분에 붙는 class. control은 실제로 조작하는 부분입니다
Prop타입기본값설명
value * PlDateRange선택된 구간. null이 아닙니다 — 비어 있는 것은 PlDateRange.empty입니다
onChangedValueChanged<PlDateRange>?새 구간과 함께 언제나 객체로 호출됩니다. 한 번의 선택에 두 번 울립니다 — 첫 누름에 start만, 둘째에 양 끝
openbool?팝업이 열려 있는지. onOpenChange와 함께 controlled로 씁니다
onOpenChangedValueChanged<bool>?달력이 열리거나 닫혀야 할 때 호출됩니다
defaultMonthDateTime?값이 없을 때 달력이 열리는 달
minDateDateTime?고를 수 있는 가장 이른 날. 일 단위입니다 — 시각은 무시됩니다
maxDateDateTime?고를 수 있는 가장 늦은 날
shouldDisableDatebool Function(DateTime date)?범위 안이지만 그래도 쓸 수 없는 날을 막습니다 — 주말, 공휴일, 이미 예약된 방
weekStartsOnPlassWeekday?한 주가 시작하는 요일. 기본은 locale이 말하는 대로이고, 0이 일요일입니다
namesPlDateNamesPlDateNames.english달력이 그리는 월과 요일 이름, 그리고 헤더가 그것들을 쓰는 순서. **React의 locale 문자열에 해당합니다** — 프레임워크에 Intl이 없으므로 단어를 객체로 받습니다
labelsPlPickerLabelsPlPickerLabels.englishpicker가 스스로 말하는 문자열들. 전부 영어 기본값이 있습니다. 날짜 이름은 여기 없습니다 — 그건 Intl이 압니다
formatValueString Function(DateTime value)?trigger가 값을 쓰는 방식. React의 Intl 옵션 대신 콜백입니다. 빼면 names의 medium 형식으로 씁니다
monthCountint2한 번에 보여 줄 달의 수. 달을 넘나드는 구간이 예외가 아니라 보통이라 2가 기본입니다
startPlaceholderWidget?아직 정하지 않은 쪽에 보이는 내용. trigger의 각 반쪽마다 하나씩
endPlaceholderWidget?startPlaceholder를 보세요
presetsList<PlDateRangePreset>const []달력 옆에 놓이는 지름길 — "지난 7일", "이번 달"
clearableboolfalse값을 비우는 ×를 보여 줍니다
closeOnSelectbooltrue양 끝이 다 정해지면 팝업을 닫습니다
variant공통PlassVariantPlassVariant.glasstrigger의 재질. PlTextField와 같은 껍데기를 씁니다. solid는 시트에 파인 우물
size공통PlassSizePlassSize.md높이와 타입 스케일
color공통PlassColorPlassColor.primary의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통PlassDensityPlassDensity.standard여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통int0trigger의 그림자 깊이. 팝업은 3으로 고정입니다 — 팝업은 정말로 페이지 위에 떠 있습니다
labelWidget?trigger 위 라벨
descriptionWidget?trigger 아래 보조 설명
errorWidget?오류 메시지. 존재 자체가 invalid 상태를 만듭니다
invalidbool?메시지 없이 invalid로 만듭니다
startIconWidget?값 앞의 글리프. 기본은 달력(또는 시계)입니다
fullWidthboolfalse컨테이너 너비만큼 확장
readOnlyboolfalse값은 보이지만 바꿀 수 없고, 팝업도 열리지 않습니다
disabledboolfalse사용 불가
semanticLabelString?보이는 label이 없는 trigger를 스크린 리더가 부를 이름
focusNodeFocusNode?포커스를 밖에서 제어할 때 넘깁니다
autofocusboolfalse트리에 들어가면서 포커스를 가져갑니다

나머지 <div> 속성은 field 래퍼로 그대로 통과합니다. color는 위 표의 color와 겹쳐서, defaultValue는 DOM 속성이 아니라 값으로 쓰기 때문에, children은 달력이 곧 컴포넌트이기 때문에 제외했습니다.

className은 label과 control, 그 아래 두 줄을 함께 담는 stack에 붙습니다. 그 안쪽 네 부분에 닿는 것이 classNames입니다: label, control(트리거), description, error.

picker는 controlled입니다. valueonChanged를 함께 주고, valuenull이 아닙니다. 비어 있는 구간은 PlDateRange.empty입니다.

PlDatePickerlocale과 헤더와 경계와 날짜 라이브러리의 부재에 대해 말한 것은 여기서도 그대로 성립합니다. 이건 그 컴포넌트에 끝이 하나 더 붙은 것입니다.

PlDateRange

Prop타입기본값설명
start * Date | null구간의 시작
end * Date | null끝. 첫 클릭과 둘째 클릭 사이에는 null입니다 — 반쪽짜리 구간은 실제로 존재하는 상태입니다
Prop타입기본값설명
startDateTime?구간의 시작
endDateTime?끝. 첫 클릭과 둘째 클릭 사이에는 null입니다 — 반쪽짜리 구간은 실제로 존재하는 상태입니다

PlDateRangePreset

Prop타입기본값설명
label * ReactNode버튼에 적히는 이름
value * PlDateRange | (() => PlDateRange)그것이 뜻하는 구간. 오늘에 달려 있다면 함수로 주세요 — 대개 그렇습니다. 모듈 로드 시점에 계산한 "지난 7일"은 탭을 밤새 열어 둔 사람에게 틀린 값입니다
Prop타입기본값설명
label * Widget버튼에 적히는 이름
build * PlDateRange Function()그것이 뜻하는 구간. React가 값도 허용하는 자리에서 여기서는 언제나 콜백입니다 — preset은 거의 언제나 오늘에 달려 있고, 시작할 때 한 번 계산한 "지난 7일"은 앱을 밤새 열어 둔 사람에게 틀린 값입니다

[Date, Date] 튜플도, prop 두 개도 아닙니다. 구간은 값 하나 입니다. 한 동작으로 고르고, 한 동작으로 비우고, 통째로 검증합니다. 그리고 이름 두 개가 호출자가 끝을 시작에 써 넣는 것을 막습니다.

반쪽짜리 구간은 실제로 존재하는 상태입니다(첫 클릭과 둘째 클릭 사이에 picker가 들고 있는 것이 그것입니다). 그래서 onValueChange는 첫 클릭 뒤에 { start, end: null }을, 둘째 뒤에 완성된 구간을 보고합니다. controlled 호출자가 요청하지 않은 중간 상태를 떠안는 일은 없습니다. 대기 중인 anchor는 폼이 아니라 컴포넌트 안에 삽니다.

미리보기 띠

띠는 두 번째 클릭이 닿기 전에 anchor와 포인터가 지금 올라가 있는 날 사이에 그려집니다. 그것이 없으면 첫 클릭에는 눈에 보이는 결과가 없고, 그 1초 남짓 동안 컨트롤은 고장 난 것처럼 보입니다.

거꾸로 클릭하는 것은 거부해야 할 실수가 아닙니다. 같은 구간을 반대 순서로 말한 것이고, 하나로 확정됩니다.

Examples

monthCount

두 달이 기본인 것은 달을 넘나드는 구간이 예외가 아니라 보통이기 때문입니다. 한 달짜리 picker는 그것을 2단계 탐색 문제로 만듭니다.

두 패널은 반으로 나뉜 하나의 달력 입니다. 왼쪽에는 앞으로 가는 stepper가 없고, 오른쪽에는 뒤로 가는 stepper가 없으며, 어느 헤더의 월/연도 버튼이든 둘 다를 움직입니다. stepper를 그리지 않는 자리에는 그 크기만큼의 빈칸을 남겨서, 두 제목이 같은 중심선에 머뭅니다.

바깥 달의 날도 그리지 않습니다. 취향의 문제가 아닙니다. 두 패널이 모두 여섯 주를 다 그리면 8월 1일이 두 번 나타납니다. 한 번은 7월의 꼬리로, 한 번은 자기 자신으로. 한 팝업 안에 이름이 같은 칸 둘은 포인터에게 모호하고 스크린리더에게는 완전히 고장입니다.

React

presets

달력 옆에 놓이는 이름 붙은 구간. 사람들이 실제로 고르는 것들입니다. 오늘에 달려 있다면 value함수 로 주세요. 대개 그렇습니다. 모듈 로드 시점에 계산한 "지난 7일"은 탭을 밤새 열어 둔 사람에게는 틀린 구간입니다.

React

minDate · maxDate · shouldDisableDate

PlDatePicker의 그 셋을 양 끝에 적용한 것입니다. 막힌 날은 그리드에 남고 화살표 경로에서 자기 자리를 지키며, 구간의 색을 입지 않습니다. 띠를 두른 막힌 날은 자기가 낄 수 없는 구간의 일부라고 광고하는 셈입니다.

React

Controlled

valueonValueChange와 함께 주세요. 콜백은 언제나 객체를 받으므로 null 구간을 방어할 필요가 없습니다. 비워진 picker는 { start: null, end: null }입니다.

React

Accessibility

  • 두 그리드 다 각자 roving tab stop을 하나씩 가지며, 키보드는 PlDatePicker의 것 그대로입니다.
  • 두 그리드 다 role="grid"입니다.
  • 모든 칸의 접근성 이름은 날짜 전체 이고, 한 팝업 안에 같은 날짜가 두 번 나타나지 않습니다. 바깥 달의 날을 끈 대가로 얻는 것이 그것입니다.
  • 푸터는 다음 클릭이 어느 쪽을 채우는지 말합니다. trigger의 두 반쪽도 같은 말을 하지만, 팝업이 떠 있는 동안 trigger는 그 뒤에 가려집니다. 읽힐 자리에서 그 말을 할 수 있는 곳은 푸터뿐입니다.
  • trigger 두 반쪽 사이의 화살표는 aria-hidden이고 RTL에서 뒤집힙니다.
  • trigger의 각 반쪽은 자기가 담을 수 있는 모든 날짜에 대해 자기 너비를 붙잡아 둡니다. 그래서 두 번째 끝을 채워도 첫 번째가 크기를 바꾸지 않습니다. 그 샘플들은 aria-hidden이고 generated content로 그려집니다.
  • name이 있으면 같은 이름의 hidden input 둘이 양 끝을 로컬 YYYY-MM-DD로 담아, FormData.getAll(name)으로 옵니다.
  • trigger는 양 끝을 label에 접어 넣는 대신 semantics value 로 지닙니다.
  • 두 반쪽 사이의 화살표는 RTL에서 돌아가므로 언제나 첫 끝에서 둘째 끝을 가리킵니다.
  • 너비를 잡아 주는 샘플들은 ExcludeSemantics 뒤에 있습니다.

React 빌드와 다른 점

ReactFlutter이유
locale / formatnames / formatValuePlDatePicker가 설명하는 그 거래입니다. 프레임워크에 Intl이 없습니다.
value: PlDateRange | nullvalue: PlDateRange, null 없음PlDateRange.empty가 그것을 말하고, non-nullable 값은 호출자가 방어할 것이 하나 줄어드는 일입니다.
preset의 value는 구간이거나 함수build는 언제나 함수preset은 거의 언제나 오늘에 달려 있고, 언제나 맞는 한 가지 모양이 두 가지보다 쌉니다.
hidden input, name참여할 네이티브 form 제출이 없습니다.
className, style, 네이티브 속성통과시킬 class 목록도 style 속성도 없습니다.

Released under the MIT License