├── .gitignore
├── assets
├── bottom-sheet-demo.gif
└── bottom-sheet-screenshot.png
├── index.html
├── main.js
├── package-lock.json
├── package.json
├── readme.md
├── src
├── TouchDragListener.js
├── _bottom-sheet.scss
├── _keyframes.scss
└── _reboot.scss
├── style.scss
├── yarn-error.log
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | node_modules/
3 | .cache/
4 |
--------------------------------------------------------------------------------
/assets/bottom-sheet-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwindo/bottom-sheet/7de993eb490a3860d65aa65f6b59dd40f9d41279/assets/bottom-sheet-demo.gif
--------------------------------------------------------------------------------
/assets/bottom-sheet-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hwindo/bottom-sheet/7de993eb490a3860d65aa65f6b59dd40f9d41279/assets/bottom-sheet-screenshot.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Parcel Sandbox
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import "./style.scss";
2 | import TouchDragListener from "./src/TouchDragListener.js";
3 |
4 | /**
5 | * Bottom Sheet
6 | * @author Windo
7 | */
8 | class BottomSheet {
9 | constructor(id) {
10 | this.id = id;
11 | this.el = document.getElementById(id);
12 | this.scrim = this.el.querySelector(".c-bottom-sheet__scrim");
13 | this.handle = this.el.querySelector(".c-bottom-sheet__handle");
14 | this.sheet = this.el.querySelector(".c-bottom-sheet__sheet");
15 | this.activate = this.activate.bind(this);
16 | this.deactivate = this.deactivate.bind(this);
17 |
18 | this.scrim.addEventListener("click", this.deactivate);
19 | this.handle.addEventListener("click", this.deactivate);
20 |
21 | this.sheetListener = new TouchDragListener({
22 | el: this.sheet,
23 | touchStartCallback: ({el, active, initialY, currentY, yOffset}) => {
24 | el.style.setProperty("--translateY", `translateY(0)`);
25 | el.style.setProperty("transition", `unset`);
26 | },
27 | touchEndCallback: ({el, active, initialY, currentY, yOffset}) => {
28 | el.style.setProperty(
29 | "transition",
30 | `transform 150ms cubic-bezier(0.4, 0, 0.2, 1)`
31 | );
32 | el.style.setProperty(
33 | "--translateY",
34 | `translateY(${currentY}px)`
35 | );
36 | },
37 | touchMoveCallback: ({el, active, initialY, currentY, yOffset}) => {
38 | if (currentY <= -40) {
39 | currentY = -41 + currentY / 10;
40 | } else if (currentY <= -60) {
41 | currentY = -60;
42 | } else if (currentY >= 210) {
43 | this.deactivate(currentY);
44 | return;
45 | }
46 |
47 | el.style.setProperty(
48 | "--translateY",
49 | `translateY(${currentY}px)`
50 | );
51 | }
52 | });
53 |
54 | this.scrimListener = new TouchDragListener({
55 | el: this.scrim,
56 | touchMoveCallback: ({el, active, initialY, currentY, yOffset}) => {
57 | if (currentY >= 83) {
58 | this.deactivate();
59 | return;
60 | }
61 | }
62 | });
63 | }
64 | activate(e) {
65 | if (e) e.preventDefault();
66 | this.el.classList.add("active");
67 | }
68 | deactivate(translateY) {
69 | if (!translateY) {
70 | this.sheet.style.setProperty("--translateY", `translateY(201px)`);
71 | } else {
72 | this.sheet.style.setProperty(
73 | "transition",
74 | `transform 150ms cubic-bezier(0.4, 0, 0.2, 1)`
75 | );
76 | this.sheet.style.setProperty(
77 | "--translateY",
78 | `translateY(${translateY}px)`
79 | );
80 | }
81 |
82 | this.el.classList.remove("active");
83 | }
84 | }
85 |
86 | const bottomSheet = new BottomSheet("country-selector");
87 | document
88 | .getElementById("country-select-button")
89 | .addEventListener("click", bottomSheet.activate);
90 |
91 | window.bottomSheet = bottomSheet;
92 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bottom-sheet",
3 | "version": "0.0.1",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "anymatch": {
8 | "version": "3.1.1",
9 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
10 | "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
11 | "dev": true,
12 | "requires": {
13 | "normalize-path": "^3.0.0",
14 | "picomatch": "^2.0.4"
15 | }
16 | },
17 | "binary-extensions": {
18 | "version": "2.1.0",
19 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
20 | "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
21 | "dev": true
22 | },
23 | "braces": {
24 | "version": "3.0.2",
25 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
26 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
27 | "dev": true,
28 | "requires": {
29 | "fill-range": "^7.0.1"
30 | }
31 | },
32 | "chokidar": {
33 | "version": "3.4.2",
34 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
35 | "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
36 | "dev": true,
37 | "requires": {
38 | "anymatch": "~3.1.1",
39 | "braces": "~3.0.2",
40 | "fsevents": "~2.1.2",
41 | "glob-parent": "~5.1.0",
42 | "is-binary-path": "~2.1.0",
43 | "is-glob": "~4.0.1",
44 | "normalize-path": "~3.0.0",
45 | "readdirp": "~3.4.0"
46 | }
47 | },
48 | "fill-range": {
49 | "version": "7.0.1",
50 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
51 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
52 | "dev": true,
53 | "requires": {
54 | "to-regex-range": "^5.0.1"
55 | }
56 | },
57 | "fsevents": {
58 | "version": "2.1.3",
59 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
60 | "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
61 | "dev": true,
62 | "optional": true
63 | },
64 | "glob-parent": {
65 | "version": "5.1.1",
66 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
67 | "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
68 | "dev": true,
69 | "requires": {
70 | "is-glob": "^4.0.1"
71 | }
72 | },
73 | "is-binary-path": {
74 | "version": "2.1.0",
75 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
76 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
77 | "dev": true,
78 | "requires": {
79 | "binary-extensions": "^2.0.0"
80 | }
81 | },
82 | "is-extglob": {
83 | "version": "2.1.1",
84 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
85 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
86 | "dev": true
87 | },
88 | "is-glob": {
89 | "version": "4.0.1",
90 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
91 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
92 | "dev": true,
93 | "requires": {
94 | "is-extglob": "^2.1.1"
95 | }
96 | },
97 | "is-number": {
98 | "version": "7.0.0",
99 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
100 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
101 | "dev": true
102 | },
103 | "normalize-path": {
104 | "version": "3.0.0",
105 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
106 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
107 | "dev": true
108 | },
109 | "picomatch": {
110 | "version": "2.2.2",
111 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
112 | "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
113 | "dev": true
114 | },
115 | "readdirp": {
116 | "version": "3.4.0",
117 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
118 | "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
119 | "dev": true,
120 | "requires": {
121 | "picomatch": "^2.2.1"
122 | }
123 | },
124 | "sass": {
125 | "version": "1.26.10",
126 | "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz",
127 | "integrity": "sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==",
128 | "dev": true,
129 | "requires": {
130 | "chokidar": ">=2.0.0 <4.0.0"
131 | }
132 | },
133 | "to-regex-range": {
134 | "version": "5.0.1",
135 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
136 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
137 | "dev": true,
138 | "requires": {
139 | "is-number": "^7.0.0"
140 | }
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bottom-sheet",
3 | "version": "0.0.1",
4 | "description": "Bottom sheet material like",
5 | "main": "main.js",
6 | "scripts": {
7 | "dev": "parcel watch index.html",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [
11 | "material",
12 | "bottom-sheet"
13 | ],
14 | "author": "Herwindo Artono",
15 | "license": "ISC",
16 | "devDependencies": {
17 | "sass": "^1.22.7"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Bottom-Sheet
2 | Vanilla Javascript Material design's Bottom-sheet for web
3 |
4 | 
5 |
6 | 
7 |
8 | ## Demo
9 | Setup parcel before running the demo
10 | `npm install -g parcel-bundler`
11 |
12 | and then just run
13 | `parcel index.html`
14 |
--------------------------------------------------------------------------------
/src/TouchDragListener.js:
--------------------------------------------------------------------------------
1 |
2 | class TouchDragListener {
3 | constructor({el, touchStartCallback, touchEndCallback, touchMoveCallback, showLog}) {
4 | this.el = el;
5 | this.touchStartCallback = touchStartCallback;
6 | this.touchEndCallback = touchEndCallback;
7 | this.touchMoveCallback = touchMoveCallback;
8 | this.showLog = showLog;
9 |
10 | this.active = false;
11 | this.currentY;
12 | this.initialY;
13 | this.yOffset = 0;
14 |
15 | this.dragStart = this.dragStart.bind(this);
16 | this.dragEnd = this.dragEnd.bind(this);
17 | this.drag = this.drag.bind(this);
18 |
19 | this.el.addEventListener("mousedown", this.dragStart);
20 | this.el.addEventListener("mouseleave", this.dragEnd);
21 | this.el.addEventListener("mouseup", this.dragEnd);
22 | this.el.addEventListener("mousemove", this.drag);
23 |
24 | this.el.addEventListener("touchstart", this.dragStart);
25 | this.el.addEventListener("touchend", this.dragEnd);
26 | this.el.addEventListener("touchmove", this.drag);
27 | }
28 |
29 | dragStart(e) {
30 | this.active = true;
31 | this.el.classList.add("active");
32 |
33 | if (e.type === "touchstart") {
34 | this.initialY = e.touches[0].clientY - this.yOffset;
35 | } else {
36 | this.initialY = e.clientY - this.yOffset;
37 | }
38 |
39 | if (!this.touchStartCallback) return;
40 |
41 | this.touchStartCallback({
42 | el: this.el,
43 | active: this.active,
44 | currentY: this.currentY,
45 | initialY: this.initialY,
46 | yOffset: this.offSetY
47 | })
48 | }
49 |
50 | dragEnd(e) {
51 | this.active = false;
52 | this.el.classList.remove("active");
53 |
54 | this.yOffset = 0;
55 |
56 | this.initialY = this.currentY;
57 |
58 | if (!this.touchEndCallback) return;
59 |
60 | this.touchEndCallback({
61 | el: this.el,
62 | active: this.active,
63 | currentY: this.currentY,
64 | initialY: this.initialY,
65 | yOffset: this.offSetY
66 | })
67 | }
68 | drag(e) {
69 | if (!this.active) return;
70 | e.preventDefault();
71 |
72 | if (e.type === "touchmove") {
73 | this.currentY = e.touches[0].clientY - this.initialY;
74 | } else {
75 | this.currentY = e.clientY - this.initialY;
76 | }
77 |
78 | this.yOffset = this.currentX;
79 |
80 | if (!this.touchMoveCallback) return;
81 |
82 | this.touchMoveCallback({
83 | el: this.el,
84 | active: this.active,
85 | currentY: this.currentY,
86 | initialY: this.initialY,
87 | yOffset: this.offSetY
88 | });
89 |
90 | if (this.showLog) {
91 | console.log({
92 | active: this.active,
93 | initialY: this.initialY,
94 | currentY: this.currentY,
95 | offSetY: this.offSetY
96 | });
97 | }
98 | }
99 | }
100 |
101 | export default TouchDragListener;
--------------------------------------------------------------------------------
/src/_bottom-sheet.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | --translatey: 0px;
3 | }
4 |
5 | body {
6 | perspective: 1000px;
7 | }
8 |
9 | .c-bottom-sheet {
10 | $component: &;
11 | $timing-fn: cubic-bezier(0.4, 0, 0.2, 1);
12 |
13 | pointer-events: none;
14 | visibility: hidden;
15 | overflow: hidden;
16 |
17 | &.active {
18 | visibility: visible;
19 | pointer-events: unset;
20 | }
21 |
22 | position: fixed;
23 | top: 0;
24 | height: 100vh;
25 | width: 100vw;
26 | z-index: 15;
27 | transition: opacity, visibility 0.25s;
28 |
29 | &__scrim {
30 | opacity: 0;
31 |
32 | .active & {
33 | opacity: 1;
34 | }
35 |
36 | display: block;
37 | position: absolute;
38 | height: 100vh;
39 | width: 100vw;
40 | background-color: rgba(0, 0, 0, 0.3);
41 | transition: opacity 0.3s;
42 | top: 0;
43 | }
44 |
45 | &__sheet {
46 | display: inline-block;
47 | position: absolute;
48 | left: 0;
49 | bottom: -100px;
50 | width: 100%;
51 | min-height: 38vh;
52 |
53 | background-color: white;
54 | border-radius: 12px 12px 0 0;
55 | padding: 0 1.5rem calc(1rem + 100px) 1.5rem;
56 | transition: transform 250ms $timing-fn;
57 | transform: translateY(100%);
58 | // animation: cubic-bezier(0.4, 0, 0.2, 1) 0.2s slideUp-0 forwards;
59 |
60 | .active & {
61 | transform: translateY(0);
62 | // animation: cubic-bezier(0.4, 0, 0.2, 1) 0.25s slideUp-1 forwards;
63 | }
64 |
65 | &.active {
66 | transform: var(--translateY);
67 | }
68 | }
69 |
70 | &__handle {
71 | display: flex;
72 | flex-direction: column;
73 | align-items: center;
74 | padding-top: 0.5rem;
75 | padding-bottom: 1rem;
76 |
77 | > span {
78 | display: block;
79 | height: 2px;
80 | width: 28px;
81 | margin-bottom: 2px;
82 | background-color: rgba(0, 0, 0, 0.3);
83 | border-radius: 2px;
84 | }
85 | }
86 |
87 | &__item {
88 | $border-item: 1px solid rgba(0, 0, 0, 0.3);
89 | width: 100%;
90 | list-style: none;
91 |
92 | border-bottom: $border-item;
93 |
94 |
95 | &:first-child {
96 | margin-top: 40px;
97 | border-top: $border-item;
98 | }
99 |
100 | &.active {
101 | font-family: sans-serif;
102 | font-weight: 900;
103 | }
104 | }
105 |
106 | &__link {
107 | display: block;
108 | padding: 1rem 0;
109 | &:hover, &:visited {
110 | color: unset;
111 | text-decoration: none;
112 | }
113 | }
114 |
115 | &__list {
116 | margin: 0;
117 | padding: 0;
118 |
119 | display: flex;
120 | flex-direction: column;
121 | align-items: center;
122 | }
123 |
124 | &__tick {
125 | display: none;
126 | font-size: 24px;
127 | object-fit: contain;
128 | vertical-align: middle;
129 |
130 | &:before {
131 | color: #48af4a;
132 | }
133 |
134 | #{$component}__item.active & {
135 | display: block;
136 | }
137 | }
138 |
139 | // on larger screen
140 | @media screen and (min-width: 769px) {
141 | // display: none;
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/src/_keyframes.scss:
--------------------------------------------------------------------------------
1 | @keyframes ball1Move-0 {
2 | 0% {
3 | transform: translate(0, 0);
4 | }
5 | 62% {
6 | transform: translate(-6px, -3px);
7 | }
8 | 100% {
9 | transform: translate(0, 0);
10 | }
11 | }
12 |
13 | @keyframes ball2Move-0 {
14 | 0% {
15 | transform: translate(0, 0);
16 | }
17 | 62% {
18 | transform: translate(3px, 6px);
19 | }
20 | 100% {
21 | transform: translate(0, 0);
22 | }
23 | }
24 |
25 | @keyframes ballHover-0 {
26 | 0% {
27 | transform: scale(1)
28 | }
29 | 16% {
30 | transform: scale(1.016)
31 | }
32 | 100% {
33 | transform: scale(1)
34 | }
35 | }
36 |
37 | @keyframes fade {
38 | 0% {
39 | opacity: 0;
40 | }
41 |
42 | 100% {
43 | opacity: 1;
44 | }
45 | }
46 |
47 | @keyframes horizontal-move {
48 | 0% {
49 | transform: scale(2) translateX(0);
50 | opacity: 1;
51 | display: flex;
52 | }
53 | 100% {
54 | transform: scale(2) translateX(6vw);
55 | opacity: 0;
56 | display: none;
57 | }
58 | }
59 |
60 | @keyframes horizontal-move-2 {
61 | 0% {
62 | transform: translateX(-15vw);
63 | opacity: 0;
64 | }
65 |
66 | 100% {
67 | transform: translateX(0);
68 | opacity: 1;
69 | }
70 | }
71 |
72 | @keyframes rotate180-0 {
73 | from {
74 | transform: rotate(-180deg);
75 | }
76 | to {
77 | transform: rotate(0deg);
78 | }
79 | }
80 |
81 | @keyframes rotate180-1 {
82 | from {
83 | transform: rotate(0deg);
84 | }
85 | to {
86 | transform: rotate(-180deg);
87 | }
88 | }
89 |
90 | @keyframes rotate180-reverse-0 {
91 | from {
92 | transform: rotate(180deg);
93 | }
94 | to {
95 | transform: rotate(0deg);
96 | }
97 | }
98 |
99 | @keyframes rotate180-reverse-1 {
100 | from {
101 | transform: rotate(0deg);
102 | }
103 | to {
104 | transform: rotate(180deg);
105 | }
106 | }
107 |
108 | @keyframes slideDown-1 {
109 | from {
110 | opacity: 0;
111 | transform: translateY(-100%);
112 | }
113 | to {
114 | opacity: 1;
115 | transform: translateY(0%);
116 | }
117 | }
118 |
119 | @keyframes slideUp-0 {
120 | from {
121 | transform: translateY(0%);
122 | }
123 | to {
124 | transform: translateY(100%);
125 | }
126 | }
127 |
128 | @keyframes slideUp-1 {
129 | from {
130 | transform: translateY(100%);
131 | }
132 | to {
133 | transform: translateY(0%);
134 | }
135 | }
136 |
137 | @keyframes markChange-0 {
138 | 0% {
139 | background: unset;
140 | }
141 | 62% {
142 | background: #333;
143 | }
144 | 100% {
145 | background: unset;
146 | }
147 | }
148 |
149 | @keyframes markChange-1 {
150 | }
151 |
152 | @keyframes pop-countryselect-1 {
153 | from {
154 | transform: scale(1, .33) translate(0, 100%);
155 | }
156 | to {
157 | transform: scale(1, 1) translate(0, 0);
158 | }
159 | }
160 |
161 | @keyframes pop-countryselect-0 {
162 | from {
163 | transform: scale(1, 1) translate(0, 0);
164 | }
165 | to {
166 | transform: scale(1, .33) translate(0, 100%);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/_reboot.scss:
--------------------------------------------------------------------------------
1 | *,
2 | *::before,
3 | *::after {
4 | box-sizing: border-box;
5 | }
6 |
7 | html {
8 | font-family: sans-serif;
9 | line-height: 1.15;
10 | -webkit-text-size-adjust: 100%;
11 | -ms-text-size-adjust: 100%;
12 | -ms-overflow-style: scrollbar;
13 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
14 | }
15 |
16 | @-ms-viewport {
17 | width: device-width;
18 | }
19 | article, aside, dialog, figcaption, figure, footer, header, hgroup, main, nav, section {
20 | display: block;
21 | }
22 |
23 | body {
24 | margin: 0;
25 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
26 | font-size: 1rem;
27 | font-weight: 400;
28 | line-height: 1.5;
29 | color: #212529;
30 | text-align: left;
31 | background-color: #fff;
32 | }
33 |
34 | [tabindex="-1"]:focus {
35 | outline: none !important;
36 | }
37 |
38 | hr {
39 | box-sizing: content-box;
40 | height: 0;
41 | overflow: visible;
42 | }
43 |
44 | h1, h2, h3, h4, h5, h6 {
45 | margin-top: 0;
46 | margin-bottom: 0.5rem;
47 | }
48 |
49 | p {
50 | margin-top: 0;
51 | margin-bottom: 1rem;
52 | }
53 |
54 | abbr[title],
55 | abbr[data-original-title] {
56 | text-decoration: underline;
57 | text-decoration: underline dotted;
58 | cursor: help;
59 | border-bottom: 0;
60 | }
61 |
62 | address {
63 | margin-bottom: 1rem;
64 | font-style: normal;
65 | line-height: inherit;
66 | }
67 |
68 | ol,
69 | ul,
70 | dl {
71 | margin-top: 0;
72 | margin-bottom: 1rem;
73 | }
74 |
75 | ol ol,
76 | ul ul,
77 | ol ul,
78 | ul ol {
79 | margin-bottom: 0;
80 | }
81 |
82 | dt {
83 | font-weight: 700;
84 | }
85 |
86 | dd {
87 | margin-bottom: .5rem;
88 | margin-left: 0;
89 | }
90 |
91 | blockquote {
92 | margin: 0 0 1rem;
93 | }
94 |
95 | dfn {
96 | font-style: italic;
97 | }
98 |
99 | b,
100 | strong {
101 | font-weight: bolder;
102 | }
103 |
104 | small {
105 | font-size: 80%;
106 | }
107 |
108 | sub,
109 | sup {
110 | position: relative;
111 | font-size: 75%;
112 | line-height: 0;
113 | vertical-align: baseline;
114 | }
115 |
116 | sub {
117 | bottom: -.25em;
118 | }
119 |
120 | sup {
121 | top: -.5em;
122 | }
123 |
124 | a {
125 | color: theme-color("primary");
126 | text-decoration: none;
127 | background-color: transparent;
128 | -webkit-text-decoration-skip: objects;
129 | }
130 | a:hover {
131 | color: #0056b3;
132 | text-decoration: underline;
133 | }
134 |
135 | a:not([href]):not([tabindex]) {
136 | color: inherit;
137 | text-decoration: none;
138 | }
139 | a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
140 | color: inherit;
141 | text-decoration: none;
142 | }
143 | a:not([href]):not([tabindex]):focus {
144 | outline: 0;
145 | }
146 |
147 | pre,
148 | code,
149 | kbd,
150 | samp {
151 | font-family: monospace, monospace;
152 | font-size: 1em;
153 | }
154 |
155 | pre {
156 | margin-top: 0;
157 | margin-bottom: 1rem;
158 | overflow: auto;
159 | -ms-overflow-style: scrollbar;
160 | }
161 |
162 | figure {
163 | margin: 0 0 1rem;
164 | }
165 |
166 | img {
167 | vertical-align: middle;
168 | border-style: none;
169 | }
170 |
171 | svg:not(:root) {
172 | overflow: hidden;
173 | }
174 |
175 | a,
176 | area,
177 | button,
178 | [role="button"],
179 | input:not([type="range"]),
180 | label,
181 | select,
182 | summary,
183 | textarea {
184 | touch-action: manipulation;
185 | }
186 |
187 | table {
188 | border-collapse: collapse;
189 | }
190 |
191 | caption {
192 | padding-top: 0.75rem;
193 | padding-bottom: 0.75rem;
194 | color: #868e96;
195 | text-align: left;
196 | caption-side: bottom;
197 | }
198 |
199 | th {
200 | text-align: inherit;
201 | }
202 |
203 | label {
204 | display: inline-block;
205 | margin-bottom: .5rem;
206 | }
207 |
208 | button {
209 | border-radius: 0;
210 | }
211 |
212 | button:focus {
213 | outline: 1px dotted;
214 | outline: 5px auto -webkit-focus-ring-color;
215 | }
216 |
217 | input,
218 | button,
219 | select,
220 | optgroup,
221 | textarea {
222 | margin: 0;
223 | font-family: inherit;
224 | font-size: inherit;
225 | line-height: inherit;
226 | }
227 |
228 | button,
229 | input {
230 | overflow: visible;
231 | }
232 |
233 | button,
234 | select {
235 | text-transform: none;
236 | }
237 |
238 | button,
239 | html [type="button"],
240 | [type="reset"],
241 | [type="submit"] {
242 | -webkit-appearance: button;
243 | }
244 |
245 | button::-moz-focus-inner,
246 | [type="button"]::-moz-focus-inner,
247 | [type="reset"]::-moz-focus-inner,
248 | [type="submit"]::-moz-focus-inner {
249 | padding: 0;
250 | border-style: none;
251 | }
252 |
253 | input[type="radio"],
254 | input[type="checkbox"] {
255 | box-sizing: border-box;
256 | padding: 0;
257 | }
258 |
259 | input[type="date"],
260 | input[type="time"],
261 | input[type="datetime-local"],
262 | input[type="month"] {
263 | -webkit-appearance: listbox;
264 | }
265 |
266 | textarea {
267 | overflow: auto;
268 | resize: vertical;
269 | }
270 |
271 | fieldset {
272 | min-width: 0;
273 | padding: 0;
274 | margin: 0;
275 | border: 0;
276 | }
277 |
278 | legend {
279 | display: block;
280 | width: 100%;
281 | max-width: 100%;
282 | padding: 0;
283 | margin-bottom: .5rem;
284 | font-size: 1.5rem;
285 | line-height: inherit;
286 | color: inherit;
287 | white-space: normal;
288 | }
289 |
290 | progress {
291 | vertical-align: baseline;
292 | }
293 |
294 | [type="number"]::-webkit-inner-spin-button,
295 | [type="number"]::-webkit-outer-spin-button {
296 | height: auto;
297 | }
298 |
299 | [type="search"] {
300 | outline-offset: -2px;
301 | -webkit-appearance: none;
302 | }
303 |
304 | [type="search"]::-webkit-search-cancel-button,
305 | [type="search"]::-webkit-search-decoration {
306 | -webkit-appearance: none;
307 | }
308 |
309 | ::-webkit-file-upload-button {
310 | font: inherit;
311 | -webkit-appearance: button;
312 | }
313 |
314 | output {
315 | display: inline-block;
316 | }
317 |
318 | summary {
319 | display: list-item;
320 | }
321 |
322 | template {
323 | display: none;
324 | }
325 |
326 | [hidden] {
327 | display: none !important;
328 | }
--------------------------------------------------------------------------------
/style.scss:
--------------------------------------------------------------------------------
1 | @import "src/reboot";
2 | @import "src/keyframes";
3 | @import "src/bottom-sheet";
4 |
5 | body {
6 | font-size: 20px;
7 | background-image: linear-gradient(#00aa13, #1ab32b, #009911);
8 | }
9 |
10 | .header {
11 | display: flex;
12 | flex-flow: column wrap;
13 | justify-content: center;
14 | align-items: center;
15 | height: 100vh;
16 | }
--------------------------------------------------------------------------------
/yarn-error.log:
--------------------------------------------------------------------------------
1 | Arguments:
2 | /Users/windo/.nvm/versions/node/v10.15.2/bin/node /Users/windo/.nvm/versions/node/v10.15.2/bin/yarn add style.scss
3 |
4 | PATH:
5 | /Users/windo/.nvm/versions/node/v10.15.2/bin:/usr/local/Cellar/pyenv-virtualenv/1.1.3/shims:/Users/windo/.pyenv/shims:/Users/windo/.pyenv/bin:/Users/windo/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/windo/.nvm/versions/node/v10.15.2/bin:/usr/local/Cellar/pyenv-virtualenv/1.1.3/shims:/Users/windo/.pyenv/shims:/Users/windo/.pyenv/bin:/Users/windo/bin:/usr/local/mysql/bin:/Users/windo/Development/flutter/bin/:/usr/local/mysql/bin:/Users/windo/Development/flutter/bin/
6 |
7 | Yarn version:
8 | 1.13.0
9 |
10 | Node version:
11 | 10.15.2
12 |
13 | Platform:
14 | darwin x64
15 |
16 | Trace:
17 | Error: https://registry.yarnpkg.com/style.scss: Not found
18 | at Request.params.callback [as _callback] (/Users/windo/.nvm/versions/node/v10.15.2/lib/node_modules/yarn/lib/cli.js:66255:18)
19 | at Request.self.callback (/Users/windo/.nvm/versions/node/v10.15.2/lib/node_modules/yarn/lib/cli.js:129397:22)
20 | at Request.emit (events.js:189:13)
21 | at Request. (/Users/windo/.nvm/versions/node/v10.15.2/lib/node_modules/yarn/lib/cli.js:130369:10)
22 | at Request.emit (events.js:189:13)
23 | at IncomingMessage. (/Users/windo/.nvm/versions/node/v10.15.2/lib/node_modules/yarn/lib/cli.js:130291:12)
24 | at Object.onceWrapper (events.js:277:13)
25 | at IncomingMessage.emit (events.js:194:15)
26 | at endReadableNT (_stream_readable.js:1103:12)
27 | at process._tickCallback (internal/process/next_tick.js:63:19)
28 |
29 | npm manifest:
30 | {
31 | "name": "bottom-sheet",
32 | "version": "0.0.1",
33 | "description": "Bottom sheet material like",
34 | "main": "main.js",
35 | "scripts": {
36 | "dev": "parcel watch index.html",
37 | "test": "echo \"Error: no test specified\" && exit 1"
38 | },
39 | "keywords": ["material", "bottom-sheet"],
40 | "author": "Herwindo Artono",
41 | "license": "ISC"
42 | }
43 |
44 | yarn manifest:
45 | No manifest
46 |
47 | Lockfile:
48 | No lockfile
49 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | anymatch@^3.0.1:
6 | version "3.0.3"
7 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.0.3.tgz#2fb624fe0e84bccab00afee3d0006ed310f22f09"
8 | integrity sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g==
9 | dependencies:
10 | normalize-path "^3.0.0"
11 | picomatch "^2.0.4"
12 |
13 | binary-extensions@^2.0.0:
14 | version "2.0.0"
15 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
16 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
17 |
18 | braces@^3.0.2:
19 | version "3.0.2"
20 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
21 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
22 | dependencies:
23 | fill-range "^7.0.1"
24 |
25 | "chokidar@>=2.0.0 <4.0.0":
26 | version "3.0.2"
27 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.0.2.tgz#0d1cd6d04eb2df0327446188cd13736a3367d681"
28 | integrity sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==
29 | dependencies:
30 | anymatch "^3.0.1"
31 | braces "^3.0.2"
32 | glob-parent "^5.0.0"
33 | is-binary-path "^2.1.0"
34 | is-glob "^4.0.1"
35 | normalize-path "^3.0.0"
36 | readdirp "^3.1.1"
37 | optionalDependencies:
38 | fsevents "^2.0.6"
39 |
40 | fill-range@^7.0.1:
41 | version "7.0.1"
42 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
43 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
44 | dependencies:
45 | to-regex-range "^5.0.1"
46 |
47 | fsevents@^2.0.6:
48 | version "2.0.7"
49 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
50 | integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
51 |
52 | glob-parent@^5.0.0:
53 | version "5.0.0"
54 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954"
55 | integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==
56 | dependencies:
57 | is-glob "^4.0.1"
58 |
59 | is-binary-path@^2.1.0:
60 | version "2.1.0"
61 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
62 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
63 | dependencies:
64 | binary-extensions "^2.0.0"
65 |
66 | is-extglob@^2.1.1:
67 | version "2.1.1"
68 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
69 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
70 |
71 | is-glob@^4.0.1:
72 | version "4.0.1"
73 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
74 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
75 | dependencies:
76 | is-extglob "^2.1.1"
77 |
78 | is-number@^7.0.0:
79 | version "7.0.0"
80 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
81 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
82 |
83 | normalize-path@^3.0.0:
84 | version "3.0.0"
85 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
86 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
87 |
88 | picomatch@^2.0.4:
89 | version "2.0.7"
90 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
91 | integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
92 |
93 | readdirp@^3.1.1:
94 | version "3.1.1"
95 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.1.1.tgz#b158123ac343c8b0f31d65680269cc0fc1025db1"
96 | integrity sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ==
97 | dependencies:
98 | picomatch "^2.0.4"
99 |
100 | sass@^1.22.7:
101 | version "1.22.9"
102 | resolved "https://registry.yarnpkg.com/sass/-/sass-1.22.9.tgz#41a2ed6038027f58be2bd5041293452a29c2cb84"
103 | integrity sha512-FzU1X2V8DlnqabrL4u7OBwD2vcOzNMongEJEx3xMEhWY/v26FFR3aG0hyeu2T965sfR0E9ufJwmG+Qjz78vFPQ==
104 | dependencies:
105 | chokidar ">=2.0.0 <4.0.0"
106 |
107 | to-regex-range@^5.0.1:
108 | version "5.0.1"
109 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
110 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
111 | dependencies:
112 | is-number "^7.0.0"
113 |
--------------------------------------------------------------------------------