Datepicker and Icon Button
This commit is contained in:
parent
6e0518c646
commit
082997585b
|
@ -24,5 +24,8 @@
|
||||||
"lint:fix": "eslint --fix packages",
|
"lint:fix": "eslint --fix packages",
|
||||||
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\""
|
"format": "prettier --write \"{,!(node_modules)/**/}*.{js,jsx,svelte}\""
|
||||||
},
|
},
|
||||||
"dependencies": {}
|
"dependencies": {
|
||||||
|
"@material/icon-button": "4.0.0",
|
||||||
|
"date-fns": "^2.10.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,31 @@
|
||||||
<script>
|
<script>
|
||||||
import { getContext } from "svelte"
|
import { getContext } from "svelte"
|
||||||
|
import ripple from "../Ripple.js"
|
||||||
|
|
||||||
|
export let onClick = null
|
||||||
export let icon = ""
|
export let icon = ""
|
||||||
export let context = ""
|
export let context = ""
|
||||||
|
|
||||||
let cls = !!context ? `material-icons mdc-${context}__icon` : "material-icons"
|
let cls = !!context ? `material-icons mdc-${context}__icon` : "material-icons"
|
||||||
|
|
||||||
|
$: useRipple = onClick !== null
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<i class={cls}>{icon}</i>
|
<i class={cls}>{icon}</i>
|
||||||
|
{#if useRipple}
|
||||||
|
<div use:ripple>
|
||||||
|
<i on:click={onClick} class={cls}>{icon}</i>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<i class={cls}>{icon}</i>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
border-radius: 50%;
|
||||||
|
padding-top: 2px;
|
||||||
|
width: fit-content;
|
||||||
|
height: fit-content;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { MDCRipple } from "@material/ripple"
|
||||||
|
|
||||||
export default function ripple(
|
export default function ripple(
|
||||||
node,
|
node,
|
||||||
props = { colour: "primary", unbounded: false }
|
props = { colour: "primary", unbounded: true }
|
||||||
) {
|
) {
|
||||||
node.classList.add("mdc-ripple-surface")
|
node.classList.add("mdc-ripple-surface")
|
||||||
let component = new MDCRipple(node)
|
let component = new MDCRipple(node)
|
||||||
|
|
|
@ -1,10 +1,185 @@
|
||||||
<script>
|
<script>
|
||||||
import { Menu } from "../Menu"
|
import { onMount } from "svelte";
|
||||||
import { Textfield } from "../Textfield"
|
import {
|
||||||
|
startOfMonth,
|
||||||
|
endOfMonth,
|
||||||
|
getDate,
|
||||||
|
getMonth,
|
||||||
|
getYear,
|
||||||
|
addMonths,
|
||||||
|
subMonths,
|
||||||
|
format
|
||||||
|
} from "date-fns";
|
||||||
|
import { MDCMenu } from "@material/menu";
|
||||||
|
import { Textfield } from "../Textfield";
|
||||||
|
import Icon from "../Common/Icon.svelte";
|
||||||
|
import ripple from "../Ripple.js";
|
||||||
|
import { Body1, Body2, Caption } from "../Typography";
|
||||||
|
|
||||||
let open = false
|
let textFieldHeight = null;
|
||||||
debugger
|
let menu;
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
let daysArr = [];
|
||||||
|
let navDate = new Date();
|
||||||
|
const weekdayMap = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
||||||
|
|
||||||
|
export let date = new Date();
|
||||||
|
export let open = true;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
if (!!menu) {
|
||||||
|
instance = new MDCMenu(menu);
|
||||||
|
instance.open = true;
|
||||||
|
instance.setFixedPostion = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function selectDate(dayOfMonth) {
|
||||||
|
let month = getMonth(navDate);
|
||||||
|
let year = getYear(navDate);
|
||||||
|
date = new Date(year, month, dayOfMonth);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addMonth() {
|
||||||
|
navDate = addMonths(navDate, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function subtractMonth() {
|
||||||
|
navDate = subMonths(navDate, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCalendar() {
|
||||||
|
instance.open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: dateMonthEnds = endOfMonth(navDate).getDate();
|
||||||
|
$: dateMonthBegins = startOfMonth(navDate).getDay();
|
||||||
|
$: dayStart = dateMonthBegins + 1; //1 = sunday
|
||||||
|
$: monthAndYear = format(navDate, "MMMM y");
|
||||||
|
$: selectedDate = format(date, "dd/MM/yyyy");
|
||||||
|
$: dayOfSelectedDate = getDate(date);
|
||||||
|
$: for (let d = 1; d <= dateMonthEnds; d++) {
|
||||||
|
if (d === 1) {
|
||||||
|
daysArr = [d];
|
||||||
|
} else {
|
||||||
|
daysArr = [...daysArr, d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$: rowRepeater =
|
||||||
|
dateMonthBegins > 5 && daysArr[daysArr.length - 1] > 30 ? 6 : 5;
|
||||||
|
$: sameMonthAndYear =
|
||||||
|
getMonth(date) === getMonth(navDate) && getYear(date) === getYear(navDate);
|
||||||
|
debugger;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Textfield label="Select Date" />
|
<style>
|
||||||
<Menu {open} />
|
.bbmd-menu {
|
||||||
|
width: 310px;
|
||||||
|
height: auto;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-picker {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 20px 1fr 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-picker > span {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-container {
|
||||||
|
display: grid;
|
||||||
|
height: 100%;
|
||||||
|
grid-template-rows: repeat(3, auto);
|
||||||
|
grid-gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.calendar-container > div {
|
||||||
|
/* border: 1px solid red; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-days {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.day-picker {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(7, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
.centreText {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
TODO: Add trailing icon button on textfield that is clickable
|
||||||
|
TODO: Add transition effects to toggling of calendar
|
||||||
|
TODO: Bug - August 2020 has too many rows. find out why
|
||||||
|
TODO: Bug - make out transition of date bg colour instantaneous
|
||||||
|
-->
|
||||||
|
<div class="mdc-menu-surface--anchor">
|
||||||
|
<Textfield
|
||||||
|
bind:tfHeight={textFieldHeight}
|
||||||
|
value={selectedDate}
|
||||||
|
trailingIcon={true}
|
||||||
|
useIconButton={true}
|
||||||
|
iconButtonClick={openCalendar}
|
||||||
|
icon="calendar_today"
|
||||||
|
label="Select Date" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={menu}
|
||||||
|
class="mdc-menu mdc-menu-surface bbmd-menu"
|
||||||
|
style={`margin-top: ${textFieldHeight + 15}px`}>
|
||||||
|
<div class="calendar-container">
|
||||||
|
<div class="month-picker">
|
||||||
|
<span>
|
||||||
|
<Icon icon="chevron_left" onClick={subtractMonth} />
|
||||||
|
</span>
|
||||||
|
<div class="centreText">
|
||||||
|
<Body1 text={monthAndYear} />
|
||||||
|
</div>
|
||||||
|
<span>
|
||||||
|
<Icon icon="chevron_right" onClick={addMonth} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="week-days">
|
||||||
|
{#each weekdayMap as day, i}
|
||||||
|
<div class="centreText">
|
||||||
|
<Caption text={day} />
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="day-picker"
|
||||||
|
style={`grid-template-rows: repeat(${rowRepeater}, 40px)`}>
|
||||||
|
{#each daysArr as day, i}
|
||||||
|
<div
|
||||||
|
use:ripple
|
||||||
|
on:click={() => selectDate(day)}
|
||||||
|
class={`bbmd-day ${dayOfSelectedDate === day && sameMonthAndYear ? 'selected' : ''}`}>
|
||||||
|
{#if i === 0}
|
||||||
|
<div style={`grid-column-start: ${dateMonthBegins}`}>
|
||||||
|
<Body2 text={day} />
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Body2 text={day} />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="mdc-list" role="menu" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
@import "@material/ripple/mdc-ripple.scss";
|
||||||
|
@import "@material/theme/mixins";
|
||||||
|
|
||||||
|
.bbmd-day {
|
||||||
|
transition: background-color 0.5s ease-in;
|
||||||
|
display: flex;
|
||||||
|
border-radius: 50%;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.selected {
|
||||||
|
@include mdc-theme-prop(background-color, primary);
|
||||||
|
@include mdc-theme-prop(color, on-primary);
|
||||||
|
}
|
|
@ -1 +1,2 @@
|
||||||
export { default as DatePicker } from "./DatePicker.svelte"
|
import "./_style.scss";
|
||||||
|
export { default as DatePicker } from "./DatePicker.svelte";
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<script>
|
||||||
|
import ripple from "../Ripple.js";
|
||||||
|
import ClassBuilder from "../ClassBuilder.js";
|
||||||
|
|
||||||
|
const cb = new ClassBuilder("icon-button");
|
||||||
|
|
||||||
|
export let onClick = () => {};
|
||||||
|
export let disabled = false;
|
||||||
|
export let href = "";
|
||||||
|
export let icon = "";
|
||||||
|
export let onIcon = ""; //on state icon for toggle button
|
||||||
|
export let size = "medium";
|
||||||
|
|
||||||
|
$: isToggleButton = !!icon && !!onIcon;
|
||||||
|
$: useLinkButton = !!href;
|
||||||
|
|
||||||
|
$: customs = { size };
|
||||||
|
$: props = { customs, extras: ["material-icons"] };
|
||||||
|
$: iconBtnClass = cb.build({ props });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if useLinkButton}
|
||||||
|
<a on:click={onClick} class={iconBtnClass} {href} {disabled}>
|
||||||
|
{#if isToggleButton}
|
||||||
|
<i class="material-icons mdc-icon-button__icon mdc-icon-button__icon--on">
|
||||||
|
{onIcon}
|
||||||
|
</i>
|
||||||
|
<i class="material-icons mdc-icon-button__icon">{icon}</i>
|
||||||
|
{:else}{icon}{/if}
|
||||||
|
</a>
|
||||||
|
{:else}
|
||||||
|
<button on:click={onClick} use:ripple class={iconBtnClass} {disabled}>
|
||||||
|
{#if isToggleButton}
|
||||||
|
<i class="material-icons mdc-icon-button__icon mdc-icon-button__icon--on">
|
||||||
|
{onIcon}
|
||||||
|
</i>
|
||||||
|
<i class="material-icons mdc-icon-button__icon">{icon}</i>
|
||||||
|
{:else}{icon}{/if}
|
||||||
|
</button>
|
||||||
|
{/if}
|
|
@ -0,0 +1,13 @@
|
||||||
|
@import "@material/icon-button/mdc-icon-button";
|
||||||
|
|
||||||
|
.bbmd-mdc-icon-button--size-large {
|
||||||
|
@include mdc-icon-button-icon-size(24px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bbmd-mdc-icon-button--size-medium {
|
||||||
|
@include mdc-icon-button-icon-size(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bbmd-mdc-icon-button--size-small {
|
||||||
|
@include mdc-icon-button-icon-size(16px);
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
import "./_style.scss";
|
||||||
|
export { default as IconButton } from "./IconButton.svelte";
|
|
@ -39,7 +39,6 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
$: menuList && _bb.attachChildren(menuList)
|
$: menuList && _bb.attachChildren(menuList)
|
||||||
debugger
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if useFixedPosition || useAbsolutePosition}
|
{#if useFixedPosition || useAbsolutePosition}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
const cb = new ClassBuilder("text-field", ["primary", "medium"])
|
const cb = new ClassBuilder("text-field", ["primary", "medium"])
|
||||||
|
|
||||||
let tf = null
|
let tf = null
|
||||||
|
export let tfHeight = null
|
||||||
let tfInstance = null
|
let tfInstance = null
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
@ -105,7 +106,7 @@ TODO:Needs error handling - this will depend on how Budibase handles errors
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<div class="textfield-container" class:fullwidth>
|
<div class="textfield-container" class:fullwidth>
|
||||||
<div bind:this={tf} class={blockClasses}>
|
<div bind:this={tf} bind:clientHeight={tfHeight} class={blockClasses}>
|
||||||
{#if textarea}
|
{#if textarea}
|
||||||
<CharacterCounter />
|
<CharacterCounter />
|
||||||
<textarea
|
<textarea
|
||||||
|
|
|
@ -2,4 +2,4 @@
|
||||||
export let text = ""
|
export let text = ""
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mdc-typography--caption">{text}</div>
|
<span class="mdc-typography--caption">{text}</span>
|
||||||
|
|
|
@ -20,3 +20,4 @@ export { List, ListItem } from "./List"
|
||||||
export { Menu } from "./Menu"
|
export { Menu } from "./Menu"
|
||||||
export { Select } from "./Select"
|
export { Select } from "./Select"
|
||||||
export { DatePicker } from "./DatePicker"
|
export { DatePicker } from "./DatePicker"
|
||||||
|
export { IconButton } from "./IconButton"
|
||||||
|
|
61
yarn.lock
61
yarn.lock
|
@ -756,6 +756,62 @@
|
||||||
npmlog "^4.1.2"
|
npmlog "^4.1.2"
|
||||||
write-file-atomic "^2.3.0"
|
write-file-atomic "^2.3.0"
|
||||||
|
|
||||||
|
"@material/animation@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/animation/-/animation-4.0.0.tgz#19eaf377809f20978f8452a4237d27867d3ffd1d"
|
||||||
|
integrity sha512-IfzXzstWdtKQcsNWu+s2Hpz5dBwkTHtgtzoesr+FC7TqENH+SJdsF1ntnZI1XVi2C9ZlBf7f4BSmXpWHD0MIlw==
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@material/base@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/base/-/base-4.0.0.tgz#535574d0b63c18892cfb70e88b27bc8f8090677a"
|
||||||
|
integrity sha512-vHm7fkqXzjdfxifXvlmaZColoIfKuWmO+1rvdzDORTWP+A8Dq70cgKd2I1SBqxzDGjOasMzHbQI6f9MISQf2vQ==
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@material/dom@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/dom/-/dom-4.0.0.tgz#f0e68c4429e555040304c958bb3e11614276fdfa"
|
||||||
|
integrity sha512-GRCJT9+PGWqygZwGf1XLTrbmzP35YWG7+T0hpfhoIJO8VDiMTeyfvhJXFuA2wh9pD0noEjte0lmbdBlykrbWZw==
|
||||||
|
dependencies:
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@material/feature-targeting@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/feature-targeting/-/feature-targeting-4.0.0.tgz#8d9d1470801a1fd166773731613d9fa89e0fd85e"
|
||||||
|
integrity sha512-0gk+f151vqmEdWkrQ9ocPlQRU9aUtSGsVBhletqIbsthLUsZIz9qk25FHjV1wHd/bGHknd9NH+T8ENprv3KLFg==
|
||||||
|
|
||||||
|
"@material/icon-button@4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/icon-button/-/icon-button-4.0.0.tgz#f7293462f1b4967712f9b8755b87c2228dcccc3d"
|
||||||
|
integrity sha512-b1SyWtr2cwlKgIVo+irxRgW0lpIzauADLAxQEJ8/RTO9qVFviohJUnS+5QQCkC5zex5Q52OmQ+aNl0KRjkUdvQ==
|
||||||
|
dependencies:
|
||||||
|
"@material/base" "^4.0.0"
|
||||||
|
"@material/feature-targeting" "^4.0.0"
|
||||||
|
"@material/ripple" "^4.0.0"
|
||||||
|
"@material/theme" "^4.0.0"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@material/ripple@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/ripple/-/ripple-4.0.0.tgz#906ba421a3e6c68651d829d44c50a95060aa1e75"
|
||||||
|
integrity sha512-9BLIOvyCP5sM+fQpLlcJZWyrHguusJq8E5A1pxg0wQwputOyaPBM7recHhYkJmVjzRpTcPgf1PkvkpN6DKGcNg==
|
||||||
|
dependencies:
|
||||||
|
"@material/animation" "^4.0.0"
|
||||||
|
"@material/base" "^4.0.0"
|
||||||
|
"@material/dom" "^4.0.0"
|
||||||
|
"@material/feature-targeting" "^4.0.0"
|
||||||
|
"@material/theme" "^4.0.0"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
|
"@material/theme@^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@material/theme/-/theme-4.0.0.tgz#8de388fcdbae20fd09b02a3bdef3049bf2f623a8"
|
||||||
|
integrity sha512-vS4G4rusJTatTH50kSYO1U3UGN8EY9kGRvPaFsEFKikJBOqcR6KWK9H9/wCLqqd6nDNifEj9H2sdWw1AV4NA6Q==
|
||||||
|
dependencies:
|
||||||
|
"@material/feature-targeting" "^4.0.0"
|
||||||
|
|
||||||
"@mrmlnc/readdir-enhanced@^2.2.1":
|
"@mrmlnc/readdir-enhanced@^2.2.1":
|
||||||
version "2.2.1"
|
version "2.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
|
||||||
|
@ -1630,6 +1686,11 @@ dashdash@^1.12.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
|
date-fns@^2.10.0:
|
||||||
|
version "2.10.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.10.0.tgz#abd10604d8bafb0bcbd2ba2e9b0563b922ae4b6b"
|
||||||
|
integrity sha512-EhfEKevYGWhWlZbNeplfhIU/+N+x0iCIx7VzKlXma2EdQyznVlZhCptXUY+BegNpPW2kjdx15Rvq503YcXXrcA==
|
||||||
|
|
||||||
dateformat@^3.0.0:
|
dateformat@^3.0.0:
|
||||||
version "3.0.3"
|
version "3.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||||
|
|
Loading…
Reference in New Issue