## What is it

Sticky notes provide a way to attach information. They are a DS2 core pattern for making notes.

## When to use it

Use a sticky when you want to make a note without adding it to the content.

## How to use it

Uses absolute positioning. Passing an optional element to the init function will initialise tabs within that element. You can move the position using either `float="[ right | left ]"` or `offset="[ top | left ]"`. Offset will take negative values in any web measurement unit. This is a sample sticky. You can drag it out of the way if you need to see the content under it. You will notice when you hover over the sticky, it shows a dot in the colour of the sticky in the position where the sticky note refers to (assuming you haven't dragged it and scrolled that location off the screen).

If you wish to create a custom element, that extends another HTML element, the native element has to be extended in customElements.define(). Custom elements that inherit native elements are also known as "type extension custom elements".

            This is a sample sticky. You can drag it out of the way if you need to see the content under it.

    sticky-note(float="right").blue This #[strong is] a sample sticky.
    	| You can drag it out of the way if you need to see the content under it.

     @import url("https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap");sticky-note-wrapper{-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid transparent;border-radius:50%;display:inline-block;height:0.5rem;position:relative;width:0.5rem}sticky-note-wrapper *{-webkit-box-sizing:border-box;box-sizing:border-box}sticky-note-wrapper sticky-note{cursor:-webkit-grab;cursor:grab;display:-ms-grid;display:grid;float:left;font-size:1rem;height:13rem;left:0;place-items:stretch;position:absolute;top:0;width:13rem;z-index:100}sticky-note-wrapper sticky-note:active{cursor:-webkit-grabbing;cursor:grabbing;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}sticky-note-wrapper sticky-note.right{float:right}sticky-note-wrapper sticky-note>div{-ms-grid-row:1;grid-row:1;-ms-grid-column:1;grid-column:1}sticky-note-wrapper sticky-note>div:first-child{background-color:rgba(0,0,0,0.25);-webkit-box-shadow:-2px 2px 15px 0 rgba(0,0,0,0.5);box-shadow:-2px 2px 15px 0 rgba(0,0,0,0.5);display:-ms-grid;display:grid;margin:2rem 1rem 0.25rem 0.36rem;width:calc(100% - 1rem)}sticky-note-wrapper sticky-note>div:nth-child(2){clip-path:url(#stickyClip);display:-ms-grid;display:grid;font-family:"Kalam",cursive;font-style:1rem;font-weight:300;line-height:1.25rem;padding:1rem;place-items:center;text-align:center}sticky-note-wrapper sticky-note>div:nth-child(2)>*{font-family:"Kalam",cursive!important;font-style:normal!important;font-weight:300!important}@media screen and (max-width:1024px){sticky-note-wrapper sticky-note>div:nth-child(2){max-width:13rem;min-width:13rem;width:1rem}}@media screen and (max-width:768px){sticky-note-wrapper sticky-note>div:nth-child(2){font-size:1.75rem;max-width:21rem;min-height:21rem}}@media screen and (max-width:640px){sticky-note-wrapper sticky-note>div:nth-child(2){font-size:2.5rem;max-width:26rem;min-height:26rem}}sticky-note-wrapper sticky-note>div:nth-child(2){background:-webkit-gradient(linear,left top,left bottom,from(#ffffdd),color-stop(2%,#ffffd3),color-stop(12%,#ffffd3),color-stop(75%,#ffffc9),to(#ffffba));background:linear-gradient(180deg,#ffffdd 0%,#ffffd3 2%,#ffffd3 12%,#ffffc9 75%,#ffffba 100%)}sticky-note-wrapper sticky-note.blue>div:nth-child(2){background:-webkit-gradient(linear,left top,left bottom,from(#9dddec),color-stop(2%,#94daea),color-stop(12%,#94daea),color-stop(75%,#8bd7e8),to(#7fd3e6));background:linear-gradient(180deg,#9dddec 0%,#94daea 2%,#94daea 12%,#8bd7e8 75%,#7fd3e6 100%)}sticky-note-wrapper sticky-note.pink>div:nth-child(2){background:-webkit-gradient(linear,left top,left bottom,from(#fa7c93),color-stop(2%,#fa728b),color-stop(12%,#fa728b),color-stop(75%,#fa6883),to(#f95977));background:linear-gradient(180deg,#fa7c93 0%,#fa728b 2%,#fa728b 12%,#fa6883 75%,#f95977 100%)}sticky-note-wrapper sticky-note.green>div:nth-child(2){background:-webkit-gradient(linear,left top,left bottom,from(#c5fcc9),color-stop(2%,#bbfbc0),color-stop(12%,#bbfbc0),color-stop(75%,#b1fab7),to(#a3faaa));background:linear-gradient(180deg,#c5fcc9 0%,#bbfbc0 2%,#bbfbc0 12%,#b1fab7 75%,#a3faaa 100%)}sticky-note-wrapper:has(sticky-note:hover){background-color:#ffffd3;border:1px solid black}sticky-note-wrapper:has(sticky-note.yellow:hover){background-color:#ffffd3}sticky-note-wrapper:has(sticky-note.blue:hover){background-color:#94daea}sticky-note-wrapper:has(sticky-note.pink:hover){background-color:#fa728b}sticky-note-wrapper:has(sticky-note.green:hover){background-color:#bbfbc0}

    $sticky-colors: ( [sass map with your own defined colours] );
    @import "scss/core/switch/_sticky-note";
    @include sticky-note;

    //-		DS2 core (c) 2024 Alexander McIlwraith
    //-		Licensed under CC BY-SA 4.0

    @use 'sass:color';
    @use "sass:map";
    @use 'sass:list';
    @import url('https://fonts.googleapis.com/css2?family=Kalam:wght@300;400;700&display=swap');

    $sticky-colors: (
    	"yellow": #ffffd3,
    	"blue": #94daea,
    	"pink": #fa728b,
    	"green": #bbfbc0 ) !default;

    @mixin sticky-note {
    	sticky-note-wrapper {
    		box-sizing: border-box;

    		border: 1px solid transparent;
    		border-radius: 50%;
    		display: inline-block;
    		height: .5rem;
    		position: relative;
    		width: .5rem;
    		& * {
    			box-sizing: border-box;
    		}
    		sticky-note {
    			cursor: grab;
    			display: grid;
    			float: left;
    			font-size: 1rem;
    			height: 13rem;
    			left: 0;
    			place-items: stretch;
    			position: absolute;
    			top: 0;
    			width: 13rem;
    			z-index: 100;

    			&:active {
    				cursor: grabbing;
    				user-select: none;
    			}

    			@media screen and (max-width: 1024px) {
    				//width: 15rem;
    				// background-color: green;
    			}
    			@media screen and (max-width: 768px) {
    				//width: 20rem;
    				// background-color: blue;
    			}
    			@media screen and (max-width: 640px) {
    				//width: 30rem;
    				// background-color: yellow;
    			}
    			&.right {
    				float: right;
    			}
    			@content;

    			> div {
    				grid-row: 1;
    				grid-column: 1;
    				&:nth-child(1) {
    					background-color: rgba(0, 0, 0, 0.25);
    					box-shadow: -2px 2px 15px 0 rgba(0, 0, 0, 0.5);
    					display: grid;
    					margin: 2rem 1rem .25rem .36rem;
    					width: calc(100% - 1rem);

    				}
    				&:nth-child(2) {
    					clip-path: url(#stickyClip);
    					display: grid;
    					font-family: "Kalam", cursive;
    					font-style: 1rem;
    					font-weight: 300;
    					line-height: 1.25rem;
    					padding: 1rem;
    					place-items: center;
    					text-align: center;
    					// not adding this because maybe we want the sticky note text to be able to be selected and copied.
    					// user-select: none;
    					> * {
    						font-family: "Kalam", cursive !important;
    						font-style: normal !important;
    						font-weight: 300 !important;
    					}

    					@media screen and (max-width: 1024px) {
    						max-width: 13rem;
    						min-width: 13rem;
    						width: 1rem;
    					}
    					@media screen and (max-width: 768px) {
    						font-size: 1.75rem;
    						max-width: 21rem;
    						min-height: 21rem;
    					}
    					@media screen and (max-width: 640px) {
    						font-size: 2.5rem;
    						max-width: 26rem;
    						min-height: 26rem;
    					}
    				}
    			}

    			// default colour
    			> div:nth-child(2) {
    				$sticky-color: nth(map.values($sticky-colors), 1);
    				background: linear-gradient(
    					180deg,
    					lighten($sticky-color, 2%) 0%,
    					$sticky-color 2%,
    					$sticky-color 12%,
    					darken($sticky-color, 2%) 75%,
    					darken($sticky-color, 5%) 100%
    				);
    			}
    			// all class colors
    			@each $class, $sticky-color in $sticky-colors {
    				&.#{$class} > div:nth-child(2) {
    					@if $class != nth(map.keys($sticky-colors), 1) {
    						background: linear-gradient(
    							180deg,
    							lighten($sticky-color, 2%) 0%,
    							$sticky-color 2%,
    							$sticky-color 12%,
    							darken($sticky-color, 2%) 75%,
    							darken($sticky-color, 5%) 100%
    						);
    					}
    				}
    			}
    		}
    		&:has(sticky-note:hover) {
    			background-color: #{nth(map.values($sticky-colors), 1)};
    			border: 1px solid black;

    		}
    		@each $class, $sticky-color in $sticky-colors {
    			&:has(sticky-note.#{$class}:hover) {
    				background-color: $sticky-color;
    			}
    		}
    	}
    }

    import * as stickynote from ""./js/core/sticky-note/_sticky-note.js";
    stickynote.init()

    //-		DS2 core (c) 2024 Alexander McIlwraith
    //-		Licensed under CC BY-SA 4.0

    const font = {
    	size: 0
    }

    const pos = {
    	x: 0,
    	y: 0
    }

    function drag(sticky) {
    	sticky.onmousedown = event => {
    		// get the position within the sticky
    		pos.x = (event.clientX - sticky.offsetLeft);
    		pos.y = (event.clientY - sticky.offsetTop);

    		// on mouse move, move the sticky to the position, minus the offset, of the mouse
    		document.onmousemove = documentEvent => {
    			sticky.style.top = (documentEvent.clientY - pos.y) + 'px';
    			sticky.style.left = (documentEvent.clientX - pos.x) + 'px';
    			sticky.setAttribute("moved", "true");
    		}
    		// when done, remove mouse move and mouse up handlers.
    		document.onmouseup = () => {
    			document.onmouseup = null;
    			document.onmousemove = null;
    		}
    	}
    }

    function waitForElement(selector) {
        return new Promise(resolve => {
            if (document.querySelector(selector)) {
                return resolve(document.querySelector(selector));
            }

            const observer = new MutationObserver(mutations => {
                if (document.querySelector(selector)) {
                    observer.disconnect();
                    resolve(document.querySelector(selector));
                }
            });

            // If you get "parameter 1 is not of type 'Node'" error, see https://stackoverflow.com/a/77855838/492336
            observer.observe(document.body, {
                childList: true,
                subtree: true
            });
        });
    }

    const checkBottom = (attach) => {
    	// check if top or bottom
    	if (attach.y < 0) {
    		attach.ys = "bottom";
    		attach.y = attach.y * -1;
    	}
    }

    const setStickyPostions = (s, attach) => {
    		// set
    		s.style[attach.ys] = `${attach.y}px`;
    		s.style[attach.xs] = `${attach.x}px`;
    		s.style.display = "grid";
    }

    const css = (el, attr) => {
    	let st = ""
    	Object.entries(attr).forEach(val => {
    		const [key, value] = val;
      		st += `${key}: ${value}; `;
    	})
      	el.setAttribute("style",st.trim());
    }

    const calculateStickyPosition = (s) => {
    	let float = s.getAttribute("float");
    	let p = s.parentNode.getBoundingClientRect()
    	switch (float) {
    		case "left":
    			css(s, {left: (p.left * -1) + "px"})
    			break;
    		case "right":
    			css(s, { left: (Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) - p.left - s.offsetWidth - (font.size * 2)) + "px" });
    			break;
    	}

    	let offset = s.getAttribute("offset");
    	if (offset !== null) {
    		offset = offset.trim().split(" ");
    		css(s, {top: offset[0], left: offset[1] })
    	}
    }

    export function init(p = document){
    	font.size = parseFloat(getComputedStyle(document.documentElement).fontSize.replace("px",""));

    	p.querySelectorAll("sticky-note").forEach((s) => {
    		if (s.querySelectorAll("svg").length == 0) {

    			let wrapper = document.createElement("sticky-note-wrapper");

    			s.parentNode.insertBefore(wrapper, s);
        		wrapper.appendChild(s);

    			s.setAttribute("content", s.innerHTML.replace(/"/g, "\""));
    			s.innerHTML = `${s.innerHTML}`;
    		}
    		calculateStickyPosition(s);
    		drag(s);
    		s.ondblclick = (e) => {
    			if (e.ctrlKey) {
    				calculateStickyPosition(s);
    			} else {
    				// add one click select
    			}
    		}
    	})

    	window.onresize = () => {
    		font.size = parseFloat(getComputedStyle(document.documentElement).fontSize.replace("px",""));
    		let stickies = p.querySelectorAll("sticky-note");
    		stickies.forEach((s) => {
    			calculateStickyPosition(s);
    		});
    	}
    }