Content Component
+{profile.name}
+Your existing weekly-note settings from the Calendar plugin have been + migrated over automatically. The functionality will be removed from + the Calendar plugin in the future.
`; + + t3 = space(); + div1 = element("div"); + if_block.c(); + attr(div0, "class", "setting-item-info"); + attr(div1, "class", "setting-item-control"); + attr(div2, "class", "setting-item"); + }, + m(target, anchor) { + insert(target, div2, anchor); + append(div2, div0); + append(div2, t3); + append(div2, div1); + if_blocks[current_block_type_index].m(div1, null); + current = true; + }, + p(ctx, dirty) { + let previous_block_index = current_block_type_index; + current_block_type_index = select_block_type_2(ctx); + + if (current_block_type_index !== previous_block_index) { + group_outros(); + + transition_out(if_blocks[previous_block_index], 1, 1, () => { + if_blocks[previous_block_index] = null; + }); + + check_outros(); + if_block = if_blocks[current_block_type_index]; + + if (!if_block) { + if_block = if_blocks[current_block_type_index] = if_block_creators[current_block_type_index](ctx); + if_block.c(); + } + + transition_in(if_block, 1); + if_block.m(div1, null); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + current = true; + }, + o(local) { + transition_out(if_block); + current = false; + }, + d(detaching) { + if (detaching) detach(div2); + if_blocks[current_block_type_index].d(); + } + }; +} + +// (67:8) {:else} +function create_else_block(ctx) { + let button; + + return { + c() { + button = element("button"); + button.textContent = "Migrate"; + attr(button, "class", "mod-cta svelte-1alo0m9"); + }, + m(target, anchor) { + insert(target, button, anchor); + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(button); + } + }; +} + +// (62:8) {#if $settings.hasMigratedWeeklyNoteSettings} +function create_if_block_2(ctx) { + let button; + let t; + let checkmark; + let current; + checkmark = new Checkmark({}); + + return { + c() { + button = element("button"); + t = text("Migrated\n "); + create_component(checkmark.$$.fragment); + button.disabled = true; + attr(button, "class", "svelte-1alo0m9"); + }, + m(target, anchor) { + insert(target, button, anchor); + append(button, t); + mount_component(checkmark, button, null); + current = true; + }, + i(local) { + if (current) return; + transition_in(checkmark.$$.fragment, local); + current = true; + }, + o(local) { + transition_out(checkmark.$$.fragment, local); + current = false; + }, + d(detaching) { + if (detaching) detach(button); + destroy_component(checkmark); + } + }; +} + +// (74:2) {#if !hasDailyNoteSettings && !hasWeeklyNoteSettings} +function create_if_block$4(ctx) { + let p; + + return { + c() { + p = element("p"); + p.textContent = "With this plugin, you can quickly create and navigate to daily, weekly,\n and monthly notes. Enable them below to get started."; + }, + m(target, anchor) { + insert(target, p, anchor); + }, + d(detaching) { + if (detaching) detach(p); + } + }; +} + +function create_fragment$4(ctx) { + let div; + let h3; + let t1; + let t2; + let t3; + let t4; + let button; + let div_outro; + let current; + let mounted; + let dispose; + let if_block0 = /*hasDailyNoteSettings*/ ctx[3] && create_if_block_3(ctx); + let if_block1 = /*hasWeeklyNoteSettings*/ ctx[4] && create_if_block_1$2(ctx); + let if_block2 = !/*hasDailyNoteSettings*/ ctx[3] && !/*hasWeeklyNoteSettings*/ ctx[4] && create_if_block$4(); + + return { + c() { + div = element("div"); + h3 = element("h3"); + h3.textContent = "Getting Started"; + t1 = space(); + if (if_block0) if_block0.c(); + t2 = space(); + if (if_block1) if_block1.c(); + t3 = space(); + if (if_block2) if_block2.c(); + t4 = space(); + button = element("button"); + button.textContent = "Dismiss"; + attr(button, "class", "svelte-1alo0m9"); + attr(div, "class", "settings-banner"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, h3); + append(div, t1); + if (if_block0) if_block0.m(div, null); + append(div, t2); + if (if_block1) if_block1.m(div, null); + append(div, t3); + if (if_block2) if_block2.m(div, null); + append(div, t4); + append(div, button); + current = true; + + if (!mounted) { + dispose = listen(button, "click", function () { + if (is_function(/*handleTeardown*/ ctx[1])) /*handleTeardown*/ ctx[1].apply(this, arguments); + }); + + mounted = true; + } + }, + p(new_ctx, [dirty]) { + ctx = new_ctx; + + if (/*hasDailyNoteSettings*/ ctx[3]) { + if (if_block0) { + if_block0.p(ctx, dirty); + + if (dirty & /*hasDailyNoteSettings*/ 8) { + transition_in(if_block0, 1); + } + } else { + if_block0 = create_if_block_3(ctx); + if_block0.c(); + transition_in(if_block0, 1); + if_block0.m(div, t2); + } + } else if (if_block0) { + group_outros(); + + transition_out(if_block0, 1, 1, () => { + if_block0 = null; + }); + + check_outros(); + } + + if (/*hasWeeklyNoteSettings*/ ctx[4]) { + if (if_block1) { + if_block1.p(ctx, dirty); + + if (dirty & /*hasWeeklyNoteSettings*/ 16) { + transition_in(if_block1, 1); + } + } else { + if_block1 = create_if_block_1$2(ctx); + if_block1.c(); + transition_in(if_block1, 1); + if_block1.m(div, t3); + } + } else if (if_block1) { + group_outros(); + + transition_out(if_block1, 1, 1, () => { + if_block1 = null; + }); + + check_outros(); + } + + if (!/*hasDailyNoteSettings*/ ctx[3] && !/*hasWeeklyNoteSettings*/ ctx[4]) { + if (if_block2) ; else { + if_block2 = create_if_block$4(); + if_block2.c(); + if_block2.m(div, t4); + } + } else if (if_block2) { + if_block2.d(1); + if_block2 = null; + } + }, + i(local) { + if (current) return; + transition_in(if_block0); + transition_in(if_block1); + if (div_outro) div_outro.end(1); + current = true; + }, + o(local) { + transition_out(if_block0); + transition_out(if_block1); + div_outro = create_out_transition(div, slide, {}); + current = false; + }, + d(detaching) { + if (detaching) detach(div); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + if (if_block2) if_block2.d(); + if (detaching && div_outro) div_outro.end(); + mounted = false; + dispose(); + } + }; +} + +function instance$4($$self, $$props, $$invalidate) { + let $settings, + $$unsubscribe_settings = noop, + $$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(5, $settings = $$value)), settings); + + $$self.$$.on_destroy.push(() => $$unsubscribe_settings()); + + + let { settings } = $$props; + $$subscribe_settings(); + let { handleTeardown } = $$props; + let { migrateDailyNoteSettings } = $$props; + let hasDailyNoteSettings; + let hasWeeklyNoteSettings; + + $$self.$$set = $$props => { + if ("settings" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings)); + if ("handleTeardown" in $$props) $$invalidate(1, handleTeardown = $$props.handleTeardown); + if ("migrateDailyNoteSettings" in $$props) $$invalidate(2, migrateDailyNoteSettings = $$props.migrateDailyNoteSettings); + }; + + { + $$invalidate(3, hasDailyNoteSettings = hasLegacyDailyNoteSettings()); + $$invalidate(4, hasWeeklyNoteSettings = hasLegacyWeeklyNoteSettings()); + } + + return [ + settings, + handleTeardown, + migrateDailyNoteSettings, + hasDailyNoteSettings, + hasWeeklyNoteSettings, + $settings + ]; +} + +class GettingStartedBanner extends SvelteComponent { + constructor(options) { + super(); + if (!document.getElementById("svelte-1alo0m9-style")) add_css(); + + init(this, options, instance$4, create_fragment$4, safe_not_equal, { + settings: 0, + handleTeardown: 1, + migrateDailyNoteSettings: 2 + }); + } +} + +function getBasename(format) { + const isTemplateNested = format.indexOf("/") !== -1; + return isTemplateNested ? format.split("/").pop() : format; +} +function isValidFilename(filename) { + const illegalRe = /[?<>\\:*|"]/g; + const controlRe = /[\x00-\x1f\x80-\x9f]/g; + const reservedRe = /^\.+$/; + const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i; + return (!illegalRe.test(filename) && + !controlRe.test(filename) && + !reservedRe.test(filename) && + !windowsReservedRe.test(filename)); +} +function validateFormat(format, periodicity) { + if (!format) { + return ""; + } + if (!isValidFilename(format)) { + return "Format contains illegal characters"; + } + if (periodicity === "daily" && + !["m", "d", "y"].every((requiredChar) => getBasename(format) + .replace(/\[[^\]]*\]/g, "") // remove everything within brackets + .toLowerCase() + .indexOf(requiredChar) !== -1)) { + return "Filename must be unique"; + } +} +function validateTemplate(template) { + if (!template) { + return ""; + } + const { metadataCache } = window.app; + const file = metadataCache.getFirstLinkpathDest(template, ""); + if (!file) { + return "Template file not found"; + } + return ""; +} +function validateFolder(folder) { + if (!folder || folder === "/") { + return ""; + } + const { vault } = window.app; + if (!vault.getAbstractFileByPath(obsidian.normalizePath(folder))) { + return "Folder not found in vault"; + } + return ""; +} + +/* src/settings/NoteFormatSetting.svelte generated by Svelte v3.35.0 */ + +function create_if_block_1$1(ctx) { + let div; + let t0; + let strong0; + let t1; + let br; + let t2; + let strong1; + let t3; + + return { + c() { + div = element("div"); + t0 = text("New files will be created at "); + strong0 = element("strong"); + t1 = text(/*value*/ ctx[2]); + br = element("br"); + t2 = text("\n Format: "); + strong1 = element("strong"); + t3 = text(/*basename*/ ctx[7]); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, t0); + append(div, strong0); + append(strong0, t1); + append(div, br); + append(div, t2); + append(div, strong1); + append(strong1, t3); + }, + p(ctx, dirty) { + if (dirty & /*value*/ 4) set_data(t1, /*value*/ ctx[2]); + if (dirty & /*basename*/ 128) set_data(t3, /*basename*/ ctx[7]); + }, + d(detaching) { + if (detaching) detach(div); + } + }; +} + +// (56:4) {#if error} +function create_if_block$3(ctx) { + let div; + let t; + + return { + c() { + div = element("div"); + t = text(/*error*/ ctx[5]); + attr(div, "class", "has-error"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, t); + }, + p(ctx, dirty) { + if (dirty & /*error*/ 32) set_data(t, /*error*/ ctx[5]); + }, + d(detaching) { + if (detaching) detach(div); + } + }; +} + +function create_fragment$3(ctx) { + let div5; + let div3; + let div0; + let t1; + let div2; + let a; + let t3; + let div1; + let t4; + let b; + let t5_value = window.moment().format(/*value*/ ctx[2] || /*defaultFormat*/ ctx[8]) + ""; + let t5; + let t6; + let t7; + let t8; + let div4; + let input; + let mounted; + let dispose; + let if_block0 = /*isTemplateNested*/ ctx[6] && create_if_block_1$1(ctx); + let if_block1 = /*error*/ ctx[5] && create_if_block$3(ctx); + + return { + c() { + div5 = element("div"); + div3 = element("div"); + div0 = element("div"); + div0.textContent = "Format"; + t1 = space(); + div2 = element("div"); + a = element("a"); + a.textContent = "Syntax Reference"; + t3 = space(); + div1 = element("div"); + t4 = text("Your current syntax looks like this: "); + b = element("b"); + t5 = text(t5_value); + t6 = space(); + if (if_block0) if_block0.c(); + t7 = space(); + if (if_block1) if_block1.c(); + t8 = space(); + div4 = element("div"); + input = element("input"); + attr(div0, "class", "setting-item-name"); + attr(a, "href", "https://momentjs.com/docs/#/displaying/format/"); + attr(b, "class", "u-pop"); + attr(div2, "class", "setting-item-description"); + attr(div3, "class", "setting-item-info"); + attr(input, "type", "text"); + attr(input, "spellcheck", false); + attr(input, "placeholder", /*defaultFormat*/ ctx[8]); + toggle_class(input, "has-error", !!/*error*/ ctx[5]); + attr(div4, "class", "setting-item-control"); + attr(div5, "class", "setting-item"); + }, + m(target, anchor) { + insert(target, div5, anchor); + append(div5, div3); + append(div3, div0); + append(div3, t1); + append(div3, div2); + append(div2, a); + append(div2, t3); + append(div2, div1); + append(div1, t4); + append(div1, b); + append(b, t5); + append(div2, t6); + if (if_block0) if_block0.m(div2, null); + append(div3, t7); + if (if_block1) if_block1.m(div3, null); + append(div5, t8); + append(div5, div4); + append(div4, input); + set_input_value(input, /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format); + /*input_binding*/ ctx[12](input); + + if (!mounted) { + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[11]), + listen(input, "change", /*onChange*/ ctx[10]), + listen(input, "input", /*clearError*/ ctx[9]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*value*/ 4 && t5_value !== (t5_value = window.moment().format(/*value*/ ctx[2] || /*defaultFormat*/ ctx[8]) + "")) set_data(t5, t5_value); + + if (/*isTemplateNested*/ ctx[6]) { + if (if_block0) { + if_block0.p(ctx, dirty); + } else { + if_block0 = create_if_block_1$1(ctx); + if_block0.c(); + if_block0.m(div2, null); + } + } else if (if_block0) { + if_block0.d(1); + if_block0 = null; + } + + if (/*error*/ ctx[5]) { + if (if_block1) { + if_block1.p(ctx, dirty); + } else { + if_block1 = create_if_block$3(ctx); + if_block1.c(); + if_block1.m(div3, null); + } + } else if (if_block1) { + if_block1.d(1); + if_block1 = null; + } + + if (dirty & /*$settings, periodicity*/ 10 && input.value !== /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format) { + set_input_value(input, /*$settings*/ ctx[3][/*periodicity*/ ctx[1]].format); + } + + if (dirty & /*error*/ 32) { + toggle_class(input, "has-error", !!/*error*/ ctx[5]); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(div5); + if (if_block0) if_block0.d(); + if (if_block1) if_block1.d(); + /*input_binding*/ ctx[12](null); + mounted = false; + run_all(dispose); + } + }; +} + +function instance$3($$self, $$props, $$invalidate) { + let $settings, + $$unsubscribe_settings = noop, + $$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(3, $settings = $$value)), settings); + + $$self.$$.on_destroy.push(() => $$unsubscribe_settings()); + + + let { settings } = $$props; + $$subscribe_settings(); + let { periodicity } = $$props; + + const DEFAULT_FORMATS = { + daily: DEFAULT_DAILY_NOTE_FORMAT_1, + weekly: DEFAULT_WEEKLY_NOTE_FORMAT_1, + monthly: DEFAULT_MONTHLY_NOTE_FORMAT_1, + quarterly: DEFAULT_QUARTERLY_NOTE_FORMAT_1, + yearly: DEFAULT_YEARLY_NOTE_FORMAT_1 + }; + + const defaultFormat = DEFAULT_FORMATS[periodicity]; + let inputEl; + let value; + let error; + let isTemplateNested; + let basename; + + onMount(() => { + $$invalidate(5, error = validateFormat(inputEl.value, periodicity)); + }); + + function clearError() { + $$invalidate(5, error = ""); + } + + function onChange() { + $$invalidate(5, error = validateFormat(inputEl.value, periodicity)); + } + + function input_input_handler() { + $settings[periodicity].format = this.value; + settings.set($settings); + $$invalidate(1, periodicity); + } + + function input_binding($$value) { + binding_callbacks[$$value ? "unshift" : "push"](() => { + inputEl = $$value; + $$invalidate(4, inputEl); + }); + } + + $$self.$$set = $$props => { + if ("settings" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings)); + if ("periodicity" in $$props) $$invalidate(1, periodicity = $$props.periodicity); + }; + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*$settings, periodicity, value*/ 14) { + { + $$invalidate(2, value = $settings[periodicity].format || ""); + $$invalidate(6, isTemplateNested = value.indexOf("/") !== -1); + $$invalidate(7, basename = getBasename(value)); + } + } + }; + + return [ + settings, + periodicity, + value, + $settings, + inputEl, + error, + isTemplateNested, + basename, + defaultFormat, + clearError, + onChange, + input_input_handler, + input_binding + ]; +} + +class NoteFormatSetting extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance$3, create_fragment$3, safe_not_equal, { settings: 0, periodicity: 1 }); + } +} + +var top = 'top'; +var bottom = 'bottom'; +var right = 'right'; +var left = 'left'; +var auto = 'auto'; +var basePlacements = [top, bottom, right, left]; +var start = 'start'; +var end = 'end'; +var clippingParents = 'clippingParents'; +var viewport = 'viewport'; +var popper = 'popper'; +var reference = 'reference'; +var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) { + return acc.concat([placement + "-" + start, placement + "-" + end]); +}, []); +var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) { + return acc.concat([placement, placement + "-" + start, placement + "-" + end]); +}, []); // modifiers that need to read the DOM + +var beforeRead = 'beforeRead'; +var read = 'read'; +var afterRead = 'afterRead'; // pure-logic modifiers + +var beforeMain = 'beforeMain'; +var main = 'main'; +var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state) + +var beforeWrite = 'beforeWrite'; +var write = 'write'; +var afterWrite = 'afterWrite'; +var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite]; + +function getNodeName(element) { + return element ? (element.nodeName || '').toLowerCase() : null; +} + +function getWindow(node) { + if (node == null) { + return window; + } + + if (node.toString() !== '[object Window]') { + var ownerDocument = node.ownerDocument; + return ownerDocument ? ownerDocument.defaultView || window : window; + } + + return node; +} + +function isElement(node) { + var OwnElement = getWindow(node).Element; + return node instanceof OwnElement || node instanceof Element; +} + +function isHTMLElement(node) { + var OwnElement = getWindow(node).HTMLElement; + return node instanceof OwnElement || node instanceof HTMLElement; +} + +function isShadowRoot(node) { + // IE 11 has no ShadowRoot + if (typeof ShadowRoot === 'undefined') { + return false; + } + + var OwnElement = getWindow(node).ShadowRoot; + return node instanceof OwnElement || node instanceof ShadowRoot; +} + +// and applies them to the HTMLElements such as popper and arrow + +function applyStyles(_ref) { + var state = _ref.state; + Object.keys(state.elements).forEach(function (name) { + var style = state.styles[name] || {}; + var attributes = state.attributes[name] || {}; + var element = state.elements[name]; // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } // Flow doesn't support to extend this property, but it's the most + // effective way to apply styles to an HTMLElement + // $FlowFixMe[cannot-write] + + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (name) { + var value = attributes[name]; + + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value === true ? '' : value); + } + }); + }); +} + +function effect$2(_ref2) { + var state = _ref2.state; + var initialStyles = { + popper: { + position: state.options.strategy, + left: '0', + top: '0', + margin: '0' + }, + arrow: { + position: 'absolute' + }, + reference: {} + }; + Object.assign(state.elements.popper.style, initialStyles.popper); + state.styles = initialStyles; + + if (state.elements.arrow) { + Object.assign(state.elements.arrow.style, initialStyles.arrow); + } + + return function () { + Object.keys(state.elements).forEach(function (name) { + var element = state.elements[name]; + var attributes = state.attributes[name] || {}; + var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them + + var style = styleProperties.reduce(function (style, property) { + style[property] = ''; + return style; + }, {}); // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (attribute) { + element.removeAttribute(attribute); + }); + }); + }; +} // eslint-disable-next-line import/no-unused-modules + + +var applyStyles$1 = { + name: 'applyStyles', + enabled: true, + phase: 'write', + fn: applyStyles, + effect: effect$2, + requires: ['computeStyles'] +}; + +function getBasePlacement(placement) { + return placement.split('-')[0]; +} + +function getBoundingClientRect(element) { + var rect = element.getBoundingClientRect(); + return { + width: rect.width, + height: rect.height, + top: rect.top, + right: rect.right, + bottom: rect.bottom, + left: rect.left, + x: rect.left, + y: rect.top + }; +} + +// means it doesn't take into account transforms. + +function getLayoutRect(element) { + var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed. + // Fixes https://github.com/popperjs/popper-core/issues/1223 + + var width = element.offsetWidth; + var height = element.offsetHeight; + + if (Math.abs(clientRect.width - width) <= 1) { + width = clientRect.width; + } + + if (Math.abs(clientRect.height - height) <= 1) { + height = clientRect.height; + } + + return { + x: element.offsetLeft, + y: element.offsetTop, + width: width, + height: height + }; +} + +function contains(parent, child) { + var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method + + if (parent.contains(child)) { + return true; + } // then fallback to custom implementation with Shadow DOM support + else if (rootNode && isShadowRoot(rootNode)) { + var next = child; + + do { + if (next && parent.isSameNode(next)) { + return true; + } // $FlowFixMe[prop-missing]: need a better way to handle this... + + + next = next.parentNode || next.host; + } while (next); + } // Give up, the result is false + + + return false; +} + +function getComputedStyle$1(element) { + return getWindow(element).getComputedStyle(element); +} + +function isTableElement(element) { + return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0; +} + +function getDocumentElement(element) { + // $FlowFixMe[incompatible-return]: assume body is always available + return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing] + element.document) || window.document).documentElement; +} + +function getParentNode(element) { + if (getNodeName(element) === 'html') { + return element; + } + + return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle + // $FlowFixMe[incompatible-return] + // $FlowFixMe[prop-missing] + element.assignedSlot || // step into the shadow DOM of the parent of a slotted node + element.parentNode || ( // DOM Element detected + isShadowRoot(element) ? element.host : null) || // ShadowRoot detected + // $FlowFixMe[incompatible-call]: HTMLElement is a Node + getDocumentElement(element) // fallback + + ); +} + +function getTrueOffsetParent(element) { + if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837 + getComputedStyle$1(element).position === 'fixed') { + return null; + } + + return element.offsetParent; +} // `.offsetParent` reports `null` for fixed elements, while absolute elements +// return the containing block + + +function getContainingBlock(element) { + var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') !== -1; + var currentNode = getParentNode(element); + + while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) { + var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that + // create a containing block. + // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block + + if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') { + return currentNode; + } else { + currentNode = currentNode.parentNode; + } + } + + return null; +} // Gets the closest ancestor positioned element. Handles some edge cases, +// such as table ancestors and cross browser bugs. + + +function getOffsetParent(element) { + var window = getWindow(element); + var offsetParent = getTrueOffsetParent(element); + + while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') { + offsetParent = getTrueOffsetParent(offsetParent); + } + + if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) { + return window; + } + + return offsetParent || getContainingBlock(element) || window; +} + +function getMainAxisFromPlacement(placement) { + return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y'; +} + +var max = Math.max; +var min = Math.min; +var round = Math.round; + +function within(min$1, value, max$1) { + return max(min$1, min(value, max$1)); +} + +function getFreshSideObject() { + return { + top: 0, + right: 0, + bottom: 0, + left: 0 + }; +} + +function mergePaddingObject(paddingObject) { + return Object.assign({}, getFreshSideObject(), paddingObject); +} + +function expandToHashMap(value, keys) { + return keys.reduce(function (hashMap, key) { + hashMap[key] = value; + return hashMap; + }, {}); +} + +var toPaddingObject = function toPaddingObject(padding, state) { + padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, { + placement: state.placement + })) : padding; + return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); +}; + +function arrow(_ref) { + var _state$modifiersData$; + + var state = _ref.state, + name = _ref.name, + options = _ref.options; + var arrowElement = state.elements.arrow; + var popperOffsets = state.modifiersData.popperOffsets; + var basePlacement = getBasePlacement(state.placement); + var axis = getMainAxisFromPlacement(basePlacement); + var isVertical = [left, right].indexOf(basePlacement) >= 0; + var len = isVertical ? 'height' : 'width'; + + if (!arrowElement || !popperOffsets) { + return; + } + + var paddingObject = toPaddingObject(options.padding, state); + var arrowRect = getLayoutRect(arrowElement); + var minProp = axis === 'y' ? top : left; + var maxProp = axis === 'y' ? bottom : right; + var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len]; + var startDiff = popperOffsets[axis] - state.rects.reference[axis]; + var arrowOffsetParent = getOffsetParent(arrowElement); + var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0; + var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is + // outside of the popper bounds + + var min = paddingObject[minProp]; + var max = clientSize - arrowRect[len] - paddingObject[maxProp]; + var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; + var offset = within(min, center, max); // Prevents breaking syntax highlighting... + + var axisProp = axis; + state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$); +} + +function effect$1(_ref2) { + var state = _ref2.state, + options = _ref2.options; + var _options$element = options.element, + arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element; + + if (arrowElement == null) { + return; + } // CSS selector + + + if (typeof arrowElement === 'string') { + arrowElement = state.elements.popper.querySelector(arrowElement); + + if (!arrowElement) { + return; + } + } + + if (process.env.NODE_ENV !== "production") { + if (!isHTMLElement(arrowElement)) { + console.error(['Popper: "arrow" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' ')); + } + } + + if (!contains(state.elements.popper, arrowElement)) { + if (process.env.NODE_ENV !== "production") { + console.error(['Popper: "arrow" modifier\'s `element` must be a child of the popper', 'element.'].join(' ')); + } + + return; + } + + state.elements.arrow = arrowElement; +} // eslint-disable-next-line import/no-unused-modules + + +var arrow$1 = { + name: 'arrow', + enabled: true, + phase: 'main', + fn: arrow, + effect: effect$1, + requires: ['popperOffsets'], + requiresIfExists: ['preventOverflow'] +}; + +var unsetSides = { + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto' +}; // Round the offsets to the nearest suitable subpixel based on the DPR. +// Zooming can change the DPR, but it seems to report a value that will +// cleanly divide the values into the appropriate subpixels. + +function roundOffsetsByDPR(_ref) { + var x = _ref.x, + y = _ref.y; + var win = window; + var dpr = win.devicePixelRatio || 1; + return { + x: round(round(x * dpr) / dpr) || 0, + y: round(round(y * dpr) / dpr) || 0 + }; +} + +function mapToStyles(_ref2) { + var _Object$assign2; + + var popper = _ref2.popper, + popperRect = _ref2.popperRect, + placement = _ref2.placement, + offsets = _ref2.offsets, + position = _ref2.position, + gpuAcceleration = _ref2.gpuAcceleration, + adaptive = _ref2.adaptive, + roundOffsets = _ref2.roundOffsets; + + var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets, + _ref3$x = _ref3.x, + x = _ref3$x === void 0 ? 0 : _ref3$x, + _ref3$y = _ref3.y, + y = _ref3$y === void 0 ? 0 : _ref3$y; + + var hasX = offsets.hasOwnProperty('x'); + var hasY = offsets.hasOwnProperty('y'); + var sideX = left; + var sideY = top; + var win = window; + + if (adaptive) { + var offsetParent = getOffsetParent(popper); + var heightProp = 'clientHeight'; + var widthProp = 'clientWidth'; + + if (offsetParent === getWindow(popper)) { + offsetParent = getDocumentElement(popper); + + if (getComputedStyle$1(offsetParent).position !== 'static') { + heightProp = 'scrollHeight'; + widthProp = 'scrollWidth'; + } + } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it + + + offsetParent = offsetParent; + + if (placement === top) { + sideY = bottom; // $FlowFixMe[prop-missing] + + y -= offsetParent[heightProp] - popperRect.height; + y *= gpuAcceleration ? 1 : -1; + } + + if (placement === left) { + sideX = right; // $FlowFixMe[prop-missing] + + x -= offsetParent[widthProp] - popperRect.width; + x *= gpuAcceleration ? 1 : -1; + } + } + + var commonStyles = Object.assign({ + position: position + }, adaptive && unsetSides); + + if (gpuAcceleration) { + var _Object$assign; + + return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign)); + } + + return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2)); +} + +function computeStyles(_ref4) { + var state = _ref4.state, + options = _ref4.options; + var _options$gpuAccelerat = options.gpuAcceleration, + gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, + _options$adaptive = options.adaptive, + adaptive = _options$adaptive === void 0 ? true : _options$adaptive, + _options$roundOffsets = options.roundOffsets, + roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets; + + if (process.env.NODE_ENV !== "production") { + var transitionProperty = getComputedStyle$1(state.elements.popper).transitionProperty || ''; + + if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) { + return transitionProperty.indexOf(property) >= 0; + })) { + console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: "transform", "top", "right", "bottom", "left".', '\n\n', 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\n\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' ')); + } + } + + var commonStyles = { + placement: getBasePlacement(state.placement), + popper: state.elements.popper, + popperRect: state.rects.popper, + gpuAcceleration: gpuAcceleration + }; + + if (state.modifiersData.popperOffsets != null) { + state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.popperOffsets, + position: state.options.strategy, + adaptive: adaptive, + roundOffsets: roundOffsets + }))); + } + + if (state.modifiersData.arrow != null) { + state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.arrow, + position: 'absolute', + adaptive: false, + roundOffsets: roundOffsets + }))); + } + + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-placement': state.placement + }); +} // eslint-disable-next-line import/no-unused-modules + + +var computeStyles$1 = { + name: 'computeStyles', + enabled: true, + phase: 'beforeWrite', + fn: computeStyles, + data: {} +}; + +var passive = { + passive: true +}; + +function effect(_ref) { + var state = _ref.state, + instance = _ref.instance, + options = _ref.options; + var _options$scroll = options.scroll, + scroll = _options$scroll === void 0 ? true : _options$scroll, + _options$resize = options.resize, + resize = _options$resize === void 0 ? true : _options$resize; + var window = getWindow(state.elements.popper); + var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper); + + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.addEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.addEventListener('resize', instance.update, passive); + } + + return function () { + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.removeEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.removeEventListener('resize', instance.update, passive); + } + }; +} // eslint-disable-next-line import/no-unused-modules + + +var eventListeners = { + name: 'eventListeners', + enabled: true, + phase: 'write', + fn: function fn() {}, + effect: effect, + data: {} +}; + +var hash$1 = { + left: 'right', + right: 'left', + bottom: 'top', + top: 'bottom' +}; +function getOppositePlacement(placement) { + return placement.replace(/left|right|bottom|top/g, function (matched) { + return hash$1[matched]; + }); +} + +var hash = { + start: 'end', + end: 'start' +}; +function getOppositeVariationPlacement(placement) { + return placement.replace(/start|end/g, function (matched) { + return hash[matched]; + }); +} + +function getWindowScroll(node) { + var win = getWindow(node); + var scrollLeft = win.pageXOffset; + var scrollTop = win.pageYOffset; + return { + scrollLeft: scrollLeft, + scrollTop: scrollTop + }; +} + +function getWindowScrollBarX(element) { + // If has a CSS width greater than the viewport, then this will be + // incorrect for RTL. + // Popper 1 is broken in this case and never had a bug report so let's assume + // it's not an issue. I don't think anyone ever specifies width on + // anyway. + // Browsers where the left scrollbar doesn't cause an issue report `0` for + // this (e.g. Edge 2019, IE11, Safari) + return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft; +} + +function getViewportRect(element) { + var win = getWindow(element); + var html = getDocumentElement(element); + var visualViewport = win.visualViewport; + var width = html.clientWidth; + var height = html.clientHeight; + var x = 0; + var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper + // can be obscured underneath it. + // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even + // if it isn't open, so if this isn't available, the popper will be detected + // to overflow the bottom of the screen too early. + + if (visualViewport) { + width = visualViewport.width; + height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently) + // In Chrome, it returns a value very close to 0 (+/-) but contains rounding + // errors due to floating point numbers, so we need to check precision. + // Safari returns a number <= 0, usually < -1 when pinch-zoomed + // Feature detection fails in mobile emulation mode in Chrome. + // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) < + // 0.001 + // Fallback here: "Not Safari" userAgent + + if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) { + x = visualViewport.offsetLeft; + y = visualViewport.offsetTop; + } + } + + return { + width: width, + height: height, + x: x + getWindowScrollBarX(element), + y: y + }; +} + +// of the `` and `` rect bounds if horizontally scrollable + +function getDocumentRect(element) { + var _element$ownerDocumen; + + var html = getDocumentElement(element); + var winScroll = getWindowScroll(element); + var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body; + var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0); + var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0); + var x = -winScroll.scrollLeft + getWindowScrollBarX(element); + var y = -winScroll.scrollTop; + + if (getComputedStyle$1(body || html).direction === 'rtl') { + x += max(html.clientWidth, body ? body.clientWidth : 0) - width; + } + + return { + width: width, + height: height, + x: x, + y: y + }; +} + +function isScrollParent(element) { + // Firefox wants us to check `-x` and `-y` variations as well + var _getComputedStyle = getComputedStyle$1(element), + overflow = _getComputedStyle.overflow, + overflowX = _getComputedStyle.overflowX, + overflowY = _getComputedStyle.overflowY; + + return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX); +} + +function getScrollParent(node) { + if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) { + // $FlowFixMe[incompatible-return]: assume body is always available + return node.ownerDocument.body; + } + + if (isHTMLElement(node) && isScrollParent(node)) { + return node; + } + + return getScrollParent(getParentNode(node)); +} + +/* +given a DOM element, return the list of all scroll parents, up the list of ancesors +until we get to the top window object. This list is what we attach scroll listeners +to, because if any of these parent elements scroll, we'll need to re-calculate the +reference element's position. +*/ + +function listScrollParents(element, list) { + var _element$ownerDocumen; + + if (list === void 0) { + list = []; + } + + var scrollParent = getScrollParent(element); + var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body); + var win = getWindow(scrollParent); + var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent; + var updatedList = list.concat(target); + return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here + updatedList.concat(listScrollParents(getParentNode(target))); +} + +function rectToClientRect(rect) { + return Object.assign({}, rect, { + left: rect.x, + top: rect.y, + right: rect.x + rect.width, + bottom: rect.y + rect.height + }); +} + +function getInnerBoundingClientRect(element) { + var rect = getBoundingClientRect(element); + rect.top = rect.top + element.clientTop; + rect.left = rect.left + element.clientLeft; + rect.bottom = rect.top + element.clientHeight; + rect.right = rect.left + element.clientWidth; + rect.width = element.clientWidth; + rect.height = element.clientHeight; + rect.x = rect.left; + rect.y = rect.top; + return rect; +} + +function getClientRectFromMixedType(element, clippingParent) { + return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element))); +} // A "clipping parent" is an overflowable container with the characteristic of +// clipping (or hiding) overflowing elements with a position different from +// `initial` + + +function getClippingParents(element) { + var clippingParents = listScrollParents(getParentNode(element)); + var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0; + var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element; + + if (!isElement(clipperElement)) { + return []; + } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414 + + + return clippingParents.filter(function (clippingParent) { + return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body'; + }); +} // Gets the maximum area that the element is visible in due to any number of +// clipping parents + + +function getClippingRect(element, boundary, rootBoundary) { + var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary); + var clippingParents = [].concat(mainClippingParents, [rootBoundary]); + var firstClippingParent = clippingParents[0]; + var clippingRect = clippingParents.reduce(function (accRect, clippingParent) { + var rect = getClientRectFromMixedType(element, clippingParent); + accRect.top = max(rect.top, accRect.top); + accRect.right = min(rect.right, accRect.right); + accRect.bottom = min(rect.bottom, accRect.bottom); + accRect.left = max(rect.left, accRect.left); + return accRect; + }, getClientRectFromMixedType(element, firstClippingParent)); + clippingRect.width = clippingRect.right - clippingRect.left; + clippingRect.height = clippingRect.bottom - clippingRect.top; + clippingRect.x = clippingRect.left; + clippingRect.y = clippingRect.top; + return clippingRect; +} + +function getVariation(placement) { + return placement.split('-')[1]; +} + +function computeOffsets(_ref) { + var reference = _ref.reference, + element = _ref.element, + placement = _ref.placement; + var basePlacement = placement ? getBasePlacement(placement) : null; + var variation = placement ? getVariation(placement) : null; + var commonX = reference.x + reference.width / 2 - element.width / 2; + var commonY = reference.y + reference.height / 2 - element.height / 2; + var offsets; + + switch (basePlacement) { + case top: + offsets = { + x: commonX, + y: reference.y - element.height + }; + break; + + case bottom: + offsets = { + x: commonX, + y: reference.y + reference.height + }; + break; + + case right: + offsets = { + x: reference.x + reference.width, + y: commonY + }; + break; + + case left: + offsets = { + x: reference.x - element.width, + y: commonY + }; + break; + + default: + offsets = { + x: reference.x, + y: reference.y + }; + } + + var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null; + + if (mainAxis != null) { + var len = mainAxis === 'y' ? 'height' : 'width'; + + switch (variation) { + case start: + offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2); + break; + + case end: + offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2); + break; + } + } + + return offsets; +} + +function detectOverflow(state, options) { + if (options === void 0) { + options = {}; + } + + var _options = options, + _options$placement = _options.placement, + placement = _options$placement === void 0 ? state.placement : _options$placement, + _options$boundary = _options.boundary, + boundary = _options$boundary === void 0 ? clippingParents : _options$boundary, + _options$rootBoundary = _options.rootBoundary, + rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary, + _options$elementConte = _options.elementContext, + elementContext = _options$elementConte === void 0 ? popper : _options$elementConte, + _options$altBoundary = _options.altBoundary, + altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary, + _options$padding = _options.padding, + padding = _options$padding === void 0 ? 0 : _options$padding; + var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); + var altContext = elementContext === popper ? reference : popper; + var referenceElement = state.elements.reference; + var popperRect = state.rects.popper; + var element = state.elements[altBoundary ? altContext : elementContext]; + var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary); + var referenceClientRect = getBoundingClientRect(referenceElement); + var popperOffsets = computeOffsets({ + reference: referenceClientRect, + element: popperRect, + strategy: 'absolute', + placement: placement + }); + var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets)); + var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect + // 0 or negative = within the clipping rect + + var overflowOffsets = { + top: clippingClientRect.top - elementClientRect.top + paddingObject.top, + bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom, + left: clippingClientRect.left - elementClientRect.left + paddingObject.left, + right: elementClientRect.right - clippingClientRect.right + paddingObject.right + }; + var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element + + if (elementContext === popper && offsetData) { + var offset = offsetData[placement]; + Object.keys(overflowOffsets).forEach(function (key) { + var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1; + var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x'; + overflowOffsets[key] += offset[axis] * multiply; + }); + } + + return overflowOffsets; +} + +function computeAutoPlacement(state, options) { + if (options === void 0) { + options = {}; + } + + var _options = options, + placement = _options.placement, + boundary = _options.boundary, + rootBoundary = _options.rootBoundary, + padding = _options.padding, + flipVariations = _options.flipVariations, + _options$allowedAutoP = _options.allowedAutoPlacements, + allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP; + var variation = getVariation(placement); + var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) { + return getVariation(placement) === variation; + }) : basePlacements; + var allowedPlacements = placements$1.filter(function (placement) { + return allowedAutoPlacements.indexOf(placement) >= 0; + }); + + if (allowedPlacements.length === 0) { + allowedPlacements = placements$1; + + if (process.env.NODE_ENV !== "production") { + console.error(['Popper: The `allowedAutoPlacements` option did not allow any', 'placements. Ensure the `placement` option matches the variation', 'of the allowed placements.', 'For example, "auto" cannot be used to allow "bottom-start".', 'Use "auto-start" instead.'].join(' ')); + } + } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions... + + + var overflows = allowedPlacements.reduce(function (acc, placement) { + acc[placement] = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding + })[getBasePlacement(placement)]; + return acc; + }, {}); + return Object.keys(overflows).sort(function (a, b) { + return overflows[a] - overflows[b]; + }); +} + +function getExpandedFallbackPlacements(placement) { + if (getBasePlacement(placement) === auto) { + return []; + } + + var oppositePlacement = getOppositePlacement(placement); + return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)]; +} + +function flip(_ref) { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + + if (state.modifiersData[name]._skip) { + return; + } + + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, + specifiedFallbackPlacements = options.fallbackPlacements, + padding = options.padding, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + _options$flipVariatio = options.flipVariations, + flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, + allowedAutoPlacements = options.allowedAutoPlacements; + var preferredPlacement = state.options.placement; + var basePlacement = getBasePlacement(preferredPlacement); + var isBasePlacement = basePlacement === preferredPlacement; + var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)); + var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) { + return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + flipVariations: flipVariations, + allowedAutoPlacements: allowedAutoPlacements + }) : placement); + }, []); + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var checksMap = new Map(); + var makeFallbackChecks = true; + var firstFittingPlacement = placements[0]; + + for (var i = 0; i < placements.length; i++) { + var placement = placements[i]; + + var _basePlacement = getBasePlacement(placement); + + var isStartVariation = getVariation(placement) === start; + var isVertical = [top, bottom].indexOf(_basePlacement) >= 0; + var len = isVertical ? 'width' : 'height'; + var overflow = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + altBoundary: altBoundary, + padding: padding + }); + var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top; + + if (referenceRect[len] > popperRect[len]) { + mainVariationSide = getOppositePlacement(mainVariationSide); + } + + var altVariationSide = getOppositePlacement(mainVariationSide); + var checks = []; + + if (checkMainAxis) { + checks.push(overflow[_basePlacement] <= 0); + } + + if (checkAltAxis) { + checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0); + } + + if (checks.every(function (check) { + return check; + })) { + firstFittingPlacement = placement; + makeFallbackChecks = false; + break; + } + + checksMap.set(placement, checks); + } + + if (makeFallbackChecks) { + // `2` may be desired in some cases – research later + var numberOfChecks = flipVariations ? 3 : 1; + + var _loop = function _loop(_i) { + var fittingPlacement = placements.find(function (placement) { + var checks = checksMap.get(placement); + + if (checks) { + return checks.slice(0, _i).every(function (check) { + return check; + }); + } + }); + + if (fittingPlacement) { + firstFittingPlacement = fittingPlacement; + return "break"; + } + }; + + for (var _i = numberOfChecks; _i > 0; _i--) { + var _ret = _loop(_i); + + if (_ret === "break") break; + } + } + + if (state.placement !== firstFittingPlacement) { + state.modifiersData[name]._skip = true; + state.placement = firstFittingPlacement; + state.reset = true; + } +} // eslint-disable-next-line import/no-unused-modules + + +var flip$1 = { + name: 'flip', + enabled: true, + phase: 'main', + fn: flip, + requiresIfExists: ['offset'], + data: { + _skip: false + } +}; + +function getSideOffsets(overflow, rect, preventedOffsets) { + if (preventedOffsets === void 0) { + preventedOffsets = { + x: 0, + y: 0 + }; + } + + return { + top: overflow.top - rect.height - preventedOffsets.y, + right: overflow.right - rect.width + preventedOffsets.x, + bottom: overflow.bottom - rect.height + preventedOffsets.y, + left: overflow.left - rect.width - preventedOffsets.x + }; +} + +function isAnySideFullyClipped(overflow) { + return [top, right, bottom, left].some(function (side) { + return overflow[side] >= 0; + }); +} + +function hide(_ref) { + var state = _ref.state, + name = _ref.name; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var preventedOffsets = state.modifiersData.preventOverflow; + var referenceOverflow = detectOverflow(state, { + elementContext: 'reference' + }); + var popperAltOverflow = detectOverflow(state, { + altBoundary: true + }); + var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect); + var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets); + var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); + var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); + state.modifiersData[name] = { + referenceClippingOffsets: referenceClippingOffsets, + popperEscapeOffsets: popperEscapeOffsets, + isReferenceHidden: isReferenceHidden, + hasPopperEscaped: hasPopperEscaped + }; + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-reference-hidden': isReferenceHidden, + 'data-popper-escaped': hasPopperEscaped + }); +} // eslint-disable-next-line import/no-unused-modules + + +var hide$1 = { + name: 'hide', + enabled: true, + phase: 'main', + requiresIfExists: ['preventOverflow'], + fn: hide +}; + +function distanceAndSkiddingToXY(placement, rects, offset) { + var basePlacement = getBasePlacement(placement); + var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; + + var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, { + placement: placement + })) : offset, + skidding = _ref[0], + distance = _ref[1]; + + skidding = skidding || 0; + distance = (distance || 0) * invertDistance; + return [left, right].indexOf(basePlacement) >= 0 ? { + x: distance, + y: skidding + } : { + x: skidding, + y: distance + }; +} + +function offset(_ref2) { + var state = _ref2.state, + options = _ref2.options, + name = _ref2.name; + var _options$offset = options.offset, + offset = _options$offset === void 0 ? [0, 0] : _options$offset; + var data = placements.reduce(function (acc, placement) { + acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); + return acc; + }, {}); + var _data$state$placement = data[state.placement], + x = _data$state$placement.x, + y = _data$state$placement.y; + + if (state.modifiersData.popperOffsets != null) { + state.modifiersData.popperOffsets.x += x; + state.modifiersData.popperOffsets.y += y; + } + + state.modifiersData[name] = data; +} // eslint-disable-next-line import/no-unused-modules + + +var offset$1 = { + name: 'offset', + enabled: true, + phase: 'main', + requires: ['popperOffsets'], + fn: offset +}; + +function popperOffsets(_ref) { + var state = _ref.state, + name = _ref.name; + // Offsets are the actual position the popper needs to have to be + // properly positioned near its reference element + // This is the most basic placement, and will be adjusted by + // the modifiers in the next step + state.modifiersData[name] = computeOffsets({ + reference: state.rects.reference, + element: state.rects.popper, + strategy: 'absolute', + placement: state.placement + }); +} // eslint-disable-next-line import/no-unused-modules + + +var popperOffsets$1 = { + name: 'popperOffsets', + enabled: true, + phase: 'read', + fn: popperOffsets, + data: {} +}; + +function getAltAxis(axis) { + return axis === 'x' ? 'y' : 'x'; +} + +function preventOverflow(_ref) { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + padding = options.padding, + _options$tether = options.tether, + tether = _options$tether === void 0 ? true : _options$tether, + _options$tetherOffset = options.tetherOffset, + tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset; + var overflow = detectOverflow(state, { + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + altBoundary: altBoundary + }); + var basePlacement = getBasePlacement(state.placement); + var variation = getVariation(state.placement); + var isBasePlacement = !variation; + var mainAxis = getMainAxisFromPlacement(basePlacement); + var altAxis = getAltAxis(mainAxis); + var popperOffsets = state.modifiersData.popperOffsets; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, { + placement: state.placement + })) : tetherOffset; + var data = { + x: 0, + y: 0 + }; + + if (!popperOffsets) { + return; + } + + if (checkMainAxis || checkAltAxis) { + var mainSide = mainAxis === 'y' ? top : left; + var altSide = mainAxis === 'y' ? bottom : right; + var len = mainAxis === 'y' ? 'height' : 'width'; + var offset = popperOffsets[mainAxis]; + var min$1 = popperOffsets[mainAxis] + overflow[mainSide]; + var max$1 = popperOffsets[mainAxis] - overflow[altSide]; + var additive = tether ? -popperRect[len] / 2 : 0; + var minLen = variation === start ? referenceRect[len] : popperRect[len]; + var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go + // outside the reference bounds + + var arrowElement = state.elements.arrow; + var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : { + width: 0, + height: 0 + }; + var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject(); + var arrowPaddingMin = arrowPaddingObject[mainSide]; + var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want + // to include its full size in the calculation. If the reference is small + // and near the edge of a boundary, the popper can overflow even if the + // reference is not overflowing as well (e.g. virtual elements with no + // width or height) + + var arrowLen = within(0, referenceRect[len], arrowRect[len]); + var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue; + var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue; + var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); + var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; + var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0; + var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset; + var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue; + + if (checkMainAxis) { + var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1); + popperOffsets[mainAxis] = preventedOffset; + data[mainAxis] = preventedOffset - offset; + } + + if (checkAltAxis) { + var _mainSide = mainAxis === 'x' ? top : left; + + var _altSide = mainAxis === 'x' ? bottom : right; + + var _offset = popperOffsets[altAxis]; + + var _min = _offset + overflow[_mainSide]; + + var _max = _offset - overflow[_altSide]; + + var _preventedOffset = within(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _max); + + popperOffsets[altAxis] = _preventedOffset; + data[altAxis] = _preventedOffset - _offset; + } + } + + state.modifiersData[name] = data; +} // eslint-disable-next-line import/no-unused-modules + + +var preventOverflow$1 = { + name: 'preventOverflow', + enabled: true, + phase: 'main', + fn: preventOverflow, + requiresIfExists: ['offset'] +}; + +function getHTMLElementScroll(element) { + return { + scrollLeft: element.scrollLeft, + scrollTop: element.scrollTop + }; +} + +function getNodeScroll(node) { + if (node === getWindow(node) || !isHTMLElement(node)) { + return getWindowScroll(node); + } else { + return getHTMLElementScroll(node); + } +} + +// Composite means it takes into account transforms as well as layout. + +function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) { + if (isFixed === void 0) { + isFixed = false; + } + + var documentElement = getDocumentElement(offsetParent); + var rect = getBoundingClientRect(elementOrVirtualElement); + var isOffsetParentAnElement = isHTMLElement(offsetParent); + var scroll = { + scrollLeft: 0, + scrollTop: 0 + }; + var offsets = { + x: 0, + y: 0 + }; + + if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) { + if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078 + isScrollParent(documentElement)) { + scroll = getNodeScroll(offsetParent); + } + + if (isHTMLElement(offsetParent)) { + offsets = getBoundingClientRect(offsetParent); + offsets.x += offsetParent.clientLeft; + offsets.y += offsetParent.clientTop; + } else if (documentElement) { + offsets.x = getWindowScrollBarX(documentElement); + } + } + + return { + x: rect.left + scroll.scrollLeft - offsets.x, + y: rect.top + scroll.scrollTop - offsets.y, + width: rect.width, + height: rect.height + }; +} + +function order(modifiers) { + var map = new Map(); + var visited = new Set(); + var result = []; + modifiers.forEach(function (modifier) { + map.set(modifier.name, modifier); + }); // On visiting object, check for its dependencies and visit them recursively + + function sort(modifier) { + visited.add(modifier.name); + var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []); + requires.forEach(function (dep) { + if (!visited.has(dep)) { + var depModifier = map.get(dep); + + if (depModifier) { + sort(depModifier); + } + } + }); + result.push(modifier); + } + + modifiers.forEach(function (modifier) { + if (!visited.has(modifier.name)) { + // check for visited object + sort(modifier); + } + }); + return result; +} + +function orderModifiers(modifiers) { + // order based on dependencies + var orderedModifiers = order(modifiers); // order based on phase + + return modifierPhases.reduce(function (acc, phase) { + return acc.concat(orderedModifiers.filter(function (modifier) { + return modifier.phase === phase; + })); + }, []); +} + +function debounce(fn) { + var pending; + return function () { + if (!pending) { + pending = new Promise(function (resolve) { + Promise.resolve().then(function () { + pending = undefined; + resolve(fn()); + }); + }); + } + + return pending; + }; +} + +function format(str) { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + return [].concat(args).reduce(function (p, c) { + return p.replace(/%s/, c); + }, str); +} + +var INVALID_MODIFIER_ERROR = 'Popper: modifier "%s" provided an invalid %s property, expected %s but got %s'; +var MISSING_DEPENDENCY_ERROR = 'Popper: modifier "%s" requires "%s", but "%s" modifier is not available'; +var VALID_PROPERTIES = ['name', 'enabled', 'phase', 'fn', 'effect', 'requires', 'options']; +function validateModifiers(modifiers) { + modifiers.forEach(function (modifier) { + Object.keys(modifier).forEach(function (key) { + switch (key) { + case 'name': + if (typeof modifier.name !== 'string') { + console.error(format(INVALID_MODIFIER_ERROR, String(modifier.name), '"name"', '"string"', "\"" + String(modifier.name) + "\"")); + } + + break; + + case 'enabled': + if (typeof modifier.enabled !== 'boolean') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"enabled"', '"boolean"', "\"" + String(modifier.enabled) + "\"")); + } + + case 'phase': + if (modifierPhases.indexOf(modifier.phase) < 0) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"phase"', "either " + modifierPhases.join(', '), "\"" + String(modifier.phase) + "\"")); + } + + break; + + case 'fn': + if (typeof modifier.fn !== 'function') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"fn"', '"function"', "\"" + String(modifier.fn) + "\"")); + } + + break; + + case 'effect': + if (typeof modifier.effect !== 'function') { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"effect"', '"function"', "\"" + String(modifier.fn) + "\"")); + } + + break; + + case 'requires': + if (!Array.isArray(modifier.requires)) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requires"', '"array"', "\"" + String(modifier.requires) + "\"")); + } + + break; + + case 'requiresIfExists': + if (!Array.isArray(modifier.requiresIfExists)) { + console.error(format(INVALID_MODIFIER_ERROR, modifier.name, '"requiresIfExists"', '"array"', "\"" + String(modifier.requiresIfExists) + "\"")); + } + + break; + + case 'options': + case 'data': + break; + + default: + console.error("PopperJS: an invalid property has been provided to the \"" + modifier.name + "\" modifier, valid properties are " + VALID_PROPERTIES.map(function (s) { + return "\"" + s + "\""; + }).join(', ') + "; but \"" + key + "\" was provided."); + } + + modifier.requires && modifier.requires.forEach(function (requirement) { + if (modifiers.find(function (mod) { + return mod.name === requirement; + }) == null) { + console.error(format(MISSING_DEPENDENCY_ERROR, String(modifier.name), requirement, requirement)); + } + }); + }); + }); +} + +function uniqueBy(arr, fn) { + var identifiers = new Set(); + return arr.filter(function (item) { + var identifier = fn(item); + + if (!identifiers.has(identifier)) { + identifiers.add(identifier); + return true; + } + }); +} + +function mergeByName(modifiers) { + var merged = modifiers.reduce(function (merged, current) { + var existing = merged[current.name]; + merged[current.name] = existing ? Object.assign({}, existing, current, { + options: Object.assign({}, existing.options, current.options), + data: Object.assign({}, existing.data, current.data) + }) : current; + return merged; + }, {}); // IE11 does not support Object.values + + return Object.keys(merged).map(function (key) { + return merged[key]; + }); +} + +var INVALID_ELEMENT_ERROR = 'Popper: Invalid reference or popper argument provided. They must be either a DOM element or virtual element.'; +var INFINITE_LOOP_ERROR = 'Popper: An infinite loop in the modifiers cycle has been detected! The cycle has been interrupted to prevent a browser crash.'; +var DEFAULT_OPTIONS = { + placement: 'bottom', + modifiers: [], + strategy: 'absolute' +}; + +function areValidElements() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return !args.some(function (element) { + return !(element && typeof element.getBoundingClientRect === 'function'); + }); +} + +function popperGenerator(generatorOptions) { + if (generatorOptions === void 0) { + generatorOptions = {}; + } + + var _generatorOptions = generatorOptions, + _generatorOptions$def = _generatorOptions.defaultModifiers, + defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def, + _generatorOptions$def2 = _generatorOptions.defaultOptions, + defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2; + return function createPopper(reference, popper, options) { + if (options === void 0) { + options = defaultOptions; + } + + var state = { + placement: 'bottom', + orderedModifiers: [], + options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions), + modifiersData: {}, + elements: { + reference: reference, + popper: popper + }, + attributes: {}, + styles: {} + }; + var effectCleanupFns = []; + var isDestroyed = false; + var instance = { + state: state, + setOptions: function setOptions(options) { + cleanupModifierEffects(); + state.options = Object.assign({}, defaultOptions, state.options, options); + state.scrollParents = { + reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [], + popper: listScrollParents(popper) + }; // Orders the modifiers based on their dependencies and `phase` + // properties + + var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers + + state.orderedModifiers = orderedModifiers.filter(function (m) { + return m.enabled; + }); // Validate the provided modifiers so that the consumer will get warned + // if one of the modifiers is invalid for any reason + + if (process.env.NODE_ENV !== "production") { + var modifiers = uniqueBy([].concat(orderedModifiers, state.options.modifiers), function (_ref) { + var name = _ref.name; + return name; + }); + validateModifiers(modifiers); + + if (getBasePlacement(state.options.placement) === auto) { + var flipModifier = state.orderedModifiers.find(function (_ref2) { + var name = _ref2.name; + return name === 'flip'; + }); + + if (!flipModifier) { + console.error(['Popper: "auto" placements require the "flip" modifier be', 'present and enabled to work.'].join(' ')); + } + } + + var _getComputedStyle = getComputedStyle$1(popper), + marginTop = _getComputedStyle.marginTop, + marginRight = _getComputedStyle.marginRight, + marginBottom = _getComputedStyle.marginBottom, + marginLeft = _getComputedStyle.marginLeft; // We no longer take into account `margins` on the popper, and it can + // cause bugs with positioning, so we'll warn the consumer + + + if ([marginTop, marginRight, marginBottom, marginLeft].some(function (margin) { + return parseFloat(margin); + })) { + console.warn(['Popper: CSS "margin" styles cannot be used to apply padding', 'between the popper and its reference element or boundary.', 'To replicate margin, use the `offset` modifier, as well as', 'the `padding` option in the `preventOverflow` and `flip`', 'modifiers.'].join(' ')); + } + } + + runModifierEffects(); + return instance.update(); + }, + // Sync update – it will always be executed, even if not necessary. This + // is useful for low frequency updates where sync behavior simplifies the + // logic. + // For high frequency updates (e.g. `resize` and `scroll` events), always + // prefer the async Popper#update method + forceUpdate: function forceUpdate() { + if (isDestroyed) { + return; + } + + var _state$elements = state.elements, + reference = _state$elements.reference, + popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements + // anymore + + if (!areValidElements(reference, popper)) { + if (process.env.NODE_ENV !== "production") { + console.error(INVALID_ELEMENT_ERROR); + } + + return; + } // Store the reference and popper rects to be read by modifiers + + + state.rects = { + reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'), + popper: getLayoutRect(popper) + }; // Modifiers have the ability to reset the current update cycle. The + // most common use case for this is the `flip` modifier changing the + // placement, which then needs to re-run all the modifiers, because the + // logic was previously ran for the previous placement and is therefore + // stale/incorrect + + state.reset = false; + state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier + // is filled with the initial data specified by the modifier. This means + // it doesn't persist and is fresh on each update. + // To ensure persistent data, use `${name}#persistent` + + state.orderedModifiers.forEach(function (modifier) { + return state.modifiersData[modifier.name] = Object.assign({}, modifier.data); + }); + var __debug_loops__ = 0; + + for (var index = 0; index < state.orderedModifiers.length; index++) { + if (process.env.NODE_ENV !== "production") { + __debug_loops__ += 1; + + if (__debug_loops__ > 100) { + console.error(INFINITE_LOOP_ERROR); + break; + } + } + + if (state.reset === true) { + state.reset = false; + index = -1; + continue; + } + + var _state$orderedModifie = state.orderedModifiers[index], + fn = _state$orderedModifie.fn, + _state$orderedModifie2 = _state$orderedModifie.options, + _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2, + name = _state$orderedModifie.name; + + if (typeof fn === 'function') { + state = fn({ + state: state, + options: _options, + name: name, + instance: instance + }) || state; + } + } + }, + // Async and optimistically optimized update – it will not be executed if + // not necessary (debounced to run at most once-per-tick) + update: debounce(function () { + return new Promise(function (resolve) { + instance.forceUpdate(); + resolve(state); + }); + }), + destroy: function destroy() { + cleanupModifierEffects(); + isDestroyed = true; + } + }; + + if (!areValidElements(reference, popper)) { + if (process.env.NODE_ENV !== "production") { + console.error(INVALID_ELEMENT_ERROR); + } + + return instance; + } + + instance.setOptions(options).then(function (state) { + if (!isDestroyed && options.onFirstUpdate) { + options.onFirstUpdate(state); + } + }); // Modifiers have the ability to execute arbitrary code before the first + // update cycle runs. They will be executed in the same order as the update + // cycle. This is useful when a modifier adds some persistent data that + // other modifiers need to use, but the modifier is run after the dependent + // one. + + function runModifierEffects() { + state.orderedModifiers.forEach(function (_ref3) { + var name = _ref3.name, + _ref3$options = _ref3.options, + options = _ref3$options === void 0 ? {} : _ref3$options, + effect = _ref3.effect; + + if (typeof effect === 'function') { + var cleanupFn = effect({ + state: state, + name: name, + instance: instance, + options: options + }); + + var noopFn = function noopFn() {}; + + effectCleanupFns.push(cleanupFn || noopFn); + } + }); + } + + function cleanupModifierEffects() { + effectCleanupFns.forEach(function (fn) { + return fn(); + }); + effectCleanupFns = []; + } + + return instance; + }; +} + +var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1]; +var createPopper = /*#__PURE__*/popperGenerator({ + defaultModifiers: defaultModifiers +}); // eslint-disable-next-line import/no-unused-modules + +class Suggest { + constructor(owner, containerEl, scope) { + this.owner = owner; + this.containerEl = containerEl; + containerEl.on("click", ".suggestion-item", this.onSuggestionClick.bind(this)); + containerEl.on("mousemove", ".suggestion-item", this.onSuggestionMouseover.bind(this)); + scope.register([], "ArrowUp", (event) => { + if (!event.isComposing) { + this.setSelectedItem(this.selectedItem - 1, true); + return false; + } + }); + scope.register([], "ArrowDown", (event) => { + if (!event.isComposing) { + this.setSelectedItem(this.selectedItem + 1, true); + return false; + } + }); + scope.register([], "Enter", (event) => { + if (!event.isComposing) { + this.useSelectedItem(event); + return false; + } + }); + } + onSuggestionClick(event, el) { + event.preventDefault(); + const item = this.suggestions.indexOf(el); + this.setSelectedItem(item, false); + this.useSelectedItem(event); + } + onSuggestionMouseover(_event, el) { + const item = this.suggestions.indexOf(el); + this.setSelectedItem(item, false); + } + setSuggestions(values) { + this.containerEl.empty(); + const suggestionEls = []; + values.forEach((value) => { + const suggestionEl = this.containerEl.createDiv("suggestion-item"); + this.owner.renderSuggestion(value, suggestionEl); + suggestionEls.push(suggestionEl); + }); + this.values = values; + this.suggestions = suggestionEls; + this.setSelectedItem(0, false); + } + useSelectedItem(event) { + const currentValue = this.values[this.selectedItem]; + if (currentValue) { + this.owner.selectSuggestion(currentValue, event); + } + } + setSelectedItem(selectedIndex, scrollIntoView) { + const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length); + const prevSelectedSuggestion = this.suggestions[this.selectedItem]; + const selectedSuggestion = this.suggestions[normalizedIndex]; + prevSelectedSuggestion === null || prevSelectedSuggestion === void 0 ? void 0 : prevSelectedSuggestion.removeClass("is-selected"); + selectedSuggestion === null || selectedSuggestion === void 0 ? void 0 : selectedSuggestion.addClass("is-selected"); + this.selectedItem = normalizedIndex; + if (scrollIntoView) { + selectedSuggestion.scrollIntoView(false); + } + } +} +class TextInputSuggest { + constructor(app, inputEl) { + this.app = app; + this.inputEl = inputEl; + this.scope = new obsidian.Scope(); + this.suggestEl = createDiv("suggestion-container"); + const suggestion = this.suggestEl.createDiv("suggestion"); + this.suggest = new Suggest(this, suggestion, this.scope); + this.scope.register([], "Escape", this.close.bind(this)); + this.inputEl.addEventListener("input", this.onInputChanged.bind(this)); + this.inputEl.addEventListener("focus", this.onInputChanged.bind(this)); + this.inputEl.addEventListener("blur", this.close.bind(this)); + this.suggestEl.on("mousedown", ".suggestion-container", (event) => { + event.preventDefault(); + }); + } + onInputChanged() { + const inputStr = this.inputEl.value; + const suggestions = this.getSuggestions(inputStr); + if (suggestions.length > 0) { + this.suggest.setSuggestions(suggestions); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.open(this.app.dom.appContainerEl, this.inputEl); + } + } + open(container, inputEl) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.app.keymap.pushScope(this.scope); + container.appendChild(this.suggestEl); + this.popper = createPopper(inputEl, this.suggestEl, { + placement: "bottom-start", + modifiers: [ + { + name: "sameWidth", + enabled: true, + fn: ({ state, instance }) => { + // Note: positioning needs to be calculated twice - + // first pass - positioning it according to the width of the popper + // second pass - position it with the width bound to the reference element + // we need to early exit to avoid an infinite loop + const targetWidth = `${state.rects.reference.width}px`; + if (state.styles.popper.width === targetWidth) { + return; + } + state.styles.popper.width = targetWidth; + instance.update(); + }, + phase: "beforeWrite", + requires: ["computeStyles"], + }, + ], + }); + } + close() { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.app.keymap.popScope(this.scope); + this.suggest.setSuggestions([]); + this.popper.destroy(); + this.suggestEl.detach(); + } +} + +class FileSuggest extends TextInputSuggest { + getSuggestions(inputStr) { + const abstractFiles = this.app.vault.getAllLoadedFiles(); + const files = []; + const lowerCaseInputStr = inputStr.toLowerCase(); + abstractFiles.forEach((file) => { + if (file instanceof obsidian.TFile && + file.extension === "md" && + file.path.toLowerCase().contains(lowerCaseInputStr)) { + files.push(file); + } + }); + return files; + } + renderSuggestion(file, el) { + el.setText(file.path); + } + selectSuggestion(file) { + this.inputEl.value = file.path; + this.inputEl.trigger("input"); + this.close(); + } +} +class FolderSuggest extends TextInputSuggest { + getSuggestions(inputStr) { + const abstractFiles = this.app.vault.getAllLoadedFiles(); + const folders = []; + const lowerCaseInputStr = inputStr.toLowerCase(); + abstractFiles.forEach((folder) => { + if (folder instanceof obsidian.TFolder && + folder.path.toLowerCase().contains(lowerCaseInputStr)) { + folders.push(folder); + } + }); + return folders; + } + renderSuggestion(file, el) { + el.setText(file.path); + } + selectSuggestion(file) { + this.inputEl.value = file.path; + this.inputEl.trigger("input"); + this.close(); + } +} + +/* src/settings/NoteTemplateSetting.svelte generated by Svelte v3.35.0 */ + +function create_if_block$2(ctx) { + let div; + let t; + + return { + c() { + div = element("div"); + t = text(/*error*/ ctx[3]); + attr(div, "class", "has-error"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, t); + }, + p(ctx, dirty) { + if (dirty & /*error*/ 8) set_data(t, /*error*/ ctx[3]); + }, + d(detaching) { + if (detaching) detach(div); + } + }; +} + +function create_fragment$2(ctx) { + let div4; + let div2; + let div0; + let t0_value = capitalize(/*periodicity*/ ctx[1]) + ""; + let t0; + let t1; + let t2; + let div1; + let t4; + let t5; + let div3; + let input; + let mounted; + let dispose; + let if_block = /*error*/ ctx[3] && create_if_block$2(ctx); + + return { + c() { + div4 = element("div"); + div2 = element("div"); + div0 = element("div"); + t0 = text(t0_value); + t1 = text(" Note Template"); + t2 = space(); + div1 = element("div"); + div1.textContent = "Choose the file to use as a template"; + t4 = space(); + if (if_block) if_block.c(); + t5 = space(); + div3 = element("div"); + input = element("input"); + attr(div0, "class", "setting-item-name"); + attr(div1, "class", "setting-item-description"); + attr(div2, "class", "setting-item-info"); + attr(input, "type", "text"); + attr(input, "spellcheck", false); + attr(input, "placeholder", "Example: folder/note"); + toggle_class(input, "has-error", !!/*error*/ ctx[3]); + attr(div3, "class", "setting-item-control"); + attr(div4, "class", "setting-item"); + }, + m(target, anchor) { + insert(target, div4, anchor); + append(div4, div2); + append(div2, div0); + append(div0, t0); + append(div0, t1); + append(div2, t2); + append(div2, div1); + append(div2, t4); + if (if_block) if_block.m(div2, null); + append(div4, t5); + append(div4, div3); + append(div3, input); + /*input_binding*/ ctx[7](input); + set_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template); + + if (!mounted) { + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[8]), + listen(input, "change", /*validateOnBlur*/ ctx[5]), + listen(input, "input", /*clearError*/ ctx[6]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*periodicity*/ 2 && t0_value !== (t0_value = capitalize(/*periodicity*/ ctx[1]) + "")) set_data(t0, t0_value); + + if (/*error*/ ctx[3]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$2(ctx); + if_block.c(); + if_block.m(div2, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + + if (dirty & /*$settings, periodicity*/ 6 && input.value !== /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template) { + set_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].template); + } + + if (dirty & /*error*/ 8) { + toggle_class(input, "has-error", !!/*error*/ ctx[3]); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(div4); + if (if_block) if_block.d(); + /*input_binding*/ ctx[7](null); + mounted = false; + run_all(dispose); + } + }; +} + +function instance$2($$self, $$props, $$invalidate) { + let $settings, + $$unsubscribe_settings = noop, + $$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(2, $settings = $$value)), settings); + + $$self.$$.on_destroy.push(() => $$unsubscribe_settings()); + + + let { settings } = $$props; + $$subscribe_settings(); + let { periodicity } = $$props; + let error; + let inputEl; + + function validateOnBlur() { + $$invalidate(3, error = validateTemplate(inputEl.value)); + } + + function clearError() { + $$invalidate(3, error = ""); + } + + onMount(() => { + $$invalidate(3, error = validateTemplate(inputEl.value)); + new FileSuggest(window.app, inputEl); + }); + + function input_binding($$value) { + binding_callbacks[$$value ? "unshift" : "push"](() => { + inputEl = $$value; + $$invalidate(4, inputEl); + }); + } + + function input_input_handler() { + $settings[periodicity].template = this.value; + settings.set($settings); + $$invalidate(1, periodicity); + } + + $$self.$$set = $$props => { + if ("settings" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings)); + if ("periodicity" in $$props) $$invalidate(1, periodicity = $$props.periodicity); + }; + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*$settings, periodicity*/ 6) { + $settings[periodicity].template || ""; + } + }; + + return [ + settings, + periodicity, + $settings, + error, + inputEl, + validateOnBlur, + clearError, + input_binding, + input_input_handler + ]; +} + +class NoteTemplateSetting extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance$2, create_fragment$2, safe_not_equal, { settings: 0, periodicity: 1 }); + } +} + +/* src/settings/NoteFolderSetting.svelte generated by Svelte v3.35.0 */ + +function create_if_block$1(ctx) { + let div; + let t; + + return { + c() { + div = element("div"); + t = text(/*error*/ ctx[4]); + attr(div, "class", "has-error"); + }, + m(target, anchor) { + insert(target, div, anchor); + append(div, t); + }, + p(ctx, dirty) { + if (dirty & /*error*/ 16) set_data(t, /*error*/ ctx[4]); + }, + d(detaching) { + if (detaching) detach(div); + } + }; +} + +function create_fragment$1(ctx) { + let div4; + let div2; + let div0; + let t1; + let div1; + let t2; + let t3; + let t4; + let t5; + let t6; + let div3; + let input; + let mounted; + let dispose; + let if_block = /*error*/ ctx[4] && create_if_block$1(ctx); + + return { + c() { + div4 = element("div"); + div2 = element("div"); + div0 = element("div"); + div0.textContent = "Note Folder"; + t1 = space(); + div1 = element("div"); + t2 = text("New "); + t3 = text(/*periodicity*/ ctx[1]); + t4 = text(" notes will be placed here"); + t5 = space(); + if (if_block) if_block.c(); + t6 = space(); + div3 = element("div"); + input = element("input"); + attr(div0, "class", "setting-item-name"); + attr(div1, "class", "setting-item-description"); + attr(div2, "class", "setting-item-info"); + attr(input, "type", "text"); + attr(input, "spellcheck", false); + attr(input, "placeholder", "Example: folder 1/folder 2"); + toggle_class(input, "has-error", !!/*error*/ ctx[4]); + attr(div3, "class", "setting-item-control"); + attr(div4, "class", "setting-item"); + }, + m(target, anchor) { + insert(target, div4, anchor); + append(div4, div2); + append(div2, div0); + append(div2, t1); + append(div2, div1); + append(div1, t2); + append(div1, t3); + append(div1, t4); + append(div2, t5); + if (if_block) if_block.m(div2, null); + append(div4, t6); + append(div4, div3); + append(div3, input); + set_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder); + /*input_binding*/ ctx[8](input); + + if (!mounted) { + dispose = [ + listen(input, "input", /*input_input_handler*/ ctx[7]), + listen(input, "change", /*onChange*/ ctx[5]), + listen(input, "input", /*clearError*/ ctx[6]) + ]; + + mounted = true; + } + }, + p(ctx, [dirty]) { + if (dirty & /*periodicity*/ 2) set_data(t3, /*periodicity*/ ctx[1]); + + if (/*error*/ ctx[4]) { + if (if_block) { + if_block.p(ctx, dirty); + } else { + if_block = create_if_block$1(ctx); + if_block.c(); + if_block.m(div2, null); + } + } else if (if_block) { + if_block.d(1); + if_block = null; + } + + if (dirty & /*$settings, periodicity*/ 6 && input.value !== /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder) { + set_input_value(input, /*$settings*/ ctx[2][/*periodicity*/ ctx[1]].folder); + } + + if (dirty & /*error*/ 16) { + toggle_class(input, "has-error", !!/*error*/ ctx[4]); + } + }, + i: noop, + o: noop, + d(detaching) { + if (detaching) detach(div4); + if (if_block) if_block.d(); + /*input_binding*/ ctx[8](null); + mounted = false; + run_all(dispose); + } + }; +} + +function instance$1($$self, $$props, $$invalidate) { + let $settings, + $$unsubscribe_settings = noop, + $$subscribe_settings = () => ($$unsubscribe_settings(), $$unsubscribe_settings = subscribe(settings, $$value => $$invalidate(2, $settings = $$value)), settings); + + $$self.$$.on_destroy.push(() => $$unsubscribe_settings()); + + + let { settings } = $$props; + $$subscribe_settings(); + let { periodicity } = $$props; + let inputEl; + let error; + + function onChange() { + $$invalidate(4, error = validateFolder(inputEl.value)); + } + + function clearError() { + $$invalidate(4, error = ""); + } + + onMount(() => { + $$invalidate(4, error = validateFolder(inputEl.value)); + new FolderSuggest(window.app, inputEl); + }); + + function input_input_handler() { + $settings[periodicity].folder = this.value; + settings.set($settings); + $$invalidate(1, periodicity); + } + + function input_binding($$value) { + binding_callbacks[$$value ? "unshift" : "push"](() => { + inputEl = $$value; + $$invalidate(3, inputEl); + }); + } + + $$self.$$set = $$props => { + if ("settings" in $$props) $$subscribe_settings($$invalidate(0, settings = $$props.settings)); + if ("periodicity" in $$props) $$invalidate(1, periodicity = $$props.periodicity); + }; + + $$self.$$.update = () => { + if ($$self.$$.dirty & /*$settings, periodicity*/ 6) { + $settings[periodicity].folder || ""; + } + }; + + return [ + settings, + periodicity, + $settings, + inputEl, + error, + onChange, + clearError, + input_input_handler, + input_binding + ]; +} + +class NoteFolderSetting extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance$1, create_fragment$1, safe_not_equal, { settings: 0, periodicity: 1 }); + } +} + +/* src/settings/SettingsTab.svelte generated by Svelte v3.35.0 */ + +function get_each_context(ctx, list, i) { + const child_ctx = ctx.slice(); + child_ctx[9] = list[i]; + return child_ctx; +} + +// (33:0) {#if $settingsStore.showGettingStartedBanner} +function create_if_block_1(ctx) { + let gettingstartedbanner; + let current; + + gettingstartedbanner = new GettingStartedBanner({ + props: { + migrateDailyNoteSettings: /*migrateDailyNoteSettings*/ ctx[2], + settings: /*settingsStore*/ ctx[1], + handleTeardown: /*func*/ ctx[6] + } + }); + + return { + c() { + create_component(gettingstartedbanner.$$.fragment); + }, + m(target, anchor) { + mount_component(gettingstartedbanner, target, anchor); + current = true; + }, + p(ctx, dirty) { + const gettingstartedbanner_changes = {}; + if (dirty & /*$settingsStore*/ 1) gettingstartedbanner_changes.handleTeardown = /*func*/ ctx[6]; + gettingstartedbanner.$set(gettingstartedbanner_changes); + }, + i(local) { + if (current) return; + transition_in(gettingstartedbanner.$$.fragment, local); + current = true; + }, + o(local) { + transition_out(gettingstartedbanner.$$.fragment, local); + current = false; + }, + d(detaching) { + destroy_component(gettingstartedbanner, detaching); + } + }; +} + +// (62:2) {#if $settingsStore[periodicity].enabled} +function create_if_block(ctx) { + let div; + let noteformatsetting; + let t0; + let notetemplatesetting; + let t1; + let notefoldersetting; + let t2; + let div_intro; + let div_outro; + let current; + + noteformatsetting = new NoteFormatSetting({ + props: { + periodicity: /*periodicity*/ ctx[9], + settings: /*settingsStore*/ ctx[1] + } + }); + + notetemplatesetting = new NoteTemplateSetting({ + props: { + periodicity: /*periodicity*/ ctx[9], + settings: /*settingsStore*/ ctx[1] + } + }); + + notefoldersetting = new NoteFolderSetting({ + props: { + periodicity: /*periodicity*/ ctx[9], + settings: /*settingsStore*/ ctx[1] + } + }); + + return { + c() { + div = element("div"); + create_component(noteformatsetting.$$.fragment); + t0 = space(); + create_component(notetemplatesetting.$$.fragment); + t1 = space(); + create_component(notefoldersetting.$$.fragment); + t2 = space(); + }, + m(target, anchor) { + insert(target, div, anchor); + mount_component(noteformatsetting, div, null); + append(div, t0); + mount_component(notetemplatesetting, div, null); + append(div, t1); + mount_component(notefoldersetting, div, null); + append(div, t2); + current = true; + }, + p: noop, + i(local) { + if (current) return; + transition_in(noteformatsetting.$$.fragment, local); + transition_in(notetemplatesetting.$$.fragment, local); + transition_in(notefoldersetting.$$.fragment, local); + + add_render_callback(() => { + if (div_outro) div_outro.end(1); + if (!div_intro) div_intro = create_in_transition(div, slide, {}); + div_intro.start(); + }); + + current = true; + }, + o(local) { + transition_out(noteformatsetting.$$.fragment, local); + transition_out(notetemplatesetting.$$.fragment, local); + transition_out(notefoldersetting.$$.fragment, local); + if (div_intro) div_intro.invalidate(); + div_outro = create_out_transition(div, slide, {}); + current = false; + }, + d(detaching) { + if (detaching) detach(div); + destroy_component(noteformatsetting); + destroy_component(notetemplatesetting); + destroy_component(notefoldersetting); + if (detaching && div_outro) div_outro.end(); + } + }; +} + +// (42:0) {#each periodicities as periodicity} +function create_each_block(ctx) { + let div4; + let div1; + let div0; + let h3; + let t0_value = capitalize(/*periodicity*/ ctx[9]) + ""; + let t0; + let t1; + let t2; + let div3; + let div2; + let t3; + let if_block_anchor; + let current; + let mounted; + let dispose; + + function click_handler() { + return /*click_handler*/ ctx[7](/*periodicity*/ ctx[9]); + } + + let if_block = /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled && create_if_block(ctx); + + return { + c() { + div4 = element("div"); + div1 = element("div"); + div0 = element("div"); + h3 = element("h3"); + t0 = text(t0_value); + t1 = text(" Notes"); + t2 = space(); + div3 = element("div"); + div2 = element("div"); + t3 = space(); + if (if_block) if_block.c(); + if_block_anchor = empty(); + attr(div0, "class", "setting-item-name"); + attr(div1, "class", "setting-item-info"); + attr(div2, "class", "checkbox-container"); + toggle_class(div2, "is-enabled", /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled); + attr(div3, "class", "setting-item-control"); + attr(div4, "class", "setting-item setting-item-heading"); + }, + m(target, anchor) { + insert(target, div4, anchor); + append(div4, div1); + append(div1, div0); + append(div0, h3); + append(h3, t0); + append(h3, t1); + append(div4, t2); + append(div4, div3); + append(div3, div2); + insert(target, t3, anchor); + if (if_block) if_block.m(target, anchor); + insert(target, if_block_anchor, anchor); + current = true; + + if (!mounted) { + dispose = listen(div2, "click", click_handler); + mounted = true; + } + }, + p(new_ctx, dirty) { + ctx = new_ctx; + + if (dirty & /*$settingsStore, periodicities*/ 9) { + toggle_class(div2, "is-enabled", /*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled); + } + + if (/*$settingsStore*/ ctx[0][/*periodicity*/ ctx[9]].enabled) { + if (if_block) { + if_block.p(ctx, dirty); + + if (dirty & /*$settingsStore*/ 1) { + transition_in(if_block, 1); + } + } else { + if_block = create_if_block(ctx); + if_block.c(); + transition_in(if_block, 1); + if_block.m(if_block_anchor.parentNode, if_block_anchor); + } + } else if (if_block) { + group_outros(); + + transition_out(if_block, 1, 1, () => { + if_block = null; + }); + + check_outros(); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + current = true; + }, + o(local) { + transition_out(if_block); + current = false; + }, + d(detaching) { + if (detaching) detach(div4); + if (detaching) detach(t3); + if (if_block) if_block.d(detaching); + if (detaching) detach(if_block_anchor); + mounted = false; + dispose(); + } + }; +} + +function create_fragment(ctx) { + let t; + let each_1_anchor; + let current; + let if_block = /*$settingsStore*/ ctx[0].showGettingStartedBanner && create_if_block_1(ctx); + let each_value = /*periodicities*/ ctx[3]; + let each_blocks = []; + + for (let i = 0; i < each_value.length; i += 1) { + each_blocks[i] = create_each_block(get_each_context(ctx, each_value, i)); + } + + const out = i => transition_out(each_blocks[i], 1, 1, () => { + each_blocks[i] = null; + }); + + return { + c() { + if (if_block) if_block.c(); + t = space(); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].c(); + } + + each_1_anchor = empty(); + }, + m(target, anchor) { + if (if_block) if_block.m(target, anchor); + insert(target, t, anchor); + + for (let i = 0; i < each_blocks.length; i += 1) { + each_blocks[i].m(target, anchor); + } + + insert(target, each_1_anchor, anchor); + current = true; + }, + p(ctx, [dirty]) { + if (/*$settingsStore*/ ctx[0].showGettingStartedBanner) { + if (if_block) { + if_block.p(ctx, dirty); + + if (dirty & /*$settingsStore*/ 1) { + transition_in(if_block, 1); + } + } else { + if_block = create_if_block_1(ctx); + if_block.c(); + transition_in(if_block, 1); + if_block.m(t.parentNode, t); + } + } else if (if_block) { + group_outros(); + + transition_out(if_block, 1, 1, () => { + if_block = null; + }); + + check_outros(); + } + + if (dirty & /*periodicities, settingsStore, $settingsStore, capitalize*/ 11) { + each_value = /*periodicities*/ ctx[3]; + let i; + + for (i = 0; i < each_value.length; i += 1) { + const child_ctx = get_each_context(ctx, each_value, i); + + if (each_blocks[i]) { + each_blocks[i].p(child_ctx, dirty); + transition_in(each_blocks[i], 1); + } else { + each_blocks[i] = create_each_block(child_ctx); + each_blocks[i].c(); + transition_in(each_blocks[i], 1); + each_blocks[i].m(each_1_anchor.parentNode, each_1_anchor); + } + } + + group_outros(); + + for (i = each_value.length; i < each_blocks.length; i += 1) { + out(i); + } + + check_outros(); + } + }, + i(local) { + if (current) return; + transition_in(if_block); + + for (let i = 0; i < each_value.length; i += 1) { + transition_in(each_blocks[i]); + } + + current = true; + }, + o(local) { + transition_out(if_block); + each_blocks = each_blocks.filter(Boolean); + + for (let i = 0; i < each_blocks.length; i += 1) { + transition_out(each_blocks[i]); + } + + current = false; + }, + d(detaching) { + if (if_block) if_block.d(detaching); + if (detaching) detach(t); + destroy_each(each_blocks, detaching); + if (detaching) detach(each_1_anchor); + } + }; +} + +function instance($$self, $$props, $$invalidate) { + let $settingsStore; + + let { settings } = $$props; + let { onUpdateSettings } = $$props; + let settingsStore = writable(settings); + component_subscribe($$self, settingsStore, value => $$invalidate(0, $settingsStore = value)); + const unsubscribeFromSettings = settingsStore.subscribe(onUpdateSettings); + + function migrateDailyNoteSettings() { + const dailyNoteSettings = getLegacyDailyNoteSettings(); + + settingsStore.update(old => Object.assign(Object.assign({}, old), { + daily: Object.assign(Object.assign({}, dailyNoteSettings), { enabled: true }), + hasMigratedDailyNoteSettings: true + })); + } + + const periodicities = ["daily", "weekly", "monthly", "quarterly", "yearly"]; + + onDestroy(() => { + unsubscribeFromSettings(); + }); + + const func = () => { + set_store_value(settingsStore, $settingsStore.showGettingStartedBanner = false, $settingsStore); + }; + + const click_handler = periodicity => { + set_store_value(settingsStore, $settingsStore[periodicity].enabled = !$settingsStore[periodicity].enabled, $settingsStore); + }; + + $$self.$$set = $$props => { + if ("settings" in $$props) $$invalidate(4, settings = $$props.settings); + if ("onUpdateSettings" in $$props) $$invalidate(5, onUpdateSettings = $$props.onUpdateSettings); + }; + + return [ + $settingsStore, + settingsStore, + migrateDailyNoteSettings, + periodicities, + settings, + onUpdateSettings, + func, + click_handler + ]; +} + +class SettingsTab extends SvelteComponent { + constructor(options) { + super(); + init(this, options, instance, create_fragment, safe_not_equal, { settings: 4, onUpdateSettings: 5 }); + } +} + +const DEFAULT_SETTINGS = Object.freeze({ + format: "", + template: "", + folder: "", +}); +class PeriodicNotesSettingsTab extends obsidian.PluginSettingTab { + constructor(app, plugin) { + super(app, plugin); + this.plugin = plugin; + } + display() { + this.containerEl.empty(); + this.view = new SettingsTab({ + target: this.containerEl, + props: { + settings: this.plugin.settings, + onUpdateSettings: this.plugin.updateSettings, + }, + }); + } +} + +class PeriodicNotesPlugin extends obsidian.Plugin { + async onload() { + this.ribbonEl = null; + this.updateSettings = this.updateSettings.bind(this); + await this.loadSettings(); + this.addSettingTab(new PeriodicNotesSettingsTab(this.app, this)); + this.app.workspace.onLayoutReady(this.onLayoutReady.bind(this)); + obsidian.addIcon("calendar-day", calendarDayIcon); + obsidian.addIcon("calendar-week", calendarWeekIcon); + obsidian.addIcon("calendar-month", calendarMonthIcon); + obsidian.addIcon("calendar-quarter", calendarQuarterIcon); + obsidian.addIcon("calendar-year", calendarYearIcon); + } + onLayoutReady() { + // If the user has Calendar Weekly Notes settings, migrate them automatically, + // since the functionality will be deprecated. + if (this.isInitialLoad && hasLegacyWeeklyNoteSettings()) { + this.migrateWeeklySettings(); + this.settings.weekly.enabled = true; + } + this.configureRibbonIcons(); + this.configureCommands(); + } + migrateWeeklySettings() { + const calendarSettings = getLegacyWeeklyNoteSettings(); + this.updateSettings(Object.assign(Object.assign({}, this.settings), { + weekly: Object.assign(Object.assign({}, calendarSettings), { enabled: true }), + hasMigratedWeeklyNoteSettings: true, + })); + } + configureRibbonIcons() { + var _a; + (_a = this.ribbonEl) === null || _a === void 0 ? void 0 : _a.detach(); + const configuredPeriodicities = [ + "daily", + "weekly", + "monthly", + "quarterly", + "yearly", + ].filter((periodicity) => this.settings[periodicity].enabled); + if (configuredPeriodicities.length) { + const periodicity = configuredPeriodicities[0]; + const config = periodConfigs[periodicity]; + this.ribbonEl = this.addRibbonIcon(`calendar-${config.unitOfTime}`, `Open ${config.relativeUnit}`, (event) => openPeriodicNote(periodicity, window.moment(), isMetaPressed(event))); + this.ribbonEl.addEventListener("contextmenu", (ev) => { + showFileMenu(this.app, this.settings, { + x: ev.pageX, + y: ev.pageY, + }); + }); + } + } + configureCommands() { + // Remove disabled commands + ["daily", "weekly", "monthly", "quarterly", "yearly"] + .filter((periodicity) => !this.settings[periodicity].enabled) + .forEach((periodicity) => { + getCommands(periodicity).forEach((command) => + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.app.commands.removeCommand(`periodic-notes:${command.id}`)); + }); + // register enabled commands + ["daily", "weekly", "monthly", "quarterly", "yearly"] + .filter((periodicity) => this.settings[periodicity].enabled) + .forEach((periodicity) => { + getCommands(periodicity).forEach(this.addCommand.bind(this)); + }); + } + async loadSettings() { + const settings = await this.loadData(); + if (!settings) { + this.isInitialLoad = true; + } + this.settings = Object.assign({}, { + showGettingStartedBanner: true, + hasMigratedDailyNoteSettings: false, + hasMigratedWeeklyNoteSettings: false, + daily: Object.assign({}, DEFAULT_SETTINGS), + weekly: Object.assign({}, DEFAULT_SETTINGS), + monthly: Object.assign({}, DEFAULT_SETTINGS), + quarterly: Object.assign({}, DEFAULT_SETTINGS), + yearly: Object.assign({}, DEFAULT_SETTINGS), + }, settings || {}); + } + onSettingsUpdate() { + this.configureCommands(); + this.configureRibbonIcons(); + // Integrations (i.e. Calendar Plugin) can listen for changes to settings + this.app.workspace.trigger(SETTINGS_UPDATED); + } + async updateSettings(val) { + this.settings = val; + await this.saveData(this.settings); + this.onSettingsUpdate(); + } +} + +module.exports = PeriodicNotesPlugin; diff --git a/.obsidian/plugins/periodic-notes/manifest.json b/.obsidian/plugins/periodic-notes/manifest.json new file mode 100644 index 0000000..f34394e --- /dev/null +++ b/.obsidian/plugins/periodic-notes/manifest.json @@ -0,0 +1,10 @@ +{ + "id": "periodic-notes", + "name": "Periodic Notes", + "description": "Create/manage your daily, weekly, and monthly notes", + "version": "0.0.17", + "author": "Liam Cain", + "authorUrl": "https://github.com/liamcain/", + "isDesktopOnly": false, + "minAppVersion": "0.10.11" +} diff --git a/.obsidian/plugins/periodic-notes/styles.css b/.obsidian/plugins/periodic-notes/styles.css new file mode 100644 index 0000000..d388888 --- /dev/null +++ b/.obsidian/plugins/periodic-notes/styles.css @@ -0,0 +1,30 @@ +.periodic-modal { + min-width: 40vw; +} + +.settings-banner { + background-color: var(--background-primary-alt); + border-radius: 8px; + border: 1px solid var(--background-modifier-border); + margin-bottom: 1em; + margin-top: 1em; + padding: 1.5em; + text-align: left; +} + +.settings-banner h3 { + margin-top: 0; +} + +.settings-banner h4 { + margin-bottom: 0.25em; +} + +.has-error { + color: var(--text-error); +} + +input.has-error { + color: var(--text-error); + border-color: var(--text-error); +} diff --git a/Read Later/2023-10-14 - Using CSS custom properties like this is a waste - YouTube.md b/Read Later/2023-10-14 - Using CSS custom properties like this is a waste - YouTube.md new file mode 100644 index 0000000..a4b7739 --- /dev/null +++ b/Read Later/2023-10-14 - Using CSS custom properties like this is a waste - YouTube.md @@ -0,0 +1,46 @@ +--- +id: 23360258-5e55-4f51-ae84-83f073539aef +title: | + Using CSS custom properties like this is a waste - YouTube +status: ARCHIVED +tags: + - read-later + - Youtube +date_added: 2023-10-14 20:11:15 +url_omnivore: | + https://omnivore.app/me/using-css-custom-properties-like-this-is-a-waste-you-tube-18b30754bdc +url_original: | + https://m.youtube.com/watch?index=12&list=WL&pp=gAQBiAQB&v=_2LwjfYc1x8 +--- + +# Using CSS custom properties like this is a waste - YouTube + +## Notes + +Definir _"variables locales"_ en la clase más alta de un _componente_ (Ej: ˋ.cardˋ), esta variable se puede utilizar para hacer variantes del componente de manera más rápida y limpia y se puede utilizar en los decendientes de la clase. + +Esto tiene la ventaja de: +1. Para crear una variante de nuestro componente solo debemos crear una nueva clase y añadirla junto a la clase más alta (ˋ.card-successˋ), y ya solo debemos sobre escribir las variables en vez de tener que actualizar cada parte del componente (ˋ.card.card-success .buttonˋ & ˋ.card.card-success .card-header h3ˋ). +2. Si tenemos propiedades complejas o animaciones donde solo varia una parte de ellas (Ej: ˋdrop-shadowˋ) no tenemos que re-escribir en cada variante la propiedad completa. + +## Original + + + +0:02 / 16:11•Watch full video + +[](https://m.youtube.com/@KevinPowell) + +45K views 2 days ago [#css](https://m.youtube.com/hashtag/css) + +If you're interested in checking out ICodeThis, you can find it here: [https://icodethis.com/?ref=kevin](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbVZsbWpVZ3M1NUdacFdJSVZha3BFQ0ZIaTNoZ3xBQ3Jtc0ttWG5nU0ltOTdzSE9YSDQ3aWlsUVFGcEVoMlRFaVhLb0hrczRKRVgta3N0bXBIeC1Sc1ZtTWJHY2MycUpfdVN6OE5pWDlfTG9WQlhTMlRzcW1YX2p1MTY4bjVybTd1ZG02RV9zM1l0QkFWeTNybjBtcw&q=https%3A%2F%2Ficodethis.com%2F%3Fref%3Dkevin&v=%5F2LwjfYc1x8) and if you want to sign up for one of their premium plans, use KEVIN at checkout for an extra 10% off. Custom properties are amazing, but a lot of people don’t take advantage of how awesome they are. They set them up in the :root and that’s it, but they can be so much more useful than that! So, in this … + +...more + +...more + + 45,645 views • Oct 12, 2023 • #css + +#### License + +Shop the Kevin Powell store \ No newline at end of file diff --git a/Read Later/2023-10-14 - You Don’t Actually Want Open World Games - YouTube.md b/Read Later/2023-10-14 - You Don’t Actually Want Open World Games - YouTube.md new file mode 100644 index 0000000..fbd9607 --- /dev/null +++ b/Read Later/2023-10-14 - You Don’t Actually Want Open World Games - YouTube.md @@ -0,0 +1,72 @@ +--- +id: d7652dec-ed7a-4473-8d58-5ef8bf4eeefd +title: | + You Don’t Actually Want Open World Games - YouTube +status: ARCHIVED +tags: + - read-later + - Youtube +date_added: 2023-10-14 20:08:13 +url_omnivore: | + https://omnivore.app/me/you-don-t-actually-want-open-world-games-you-tube-18b307286a6 +url_original: | + https://m.youtube.com/watch?index=2&list=WL&pp=gAQBiAQB&v=-O3oe8sSRhQ +--- + +# You Don’t Actually Want Open World Games - YouTube + +## Notes + +> Realmente no queremos juegos _"open world"_, queremos la libertad que creemos que nos dará + +Los juegos open world no están excentos de necesitar un buen diseño para proveer una experiencia divertida de jugar. En este caso particular se debe principalmente a 2 fenomenos: + +### No nos gusta que nos digan que hacer + +Por lo que si encontramos una forma de impedimento para poder avanzar en cierta dirección podemos tener 2 posibles reacciones: + +1. Rebeldía al querer desafiar este impedimento solo porque se nos dijo que **NO**. +2. Apatía y/o frustración ya que se nos quitó la _"libertad"_ de elección. + +### Demaciadas elecciones son abrumantes + +Según estudios, las personas son más seguras y quedan más contentas con sus elecciones si es que las opciones son más limitadas (Ej: 5 vs 30). Esto se debe principalmente a que al realizar una elección de algo, también elegimos no tener acceso al resto de opciones. + +Si bien esta en la mayoría de los casos esta inaccesibilidad es temporal , aún existe, probocando una sensación de de angustia cuando se van multiplicando y multiplicando sin control. + +### Conclusión + +Al igual que en otros casos, una buena idea mal implementada puede llevar al fracaso, es por eso que se necesita un buen diseño para mantener el balance entre _"guiar sutilmente_" al jugador sin imponer una tajante limitación que le quite totalmente la libertad. + +Juegos que han implementan esta idea son: +- [TLOZ - Breath of the wild](games/the-legend-of-zelda-breath-of-the-wild) +- [Metroid Dread](games/metroid-dread) +## Original + +## Chapters + +## Description + +You Don’t Actually Want Open World Games + +Daryl Talks Games + + Daryl Talks Games + +23K Likes + +343,299 Views + +2022 Jul 9 + +Get 20% OFF + Free Shipping with code “DARYL” at [https://mnscpd.com/daryl](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqa1AxdEdWTE4xQ1ljVllOczNhaEtQR0JXbkk1d3xBQ3Jtc0ttOE9WYWZHVkZWV1VUMHhOZnFtZUZYT0dmRlFMTjZXaGNmQlBodHdEaDZQTDNRSkw5NkhoVmIwVW9TQlIyb2xkQmQ4d0ozS1RlNnJuYTlyclFYUlJaODlRRVRDNUFsMVBScEN0dkkwZW1GdGZ1eU16QQ&q=https%3A%2F%2Fmnscpd.com%2Fdaryl&v=-O3oe8sSRhQ) [#ad](https://m.youtube.com/hashtag/ad)Are you a fan of being told “No”? Do you like it when a person keeps you from doing what you want to do, do you enjoy when a game limits your options? Probably not. In fact if anything, being told no likely makes you want that thing even more. Today on Psych of Play, were going to take a look at Psychological Reactance and how it affects our time with a game. And more specifically, we’ll take a look at how it influences your time with open world games. Buckle up, this is gonna be a good one. Amazing thumbnail art by Kloir! - [https://twitter.com/kloirr/status/139...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbmRPeTdhUGdMT1dkNHl3RU9VWU92N1BPQTlXQXxBQ3Jtc0tsSkpTc1RuZ0NzMFM0Q1NBQVpya1JGSHNZbGVBR051Nzd6enI1ck1YU3lKQm5ETHJjUFJlZzRRQ0xicHhhcXpwUm1HZlFuMzl4T3lycmx1M0paeUtUaktTc0NkNGtDQ3ptbTF5M21jbkVLMmt1MWlIaw&q=https%3A%2F%2Ftwitter.com%2Fkloirr%2Fstatus%2F1394322065528745984%3Fs%3D20%26t%3DbIFXtmU3NBNY8MRrDynG5w&v=-O3oe8sSRhQ)Support Daryl Talks Games on Patreon! ▶▶ [https://www.patreon.com/daryltalksgames](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbFlTM1JTTHlXcEN6VzFZLUJwVHVxR3VlMGlMZ3xBQ3Jtc0trOG5EZEQ2eWg5bzJveUZ0Z3VYdlk3SUlISWJvWlhWN2t1aUxjclhYdjZ1SGR0bFhQeDZFay10akFqb3czbmxwelg2VnNPc1UzX1ltYU02TEZSU1dsT3hFUF9KZ3hBMGJlMWhMTXVpVTZwYTNTY0cxVQ&q=https%3A%2F%2Fwww.patreon.com%2Fdaryltalksgames&v=-O3oe8sSRhQ)Bonus content, early access, YOUR name at the end of videos, and more all for $1/month! Twitter ▶[https://twitter.com/DarylTalksGames](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbW9pZ0lCN2FzLWVNY0FjMGZfVGNhalNuX0RWZ3xBQ3Jtc0trRUFSam4xY21sUWFidmlYS3VhOE9kN3AySktZQ1htb0JOODlycWZ3M2ZyS1YtYXBNV2NUd1VmRUxMUGNyOEhsc1JWZm5VXzJxN29FVnhaSEttZmRIaE9KYkVZaE1tWE5VSlpJUllHU1cwTmVqVER5dw&q=https%3A%2F%2Ftwitter.com%2FDarylTalksGames&v=-O3oe8sSRhQ)Twitch ▶[https://www.twitch.tv/daryltalksgames](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbE5WYTVGQ1U5SGc3R1BiSGJZZ1FteGRpVGp1Z3xBQ3Jtc0ttQmtzRUloblVKeC1TQ2lfVDRrcjhXM09xc1VadEdyeVZsdnVNVmxGQ3NUbzdHakFDemRfSEV0VlE5YVVMeUh2cFRRUVNNY3dtU1dVMzhhOVFOOW93N0VELWJNdGk0VE94TTk5bnNKYkJrSUlyWGlKOA&q=https%3A%2F%2Fwww.twitch.tv%2Fdaryltalksgames&v=-O3oe8sSRhQ)Manscaped: Do it for the boys ([0:00](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=0s)) A Trip Down Memory Lane ([1:21](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=81s)) What is Reactance? ([3:25](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=205s)) The Mistaken Allure of Open Worlds ([7:15](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=435s)) Internal vs External Reactance ([9:38](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=578s)) How Games Can Avoid Both ([12:15](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=735s)) When Reactance is Good! ([15:16](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=916s)) Whale ([17:21](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=1041s)) Credits and Next Time ;) ([18:25](https://m.youtube.com/watch?v=-O3oe8sSRhQ&t=1105s)) ▶Games Shown Elden Ring (2022) -FromSoftware The Legend of Zelda: Breath of the Wild (2017) - Nintendo Ghost of Tsushima (2020) - Sucker Punch Productions Metroid Dread (2021) - Mercury Steam Persona 5: Royal (2019) - Atlus, P Studio The Legend of Zelda: Wind Waker (2002) - Nintendo The Legend of Zelda: Twilight Princess (2006) - Nintendo Hades (2020) - Supergiant Games No Man’s Sky (2016) - Hello Games Pokemon Legends: Arceus (2022) - Game Freak Red Dead Redemption 2 (2018) - Rockstar Games Horizon Zero Dawn (2017) - Guerilla Games Horizon Forbidden West (2021) - Guerrilla Games Far Cry 5 (2018) - Ubisoft Fallout 4 (2015) - Bethesda Skyrim (2011) - Bethesda BioShock (2007) - 2K Games Genshin Impact (2020) - miHoYo Pokemon Crystal (2000) - Game Freak Pokémon X and Y (2013) - Game Freak OMORI (2020) - OMOCAT, LLC Zelda: Wind Waker (2002) - Nintendo Super Mario Sunshine (2002) - Nintendo Neon White (2022) - Ben Esposito Final Fantasy VII Remake (2020) - Square Enix Ghostwire: Tokyo (2022) - Tango Gameworks Metro Exodus (2019) - 4A Games Phantasy Star Online 2 (2012) - Sega Sunset Overdrive (2014) - Insomniac Games Batman: Arkham Knight (2015) - Rocksteady Studios Sonic Frontiers (2022) - Sonic Team Forspoken (2023) - Luminous Productions Far Cry 6 (2021) - Ubisoft Pokemon Sword & Shield (2019) - Game Freak Danganronpa: Trigger Happy Havoc (2010) - Spike Chunsoft Cyberpunk 2077 (2020) - CD Projekt RED The Witcher 3: Wild Hunt (2015) - CD Projekt RED Grand Theft Auto V (2013) - Rockstar Games The Walking Dead (2012) - Telltale Games 10 Minutes Till Dawn (2022) - Flanne The Quarry (2022) - Supermassive Games Sable (2021) - Shedworks Starfield (2023) - Bethesda Fallout: New Vegas (2010) - Obsidian Entertainment Unpacking (2021) - Witch Beam ▶Media/Clips/Considerations:[ • Reactance PoP ](https://m.youtube.com/playlist?list=PLwABHajSLTc%5FbPASy3YrBC7uYYzYKLEv7) [ • Playlist ](https://m.youtube.com/playlist?list=PLwABHajSLTc9XTktQrlXVia0kRqOpH8wD)Icons from flaticon:[https://www.flaticon.com/free-icons/p...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbTktcFJ4ZWxPVTl4bW9neXplVVpVSTZPU2Zhd3xBQ3Jtc0trUG5HclhQMFRPLVlPcjZ5S3lIRnFQc01YTFdITVpSdmZsY1kyZXJrRXBxczU2MnlmeExnb3NZem42NHRhbzlBMVlsSE5sR1NfOXlnNVByNnowN1FUSk5iSGJhMnV3cG54LXcxYndRNEtvOFJISU5Eaw&q=https%3A%2F%2Fwww.flaticon.com%2Ffree-icons%2Fperfume-bottle&v=-O3oe8sSRhQ) [https://www.flaticon.com/free-icons/c...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbGV1azYzM2JWaE9vYmFKLU5IM0xHRU1reG8wZ3xBQ3Jtc0ttTHJSU2xpODdTV19vaTd1OGN1WWViR3VuWHhkMnNxMjFtVG1IZHEteTVxNW8xWGlSOWw4Nng3aUZHeW9KbUFJTWNUV3lTLVo1RHhGLXc2eDlFZFRSX21qd2VyU3ZXdXRaNTlfNmVkRmxXSktYSVRCVQ&q=https%3A%2F%2Fwww.flaticon.com%2Ffree-icons%2Fclock&v=-O3oe8sSRhQ) [https://www.flaticon.com/free-icons/m...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbDZjOHZqaWd4SUdrY2RxUnl2TWJaWmw3c2lYUXxBQ3Jtc0tseUFrNnNKb005dl9xR2ppWklCZV8zX3otZi1BaWsyY1ZqTGsyb3FzeHBScFRYXzZydUh0X19nS2p6TjlwUWRHNmgwWUh4UUZIckF1bGpiWHBuS0FzOW9PVElrUnpyRk5KeDVJVGUzcUdHeHhLSHl5Zw&q=https%3A%2F%2Fwww.flaticon.com%2Ffree-icons%2Fmoney&v=-O3oe8sSRhQ)▶Music Sources (in Order): Saints Row IV OST - Hail to the Chief Remix de Blob OST - Blissful Skyrim OST - Far Horizons Pokemon Colosseum OST - Semi Final Battle Gran Turismo 5 OST - feels so good (KEMMEI ADACHI) Breath of the Wild OST - Riding at night Breath of the Wild OST - Field Battle Breath of the Wild OST - Guardian Metroid Prime OST - Phendrana Drifts (Depths) stiig - Gently Pass ([https://stiig.bandcamp.com/track/gent...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbVZZOU8wUEk3NWtvT0JUdmpOZDJLbFZ0UXc5QXxBQ3Jtc0trSkVKSDA5Nzg4d0JFeG9EVWZsMHE4ODEtSi1iY1NoUWFGRXFLOVJ0WW94a2FyVnRIdTJYLVctbzdldWhwS2NDajYyV0RxX21CMjFnN3lkWWJESS1OOTJOMDdaM1NhenBvWVdpOXZCUlBWdnBMVHhSWQ&q=https%3A%2F%2Fstiig.bandcamp.com%2Ftrack%2Fgently-pass&v=-O3oe8sSRhQ)) Machinarium OST - The Bottom - DLJ - Flowers - Provided by Lofi Records - Watch: [ • DLJ - Flowers ](https://m.youtube.com/watch?v=M03fDyewvJc&t=0s)\- Download/Stream: [https://fanlink.to/AfterLifeAlbum](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbnV6S3gzb2hpSERjaXRzU2tSc215UlF3ZnFKd3xBQ3Jtc0tsTWVyaHA5NTR6TGlRd0g5dE9yTkxrT2dCLUxmbXpuZmN3QkpzejJSZU1wUU5yUXVUX1dfemMzMjVmYW1GVlhjQk84UURFU2JsbnRORWxCUVlKdi1HLXd3d2xHWV94cjlkX1dDSFJrNFM0ZmpHS2g0dw&q=https%3A%2F%2Ffanlink.to%2FAfterLifeAlbum&v=-O3oe8sSRhQ)▶Research Articles Cited [https://docs.google.com/document/d/1C...](https://www.youtube.com/redirect?event=video%5Fdescription&redir%5Ftoken=QUFFLUhqbWg4TGtnS1lHSC1vYWRveVFkUGxaZ3ptbmhKd3xBQ3Jtc0tsUHVFMFZUWmlMRWlZS0xMVG1JVFlyRUtfRmJncW8zdjBTbnZYclQ1Z0FKd0lMMFdxb2RGV3dpR1hrWlhIZEVlQXNWQXhEMWVMM29MN3B6ZWZqVFkxUUt0WE54TDN6ZlcwRTFMeHpWeDdnSmxEZnV4aw&q=https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F1Cdv5oLFP0iq7OOf7vSyU%5FsNWt9W2z5LYlJ1-zYjPxG4%2Fedit%3Fusp%3Dsharing&v=-O3oe8sSRhQ) [#PsychofPlay](https://m.youtube.com/hashtag/psychofplay) + +### Transcript + +Follow along using the transcript. + +[ Daryl Talks Games 487K subscribers ](https://m.youtube.com/@DarylTalksGames) + +## Comments 1.7K + +## Transcript \ No newline at end of file diff --git a/Read Later/2023-10-15 - Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram ....md b/Read Later/2023-10-15 - Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram ....md new file mode 100644 index 0000000..8b93329 --- /dev/null +++ b/Read Later/2023-10-15 - Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram ....md @@ -0,0 +1,349 @@ +--- +id: 512f7bbc-6ba0-11ee-be2a-83432433f852 +title: | + Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram usage of LSP servers, svelte inspector integration +status: ARCHIVED +tags: + - read-later + - RSS +date_added: 2023-10-15 16:10:23 +url_omnivore: | + https://omnivore.app/me/highlighting-fold-text-community-fork-of-null-ls-leetcode-integr-18b3533f57b +url_original: | + https://dotfyle.com/this-week-in-neovim/55 +--- + +# Highlighting fold text, community fork of null-ls, leetcode integration, reduce ram usage of LSP servers, svelte inspector integration + +## Highlights + +hinell/duplicate.nvim + +> [!note] +> Add to nvim config + +[source](https://omnivore.app/me/highlighting-fold-text-community-fork-of-null-ls-leetcode-integr-18b3533f57b#5de369b4-f406-446f-b59a-358d59dd9eb1) #Todo + +--- + +## Original + +## Introduction + +This week we have new features in Neovim Core, new plugins and new releases. Some new Neovim features include `:fclose` to close floating windows, support spaces in in directory names, treesitter highlighting in folds and NVIM\_APPNAME supports relative paths. + +We have several new plugins, e.g. you can now grind LeetCode inside Neovim, mini.pick a new fuzzy finder + selector added to the mini.nvim library, and a plugin to start/stop LSP servers upon demand to keep RAM usage low etc.. + +Hope you enjoy! + +## Neovim core + +> Updates of Neovim itself, which are available on Neovim nightly. + +> * [@neovim](https://twitter.com/neovim) on Twitter +> * [Neovim news](https://neovim.io/doc/user/news.html) +> * `:h news.txt` updates in Neovim directly +> * [PR's on GitHub](https://github.com/neovim/neovim/pulls) + +* [:fclose to close floating window](https://github.com/neovim/neovim/commit/fd39f5ce8c9bbda1b77ff6c03553148fadac5d57) +* [Spaces can be used to separate directory names. To have a space in a directory name, precede it with an extra backslash, and escape the space](https://github.com/neovim/neovim/commit/f5eabaa9407ae3d1ccf6592337453c423eff3d9a) +* [Ignore swapfile for running Nvim processes](https://github.com/neovim/neovim/commit/29fe883aa9166bdbcae3f935523c75a8aa56fe45) +* [vim.lsp.util.parse\_snippet() will now strictly follow the snippet grammar defined by LSP, and hence previously parsed snippets might now be considered invalid input.](https://github.com/neovim/neovim/commit/eb1f0e8fcca756a00d287e23bf87554e0e7f6dfd) +* [vim.treesitter.foldtext() applies treesitter highlighting to foldtext.](https://github.com/neovim/neovim/commit/9ce1623837a817c3f4f5deff9c8ba862578b6009) +* [Better cmdline completion for string option value](https://github.com/neovim/neovim/commit/01c51a491330bd10202c73aff92c0978984c0692) +* [Support toggling showing of float window](https://github.com/neovim/neovim/commit/4200a0f1678c06c6da4e4cfb0184c29c1174ed21) +* [NVIM\_APPNAME now supports relative paths](https://github.com/neovim/neovim/commit/a66b0fdfaa35715c832b98b8941cc5673505e0c2) + +### Highlighted folds on Neovim Nightly + + + +* [PR](https://github.com/neovim/neovim/pull/25209) +* [Reddit](https://www.reddit.com/r/neovim/comments/16sqyjz/finally%5Fwe%5Fcan%5Fhave%5Fhighlighted%5Ffolds/) + +## Neovim Plugin Community + +> Neovim is full of active plugins. This section is about the community and what is going on. + +--- + +### Resources & articles + +#### Open Neovim From Your Browser - Integrating nvim with Svelte’s Inspector + +* [Blog](https://theosteiner.de/open-neovim-from-your-browser-integrating-nvim-with-sveltes-inspector) +* [Reddit](https://www.reddit.com/r/neovim/comments/177p9fj/open%5Fneovim%5Ffrom%5Fyour%5Fbrowser%5Fintegrating%5Fnvim/) + +--- + +### New plugins + +#### none-ls.nvim is a community fork of null-ls.nvim + +> null-ls.nvim reloaded / Use Neovim as a language server to inject LSP diagnostics, code actions, and more via Lua. + +null-ls.nvim fork, maintained by the community. Only the repository name has changed for compatibility reasons. All the API's will stay as is. + +Migrate by replacing `jose-elias-alvarez/null-ls.nvim` with `nvimtools/none-ls.nvim` in your package manager. + +* [GitHub](https://github.com/nvimtools/none-ls.nvim) +* [Dotfyle](https://dotfyle.com/plugins/nvimtools/none-ls.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16wystn/nonelsnvim%5Fis%5Fa%5Fcommunity%5Ffork%5Fof%5Fnulllsnvim/) + +#### kawre/leetcode.nvim + + + +> A Neovim plugin enabling you to solve LeetCode problems within Neovim. + +* [GitHub](https://github.com/kawre/leetcode.nvim) +* [Dotfyle](https://dotfyle.com/plugins/kawre/leetcode.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/173ctlz/leetcodenvim%5Fsolve%5Fleetcode%5Fproblems%5Fwithin%5Fneovim/) + +#### echasnovski/mini.pick + + + +> pick anything. Interactive non-blocking picker with one window design, toggleable preview, fast default matching, built-in pickers, and more + +* [GitHub](https://github.com/echasnovski/mini.pick) +* [Dotfyle](https://dotfyle.com/plugins/echasnovski/mini.pick) +* [Reddit](https://www.reddit.com/r/neovim/comments/176yv8g/minipick%5Fpick%5Fanything%5Finteractive%5Fnonblocking/) + +#### hinell/lsp-timeout.nvim + + + +> Start/stop LSP servers upon demand; keeps RAM usage low + +Some LSP servers are terribly inefficient at memory management and can easily take up gigabytes of RAM MBs if left unattended (just like VS Code huh?!). This plugin prevents excessive memory usage by stopping and restarting LSP servers automatically upon gaining or loosing window focus, keeping neovim fast. + +* [GitHub](https://github.com/hinell/lsp-timeout.nvim) +* [Dotfyle](https://dotfyle.com/plugins/hinell/lsp-timeout.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16vkkj8/lsptimeoutnvim/) + +--- + +#### luckasRanarison/clear-action.nvim + + + +> Predictable LSP code actions + +A simple Neovim plugin that enhances LSP code actions with fully customizable signs, personalized actions, and server-specific mappings, making code actions more predictable. + +* [GitHub](https://github.com/luckasRanarison/clear-action.nvim) +* [Dotfyle](https://dotfyle.com/plugins/luckasRanarison/clear-action.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16v32p5/clearactionnvim%5Fmakes%5Flsp%5Fcode%5Factions/) + +--- + +#### JMarkin/gentags.lua + +> autogenerate tags for neovim + +* [GitHub](https://github.com/JMarkin/gentags.lua) +* [Dotfyle](https://dotfyle.com/plugins/JMarkin/gentags.lua) + +--- + +#### roobert/palette.nvim + + + +> 🎨 Palette - A beautiful, versatile, systematic, Neovim theme system + +Palette is a Neovim theme system to make creating and customizing themes easy. + +Highlight groups are logically arranged to strike a harmonious balance between clarity and aesthetic appeal. + +Caching ensures themes are performant. + +Build easily distributable themes using the provided build script. + +Generate application color schemes, such as for LS\_COLORS and iterm2 for matching terminal feel. + +* [GitHub](https://github.com/roobert/palette.nvim) +* [Dotfyle](https://dotfyle.com/plugins/roobert/palette.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16smdr6/introducing%5Froobertpalettenvim%5Fa%5Fbeautiful/) + +--- + +#### MunifTanjim/nougat.nvim + +   + +> 🍫 Hyperextensible Statusline / Tabline / Winbar for Neovim 🚀 + +* [GitHub](https://github.com/MunifTanjim/nougat.nvim) +* [Dotfyle](https://dotfyle.com/plugins/MunifTanjim/nougat.nvim) + +--- + +#### trimclain/builder.nvim + + + +> Simple building plugin for neovim + +* [GitHub](https://github.com/trimclain/builder.nvim) +* [Dotfyle](https://dotfyle.com/plugins/trimclain/builder.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16qwcl7/buildernvim%5Fsimple%5Fbuild%5Fplugin%5Ffor%5Fneovim/) + +--- + +#### niuiic/git-log.nvim + + + +> Check git log of the selected code. + +* [GitHub](https://github.com/niuiic/git-log.nvim) +* [Dotfyle](https://dotfyle.com/plugins/niuiic/git-log.nvim) + +--- + +#### 2KAbhishek/nerdy.nvim + + + +> Find Nerd Glyphs Easily 🤓🔭 + +Do you like Nerd fonts, but don't like going over to the site just to find a glyph? nerdy.nvim, is a super handy plugin that lets you easily search, preview and insert any nerd font glyph from Neovim! + +* [GitHub](https://github.com/2KAbhishek/nerdy.nvim) +* [Dotfyle](https://dotfyle.com/plugins/2KAbhishek/nerdy.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16qr135/nerdynvim%5Feasily%5Ffind%5Fand%5Finsert%5Fnerd%5Ffont%5Fglyphs/) + +--- + +#### David-Kunz/gen.nvim + + + +> Neovim plugin to generate text using LLMs with customizable prompts + +* [GitHub](https://github.com/David-Kunz/gen.nvim) +* [Dotfyle](https://dotfyle.com/plugins/David-Kunz/gen.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16x1zf7/local%5Fllms%5Fin%5Fneovim%5Fgennvim/) +* [Youtube](https://www.youtube.com/watch?v=FIZt7MinpMY) + +--- + +#### VidocqH/data-viewer.nvim + + + +> Table view for data files, csv, tsv + +Lightweight neovim plugin provides a table view for inspect data files such as csv, tsv + +* [GitHub](https://github.com/VidocqH/data-viewer.nvim) +* [Dotfyle](https://dotfyle.com/plugins/VidocqH/data-viewer.nvim) + +--- + +#### ==hinell/duplicate.nvim== + + + +> Duplicate visual selection, lines, and textobjects + +Duplicate lines in different directions (up/down) by specified offset Duplicate visual selection & line-wise blocks + +* [GitHub](https://github.com/hinell/duplicate.nvim) +* [Dotfyle](https://dotfyle.com/plugins/hinell/duplicate.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16vkd4x/duplicatenvim/) + +--- + +#### niuiic/remote.nvim + + + +> Edit remote files locally. + +Edit remote files with local neovim configuration. + +Edit them as local directories. + +No other dependencies required for remote machine except ssh. + +* [GitHub](https://github.com/niuiic/remote.nvim) +* [Dotfyle](https://dotfyle.com/plugins/niuiic/remote.nvim) + +--- + +#### niuiic/typst-preview.nvim + + + +> Neovim plugin to preview typst document. + +Generate pdf files by typst compile. Respond to subsequent file changes with typst-lsp. Redirect these pdf files to a fixed path when you switch buffer. Preview this pdf by a pdf viewer with the ability to respond to the file changes. + +* [GitHub](https://github.com/niuiic/typst-preview.nvim) +* [Dotfyle](https://dotfyle.com/plugins/niuiic/typst-preview.nvim) + +--- + +#### SalOrak/whaler.nvim + + + +> Telescope extension to change between directories blazingly fast + +Whaler is a Telescope extension to move between directories. It is based on the concept of [tmux-windowizer](https://github.com/ThePrimeagen/.dotfiles/blob/master/bin/.local/scripts/tmux-windowizer) which uses a set of directories and fzf to move to another directory whilst creating a new tmux session. + +* [GitHub](https://github.com/SalOrak/whaler.nvim) +* [Dotfyle](https://dotfyle.com/plugins/SalOrak/whaler.nvim) +* [Reddit](https://www.reddit.com/r/neovim/comments/16wgw0b/whalernvim/) + +--- + +#### gsuuon/note.nvim + + + +> Notes in neovim + +A simple Neovim note taking plugin with daily notes, task tracking and syntax highlighting. + +note.nvim makes it easy to take working notes and track tasks. It adds commands to help manipulate task items, create daily notes, and navigate within (and between) notes. + +* [GitHub](https://github.com/gsuuon/note.nvim) +* [Dotfyle](https://dotfyle.com/plugins/gsuuon/note.nvim) + +--- + +#### A retrospective on why Nyoom is archived + +* [Reddit](https://www.reddit.com/r/neovim/comments/16sk266/nyoom%5Fwhy%5Fim%5Fultimately%5Farchiving%5Fit%5Fa%5Fshort/) + +#### indent-blankline.nvim v3 is released + +* [GitHub](https://github.com/lukas-reineke/indent-blankline.nvim) +* [Dotfyle](https://dotfyle.com/plugins/lukas-reineke/indent-blankline.nvim) +* [Migration guide](https://github.com/lukas-reineke/indent-blankline.nvim/wiki/Migrate-to-version-3) +* [Reddit](https://www.reddit.com/r/neovim/comments/16u5abl/indent%5Fblankline%5Fv3%5Fis%5Freleased/) + +#### LazyVim 10.0.0 has been released! + +* [GitHub](https://github.com/LazyVim/LazyVim) +* [Dotfyle](https://dotfyle.com/plugins/LazyVim/LazyVim) +* [Changelog](https://github.com/LazyVim/LazyVim/blob/main/CHANGELOG.md) +* [Reddit](https://www.reddit.com/r/neovim/comments/1766fl1/lazyvim%5F1000%5Fhas%5Fbeen%5Freleased/) + +--- + +## Contributing + +Add your the plugin in either of the following to be featured in This Week in Neovim and Dotfyle: + +* [rockerBOO/awesome-neovim](https://github.com/rockerBOO/awesome-neovim) +* [SUBMITTED\_PLUGINS.md](https://github.com/codicocodes/dotfyle/blob/main/SUBMITTED-PLUGINS.md) + +Contribute to the development of Dotfyle: + +* File issues and submit pull requests on [GitHub](https://github.com/codicocodes/dotfyle) +* Discuss ideas on [Discord](https://discord.gg/AMbnnN5eep) \ No newline at end of file diff --git a/Read Later/2023-10-18 - The Unreasonable Effectiveness Of Plain Text.md b/Read Later/2023-10-18 - The Unreasonable Effectiveness Of Plain Text.md new file mode 100644 index 0000000..641fc81 --- /dev/null +++ b/Read Later/2023-10-18 - The Unreasonable Effectiveness Of Plain Text.md @@ -0,0 +1,592 @@ +--- +id: 07f91eda-1940-4aaa-8e27-78b0bf176193 +title: | + The Unreasonable Effectiveness Of Plain Text +status: ARCHIVED +tags: + - read-later +date_added: 2023-10-18 10:01:51 +url_omnivore: | + https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185 +url_original: | + https://github.com/0atman/noboilerplate/blob/main/scripts/34-Plain-Text-Team.md +--- + +# The Unreasonable Effectiveness Of Plain Text + +## Highlights + +## [Tie Yourself to the Mast](#tie-yourself-to-the-mast) + +%%pron. oh diss e us%% In the Odyssey, Odysseus (confusingly called Ulysses in English literature) had to travel through siren-infested waters. + +This was a well-understood problem in his world. Sailors would simply solve this by putting wax in their ears, so the sirens' tempting song wouldn't lure them to their deaths. + +But Odysseus had a challenge: He WANTED to hear the Sirens' beautiful song. He certainly didn't want to drown, so he ordered his crew to tie him to the mast of the ship, and to ignore any of his pleas to let him go, until safety. + +This way, he was able to guard against future bad decisions he knew he would make by setting up a framework to control his future self. + +This is the Ulysses pact, and it's a very common trick: + +* Leaving your credit card or car keys at home when going out drinking is a Ulysses pact. +* Publishing a warrant canary on your company's website is a Ulysses pact, +* and standardising all your tools on plain text is a Ulysses pact. + +> [!note] +> El pacto de Ulysses es una estrategia (o framework) en donde tomamos medidas tempranamente para prevenir malas desiciones en un futuro. + +[source](https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185#7466a699-a115-4b9f-99fc-416852b5aef2) #frameworks + +--- + +"The difference between science and screwing around is _writing it down_." + +## [— Adam Savage](#-adam-savage) + +> [!note] +> This was just a cool quote... + +[source](https://omnivore.app/me/noboilerplate-scripts-34-plain-text-team-md-at-main-0-atman-nobo-18b42e0d185#9a030eb7-6269-4863-8e5e-61b59a1704b6) #quotes + +--- + +## Original + + + +!\[\[git-logo.png|500\]\] + +## [Plain-Text Team](#plain-text-team) + +notes: %% + +* Tell them what you're going to tell them +* Tell them +* Tell them what you told them %% Hi friends my name is Tris and this is No Boilerplate, focusing on fast, technical videos. + +All good teams are alike; each bad team is bad in its own way. %% to paraphrase Tolstoy %% + +Software is an incredible thing, isn't it? Combined with the internet, a small team of friends can change the world overnight. + +Every company, no matter what their industry, must now run a tech team, even if only to maintain their website. + +So why are they all so bad at it? + +--- + +!\[\[cc-logo.png\]\] + +## [Public Domain Videos](#public-domain-videos) + +
+
+```
+
+Here is an example that shows an image of two (2) dogs:
+
+
+
+Image of two dogs
+
+And here's an example of an image that illustrates the use of alt text:
+
+
+
+Image of dog with alt text displayed
+
+==You should also describe your icon buttons.==
+
+Icons can be easily understood most of the time. It's widely recognized that an x symbol, like this ❌, typically closes a window, a check mark ✅ signifies completion, a forward arrow ▶ signifies send (or play), and a plus sign ➕ represents addition.
+
+But this is clear only for individuals with visual capabilities. For people who aren't able to see the buttons, you'll need to provide a description so they know what that button does.
+
+Let's take a look at this HTML and CSS code that shows how to make buttons access:
+
+Document
+
+Here's the result of the code implemented above:
+
+
+
+### Is it Operable?
+
+Users should be able to navigate and interact with the interface quickly. Consider the following factors:
+
+==First, make sure you use clear and consistent headings.==
+
+This is what clear and consistent headings look like:
+
+## I am a Title
+
+## I am a Subtitle
+
+### This is heading 3
+
+#### This is Heading 4
+
+##### This is Heading 5
+
+###### This is heading 6
+
+As you can see, these headings go from largest to smallest in order. We have an H1 heading first, followed by H2, H3, and so on.
+
+Here are some headings that don't follow the proper hierarchy:
+
+###### This is heading 6
+
+##### This is Heading 5
+
+#### This is Heading 4
+
+### This is heading 3
+
+## I am a Subtitle
+
+## I am a Title
+
+In this example, the headings go in reverse order, starting from H6 and moving up through H5, H4, and so on.
+
+Just remember to use proper heading hierarchy – don't use an H2 and then jump straight to H4 for a subheading, for example, as this is visually jarring and doesn't convey the proper importance or hierarchy of the text.
+
+Here's why heading hierarchy is important:
+
+* A clear heading hierarchy helps readers easily navigate and understand the content of a document.
+* Heading hierarchy is crucial for accessibility, as it helps screen readers and assistive technologies interpret the structure of the content. This is important for individuals with visual impairments who rely on such tools to access information.
+* A well-organized heading hierarchy implement a logical flow of information, ensuring that topics are presented in a coherent order.
+
+Also, refrain from using elements that might trigger physical discomfort, like bright flashing lights.
+
+==And make sure you think about== ==[keyboard accessibility](https://www.freecodecamp.org/news/designing-keyboard-accessibility-for-complex-react-experiences/)== ==so users can navigate and communicate using the keyboard, and not exclusively using a mouse.==
+
+### Is it Understandable?
+
+Content and functionality should be presented clearly and understandably. Consider the following factors:
+
+* ==Organize content using headings, subheadings, and bullet points to enhance readability.==
+* Provide instructions and error messages that are easy to understand.
+* Use simple and concise language, avoid complex terms.
+
+### Is it Robust?
+
+Websites should be built using robust and widely supported technologies to enable compatibility across devices and assistive technologies.
+
+You'll want to maximize compatibility with current and future user agents, including assistive technologies.
+
+Here are some of the ways you can maximize compatibility with current and future agents, including assistive tools:
+
+* ==Use== ==[HTML5 semantic elements](https://www.freecodecamp.org/news/semantic-html-alternatives-to-using-divs/)== ==like== `==<====header====>==`==,== `==<====nav====>==`==,== `==<====main====>==`==, and== `==<====footer====>==` ==to enhance the document's structure.==
+* ==Ensure that your== ==[JavaScript code is efficient](https://www.freecodecamp.org/news/javascript-performance-async-defer/)== ==and doesn't block the rendering process.==
+* ==Utilize== ==[browser developer tools](https://www.freecodecamp.org/news/learn-how-to-use-the-chrome-devtools-to-troubleshoot-websites/)== ==and online testing services to identify and fix compatibility issues.==
+* ==Conduct== ==[usability testing](https://www.freecodecamp.org/news/10-best-ux-testing-software-tools/)== ==with a diverse group of users, including those who rely on assistive technologies, to gather feedback and make improvements.==
+* ==Optimize your website for fast loading times and low data usage using techniques like== ==[caching](https://www.freecodecamp.org/news/a-detailed-guide-to-pre-caching/)== ==and== ==[tools like CDNs](https://www.freecodecamp.org/news/cdns-speed-up-performance-by-reducing-latency/)== ==to reduce latency. This benefits both accessibility and user experience.==
+* ==Document your code and accessibility features for future maintainers.==
+* ==Test== ==[website compatibility across various browsers](https://www.freecodecamp.org/news/cross-browser-compatibility-testing-best-practices-for-web-developers/)====. Testing website compatibility involves ensuring that your website functions correctly and looks good on a variety of devices, browsers, and assistive technologies.==
+
+Here are the steps you can follow to test website compatibility effectively:
+
+1. **Device Testing**: Test your website on various devices, such as desktop computers, laptops, tablets, and smartphones. This includes both iOS and Android devices.
+2. **Browser Testing**: Check your website's performance and appearance on multiple browsers, including but not limited to Google Chrome, Mozilla Firefox, Apple Safari, and Microsoft Edge.
+3. **User Testing**: Conduct usability testing with real users. Ask them to use your website on different devices and browsers and collect feedback on compatibility issues.
+4. **Performance Testing**: Assess website loading times, and optimize for speed using tools like Google PageSpeed Insights, GTmetrix, or Lighthouse. Check for compatibility with slow internet connections.
+
+## Conclusion
+
+Understanding web accessibility can enhance the user experience by creating a smooth and seamless interaction with websites and web applications.
+
+Implementing these tips can improve the overall user-friendliness and navigability of your app. It'll help create a more enjoyable experience for all users, and will also allow people with disabilities to perceive, understand, navigate, and interact with your sites effectively.
+
+---
+
+---
+
+ Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/)
\ No newline at end of file
diff --git a/Read Later/2023-11-04 - Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir-.md b/Read Later/2023-11-04 - Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir-.md
new file mode 100644
index 0000000..d8de707
--- /dev/null
+++ b/Read Later/2023-11-04 - Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir-.md
@@ -0,0 +1,27 @@
+---
+id: fc51bf82-66d3-451f-8f64-17d6add50f92
+title: |
+ Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?
+status: ARCHIVED
+tags:
+ - read-later
+ - Youtube
+date_added: 2023-11-04 14:14:49
+url_omnivore: |
+ https://omnivore.app/me/https-www-youtube-com-watch-pp-yg-ukz-2-l-0-ih-nxd-w-fza-a-253-d-18b9b548407
+url_original: |
+ https://www.youtube.com/watch?pp=ygUKZ2l0IHNxdWFzaA%253D%253D&v=HlmZLXMOpEM
+---
+
+# Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?
+
+## Notes
+
+- Merge commit: Se crea un commit que tiene 2 padres, el último commit de main y la feature branch, se mantiene la trazabilidad hacia la feature branch pero el historial queda visualmente más complejo
+- Rebase: Se copian los commits de la feature branch a main como nuevos commits, se pierde la trazabilidad hacia la feature branch pero queda un historial lineal en main
+- Squash commit: Se juntan todos los commits en uno solo con un squash que queda en main, se pierde la trazabilidad hacia la feature branch pero queda un historial lineal en main
+## Original
+
+[Git Merge vs Rebase vs Squash ¿Qué estrategia debemos elegir?](https://www.youtube.com/watch?pp=ygUKZ2l0IHNxdWFzaA%253D%253D&v=HlmZLXMOpEM)
+
+By [CodelyTV - Redescubre la programación](https://www.youtube.com/@CodelyTV)
\ No newline at end of file
diff --git a/Read Later/2023-11-06 - How to Write Components that Work in Any Framework.md b/Read Later/2023-11-06 - How to Write Components that Work in Any Framework.md
new file mode 100644
index 0000000..628e953
--- /dev/null
+++ b/Read Later/2023-11-06 - How to Write Components that Work in Any Framework.md
@@ -0,0 +1,402 @@
+---
+id: 616d5d08-7d04-11ee-8eaa-9f56108b78ec
+title: |
+ How to Write Components that Work in Any Framework
+status: ARCHIVED
+tags:
+ - read-later
+ - RSS
+date_added: 2023-11-06 17:25:12
+url_omnivore: |
+ https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079
+url_original: |
+ https://www.freecodecamp.org/news/write-components-that-work-in-any-framework/
+---
+
+# How to Write Components that Work in Any Framework
+
+## Highlights
+
+With Custom Elements you can author your own custom HTML elements that you can reuse across your site. They can be as simple as text, images, or visual decorations. You can push them further and build interactive components, complex widgets, or entire web applications.
+
+[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#bceef8c0-728e-422a-aed6-b047736cb395)
+
+---
+
+### Writing a web component requires understanding all of its underlying technologies
+
+As we saw above, web components are made up of three technologies. You can also see in the hello world code snippet, that we explicitly need to know and understand these three technologies.
+
+1. We’re creating a **template element** and setting its inner HTML
+2. We’re creating a **shadow root**, and explicitly setting its mode to ‘open’.
+3. We’re cloning our **template** and appending it to our **shadow root**
+4. We’re registering a new **custom element** to the document
+
+[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#46fc130a-1549-40c8-b950-42035c227bc4)
+
+---
+
+As web component authors, we need to consider a lot of things:
+
+* Setting up the shadow DOM
+* Setting up the HTML templates
+* Cleaning up event listeners
+* Defining properties that we want to observe
+* Reacting to properties when they change
+* Handling type conversions for attributes
+
+[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#855f444c-49f1-4176-9537-aaeeb6a01355)
+
+---
+
+One such tool is called Lit, which is developed by a team at Google. [Lit](https://lit.dev/) is a lightweight library designed to make writing web components simple, by removing the need for the boilerplate we’ve already seen above.
+
+[source](https://omnivore.app/me/how-to-write-components-that-work-in-any-framework-18ba72d0079#385d9ef8-13fb-4799-bff5-ef767b3df67f)
+
+---
+
+## Original
+
+
+
+The browser has a built-in way of writing reusable components in the form of **web components**. They’re an excellent choice for building interactive and reusable components that work in any frontend framework.
+
+With that said, writing highly interactive and robust web components isn’t simple. They require a lot of boilerplate and feel much less intuitive than the components you may have written in frameworks like React, Svelte, or Vue.
+
+In this tutorial, I’ll give you an example of an interactive component written as a web component, and then refactor it using a library that softens the edges and removes heaps of boilerplate.
+
+Don’t sweat it if you’re not familiar with web components. In the next section, I’ll do a (brief) overview of what web components are, and what they’re made out of. If you have some basic experience with them, you can skip the next section.
+
+## What are Web Components?
+
+Before web components, the browser didn’t have a standard way of writing reusable components. Many libraries solve this problem, but they often run into limitations like performance, interoperability, and issues with web standards.
+
+Web components are a technology made up of 3 different browser features:
+
+* Custom elements
+* Shadow DOM
+* HTML Templates
+
+We’ll do a quick crash course covering these technologies, but it’s by no means a comprehensive breakdown.
+
+### What are Custom Elements?
+
+==With Custom Elements you can author your own custom HTML elements that you can reuse across your site. They can be as simple as text, images, or visual decorations. You can push them further and build interactive components, complex widgets, or entire web applications.==
+
+You’re not just limited to using them in your projects, but you can publish them and allow other developers to use them on their sites.
+
+Here are some of the reusable components from my library [A2K](https://a2000-docs.netlify.app/). You can see that they come in all shapes and sizes, and have a range of different functionalities. Using them in your projects is similar to using any old HTML element.
+
+
+
+A small collection of web components from the A2K library
+
+Here’s how you’d use the progress element in your project:
+
+```xml
+
+
+
+ Hello World
`; + +class HelloWorld extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: 'open' }); + this.shadowRoot.append(template.content.cloneNode(true)); + } +} + +customElements.define('hello-world', HelloWorld); + +``` + +This is the most simple component you can write, but there’s already so much going on. For someone completely new to web components, and without the background knowledge I provided above, they’re going to be left with a lot of questions, and a lot of confusion. + +For me, there are at least two key reasons why web components can be challenging to write, at least within the context of the hello world examples. + +### The markup is decoupled from the component logic + +In many frameworks, the markup of the component is often treated as a first-class citizen. It’s often the content that gets returned from the component function, or has direct access to the component’s state, or has built-in utilities to help manipulate markup (like loops, conditionals, and so on). + +This isn’t the case for web components. In fact, the markup is often defined outside of the component’s class. There’s also no built-in way for the template to reference the current state of the component. This becomes a cumbersome limitation as the complexity of a component grows. + +In the world of frontend, components are designed to help developers reuse markup in several pages. As a result, the markup and the component logic are inextricably linked, and so they should be colocated with one another. + +### ==Writing a web component requires understanding all of its underlying technologies== + +==As we saw above, web components are made up of three technologies. You can also see in the hello world code snippet, that we explicitly need to know and understand these three technologies.== + +1. ==We’re creating a== **==template element==** ==and setting its inner HTML== +2. ==We’re creating a== **==shadow root==**==, and explicitly setting its mode to ‘open’.== +3. ==We’re cloning our== **==template==** ==and appending it to our== **==shadow root==** +4. ==We’re registering a new== **==custom element==** ==to the document== + +There’s nothing inherently wrong with this, since web components are supposed to be a “lower-level” browser API, making them prime for building abstractions on top of. But for a developer coming from a React or a Svelte background, having to understand these new browser features, and then having to write components with them can feel like too much friction. + +## More Advanced Web Components + +Let’s take a look at a more advanced web component, a counter button. + + + +You click the button, and the counter increments. + +The following example contains a few extra web component concepts, like lifecycle functions and observable attributes. You don’t need to understand everything going on in the code snippet. This example is really only used to illustrate how much boilerplate is required for the most basic of interactive interfaces, a counter button: + +```kotlin +const templateEl = document.createElement("template"); + +templateEl.innerHTML = ` + +You pressed me 0 times.
+`; + +export class OdysseyButton extends HTMLElement { + constructor() { + super(); + this.attachShadow({ mode: "open" }); + this.shadowRoot.appendChild(templateEl.content.cloneNode(true)); + this.button = this.shadowRoot.querySelector("button"); + this.p = this.shadowRoot.querySelector("p"); + this.setAttribute("count", "0"); + } + + // Note: Web components have lifecycle methods, + // If we're setting event listeners when the component is added to the DOM, it's our job to clean + // them up when it gets removed from the DOM + connectedCallback() { + this.button.addEventListener("click", this.handleClick); + } + + disconnectedCallback() { + this.button.removeEventListener("click", this.handleClick); + } + + // Unlike frameworks like React, Web Components don't automatically rerender when a prop (or attribute) + // changes. Instead, we need to explicitly define which attributes we want to observe. + static get observedAttributes() { + return ["disabled", "count"]; + } + + // When one of the above attributes changes, this lifecycle method runs, and we can + // react to the new attribute's value accordingly. + attributeChangedCallback(name, _, newVal) { + if (name === "count") { + this.p.innerHTML = `You pressed me ${newVal} times.`; + } + if (name === "disabled") { + this.button.disabled = true; + } + } + + // In HTML, attribute values are always strings. This means that it's our job to + // convert types. You can see below that we're converting a string -> number, and then back to a string + handleClick = () => { + const counter = Number(this.getAttribute("count")); + this.setAttribute("count", `${counter + 1}`); + }; + +``` + +==As web component authors, we need to consider a lot of things:== + +* ==Setting up the shadow DOM== +* ==Setting up the HTML templates== +* ==Cleaning up event listeners== +* ==Defining properties that we want to observe== +* ==Reacting to properties when they change== +* ==Handling type conversions for attributes== + +And there are still so many other things to consider that I haven’t touched on in this article. + +That isn’t to say that web components are bad and that you shouldn’t write them. In fact, I’d argue that you learn so much about the browser platform by building with them. + +But I feel that there are better ways to write components if your priority is to write interoperable components in a much more streamlined and ergonomic way. + +## How to Write Web Components with Less Boilerplate + +As I mentioned earlier, there are a lot of tools out there to help make writing web components much easier. + +==One such tool is called Lit, which is developed by a team at Google.== ==[Lit](https://lit.dev/)== ==is a lightweight library designed to make writing web components simple, by removing the need for the boilerplate we’ve already seen above.== + +As we’ll see, Lit does a lot of heavy lifting under-the-hood to help cut down the total lines of code by nearly half! And because Lit is a wrapper around web components and other native browser features, all your existing knowledge about web components is transferable. + +To start seeing how Lit simplifies your web components. Here’s the **hello world** example from earlier, but refactored to use Lit instead of a vanilla web component: + +```scala +import { LitElement, html } from "lit"; + +export class HelloWorld extends LitElement { + render() { + return html`Hello World!
`; + } +}` + +customElements.define('hello-world', HelloWorld); + +``` + +There’s a lot less boilerplate with the Lit component, and Lit handles the two problems I mentioned earlier, a little bit differently. Let’s see how: + +1. The markup is directly defined from within the component class. While you can define your templates outside of the class, it’s common practice to return the template from the `render` function. This is more in line with the mental model presented in other UI frameworks, where the UI is a function of the state. +2. Lit also doesn’t require developers to attach the shadow DOM, or create templates and clone template elements. While having an understanding of the underlying web component features will help when developing Lit components, they’re not required for getting started, so the barrier for entry is much lower. + +So now for the big finale, what does the counter component look like once we’ve migrated it over to Lit? + +```typescript +import { LitElement, html } from "lit"; + +export class OdysseyCounter extends LitElement { + static properties = { + // We define the component's properties as well as their type. + // These properties will trigger the component to re-render when their values change. + // While they're not the same, you can think of these "properties" as being + // Lit's alternatives to "observed attributes" + // If the value is passed down as an attribute, Lit converts the value + // to the correct type + count: { type: Number }, + disabled: { type: Boolean }, + }; + + constructor() { + super(); + // There's no need to create a shadow DOM, clone the template, + // or store references to our DOM nodes. + this.count = 0; + } + + onCount() { + this.count = this.count + 1; + } + + render() { + // Instead of using the attributeChangedCallback lifecycle, the + // render function has access to all of the component's properties, + // which simplifies the process of manipulating our templates. + return html` + +You pressed me ${this.count} times.
+ `; + } +}` + +``` + +The amount of code we’re writing is cut down by almost half! And this difference becomes more noticeable when creating more complex user interfaces. + +## Why am I going on about Lit? + +I’m a big believer in web components, but I recognise that the barrier to entry is high for many developers. Writing complex web components requires understanding heaps of browser features and the education around web components isn’t as comprehensive as other technologies, like React or Vue. + +This is why I think it’s important to use tools like Lit can make writing performant and interoperable web components much easier. This is great if you want your components to work within any frontend framework. + +If you’d like to learn even more, this is the approach I teach in my upcoming course [Component Odyssey](https://component-odyssey.com/). This course is excellent for anyone who wants to understand how to write components that work in any framework. + +I do this by covering the absolute basics of web components, before moving on to tools like Lit that simplify the process of writing web components without complicating your development environment. By the end, you’ll learn how to build and publish a component library that works across any frontend framework. + +If you want early-bird discount codes for Component Odyssey, then head on [over to the site to get notified](https://component-odyssey.com/subscribe). + +--- + +--- + + Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. [Get started](https://www.freecodecamp.org/learn/) \ No newline at end of file diff --git a/Read Later/2023-11-07 - How to Avoid Prop Drilling in React.md b/Read Later/2023-11-07 - How to Avoid Prop Drilling in React.md new file mode 100644 index 0000000..52236fb --- /dev/null +++ b/Read Later/2023-11-07 - How to Avoid Prop Drilling in React.md @@ -0,0 +1,479 @@ +--- +id: aceac380-7e10-11ee-992a-432064e77190 +title: | + How to Avoid Prop Drilling in React +status: ARCHIVED +tags: + - read-later + - RSS + - react +date_added: 2023-11-07 19:58:39 +url_omnivore: | + https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2 +url_original: | + https://www.freecodecamp.org/news/avoid-prop-drilling-in-react/ +--- + +# How to Avoid Prop Drilling in React + +## Highlights + +Prop drilling occurs when a parent component generates its state and passes it down as `props` to its children components that do not consume the props – instead, they only pass it down to another component that finally consumes it. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#05db3def-4e59-4cfe-b8dd-1044ce91a9d5) + +--- + +First of all, **grouping static elements and dependent components** together to achieve an appealing UI design is the major cause of prop drilling. You can't avoid prop drilling when your UI groups static elements and dependent components together in a parent. The parent component clearly won't use the `prop`, as everything within it is a static element – except the component that needs a prop. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#fa2c28c0-1b7e-4416-8553-c1b5c7a59637) + +--- + +Second of all, when a **component accepts `props` that it doesn't use but merely passes it down to its children**, this is a sign that you have prop drilling in your component: + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#6749a89e-a38c-4f4f-aa3f-c6455e6daf85) + +--- + +Third, when a component that represents an independent section of a page is **forced to take props from its parent**, prop drilling is inevitable. It should ideally be self-contained with its state and operations. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#751d81de-62b7-444b-a2f0-a0b374f6ce45) + +--- + +And finally, **the presence of elongated `props`** is a sure sign of prop drilling. Since an elongated prop is a fundamental element that's consistently present in every case of prop drilling, grasping this concept allows you to instinctively avoid prop drilling. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#90f807ca-03a3-4804-bcf1-c5df4e53a997) + +--- + +Component composition is a good approach to fix prop drilling. If you ever find yourself in a situation where a component passes down a prop it neither creates nor consumes, you can use component composition to fix it. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#0112181f-34b7-4ca3-b941-f1c16303c6c0) + +--- + +To avoid prop drilling in this case, any grandchildren components that require access to the same `props`, especially when their parent don't consume the data, should be passed as children ensuring that the data remains within the `App` context. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#c17f1d4e-8f5c-45d1-9078-fe8ab740e11e) + +--- + +Prop drilling can also be fixed by moving state to where it is consumed. The example of prop drilling in this article has a component named `Content`. But the component is forced to receive a `prop` from its parent instead of having a state and be an independent component – and so we have prop drilling. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#9f94fd13-9558-4bd3-a60c-60074b3495d2) + +--- + +It's essential to highlight what to avoid when dealing with prop drilling to prevent unnecessary challenges. + +* **Avoid React Context, if possible, to fix prop drilling.** This approach ties your component to a specific context, restricting its usability outside of that context and hindering composition and reusability. +* **Steer clear of redundant components by employing a children-parent replacement approach.** This approach naturally incorporates [component composition](https://www.codementor.io/@dinerismail/the-power-of-component-composition-in-react-21goassg4m) without introducing redundant components or states when resolving prop drilling. + +[source](https://omnivore.app/me/how-to-avoid-prop-drilling-in-react-18bae0b4ca2#8ff7b79b-5503-4e1a-b7fe-1a07a46c578c) + +--- + +## Original + + + +In order to write scalable, reusable, and maintainable applications with React, you'll need to go beyond the surface of using React components, useEffect, useContext, useState, and the like. It involves learning in detail how React works in more depth. + +And if you don't properly understand these key React concepts, you can run into various issues, like [prop drilling](https://www.quora.com/What-is-prop-drilling-in-ReactJS). + +In this tutorial, you'll learn what prop drilling is. I'll also teach you how to intuitively avoid it without relying on React context. In the end, you'll understand how to identify prop drilling without thinking and fix it with precision. + +If you prefer a visual guide, here's a video version of this tutorial on my [YouTube channel](https://youtu.be/KZnQ5R8Kd4I) (approximately 15 minutes). + +[](https://www.youtube.com/embed/ELZZnqHJhlw) + +## What is Prop Drilling? + +==Prop drilling occurs when a parent component generates its state and passes it down as== `==props==` ==to its children components that do not consume the props – instead, they only pass it down to another component that finally consumes it.== + +Below is an example of prop drilling in React: + +```xquery +function App() { + const [profile, setProfile] = useState({ame: 'John'}); + return ( +{profile.name}
+{profile.name}
+{profile.name}
+{profile.name}
+{post.content}
+ {signedIn && } +Count: {count}
+Square: {memoizedValue}
+ + setOtherState(e.target.value)} /> +Count: {count}
+This is a dynamically loaded component!
+