Skip to content

Commit

Permalink
refactor(datepicker): replace inline with close-on-select
Browse files Browse the repository at this point in the history
  • Loading branch information
segunadebayo committed Oct 30, 2023
1 parent a528501 commit abaec35
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 159 deletions.
7 changes: 7 additions & 0 deletions .changeset/kind-buttons-beam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@zag-js/date-picker": minor
"@zag-js/docs": minor
---

- Remove support for `inline` in datepicker and replace with `closeOnSelect` for API consistency.
- Add `data-placement` to trigger and content parts for position-aware styling.
69 changes: 28 additions & 41 deletions .xstate/date-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,30 @@ const {
} = actions;
const fetchMachine = createMachine({
id: "datepicker",
initial: ctx.inline || ctx.open ? "open" : "idle",
initial: ctx.open ? "open" : "idle",
context: {
"isYearView": false,
"isMonthView": false,
"isYearView": false,
"isMonthView": false,
"!isinline": false,
"isMonthView": false,
"isYearView": false,
"isRangePicker && hasSelectedRange": false,
"isRangePicker && isSelectingEndDate && isInline": false,
"isRangePicker && isSelectingEndDate && closeOnSelect": false,
"isRangePicker && isSelectingEndDate": false,
"isRangePicker": false,
"isMultiPicker": false,
"isInline": false,
"closeOnSelect": false,
"isRangePicker && isSelectingEndDate": false,
"isRangePicker": false,
"!isInline": false,
"!isInline": false,
"!isInline": false,
"isMonthView": false,
"isYearView": false,
"isRangePicker && hasSelectedRange": false,
"isRangePicker && isSelectingEndDate && isInline": false,
"isRangePicker && isSelectingEndDate && closeOnSelect": false,
"isRangePicker && isSelectingEndDate": false,
"isRangePicker": false,
"isMultiPicker": false,
"isInline": false,
"closeOnSelect": false,
"isMonthView": false,
"isYearView": false,
"isMonthView": false,
Expand Down Expand Up @@ -102,7 +98,7 @@ const fetchMachine = createMachine({
},
"TRIGGER.CLICK": {
target: "open",
actions: ["focusFirstSelectedDate", "invokeOnOpen"]
actions: ["focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"]
},
OPEN: {
target: "open",
Expand All @@ -115,7 +111,7 @@ const fetchMachine = createMachine({
on: {
"TRIGGER.CLICK": {
target: "open",
actions: ["setViewToDay", "focusFirstSelectedDate", "invokeOnOpen"]
actions: ["setViewToDay", "focusFirstSelectedDate", "focusActiveCell", "invokeOnOpen"]
},
"INPUT.CHANGE": {
actions: ["focusParsedDate"]
Expand All @@ -128,7 +124,7 @@ const fetchMachine = createMachine({
},
"CELL.FOCUS": {
target: "open",
actions: ["setView", "invokeOnOpen"]
actions: ["setView", "focusActiveCell", "invokeOnOpen"]
},
OPEN: {
target: "open",
Expand All @@ -139,10 +135,6 @@ const fetchMachine = createMachine({
open: {
tags: "open",
activities: ["trackDismissableElement", "trackPositioning"],
entry: choose([{
cond: "!isinline",
actions: ["focusActiveCell"]
}]),
exit: ["clearHoveredDate", "resetView"],
on: {
"INPUT.CHANGE": {
Expand All @@ -158,14 +150,14 @@ const fetchMachine = createMachine({
cond: "isRangePicker && hasSelectedRange",
actions: ["setStartIndex", "clearSelectedDate", "setFocusedDate", "setSelectedDate", "setEndIndex"]
},
// === Grouped transitions (based on isInline) ===
// === Grouped transitions (based on `closeOnSelect`) ===
{
cond: "isRangePicker && isSelectingEndDate && isInline",
actions: ["setFocusedDate", "setSelectedDate", "setStartIndex", "clearHoveredDate"]
}, {
cond: "isRangePicker && isSelectingEndDate && closeOnSelect",
target: "focused",
cond: "isRangePicker && isSelectingEndDate",
actions: ["setFocusedDate", "setSelectedDate", "setStartIndex", "clearHoveredDate", "focusInputElement", "invokeOnClose"]
}, {
cond: "isRangePicker && isSelectingEndDate",
actions: ["setFocusedDate", "setSelectedDate", "setStartIndex", "clearHoveredDate"]
},
// ===
{
Expand All @@ -175,13 +167,13 @@ const fetchMachine = createMachine({
cond: "isMultiPicker",
actions: ["setFocusedDate", "toggleSelectedDate"]
},
// === Grouped transitions (based on isInline) ===
// === Grouped transitions (based on `closeOnSelect`) ===
{
cond: "isInline",
actions: ["setFocusedDate", "setSelectedDate"]
}, {
cond: "closeOnSelect",
target: "focused",
actions: ["setFocusedDate", "setSelectedDate", "focusInputElement", "invokeOnClose"]
}, {
actions: ["setFocusedDate", "setSelectedDate"]
}
// ===
],
Expand All @@ -195,15 +187,12 @@ const fetchMachine = createMachine({
actions: ["clearHoveredDate"]
},
"TABLE.POINTER_DOWN": {
cond: "!isInline",
actions: ["disableTextSelection"]
},
"TABLE.POINTER_UP": {
cond: "!isInline",
actions: ["enableTextSelection"]
},
"TABLE.ESCAPE": {
cond: "!isInline",
target: "focused",
actions: ["setViewToDay", "focusFirstSelectedDate", "focusTriggerElement", "invokeOnClose"]
},
Expand All @@ -217,14 +206,14 @@ const fetchMachine = createMachine({
cond: "isRangePicker && hasSelectedRange",
actions: ["setStartIndex", "clearSelectedDate", "setSelectedDate", "setEndIndex"]
},
// === Grouped transitions (based on isInline) ===
// === Grouped transitions (based on `closeOnSelect`) ===
{
cond: "isRangePicker && isSelectingEndDate && isInline",
actions: ["setSelectedDate", "setStartIndex"]
}, {
cond: "isRangePicker && isSelectingEndDate && closeOnSelect",
target: "focused",
cond: "isRangePicker && isSelectingEndDate",
actions: ["setSelectedDate", "setStartIndex", "focusInputElement", "invokeOnClose"]
}, {
cond: "isRangePicker && isSelectingEndDate",
actions: ["setSelectedDate", "setStartIndex"]
},
// ===
{
Expand All @@ -234,13 +223,13 @@ const fetchMachine = createMachine({
cond: "isMultiPicker",
actions: ["toggleSelectedDate"]
},
// === Grouped transitions (based on isInline) ===
// === Grouped transitions (based on `closeOnSelect`) ===
{
cond: "isInline",
actions: ["selectFocusedDate"]
}, {
cond: "closeOnSelect",
target: "focused",
actions: ["selectFocusedDate", "focusInputElement", "invokeOnClose"]
}, {
actions: ["selectFocusedDate"]
}
// ===
],
Expand Down Expand Up @@ -342,14 +331,12 @@ const fetchMachine = createMachine({
guards: {
"isYearView": ctx => ctx["isYearView"],
"isMonthView": ctx => ctx["isMonthView"],
"!isinline": ctx => ctx["!isinline"],
"isRangePicker && hasSelectedRange": ctx => ctx["isRangePicker && hasSelectedRange"],
"isRangePicker && isSelectingEndDate && isInline": ctx => ctx["isRangePicker && isSelectingEndDate && isInline"],
"isRangePicker && isSelectingEndDate && closeOnSelect": ctx => ctx["isRangePicker && isSelectingEndDate && closeOnSelect"],
"isRangePicker && isSelectingEndDate": ctx => ctx["isRangePicker && isSelectingEndDate"],
"isRangePicker": ctx => ctx["isRangePicker"],
"isMultiPicker": ctx => ctx["isMultiPicker"],
"isInline": ctx => ctx["isInline"],
"!isInline": ctx => ctx["!isInline"],
"closeOnSelect": ctx => ctx["closeOnSelect"],
"isDayView": ctx => ctx["isDayView"],
"isTargetFocusable": ctx => ctx["isTargetFocusable"]
}
Expand Down
90 changes: 19 additions & 71 deletions packages/docs/api.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
"getRootNode": {
"type": "() => ShadowRoot | Node | Document",
"description": "A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron."
},
"dir": {
"type": "\"ltr\" | \"rtl\"",
"description": "The document's text/writing direction.",
"defaultValue": "\"ltr\""
}
}
},
Expand Down Expand Up @@ -304,11 +309,7 @@
"type": "string",
"description": "The current color value (as a Color object)"
},
"channels": {
"type": "[ColorChannel]",
"description": "The current color channels of the color"
},
"setColor": {
"setValue": {
"type": "(value: string | Color) => void",
"description": "Function to set the color value"
},
Expand Down Expand Up @@ -819,9 +820,10 @@
"type": "DateValue",
"description": "The maximum date that can be selected."
},
"inline": {
"closeOnSelect": {
"type": "boolean",
"description": "Whether the calendar should be displayed inline."
"description": "Whether the calendar should close after the date selection is complete.\nThis is ignored when the selection mode is `multiple`.",
"defaultValue": "true"
},
"value": {
"type": "DateValue[]",
Expand Down Expand Up @@ -1907,6 +1909,11 @@
"getRootNode": {
"type": "() => Node | ShadowRoot | Document",
"description": "A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron."
},
"dir": {
"type": "\"ltr\" | \"rtl\"",
"description": "The document's text/writing direction.",
"defaultValue": "\"ltr\""
}
}
},
Expand All @@ -1923,69 +1930,6 @@
},
"context": {}
},
"pressable": {
"api": {
"isPressed": {
"type": "boolean",
"description": "Whether the element is pressed."
}
},
"context": {
"disabled": {
"type": "boolean",
"description": "Whether the element is disabled"
},
"preventFocusOnPress": {
"type": "boolean",
"description": "Whether the target should not receive focus on press."
},
"cancelOnPointerExit": {
"type": "boolean",
"description": "Whether press events should be canceled when the pointer leaves the target while pressed.\n\nBy default, this is `false`, which means if the pointer returns back over the target while\nstill pressed, onPressStart will be fired again.\n\nIf set to `true`, the press is canceled when the pointer leaves the target and\nonPressStart will not be fired if the pointer returns."
},
"allowTextSelectionOnPress": {
"type": "boolean",
"description": "Whether text selection should be enabled on the pressable element."
},
"longPressDelay": {
"type": "number",
"description": "The amount of time (in milliseconds) to wait before firing the `onLongPress` event."
},
"dir": {
"type": "\"ltr\" | \"rtl\"",
"description": "The document's text/writing direction.",
"defaultValue": "\"ltr\""
},
"id": {
"type": "string",
"description": "The unique identifier of the machine."
},
"getRootNode": {
"type": "() => ShadowRoot | Node | Document",
"description": "A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron."
},
"onPress": {
"type": "(event: PressEvent) => void",
"description": "Handler that is called when the press is released over the target."
},
"onPressStart": {
"type": "(event: PressEvent) => void",
"description": "Handler that is called when a press interaction starts."
},
"onPressEnd": {
"type": "(event: PressEvent) => void",
"description": "Handler that is called when a press interaction ends, either\nover the target or when the pointer leaves the target."
},
"onPressUp": {
"type": "(event: PressEvent) => void",
"description": "Handler that is called when a press is released over the target, regardless of\nwhether it started on the target or not."
},
"onLongPress": {
"type": "(event: PressEvent) => void",
"description": "Handler that is called when the element has been pressed for 500 milliseconds"
}
}
},
"radio-group": {
"api": {
"value": {
Expand Down Expand Up @@ -2218,6 +2162,10 @@
"type": "() => void",
"description": "Function to close the combobox"
},
"collection": {
"type": "Collection<V>",
"description": "Function to toggle the combobox"
},
"setCollection": {
"type": "(collection: Collection<V>) => void",
"description": "Function to set the collection of items"
Expand Down Expand Up @@ -2392,7 +2340,7 @@
},
"context": {
"ids": {
"type": "Partial<{ root: string; thumb(index: number): string; control: string; track: string; range: string; label: string; output: string; marker(index: number): string; }>",
"type": "Partial<{ root: string; thumb(index: number): string; control: string; track: string; range: string; label: string; valueText: string; marker(index: number): string; }>",
"description": "The ids of the elements in the range slider. Useful for composition."
},
"aria-label": {
Expand Down
5 changes: 4 additions & 1 deletion packages/machines/date-picker/src/date-picker.connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
const startOfWeek = state.context.startOfWeek

const isFocused = state.matches("focused")
const isOpen = Boolean(state.matches("open") || state.context.inline)
const isOpen = state.matches("open")

const isRangePicker = state.context.selectionMode === "range"
const isDateUnavailableFn = state.context.isDateUnavailable

Expand Down Expand Up @@ -294,6 +295,7 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
hidden: !isOpen,
dir: state.context.dir,
"data-state": isOpen ? "open" : "closed",
"data-placement": currentPlacement,
id: dom.getContentId(state.context),
role: "application",
"aria-roledescription": "datepicker",
Expand Down Expand Up @@ -581,6 +583,7 @@ export function connect<T extends PropTypes>(state: State, send: Send, normalize
id: dom.getTriggerId(state.context),
dir: state.context.dir,
type: "button",
"data-placement": currentPlacement,
"aria-label": isOpen ? "Close calendar" : "Open calendar",
"data-state": isOpen ? "open" : "closed",
"aria-haspopup": "grid",
Expand Down
Loading

4 comments on commit abaec35

@vercel
Copy link

@vercel vercel bot commented on abaec35 Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

zag-nextjs – ./examples/next-ts

zag-two.vercel.app
zag-nextjs-git-main-chakra-ui.vercel.app
zag-nextjs-chakra-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on abaec35 Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on abaec35 Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

zag-vue – ./examples/vue-ts

zag-vue.vercel.app
zag-vue-chakra-ui.vercel.app
zag-vue-git-main-chakra-ui.vercel.app

@vercel
Copy link

@vercel vercel bot commented on abaec35 Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

zag-solid – ./examples/solid-ts

zag-solid-git-main-chakra-ui.vercel.app
zag-solid.vercel.app
zag-solid-chakra-ui.vercel.app

Please sign in to comment.