@bokeh/bokehjs
Version:
Interactive, novel data visualization
148 lines • 6.27 kB
JavaScript
import flatpickr from "flatpickr";
import { InputWidget, InputWidgetView } from "./input_widget";
import { input } from "../../core/dom";
import { CalendarPosition } from "../../core/enums";
import { bounding_box } from "../../core/dom";
import { assert } from "../../core/util/assert";
import flatpickr_css from "../../styles/widgets/flatpickr.css";
import * as inputs from "../../styles/widgets/inputs.css";
export class PickerBaseView extends InputWidgetView {
static __name__ = "PickerBaseView";
_picker;
get picker() {
assert(this._picker != null);
return this._picker;
}
*controls() {
yield this.picker.altInput ?? this.input_el;
}
remove() {
this._picker?.destroy();
super.remove();
}
stylesheets() {
return [...super.stylesheets(), flatpickr_css];
}
connect_signals() {
super.connect_signals();
const { inline } = this.model.properties;
this.connect(inline.change, () => this.picker.set("inline", this.model.inline));
}
get flatpickr_options() {
return {
appendTo: this.group_el,
inline: this.model.inline,
position: this._position.bind(this),
onChange: (selected) => {
this._on_change(selected);
this.change_input();
},
};
}
_render_input() {
return this.input_el = input({ type: "text", class: inputs.input, disabled: this.model.disabled });
}
render() {
super.render();
this._picker?.destroy();
const options = this.flatpickr_options;
this._picker = flatpickr(this.input_el, options);
}
// https://github.com/flatpickr/flatpickr/pull/2362
_position(self, custom_el) {
const positionElement = custom_el ?? self._positionElement;
const calendarHeight = [...self.calendarContainer.children].reduce((acc, child) => acc + bounding_box(child).height, 0);
const calendarWidth = self.calendarContainer.offsetWidth;
const configPos = this.model.position.split(" ");
const configPosVertical = configPos[0];
const configPosHorizontal = configPos.length > 1 ? configPos[1] : null;
// const inputBounds = positionElement.getBoundingClientRect()
const inputBounds = {
top: positionElement.offsetTop,
bottom: positionElement.offsetTop + positionElement.offsetHeight,
left: positionElement.offsetLeft,
right: positionElement.offsetLeft + positionElement.offsetWidth,
width: positionElement.offsetWidth,
};
const distanceFromBottom = window.innerHeight - inputBounds.bottom;
const showOnTop = configPosVertical === "above" ||
(configPosVertical !== "below" &&
distanceFromBottom < calendarHeight &&
inputBounds.top > calendarHeight);
// const top =
// window.scrollY +
// inputBounds.top +
// (!showOnTop ? positionElement.offsetHeight + 2 : -calendarHeight - 2)
const top = self.config.appendTo != null
? inputBounds.top +
(!showOnTop ? positionElement.offsetHeight + 2 : -calendarHeight - 2)
: window.scrollY +
inputBounds.top +
(!showOnTop ? positionElement.offsetHeight + 2 : -calendarHeight - 2);
self.calendarContainer.classList.toggle("arrowTop", !showOnTop);
self.calendarContainer.classList.toggle("arrowBottom", showOnTop);
if (self.config.inline) {
return;
}
let left = window.scrollX + inputBounds.left;
let isCenter = false;
let isRight = false;
if (configPosHorizontal === "center") {
left -= (calendarWidth - inputBounds.width) / 2;
isCenter = true;
}
else if (configPosHorizontal === "right") {
left -= calendarWidth - inputBounds.width;
isRight = true;
}
self.calendarContainer.classList.toggle("arrowLeft", !isCenter && !isRight);
self.calendarContainer.classList.toggle("arrowCenter", isCenter);
self.calendarContainer.classList.toggle("arrowRight", isRight);
const right = window.document.body.offsetWidth -
(window.scrollX + inputBounds.right);
const rightMost = left + calendarWidth > window.document.body.offsetWidth;
const centerMost = right + calendarWidth > window.document.body.offsetWidth;
self.calendarContainer.classList.toggle("rightMost", rightMost);
if (self.config.static) {
return;
}
self.calendarContainer.style.top = `${top}px`;
if (!rightMost) {
self.calendarContainer.style.left = `${left}px`;
self.calendarContainer.style.right = "auto";
}
else if (!centerMost) {
self.calendarContainer.style.left = "auto";
self.calendarContainer.style.right = `${right}px`;
}
else {
const css = this.shadow_el.styleSheets[0];
const bodyWidth = window.document.body.offsetWidth;
const centerLeft = Math.max(0, bodyWidth / 2 - calendarWidth / 2);
const centerBefore = ".flatpickr-calendar.centerMost:before";
const centerAfter = ".flatpickr-calendar.centerMost:after";
const centerIndex = css.cssRules.length;
const centerStyle = `{left:${inputBounds.left}px;right:auto;}`;
self.calendarContainer.classList.toggle("rightMost", false);
self.calendarContainer.classList.toggle("centerMost", true);
css.insertRule(`${centerBefore},${centerAfter}${centerStyle}`, centerIndex);
self.calendarContainer.style.left = `${centerLeft}px`;
self.calendarContainer.style.right = "auto";
}
}
}
export class PickerBase extends InputWidget {
static __name__ = "PickerBase";
constructor(attrs) {
super(attrs);
}
static {
this.define(({ Bool }) => {
return {
position: [CalendarPosition, "auto"],
inline: [Bool, false],
};
});
}
}
//# sourceMappingURL=picker_base.js.map