isDateDisabled should supply the date in ISO8601 string format

This is my POSSE copy of duetds/date-picker issue #116 .


When using isDateDisabled I want to check whether the date given in the callback is in a list of dates that I have supplied. My list of dates is in ISO8601 format (“YYYY-MM-DD”) which fits nicely with the main inputs and outputs of this date-picker. The problem is that obtaining “YYYY-MM-DD” from this particular Date object is surprisingly awkward, and having only this representation available means it is less possible to share code between isDateDisabled and duetChange callbacks.

What happens now

isDateDisabled currently provides the date only as a javascript Date object, representing midnight in local time. Converting that to “YYYY-MM-DD” is awkward, partly because the javascript Date object does not supply adequate methods for doing so. The fact that it's local time makes things harder, because Date.toISOString() returns UTC, leading to the resulting YYYY-MM-DD portion of the string being off-by-one depending on local time zone. One alternative is taking the individual components such as Date.getMonth() and formatting them, which is straightforward but surprisingly verbose for reasons that can be seen in the code below.

The code I am using now:

  // convert a date to a string 'yyyy-mm-dd'
  // 'date' from this widget is a midnight in local time, which is awkward
  function dateStr(date) {
    const pad2 = (x) => (String(x).padStart(2,'0'))
    return `${date.getFullYear()}-${pad2(date.getMonth()+1)}-${pad2(date.getDate())}`
  picker.isDateDisabled = (date) => ! myDatesList.includes(dateStr(date))

Whereas checking for disabled dates in the duetChange callback is a short one-liner and does not require such helper functions:

  picker.addEventListener("duetChange", function(e) {
    // check for unavailable dates (entered manually) is easy:
    if (! myDatesList.includes(e.detail.value) // { alert(...) }

Suggested solution

Add to the isDateDisabled callback a new argument giving the same detail that is provided as the argument to the duetChange callback. This detail contains both the Date object and the YYYY-MM-DD string representation.

I do not wish to recommend here any particular backward compatibility strategy; options include adding an optional second argument, or making a differently named callback while keeping (or deprecating) isDateDisabled. Let's say for example that we make a differently named callback, that supplies a parameter in the same form as duetChange does. Then the user code could be a short one-liner matching the implementation of duetChange:

  picker.isDateDisabled = (e) => ! myDatesList.includes(e.detail.value)

Alternatives considered

Looked for simpler ways to use the supplied Date object; found no really simple ways to do so without further dependencies.