JSFiddle - React, Tailwind, and code Playground

by whelkaholism

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/dayjs/1.11.18/dayjs.min.js"></script>
<script src="https://cdn.cfront-cloud.co.uk/scripts/koa1.2/cf.DOM.js"></script>
<input type="text" data-bind="dateFilter: FilterDate" />
<br/>
<br/>
<input type="text" readonly="true" data-bind="value: FilterDate" />

CSS

.koa-date-filter {
    position: relative;
    display: flex;
    align-items: center;
}

.koa-date-filter .show-date-filter::before {
    content: '...'
}

.koa-date-filter .date-filter-ui {
    display: none;
    position: absolute;
    z-index: 1;
    background: #ffffff;
    border: 1px solid #909090;
    border-radius: 10px;
    border-top-left-radius: 0;
    padding: 1em;
    width: 300%;
    height: fit-content;
    top: 100%;
}

.koa-date-filter .date-filter-ui.show {
    display: flex;
    flex-direction: column;
    gap: 0.5em
}

.koa-date-filter .date-filter-ui select,
.koa-date-filter .date-filter-ui input[type=date] {
    width: unset !important;
    background: rgba(0, 0, 0, 0.05);
    color: #212121 !important;
}

.koa-date-filter .date-filter-ui .date-filter-range {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.koa-date-filter .date-filter-ui.show {
    width: 330px
}

.koa-date-filter .date-filter-ui.show button {
    padding: 0.25em 0.5em;
    line-height: unset;
    margin: 0;
}

.koa-date-filter .date-filter-ui.show button.selected {
    background: #eeeecc
}

.koa-date-filter .date-filter-ui.show * {
    font-size: 13px;
}

.koa-date-filter .date-filter-ui .date-filter-mode {
    margin-bottom: 1rem;
}

.koa-date-filter .date-filter-side, .date-filter-single {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

JavaScript

if (typeof (Date.hasValue) == 'undefined') Date.hasValue = function(s) { return !!s && !/^0001[\-\/\.]/.test(s); };

/*

::date: Simple binding to take the ISO date+time strings returned by Core services and allow them to bind to am HTML [type=date] field
::dateFilter: Popup UI to assist with entering ambiguous dates expected by fuzzy date filtering

*/
(function()
{
    // ------------------------------------------------------------------------------------------------------------------------------------------------
    // DATES
    ko.bindingHandlers.date = {
        init:
            function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
            {
                if (el.nodeName == 'INPUT' && el.type != 'date')
                    el.type = 'date';

                var obs = f_valueaccessor();

                el.addEventListener('change', function(e)
                {
                    obs(el.value || null);
                });
            },
        update:
            function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
            {
                var dt = ko.unwrap(f_valueaccessor());
                var djs = Date.hasValue(dt) ? dayjs(dt) : null;

                el.value = djs ? djs.format('YYYY-MM-DD') : '';
            }
    };

    // ------------------------------------------------------------------------------------------------------------------------------------------------
    ko.bindingHandlers.dateFilter = {
        init:
            function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext) 
            {
                var obs = f_valueaccessor();
                var numyears = allbindings.get('dateFilterNumYears') || 10;

                if (!!obs)
                {
                    el.wrap('<div class="koa-date-filter"></div>');
                    const nparent = el.parentNode;

                    const nbtn =...