diff --git a/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs b/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs deleted file mode 100644 index 91edb191c3f..00000000000 --- a/app/assets/javascripts/discourse/app/components/admin-post-menu.gjs +++ /dev/null @@ -1,241 +0,0 @@ -import Component from "@glimmer/component"; -import { inject as service } from "@ember/service"; -import DButton from "discourse/components/d-button"; -import { fn } from "@ember/helper"; -import and from "truth-helpers/helpers/and"; -import or from "truth-helpers/helpers/or"; -import not from "truth-helpers/helpers/not"; -import { action } from "@ember/object"; -import concatClass from "discourse/helpers/concat-class"; - -export default class AdminPostMenu extends Component { - @service currentUser; - @service siteSettings; - @service store; - @service adminPostMenuButtons; - - - - get reviewUrl() { - return `/review?topic_id=${this.args.data.transformedPost.id}&status=all`; - } - - get extraButtons() { - return this.adminPostMenuButtons.callbacks - .map((callback) => { - return callback(this.args.data.transformedPost); - }) - .filter(Boolean); - } - - @action - async topicAction(actionName) { - await this.args.close(); - - try { - await this.args.data[actionName]?.(); - } catch (error) { - // eslint-disable-next-line no-console - console.error(`Unknown error while attempting \`${actionName}\`:`, error); - } - - await this.args.data.scheduleRerender(); - } - - @action - async extraAction(button) { - await this.args.close(); - await button.action(this.args.data.post); - await this.args.data.scheduleRerender(); - } -} diff --git a/app/assets/javascripts/discourse/app/components/bootstrap-mode-notice.hbs b/app/assets/javascripts/discourse/app/components/bootstrap-mode-notice.hbs index d4f80b8f439..8c1aab46f29 100644 --- a/app/assets/javascripts/discourse/app/components/bootstrap-mode-notice.hbs +++ b/app/assets/javascripts/discourse/app/components/bootstrap-mode-notice.hbs @@ -1,28 +1,20 @@ - - <:button> - - {{#if this.showUserTip}} - - {{/if}} - - - - <:tooltip> - {{#unless this.showUserTip}} - -
-
- {{i18n "user_tips.admin_guide.title"}} -
-
- {{i18n "user_tips.admin_guide.content_no_url"}} -
+ + {{#if this.showUserTip}} + + {{else}} + +
+
+ {{i18n "user_tips.admin_guide.title"}}
- - {{/unless}} - - \ No newline at end of file +
+ {{i18n "user_tips.admin_guide.content_no_url"}} +
+
+
+ {{/if}} +
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js index b98eeaf22ae..cee2e5f20d8 100644 --- a/app/assets/javascripts/discourse/app/components/composer-editor.js +++ b/app/assets/javascripts/discourse/app/components/composer-editor.js @@ -42,7 +42,6 @@ import { initUserStatusHtml, renderUserStatusHtml, } from "discourse/lib/user-status-on-autocomplete"; -import { getOwner } from "discourse-common/lib/get-owner"; // original string `![image|foo=bar|690x220, 50%|bar=baz](upload://1TjaobgKObzpU7xRMw2HuUc87vO.png "image title")` // group 1 `image|foo=bar` @@ -224,7 +223,7 @@ export default Component.extend(ComposerUploadUppy, { categoryId: this.topic?.category_id || this.composer?.categoryId, includeGroups: true, }).then((result) => { - initUserStatusHtml(getOwner(this), result.users); + initUserStatusHtml(result.users); return result; }); }, diff --git a/app/assets/javascripts/discourse/app/components/create-topic-button.hbs b/app/assets/javascripts/discourse/app/components/create-topic-button.hbs index 34bdcd2c512..5b6e7b826b9 100644 --- a/app/assets/javascripts/discourse/app/components/create-topic-button.hbs +++ b/app/assets/javascripts/discourse/app/components/create-topic-button.hbs @@ -1,22 +1,11 @@ {{#if this.canCreateTopic}} - - <:button> - - - <:tooltip> - {{#if @disabled}} - - {{/if}} - - + + {{yield}} {{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/d-modal.hbs b/app/assets/javascripts/discourse/app/components/d-modal.hbs index e067b5f2c29..d91888fe2f7 100644 --- a/app/assets/javascripts/discourse/app/components/d-modal.hbs +++ b/app/assets/javascripts/discourse/app/components/d-modal.hbs @@ -20,7 +20,6 @@ {{did-insert this.setupListeners}} {{will-destroy this.cleanupListeners}} {{on "mouseup" this.handleMouseUp}} - {{trap-tab (hash preventScroll=false)}} > {{/if}} diff --git a/app/assets/javascripts/discourse/app/components/post-text-selection-toolbar.gjs b/app/assets/javascripts/discourse/app/components/post-text-selection-toolbar.gjs deleted file mode 100644 index d36e8630a89..00000000000 --- a/app/assets/javascripts/discourse/app/components/post-text-selection-toolbar.gjs +++ /dev/null @@ -1,253 +0,0 @@ -import { ajax } from "discourse/lib/ajax"; -import { postUrl, setCaretPosition } from "discourse/lib/utilities"; -import Sharing from "discourse/lib/sharing"; -import { action } from "@ember/object"; -import { getAbsoluteURL } from "discourse-common/lib/get-url"; -import { inject as service } from "@ember/service"; -import FastEditModal from "discourse/components/modal/fast-edit"; -import Component from "@glimmer/component"; -import concatClass from "discourse/helpers/concat-class"; -import DButton from "discourse/components/d-button"; -import { fn } from "@ember/helper"; -import PluginOutlet from "discourse/components/plugin-outlet"; -import FastEdit from "discourse/components/fast-edit"; -import { on } from "@ember/modifier"; -import { tracked } from "@glimmer/tracking"; -import { modifier } from "ember-modifier"; - -export function fixQuotes(str) { - // u+201c, u+201d = “ ” - // u+2018, u+2019 = ‘ ’ - return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'"); -} - -export default class PostTextSelectionToolbar extends Component { - - - @service currentUser; - @service modal; - @service site; - @service siteSettings; - @service appEvents; - - @tracked isFastEditing = false; - - appEventsListeners = modifier(() => { - this.appEvents.on("quote-button:edit", this, "toggleFastEdit"); - - return () => { - this.appEvents.off("quote-button:edit", this, "toggleFastEdit"); - }; - }); - - get topic() { - return this.args.data.topic; - } - - get quoteState() { - return this.args.data.quoteState; - } - - get post() { - return this.topic.postStream.findLoadedPost( - this.args.data.quoteState.postId - ); - } - - get quoteSharingEnabled() { - return ( - this.site.desktopView && - this.quoteSharingSources.length > 0 && - !this.topic.invisible && - !this.topic.category?.read_restricted && - (this.siteSettings.share_quote_visibility === "all" || - (this.siteSettings.share_quote_visibility === "anonymous" && - !this.currentUser)) - ); - } - - get quoteSharingSources() { - return Sharing.activeSources( - this.siteSettings.share_quote_buttons, - this.siteSettings.login_required || this.topic.isPrivateMessage - ); - } - - get quoteSharingShowLabel() { - return this.quoteSharingSources.length > 1; - } - - get shareUrl() { - return getAbsoluteURL( - postUrl(this.topic.slug, this.topic.id, this.post.post_number) - ); - } - - get embedQuoteButton() { - const canCreatePost = this.topic.details.can_create_post; - const canReplyAsNewTopic = this.topic.details.can_reply_as_new_topic; - - return ( - (canCreatePost || canReplyAsNewTopic) && - this.currentUser?.get("user_option.enable_quoting") - ); - } - - @action - trapEvents(event) { - event.stopPropagation(); - } - - @action - async closeFastEdit() { - this.isFastEditing = false; - await this.args.data.hideToolbar(); - } - - @action - async toggleFastEdit() { - if (this.args.data.supportsFastEdit) { - if (this.site.desktopView) { - this.isFastEditing = !this.isFastEditing; - } else { - this.modal.show(FastEditModal, { - model: { - initialValue: this.args.data.quoteState.buffer, - post: this.post, - }, - }); - this.args.data.hideToolbar(); - } - } else { - const result = await ajax(`/posts/${this.post.id}`); - - if (this.isDestroying || this.isDestroyed) { - return; - } - - let bestIndex = 0; - const rows = result.raw.split("\n"); - - // selecting even a part of the text of a list item will include - // "* " at the beginning of the buffer, we remove it to be able - // to find it in row - const buffer = fixQuotes( - this.args.data.quoteState.buffer.split("\n")[0].replace(/^\* /, "") - ); - - rows.some((row, index) => { - if (row.length && row.includes(buffer)) { - bestIndex = index; - return true; - } - }); - - this.args.data.editPost(this.post); - - document - .querySelector("#reply-control") - ?.addEventListener("transitionend", () => { - const textarea = document.querySelector(".d-editor-input"); - if (!textarea || this.isDestroyed || this.isDestroying) { - return; - } - - // best index brings us to one row before as slice start from 1 - // we add 1 to be at the beginning of next line, unless we start from top - setCaretPosition( - textarea, - rows.slice(0, bestIndex).join("\n").length + (bestIndex > 0 ? 1 : 0) - ); - - // ensures we correctly scroll to caret and reloads composer - // if we do another selection/edit - textarea.blur(); - textarea.focus(); - }); - - this.args.data.hideToolbar(); - return; - } - } - - @action - share(source) { - Sharing.shareSource(source, { - url: this.shareUrl, - title: this.topic.title, - quote: window.getSelection().toString(), - }); - } -} diff --git a/app/assets/javascripts/discourse/app/components/post-text-selection.gjs b/app/assets/javascripts/discourse/app/components/post-text-selection.gjs deleted file mode 100644 index 8165bde932d..00000000000 --- a/app/assets/javascripts/discourse/app/components/post-text-selection.gjs +++ /dev/null @@ -1,279 +0,0 @@ -import { - selectedNode, - selectedRange, - selectedText, -} from "discourse/lib/utilities"; -import { INPUT_DELAY } from "discourse-common/config/environment"; -import { action } from "@ember/object"; -import { bind } from "discourse-common/utils/decorators"; -import discourseDebounce from "discourse-common/lib/debounce"; -import toMarkdown from "discourse/lib/to-markdown"; -import escapeRegExp from "discourse-common/utils/escape-regexp"; -import virtualElementFromTextRange from "discourse/lib/virtual-element-from-text-range"; -import { inject as service } from "@ember/service"; -import Component from "@glimmer/component"; -import { modifier } from "ember-modifier"; -import PostTextSelectionToolbar from "discourse/components/post-text-selection-toolbar"; -import { cancel } from "@ember/runloop"; -import discourseLater from "discourse-common/lib/later"; - -function getQuoteTitle(element) { - const titleEl = element.querySelector(".title"); - if (!titleEl) { - return; - } - - const titleLink = titleEl.querySelector("a:not(.back)"); - if (titleLink) { - return titleLink.textContent.trim(); - } - - return titleEl.textContent.trim().replace(/:$/, ""); -} - -export function fixQuotes(str) { - // u+201c, u+201d = “ ” - // u+2018, u+2019 = ‘ ’ - return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'"); -} - -export default class PostTextSelection extends Component { - - - @service appEvents; - @service capabilities; - @service currentUser; - @service site; - @service siteSettings; - @service menu; - - prevSelection; - - runLoopHandlers = modifier(() => { - return () => { - cancel(this.selectionChangeHandler); - cancel(this.holdingMouseDownHandle); - }; - }); - - documentListeners = modifier(() => { - document.addEventListener("mousedown", this.mousedown, { passive: true }); - document.addEventListener("mouseup", this.mouseup, { passive: true }); - document.addEventListener("selectionchange", this.selectionchange); - - return () => { - document.removeEventListener("mousedown", this.mousedown); - document.removeEventListener("mouseup", this.mouseup); - document.removeEventListener("selectionchange", this.selectionchange); - }; - }); - - appEventsListeners = modifier(() => { - this.appEvents.on("quote-button:quote", this, "insertQuote"); - - return () => { - this.appEvents.off("quote-button:quote", this, "insertQuote"); - }; - }); - - willDestroy() { - super.willDestroy(...arguments); - - this.menuInstance?.destroy(); - cancel(this.selectionChangedHandler); - } - - @bind - async hideToolbar() { - this.args.quoteState.clear(); - await this.menuInstance?.close(); - } - - @bind - async selectionChanged() { - let supportsFastEdit = this.canEditPost; - const selection = window.getSelection(); - - if (selection.isCollapsed) { - return; - } - - // ensure we selected content inside 1 post *only* - let postId; - for (let r = 0; r < selection.rangeCount; r++) { - const range = selection.getRangeAt(r); - const selectionStart = - range.startContainer.nodeType === Node.ELEMENT_NODE - ? range.startContainer - : range.startContainer.parentElement; - const ancestor = - range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE - ? range.commonAncestorContainer - : range.commonAncestorContainer.parentElement; - - if (!selectionStart.closest(".cooked")) { - return await this.hideToolbar(); - } - - postId ||= ancestor.closest(".boxed, .reply")?.dataset?.postId; - - if (!ancestor.closest(".contents") || !postId) { - return await this.hideToolbar(); - } - } - - const _selectedElement = - selectedNode().nodeType === Node.ELEMENT_NODE - ? selectedNode() - : selectedNode().parentElement; - const _selectedText = selectedText(); - const cooked = - _selectedElement.querySelector(".cooked") || - _selectedElement.closest(".cooked"); - - // computing markdown takes a lot of time on long posts - // this code attempts to compute it only when we can't fast track - let opts = { - full: - selectedRange().startOffset > 0 - ? false - : _selectedText === toMarkdown(cooked.innerHTML), - }; - - for ( - let element = _selectedElement; - element && element.tagName !== "ARTICLE"; - element = element.parentElement - ) { - if (element.tagName === "ASIDE" && element.classList.contains("quote")) { - opts.username = element.dataset.username || getQuoteTitle(element); - opts.post = element.dataset.post; - opts.topic = element.dataset.topic; - break; - } - } - - const quoteState = this.args.quoteState; - quoteState.selected(postId, _selectedText, opts); - - if (this.canEditPost) { - const regexp = new RegExp(escapeRegExp(quoteState.buffer), "gi"); - const matches = cooked.innerHTML.match(regexp); - const non_ascii_regex = /[^\x00-\x7F]/; - - if ( - quoteState.buffer.length === 0 || - quoteState.buffer.includes("|") || // tables are too complex - quoteState.buffer.match(/\n/g) || // linebreaks are too complex - matches?.length > 1 || // duplicates are too complex - non_ascii_regex.test(quoteState.buffer) // non-ascii chars break fast-edit - ) { - supportsFastEdit = false; - } else if (matches?.length === 1) { - supportsFastEdit = true; - } - } - - // avoid hard loops in quote selection unconditionally - // this can happen if you triple click text in firefox - if (this.menuInstance?.expanded && this.prevSelection === _selectedText) { - return; - } - - this.prevSelection = _selectedText; - - // on Desktop, shows the button at the beginning of the selection - // on Mobile, shows the button at the end of the selection - const { isIOS, isAndroid, isOpera } = this.capabilities; - const showAtEnd = this.site.isMobileDevice || isIOS || isAndroid || isOpera; - const options = { - component: PostTextSelectionToolbar, - inline: true, - placement: showAtEnd ? "bottom-start" : "top-start", - fallbackPlacements: showAtEnd - ? ["bottom-end", "top-start"] - : ["bottom-start"], - offset: showAtEnd ? 25 : 3, - trapTab: false, - data: { - canEditPost: this.canEditPost, - editPost: this.args.editPost, - supportsFastEdit, - topic: this.args.topic, - quoteState, - insertQuote: this.insertQuote, - hideToolbar: this.hideToolbar, - }, - }; - - this.menuInstance?.destroy(); - - this.menuInstance = await this.menu.show( - virtualElementFromTextRange(), - options - ); - } - - @bind - onSelectionChanged() { - const { isIOS, isWinphone, isAndroid } = this.capabilities; - const wait = isIOS || isWinphone || isAndroid ? INPUT_DELAY : 100; - this.selectionChangedHandler = discourseDebounce( - this, - this.selectionChanged, - wait - ); - } - - @bind - async mousedown() { - this.isMousedown = true; - this.holdingMouseDown = false; - this.holdingMouseDownHandler = discourseLater(() => { - this.holdingMouseDown = true; - }, 100); - } - - @bind - async mouseup() { - this.prevSelection = null; - this.isMousedown = false; - - if (this.holdingMouseDown) { - this.onSelectionChanged(); - } - } - - @bind - selectionchange() { - cancel(this.selectionChangeHandler); - this.selectionChangeHandler = discourseLater(() => { - if (!this.isMousedown) { - this.onSelectionChanged(); - } - }, 100); - } - - get post() { - return this.args.topic.postStream.findLoadedPost( - this.args.quoteState.postId - ); - } - - get canEditPost() { - return this.siteSettings.enable_fast_edit && this.post?.can_edit; - } - - @action - async insertQuote() { - await this.args.selectText(); - await this.hideToolbar(); - } -} diff --git a/app/assets/javascripts/discourse/app/components/quote-button.hbs b/app/assets/javascripts/discourse/app/components/quote-button.hbs new file mode 100644 index 00000000000..bb4ab12704e --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/quote-button.hbs @@ -0,0 +1,71 @@ +
+
+ {{#if this.embedQuoteButton}} + + {{/if}} + + {{#if this.canEditPost}} + + {{/if}} + + {{#if this.quoteSharingEnabled}} + + {{#if this.quoteSharingShowLabel}} + + {{/if}} + + + {{#each this.quoteSharingSources as |source|}} + + {{/each}} + + + + + {{/if}} +
+ +
+ {{#if this.displayFastEditInput}} + + {{/if}} + + +
+
\ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/quote-button.js b/app/assets/javascripts/discourse/app/components/quote-button.js new file mode 100644 index 00000000000..f6d449bb2a6 --- /dev/null +++ b/app/assets/javascripts/discourse/app/components/quote-button.js @@ -0,0 +1,442 @@ +import Component from "@glimmer/component"; +import { tracked } from "@glimmer/tracking"; +import { ajax } from "discourse/lib/ajax"; +import { + postUrl, + selectedNode, + selectedRange, + selectedText, + setCaretPosition, +} from "discourse/lib/utilities"; +import { INPUT_DELAY } from "discourse-common/config/environment"; +import Sharing from "discourse/lib/sharing"; +import { action } from "@ember/object"; +import { bind } from "discourse-common/utils/decorators"; +import discourseDebounce from "discourse-common/lib/debounce"; +import { getAbsoluteURL } from "discourse-common/lib/get-url"; +import { next, schedule } from "@ember/runloop"; +import toMarkdown from "discourse/lib/to-markdown"; +import escapeRegExp from "discourse-common/utils/escape-regexp"; +import { createPopper } from "@popperjs/core"; +import virtualElementFromTextRange from "discourse/lib/virtual-element-from-text-range"; +import { inject as service } from "@ember/service"; +import FastEditModal from "discourse/components/modal/fast-edit"; + +function getQuoteTitle(element) { + const titleEl = element.querySelector(".title"); + if (!titleEl) { + return; + } + + const titleLink = titleEl.querySelector("a:not(.back)"); + if (titleLink) { + return titleLink.textContent.trim(); + } + + return titleEl.textContent.trim().replace(/:$/, ""); +} + +export function fixQuotes(str) { + // u+201c, u+201d = “ ” + // u+2018, u+2019 = ‘ ’ + return str.replace(/[\u201C\u201D]/g, '"').replace(/[\u2018\u2019]/g, "'"); +} + +export default class QuoteButton extends Component { + @service appEvents; + @service capabilities; + @service currentUser; + @service modal; + @service site; + @service siteSettings; + + @tracked visible = false; + @tracked animated = false; + @tracked isFastEditable = false; + @tracked displayFastEditInput = false; + @tracked fastEditInitialSelection; + + isMouseDown = false; + reselected = false; + prevSelection; + element; + popper; + popperPlacement = "top-start"; + popperOffset = [0, 3]; + + @bind + hideButton() { + this.args.quoteState.clear(); + + this.visible = false; + this.animated = false; + this.isFastEditable = false; + this.displayFastEditInput = false; + this.fastEditInitialSelection = null; + + this.teardownSelectionListeners(); + } + + selectionChanged() { + if (this.displayFastEditInput) { + this.textRange = virtualElementFromTextRange(); + return; + } + + const selection = window.getSelection(); + if (selection.isCollapsed) { + if (this.visible) { + this.hideButton(); + } + return; + } + + // ensure we selected content inside 1 post *only* + let postId; + for (let r = 0; r < selection.rangeCount; r++) { + const range = selection.getRangeAt(r); + const selectionStart = + range.startContainer.nodeType === Node.ELEMENT_NODE + ? range.startContainer + : range.startContainer.parentElement; + const ancestor = + range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE + ? range.commonAncestorContainer + : range.commonAncestorContainer.parentElement; + + if (!selectionStart.closest(".cooked")) { + return; + } + + postId ||= ancestor.closest(".boxed, .reply")?.dataset?.postId; + + if (!ancestor.closest(".contents") || !postId) { + if (this.visible) { + this.hideButton(); + } + return; + } + } + + const _selectedElement = + selectedNode().nodeType === Node.ELEMENT_NODE + ? selectedNode() + : selectedNode().parentElement; + const _selectedText = selectedText(); + const cooked = + _selectedElement.querySelector(".cooked") || + _selectedElement.closest(".cooked"); + + // computing markdown takes a lot of time on long posts + // this code attempts to compute it only when we can't fast track + let opts = { + full: + selectedRange().startOffset > 0 + ? false + : _selectedText === toMarkdown(cooked.innerHTML), + }; + + for ( + let element = _selectedElement; + element && element.tagName !== "ARTICLE"; + element = element.parentElement + ) { + if (element.tagName === "ASIDE" && element.classList.contains("quote")) { + opts.username = element.dataset.username || getQuoteTitle(element); + opts.post = element.dataset.post; + opts.topic = element.dataset.topic; + break; + } + } + + const quoteState = this.args.quoteState; + quoteState.selected(postId, _selectedText, opts); + this.visible = quoteState.buffer.length > 0; + + if (this.canEditPost) { + const regexp = new RegExp(escapeRegExp(quoteState.buffer), "gi"); + const matches = cooked.innerHTML.match(regexp); + const non_ascii_regex = /[^\x00-\x7F]/; + + if ( + quoteState.buffer.length === 0 || + quoteState.buffer.includes("|") || // tables are too complex + quoteState.buffer.match(/\n/g) || // linebreaks are too complex + matches?.length > 1 || // duplicates are too complex + non_ascii_regex.test(quoteState.buffer) // non-ascii chars break fast-edit + ) { + this.isFastEditable = false; + this.fastEditInitialSelection = null; + } else if (matches?.length === 1) { + this.isFastEditable = true; + this.fastEditInitialSelection = quoteState.buffer; + } + } + + // avoid hard loops in quote selection unconditionally + // this can happen if you triple click text in firefox + if (this.prevSelection === _selectedText) { + return; + } + + this.prevSelection = _selectedText; + + // on Desktop, shows the button at the beginning of the selection + // on Mobile, shows the button at the end of the selection + const isMobileDevice = this.site.isMobileDevice; + const { isIOS, isAndroid, isOpera } = this.capabilities; + const showAtEnd = isMobileDevice || isIOS || isAndroid || isOpera; + + if (showAtEnd) { + this.popperPlacement = "bottom-start"; + this.popperOffset = [0, 25]; + } + + // change the position of the button + schedule("afterRender", () => { + if (!this.element || this.isDestroying || this.isDestroyed) { + return; + } + + this.textRange = virtualElementFromTextRange(); + this.setupSelectionListeners(); + + this.popper = createPopper(this.textRange, this.element, { + placement: this.popperPlacement, + modifiers: [ + { + name: "computeStyles", + options: { + adaptive: false, + }, + }, + { + name: "offset", + options: { + offset: this.popperOffset, + }, + }, + ], + }); + + if (!this.animated) { + // We only enable CSS transitions after the initial positioning + // otherwise the button can appear to fly in from off-screen + next(() => (this.animated = true)); + } + }); + } + + @bind + updateRect() { + this.textRange?.updateRect(); + } + + setupSelectionListeners() { + document.body.addEventListener("mouseup", this.updateRect); + window.addEventListener("scroll", this.updateRect); + document.scrollingElement.addEventListener("scroll", this.updateRect); + } + + teardownSelectionListeners() { + document.body.removeEventListener("mouseup", this.updateRect); + window.removeEventListener("scroll", this.updateRect); + document.scrollingElement.removeEventListener("scroll", this.updateRect); + } + + @bind + onSelectionChanged() { + const { isWinphone, isAndroid } = this.capabilities; + const wait = isWinphone || isAndroid ? INPUT_DELAY : 25; + discourseDebounce(this, this.selectionChanged, wait); + } + + @bind + mousedown(e) { + this.prevSelection = null; + this.isMouseDown = true; + this.reselected = false; + + // prevents fast-edit input event from triggering mousedown + if (e.target.classList.contains("fast-edit-input")) { + return; + } + + if (!e.target.closest(".quote-button, .create, .share, .reply-new")) { + this.hideButton(); + } + } + + @bind + mouseup(e) { + // prevents fast-edit input event from triggering mouseup + if (e.target.classList.contains("fast-edit-input")) { + return; + } + + this.prevSelection = null; + this.isMouseDown = false; + this.onSelectionChanged(); + } + + @bind + selectionchange() { + if (!this.isMouseDown && !this.reselected) { + this.onSelectionChanged(); + } + } + + @action + didInsert(element) { + this.element = element; + + document.addEventListener("mousedown", this.mousedown); + document.addEventListener("mouseup", this.mouseup); + document.addEventListener("selectionchange", this.selectionchange); + + this.appEvents.on("quote-button:quote", this, "insertQuote"); + this.appEvents.on("quote-button:edit", this, "toggleFastEditForm"); + } + + willDestroy() { + super.willDestroy(...arguments); + this.popper?.destroy(); + + document.removeEventListener("mousedown", this.mousedown); + document.removeEventListener("mouseup", this.mouseup); + document.removeEventListener("selectionchange", this.selectionchange); + + this.appEvents.off("quote-button:quote", this, "insertQuote"); + this.appEvents.off("quote-button:edit", this, "toggleFastEditForm"); + this.teardownSelectionListeners(); + } + + get post() { + return this.args.topic.postStream.findLoadedPost( + this.args.quoteState.postId + ); + } + + get quoteSharingEnabled() { + return ( + this.site.desktopView && + this.quoteSharingSources.length > 0 && + !this.args.topic.invisible && + !this.args.topic.category?.read_restricted && + (this.siteSettings.share_quote_visibility === "all" || + (this.siteSettings.share_quote_visibility === "anonymous" && + !this.currentUser)) + ); + } + + get quoteSharingSources() { + return Sharing.activeSources( + this.siteSettings.share_quote_buttons, + this.siteSettings.login_required || this.args.topic.isPrivateMessage + ); + } + + get quoteSharingShowLabel() { + return this.quoteSharingSources.length > 1; + } + + get shareUrl() { + return getAbsoluteURL( + postUrl(this.args.topic.slug, this.args.topic.id, this.post.post_number) + ); + } + + get embedQuoteButton() { + const canCreatePost = this.args.topic.details.can_create_post; + const canReplyAsNewTopic = this.args.topic.details.can_reply_as_new_topic; + + return ( + (canCreatePost || canReplyAsNewTopic) && + this.currentUser?.get("user_option.enable_quoting") + ); + } + + get canEditPost() { + return this.siteSettings.enable_fast_edit && this.post?.can_edit; + } + + @action + async insertQuote() { + await this.args.selectText(); + this.hideButton(); + } + + @action + async toggleFastEditForm() { + if (this.isFastEditable) { + if (this.site.desktopView) { + this.displayFastEditInput = !this.displayFastEditInput; + } else { + this.modal.show(FastEditModal, { + model: { + initialValue: this.fastEditInitialSelection, + post: this.post, + }, + }); + this.hideButton(); + } + + return; + } + + const result = await ajax(`/posts/${this.post.id}`); + + if (this.isDestroying || this.isDestroyed) { + return; + } + + let bestIndex = 0; + const rows = result.raw.split("\n"); + + // selecting even a part of the text of a list item will include + // "* " at the beginning of the buffer, we remove it to be able + // to find it in row + const buffer = fixQuotes( + this.args.quoteState.buffer.split("\n")[0].replace(/^\* /, "") + ); + + rows.some((row, index) => { + if (row.length && row.includes(buffer)) { + bestIndex = index; + return true; + } + }); + + this.args.editPost(this.post); + + document + .querySelector("#reply-control") + ?.addEventListener("transitionend", () => { + const textarea = document.querySelector(".d-editor-input"); + if (!textarea || this.isDestroyed || this.isDestroying) { + return; + } + + // best index brings us to one row before as slice start from 1 + // we add 1 to be at the beginning of next line, unless we start from top + setCaretPosition( + textarea, + rows.slice(0, bestIndex).join("\n").length + (bestIndex > 0 ? 1 : 0) + ); + + // ensures we correctly scroll to caret and reloads composer + // if we do another selection/edit + textarea.blur(); + textarea.focus(); + }); + } + + @action + share(source) { + Sharing.shareSource(source, { + url: this.shareUrl, + title: this.args.topic.title, + quote: window.getSelection().toString(), + }); + } +} diff --git a/app/assets/javascripts/discourse/app/components/sidebar/section.hbs b/app/assets/javascripts/discourse/app/components/sidebar/section.hbs index af578be224f..5ec274885a1 100644 --- a/app/assets/javascripts/discourse/app/components/sidebar/section.hbs +++ b/app/assets/javascripts/discourse/app/components/sidebar/section.hbs @@ -20,18 +20,13 @@ {{@headerLinkText}} - {{#if @indicatePublic}} - - {{d-icon "shield-alt"}}{{i18n - "sidebar.sections.global_section" - }} - + + {{d-icon "globe"}} + {{d-icon "shield-alt"}} + {{i18n "sidebar.sections.global_section"}} + + {{/if}} diff --git a/app/assets/javascripts/discourse/app/components/summary-box.hbs b/app/assets/javascripts/discourse/app/components/summary-box.hbs index d8053f2dfcc..5da801b60dc 100644 --- a/app/assets/javascripts/discourse/app/components/summary-box.hbs +++ b/app/assets/javascripts/discourse/app/components/summary-box.hbs @@ -50,15 +50,12 @@

{{i18n "summary.summarized_on" date=this.summarizedOn}} - - - <:trigger> - {{d-icon "info-circle"}} - - <:content> + + {{d-icon "info-circle"}} + {{i18n "summary.model_used" model=this.summarizedBy}} - - + +

{{#if this.outdated}} diff --git a/app/assets/javascripts/discourse/app/components/topic-timeline.js b/app/assets/javascripts/discourse/app/components/topic-timeline.js index 6477331c7a1..92c4f6d545a 100644 --- a/app/assets/javascripts/discourse/app/components/topic-timeline.js +++ b/app/assets/javascripts/discourse/app/components/topic-timeline.js @@ -52,7 +52,7 @@ export default class TopicTimeline extends Component { } @bind - addUserTip() { + addUserTip(element) { if (!this.currentUser) { return; } @@ -62,6 +62,7 @@ export default class TopicTimeline extends Component { titleText: I18n.t("user_tips.topic_timeline.title"), contentText: I18n.t("user_tips.topic_timeline.content"), reference: document.querySelector("div.timeline-scrollarea-wrapper"), + appendTo: element, placement: "left", }); } diff --git a/app/assets/javascripts/discourse/app/components/user-info.hbs b/app/assets/javascripts/discourse/app/components/user-info.hbs index bca19c789a2..812ccd20ce9 100644 --- a/app/assets/javascripts/discourse/app/components/user-info.hbs +++ b/app/assets/javascripts/discourse/app/components/user-info.hbs @@ -34,6 +34,7 @@ {{/if}} diff --git a/app/assets/javascripts/discourse/app/components/user-status-message.hbs b/app/assets/javascripts/discourse/app/components/user-status-message.hbs index 92844d381bd..630c42a8bbe 100644 --- a/app/assets/javascripts/discourse/app/components/user-status-message.hbs +++ b/app/assets/javascripts/discourse/app/components/user-status-message.hbs @@ -1,26 +1,25 @@ {{#if @status}} - - <:trigger> - {{emoji @status.emoji skipTitle=true}} - {{#if @showDescription}} - - {{@status.description}} - - {{/if}} - - <:content> - {{emoji @status.emoji skipTitle=true}} - + + {{emoji @status.emoji skipTitle=true}} + {{#if @showDescription}} + {{@status.description}} - {{#if this.until}} -
- {{this.until}} + {{/if}} + {{#if this.showTooltip}} + +
+ {{emoji @status.emoji skipTitle=true}} + + {{@status.description}} + + {{#if this.until}} +
+ {{this.until}} +
+ {{/if}}
- {{/if}} - -
+ + {{/if}} + {{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/components/user-status-message.js b/app/assets/javascripts/discourse/app/components/user-status-message.js index 6f857f562e5..18934c14907 100644 --- a/app/assets/javascripts/discourse/app/components/user-status-message.js +++ b/app/assets/javascripts/discourse/app/components/user-status-message.js @@ -1,19 +1,21 @@ -import Component from "@glimmer/component"; +import Component from "@ember/component"; +import { computed } from "@ember/object"; import { until } from "discourse/lib/formatter"; -import { inject as service } from "@ember/service"; export default class UserStatusMessage extends Component { - @service currentUser; + tagName = ""; + showTooltip = true; + @computed("status.ends_at") get until() { - if (!this.args.status.ends_at) { - return; + if (!this.status.ends_at) { + return null; } const timezone = this.currentUser ? this.currentUser.user_option?.timezone : moment.tz.guess(); - return until(this.args.status.ends_at, timezone, this.currentUser?.locale); + return until(this.status.ends_at, timezone, this.currentUser?.locale); } } diff --git a/app/assets/javascripts/discourse/app/components/user-tip-container.gjs b/app/assets/javascripts/discourse/app/components/user-tip-container.gjs deleted file mode 100644 index 258f1b5a06d..00000000000 --- a/app/assets/javascripts/discourse/app/components/user-tip-container.gjs +++ /dev/null @@ -1,40 +0,0 @@ -import { htmlSafe } from "@ember/template"; -import Component from "@glimmer/component"; -import DButton from "discourse/components/d-button"; -import { action } from "@ember/object"; - -export default class UserTipContainer extends Component { - - - get safeHtmlContent() { - return htmlSafe(this.args.data.contentHtml); - } - - @action - handleDismiss(_, event) { - event.preventDefault(); - this.args.close(); - this.args.data.onDismiss(); - } -} diff --git a/app/assets/javascripts/discourse/app/components/user-tip.js b/app/assets/javascripts/discourse/app/components/user-tip.js index aabfebec11a..fdf78b8e0cc 100644 --- a/app/assets/javascripts/discourse/app/components/user-tip.js +++ b/app/assets/javascripts/discourse/app/components/user-tip.js @@ -37,6 +37,7 @@ export default class UserTip extends Component { buttonIcon, reference: (selector && element.parentElement.querySelector(selector)) || element, + appendTo: element.parentElement, placement, onDismiss, }); diff --git a/app/assets/javascripts/discourse/app/helpers/noop.js b/app/assets/javascripts/discourse/app/helpers/noop.js deleted file mode 100644 index b09b41e3c6b..00000000000 --- a/app/assets/javascripts/discourse/app/helpers/noop.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function noop() { - return () => {}; -} diff --git a/app/assets/javascripts/discourse/app/helpers/unique-id.js b/app/assets/javascripts/discourse/app/helpers/unique-id.js deleted file mode 100644 index a1b3cef924c..00000000000 --- a/app/assets/javascripts/discourse/app/helpers/unique-id.js +++ /dev/null @@ -1,10 +0,0 @@ -// https://github.com/emberjs/ember.js/blob/master/packages/@ember/-internals/glimmer/lib/helpers/unique-id.ts -export default function uniqueId() { - return ([3e7] + -1e3 + -4e3 + -2e3 + -1e11).replace( - /[0-3]/g, - (a) => - /* eslint-disable no-bitwise */ - ((a * 4) ^ ((Math.random() * 16) >> (a & 2))).toString(16) - /* eslint-enable no-bitwise */ - ); -} diff --git a/app/assets/javascripts/discourse/app/instance-initializers/d-popover.js b/app/assets/javascripts/discourse/app/instance-initializers/d-popover.js new file mode 100644 index 00000000000..2d11e739323 --- /dev/null +++ b/app/assets/javascripts/discourse/app/instance-initializers/d-popover.js @@ -0,0 +1,17 @@ +import { showPopover } from "discourse/lib/d-popover"; + +export default { + initialize() { + ["click", "mouseover"].forEach((eventType) => { + document.addEventListener(eventType, (e) => { + if (e.target.dataset.tooltip || e.target.dataset.popover) { + showPopover(e, { + interactive: false, + content: (reference) => + reference.dataset.tooltip || reference.dataset.popover, + }); + } + }); + }); + }, +}; diff --git a/app/assets/javascripts/discourse/app/lib/d-popover.js b/app/assets/javascripts/discourse/app/lib/d-popover.js index 7a10d17ad14..42bea264b69 100644 --- a/app/assets/javascripts/discourse/app/lib/d-popover.js +++ b/app/assets/javascripts/discourse/app/lib/d-popover.js @@ -1,13 +1,74 @@ -import deprecated from "discourse-common/lib/deprecated"; +import tippy from "tippy.js"; +import { iconHTML } from "discourse-common/lib/icon-library"; -export function showPopover() { - deprecated("`showPopover` is deprecated. Use tooltip service instead.", { - id: "show-popover", - }); +export const hideOnEscapePlugin = { + name: "hideOnEscape", + + defaultValue: true, + + fn({ hide }) { + function onKeyDown(event) { + if (event.keyCode === 27) { + hide(); + } + } + + return { + onShow() { + document.addEventListener("keydown", onKeyDown); + }, + onHide() { + document.removeEventListener("keydown", onKeyDown); + }, + }; + }, +}; + +export function isPopoverShown(event) { + const instance = event.target._tippy; + return instance?.state.isShown; } -export function hidePopover() { - deprecated("`hidePopover` is deprecated. Use tooltip service instead.", { - id: "hide-popover", - }); +// legacy, shouldn't be needed with setup +export function hidePopover(event) { + const instance = event.target._tippy; + + if (instance?.state.isShown) { + instance.hide(); + } +} + +// legacy, setup() should be used +export function showPopover(event, options = {}) { + const instance = event.target._tippy ?? setup(event.target, options); + + if (instance.state.isShown) { + instance.hide(); + } else { + instance.show(); + } +} + +// target is the element that triggers the display of the popover +// options accepts all tippy.js options as defined in their documentation +// https://atomiks.github.io/tippyjs/v6/all-props/ +export default function setup(target, options) { + const tippyOptions = Object.assign( + { + arrow: iconHTML("tippy-rounded-arrow"), + content: options.textContent || options.htmlContent, + allowHTML: options?.htmlContent?.length, + trigger: "mouseenter click", + hideOnClick: true, + zIndex: 1400, + plugins: [hideOnEscapePlugin], + touch: ["hold", 500], + }, + options + ); + + // legacy support delete tippyOptions.textContent; + delete tippyOptions.htmlContent; + + return tippy(target, tippyOptions); } diff --git a/app/assets/javascripts/discourse/app/lib/d-tooltip.js b/app/assets/javascripts/discourse/app/lib/d-tooltip.js new file mode 100644 index 00000000000..5ef2a65022b --- /dev/null +++ b/app/assets/javascripts/discourse/app/lib/d-tooltip.js @@ -0,0 +1,48 @@ +import tippy from "tippy.js"; +import { bind } from "discourse-common/utils/decorators"; +import discourseDebounce from "discourse-common/lib/debounce"; + +export class DTooltip { + #tippyInstance; + + constructor(target, content) { + this.#tippyInstance = this.#initTippy(target, content); + if (this.#hasTouchCapabilities()) { + window.addEventListener("scroll", this.onScroll); + } + } + + destroy() { + if (this.#hasTouchCapabilities()) { + window.removeEventListener("scroll", this.onScroll); + } + this.#tippyInstance.destroy(); + } + + @bind + onScroll() { + discourseDebounce(() => this.#tippyInstance.hide(), 10); + } + + #initTippy(target, content) { + return tippy(target, { + interactive: false, + content, + trigger: this.#hasTouchCapabilities() ? "click" : "mouseenter", + theme: "d-tooltip", + arrow: false, + placement: "bottom-start", + onTrigger: this.#stopPropagation, + onUntrigger: this.#stopPropagation, + }); + } + + #hasTouchCapabilities() { + return navigator.maxTouchPoints > 1 || "ontouchstart" in window; + } + + #stopPropagation(instance, event) { + event.preventDefault(); + event.stopPropagation(); + } +} diff --git a/app/assets/javascripts/discourse/app/lib/discourse-location.js b/app/assets/javascripts/discourse/app/lib/discourse-location.js index 4d408100cf3..39a18a7fbd3 100644 --- a/app/assets/javascripts/discourse/app/lib/discourse-location.js +++ b/app/assets/javascripts/discourse/app/lib/discourse-location.js @@ -2,7 +2,6 @@ import EmberObject from "@ember/object"; import { defaultHomepage } from "discourse/lib/utilities"; import { guidFor } from "@ember/object/internals"; import { withoutPrefix } from "discourse-common/lib/get-url"; - let popstateFired = false; const supportsHistoryState = window.history && "state" in window.history; const popstateCallbacks = []; diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index d8724884755..76e076fcc36 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -134,8 +134,7 @@ import { addBeforeAuthCompleteCallback } from "discourse/instance-initializers/a // based on Semantic Versioning 2.0.0. Please update the changelog at // docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version // using the format described at https://keepachangelog.com/en/1.0.0/. - -export const PLUGIN_API_VERSION = "1.12.0"; +export const PLUGIN_API_VERSION = "1.11.0"; // This helper prevents us from applying the same `modifyClass` over and over in test mode. function canModify(klass, type, resolverName, changes) { @@ -641,30 +640,6 @@ class PluginApi { addButton(name, callback); } - /** - * Add a new button in the post admin menu. - * - * Example: - * - * ``` - * api.addPostAdminMenuButton((name, attrs) => { - * return { - * action: () => { - * alert('You clicked on the coffee button!'); - * }, - * icon: 'coffee', - * className: 'hot-coffee', - * title: 'coffee.title', - * }; - * }); - * ``` - **/ - addPostAdminMenuButton(name, callback) { - this.container - .lookup("service:admin-post-menu-buttons") - .addButton(name, callback); - } - /** * Remove existing button below a post with your plugin. * diff --git a/app/assets/javascripts/discourse/app/lib/update-user-status-on-mention.js b/app/assets/javascripts/discourse/app/lib/update-user-status-on-mention.js index 2a1e4c1f1b9..a52afb06fb3 100644 --- a/app/assets/javascripts/discourse/app/lib/update-user-status-on-mention.js +++ b/app/assets/javascripts/discourse/app/lib/update-user-status-on-mention.js @@ -1,24 +1,22 @@ import { UserStatusMessage } from "discourse/lib/user-status-message"; -import { guidFor } from "@ember/object/internals"; -const userStatusMessages = {}; +let userStatusMessages = []; -export function updateUserStatusOnMention(owner, mention, status) { +export function updateUserStatusOnMention(mention, status) { removeStatus(mention); if (status) { - const userStatusMessage = new UserStatusMessage(owner, status); - userStatusMessages[guidFor(mention)] = userStatusMessage; + const userStatusMessage = new UserStatusMessage(status); + userStatusMessages.push(userStatusMessage); mention.appendChild(userStatusMessage.html); } } export function destroyUserStatusOnMentions() { - Object.values(userStatusMessages).forEach((instance) => { + userStatusMessages.forEach((instance) => { instance.destroy(); }); } function removeStatus(mention) { - userStatusMessages[guidFor(mention)]?.destroy(); mention.querySelector("span.user-status-message")?.remove(); } diff --git a/app/assets/javascripts/discourse/app/lib/user-status-message.js b/app/assets/javascripts/discourse/app/lib/user-status-message.js index a3ba98f36ce..2148c036a39 100644 --- a/app/assets/javascripts/discourse/app/lib/user-status-message.js +++ b/app/assets/javascripts/discourse/app/lib/user-status-message.js @@ -1,27 +1,19 @@ +import { DTooltip } from "discourse/lib/d-tooltip"; import { emojiUnescape } from "discourse/lib/text"; import { escapeExpression } from "discourse/lib/utilities"; import { until } from "discourse/lib/formatter"; import User from "discourse/models/user"; -import { setOwner } from "@ember/application"; -import { inject as service } from "@ember/service"; export class UserStatusMessage { - @service tooltip; + #dTooltip; - html = null; - content = null; - - constructor(owner, status, opts) { - setOwner(this, owner); + constructor(status, opts) { this.html = this.#statusHtml(status, opts); - this.content = this.#tooltipHtml(status); - this.tooltipInstance = this.tooltip.register(this.html, { - content: this.content, - }); + this.#dTooltip = new DTooltip(this.html, this.#tooltipHtml(status)); } destroy() { - this.tooltipInstance.destroy(); + this.#dTooltip.destroy(); } #emojiHtml(emojiName) { diff --git a/app/assets/javascripts/discourse/app/lib/user-status-on-autocomplete.js b/app/assets/javascripts/discourse/app/lib/user-status-on-autocomplete.js index 1facca9cbda..b416aa7ab3f 100644 --- a/app/assets/javascripts/discourse/app/lib/user-status-on-autocomplete.js +++ b/app/assets/javascripts/discourse/app/lib/user-status-on-autocomplete.js @@ -2,11 +2,11 @@ import { UserStatusMessage } from "discourse/lib/user-status-message"; let userStatusMessages = []; -export function initUserStatusHtml(owner, users) { +export function initUserStatusHtml(users) { (users || []).forEach((user, index) => { if (user.status) { user.index = index; - const userStatusMessage = new UserStatusMessage(owner, user.status, { + const userStatusMessage = new UserStatusMessage(user.status, { showDescription: true, }); user.statusHtml = userStatusMessage.html; diff --git a/app/assets/javascripts/discourse/app/lib/virtual-element-from-text-range.js b/app/assets/javascripts/discourse/app/lib/virtual-element-from-text-range.js index f2e499d2078..c2ada2c96b0 100644 --- a/app/assets/javascripts/discourse/app/lib/virtual-element-from-text-range.js +++ b/app/assets/javascripts/discourse/app/lib/virtual-element-from-text-range.js @@ -19,10 +19,6 @@ class VirtualElementFromTextRange { return this.rect; } - getClientRects() { - return this.range.getClientRects(); - } - get clientWidth() { return this.rect.width; } diff --git a/app/assets/javascripts/discourse/app/loader-shims.js b/app/assets/javascripts/discourse/app/loader-shims.js index de672af9b20..92cf12d4f97 100644 --- a/app/assets/javascripts/discourse/app/loader-shims.js +++ b/app/assets/javascripts/discourse/app/loader-shims.js @@ -8,7 +8,6 @@ loaderShim("@ember-compat/tracked-built-ins", () => importSync("@ember-compat/tracked-built-ins") ); loaderShim("@popperjs/core", () => importSync("@popperjs/core")); -loaderShim("@floating-ui/dom", () => importSync("@floating-ui/dom")); loaderShim("@uppy/aws-s3", () => importSync("@uppy/aws-s3")); loaderShim("@uppy/aws-s3-multipart", () => importSync("@uppy/aws-s3-multipart") @@ -28,5 +27,6 @@ loaderShim("ember-modifier", () => importSync("ember-modifier")); loaderShim("handlebars", () => importSync("handlebars")); loaderShim("js-yaml", () => importSync("js-yaml")); loaderShim("message-bus-client", () => importSync("message-bus-client")); +loaderShim("tippy.js", () => importSync("tippy.js")); loaderShim("virtual-dom", () => importSync("virtual-dom")); loaderShim("xss", () => importSync("xss")); diff --git a/app/assets/javascripts/discourse/app/mixins/card-contents-base.js b/app/assets/javascripts/discourse/app/mixins/card-contents-base.js index 218245c26fb..08c9ba26eee 100644 --- a/app/assets/javascripts/discourse/app/mixins/card-contents-base.js +++ b/app/assets/javascripts/discourse/app/mixins/card-contents-base.js @@ -7,6 +7,7 @@ import { inject as service } from "@ember/service"; import { wantsNewWindow } from "discourse/lib/intercept-click"; import { bind } from "discourse-common/utils/decorators"; import discourseLater from "discourse-common/lib/later"; +import { createPopper } from "@popperjs/core"; import { headerOffset } from "discourse/lib/offset-calculator"; const DEFAULT_SELECTOR = "#main-outlet"; @@ -23,7 +24,6 @@ export function resetCardClickListenerSelector() { export default Mixin.create({ router: service(), - menu: service(), elementId: null, //click detection added for data-{elementId} triggeringLinkClass: null, //the classname where this card should appear @@ -39,7 +39,7 @@ export default Mixin.create({ post: null, isDocked: false, - _menuInstance: null, + _popperReference: null, _show(username, target, event) { // No user card for anon @@ -85,6 +85,7 @@ export default Mixin.create({ this.appEvents.trigger("user-card:show", { username }); this._showCallback(username, $(target)).then((user) => { this.appEvents.trigger("user-card:after-show", { user }); + this._positionCard($(target), event); }); // We bind scrolling on mobile after cards are shown to hide them if user scrolls @@ -188,35 +189,57 @@ export default Mixin.create({ return this._show($target.text().replace(/^@/, ""), $target); }, - _positionCard(target) { - schedule("afterRender", async () => { + _positionCard(target, event) { + this._popperReference?.destroy(); + + schedule("afterRender", () => { if (!target) { return; } - const avatarOverflowSize = 44; if (this.site.desktopView) { - this._menuInstance = await this.menu.show(target[0], { - content: this.element, - autoUpdate: false, - identifier: "card", - padding: { - top: 10 + avatarOverflowSize + headerOffset(), - right: 10, - bottom: 10, - left: 10, - }, + const avatarOverflowSize = 44; + this._popperReference = createPopper(target[0], this.element, { + placement: "right", + modifiers: [ + { + name: "preventOverflow", + options: { + padding: { + top: headerOffset() + avatarOverflowSize, + right: 10, + bottom: 10, + left: 10, + }, + }, + }, + { name: "eventListeners", enabled: false }, + { name: "offset", options: { offset: [10, 10] } }, + ], }); } else { - this._menuInstance = await this.menu.show(target[0], { - content: this.element, - strategy: "fixed", - identifier: "card", - computePosition: (content) => { - content.style.left = "10px"; - content.style.right = "10px"; - content.style.top = 10 + avatarOverflowSize + "px"; - }, + this._popperReference = createPopper(target[0], this.element, { + modifiers: [ + { name: "eventListeners", enabled: false }, + { + name: "computeStyles", + enabled: true, + fn({ state }) { + // mimics our modal top of the screen positioning + state.styles.popper = { + ...state.styles.popper, + position: "fixed", + left: `${ + (window.innerWidth - state.rects.popper.width) / 2 + }px`, + top: "10%", + transform: "translateY(-10%)", + }; + + return state; + }, + }, + ], }); } @@ -238,12 +261,11 @@ export default Mixin.create({ @bind _hide() { if (!this.visible) { + $(this.element).css({ left: -9999, top: -9999 }); if (this.site.mobileView) { $(".card-cloak").addClass("hidden"); } } - - this._menuInstance?.destroy(); }, _close() { diff --git a/app/assets/javascripts/discourse/app/modifiers/trap-tab.js b/app/assets/javascripts/discourse/app/modifiers/trap-tab.js deleted file mode 100644 index a7cd6b8c01e..00000000000 --- a/app/assets/javascripts/discourse/app/modifiers/trap-tab.js +++ /dev/null @@ -1,73 +0,0 @@ -import Modifier from "ember-modifier"; -import { registerDestructor } from "@ember/destroyable"; -import { bind } from "discourse-common/utils/decorators"; - -const FOCUSABLE_ELEMENTS = - 'details:not(.is-disabled) summary, [autofocus], a, input, select, textarea, summary, [tabindex]:not([tabindex="-1"])'; - -export default class TrapTabModifier extends Modifier { - element = null; - - constructor(owner, args) { - super(owner, args); - registerDestructor(this, (instance) => instance.cleanup()); - } - - modify(element, [options]) { - this.preventScroll = options?.preventScroll ?? true; - this.orignalElement = element; - this.element = element.querySelector(".modal-inner-container") || element; - this.orignalElement.addEventListener("keydown", this.trapTab); - - // on first trap we don't allow to focus modal-close - // and apply manual focus only if we don't have any autofocus element - const autofocusedElement = this.element.querySelector("[autofocus]"); - - if (!autofocusedElement || document.activeElement !== autofocusedElement) { - // if there's not autofocus, or the activeElement, is not the autofocusable element - // attempt to focus the first of the focusable elements or just the modal-body - // to make it possible to scroll with arrow down/up - ( - autofocusedElement || - this.element.querySelector( - FOCUSABLE_ELEMENTS + ", button:not(.modal-close)" - ) || - this.element.querySelector(".modal-body") - )?.focus({ - preventScroll: this.preventScroll, - }); - } - } - - @bind - trapTab(event) { - if (event.key !== "Tab") { - return; - } - - const focusableElements = FOCUSABLE_ELEMENTS + ", button:enabled"; - const firstFocusableElement = this.element.querySelector(focusableElements); - const focusableContent = this.element.querySelectorAll(focusableElements); - - const lastFocusableElement = focusableContent[focusableContent.length - 1]; - - if (event.shiftKey) { - if (document.activeElement === firstFocusableElement) { - lastFocusableElement?.focus(); - event.preventDefault(); - } - } else { - if (document.activeElement === lastFocusableElement) { - event.preventDefault(); - - ( - this.element.querySelector(".modal-close") || firstFocusableElement - )?.focus({ preventScroll: this.preventScroll }); - } - } - } - - cleanup() { - this.orignalElement.removeEventListener("keydown", this.trapTab); - } -} diff --git a/app/assets/javascripts/discourse/app/services/admin-post-menu-buttons.js b/app/assets/javascripts/discourse/app/services/admin-post-menu-buttons.js deleted file mode 100644 index 90c39c19135..00000000000 --- a/app/assets/javascripts/discourse/app/services/admin-post-menu-buttons.js +++ /dev/null @@ -1,10 +0,0 @@ -import Service from "@ember/service"; -import { tracked } from "@glimmer/tracking"; - -export default class AdminPostMenuButtons extends Service { - @tracked callbacks = []; - - addButton(callback) { - this.callbacks.push(callback); - } -} diff --git a/app/assets/javascripts/discourse/app/services/user-tips.js b/app/assets/javascripts/discourse/app/services/user-tips.js index 6ac5c5a5945..9de6f7e8b8d 100644 --- a/app/assets/javascripts/discourse/app/services/user-tips.js +++ b/app/assets/javascripts/discourse/app/services/user-tips.js @@ -1,20 +1,16 @@ -import { getOwner } from "discourse-common/lib/get-owner"; -import Service, { inject as service } from "@ember/service"; +import Service from "@ember/service"; import { isTesting } from "discourse-common/config/environment"; import { iconHTML } from "discourse-common/lib/icon-library"; import I18n from "I18n"; import { escape } from "pretty-text/sanitizer"; +import tippy from "tippy.js"; import isElementInViewport from "discourse/lib/is-element-in-viewport"; import discourseLater from "discourse-common/lib/later"; import { cancel } from "@ember/runloop"; -import DTooltipInstance from "float-kit/lib/d-tooltip-instance"; -import UserTipContainer from "discourse/components/user-tip-container"; -const DELAY = 500; +const TIPPY_DELAY = 500; export default class UserTips extends Service { - @service tooltip; - #instances = new Map(); /** @@ -24,6 +20,7 @@ export default class UserTips extends Service { * @param {string} [options.buttonLabel] * @param {string} [options.buttonIcon] * @param {string} [options.placement] + * @param {Element} [options.appendTo] * @param {string} [options.content] * @param {string} [options.contentText] * @param {string} [options.titleText] @@ -54,19 +51,42 @@ export default class UserTips extends Service { this.#instances.set( options.id, - new DTooltipInstance(getOwner(this), options.reference, { - identifier: "user-tip", - interactive: true, - closeOnScroll: false, - closeOnClickOutside: false, + tippy(options.reference, { + hideOnClick: false, + trigger: "manual", + theme: "user-tip", + zIndex: "", // reset z-index to use inherited value from the parent + duration: TIPPY_DELAY, + + arrow: iconHTML("tippy-rounded-arrow"), placement: options.placement, - component: UserTipContainer, - data: { - titleText: escape(options.titleText), - contentHtml: options.contentHtml || null, - contentText: options.contentText ? escape(options.contentText) : null, - onDismiss: options.onDismiss, - buttonText, + appendTo: options.appendTo, + + interactive: true, // for buttons in content + allowHTML: true, + + content: + options.content || + `
+
${escape(options.titleText)}
+
${ + options.contentHtml || escape(options.contentText) + }
+
+ +
+
`, + + onCreate(tippyInstance) { + // Used to set correct z-index property on root tippy element + tippyInstance.popper.classList.add("user-tip"); + + tippyInstance.popper + .querySelector(".btn") + .addEventListener("click", (event) => { + options.onDismiss?.(); + event.preventDefault(); + }); }, }) ); @@ -75,7 +95,7 @@ export default class UserTips extends Service { } hideTip(userTipId, force = false) { - // Instances are not destroyed immediately because sometimes their + // Tippy instances are not destroyed immediately because sometimes there // user tip is recreated immediately. This happens when Ember components // are re-rendered because a parent component has changed @@ -93,7 +113,7 @@ export default class UserTips extends Service { this.#destroyInstance(this.#instances.get(userTipId)); this.#instances.delete(userTipId); this.showNextTip(); - }, DELAY); + }, TIPPY_DELAY); } } @@ -107,7 +127,7 @@ export default class UserTips extends Service { showNextTip() { // Return early if a user tip is already visible and it is in viewport for (const tip of this.#instances.values()) { - if (tip.expanded && isElementInViewport(tip.trigger)) { + if (tip.state.isVisible && isElementInViewport(tip.reference)) { return; } } @@ -115,9 +135,8 @@ export default class UserTips extends Service { // Otherwise, try to find a user tip in the viewport let visibleTip; for (const tip of this.#instances.values()) { - if (isElementInViewport(tip.trigger)) { + if (isElementInViewport(tip.reference)) { visibleTip = tip; - break; } } @@ -158,18 +177,20 @@ export default class UserTips extends Service { #showInstance(instance) { if (isTesting()) { - this.tooltip.show(instance); + instance.show(); } else if (!instance.showTimer) { instance.showTimer = discourseLater(() => { instance.showTimer = null; - this.tooltip.show(instance); - }, DELAY); + if (!instance.state.isDestroyed) { + instance.show(); + } + }, TIPPY_DELAY); } } #hideInstance(instance) { cancel(instance.showTimer); instance.showTimer = null; - this.tooltip.close(instance); + instance.hide(); } } diff --git a/app/assets/javascripts/discourse/app/templates/application.hbs b/app/assets/javascripts/discourse/app/templates/application.hbs index 60ba0ca5faa..0a604ff204d 100644 --- a/app/assets/javascripts/discourse/app/templates/application.hbs +++ b/app/assets/javascripts/discourse/app/templates/application.hbs @@ -105,8 +105,4 @@ {{#if this.showFooterNav}} {{/if}} - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/assets/javascripts/discourse/app/templates/topic.hbs b/app/assets/javascripts/discourse/app/templates/topic.hbs index ff0f3a90501..c63b1a8bd56 100644 --- a/app/assets/javascripts/discourse/app/templates/topic.hbs +++ b/app/assets/javascripts/discourse/app/templates/topic.hbs @@ -593,7 +593,7 @@
{{/if}} - { + b.secondaryAction = "closeAdminMenu"; + contents.push(this.attach("post-admin-menu-button", b)); + } + ); + + return h("ul", contents); + }, + + clickOutside() { + this.sendWidgetAction("closeAdminMenu"); + }, +}); diff --git a/app/assets/javascripts/discourse/app/widgets/post-cooked.js b/app/assets/javascripts/discourse/app/widgets/post-cooked.js index d2433493f0c..1bf2993d4df 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-cooked.js +++ b/app/assets/javascripts/discourse/app/widgets/post-cooked.js @@ -13,7 +13,6 @@ import { destroyUserStatusOnMentions, updateUserStatusOnMention, } from "discourse/lib/update-user-status-on-mention"; -import { getOwner } from "discourse-common/lib/get-owner"; let _beforeAdoptDecorators = []; let _afterAdoptDecorators = []; @@ -397,7 +396,7 @@ export default class PostCooked { const mentions = postElement.querySelectorAll(`a.mention[href="${href}"]`); mentions.forEach((mention) => { - updateUserStatusOnMention(getOwner(this._post()), mention, user.status); + updateUserStatusOnMention(mention, user.status); }); } diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index 21671d93ae9..97570e78d16 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -12,9 +12,6 @@ import { } from "discourse/models/bookmark"; import { isTesting } from "discourse-common/config/environment"; import DeleteTopicDisallowedModal from "discourse/components/modal/delete-topic-disallowed"; -import RenderGlimmer from "discourse/widgets/render-glimmer"; -import { hbs } from "ember-cli-htmlbars"; -import AdminPostMenu from "discourse/components/admin-post-menu"; const LIKE_ACTION = 2; const VIBRATE_DURATION = 5; @@ -406,13 +403,11 @@ registerButton("admin", (attrs) => { if (!attrs.canManage && !attrs.canWiki && !attrs.canEditStaffNotes) { return; } - return { action: "openAdminMenu", title: "post.controls.admin", className: "show-post-admin-menu", icon: "wrench", - sendActionEvent: true, }; }); @@ -469,7 +464,7 @@ function _replaceButton(buttons, find, replace) { export default createWidget("post-menu", { tagName: "section.post-menu-area.clearfix", - services: ["modal", "menu"], + services: ["modal"], settings: { collapseButtons: true, @@ -482,67 +477,27 @@ export default createWidget("post-menu", { collapsed: true, likedUsers: [], readers: [], + adminVisible: false, }; }, buildKey: (attrs) => `post-menu-${attrs.id}`, attachButton(name) { - let buttonAttrs = buildButton(name, this); - - if (buttonAttrs?.component) { - return [ - new RenderGlimmer( - this, - buttonAttrs.tagName, - hbs`<@data.component - @permanentlyDeletePost={{@data.permanentlyDeletePost}} - @lockPost={{@data.lockPost}} - @unlockPost={{@data.unlockPost}} - @grantBadge={{@data.grantBadge}} - @rebakePost={{@data.rebakePost}} - @toggleWiki={{@data.toggleWiki}} - @changePostOwner={{@data.changePostOwner}} - @changeNotice={{@data.changeNotice}} - @togglePostType={{@data.togglePostType}} - @unhidePost={{@data.unhidePost}} - @showPagePublish={{@data.showPagePublish}} - @post={{@data.post}} - @transformedPost={{@data.transformedPost}} - @scheduleRerender={{@data.scheduleRerender}} - />`, - { - component: buttonAttrs.component, - transformedPost: this.attrs, - post: this.findAncestorModel(), - permanentlyDeletePost: () => - this.sendWidgetAction("permanentlyDeletePost"), - lockPost: () => this.sendWidgetAction("lockPost"), - unlockPost: () => this.sendWidgetAction("unlockPost"), - grantBadge: () => this.sendWidgetAction("grantBadge"), - rebakePost: () => this.sendWidgetAction("rebakePost"), - toggleWiki: () => this.sendWidgetAction("toggleWiki"), - changePostOwner: () => this.sendWidgetAction("changePostOwner"), - changeNotice: () => this.sendWidgetAction("changeNotice"), - togglePostType: () => this.sendWidgetAction("togglePostType"), - scheduleRerender: () => this.scheduleRerender(), - } - ), - ]; - } + let buttonAtts = buildButton(name, this); // If the button is replaced via the plugin API, we need to render the // replacement rather than a button - if (buttonAttrs?.replaced) { - return this.attach(buttonAttrs.name, buttonAttrs.attrs); + if (buttonAtts?.replaced) { + return this.attach(buttonAtts.name, buttonAtts.attrs); } - if (buttonAttrs) { - let button = this.attach(this.settings.buttonType, buttonAttrs); - if (buttonAttrs.before) { - let before = this.attachButton(buttonAttrs.before); + if (buttonAtts) { + let button = this.attach(this.settings.buttonType, buttonAtts); + if (buttonAtts.before) { + let before = this.attachButton(buttonAtts.before); return h("div.double-button", [before, button]); - } else if (buttonAttrs.addContainer) { + } else if (buttonAtts.addContainer) { return h("div.double-button", [button]); } @@ -635,18 +590,18 @@ export default createWidget("post-menu", { } if (shouldAddButton && builder) { - const buttonAttrs = builder( + const buttonAtts = builder( attrs, this.state, this.siteSettings, this.settings, this.currentUser ); - if (buttonAttrs) { - const { position, beforeButton, afterButton } = buttonAttrs; - delete buttonAttrs.position; + if (buttonAtts) { + const { position, beforeButton, afterButton } = buttonAtts; + delete buttonAtts.position; - let button = this.attach(this.settings.buttonType, buttonAttrs); + let button = this.attach(this.settings.buttonType, buttonAtts); const content = []; if (beforeButton) { @@ -711,6 +666,9 @@ export default createWidget("post-menu", { ]; postControls.push(h("div.actions", controlsButtons)); + if (state.adminVisible) { + postControls.push(this.attach("post-admin-menu", attrs)); + } const contents = [ h( @@ -770,28 +728,12 @@ export default createWidget("post-menu", { return contents; }, - openAdminMenu(event) { - this.menu.show(event.target, { - identifier: "admin-post-menu", - component: AdminPostMenu, - data: { - scheduleRerender: this.scheduleRerender.bind(this), - transformedPost: this.attrs, - post: this.findAncestorModel(), - permanentlyDeletePost: () => - this.sendWidgetAction("permanentlyDeletePost"), - lockPost: () => this.sendWidgetAction("lockPost"), - unlockPost: () => this.sendWidgetAction("unlockPost"), - grantBadge: () => this.sendWidgetAction("grantBadge"), - rebakePost: () => this.sendWidgetAction("rebakePost"), - toggleWiki: () => this.sendWidgetAction("toggleWiki"), - changePostOwner: () => this.sendWidgetAction("changePostOwner"), - changeNotice: () => this.sendWidgetAction("changeNotice"), - togglePostType: () => this.sendWidgetAction("togglePostType"), - unhidePost: () => this.sendWidgetAction("unhidePost"), - showPagePublish: () => this.sendWidgetAction("showPagePublish"), - }, - }); + openAdminMenu() { + this.state.adminVisible = true; + }, + + closeAdminMenu() { + this.state.adminVisible = false; }, showDeleteTopicModal() { diff --git a/app/assets/javascripts/discourse/app/widgets/post.js b/app/assets/javascripts/discourse/app/widgets/post.js index 1ca5f3a4f74..446f1c0d6e6 100644 --- a/app/assets/javascripts/discourse/app/widgets/post.js +++ b/app/assets/javascripts/discourse/app/widgets/post.js @@ -991,9 +991,13 @@ export default createWidget("post", { this.currentUser.showUserTip({ id: "post_menu", + titleText: I18n.t("user_tips.post_menu.title"), contentText: I18n.t("user_tips.post_menu.content"), + reference, + appendTo: reference?.closest(".post-controls"), + placement: "top", }); }, diff --git a/app/assets/javascripts/discourse/package.json b/app/assets/javascripts/discourse/package.json index 3fdc1255e25..d801e695d8a 100644 --- a/app/assets/javascripts/discourse/package.json +++ b/app/assets/javascripts/discourse/package.json @@ -40,7 +40,6 @@ "@embroider/core": "^3.2.1", "@embroider/macros": "^1.13.1", "@embroider/webpack": "^3.1.5", - "@floating-ui/dom": "^1.5.0", "@glimmer/component": "^1.1.2", "@glimmer/tracking": "^1.1.2", "@popperjs/core": "^2.11.8", @@ -99,10 +98,10 @@ "qunit-dom": "^2.0.0", "sass": "^1.66.1", "select-kit": "1.0.0", - "float-kit": "1.0.0", "sinon": "^15.2.0", "source-map": "^0.7.4", "terser": "^5.19.4", + "tippy.js": "^6.3.7", "truth-helpers": "1.0.0", "util": "^0.12.5", "virtual-dom": "^2.1.1", diff --git a/app/assets/javascripts/discourse/tests/acceptance/page-publishing-test.js b/app/assets/javascripts/discourse/tests/acceptance/page-publishing-test.js index c1c5dec3487..cc77008f4f8 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/page-publishing-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/page-publishing-test.js @@ -28,7 +28,7 @@ acceptance("Page Publishing", function (needs) { await visit("/t/internationalization-localization/280"); await click(".topic-post:nth-of-type(1) button.show-more-actions"); await click(".topic-post:nth-of-type(1) button.show-post-admin-menu"); - await click(".publish-page"); + await click(".topic-post:nth-of-type(1) .publish-page"); await fillIn(".publish-slug", "bad-slug"); assert.ok(!exists(".valid-slug")); diff --git a/app/assets/javascripts/discourse/tests/acceptance/post-inline-mentions-test.js b/app/assets/javascripts/discourse/tests/acceptance/post-inline-mentions-test.js index d2de555fbe9..fb854f4cee5 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/post-inline-mentions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/post-inline-mentions-test.js @@ -162,8 +162,8 @@ acceptance("Post inline mentions – user status tooltip", function (needs) { ends_at: null, }; - async function mouseMove(selector) { - await triggerEvent(selector, "mousemove"); + async function mouseEnter(selector) { + await triggerEvent(query(selector), "mouseenter"); } test("shows user status tooltip", async function (assert) { @@ -177,7 +177,7 @@ acceptance("Post inline mentions – user status tooltip", function (needs) { "user status is shown" ); - await mouseMove(".user-status-message"); + await mouseEnter(".user-status-message"); const statusTooltip = document.querySelector( ".user-status-message-tooltip" ); diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js new file mode 100644 index 00000000000..804a24bdcf2 --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/d-popover-test.js @@ -0,0 +1,128 @@ +import { module, test } from "qunit"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { click, render, triggerKeyEvent } from "@ember/test-helpers"; +import { exists, query } from "discourse/tests/helpers/qunit-helpers"; +import { hbs } from "ember-cli-htmlbars"; +import { + hidePopover, + isPopoverShown, + showPopover, +} from "discourse/lib/d-popover"; + +module("Integration | Component | d-popover", function (hooks) { + setupRenderingTest(hooks); + + test("show/hide popover from lib", async function (assert) { + let showCallCount = 0; + let hideCallCount = 0; + + this.set("onButtonClick", (_, event) => { + if (isPopoverShown(event)) { + hidePopover(event); + hideCallCount++; + } else { + // Note: we need to override the default `trigger` and `hideOnClick` + // settings in order to completely control showing / hiding the tip + // via showPopover / hidePopover. Otherwise tippy's event listeners + // will compete with those created in this test (on DButton). + showPopover(event, { + content: "test", + duration: 0, + trigger: "manual", + hideOnClick: false, + }); + showCallCount++; + } + }); + + await render(hbs` + + `); + + assert.notOk(document.querySelector("div[data-tippy-root]")); + + await click(".btn"); + assert.strictEqual( + document.querySelector("div[data-tippy-root]").innerText.trim(), + "test" + ); + + await click(".btn"); + + assert.notOk(document.querySelector("div[data-tippy-root]")); + + assert.strictEqual(showCallCount, 1, "showPopover was invoked once"); + assert.strictEqual(hideCallCount, 1, "hidePopover was invoked once"); + }); + + test("show/hide popover from component", async function (assert) { + await render(hbs` + + +
    +
  • foo
  • +
  • +
+
+ `); + + assert.notOk(exists(".d-popover.is-expanded")); + assert.notOk(exists(".test")); + + await click(".trigger"); + + assert.ok(exists(".d-popover.is-expanded")); + assert.strictEqual(query(".test").innerText.trim(), "foo"); + + await click(".closer"); + assert.notOk(exists(".d-popover.is-expanded")); + }); + + test("using options with component", async function (assert) { + await render(hbs` + + + + `); + + await click(".btn"); + assert.strictEqual(query(".tippy-content").innerText.trim(), "bar"); + }); + + test("d-popover component accepts a block", async function (assert) { + await render(hbs` + + + + `); + + assert.ok(exists(".d-icon-chevron-down")); + + await click(".btn"); + assert.ok(exists(".d-icon-chevron-up")); + }); + + test("d-popover component accepts a class property", async function (assert) { + await render(hbs``); + + assert.ok(exists(".d-popover.foo")); + }); + + test("d-popover component closes on escape key", async function (assert) { + await render(hbs` + + + + `); + + await click(".btn"); + assert.ok(exists(".d-popover.is-expanded")); + + await triggerKeyEvent(document, "keydown", "Escape"); + assert.notOk(exists(".d-popover.is-expanded")); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js new file mode 100644 index 00000000000..d775130913a --- /dev/null +++ b/app/assets/javascripts/discourse/tests/integration/components/d-tooltip-test.js @@ -0,0 +1,47 @@ +import { module, test } from "qunit"; +import { render, triggerEvent } from "@ember/test-helpers"; +import { setupRenderingTest } from "discourse/tests/helpers/component-test"; +import { hbs } from "ember-cli-htmlbars"; +import { query } from "discourse/tests/helpers/qunit-helpers"; + +async function mouseenter() { + await triggerEvent(query("button"), "mouseenter"); +} + +module("Integration | Component | d-tooltip", function (hooks) { + setupRenderingTest(hooks); + + test("doesn't show tooltip if it wasn't expanded", async function (assert) { + await render(hbs` + + `); + assert.notOk(document.querySelector("[data-tippy-root]")); + }); + + test("it shows tooltip on mouseenter", async function (assert) { + await render(hbs` + + `); + + await mouseenter(); + assert.ok( + document.querySelector("[data-tippy-root]"), + "the tooltip is added to the page" + ); + assert.equal( + document + .querySelector("[data-tippy-root] .tippy-content") + .textContent.trim(), + "Tooltip text", + "the tooltip content is correct" + ); + }); +}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-button-tooltip-test.js b/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-button-tooltip-test.js deleted file mode 100644 index 2fee66c0d29..00000000000 --- a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-button-tooltip-test.js +++ /dev/null @@ -1,26 +0,0 @@ -import { module, test } from "qunit"; -import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { render } from "@ember/test-helpers"; -import { hbs } from "ember-cli-htmlbars"; - -module( - "Integration | Component | FloatKit | d-button-tooltip", - function (hooks) { - setupRenderingTest(hooks); - - test("default", async function (assert) { - await render(hbs` - - <:button> - - - <:tooltip> - - - `); - - assert.dom(".btn").exists(); - assert.dom("[data-trigger]").exists(); - }); - } -); diff --git a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-default-toast-test.js b/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-default-toast-test.js deleted file mode 100644 index 2c79af679ed..00000000000 --- a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-default-toast-test.js +++ /dev/null @@ -1,86 +0,0 @@ -import { module, test } from "qunit"; -import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { render } from "@ember/test-helpers"; -import { hbs } from "ember-cli-htmlbars"; -import DToastInstance from "float-kit/lib/d-toast-instance"; - -module( - "Integration | Component | FloatKit | d-default-toast", - function (hooks) { - setupRenderingTest(hooks); - - test("icon", async function (assert) { - this.toast = new DToastInstance(this, { data: { icon: "check" } }); - - await render(hbs``); - - assert.dom(".fk-d-default-toast__icon-container .d-icon-check").exists(); - }); - - test("no icon", async function (assert) { - this.toast = new DToastInstance(this, {}); - - await render(hbs``); - - assert.dom(".fk-d-default-toast__icon-container").doesNotExist(); - }); - - test("title", async function (assert) { - this.toast = new DToastInstance(this, { data: { title: "Title" } }); - - await render(hbs``); - - assert - .dom(".fk-d-default-toast__title") - .hasText(this.toast.options.data.title); - }); - - test("no title", async function (assert) { - this.toast = new DToastInstance(this, {}); - - await render(hbs``); - - assert.dom(".fk-d-default-toast__title").doesNotExist(); - }); - - test("message", async function (assert) { - this.toast = new DToastInstance(this, { data: { message: "Message" } }); - - await render(hbs``); - - assert - .dom(".fk-d-default-toast__message") - .hasText(this.toast.options.data.message); - }); - - test("no message", async function (assert) { - this.toast = new DToastInstance(this, {}); - - await render(hbs``); - - assert.dom(".fk-d-default-toast__message").doesNotExist(); - }); - - test("actions", async function (assert) { - this.toast = new DToastInstance(this, { - data: { - actions: [ - { - label: "cancel", - icon: "times", - class: "btn-danger", - action: () => {}, - }, - ], - }, - }); - - await render(hbs``); - - assert - .dom(".fk-d-default-toast__actions .btn.btn-danger") - .exists() - .hasText("cancel"); - }); - } -); diff --git a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-menu-test.js b/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-menu-test.js deleted file mode 100644 index af526d3377d..00000000000 --- a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-menu-test.js +++ /dev/null @@ -1,186 +0,0 @@ -import { module, test } from "qunit"; -import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { - click, - find, - render, - triggerEvent, - triggerKeyEvent, -} from "@ember/test-helpers"; -import { hbs } from "ember-cli-htmlbars"; -import DDefaultToast from "float-kit/components/d-default-toast"; - -module("Integration | Component | FloatKit | d-menu", function (hooks) { - setupRenderingTest(hooks); - - async function open() { - await triggerEvent(".fk-d-menu__trigger", "click"); - } - - test("@label", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-menu__trigger").containsText("label"); - }); - - test("@icon", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-menu__trigger .d-icon-check").exists(); - }); - - test("@content", async function (assert) { - await render( - hbs`` - ); - await open(); - - assert.dom(".fk-d-menu").hasText("content"); - }); - - test("-expanded class", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-menu__trigger").doesNotHaveClass("-expanded"); - - await open(); - - assert.dom(".fk-d-menu__trigger").hasClass("-expanded"); - }); - - test("trigger id attribute", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-menu__trigger").hasAttribute("id"); - }); - - test("@identifier", async function (assert) { - await render( - hbs`` - ); - - assert.dom(".fk-d-menu__trigger").hasAttribute("data-identifier", "tip"); - - await open(); - - assert.dom(".fk-d-menu").hasAttribute("data-identifier", "tip"); - }); - - test("aria-expanded attribute", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-menu__trigger").hasAttribute("aria-expanded", "false"); - - await open(); - - assert.dom(".fk-d-menu__trigger").hasAttribute("aria-expanded", "true"); - }); - - test("<:trigger>", async function (assert) { - await render( - hbs`<:trigger>label` - ); - - assert.dom(".fk-d-menu__trigger").containsText("label"); - }); - - test("<:content>", async function (assert) { - await render( - hbs`<:content>content` - ); - - await open(); - - assert.dom(".fk-d-menu").containsText("content"); - }); - - test("content role attribute", async function (assert) { - await render(hbs``); - - await open(); - - assert.dom(".fk-d-menu").hasAttribute("role", "dialog"); - }); - - test("@component", async function (assert) { - this.component = DDefaultToast; - - await render( - hbs`` - ); - - await open(); - - assert.dom(".fk-d-menu").containsText("content"); - - await click(".fk-d-menu .btn"); - - assert.dom(".fk-d-menu").doesNotExist(); - }); - - test("content aria-labelledby attribute", async function (assert) { - await render(hbs``); - - await open(); - - assert.strictEqual( - document.querySelector(".fk-d-menu__trigger").id, - document.querySelector(".fk-d-menu").getAttribute("aria-labelledby") - ); - }); - - test("@closeOnEscape", async function (assert) { - await render( - hbs`` - ); - await open(); - await triggerKeyEvent(document.activeElement, "keydown", "Escape"); - - assert.dom(".fk-d-menu").doesNotExist(); - - await render( - hbs`` - ); - await open(); - await triggerKeyEvent(document.activeElement, "keydown", "Escape"); - - assert.dom(".fk-d-menu").exists(); - }); - - test("@closeOnClickOutside", async function (assert) { - await render( - hbs`test` - ); - await open(); - await click(".test"); - - assert.dom(".fk-d-menu").doesNotExist(); - - await render( - hbs`test` - ); - await open(); - await click(".test"); - - assert.dom(".fk-d-menu").exists(); - }); - - test("@maxWidth", async function (assert) { - await render( - hbs`` - ); - await open(); - - assert.ok( - find(".fk-d-menu").getAttribute("style").includes("max-width: 20px;") - ); - }); - - test("applies position", async function (assert) { - await render(hbs``); - await open(); - - assert.dom(".fk-d-menu").hasAttribute("style", /left: /); - assert.ok(find(".fk-d-menu").getAttribute("style").includes("top: ")); - }); -}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-tooltip-test.js b/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-tooltip-test.js deleted file mode 100644 index 1aa9241e8f9..00000000000 --- a/app/assets/javascripts/discourse/tests/integration/components/float-kit/d-tooltip-test.js +++ /dev/null @@ -1,192 +0,0 @@ -import { module, test } from "qunit"; -import { setupRenderingTest } from "discourse/tests/helpers/component-test"; -import { - click, - find, - render, - triggerEvent, - triggerKeyEvent, -} from "@ember/test-helpers"; -import { hbs } from "ember-cli-htmlbars"; -import DDefaultToast from "float-kit/components/d-default-toast"; - -module("Integration | Component | FloatKit | d-tooltip", function (hooks) { - setupRenderingTest(hooks); - - async function hover() { - await triggerEvent(".fk-d-tooltip__trigger", "mousemove"); - } - - test("@label", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__label").hasText("label"); - }); - - test("@icon", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__icon .d-icon-check").exists(); - }); - - test("@content", async function (assert) { - await render( - hbs`` - ); - await hover(); - - assert.dom(".fk-d-tooltip").hasText("content"); - }); - - test("-expanded class", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__trigger").doesNotHaveClass("-expanded"); - - await hover(); - - assert.dom(".fk-d-tooltip__trigger").hasClass("-expanded"); - }); - - test("trigger role attribute", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__trigger").hasAttribute("role", "button"); - }); - - test("trigger id attribute", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__trigger").hasAttribute("id"); - }); - - test("@identifier", async function (assert) { - await render( - hbs`` - ); - - assert.dom(".fk-d-tooltip__trigger").hasAttribute("data-identifier", "tip"); - - await hover(); - - assert.dom(".fk-d-tooltip").hasAttribute("data-identifier", "tip"); - }); - - test("aria-expanded attribute", async function (assert) { - await render(hbs``); - - assert.dom(".fk-d-tooltip__trigger").hasAttribute("aria-expanded", "false"); - - await hover(); - - assert.dom(".fk-d-tooltip__trigger").hasAttribute("aria-expanded", "true"); - }); - - test("<:trigger>", async function (assert) { - await render( - hbs`<:trigger>label` - ); - - assert.dom(".fk-d-tooltip__trigger").hasText("label"); - }); - - test("<:content>", async function (assert) { - await render( - hbs`<:content>content` - ); - - await hover(); - - assert.dom(".fk-d-tooltip").hasText("content"); - }); - - test("content role attribute", async function (assert) { - await render(hbs``); - - await hover(); - - assert.dom(".fk-d-tooltip").hasAttribute("role", "tooltip"); - }); - - test("@component", async function (assert) { - this.component = DDefaultToast; - - await render( - hbs`` - ); - - await hover(); - - assert.dom(".fk-d-tooltip").containsText("content"); - - await click(".fk-d-tooltip .btn"); - - assert.dom(".fk-d-tooltip").doesNotExist(); - }); - - test("content aria-labelledby attribute", async function (assert) { - await render(hbs``); - - await hover(); - - assert.strictEqual( - document.querySelector(".fk-d-tooltip__trigger").id, - document.querySelector(".fk-d-tooltip").getAttribute("aria-labelledby") - ); - }); - - test("@closeOnEscape", async function (assert) { - await render( - hbs`` - ); - await hover(); - await triggerKeyEvent(document.activeElement, "keydown", "Escape"); - - assert.dom(".fk-d-tooltip").doesNotExist(); - - await render( - hbs`` - ); - await hover(); - await triggerKeyEvent(document.activeElement, "keydown", "Escape"); - - assert.dom(".fk-d-tooltip").exists(); - }); - - test("@closeOnClickOutside", async function (assert) { - await render( - hbs`test` - ); - await hover(); - await click(".test"); - - assert.dom(".fk-d-tooltip").doesNotExist(); - - await render( - hbs`test` - ); - await hover(); - await click(".test"); - - assert.dom(".fk-d-tooltip").exists(); - }); - - test("@maxWidth", async function (assert) { - await render( - hbs`` - ); - await hover(); - - assert.ok( - find(".fk-d-tooltip").getAttribute("style").includes("max-width: 20px;") - ); - }); - - test("applies position", async function (assert) { - await render(hbs``); - await hover(); - - assert.ok(find(".fk-d-tooltip").getAttribute("style").includes("left: ")); - assert.ok(find(".fk-d-tooltip").getAttribute("style").includes("top: ")); - }); -}); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-info-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-info-test.js index f44601c14bd..57092a42b57 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-info-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-info-test.js @@ -118,17 +118,31 @@ module("Integration | Component | user-info", function (hooks) { .exists(); }); + test("doesn't show status tooltip by default", async function (assert) { + this.currentUser.name = "Evil Trout"; + this.currentUser.status = { emoji: "tooth", description: "off to dentist" }; + + await render( + hbs`` + ); + await triggerEvent(query(".user-status-message"), "mouseenter"); + + assert.notOk( + document.querySelector("[data-tippy-root] .user-status-message-tooltip") + ); + }); + test("shows status tooltip if enabled", async function (assert) { this.currentUser.name = "Evil Trout"; this.currentUser.status = { emoji: "tooth", description: "off to dentist" }; await render( - hbs`` + hbs`` ); - await triggerEvent(query(".user-status-message"), "mousemove"); + await triggerEvent(query(".user-status-message"), "mouseenter"); - assert - .dom("[data-content][data-identifier='user-status-message-tooltip']") - .exists(); + assert.ok( + document.querySelector("[data-tippy-root] .user-status-message-tooltip") + ); }); }); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js index aa8b965aaf9..9cf52c8fcd0 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js @@ -5,7 +5,7 @@ import { hbs } from "ember-cli-htmlbars"; import { exists, fakeTime, query } from "discourse/tests/helpers/qunit-helpers"; async function mouseenter() { - await triggerEvent(query(".user-status-message"), "mousemove"); + await triggerEvent(query(".user-status-message"), "mouseenter"); } module("Integration | Component | user-status-message", function (hooks) { @@ -27,6 +27,11 @@ module("Integration | Component | user-status-message", function (hooks) { assert.ok(exists("img.emoji[alt='tooth']"), "the status emoji is shown"); }); + test("it doesn't render status description by default", async function (assert) { + await render(hbs``); + assert.notOk(exists(".user-status-message-description")); + }); + test("it renders status description if enabled", async function (assert) { await render(hbs` `); - assert - .dom('[data-trigger][data-identifier="user-status-message-tooltip"]') - .containsText("off to dentist"); + assert.equal( + query(".user-status-message-description").innerText.trim(), + "off to dentist" + ); }); test("it shows the until TIME on the tooltip if status will expire today", async function (assert) { @@ -47,14 +53,15 @@ module("Integration | Component | user-status-message", function (hooks) { ); this.status.ends_at = "2100-02-01T12:30:00.000Z"; - await render( - hbs`` - ); - await mouseenter(); + await render(hbs``); - assert - .dom('[data-content][data-identifier="user-status-message-tooltip"]') - .containsText("Until: 12:30 PM"); + await mouseenter(); + assert.equal( + document + .querySelector("[data-tippy-root] .user-status-tooltip-until") + .textContent.trim(), + "Until: 12:30 PM" + ); }); test("it shows the until DATE on the tooltip if status will expire tomorrow", async function (assert) { @@ -65,14 +72,15 @@ module("Integration | Component | user-status-message", function (hooks) { ); this.status.ends_at = "2100-02-02T12:30:00.000Z"; - await render( - hbs`` - ); - await mouseenter(); + await render(hbs``); - assert - .dom('[data-content][data-identifier="user-status-message-tooltip"]') - .containsText("Until: Feb 2"); + await mouseenter(); + assert.equal( + document + .querySelector("[data-tippy-root] .user-status-tooltip-until") + .textContent.trim(), + "Until: Feb 2" + ); }); test("it doesn't show until datetime on the tooltip if status doesn't have expiration date", async function (assert) { @@ -83,27 +91,32 @@ module("Integration | Component | user-status-message", function (hooks) { ); this.status.ends_at = null; - await render( - hbs`` - ); - await mouseenter(); + await render(hbs``); - assert - .dom( - '[data-content][data-identifier="user-status-message-tooltip"] .user-status-tooltip-until' - ) - .doesNotExist(); + await mouseenter(); + assert.notOk( + document.querySelector("[data-tippy-root] .user-status-tooltip-until") + ); }); test("it shows tooltip by default", async function (assert) { + await render(hbs``); + await mouseenter(); + + assert.ok( + document.querySelector("[data-tippy-root] .user-status-message-tooltip") + ); + }); + + test("it doesn't show tooltip if disabled", async function (assert) { await render( - hbs`` + hbs`` ); await mouseenter(); - assert - .dom('[data-content][data-identifier="user-status-message-tooltip"]') - .exists(); + assert.notOk( + document.querySelector("[data-tippy-root] .user-status-message-tooltip") + ); }); test("doesn't blow up with an anonymous user", async function (assert) { @@ -112,9 +125,7 @@ module("Integration | Component | user-status-message", function (hooks) { await render(hbs``); - assert - .dom('[data-trigger][data-identifier="user-status-message-tooltip"]') - .exists(); + assert.dom(".user-status-message").exists(); }); test("accepts a custom css class", async function (assert) { @@ -124,8 +135,6 @@ module("Integration | Component | user-status-message", function (hooks) { hbs`` ); - assert - .dom('[data-trigger][data-identifier="user-status-message-tooltip"].foo') - .exists(); + assert.dom(".user-status-message.foo").exists(); }); }); diff --git a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js index d9bea1d80ea..3ad97ae96c9 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/widgets/post-test.js @@ -564,21 +564,13 @@ module("Integration | Component | Widget | post", function (hooks) { test("show admin menu", async function (assert) { this.set("args", { canManage: true }); - await render( - hbs`` - ); + await render(hbs``); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist(); + assert.ok(!exists(".post-admin-menu")); await click(".post-menu-area .show-post-admin-menu"); - - assert.dom("[data-content][data-identifier='admin-post-menu']").exists(); - + assert.strictEqual(count(".post-admin-menu"), 1, "it shows the popup"); await click(".post-menu-area"); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("clicking outside clears the popup"); + assert.ok(!exists(".post-admin-menu"), "clicking outside clears the popup"); }); test("permanently delete topic", async function (assert) { @@ -586,17 +578,13 @@ module("Integration | Component | Widget | post", function (hooks) { this.set("permanentlyDeletePost", () => (this.deleted = true)); await render( - hbs`` + hbs`` ); await click(".post-menu-area .show-post-admin-menu"); - await click( - "[data-content][data-identifier='admin-post-menu'] .permanently-delete" - ); + await click(".post-admin-menu .permanently-delete"); assert.ok(this.deleted); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("permanently delete post", async function (assert) { @@ -605,18 +593,12 @@ module("Integration | Component | Widget | post", function (hooks) { await render(hbs` - `); await click(".post-menu-area .show-post-admin-menu"); - - await click( - "[data-content][data-identifier='admin-post-menu'] .permanently-delete" - ); + await click(".post-admin-menu .permanently-delete"); assert.ok(this.deleted); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("toggle moderator post", async function (assert) { @@ -626,18 +608,29 @@ module("Integration | Component | Widget | post", function (hooks) { await render(hbs` - `); await click(".post-menu-area .show-post-admin-menu"); - await click( - "[data-content][data-identifier='admin-post-menu'] .toggle-post-type" - ); + await click(".post-admin-menu .toggle-post-type"); assert.ok(this.toggled); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); + }); + + test("toggle moderator post", async function (assert) { + this.currentUser.set("moderator", true); + this.set("args", { canManage: true }); + this.set("togglePostType", () => (this.toggled = true)); + + await render(hbs` + + `); + + await click(".post-menu-area .show-post-admin-menu"); + await click(".post-admin-menu .toggle-post-type"); + + assert.ok(this.toggled); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("rebake post", async function (assert) { @@ -646,41 +639,27 @@ module("Integration | Component | Widget | post", function (hooks) { await render(hbs` - `); await click(".post-menu-area .show-post-admin-menu"); - await click( - "[data-content][data-identifier='admin-post-menu'] .rebuild-html" - ); + await click(".post-admin-menu .rebuild-html"); assert.ok(this.baked); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("unhide post", async function (assert) { - let unhidden; this.currentUser.admin = true; this.set("args", { canManage: true, hidden: true }); - this.set("unhidePost", () => (unhidden = true)); + this.set("unhidePost", () => (this.unhidden = true)); await render(hbs` - `); await click(".post-menu-area .show-post-admin-menu"); - - await click( - "[data-content][data-identifier='admin-post-menu'] .unhide-post" - ); - - assert.ok(unhidden); - - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + await click(".post-admin-menu .unhide-post"); + assert.ok(this.unhidden); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("change owner", async function (assert) { @@ -690,17 +669,12 @@ module("Integration | Component | Widget | post", function (hooks) { await render(hbs` - `); await click(".post-menu-area .show-post-admin-menu"); - await click( - "[data-content][data-identifier='admin-post-menu'] .change-owner" - ); + await click(".post-admin-menu .change-owner"); assert.ok(this.owned); - assert - .dom("[data-content][data-identifier='admin-post-menu']") - .doesNotExist("also hides the menu"); + assert.ok(!exists(".post-admin-menu"), "also hides the menu"); }); test("reply", async function (assert) { diff --git a/app/assets/javascripts/float-kit/.npmrc b/app/assets/javascripts/float-kit/.npmrc deleted file mode 100644 index c42da845b44..00000000000 --- a/app/assets/javascripts/float-kit/.npmrc +++ /dev/null @@ -1 +0,0 @@ -engine-strict = true diff --git a/app/assets/javascripts/float-kit/addon/components/d-button-tooltip.gjs b/app/assets/javascripts/float-kit/addon/components/d-button-tooltip.gjs deleted file mode 100644 index 34b871153ff..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-button-tooltip.gjs +++ /dev/null @@ -1,8 +0,0 @@ -const DButtonTooltip = ; - -export default DButtonTooltip; diff --git a/app/assets/javascripts/float-kit/addon/components/d-default-toast.gjs b/app/assets/javascripts/float-kit/addon/components/d-default-toast.gjs deleted file mode 100644 index 4fe30ba7f7c..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-default-toast.gjs +++ /dev/null @@ -1,56 +0,0 @@ -import DButton from "discourse/components/d-button"; -import icon from "discourse-common/helpers/d-icon"; -import { concat, fn, hash } from "@ember/helper"; -import concatClass from "discourse/helpers/concat-class"; -import or from "truth-helpers/helpers/or"; - -const DDefaultToast = ; - -export default DDefaultToast; diff --git a/app/assets/javascripts/float-kit/addon/components/d-float-body.gjs b/app/assets/javascripts/float-kit/addon/components/d-float-body.gjs deleted file mode 100644 index de7d0ee972b..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-float-body.gjs +++ /dev/null @@ -1,85 +0,0 @@ -import Component from "@glimmer/component"; -import FloatKitApplyFloatingUi from "float-kit/modifiers/apply-floating-ui"; -import FloatKitCloseOnEscape from "float-kit/modifiers/close-on-escape"; -import FloatKitCloseOnClickOutside from "float-kit/modifiers/close-on-click-outside"; -import { modifier } from "ember-modifier"; -import { getScrollParent } from "float-kit/lib/get-scroll-parent"; -import concatClass from "discourse/helpers/concat-class"; -import { htmlSafe } from "@ember/template"; -import { concat } from "@ember/helper"; -import TrapTab from "discourse/modifiers/trap-tab"; -import DFloatPortal from "float-kit/components/d-float-portal"; - -export default class DFloatBody extends Component { - - - closeOnScroll = modifier(() => { - const firstScrollParent = getScrollParent(this.trigger); - - const handler = () => { - this.args.instance.close(); - }; - - firstScrollParent.addEventListener("scroll", handler, { passive: true }); - - return () => { - firstScrollParent.removeEventListener("scroll", handler); - }; - }); - - get supportsCloseOnClickOutside() { - return this.args.instance.expanded && this.options.closeOnClickOutside; - } - - get supportsCloseOnEscape() { - return this.args.instance.expanded && this.options.closeOnEscape; - } - - get supportsCloseOnScroll() { - return this.args.instance.expanded && this.options.closeOnScroll; - } - - get trigger() { - return this.args.instance.trigger; - } - - get options() { - return this.args.instance.options; - } -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-float-portal.gjs b/app/assets/javascripts/float-kit/addon/components/d-float-portal.gjs deleted file mode 100644 index 7cc2650f825..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-float-portal.gjs +++ /dev/null @@ -1,18 +0,0 @@ -import Component from "@glimmer/component"; -import { isTesting } from "discourse-common/config/environment"; - -export default class DFloatPortal extends Component { - - - get inline() { - return this.args.inline ?? isTesting(); - } -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs b/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs deleted file mode 100644 index 68c1860df49..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-inline-float.gjs +++ /dev/null @@ -1,26 +0,0 @@ -import DFloatBody from "float-kit/components/d-float-body"; - -const DInlineFloat = ; - -export default DInlineFloat; diff --git a/app/assets/javascripts/float-kit/addon/components/d-inline-menu.gjs b/app/assets/javascripts/float-kit/addon/components/d-inline-menu.gjs deleted file mode 100644 index cf7e1a31266..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-inline-menu.gjs +++ /dev/null @@ -1,27 +0,0 @@ -import Component from "@glimmer/component"; -import { inject as service } from "@ember/service"; -import DInlineFloat from "float-kit/components/d-inline-float"; -import { MENU } from "float-kit/lib/constants"; -import didInsert from "@ember/render-modifiers/modifiers/did-insert"; - -export default class DInlineMenu extends Component { - - - @service menu; -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-inline-tooltip.gjs b/app/assets/javascripts/float-kit/addon/components/d-inline-tooltip.gjs deleted file mode 100644 index 33958abd900..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-inline-tooltip.gjs +++ /dev/null @@ -1,31 +0,0 @@ -import Component from "@glimmer/component"; -import { inject as service } from "@ember/service"; -import DInlineFloat from "float-kit/components/d-inline-float"; -import { TOOLTIP } from "float-kit/lib/constants"; -import didInsert from "@ember/render-modifiers/modifiers/did-insert"; -import and from "truth-helpers/helpers/and"; - -export default class DInlineTooltip extends Component { - - - @service tooltip; -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-menu.gjs b/app/assets/javascripts/float-kit/addon/components/d-menu.gjs deleted file mode 100644 index 234ab4fa470..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-menu.gjs +++ /dev/null @@ -1,104 +0,0 @@ -import Component from "@glimmer/component"; -import { modifier } from "ember-modifier"; -import { tracked } from "@glimmer/tracking"; -import { inject as service } from "@ember/service"; -import DButton from "discourse/components/d-button"; -import DFloatBody from "float-kit/components/d-float-body"; -import concatClass from "discourse/helpers/concat-class"; -import { getOwner } from "discourse-common/lib/get-owner"; -import DMenuInstance from "float-kit/lib/d-menu-instance"; - -export default class DMenu extends Component { - - - @service menu; - - @tracked menuInstance = null; - - registerTrigger = modifier((element) => { - const options = { - ...this.args, - ...{ - autoUpdate: true, - listeners: true, - beforeTrigger: () => { - this.menu.close(); - }, - }, - }; - const instance = new DMenuInstance(getOwner(this), element, options); - - this.menuInstance = instance; - - return () => { - instance.destroy(); - - if (this.isDestroying) { - this.menuInstance = null; - } - }; - }); - - get menuId() { - return `d-menu-${this.menuInstance.id}`; - } - - get options() { - return this.menuInstance?.options ?? {}; - } - - get componentArgs() { - return { - close: this.menu.close, - data: this.options.data, - }; - } -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-popover.gjs b/app/assets/javascripts/float-kit/addon/components/d-popover.gjs deleted file mode 100644 index 508a5076454..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-popover.gjs +++ /dev/null @@ -1,40 +0,0 @@ -import Component from "@glimmer/component"; -import { inject as service } from "@ember/service"; -import { modifier } from "ember-modifier"; - -import deprecated from "discourse-common/lib/deprecated"; - -export default class DPopover extends Component { - - - @service tooltip; - - registerDTooltip = modifier((element) => { - deprecated( - "`` is deprecated. Use `` or the `tooltip` service instead.", - { id: "discourse.d-popover" } - ); - - const trigger = element.children[0]; - const content = element.children[1]; - - if (!trigger || !content) { - return; - } - - const instance = this.tooltip.register(trigger, { - content, - }); - - content.remove(); - - return () => { - instance.destroy(); - }; - }); -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-toasts.gjs b/app/assets/javascripts/float-kit/addon/components/d-toasts.gjs deleted file mode 100644 index 2f6f3149017..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-toasts.gjs +++ /dev/null @@ -1,27 +0,0 @@ -import Component from "@glimmer/component"; -import { inject as service } from "@ember/service"; -import concatClass from "discourse/helpers/concat-class"; -import { on } from "@ember/modifier"; - -export default class DToasts extends Component { - - - @service toasts; -} diff --git a/app/assets/javascripts/float-kit/addon/components/d-tooltip.gjs b/app/assets/javascripts/float-kit/addon/components/d-tooltip.gjs deleted file mode 100644 index cc468134404..00000000000 --- a/app/assets/javascripts/float-kit/addon/components/d-tooltip.gjs +++ /dev/null @@ -1,109 +0,0 @@ -import Component from "@glimmer/component"; -import { modifier } from "ember-modifier"; -import { tracked } from "@glimmer/tracking"; -import icon from "discourse-common/helpers/d-icon"; -import { inject as service } from "@ember/service"; -import DFloatBody from "float-kit/components/d-float-body"; -import concatClass from "discourse/helpers/concat-class"; -import DTooltipInstance from "float-kit/lib/d-tooltip-instance"; -import { getOwner } from "discourse-common/lib/get-owner"; -import and from "truth-helpers/helpers/and"; - -export default class DTooltip extends Component { - - - @service tooltip; - - @tracked tooltipInstance = null; - - registerTrigger = modifier((element) => { - const options = { - ...this.args, - ...{ - listeners: true, - beforeTrigger: () => { - this.tooltip.close(); - }, - }, - }; - const instance = new DTooltipInstance(getOwner(this), element, options); - - this.tooltipInstance = instance; - - return () => { - instance.destroy(); - - if (this.isDestroying) { - this.tooltipInstance = null; - } - }; - }); - - get options() { - return this.tooltipInstance?.options; - } - - get componentArgs() { - return { - close: this.tooltip.close, - data: this.options.data, - }; - } -} diff --git a/app/assets/javascripts/float-kit/addon/lib/constants.js b/app/assets/javascripts/float-kit/addon/lib/constants.js deleted file mode 100644 index 64a1a39c25e..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/constants.js +++ /dev/null @@ -1,76 +0,0 @@ -export const FLOAT_UI_PLACEMENTS = [ - "top", - "top-start", - "top-end", - "right", - "right-start", - "right-end", - "bottom", - "bottom-start", - "bottom-end", - "left", - "left-start", - "left-end", -]; - -export const TOOLTIP = { - options: { - animated: true, - arrow: true, - beforeTrigger: null, - closeOnClickOutside: true, - closeOnEscape: true, - closeOnScroll: true, - component: null, - content: null, - identifier: null, - interactive: false, - listeners: false, - maxWidth: 350, - data: null, - offset: 10, - triggers: ["hover", "click"], - untriggers: ["hover", "click"], - placement: "top", - fallbackPlacements: FLOAT_UI_PLACEMENTS, - autoUpdate: true, - trapTab: true, - }, - portalOutletId: "d-tooltip-portal-outlet", -}; - -export const MENU = { - options: { - animated: true, - arrow: false, - beforeTrigger: null, - closeOnEscape: true, - closeOnClickOutside: true, - closeOnScroll: false, - component: null, - content: null, - identifier: null, - interactive: true, - listeners: false, - maxWidth: 400, - data: null, - offset: 10, - triggers: ["click"], - untriggers: ["click"], - placement: "bottom", - fallbackPlacements: FLOAT_UI_PLACEMENTS, - autoUpdate: true, - trapTab: true, - }, - portalOutletId: "d-menu-portal-outlet", -}; - -import DDefaultToast from "float-kit/components/d-default-toast"; - -export const TOAST = { - options: { - autoClose: true, - duration: 10000, - component: DDefaultToast, - }, -}; diff --git a/app/assets/javascripts/float-kit/addon/lib/d-menu-instance.js b/app/assets/javascripts/float-kit/addon/lib/d-menu-instance.js deleted file mode 100644 index bf069c7f010..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/d-menu-instance.js +++ /dev/null @@ -1,63 +0,0 @@ -import { inject as service } from "@ember/service"; -import { action } from "@ember/object"; -import { setOwner } from "@ember/application"; -import { MENU } from "float-kit/lib/constants"; -import { guidFor } from "@ember/object/internals"; -import FloatKitInstance from "float-kit/lib/float-kit-instance"; - -export default class DMenuInstance extends FloatKitInstance { - @service menu; - - constructor(owner, trigger, options = {}) { - super(...arguments); - - setOwner(this, owner); - this.options = { ...MENU.options, ...options }; - this.id = trigger.id || guidFor(trigger); - this.trigger = trigger; - this.setupListeners(); - } - - @action - onMouseMove(event) { - if (this.trigger.contains(event.target) && this.expanded) { - return; - } - - this.onTrigger(event); - } - - @action - onClick(event) { - if (this.expanded && this.untriggers.includes("click")) { - this.onUntrigger(event); - return; - } - - this.onTrigger(event); - } - - @action - onMouseLeave(event) { - if (this.untriggers.includes("hover")) { - this.onUntrigger(event); - } - } - - @action - async onTrigger() { - this.options.beforeTrigger?.(this); - await this.show(); - } - - @action - async onUntrigger() { - await this.close(); - } - - @action - async destroy() { - await this.close(); - this.tearDownListeners(); - } -} diff --git a/app/assets/javascripts/float-kit/addon/lib/d-toast-instance.js b/app/assets/javascripts/float-kit/addon/lib/d-toast-instance.js deleted file mode 100644 index 4e5ef55c7ac..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/d-toast-instance.js +++ /dev/null @@ -1,51 +0,0 @@ -import { setOwner } from "@ember/application"; -import { TOAST } from "float-kit/lib/constants"; -import uniqueId from "discourse/helpers/unique-id"; -import { action } from "@ember/object"; -import { inject as service } from "@ember/service"; -import { modifier } from "ember-modifier"; -import discourseLater from "discourse-common/lib/later"; -import { cancel } from "@ember/runloop"; - -const CSS_TRANSITION_DELAY_MS = 500; -const TRANSITION_CLASS = "-fade-out"; - -export default class DToastInstance { - @service toasts; - - options = null; - id = uniqueId(); - autoCloseHandler = null; - - registerAutoClose = modifier((element) => { - let innerHandler; - - this.autoCloseHandler = discourseLater(() => { - element.classList.add(TRANSITION_CLASS); - - innerHandler = discourseLater(() => { - this.close(); - }, CSS_TRANSITION_DELAY_MS); - }, this.options.duration || TOAST.options.duration); - - return () => { - cancel(innerHandler); - cancel(this.autoCloseHandler); - }; - }); - - constructor(owner, options = {}) { - setOwner(this, owner); - this.options = { ...TOAST.options, ...options }; - } - - @action - close() { - this.toasts.close(this); - } - - @action - cancelAutoClose() { - cancel(this.autoCloseHandler); - } -} diff --git a/app/assets/javascripts/float-kit/addon/lib/d-tooltip-instance.js b/app/assets/javascripts/float-kit/addon/lib/d-tooltip-instance.js deleted file mode 100644 index b242d8d3b73..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/d-tooltip-instance.js +++ /dev/null @@ -1,63 +0,0 @@ -import { inject as service } from "@ember/service"; -import { action } from "@ember/object"; -import { setOwner } from "@ember/application"; -import { TOOLTIP } from "float-kit/lib/constants"; -import { guidFor } from "@ember/object/internals"; -import FloatKitInstance from "float-kit/lib/float-kit-instance"; - -export default class DTooltipInstance extends FloatKitInstance { - @service tooltip; - - constructor(owner, trigger, options = {}) { - super(...arguments); - - setOwner(this, owner); - this.options = { ...TOOLTIP.options, ...options }; - this.id = trigger.id || guidFor(trigger); - this.trigger = trigger; - this.setupListeners(); - } - - @action - onMouseMove(event) { - if (this.trigger.contains(event.target) && this.expanded) { - return; - } - - this.onTrigger(event); - } - - @action - onClick(event) { - if (this.expanded && this.untriggers.includes("click")) { - this.onUntrigger(event); - return; - } - - this.onTrigger(event); - } - - @action - onMouseLeave(event) { - if (this.untriggers.includes("hover")) { - this.onUntrigger(event); - } - } - - @action - async onTrigger() { - this.options.beforeTrigger?.(this); - await this.show(); - } - - @action - async onUntrigger() { - await this.close(); - } - - @action - async destroy() { - await this.close(); - this.tearDownListeners(); - } -} diff --git a/app/assets/javascripts/float-kit/addon/lib/float-kit-instance.js b/app/assets/javascripts/float-kit/addon/lib/float-kit-instance.js deleted file mode 100644 index a9ae1326058..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/float-kit-instance.js +++ /dev/null @@ -1,198 +0,0 @@ -import { action } from "@ember/object"; -import { cancel, next } from "@ember/runloop"; -import { tracked } from "@glimmer/tracking"; -import discourseLater from "discourse-common/lib/later"; -import { makeArray } from "discourse-common/lib/helpers"; -import { bind } from "discourse-common/utils/decorators"; - -const TOUCH_OPTIONS = { passive: true, capture: true }; - -function cancelEvent(event) { - event.preventDefault(); - event.stopImmediatePropagation(); -} - -export default class FloatKitInstance { - @tracked expanded = false; - @tracked id = null; - - trigger = null; - content = null; - - @action - async show() { - this.expanded = true; - - await new Promise((resolve) => next(resolve)); - } - - @action - async close() { - this.expanded = false; - - await new Promise((resolve) => next(resolve)); - } - - @action - onFocus(event) { - this.onTrigger(event); - } - - @action - onBlur(event) { - this.onTrigger(event); - } - - @action - onFocusIn(event) { - this.onTrigger(event); - } - - @action - onFocusOut(event) { - this.onTrigger(event); - } - - @action - onTouchStart(event) { - if (event.touches.length > 1) { - this.onTouchCancel(); - return; - } - - event.stopPropagation(); - - this.trigger.addEventListener( - "touchmove", - this.onTouchCancel, - TOUCH_OPTIONS - ); - this.trigger.addEventListener( - "touchcancel", - this.onTouchCancel, - TOUCH_OPTIONS - ); - this.trigger.addEventListener( - "touchend", - this.onTouchCancel, - TOUCH_OPTIONS - ); - this.touchTimeout = discourseLater(() => { - if (this.isDestroying || this.isDestroyed) { - return; - } - - this.trigger.addEventListener("touchend", cancelEvent, { - once: true, - capture: true, - }); - - this.onTrigger(event); - }, 500); - } - - @bind - onTouchCancel() { - cancel(this.touchTimeout); - - this.trigger.removeEventListener("touchmove", this.onTouchCancel); - this.trigger.removeEventListener("touchend", this.onTouchCancel); - this.trigger.removeEventListener("touchcancel", this.onTouchCancel); - } - - tearDownListeners() { - if (!this.options.listeners) { - return; - } - - makeArray(this.triggers) - .filter(Boolean) - .forEach((trigger) => { - switch (trigger) { - case "hold": - this.trigger.addEventListener("touchstart", this.onTouchStart); - break; - case "focus": - this.trigger.removeEventListener("focus", this.onFocus); - this.trigger.removeEventListener("blur", this.onBlur); - break; - case "focusin": - this.trigger.removeEventListener("focusin", this.onFocusIn); - this.trigger.removeEventListener("focusout", this.onFocusOut); - break; - case "hover": - this.trigger.removeEventListener("mousemove", this.onMouseMove); - if (!this.options.interactive) { - this.trigger.removeEventListener("mouseleave", this.onMouseLeave); - } - - break; - case "click": - this.trigger.removeEventListener("click", this.onClick); - break; - } - }); - - cancel(this.touchTimeout); - } - - setupListeners() { - if (!this.options.listeners) { - return; - } - - makeArray(this.triggers) - .filter(Boolean) - .forEach((trigger) => { - switch (trigger) { - case "hold": - this.trigger.addEventListener( - "touchstart", - this.onTouchStart, - TOUCH_OPTIONS - ); - break; - case "focus": - this.trigger.addEventListener("focus", this.onFocus, { - passive: true, - }); - this.trigger.addEventListener("blur", this.onBlur, { - passive: true, - }); - break; - case "focusin": - this.trigger.addEventListener("focusin", this.onFocusIn, { - passive: true, - }); - this.trigger.addEventListener("focusout", this.onFocusOut, { - passive: true, - }); - break; - case "hover": - this.trigger.addEventListener("mousemove", this.onMouseMove, { - passive: true, - }); - if (!this.options.interactive) { - this.trigger.addEventListener("mouseleave", this.onMouseLeave, { - passive: true, - }); - } - - break; - case "click": - this.trigger.addEventListener("click", this.onClick, { - passive: true, - }); - break; - } - }); - } - - get triggers() { - return this.options.triggers ?? ["click"]; - } - - get untriggers() { - return this.options.untriggers ?? ["click"]; - } -} diff --git a/app/assets/javascripts/float-kit/addon/lib/get-scroll-parent.js b/app/assets/javascripts/float-kit/addon/lib/get-scroll-parent.js deleted file mode 100644 index d0de893ac0c..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/get-scroll-parent.js +++ /dev/null @@ -1,13 +0,0 @@ -export function getScrollParent(node) { - const isElement = node instanceof HTMLElement; - const overflowY = isElement && window.getComputedStyle(node).overflowY; - const isScrollable = overflowY !== "visible" && overflowY !== "hidden"; - - if (!node || node === document.documentElement) { - return null; - } else if (isScrollable && node.scrollHeight >= node.clientHeight) { - return node; - } - - return getScrollParent(node.parentNode) || window; -} diff --git a/app/assets/javascripts/float-kit/addon/lib/update-position.js b/app/assets/javascripts/float-kit/addon/lib/update-position.js deleted file mode 100644 index 40987b95710..00000000000 --- a/app/assets/javascripts/float-kit/addon/lib/update-position.js +++ /dev/null @@ -1,93 +0,0 @@ -import { - arrow, - computePosition, - flip, - inline, - offset, - shift, -} from "@floating-ui/dom"; -import { FLOAT_UI_PLACEMENTS } from "float-kit/lib/constants"; -import { isTesting } from "discourse-common/config/environment"; -import { headerOffset } from "discourse/lib/offset-calculator"; -import { iconHTML } from "discourse-common/lib/icon-library"; -import domFromString from "discourse-common/lib/dom-from-string"; - -export async function updatePosition(trigger, content, options) { - let padding = 0; - if (!isTesting()) { - padding = options.padding || { - top: headerOffset(), - left: 10, - right: 10, - bottom: 10, - }; - } - - const flipOptions = { - fallbackPlacements: options.fallbackPlacements ?? FLOAT_UI_PLACEMENTS, - padding, - }; - - const middleware = [ - offset(options.offset ? parseInt(options.offset, 10) : 10), - ]; - - if (options.inline) { - middleware.push(inline()); - } - - middleware.push(flip(flipOptions)); - middleware.push(shift({ padding })); - - let arrowElement; - if (options.arrow) { - arrowElement = content.querySelector(".arrow"); - - if (!arrowElement) { - arrowElement = domFromString( - iconHTML("tippy-rounded-arrow", { class: "arrow" }) - )[0]; - content.appendChild(arrowElement); - } - - middleware.push(arrow({ element: arrowElement })); - } - - content.dataset.strategy = options.strategy || "absolute"; - - const { x, y, placement, middlewareData } = await computePosition( - trigger, - content, - { - placement: options.placement, - strategy: options.strategy || "absolute", - middleware, - } - ); - - if (options.computePosition) { - options.computePosition(content, { - x, - y, - placement, - middlewareData, - arrowElement, - }); - } else { - content.dataset.placement = placement; - Object.assign(content.style, { - left: `${x}px`, - top: `${y}px`, - }); - - if (middlewareData.arrow && arrowElement) { - const arrowX = middlewareData.arrow.x; - const arrowY = middlewareData.arrow.y; - - Object.assign(arrowElement.style, { - left: arrowX != null ? `${arrowX}px` : "", - top: arrowY != null ? `${arrowY}px` : "", - }); - } - } -} diff --git a/app/assets/javascripts/float-kit/addon/modifiers/apply-floating-ui.js b/app/assets/javascripts/float-kit/addon/modifiers/apply-floating-ui.js deleted file mode 100644 index 338eb9e1e91..00000000000 --- a/app/assets/javascripts/float-kit/addon/modifiers/apply-floating-ui.js +++ /dev/null @@ -1,37 +0,0 @@ -import Modifier from "ember-modifier"; -import { registerDestructor } from "@ember/destroyable"; -import { bind } from "discourse-common/utils/decorators"; -import { autoUpdate } from "@floating-ui/dom"; -import { updatePosition } from "float-kit/lib/update-position"; - -export default class FloatKitApplyFloatingUi extends Modifier { - constructor(owner, args) { - super(owner, args); - registerDestructor(this, (instance) => instance.teardown()); - } - - modify(element, [trigger, options, instance]) { - instance.content = element; - this.instance = instance; - this.options = options ?? {}; - - if (this.options.autoUpdate) { - this.cleanup = autoUpdate(trigger, element, this.update); - } else { - this.update(); - } - } - - @bind - async update() { - await updatePosition( - this.instance.trigger, - this.instance.content, - this.options - ); - } - - teardown() { - this.cleanup?.(); - } -} diff --git a/app/assets/javascripts/float-kit/addon/modifiers/close-on-click-outside.js b/app/assets/javascripts/float-kit/addon/modifiers/close-on-click-outside.js deleted file mode 100644 index 84b0f64eb8d..00000000000 --- a/app/assets/javascripts/float-kit/addon/modifiers/close-on-click-outside.js +++ /dev/null @@ -1,38 +0,0 @@ -import Modifier from "ember-modifier"; -import { registerDestructor } from "@ember/destroyable"; -import { bind } from "discourse-common/utils/decorators"; - -export default class FloatKitCloseOnClickOutside extends Modifier { - constructor(owner, args) { - super(owner, args); - registerDestructor(this, (instance) => instance.cleanup()); - } - - modify(element, [trigger, closeFn]) { - this.closeFn = closeFn; - this.trigger = trigger; - this.element = element; - document.addEventListener("click", this.check, { - passive: true, - }); - } - - @bind - check(event) { - if (this.element.contains(event.target)) { - return; - } - if ( - this.trigger instanceof HTMLElement && - this.trigger.contains(event.target) - ) { - return; - } - - this.closeFn(); - } - - cleanup() { - document.removeEventListener("click", this.check); - } -} diff --git a/app/assets/javascripts/float-kit/addon/modifiers/close-on-escape.js b/app/assets/javascripts/float-kit/addon/modifiers/close-on-escape.js deleted file mode 100644 index a6d038c4882..00000000000 --- a/app/assets/javascripts/float-kit/addon/modifiers/close-on-escape.js +++ /dev/null @@ -1,33 +0,0 @@ -import Modifier from "ember-modifier"; -import { registerDestructor } from "@ember/destroyable"; -import { bind } from "discourse-common/utils/decorators"; -import { inject as service } from "@ember/service"; - -export default class FloatKitCloseOnEscape extends Modifier { - @service menu; - - constructor(owner, args) { - super(owner, args); - registerDestructor(this, (instance) => instance.cleanup()); - } - - modify(element, [closeFn]) { - this.closeFn = closeFn; - this.element = element; - - document.addEventListener("keydown", this.check); - } - - @bind - check(event) { - if (event.key === "Escape") { - event.stopPropagation(); - event.preventDefault(); - this.closeFn(); - } - } - - cleanup() { - document.removeEventListener("keydown", this.check); - } -} diff --git a/app/assets/javascripts/float-kit/addon/services/menu.js b/app/assets/javascripts/float-kit/addon/services/menu.js deleted file mode 100644 index c132e9ec5e3..00000000000 --- a/app/assets/javascripts/float-kit/addon/services/menu.js +++ /dev/null @@ -1,120 +0,0 @@ -import Service from "@ember/service"; -import { getOwner } from "@ember/application"; -import { action } from "@ember/object"; -import DMenuInstance from "float-kit/lib/d-menu-instance"; -import { guidFor } from "@ember/object/internals"; -import { tracked } from "@glimmer/tracking"; -import { updatePosition } from "float-kit/lib/update-position"; - -export default class Menu extends Service { - @tracked activeMenu; - @tracked portalOutletElement; - - /** - * Render a menu - * - * @param {Element | DMenuInstance} - * - trigger - the element that triggered the menu, can also be an object implementing `getBoundingClientRect` - * - menu - an instance of a menu - * @param {Object} [options] - options - * @param {String | Element | Component} [options.content] - Specifies the content of the menu - * @param {Integer} [options.maxWidth] - Specifies the maximum width of the content - * @param {Object} [options.data] - An object which will be passed as the `@data` argument when content is a `Component` - * @param {Boolean} [options.arrow] - Determines if the menu has an arrow - * @param {Boolean} [options.offset] - Displaces the content from its reference trigger in pixels - * @param {String} [options.identifier] - Add a data-identifier attribute to the trigger and the content - * @param {Boolean} [options.inline] - Improves positioning for trigger that spans over multiple lines - * - * @returns {Promise} - */ - @action - async show() { - let instance; - - if (arguments[0] instanceof DMenuInstance) { - instance = arguments[0]; - - if (this.activeMenu === instance && this.activeMenu.expanded) { - return; - } - } else { - const trigger = arguments[0]; - if ( - this.activeMenu && - this.activeMenu.id === - (trigger?.id?.length ? trigger.id : guidFor(trigger)) && - this.activeMenu.expanded - ) { - this.activeMenu?.close(); - return; - } - - instance = new DMenuInstance(getOwner(this), trigger, arguments[1]); - } - - await this.replace(instance); - instance.expanded = true; - return instance; - } - - /** - * Replaces any active menu- - */ - @action - async replace(menu) { - await this.activeMenu?.close(); - this.activeMenu = menu; - } - - /** - * Closes the active menu - * @param {DMenuInstance} [menu] - the menu to close, if not provider will close any active menu - */ - @action - async close(menu) { - if (this.activeMenu && menu && this.activeMenu.id !== menu.id) { - return; - } - - await this.activeMenu?.close(); - this.activeMenu = null; - } - - /** - * Update the menu position - * @param {DMenuInstance} [menu] - the menu to update, if not provider will update any active menu - */ - @action - async update(menu) { - const instance = menu || this.activeMenu; - if (!instance) { - return; - } - await updatePosition(instance.trigger, instance.content, instance.options); - await instance.show(); - } - - /** - * Register event listeners on a trigger to show a menu - * - * @param {Element} trigger - the element that triggered the menu, can also be an object implementing `getBoundingClientRect` - * @param {Object} [options] - @see `show` - * - * @returns {DMenuInstance} An instance of the menu - */ - @action - register(trigger, options = {}) { - return new DMenuInstance(getOwner(this), trigger, { - ...options, - listeners: true, - beforeTrigger: async (menu) => { - await this.replace(menu); - }, - }); - } - - @action - registerPortalOutletElement(element) { - this.portalOutletElement = element; - } -} diff --git a/app/assets/javascripts/float-kit/addon/services/toasts.js b/app/assets/javascripts/float-kit/addon/services/toasts.js deleted file mode 100644 index 3c1381a5a2c..00000000000 --- a/app/assets/javascripts/float-kit/addon/services/toasts.js +++ /dev/null @@ -1,113 +0,0 @@ -import Service from "@ember/service"; -import { tracked } from "@glimmer/tracking"; -import { TrackedArray } from "@ember-compat/tracked-built-ins"; -import { action } from "@ember/object"; -import DDefaultToast from "float-kit/components/d-default-toast"; -import DToastInstance from "float-kit/lib/d-toast-instance"; -import { getOwner } from "discourse-common/lib/get-owner"; - -export default class Toasts extends Service { - @tracked activeToasts = new TrackedArray(); - - /** - * Render a toast - * - * @param {Object} [options] - options passed to the toast component as `@toast` argument - * @param {String} [options.duration] - The duration (ms) of the toast, will be closed after this time - * @param {ComponentClass} [options.component] - A component to render, will use `DDefaultToast` if not provided - * @param {String} [options.class] - A class added to the d-toast element - * @param {Object} [options.data] - An object which will be passed as the `@data` argument to the component - * - * @returns {DToastInstance} - a toast instance - */ - @action - show(options = {}) { - const instance = new DToastInstance(getOwner(this), options); - this.activeToasts.push(instance); - return instance; - } - - /** - * Render a DDefaultToast toast with the default theme - * - * @param {Object} [options] - @see show - * - * @returns {DToastInstance} - a toast instance - */ - @action - default(options = {}) { - options.data.theme = "default"; - - return this.show({ ...options, component: DDefaultToast }); - } - - /** - * Render a DDefaultToast toast with the success theme - * - * @param {Object} [options] - @see show - * - * @returns {DToastInstance} - a toast instance - */ - @action - success(options = {}) { - options.data.theme = "success"; - options.data.icon = "check"; - - return this.show({ ...options, component: DDefaultToast }); - } - - /** - * Render a DDefaultToast toast with the error theme - * - * @param {Object} [options] - @see show - * - * @returns {DToastInstance} - a toast instance - */ - @action - error(options = {}) { - options.data.theme = "error"; - options.data.icon = "exclamation-triangle"; - - return this.show({ ...options, component: DDefaultToast }); - } - - /** - * Render a DDefaultToast toast with the warning theme - * - * @param {Object} [options] - @see show - * - * @returns {DToastInstance} - a toast instance - */ - @action - warning(options = {}) { - options.data.theme = "warning"; - options.data.icon = "exclamation-circle"; - - return this.show({ ...options, component: DDefaultToast }); - } - - /** - * Render a DDefaultToast toast with the info theme - * - * @param {Object} [options] - @see show - * - * @returns {DToastInstance} - a toast instance - */ - @action - info(options = {}) { - options.data.theme = "info"; - options.data.icon = "info-circle"; - - return this.show({ ...options, component: DDefaultToast }); - } - - /** - * Close a toast. Any object containg a valid `id` property can be used as a toast parameter. - */ - @action - close(toast) { - this.activeToasts = new TrackedArray( - this.activeToasts.filter((activeToast) => activeToast.id !== toast.id) - ); - } -} diff --git a/app/assets/javascripts/float-kit/addon/services/tooltip.js b/app/assets/javascripts/float-kit/addon/services/tooltip.js deleted file mode 100644 index 19eaa29f5be..00000000000 --- a/app/assets/javascripts/float-kit/addon/services/tooltip.js +++ /dev/null @@ -1,120 +0,0 @@ -import Service from "@ember/service"; -import { getOwner } from "@ember/application"; -import { action } from "@ember/object"; -import DTooltipInstance from "float-kit/lib/d-tooltip-instance"; -import { guidFor } from "@ember/object/internals"; -import { tracked } from "@glimmer/tracking"; -import { updatePosition } from "float-kit/lib/update-position"; - -export default class Tooltip extends Service { - @tracked activeTooltip; - @tracked portalOutletElement; - - /** - * Render a tooltip - * - * @param {Element | DTooltipInstance} - * - trigger - the element that triggered the tooltip, can also be an object implementing `getBoundingClientRect` - * - tooltip - an instance of a tooltip - * @param {Object} [options] - options, if trigger given as first argument - * @param {String | Element | Component} [options.content] - Specifies the content of the tooltip - * @param {Integer} [options.maxWidth] - Specifies the maximum width of the content - * @param {Object} [options.data] - An object which will be passed as the `@data` argument when content is a `Component` - * @param {Boolean} [options.arrow] - Determines if the tooltip has an arrow - * @param {Boolean} [options.offset] - Displaces the content from its reference trigger in pixels - * @param {String} [options.identifier] - Add a data-identifier attribute to the trigger and the content - * @param {Boolean} [options.inline] - Improves positioning for trigger that spans over multiple lines - * - * @returns {Promise} - */ - @action - async show() { - let instance; - - if (arguments[0] instanceof DTooltipInstance) { - instance = arguments[0]; - - if (this.activeTooltip === instance && this.activeTooltip.expanded) { - return; - } - } else { - const trigger = arguments[0]; - if ( - this.activeTooltip && - this.activeTooltip.id === - (trigger?.id?.length ? trigger.id : guidFor(trigger)) && - this.activeTooltip.expanded - ) { - this.activeTooltip?.close(); - return; - } - - instance = new DTooltipInstance(getOwner(this), trigger, arguments[1]); - } - - await this.replace(instance); - instance.expanded = true; - return instance; - } - - /** - * Replaces any active tooltip - */ - @action - async replace(tooltip) { - await this.activeTooltip?.close(); - this.activeTooltip = tooltip; - } - - /** - * Closes the active tooltip - * @param {DTooltipInstance} [tooltip] - the tooltip to close, if not provider will close any active tooltip - */ - @action - async close(tooltip) { - if (this.activeTooltip && tooltip && this.activeTooltip.id !== tooltip.id) { - return; - } - - await this.activeTooltip?.close(); - this.activeTooltip = null; - } - - /** - * Update the tooltip position - * @param {DTooltipInstance} [tooltip] - the tooltip to update, if not provider will update any active tooltip - */ - @action - async update(tooltip) { - const instance = tooltip || this.activeTooltip; - if (!instance) { - return; - } - await updatePosition(instance.trigger, instance.content, instance.options); - await instance.show(); - } - - /** - * Register event listeners on a trigger to show a tooltip - * - * @param {Element} trigger - the element that triggered the tooltip, can also be an object implementing `getBoundingClientRect` - * @param {Object} [options] - @see `show` - * - * @returns {DTooltipInstance} An instance of the tooltip - */ - @action - register(trigger, options = {}) { - return new DTooltipInstance(getOwner(this), trigger, { - ...options, - listeners: true, - beforeTrigger: async (tooltip) => { - await this.replace(tooltip); - }, - }); - } - - @action - registerPortalOutletElement(element) { - this.portalOutletElement = element; - } -} diff --git a/app/assets/javascripts/float-kit/app/.gitkeep b/app/assets/javascripts/float-kit/app/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/app/assets/javascripts/float-kit/app/components/d-button-tooltip.js b/app/assets/javascripts/float-kit/app/components/d-button-tooltip.js deleted file mode 100644 index ff10ff34c1b..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-button-tooltip.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-button-tooltip"; diff --git a/app/assets/javascripts/float-kit/app/components/d-default-toast.gjs b/app/assets/javascripts/float-kit/app/components/d-default-toast.gjs deleted file mode 100644 index 3bf6e0d8e6f..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-default-toast.gjs +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-default-toast"; diff --git a/app/assets/javascripts/float-kit/app/components/d-inline-menu.js b/app/assets/javascripts/float-kit/app/components/d-inline-menu.js deleted file mode 100644 index 65c4b0de930..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-inline-menu.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-inline-menu"; diff --git a/app/assets/javascripts/float-kit/app/components/d-inline-tooltip.js b/app/assets/javascripts/float-kit/app/components/d-inline-tooltip.js deleted file mode 100644 index 173122c7b20..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-inline-tooltip.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-inline-tooltip"; diff --git a/app/assets/javascripts/float-kit/app/components/d-menu.js b/app/assets/javascripts/float-kit/app/components/d-menu.js deleted file mode 100644 index 1abf4922f56..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-menu.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-menu"; diff --git a/app/assets/javascripts/float-kit/app/components/d-popover.js b/app/assets/javascripts/float-kit/app/components/d-popover.js deleted file mode 100644 index 9698f99ba72..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-popover.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-popover"; diff --git a/app/assets/javascripts/float-kit/app/components/d-toasts.js b/app/assets/javascripts/float-kit/app/components/d-toasts.js deleted file mode 100644 index 59a465f7240..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-toasts.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-toasts"; diff --git a/app/assets/javascripts/float-kit/app/components/d-tooltip.js b/app/assets/javascripts/float-kit/app/components/d-tooltip.js deleted file mode 100644 index 7f388b800b1..00000000000 --- a/app/assets/javascripts/float-kit/app/components/d-tooltip.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/components/d-tooltip"; diff --git a/app/assets/javascripts/float-kit/app/lib/d-menu-instance.js b/app/assets/javascripts/float-kit/app/lib/d-menu-instance.js deleted file mode 100644 index b26ba8e00ef..00000000000 --- a/app/assets/javascripts/float-kit/app/lib/d-menu-instance.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/lib/d-menu-instance"; diff --git a/app/assets/javascripts/float-kit/app/lib/d-tooltip-instance.js b/app/assets/javascripts/float-kit/app/lib/d-tooltip-instance.js deleted file mode 100644 index 1afb55aca88..00000000000 --- a/app/assets/javascripts/float-kit/app/lib/d-tooltip-instance.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/lib/d-tooltip-instance"; diff --git a/app/assets/javascripts/float-kit/app/services/menu.js b/app/assets/javascripts/float-kit/app/services/menu.js deleted file mode 100644 index 7a5860455d5..00000000000 --- a/app/assets/javascripts/float-kit/app/services/menu.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/services/menu"; diff --git a/app/assets/javascripts/float-kit/app/services/toasts.js b/app/assets/javascripts/float-kit/app/services/toasts.js deleted file mode 100644 index 99ed2c35b61..00000000000 --- a/app/assets/javascripts/float-kit/app/services/toasts.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/services/toasts"; diff --git a/app/assets/javascripts/float-kit/app/services/tooltip.js b/app/assets/javascripts/float-kit/app/services/tooltip.js deleted file mode 100644 index 71206d00609..00000000000 --- a/app/assets/javascripts/float-kit/app/services/tooltip.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from "float-kit/services/tooltip"; diff --git a/app/assets/javascripts/float-kit/config/ember-cli-update.json b/app/assets/javascripts/float-kit/config/ember-cli-update.json deleted file mode 100644 index 994928cd9c9..00000000000 --- a/app/assets/javascripts/float-kit/config/ember-cli-update.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schemaVersion": "1.0.0", - "packages": [ - { - "name": "ember-cli", - "version": "5.0.0", - "blueprints": [ - { - "name": "addon", - "outputRepo": "https://github.com/ember-cli/ember-addon-output", - "codemodsSource": "ember-addon-codemods-manifest@1", - "isBaseBlueprint": true, - "options": [ - "--no-welcome" - ] - } - ] - } - ] -} diff --git a/app/assets/javascripts/float-kit/ember-cli-build.js b/app/assets/javascripts/float-kit/ember-cli-build.js deleted file mode 100644 index da57a67830a..00000000000 --- a/app/assets/javascripts/float-kit/ember-cli-build.js +++ /dev/null @@ -1,27 +0,0 @@ -"use strict"; - -const EmberAddon = require("ember-cli/lib/broccoli/ember-addon"); - -module.exports = function (defaults) { - const app = new EmberAddon(defaults, { - autoImport: { - publicAssetURL: "", - }, - }); - - /* - This build file specifies the options for the dummy test app of this - addon, located in `/tests/dummy` - This build file does *not* influence how the addon or the app using it - behave. You most likely want to be modifying `./index.js` or app's build file - */ - - const { maybeEmbroider } = require("@embroider/test-setup"); - return maybeEmbroider(app, { - skipBabel: [ - { - package: "qunit", - }, - ], - }); -}; diff --git a/app/assets/javascripts/float-kit/index.js b/app/assets/javascripts/float-kit/index.js deleted file mode 100644 index 28c7dca628f..00000000000 --- a/app/assets/javascripts/float-kit/index.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; - -module.exports = { - name: require("./package").name, - options: {}, - isDevelopingAddon() { - return true; - }, -}; diff --git a/app/assets/javascripts/float-kit/jsconfig.json b/app/assets/javascripts/float-kit/jsconfig.json deleted file mode 100644 index 9f224112d4b..00000000000 --- a/app/assets/javascripts/float-kit/jsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../../../jsconfig.base.json", - "compilerOptions": { - "baseUrl": ".", - "paths": { - "float-kit/*": ["./addon/*"], - "discourse/*": ["../discourse/app/*"], - "discourse/tests/*": ["../discourse/tests/*"], - "discourse-common/*": ["../discourse-common/addon/*"], - } - }, -} diff --git a/app/assets/javascripts/float-kit/package.json b/app/assets/javascripts/float-kit/package.json deleted file mode 100644 index b5bb6050cd3..00000000000 --- a/app/assets/javascripts/float-kit/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "float-kit", - "version": "1.0.0", - "description": "Discourse's floating panels component.", - "author": "Discourse", - "license": "GPL-2.0-only", - "keywords": [ - "ember-addon" - ], - "scripts": { - "build": "ember build", - "lint:hbs": "ember-template-lint .", - "lint:js": "eslint .", - "start": "ember serve" - }, - "dependencies": { - "ember-auto-import": "^2.6.3", - "ember-cli-babel": "^7.26.11", - "ember-cli-htmlbars": "^6.3.0", - "ember-template-imports": "^3.4.2" - }, - "devDependencies": { - "@babel/core": "^7.22.10", - "@ember/optional-features": "^2.0.0", - "@ember/string": "^3.1.1", - "@embroider/test-setup": "^3.0.1", - "@glimmer/component": "^1.1.2", - "broccoli-asset-rev": "^3.0.0", - "ember-cli": "~5.0.0", - "ember-cli-inject-live-reload": "^2.1.0", - "ember-cli-sri": "^2.1.1", - "ember-cli-terser": "^4.0.2", - "ember-disable-prototype-extensions": "^1.1.3", - "ember-load-initializers": "^2.1.1", - "ember-resolver": "^10.1.1", - "ember-source": "~3.28.12", - "ember-source-channel-url": "^3.0.0", - "loader.js": "^4.7.0", - "webpack": "^5.88.2" - }, - "engines": { - "node": "16.* || >= 18", - "npm": "please-use-yarn", - "yarn": ">= 1.21.1" - }, - "ember": { - "edition": "default" - } -} diff --git a/app/assets/javascripts/package.json b/app/assets/javascripts/package.json index e73d1f216a9..7b28c5d6886 100644 --- a/app/assets/javascripts/package.json +++ b/app/assets/javascripts/package.json @@ -17,7 +17,6 @@ "ember-production-deprecations", "pretty-text", "select-kit", - "float-kit", "truth-helpers", "wizard" ], diff --git a/app/assets/javascripts/yarn.lock b/app/assets/javascripts/yarn.lock index e0c389221e5..695667c5be7 100644 --- a/app/assets/javascripts/yarn.lock +++ b/app/assets/javascripts/yarn.lock @@ -28,28 +28,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== -"@babel/core@^7.12.0", "@babel/core@^7.14.5", "@babel/core@^7.16.10", "@babel/core@^7.16.7", "@babel/core@^7.21.4", "@babel/core@^7.22.10", "@babel/core@^7.3.4": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.15.tgz#15d4fd03f478a459015a4b94cfbb3bd42c48d2f4" - integrity sha512-PtZqMmgRrvj8ruoEOIwVA3yoF91O+Hgw9o7DAUTNBA6Mo2jpu31clx9a7Nz/9JznqetTR6zwfC4L3LAjKQXUwA== - dependencies: - "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.13" - "@babel/generator" "^7.22.15" - "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.15" - "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.15" - "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.15" - "@babel/types" "^7.22.15" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/core@^7.22.17": +"@babel/core@^7.12.0", "@babel/core@^7.14.5", "@babel/core@^7.16.10", "@babel/core@^7.16.7", "@babel/core@^7.21.4", "@babel/core@^7.22.17", "@babel/core@^7.3.4": version "7.22.17" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866" integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ== @@ -1433,26 +1412,6 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== -"@floating-ui/core@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.4.1.tgz#0d633f4b76052668afb932492ac452f7ebe97f17" - integrity sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ== - dependencies: - "@floating-ui/utils" "^0.1.1" - -"@floating-ui/dom@^1.5.0": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.1.tgz#88b70defd002fe851f17b4a25efb2d3c04d7a8d7" - integrity sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw== - dependencies: - "@floating-ui/core" "^1.4.1" - "@floating-ui/utils" "^0.1.1" - -"@floating-ui/utils@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.1.tgz#1a5b1959a528e374e8037c4396c3e825d6cf4a83" - integrity sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw== - "@glimmer/component@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@glimmer/component/-/component-1.1.2.tgz#892ec0c9f0b6b3e41c112be502fde073cf24d17c" @@ -1624,7 +1583,7 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@popperjs/core@^2.11.8": +"@popperjs/core@^2.11.8", "@popperjs/core@^2.9.0": version "2.11.8" resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== @@ -10307,6 +10266,13 @@ tiny-lr@^2.0.0: object-assign "^4.1.0" qs "^6.4.0" +tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + tmp@0.0.28: version "0.0.28" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" diff --git a/app/assets/stylesheets/color_definitions.scss b/app/assets/stylesheets/color_definitions.scss index 0c99452ae93..5211a129cca 100644 --- a/app/assets/stylesheets/color_definitions.scss +++ b/app/assets/stylesheets/color_definitions.scss @@ -144,7 +144,4 @@ --shadow-header: 0 2px 4px -1px rgba(0, 0, 0, #{$shadow-opacity-header}); --shadow-footer-nav: 0 0 2px 0 rgba(0, 0, 0, #{$shadow-opacity-footer-nav}); --shadow-focus-danger: 0 0 6px 0 var(--danger); - - --float-kit-arrow-stroke-color: var(--primary-low); - --float-kit-arrow-fill-color: var(--secondary); } diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index c93b705538d..9ec8d1776c0 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -3,6 +3,8 @@ @import "vendor/normalize-ext"; @import "vendor/pikaday"; @import "vendor/rotate-center"; +@import "vendor/tippy"; +@import "vendor/svg-arrow"; @import "common/whcm"; @import "common/foundation/helpers"; @import "common/foundation/base"; @@ -17,4 +19,3 @@ @import "common/software-update-prompt"; @import "common/topic-timeline"; @import "common/loading-slider"; -@import "common/float-kit/_index"; diff --git a/app/assets/stylesheets/common/base/_index.scss b/app/assets/stylesheets/common/base/_index.scss index 387651c4906..74c56a123c2 100644 --- a/app/assets/stylesheets/common/base/_index.scss +++ b/app/assets/stylesheets/common/base/_index.scss @@ -12,6 +12,7 @@ @import "crawler_layout"; @import "d-image-grid"; @import "d-icon"; +@import "d-popover"; @import "dialog"; @import "directory"; @import "discourse"; diff --git a/app/assets/stylesheets/common/base/d-popover.scss b/app/assets/stylesheets/common/base/d-popover.scss new file mode 100644 index 00000000000..8b9c8f0c587 --- /dev/null +++ b/app/assets/stylesheets/common/base/d-popover.scss @@ -0,0 +1,32 @@ +$d-popover-background: var(--secondary); +$d-popover-border: var(--primary-low); + +.tippy-box { + color: var(--primary); + background: $d-popover-background; + border: 1px solid var(--primary-low); + box-shadow: var(--shadow-menu-panel); + border-radius: var(--d-border-radius); + + > .tippy-svg-arrow { + color: $d-popover-background; + } +} + +.tippy-box[data-placement^="top"] .tippy-svg-arrow > svg { + top: 12px; +} +.tippy-box[data-placement^="bottom"] .tippy-svg-arrow > svg { + top: -10px; +} + +#tippy-rounded-arrow { + .svg-arrow { + fill: $d-popover-border; + } +} + +[data-tooltip] > *, +[data-popover] > * { + pointer-events: none; +} diff --git a/app/assets/stylesheets/common/base/search-menu.scss b/app/assets/stylesheets/common/base/search-menu.scss index d1f3e54e0be..31b8a865214 100644 --- a/app/assets/stylesheets/common/base/search-menu.scss +++ b/app/assets/stylesheets/common/base/search-menu.scss @@ -26,7 +26,6 @@ $search-pad-horizontal: 0.5em; align-items: center; border: 1px solid var(--primary-medium); border-radius: var(--d-border-radius-large); - input#search-term { border-width: 0; border-radius: var(--d-border-radius-large); diff --git a/app/assets/stylesheets/common/base/sidebar-section.scss b/app/assets/stylesheets/common/base/sidebar-section.scss index f886c8f1f69..98d8636852b 100644 --- a/app/assets/stylesheets/common/base/sidebar-section.scss +++ b/app/assets/stylesheets/common/base/sidebar-section.scss @@ -150,9 +150,3 @@ } } } - -.sidebar-section-header-global-indicator__content { - .d-icon-shield-alt { - padding-right: 0.25rem; - } -} diff --git a/app/assets/stylesheets/common/base/sidebar.scss b/app/assets/stylesheets/common/base/sidebar.scss index f4ef150d1aa..c4ba5a41698 100644 --- a/app/assets/stylesheets/common/base/sidebar.scss +++ b/app/assets/stylesheets/common/base/sidebar.scss @@ -217,11 +217,6 @@ } } } - - .always-public-tooltip { - padding-right: 0.5rem; - } - .btn-flat.add-link { margin-top: 0.5em; margin-left: -0.5em; diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 82bf2379e15..49504acf2c6 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -560,8 +560,18 @@ aside.quote { } .quote-button { + display: none; + position: absolute; + z-index: z("dropdown"); + background-color: var(--secondary); + border: 1px solid var(--primary-low); + box-shadow: var(--shadow-card); flex-direction: column; + &.animated { + transition: top 0.1s linear, left 0.1s linear; + } + &.visible { display: flex; } @@ -599,9 +609,12 @@ aside.quote { } .btn-flat { - &:hover { - .d-icon { - color: var(--tertiary); + .d-icon { + color: var(--primary-high); + } + .discourse-no-touch & { + &:hover { + background-color: var(--tertiary-low); } } } diff --git a/app/assets/stylesheets/common/base/user-tips.scss b/app/assets/stylesheets/common/base/user-tips.scss index 94fe31ba042..ea432faabfe 100644 --- a/app/assets/stylesheets/common/base/user-tips.scss +++ b/app/assets/stylesheets/common/base/user-tips.scss @@ -1,24 +1,49 @@ -[data-content][data-identifier="user-tip"] { - min-width: 300px; +.tippy-box[data-theme="user-tip"] { background-color: var(--tertiary); - border: none; color: var(--secondary); - --float-kit-arrow-stroke-color: var(--tertiary); - --float-kit-arrow-fill-color: var(--tertiary); + .btn-flat { + color: var(--secondary); - .user-tip__container { + &:hover { + color: var(--d-hover); + } + } + + .btn-primary { + background: var(--secondary); + color: var(--tertiary); + + &:hover { + color: var(--tertiary-hover); + } + + .d-icon { + color: var(--tertiary); + } + } + + > .tippy-svg-arrow { + color: var(--tertiary); + } +} + +.user-tip { + z-index: z("composer", "content") - 1; + + &__container { font-weight: normal; + min-width: 300px; padding: 0.5em; text-align: left; } - .user-tip__title { + &__title { font-size: var(--font-up-2); font-weight: bold; } - .user-tip__content { + &__content { margin-top: 0.25em; a { @@ -27,12 +52,17 @@ } } - .user-tip__buttons { + &__buttons { margin-top: 1em; } - - .btn-primary { - background: var(--secondary); - color: var(--tertiary); - } +} + +.tippy-box[data-placement^="left"] > .tippy-svg-arrow { + right: -1px; +} + +.tippy-box[data-theme~="user-tips"] > .tippy-svg-arrow:after, +.tippy-box[data-theme~="user-tips"] > .tippy-svg-arrow > svg { + width: 18px; + height: 18px; } diff --git a/app/assets/stylesheets/common/components/_index.scss b/app/assets/stylesheets/common/components/_index.scss index 9f750493453..847205aa6b0 100644 --- a/app/assets/stylesheets/common/components/_index.scss +++ b/app/assets/stylesheets/common/components/_index.scss @@ -9,6 +9,7 @@ @import "calendar-date-time-input"; @import "convert-to-public-topic-modal"; @import "d-lightbox"; +@import "d-tooltip"; @import "d-toggle-switch"; @import "date-input"; @import "date-picker"; @@ -45,4 +46,3 @@ @import "user-stream-item"; @import "user-stream"; @import "widget-dropdown"; -@import "admin-post-menu"; diff --git a/app/assets/stylesheets/common/components/admin-post-menu.scss b/app/assets/stylesheets/common/components/admin-post-menu.scss deleted file mode 100644 index 09bb530e350..00000000000 --- a/app/assets/stylesheets/common/components/admin-post-menu.scss +++ /dev/null @@ -1,20 +0,0 @@ -[data-content][data-identifier="admin-post-menu"] { - ul { - padding: 0.5rem; - margin: 0; - list-style: none; - - li .btn { - width: 100%; - justify-content: flex-start; - } - - li { - margin-bottom: 2px; - - &:last-child { - margin-bottom: 0; - } - } - } -} diff --git a/app/assets/stylesheets/common/components/buttons.scss b/app/assets/stylesheets/common/components/buttons.scss index 56d8936a620..95909e5c689 100644 --- a/app/assets/stylesheets/common/components/buttons.scss +++ b/app/assets/stylesheets/common/components/buttons.scss @@ -381,60 +381,6 @@ } } -.btn-transparent { - background: none; - border: 0; - color: var(--primary); - - &.btn-primary, - &.btn-primary:focus, - &.btn-primary:hover { - .d-icon { - color: var(--tertiary) !important; - } - } - &.btn-danger, - &.btn-danger:focus, - &.btn-danger:hover { - .d-icon { - color: var(--danger) !important; - } - } - &.btn-success, - &.btn-success:focus, - &.btn-success:hover { - .d-icon { - color: var(--success) !important; - } - } - - .discourse-no-touch & { - &:hover { - color: var(--primary); - background: var(--d-hover); - .d-icon { - color: var(--primary); - } - } - } - - &:focus { - color: var(--primary); - background: var(--d-hover); - .d-icon { - color: var(--primary); - } - } - - &:focus-visible { - color: var(--primary); - background: var(--d-hover); - .d-icon { - color: var(--primary); - } - } -} - .btn-mini-toggle { border-radius: var(--d-border-radius); padding: 0.4em 0.467em; diff --git a/app/assets/stylesheets/common/components/d-tooltip.scss b/app/assets/stylesheets/common/components/d-tooltip.scss new file mode 100644 index 00000000000..28433f513db --- /dev/null +++ b/app/assets/stylesheets/common/components/d-tooltip.scss @@ -0,0 +1,12 @@ +// ".tippy-box" is one of the classes tippy.js uses for creating tooltips +// see https://atomiks.github.io/tippyjs/v6/themes/#tippy-elements +// +// Using `data-theme~="d-tooltip"` scopes down these styles +// to tooltips created using the d-tooltip component +.tippy-box[data-theme~="d-tooltip"] { + color: var(--primary); + background: var(--secondary); + border: 1px solid var(--primary-low); + box-shadow: var(--shadow-menu-panel); + overflow-wrap: break-word; +} diff --git a/app/assets/stylesheets/common/components/download-calendar.scss b/app/assets/stylesheets/common/components/download-calendar.scss index fd8693db0c6..2acfb340f80 100644 --- a/app/assets/stylesheets/common/components/download-calendar.scss +++ b/app/assets/stylesheets/common/components/download-calendar.scss @@ -2,7 +2,7 @@ margin-top: 2em; } -.download-calendar { +div[data-tippy-root] .download-calendar { color: var(--primary-med-or-secondary-med); } diff --git a/app/assets/stylesheets/common/components/user-card.scss b/app/assets/stylesheets/common/components/user-card.scss index c1b6a3e8c2a..3c9a807ca49 100644 --- a/app/assets/stylesheets/common/components/user-card.scss +++ b/app/assets/stylesheets/common/components/user-card.scss @@ -37,14 +37,11 @@ .user-card, .group-card { width: var(--card-width); + box-shadow: var(--shadow-card); color: var(--primary); background: var(--secondary) center center; background-size: cover; - position: unset !important; - margin: 0 !important; - border-radius: 0 !important; - box-shadow: unset !important; - z-index: unset !important; + outline: 2px solid transparent; .card-content { padding: 10px; diff --git a/app/assets/stylesheets/common/components/user-status-message.scss b/app/assets/stylesheets/common/components/user-status-message.scss index 3c2b384593d..b8f1aae0c4d 100644 --- a/app/assets/stylesheets/common/components/user-status-message.scss +++ b/app/assets/stylesheets/common/components/user-status-message.scss @@ -1,22 +1,22 @@ -[data-content][data-identifier="user-status-message-tooltip"] { +.user-status-message-description { + margin-left: 0.1em; + color: var(--primary-800); +} + +.user-status-message-tooltip { .emoji { width: 1em; height: 1em; } - .user-status-message-description { - margin-left: 0.1rem; - color: var(--primary-800); - } - .user-status-tooltip-description { font-weight: bold; - margin-left: 0.25rem; + margin-left: 0.1em; vertical-align: middle; } .user-status-tooltip-until { - margin-top: 0.1rem; + margin-top: 0.2em; color: var(--primary-medium); } } diff --git a/app/assets/stylesheets/common/float-kit/_index.scss b/app/assets/stylesheets/common/float-kit/_index.scss deleted file mode 100644 index 6754da592bc..00000000000 --- a/app/assets/stylesheets/common/float-kit/_index.scss +++ /dev/null @@ -1,5 +0,0 @@ -@import "d-menu"; -@import "d-tooltip"; -@import "d-button-tooltip"; -@import "d-toasts"; -@import "d-default-toast"; diff --git a/app/assets/stylesheets/common/float-kit/d-button-tooltip.scss b/app/assets/stylesheets/common/float-kit/d-button-tooltip.scss deleted file mode 100644 index 7644c6560d0..00000000000 --- a/app/assets/stylesheets/common/float-kit/d-button-tooltip.scss +++ /dev/null @@ -1,12 +0,0 @@ -.fk-d-button-tooltip { - display: inline-flex; - align-items: center; - - .fk-d-tooltip__trigger { - background: var(--primary-very-low); - height: 100%; - align-items: center; - display: flex; - padding-inline: 0.5rem; - } -} diff --git a/app/assets/stylesheets/common/float-kit/d-default-toast.scss b/app/assets/stylesheets/common/float-kit/d-default-toast.scss deleted file mode 100644 index 3be87e4e43e..00000000000 --- a/app/assets/stylesheets/common/float-kit/d-default-toast.scss +++ /dev/null @@ -1,101 +0,0 @@ -.fk-d-default-toast { - display: flex; - flex: 1 1 auto; - max-width: 350px; - padding: 0.5rem; - - &__close-container { - width: calc(40px - 0.5rem); - height: 30px; - } - - &__icon-container { - flex: 1 0 auto; - display: flex; - width: calc(40px - 0.5rem); - height: 30px; - align-items: center; - justify-content: center; - - &.alert-success { - background-color: var(--success-low); - color: var(--primary); - } - &.alert-error { - background-color: var(--danger-low); - color: var(--primary); - } - &.alert-warning { - background-color: var(--highlight-bg); - color: var(--primary); - } - &.alert-info { - background-color: var(--tertiary-low); - color: var(--primary); - &.clickable { - color: var(--tertiary); - z-index: z("base"); - } - } - - .-success & { - .d-icon { - color: var(--success); - } - } - - .-error & { - .d-icon { - color: var(--danger); - } - } - - .-warning & { - .d-icon { - color: var(--highlight); - } - } - - .-info & { - .d-icon { - color: var(--tertiary); - } - } - } - - &__main-container { - box-sizing: border-box; - display: flex; - flex-direction: column; - width: 100%; - min-height: 30px; - } - - &__texts { - min-height: 30px; - display: flex; - justify-content: center; - flex-direction: column; - } - - &__actions { - display: flex; - flex-wrap: wrap; - padding-top: 1rem; - margin-bottom: -0.5rem; - - .btn { - margin-right: 0.5rem; - margin-bottom: 0.5rem; - } - } - - &__title { - display: flex; - font-weight: 700; - } - - &__message { - display: flex; - } -} diff --git a/app/assets/stylesheets/common/float-kit/d-menu.scss b/app/assets/stylesheets/common/float-kit/d-menu.scss deleted file mode 100644 index 23249ed8ba6..00000000000 --- a/app/assets/stylesheets/common/float-kit/d-menu.scss +++ /dev/null @@ -1,91 +0,0 @@ -@keyframes d-menu-opening { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -.fk-d-menu { - width: max-content; - position: absolute; - top: 0; - left: 0; - max-width: 600px; - display: flex; - padding: 0; - z-index: z("dropdown"); - - &__trigger { - .touch & { - @include unselectable; - } - } - - &.-animated { - animation: d-menu-opening 0.15s ease-in; - - &[data-placement^="bottom"] { - transform-origin: top center; - } - - &[data-placement^="top"] { - transform-origin: bottom center; - } - - &[data-placement^="right"] { - transform-origin: center left; - } - - &[data-placement^="left"] { - transform-origin: center right; - } - } - - &[data-strategy="fixed"] { - position: fixed; - } - - &__inner-content { - display: flex; - border-radius: var(--d-border-radius); - background-color: var(--secondary); - border: 1px solid var(--primary-low); - box-shadow: var(--shadow-menu-panel); - } - - .arrow { - z-index: z("max"); - position: absolute; - color: var(--secondary); - } - - &[data-placement^="top"] { - .arrow { - bottom: -9px; - rotate: 180deg; - } - } - - &[data-placement^="bottom"] { - .arrow { - top: -9px; - } - } - - &[data-placement^="right"] { - .arrow { - rotate: -90deg; - left: -9px; - } - } - - &[data-placement^="left"] { - .arrow { - rotate: 90deg; - right: -9px; - } - } -} diff --git a/app/assets/stylesheets/common/float-kit/d-toasts.scss b/app/assets/stylesheets/common/float-kit/d-toasts.scss deleted file mode 100644 index 6619ca13080..00000000000 --- a/app/assets/stylesheets/common/float-kit/d-toasts.scss +++ /dev/null @@ -1,48 +0,0 @@ -@keyframes d-toast-opening { - 0% { - transform: translateX(0px); - } - 50% { - transform: translateX(-5px); - } - 100% { - transform: translateX(0px); - } -} - -.fk-d-toasts { - position: fixed; - top: 5px; - right: 5px; - z-index: z("max"); - - .mobile-view & { - left: 5px; - } - - .fk-d-toast { - box-sizing: border-box; - opacity: 1; - transition: opacity 0.5s; - border-radius: var(--d-border-radius); - overflow: hidden; - background-color: var(--secondary); - border: 1px solid var(--primary-low); - box-shadow: var(--shadow-menu-panel); - overflow-wrap: break-word; - display: flex; - animation: d-toast-opening 0.5s ease-in-out; - - &:hover { - border-color: var(--primary-300); - } - - &.-fade-out { - opacity: 0; - } - - & + .d-toast { - margin-top: 0.25rem; - } - } -} diff --git a/app/assets/stylesheets/common/float-kit/d-tooltip.scss b/app/assets/stylesheets/common/float-kit/d-tooltip.scss deleted file mode 100644 index d2f1fc79250..00000000000 --- a/app/assets/stylesheets/common/float-kit/d-tooltip.scss +++ /dev/null @@ -1,91 +0,0 @@ -@keyframes d-tooltip-opening { - 0% { - opacity: 0; - } - - 100% { - opacity: 1; - } -} - -.fk-d-tooltip { - background-color: var(--secondary); - border-radius: var(--d-border-radius); - border: 1px solid var(--primary-low); - box-shadow: var(--shadow-menu-panel); - z-index: z("tooltip"); - width: max-content; - position: absolute; - top: 0; - left: 0; - display: flex !important; - padding: 0; - - &__trigger { - display: inline-flex; - - .touch & { - @include unselectable; - } - } - - &.-animated { - animation: d-tooltip-opening 0.15s ease-in; - - &[data-placement^="bottom"] { - transform-origin: top center; - } - - &[data-placement^="top"] { - transform-origin: bottom center; - } - - &[data-placement^="right"] { - transform-origin: center left; - } - - &[data-placement^="left"] { - transform-origin: center right; - } - } - - &__inner-content { - display: flex; - overflow: hidden; - overflow-wrap: break-word; - padding: 0.5rem; - align-items: center; - } - - .arrow { - z-index: z("max"); - position: absolute; - } - - &[data-placement^="top"] { - .arrow { - bottom: -9px; - rotate: 180deg; - } - } - - &[data-placement^="bottom"] { - .arrow { - top: -9px; - } - } - - &[data-placement^="right"] { - .arrow { - rotate: -90deg; - left: -9px; - } - } - - &[data-placement^="left"] { - .arrow { - rotate: 90deg; - right: -9px; - } - } -} diff --git a/app/assets/stylesheets/desktop/components/user-card.scss b/app/assets/stylesheets/desktop/components/user-card.scss index fca587b11bb..e048b9ca956 100644 --- a/app/assets/stylesheets/desktop/components/user-card.scss +++ b/app/assets/stylesheets/desktop/components/user-card.scss @@ -1,6 +1,14 @@ // shared styles for user and group cards .user-card, .group-card { + z-index: z("usercard"); + &.fixed { + position: fixed; + z-index: z("header") + 1; + } + &.docked-card { + z-index: z("header") + 1; + } // avatar - names - controls .first-row { .names { diff --git a/app/assets/stylesheets/mobile/components/user-card.scss b/app/assets/stylesheets/mobile/components/user-card.scss index aa2f04ba7ef..f114ed1647e 100644 --- a/app/assets/stylesheets/mobile/components/user-card.scss +++ b/app/assets/stylesheets/mobile/components/user-card.scss @@ -1,14 +1,11 @@ -[data-content][data-identifier="card"] { - z-index: z("max"); -} - // shared styles for user and group cards .user-card, .group-card { + // mobile cards should always be on top of everything - 1102 + z-index: z("mobile-composer") + 2; max-width: 95vw; - margin: 0; + margin: 0 2.5vw; max-height: 85vh; // 2.5vh margin-top and margin-bottom. 10vh top - box-sizing: border-box; // avatar - names - controls .first-row { flex-wrap: wrap; diff --git a/app/assets/stylesheets/vendor/svg-arrow.css b/app/assets/stylesheets/vendor/svg-arrow.css new file mode 100644 index 00000000000..c2a61ad7ae3 --- /dev/null +++ b/app/assets/stylesheets/vendor/svg-arrow.css @@ -0,0 +1 @@ +.tippy-box[data-placement^=top]>.tippy-svg-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-svg-arrow:after,.tippy-box[data-placement^=top]>.tippy-svg-arrow>svg{top:16px;transform:rotate(180deg)}.tippy-box[data-placement^=bottom]>.tippy-svg-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:16px}.tippy-box[data-placement^=left]>.tippy-svg-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-svg-arrow:after,.tippy-box[data-placement^=left]>.tippy-svg-arrow>svg{transform:rotate(90deg);top:calc(50% - 3px);left:11px}.tippy-box[data-placement^=right]>.tippy-svg-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-svg-arrow:after,.tippy-box[data-placement^=right]>.tippy-svg-arrow>svg{transform:rotate(-90deg);top:calc(50% - 3px);right:11px}.tippy-svg-arrow{width:16px;height:16px;fill:#333;text-align:initial}.tippy-svg-arrow,.tippy-svg-arrow>svg{position:absolute} \ No newline at end of file diff --git a/app/assets/stylesheets/vendor/tippy.css b/app/assets/stylesheets/vendor/tippy.css new file mode 100644 index 00000000000..e6ae635cb1f --- /dev/null +++ b/app/assets/stylesheets/vendor/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md index f11dbad05a4..6473d754758 100644 --- a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md +++ b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md @@ -7,18 +7,12 @@ in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.12.0] - 2023-09-06 - -### Added - -- Adds `addPostAdminMenuButton` which allows to register a new button in the post admin menu. - ## [1.11.0] - 2023-08-30 ### Added -- Adds `addBeforeAuthCompleteCallback` which allows plugins and themes to add functions to be - evaluated before the auth-complete logic is run. If any of these callbacks return false, the +- Adds `addBeforeAuthCompleteCallback` which allows plugins and themes to add functions to be + evaluated before the auth-complete logic is run. If any of these callbacks return false, the auth-complete logic will be aborted. ## [1.10.0] - 2023-08-25 @@ -45,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.8.0] - 2023-07-18 ### Added -- Adds `addSidebarPanel` which is experimental, and adds a Sidebar panel by returning a class which extends from the +- Adds `addSidebarPanel` which is experimental, and adds a Sidebar panel by returning a class which extends from the BaseCustomSidebarPanel class. - Adds `setSidebarPanel` which is experimental, and sets the current sidebar panel. diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.hbs index e9b8c74727e..710fca376ab 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.hbs @@ -1,24 +1,30 @@ {{#if @buttons.length}} - -
    + /> + {{#if this.isExpanded}} +
      {{#each @buttons as |button|}}
    • {{/each}}
    - + {{/if}} {{/if}} \ No newline at end of file diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.js b/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.js index 94059e2ad32..70ee9a414b1 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.js +++ b/plugins/chat/assets/javascripts/discourse/components/chat-composer-dropdown.js @@ -1,10 +1,68 @@ import Component from "@glimmer/component"; +import { iconHTML } from "discourse-common/lib/icon-library"; +import tippy from "tippy.js"; import { action } from "@ember/object"; +import { hideOnEscapePlugin } from "discourse/lib/d-popover"; +import { tracked } from "@glimmer/tracking"; export default class ChatComposerDropdown extends Component { + @tracked isExpanded = false; + @tracked tippyInstance = null; + + trigger = null; + @action - onButtonClick(button, closeFn) { - closeFn(); + setupTrigger(element) { + this.trigger = element; + } + + get ariaControls() { + return this.tippyInstance?.popper?.id; + } + + @action + toggleExpand() { + if (this.args.hasActivePanel) { + this.args.onCloseActivePanel?.(); + } else { + this.isExpanded = !this.isExpanded; + } + } + + @action + onButtonClick(button) { + this.tippyInstance.hide(); button.action(); } + + @action + setupPanel(element) { + this.tippyInstance = tippy(this.trigger, { + theme: "chat-composer-dropdown", + trigger: "click", + zIndex: 1400, + arrow: iconHTML("tippy-rounded-arrow"), + interactive: true, + allowHTML: false, + appendTo: "parent", + hideOnClick: true, + plugins: [hideOnEscapePlugin], + content: element, + onShow: () => { + this.isExpanded = true; + return true; + }, + onHide: () => { + this.isExpanded = false; + return true; + }, + }); + + this.tippyInstance.show(); + } + + @action + teardownPanel() { + this.tippyInstance?.destroy(); + } } diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-composer.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-composer.hbs index 66a32b97f1e..9d12ae0bc5d 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-composer.hbs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-composer.hbs @@ -35,6 +35,13 @@
    - {{! template-lint-disable modifier-name-case }} - {{#if (and @reaction this.emojiUrl)}} - - {{/if}} - - - @service capabilities; - @service currentUser; - @service tooltip; - @service site; - - @tracked isActive = false; - - registerTooltip = modifier((element) => { - if (!this.popoverContent?.length) { - return; - } - - const instance = this.tooltip.register(element, { - content: htmlSafe(this.popoverContent), - identifier: "chat-message-reaction-tooltip", - animated: false, - placement: "top", - fallbackPlacements: ["bottom"], - triggers: this.site.mobileView ? ["hold"] : ["hover"], - }); - - return () => { - instance?.destroy(); - }; - }); - - get showCount() { - return this.args.showCount ?? true; - } - - get emojiString() { - return `:${this.args.reaction.emoji}:`; - } - - get emojiUrl() { - return emojiUrlFor(this.args.reaction.emoji); - } - - @action - handleClick(event) { - event.stopPropagation(); - - this.args.onReaction?.( - this.args.reaction.emoji, - this.args.reaction.reacted ? "remove" : "add" - ); - - this.tooltip.close(); - } - - @cached - get popoverContent() { - if (!this.args.reaction.count || !this.args.reaction.users?.length) { - return; - } - - return emojiUnescape(getReactionText(this.args.reaction, this.currentUser)); - } -} diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.hbs new file mode 100644 index 00000000000..44aa89c5dda --- /dev/null +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.hbs @@ -0,0 +1,30 @@ +{{#if (and @reaction this.emojiUrl)}} + +{{/if}} \ No newline at end of file diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js new file mode 100644 index 00000000000..1511eec04a1 --- /dev/null +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message-reaction.js @@ -0,0 +1,156 @@ +import Component from "@glimmer/component"; +import { action } from "@ember/object"; +import { emojiUnescape, emojiUrlFor } from "discourse/lib/text"; +import { cancel } from "@ember/runloop"; +import { inject as service } from "@ember/service"; +import setupPopover from "discourse/lib/d-popover"; +import discourseLater from "discourse-common/lib/later"; +import { tracked } from "@glimmer/tracking"; +import { getReactionText } from "discourse/plugins/chat/discourse/lib/get-reaction-text"; + +export default class ChatMessageReaction extends Component { + @service capabilities; + @service currentUser; + + @tracked isActive = false; + + get showCount() { + return this.args.showCount ?? true; + } + + @action + setup(element) { + this.setupListeners(element); + this.setupTooltip(element); + } + + @action + teardown() { + cancel(this.longPressHandler); + this.teardownTooltip(); + } + + @action + setupListeners(element) { + this.element = element; + + if (this.capabilities.touch) { + this.element.addEventListener("touchstart", this.onTouchStart, { + passive: true, + }); + this.element.addEventListener("touchmove", this.cancelTouch, { + passive: true, + }); + this.element.addEventListener("touchend", this.onTouchEnd); + this.element.addEventListener("touchCancel", this.cancelTouch); + } + + this.element.addEventListener("click", this.handleClick, { + passive: true, + }); + } + + @action + teardownListeners() { + if (this.capabilities.touch) { + this.element.removeEventListener("touchstart", this.onTouchStart, { + passive: true, + }); + this.element.removeEventListener("touchmove", this.cancelTouch, { + passive: true, + }); + this.element.removeEventListener("touchend", this.onTouchEnd); + this.element.removeEventListener("touchCancel", this.cancelTouch); + } + + this.element.removeEventListener("click", this.handleClick, { + passive: true, + }); + } + + @action + onTouchStart(event) { + event.stopPropagation(); + this.isActive = true; + + this.longPressHandler = discourseLater(() => { + this.touching = false; + }, 400); + + this.touching = true; + } + + @action + cancelTouch() { + cancel(this.longPressHandler); + this._tippyInstance?.hide(); + this.touching = false; + this.isActive = false; + } + + @action + onTouchEnd(event) { + event.preventDefault(); + + if (this.touching) { + this.handleClick(event); + } + + cancel(this.longPressHandler); + this._tippyInstance?.hide(); + this.isActive = false; + } + + @action + setupTooltip(element) { + this._tippyInstance = setupPopover(element, { + trigger: "mouseenter", + interactive: false, + allowHTML: true, + offset: [0, 10], + onShow(instance) { + if (instance.props.content === "") { + return false; + } + }, + }); + } + + @action + teardownTooltip() { + this._tippyInstance?.destroy(); + } + + @action + refreshTooltip() { + this._tippyInstance?.setContent(this.popoverContent || ""); + } + + get emojiString() { + return `:${this.args.reaction.emoji}:`; + } + + get emojiUrl() { + return emojiUrlFor(this.args.reaction.emoji); + } + + @action + handleClick(event) { + event.stopPropagation(); + + this.args.onReaction?.( + this.args.reaction.emoji, + this.args.reaction.reacted ? "remove" : "add" + ); + + this._tippyInstance?.clearDelayTimeouts(); + } + + get popoverContent() { + if (!this.args.reaction.count || !this.args.reaction.users?.length) { + return; + } + + return emojiUnescape(getReactionText(this.args.reaction, this.currentUser)); + } +} diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-message.gjs b/plugins/chat/assets/javascripts/discourse/components/chat-message.gjs index e5f7687406e..c93132059b5 100644 --- a/plugins/chat/assets/javascripts/discourse/components/chat-message.gjs +++ b/plugins/chat/assets/javascripts/discourse/components/chat-message.gjs @@ -34,6 +34,7 @@ import willDestroy from "@ember/render-modifiers/modifiers/will-destroy"; import ChatOnLongPress from "discourse/plugins/chat/discourse/modifiers/chat/on-long-press"; let _chatMessageDecorators = []; +let _tippyInstances = []; export function addChatMessageDecorator(decorator) { _chatMessageDecorators.push(decorator); @@ -296,6 +297,13 @@ export default class ChatMessage extends Component { this.#teardownMentionedUsers(); } + #destroyTippyInstances() { + _tippyInstances.forEach((instance) => { + instance.destroy(); + }); + _tippyInstances = []; + } + @action refreshStatusOnMentions() { schedule("afterRender", () => { @@ -306,7 +314,7 @@ export default class ChatMessage extends Component { ); mentions.forEach((mention) => { - updateUserStatusOnMention(getOwner(this), mention, user.status); + updateUserStatusOnMention(mention, user.status, _tippyInstances); }); }); }); @@ -588,5 +596,6 @@ export default class ChatMessage extends Component { user.stopTrackingStatus(); user.off("status-changed", this, "refreshStatusOnMentions"); }); + this.#destroyTippyInstances(); } } diff --git a/plugins/chat/assets/javascripts/discourse/helpers/noop.js b/plugins/chat/assets/javascripts/discourse/helpers/noop.js new file mode 100644 index 00000000000..c224727fc2e --- /dev/null +++ b/plugins/chat/assets/javascripts/discourse/helpers/noop.js @@ -0,0 +1,5 @@ +import { helper } from "@ember/component/helper"; + +export default helper(function noop() { + return () => {}; +}); diff --git a/plugins/chat/assets/stylesheets/common/chat-composer-dropdown.scss b/plugins/chat/assets/stylesheets/common/chat-composer-dropdown.scss index 9eb8444f66d..d0a3364fdd4 100644 --- a/plugins/chat/assets/stylesheets/common/chat-composer-dropdown.scss +++ b/plugins/chat/assets/stylesheets/common/chat-composer-dropdown.scss @@ -1,3 +1,11 @@ +[data-theme="chat-composer-dropdown"] { + margin-left: 0.2rem; + + .tippy-content { + padding: 0; + } +} + .chat-composer.is-disabled { .no-touch & { .chat-composer-dropdown__trigger-btn:hover { @@ -10,9 +18,7 @@ } .chat-composer-dropdown__trigger-btn { - margin-left: 0.2rem; transition: transform 0.25s ease-in-out; - .d-icon { padding: 5px; transition: transform 0.1s ease-in-out; @@ -20,25 +26,14 @@ border-radius: 100%; } - &:focus, - &:hover, - &:active { - .d-icon { - color: var(--primary) !important; - } - - background: none !important; - background-image: none !important; - } - &:hover { transform: scale(1.1); } - &.-expanded { + &[aria-expanded="true"] { .d-icon { transform: rotate(135deg); - transform-origin: center center; + transform-origin: center; } } } @@ -50,9 +45,9 @@ } .chat-composer-dropdown__action-btn { + background: none; width: 100%; justify-content: flex-start; - background: none; .d-icon { color: var(--primary); diff --git a/plugins/chat/assets/stylesheets/common/chat-message.scss b/plugins/chat/assets/stylesheets/common/chat-message.scss index ea179c45e39..a05bff4c16d 100644 --- a/plugins/chat/assets/stylesheets/common/chat-message.scss +++ b/plugins/chat/assets/stylesheets/common/chat-message.scss @@ -24,14 +24,6 @@ } } -[data-content][data-identifier="chat-message-reaction-tooltip"] { - font-size: var(--font-down-1); - - .emoji { - padding-left: 0.5rem; - } -} - .chat-message { align-items: flex-start; padding: 0.25em 0.5em 0.25em 0.75em; @@ -234,6 +226,10 @@ } } + &:has(.tippy-box) { + position: relative; + z-index: 1; + } .chat-message-reaction-list .chat-message-react-btn { display: none; } diff --git a/plugins/chat/spec/system/react_to_message_spec.rb b/plugins/chat/spec/system/react_to_message_spec.rb index 0fd6c48d436..50acaed31dc 100644 --- a/plugins/chat/spec/system/react_to_message_spec.rb +++ b/plugins/chat/spec/system/react_to_message_spec.rb @@ -166,6 +166,9 @@ RSpec.describe "React to message", type: :system do channel.click_reaction(message_1, "female_detective") expect(channel).to have_reaction(message_1, "female_detective", "1") + expect( + channel.find_reaction(message_1, "female_detective")["data-tippy-content"], + ).to include(other_user.username) end end end diff --git a/plugins/chat/test/javascripts/components/chat-channel-test.js b/plugins/chat/test/javascripts/components/chat-channel-test.js index 522f5004e00..c53359d10db 100644 --- a/plugins/chat/test/javascripts/components/chat-channel-test.js +++ b/plugins/chat/test/javascripts/components/chat-channel-test.js @@ -61,9 +61,7 @@ module( }); test("it shows status on mentions", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); assertStatusIsRendered( assert, @@ -78,9 +76,7 @@ module( }); test("it updates status on mentions", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); const newStatus = { description: "off to dentist", @@ -93,13 +89,11 @@ module( const selector = statusSelector(mentionedUser.username); await waitFor(selector); - assertStatusIsRendered( assert, statusSelector(mentionedUser.username), newStatus ); - await assertStatusTooltipIsRendered( assert, statusSelector(mentionedUser.username), @@ -108,9 +102,7 @@ module( }); test("it deletes status on mentions", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); this.appEvents.trigger("user-status:changed", { [mentionedUser.id]: null, @@ -122,9 +114,7 @@ module( }); test("it shows status on mentions on messages that came from Message Bus", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); await receiveChatMessageViaMessageBus(); @@ -141,9 +131,7 @@ module( }); test("it updates status on mentions on messages that came from Message Bus", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); await receiveChatMessageViaMessageBus(); const newStatus = { @@ -169,9 +157,7 @@ module( }); test("it deletes status on mentions on messages that came from Message Bus", async function (assert) { - await render( - hbs`` - ); + await render(hbs``); await receiveChatMessageViaMessageBus(); this.appEvents.trigger("user-status:changed", { @@ -195,7 +181,7 @@ module( } async function assertStatusTooltipIsRendered(assert, selector, status) { - await triggerEvent(selector, "mousemove"); + await triggerEvent(selector, "mouseenter"); assert.equal( document diff --git a/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js b/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js index 1619388a3b2..344d796cdf7 100644 --- a/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js +++ b/plugins/discourse-local-dates/assets/javascripts/initializers/discourse-local-dates.js @@ -1,16 +1,17 @@ -import { bind } from "discourse-common/utils/decorators"; +import deprecated from "discourse-common/lib/deprecated"; +import { getOwner } from "discourse-common/lib/get-owner"; import LocalDateBuilder from "../lib/local-date-builder"; import { withPluginApi } from "discourse/lib/plugin-api"; import showModal from "discourse/lib/show-modal"; import { downloadCalendar } from "discourse/lib/download-calendar"; import { renderIcon } from "discourse-common/lib/icon-library"; import I18n from "I18n"; +import { hidePopover, showPopover } from "discourse/lib/d-popover"; import { addTagDecorateCallback, addTextDecorateCallback, } from "discourse/lib/to-markdown"; import generateDateMarkup from "discourse/plugins/discourse-local-dates/lib/local-date-markup-generator"; -import { htmlSafe } from "@ember/template"; // Import applyLocalDates from discourse/lib/local-dates instead export function applyLocalDates(dates, siteSettings) { @@ -347,9 +348,11 @@ function _calculateDuration(element) { export default { name: "discourse-local-dates", - @bind showDatePopover(event) { - const tooltip = this.container.lookup("service:tooltip"); + const owner = getOwner(this); + if (owner.isDestroyed || owner.isDestroying) { + return; + } if (event?.target?.classList?.contains("download-calendar")) { const dataset = event.target.dataset; @@ -360,25 +363,50 @@ export default { }, ]); - return tooltip.close(); + // TODO: remove this when rewriting preview as a component + const parentPopover = event.target.closest("[data-tippy-root]"); + if (parentPopover?._tippy) { + parentPopover._tippy.hide(); + } + + return; } if (!event?.target?.classList?.contains("discourse-local-date")) { return; } - const siteSettings = this.container.lookup("service:site-settings"); - return tooltip.show(event.target, { - content: htmlSafe(buildHtmlPreview(event.target, siteSettings)), + const siteSettings = owner.lookup("service:site-settings"); + + showPopover(event, { + trigger: "click", + content: buildHtmlPreview(event.target, siteSettings), + allowHTML: true, + interactive: true, + appendTo: "parent", + onHidden: (instance) => { + instance.destroy(); + }, }); }, + hideDatePopover(event) { + hidePopover(event); + }, + initialize(container) { - this.container = container; - window.addEventListener("click", this.showDatePopover, { passive: true }); + window.addEventListener("click", this.showDatePopover); const siteSettings = container.lookup("service:site-settings"); if (siteSettings.discourse_local_dates_enabled) { + $.fn.applyLocalDates = function () { + deprecated( + "`$.applyLocalDates()` is deprecated, import and use `applyLocalDates()` instead." + ); + + return applyLocalDates(this.toArray(), siteSettings); + }; + withPluginApi("0.8.8", initializeDiscourseLocalDates); } }, diff --git a/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss b/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss index 51a65f5eb99..bd21f6f7616 100644 --- a/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss +++ b/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss @@ -23,29 +23,29 @@ } } -.locale-dates-previews { - max-width: 250px; +div[data-tippy-root] { + .locale-dates-previews { + max-width: 360px; + .preview { + display: flex; + flex-direction: column; + padding: 5px; - .preview { - display: flex; - flex-direction: column; - padding: 5px; - margin: 0; + .timezone { + font-weight: 700; + } - .timezone { - font-weight: 700; - } - - &.current { - background: var(--tertiary-low); + &.current { + background: var(--tertiary-low); + } } } -} -.download-calendar { - text-align: right; - cursor: pointer; - margin-top: 0.5em; + .download-calendar { + text-align: right; + cursor: pointer; + margin-top: 0.5em; + } } .discourse-local-dates-create-modal-footer { diff --git a/plugins/discourse-local-dates/spec/system/local_dates_spec.rb b/plugins/discourse-local-dates/spec/system/local_dates_spec.rb index a00fad8bcad..08a892d7ea7 100644 --- a/plugins/discourse-local-dates/spec/system/local_dates_spec.rb +++ b/plugins/discourse-local-dates/spec/system/local_dates_spec.rb @@ -31,46 +31,44 @@ describe "Local dates", type: :system do expect(topic_page).to have_content(topic.title) + post_dates = topic_page.find_all("span[data-date]") + # Single date in a paragraph. # - find("span[data-date]:nth-of-type(1)").click - expect(page.find("[data-content] .current .date-time")).to have_text( - "#{formatted_date_for_year(12, 15)}\n2:19 PM", - exact: true, - ) - page.send_keys(:escape) + post_dates[0].click + tippy_date = topic_page.find(".tippy-content .current .date-time") + + expect(tippy_date).to have_text("#{formatted_date_for_year(12, 15)}\n2:19 PM", exact: true) # Two single dates in the same paragraph. # - find("span[data-date]:nth-of-type(2)").click - expect(page.find("[data-content] .current .date-time")).to have_text( - "#{formatted_date_for_year(12, 15)}\n1:20 AM", - exact: true, - ) - page.send_keys(:escape) + post_dates[1].click + tippy_date = topic_page.find(".tippy-content .current .date-time") - find("span[data-date]:nth-of-type(3)").click - expect(page.find("[data-content] .current .date-time")).to have_text( - "#{formatted_date_for_year(12, 15)}\n2:40 AM", - exact: true, - ) - page.send_keys(:escape) + expect(tippy_date).to have_text("#{formatted_date_for_year(12, 15)}\n1:20 AM", exact: true) + + post_dates[2].click + tippy_date = topic_page.find(".tippy-content .current .date-time") + + expect(tippy_date).to have_text("#{formatted_date_for_year(12, 15)}\n2:40 AM", exact: true) # Two date ranges in the same paragraph. # - find("span[data-date]:nth-of-type(4)").click - expect(page.find("[data-content] .current .date-time")).to have_text( + post_dates[3].click + tippy_date = topic_page.find(".tippy-content .current .date-time") + + expect(tippy_date).to have_text( "#{formatted_date_for_year(12, 15)}\n11:25 AM → 12:26 AM", exact: true, ) - page.send_keys(:escape) - find("span[data-date]:nth-of-type(6)").click - expect(page.find("[data-content] .current .date-time")).to have_text( + post_dates[5].click + tippy_date = topic_page.find(".tippy-content .current .date-time") + + expect(tippy_date).to have_text( "#{formatted_date_for_year(12, 22)} 11:57 AM → #{formatted_date_for_year(12, 23)} 11:58 AM", exact: true, ) - page.send_keys(:escape) end end diff --git a/plugins/styleguide/assets/javascripts/discourse/components/dummy-component.gjs b/plugins/styleguide/assets/javascripts/discourse/components/dummy-component.gjs deleted file mode 100644 index cafcff046ca..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/dummy-component.gjs +++ /dev/null @@ -1,7 +0,0 @@ -import Component from "@glimmer/component"; - -export default class DummyComponent extends Component { - -} diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.hbs b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.hbs deleted file mode 100644 index e50ca8baa02..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.hbs +++ /dev/null @@ -1,103 +0,0 @@ - - - <:sample> - - {{this.content}} - - - - - - <:sample> - - <:trigger> - {{this.label}} - - <:content> - {{this.content}} - - - - - - - <:sample> - - - <:actions> - Register - - - - - <:sample> - - - <:actions> - Register - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.js b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.js deleted file mode 100644 index a42ff77af70..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/menus.js +++ /dev/null @@ -1,112 +0,0 @@ -import Component from "@glimmer/component"; -import { action } from "@ember/object"; -import { inject as service } from "@ember/service"; -import { tracked } from "@glimmer/tracking"; -import DummyComponent from "discourse/plugins/styleguide/discourse/components/dummy-component"; -import { htmlSafe } from "@ember/template"; -import { MENU } from "float-kit/lib/constants"; - -export default class Menus extends Component { - @service menu; - - @tracked label = "What is this?"; - @tracked triggers = MENU.options.triggers; - @tracked untriggers = MENU.options.untriggers; - @tracked arrow = MENU.options.arrow; - @tracked inline = MENU.options.inline; - @tracked interactive = MENU.options.interactive; - @tracked maxWidth = MENU.options.maxWidth; - @tracked identifier; - @tracked offset = MENU.options.offset; - @tracked _content = htmlSafe("
    • Hello
    • World!
    "); - - get content() { - return this._content; - } - - set content(value) { - this._content = htmlSafe(value); - } - - get templateCode() { - return ``; - } - - get templateCodeContent() { - return ` - <:trigger> - ${this.label} - - <:content> - ${this.content} - -`; - } - - get serviceCode() { - return `this.menu.register( - document.queryselector(".my-element"), - { content: htmlSafe(${this.content}) } -);`; - } - - get serviceCodeComponent() { - return `this.menu.register( - document.queryselector(".my-element"), - { component: MyComponent, data: { foo: 1 } } -);`; - } - - @action - toggleArrow() { - this.arrow = !this.arrow; - } - - @action - toggleInteractive() { - this.interactive = !this.interactive; - } - - @action - toggleInline() { - this.inline = !this.inline; - } - - @action - registerMenu() { - this.menuInstance?.destroy(); - this.menuInstance = this.menu.register( - document.querySelector("#menu-instance"), - this.options - ); - } - - @action - registerMenuWithComponent() { - this.menuInstanceWithComponent?.destroy(); - this.menuInstanceWithComponent = this.menu.register( - document.querySelector("#menu-instance-with-component"), - { - ...this.options, - component: DummyComponent, - data: { foo: 1 }, - } - ); - } - - get options() { - return { - offset: this.offset, - arrow: this.arrow, - maxWidth: this.maxWidth, - identifier: this.identifier, - interactive: this.interactive, - triggers: this.triggers ?? ["click"], - untriggers: this.untriggers ?? ["click"], - content: this.content, - }; - } -} diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/rich-tooltip.hbs b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/rich-tooltip.hbs new file mode 100644 index 00000000000..1c767dabf4f --- /dev/null +++ b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/rich-tooltip.hbs @@ -0,0 +1,10 @@ + + + {{i18n "styleguide.sections.rich_tooltip.hover_to_see"}} + + +

    {{i18n "styleguide.sections.rich_tooltip.header"}}

    + {{i18n "styleguide.sections.rich_tooltip.description"}} +
    +
    +
    \ No newline at end of file diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.hbs b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.hbs deleted file mode 100644 index 8664fec2b85..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.hbs +++ /dev/null @@ -1,93 +0,0 @@ -{{! template-lint-disable no-potential-path-strings }} - - - <:actions> - - - - - - <:actions> - - - - - - <:actions> - - - - - - <:actions> - - - - - - <:actions> - - - - - - <:actions> - - - - - - - - - {{#if this.autoClose}} - - - - {{/if}} - - - - - Model props for default: - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.js b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.js deleted file mode 100644 index 1989cab43f2..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/toasts.js +++ /dev/null @@ -1,70 +0,0 @@ -import { action } from "@ember/object"; -import Component from "@glimmer/component"; -import { tracked } from "@glimmer/tracking"; -import { inject as service } from "@ember/service"; -import { TOAST } from "float-kit/lib/constants"; -import DummyComponent from "discourse/plugins/styleguide/discourse/components/dummy-component"; - -export default class Toasts extends Component { - @service toasts; - - @tracked title = "Title"; - @tracked message = "Message"; - @tracked duration = TOAST.options.duration; - @tracked autoClose = TOAST.options.autoClose; - @tracked class; - @tracked action = true; - @tracked icon; - - @action - showCustomComponentToast() { - this.toasts.show({ - duration: this.duration, - autoClose: this.autoClose, - class: this.class, - component: DummyComponent, - data: { - foo: 1, - }, - }); - } - - @action - showToast(theme) { - const actions = []; - - if (this.action) { - actions.push({ - label: "Ok", - class: "btn-primary", - action: (args) => { - // eslint-disable-next-line no-alert - alert("Closing toast:" + args.data.title); - args.close(); - }, - }); - } - - this.toasts[theme]({ - duration: this.duration, - autoClose: this.autoClose, - class: this.class, - data: { - title: this.title, - message: this.message, - icon: this.icon, - actions, - }, - }); - } - - @action - toggleAction() { - this.action = !this.action; - } - - @action - toggleAutoClose() { - this.autoClose = !this.autoClose; - } -} diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.hbs b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.hbs deleted file mode 100644 index a75f59ea166..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.hbs +++ /dev/null @@ -1,95 +0,0 @@ - - - <:sample> - - - - - - <:sample> - - <:trigger> - {{this.label}} - - <:content> - {{this.content}} - - - - - - - <:sample> - {{this.label}} - - <:actions> - Register - - - - - <:sample> - {{this.label}} - - <:actions> - Register - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.js b/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.js deleted file mode 100644 index 7e8eb1bd878..00000000000 --- a/plugins/styleguide/assets/javascripts/discourse/components/sections/molecules/tooltips.js +++ /dev/null @@ -1,112 +0,0 @@ -import Component from "@glimmer/component"; -import { action } from "@ember/object"; -import { inject as service } from "@ember/service"; -import { tracked } from "@glimmer/tracking"; -import DummyComponent from "discourse/plugins/styleguide/discourse/components/dummy-component"; -import { TOOLTIP } from "float-kit/lib/constants"; -import { htmlSafe } from "@ember/template"; - -export default class Tooltips extends Component { - @service tooltip; - - @tracked label = "What is this?"; - @tracked triggers = TOOLTIP.options.triggers; - @tracked untriggers = TOOLTIP.options.untriggers; - @tracked arrow = TOOLTIP.options.arrow; - @tracked inline = TOOLTIP.options.inline; - @tracked interactive = TOOLTIP.options.interactive; - @tracked maxWidth = TOOLTIP.options.maxWidth; - @tracked identifier; - @tracked offset = TOOLTIP.options.offset; - @tracked _content = "Hello World!"; - - get content() { - return this._content; - } - - set content(value) { - this._content = htmlSafe(value); - } - - get templateCode() { - return ``; - } - - get templateCodeContent() { - return ` - <:trigger> - ${this.label} - - <:content> - ${this.content} - -`; - } - - get serviceCode() { - return `this.tooltip.register( - document.queryselector(".my-element"), - { content: "${this.content}" } -);`; - } - - get serviceCodeComponent() { - return `this.tooltip.register( - document.queryselector(".my-element"), - { component: MyComponent, data: { foo: 1 } } -);`; - } - - @action - toggleArrow() { - this.arrow = !this.arrow; - } - - @action - toggleInteractive() { - this.interactive = !this.interactive; - } - - @action - toggleInline() { - this.inline = !this.inline; - } - - @action - registerTooltip() { - this.tooltipInstance?.destroy(); - this.tooltipInstance = this.tooltip.register( - document.querySelector("#tooltip-instance"), - this.options - ); - } - - @action - registerTooltipWithComponent() { - this.tooltipInstanceWithComponent?.destroy(); - this.tooltipInstanceWithComponent = this.tooltip.register( - document.querySelector("#tooltip-instance-with-component"), - { - ...this.options, - component: DummyComponent, - data: { foo: 1 }, - } - ); - } - - get options() { - return { - offset: this.offset, - arrow: this.arrow, - maxWidth: this.maxWidth, - identifier: this.identifier, - interactive: this.interactive, - triggers: this.triggers, - untriggers: this.untriggers, - content: this.content, - }; - } -} diff --git a/plugins/styleguide/assets/javascripts/discourse/components/styleguide/component.hbs b/plugins/styleguide/assets/javascripts/discourse/components/styleguide/component.hbs index 5a7e89d45b0..87963a352ae 100644 --- a/plugins/styleguide/assets/javascripts/discourse/components/styleguide/component.hbs +++ b/plugins/styleguide/assets/javascripts/discourse/components/styleguide/component.hbs @@ -1,35 +1,3 @@ -
    - {{#if @tag}} - {{@tag}} - {{/if}} - - {{#if (has-block "title")}} -
    - {{yield to="title"}} -
    - {{/if}} - - {{#if (or (has-block) (has-block "sample"))}} -
    - {{#if (has-block)}} - {{yield}} - {{/if}} - - {{#if (has-block "sample")}} - {{yield to="sample"}} - {{/if}} -
    - {{/if}} - - {{#if (has-block "actions")}} -
    - {{yield to="actions"}} -
    - {{/if}} - - {{#if (has-block "code")}} -
    - {{yield to="code"}} -
    - {{/if}} +
    + {{yield}}
    \ No newline at end of file diff --git a/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js b/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js index 30d3c92722d..7239cf85326 100644 --- a/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js +++ b/plugins/styleguide/assets/javascripts/discourse/lib/styleguide.js @@ -18,9 +18,7 @@ import headerIcons from "../components/sections/molecules/header-icons"; import navigationBar from "../components/sections/molecules/navigation-bar"; import navigationStacked from "../components/sections/molecules/navigation-stacked"; import postMenu from "../components/sections/molecules/post-menu"; -import tooltips from "../components/sections/molecules/tooltips"; -import menus from "../components/sections/molecules/menus"; -import toasts from "../components/sections/molecules/toasts"; +import richTooltip from "../components/sections/molecules/rich-tooltip"; import signupCta from "../components/sections/molecules/signup-cta"; import topicListItem from "../components/sections/molecules/topic-list-item"; import topicNotifications from "../components/sections/molecules/topic-notifications"; @@ -72,9 +70,7 @@ const SECTIONS = [ id: "navigation-stacked", }, { component: postMenu, category: "molecules", id: "post-menu" }, - { component: tooltips, category: "molecules", id: "tooltips" }, - { component: menus, category: "molecules", id: "menus" }, - { component: toasts, category: "molecules", id: "toasts" }, + { component: richTooltip, category: "molecules", id: "rich-tooltip" }, { component: signupCta, category: "molecules", id: "signup-cta" }, { component: topicListItem, category: "molecules", id: "topic-list-item" }, { diff --git a/plugins/styleguide/assets/stylesheets/styleguide.scss b/plugins/styleguide/assets/stylesheets/styleguide.scss index cc799b631c1..9d41477e7a9 100644 --- a/plugins/styleguide/assets/stylesheets/styleguide.scss +++ b/plugins/styleguide/assets/stylesheets/styleguide.scss @@ -75,6 +75,12 @@ width: 100%; position: relative; + .component { + padding: 2rem; + border: 2px dotted var(--primary-low); + margin-bottom: 2rem; + } + .component-properties { width: 100%; @@ -229,42 +235,3 @@ } } } - -.styleguide__component { - border: 2px dotted var(--primary-low); - margin-bottom: 2rem; - position: relative; - - &-tag { - position: absolute; - top: 0; - right: 0; - padding: 3px 6px; - background: var(--primary-low); - max-width: 25%; - @include ellipsis; - } - - &-sample { - display: flex; - padding: 2rem; - } - - &-actions { - display: flex; - align-items: center; - padding: 1rem 2rem; - } - - &-code { - display: flex; - - .ember-view { - width: 100%; - } - - pre { - margin: 0; - } - } -} diff --git a/plugins/styleguide/config/locales/client.en.yml b/plugins/styleguide/config/locales/client.en.yml index fc227051380..6a2780abb09 100644 --- a/plugins/styleguide/config/locales/client.en.yml +++ b/plugins/styleguide/config/locales/client.en.yml @@ -16,10 +16,6 @@ en: paragraph: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." date_time_inputs: title: "Date/Time inputs" - menus: - title: "Menus" - toasts: - title: "Toasts" font_scale: title: "Font System" colors: @@ -87,12 +83,12 @@ en: title: "Spinners" empty_state: title: "Empty State" - tooltips: - title: "Tooltips" + rich_tooltip: + title: "Rich Tooltip" description: "Description" header: "Header" hover_to_see: "Hover to see a tooltip" char_counter: title: "Character Counter" placeholder: "Enter your text here..." - + diff --git a/spec/system/page_objects/pages/topic.rb b/spec/system/page_objects/pages/topic.rb index 06877050350..0c463a6bdff 100644 --- a/spec/system/page_objects/pages/topic.rb +++ b/spec/system/page_objects/pages/topic.rb @@ -92,13 +92,12 @@ module PageObjects end def click_post_admin_action_button(post, button) - element_klass = "[data-content][data-identifier='admin-post-menu']" + element_klass = ".popup-menu-button" case button when :grant_badge - element_klass += " .grant-badge" + element_klass += ".grant-badge" end - - find(element_klass).click + post_by_number(post).find(element_klass).click end def click_topic_footer_button(button) diff --git a/vendor/assets/svg-icons/discourse-additional.svg b/vendor/assets/svg-icons/discourse-additional.svg index bae0d236ec9..1954b5e451b 100644 --- a/vendor/assets/svg-icons/discourse-additional.svg +++ b/vendor/assets/svg-icons/discourse-additional.svg @@ -35,10 +35,10 @@ Additional SVG icons - + - - + + diff --git a/yarn.lock b/yarn.lock index 8560bac7466..a480dd25411 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,20 +29,20 @@ integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== "@babel/core@^7.18.6", "@babel/core@^7.20.12", "@babel/core@^7.22.5": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.17.tgz#2f9b0b395985967203514b24ee50f9fd0639c866" - integrity sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ== + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.15.tgz#15d4fd03f478a459015a4b94cfbb3bd42c48d2f4" + integrity sha512-PtZqMmgRrvj8ruoEOIwVA3yoF91O+Hgw9o7DAUTNBA6Mo2jpu31clx9a7Nz/9JznqetTR6zwfC4L3LAjKQXUwA== dependencies: "@ampproject/remapping" "^2.2.0" "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.22.15" "@babel/helper-compilation-targets" "^7.22.15" - "@babel/helper-module-transforms" "^7.22.17" + "@babel/helper-module-transforms" "^7.22.15" "@babel/helpers" "^7.22.15" - "@babel/parser" "^7.22.16" + "@babel/parser" "^7.22.15" "@babel/template" "^7.22.15" - "@babel/traverse" "^7.22.17" - "@babel/types" "^7.22.17" + "@babel/traverse" "^7.22.15" + "@babel/types" "^7.22.15" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -50,13 +50,13 @@ semver "^6.3.1" "@babel/eslint-parser@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz#263f059c476e29ca4972481a17b8b660cb025a34" - integrity sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg== + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.22.5.tgz#fa032503b9e2d188e25b1b95d29e8b8431042d78" + integrity sha512-C69RWYNYtrgIRE5CmTd77ZiLDXqgBipahJc/jHP3sLcAGj6AJzxNIuKNpVnICqbyK7X3pFUfEvL++rvtbQpZkQ== dependencies: "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1" eslint-visitor-keys "^2.1.0" - semver "^6.3.1" + semver "^6.3.0" "@babel/generator@^7.22.15": version "7.22.15" @@ -86,15 +86,15 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" - integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== +"@babel/helper-create-class-features-plugin@^7.22.6": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz#c36ea240bb3348f942f08b0fbe28d6d979fab236" + integrity sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-environment-visitor" "^7.22.5" "@babel/helper-function-name" "^7.22.5" - "@babel/helper-member-expression-to-functions" "^7.22.15" + "@babel/helper-member-expression-to-functions" "^7.22.5" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-replace-supers" "^7.22.9" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" @@ -121,12 +121,12 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-member-expression-to-functions@^7.22.15", "@babel/helper-member-expression-to-functions@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz#b95a144896f6d491ca7863576f820f3628818621" - integrity sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA== +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== dependencies: - "@babel/types" "^7.22.15" + "@babel/types" "^7.22.5" "@babel/helper-module-imports@^7.22.15": version "7.22.15" @@ -135,10 +135,10 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.22.17": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz#7edf129097a51ccc12443adbc6320e90eab76693" - integrity sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ== +"@babel/helper-module-transforms@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.15.tgz#40ad2f6950f143900e9c1c72363c0b431a606082" + integrity sha512-l1UiX4UyHSFsYt17iQ3Se5pQQZZHa22zyIXURmvkmLCD4t/aU+dvNWHatKac/D9Vm9UES7nvIqHs4jZqKviUmQ== dependencies: "@babel/helper-environment-visitor" "^7.22.5" "@babel/helper-module-imports" "^7.22.15" @@ -158,7 +158,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== -"@babel/helper-replace-supers@^7.22.9": +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": version "7.22.9" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== @@ -221,35 +221,35 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.22.16", "@babel/parser@^7.9.4": - version "7.22.16" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" - integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== +"@babel/parser@^7.20.15", "@babel/parser@^7.22.15", "@babel/parser@^7.9.4": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.15.tgz#d34592bfe288a32e741aa0663dbc4829fcd55160" + integrity sha512-RWmQ/sklUN9BvGGpCDgSubhHWfAx24XDTDObup4ffvxaYsptOg2P3KG0j+1eWKLxpkX0j0uHxmpq2Z1SP/VhxA== "@babel/plugin-proposal-decorators@^7.18.6", "@babel/plugin-proposal-decorators@^7.22.5": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.15.tgz#dc774eae73ab8c28a644d490b45aa47a85bb0bf5" - integrity sha512-kc0VvbbUyKelvzcKOSyQUSVVXS5pT3UhRB0e3c9An86MvLqs+gx0dN4asllrDluqSa3m9YyooXKGOFVomnyFkg== + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.22.7.tgz#9b5b73c2e404f0869ef8a8a53765f8203c5467a7" + integrity sha512-omXqPF7Onq4Bb7wHxXjM3jSMSJvUUbvDvmmds7KI5n9Cq6Ln5I05I1W2nRlRof1rGdiUxJrxwe285WF96XlBXQ== dependencies: - "@babel/helper-create-class-features-plugin" "^7.22.15" + "@babel/helper-create-class-features-plugin" "^7.22.6" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-replace-supers" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/plugin-syntax-decorators" "^7.22.10" + "@babel/plugin-syntax-decorators" "^7.22.5" -"@babel/plugin-syntax-decorators@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.10.tgz#7d83ea04d893c442b78ebf4c3cbac59a7211deff" - integrity sha512-z1KTVemBjnz+kSEilAsI4lbkPOl5TvJH7YDSY1CTIzvLWJ+KHXp+mRe8VPmfnyvqOPqar1V2gid2PleKzRUstQ== +"@babel/plugin-syntax-decorators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.22.5.tgz#329fe2907c73de184033775637dbbc507f09116a" + integrity sha512-avpUOBS7IU6al8MmF1XpAyj9QYeLPuSDJI5D4pVMSMdL7xQokKqJPYQC67RCT0aCTashUXPiGwMJ0DEXXCEmMA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/runtime@^7.21.0": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" - integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA== + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" + integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== dependencies: - regenerator-runtime "^0.14.0" + regenerator-runtime "^0.13.11" "@babel/template@^7.22.15", "@babel/template@^7.22.5": version "7.22.15" @@ -260,10 +260,10 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.17": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.17.tgz#b23c203ab3707e3be816043081b4a994fcacec44" - integrity sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg== +"@babel/traverse@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.15.tgz#75be4d2d6e216e880e93017f4e2389aeb77ef2d9" + integrity sha512-DdHPwvJY0sEeN4xJU5uRLmZjgMMDIvMPniLuYzUVXj/GGzysPl0/fwt44JBkyUIzGJPV8QgHMcQdQ34XFuKTYQ== dependencies: "@babel/code-frame" "^7.22.13" "@babel/generator" "^7.22.15" @@ -271,15 +271,15 @@ "@babel/helper-function-name" "^7.22.5" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.16" - "@babel/types" "^7.22.17" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.17", "@babel/types@^7.22.5": - version "7.22.17" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.17.tgz#f753352c4610ffddf9c8bc6823f9ff03e2303eee" - integrity sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg== +"@babel/types@^7.22.15", "@babel/types@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.15.tgz#266cb21d2c5fd0b3931e7a91b6dd72d2f617d282" + integrity sha512-X+NLXr0N8XXmN5ZsaQdm9U2SSC3UbIYq/doL++sueHOTisgZHoKaQtZxGuV2cUPQHMfjKEfg/g6oy7Hm6SKFtA== dependencies: "@babel/helper-string-parser" "^7.22.5" "@babel/helper-validator-identifier" "^7.22.15" @@ -417,19 +417,19 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.6.1": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" - integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== +"@eslint-community/regexpp@^4.4.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz#cdd35dce4fa1a89a4fd42b1599eb35b3af408884" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz#4910db5505f4d503f27774bf356e3704818a0331" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" + espree "^9.5.2" globals "^13.19.0" ignore "^5.2.0" import-fresh "^3.2.1" @@ -437,10 +437,10 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.49.0": - version "8.49.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" - integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== +"@eslint/js@8.43.0": + version "8.43.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.43.0.tgz#559ca3d9ddbd6bf907ad524320a0d14b85586af0" + integrity sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg== "@fortawesome/fontawesome-free@5.15.4": version "5.15.4" @@ -544,10 +544,10 @@ resolved "https://registry.yarnpkg.com/@highlightjs/cdn-assets/-/cdn-assets-11.8.0.tgz#e3aa9f20bf742b50bd7b1d60a24c8e7d124a602f" integrity sha512-gkfCH4xGBGY9xPaW+t26WpgnfpDhNhB5RtVUDLx3MHkC7ZrmKeIxXsfjzOiuOnEgRk+vydlY6XeOeglh+eVhyg== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@humanwhocodes/config-array@^0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" + integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== dependencies: "@humanwhocodes/object-schema" "^1.2.1" debug "^4.1.1" @@ -572,28 +572,33 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.19" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" - integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" "@jsdoc/salty@^0.2.1": version "0.2.5" @@ -663,10 +668,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@puppeteer/browsers@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.0.tgz#714a25ad6963f5478e36004ea7eda254870a4659" - integrity sha512-sl7zI0IkbQGak/+IE3VEEZab5SSOlI5F6558WvzWGC1n3+C722rfewC1ZIkcF9dsoGSsxhsONoseVlNQG4wWvQ== +"@puppeteer/browsers@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.6.0.tgz#d52413a7039e40a5ef72fb13fb6505fd87ce842e" + integrity sha512-R2ib8j329427jtKB/qlz0MJbwfJE/6I8ocJLiajsRqJ2PPI8DbjiNzC3lQZeISXEcjOBVhbG2RafN8SlHdcT+A== dependencies: debug "4.3.4" extract-zip "2.0.1" @@ -705,9 +710,9 @@ integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== "@types/linkify-it@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.3.tgz#15a0712296c5041733c79efe233ba17ae5a7587b" - integrity sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g== + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/linkify-it/-/linkify-it-3.0.2.tgz#fd2cd2edbaa7eaac7e7f3c1748b52a19143846c9" + integrity sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA== "@types/markdown-it@^12.2.3": version "12.2.3" @@ -728,9 +733,9 @@ integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== "@types/node@*": - version "20.6.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.0.tgz#9d7daa855d33d4efec8aea88cd66db1c2f0ebe16" - integrity sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg== + version "20.3.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.2.tgz#fa6a90f2600e052a03c18b8cb3fd83dd4e599898" + integrity sha512-vOBLVQeCQfIcF/2Y7eKFTqrMnizK5lRNQ7ykML/5RuwVXVWxYkgwS7xbt4B6fKCUPgbSL5FSsjHQpaGQP/dQmw== "@types/symlink-or-copy@^1.2.0": version "1.2.0" @@ -754,19 +759,19 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.8.0: + version "8.9.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59" + integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== -agent-base@^7.0.2, agent-base@^7.1.0: +agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== dependencies: debug "^4.3.4" -ajv@^6.12.4: +ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -825,19 +830,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -arraybuffer.prototype.slice@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -924,9 +916,9 @@ babel-plugin-ember-modules-api-polyfill@^3.5.0: ember-rfc176-data "^0.3.17" babel-plugin-ember-template-compilation@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-ember-template-compilation/-/babel-plugin-ember-template-compilation-2.2.0.tgz#b119fadcd5c831299fbd706420d2ea742848a659" - integrity sha512-1I7f5gf06h5wKdKUvaYEIaoSFur5RLUvTMQG4ak0c5Y11DWUxcoX9hrun1xe9fqfY2dtGFK+ZUM6sn6z8sqK/w== + version "2.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-template-compilation/-/babel-plugin-ember-template-compilation-2.1.1.tgz#215c6e983617d514811361a521d61ca4f81450df" + integrity sha512-vwEUw7qfwAgwUokQc5xMxrcJMhCu2dVvDDMIXFyOpXwxt+kqZ2FKvXFV+rJjYchIgHH5rBduEtt4Qk1qeZ6RDA== dependencies: "@glimmer/syntax" "^0.84.3" babel-import-util "^2.0.0" @@ -1153,13 +1145,13 @@ broccoli-stew@^3.0.0: walk-sync "^1.1.3" browserslist@^4.21.9: - version "4.21.10" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + version "4.21.9" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.9.tgz#e11bdd3c313d7e2a9e87e8b4b0c7872b13897635" + integrity sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg== dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" - node-releases "^2.0.13" + caniuse-lite "^1.0.30001503" + electron-to-chromium "^1.4.431" + node-releases "^2.0.12" update-browserslist-db "^1.0.11" buffer-crc32@~0.2.3: @@ -1195,10 +1187,10 @@ can-symlink@^1.0.0: dependencies: tmp "0.0.28" -caniuse-lite@^1.0.30001517: - version "1.0.30001532" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001532.tgz#c6a4d5d2da6d2b967f0ee5e12e7f680db6ad2fca" - integrity sha512-FbDFnNat3nMnrROzqrsg314zhqN5LGQ1kyyMk2opcrwGbVGpHRhgCWtAgD5YJUqNAiQ+dklreil/c3Qf1dfCTw== +caniuse-lite@^1.0.30001503: + version "1.0.30001509" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz#2b7ad5265392d6d2de25cd8776d1ab3899570d14" + integrity sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA== catharsis@^0.9.0: version "0.9.0" @@ -1208,9 +1200,9 @@ catharsis@^0.9.0: lodash "^4.17.15" chai@^4.3.6: - version "4.3.8" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.8.tgz#40c59718ad6928da6629c70496fe990b2bb5b17c" - integrity sha512-vX4YvVVtxlfSZ2VecZgFUTU5qPCYsobVI2O9FmwEXBhDigYGQA6jRXCycIs1yJnnWbZ6/+a2zNIF5DfVCcJBFQ== + version "4.3.7" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== dependencies: assertion-error "^1.1.0" check-error "^1.0.2" @@ -1275,10 +1267,10 @@ chrome-remote-interface@^0.31.3: commander "2.11.x" ws "^7.2.0" -chromium-bidi@0.4.22: - version "0.4.22" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.22.tgz#625dab72946e177f538da2d2b8a681652ef916da" - integrity sha512-wR7Y9Ioez+cNXT4ZP7VNM1HRTljpNnMSLw4/RnwhhZUP4yCU7kIQND00YiktuHekch68jklGPK1q9Jkb29+fQg== +chromium-bidi@0.4.20: + version "0.4.20" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.20.tgz#1cd56426638452b40b29b7054e83c379e7e2b20a" + integrity sha512-ruHgVZFEv00mAQMz1tQjfjdG63jiPWrQPF6HLlX2ucqLqVTJoWngeBEKHaJ6n1swV/HSvgnBNbtTRIlcVyW3Fw== dependencies: mitt "3.0.1" @@ -1393,9 +1385,9 @@ convert-source-map@^1.7.0: integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== core-js@^3.27.2, core-js@^3.4.1: - version "3.32.2" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.2.tgz#172fb5949ef468f93b4be7841af6ab1f21992db7" - integrity sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ== + version "3.32.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.32.1.tgz#a7d8736a3ed9dd05940c3c4ff32c591bb735be77" + integrity sha512-lqufgNn9NLnESg5mQeYsxQP5w7wrViSj0jr/kv6ECQiByzQkrn1MKvV0L3acttpDqfQrHLwr2KCMgX5b8X+lyQ== core-util-is@~1.0.0: version "1.0.3" @@ -1493,10 +1485,10 @@ dequal@^2.0.3: resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -devtools-protocol@0.0.1159816: - version "0.0.1159816" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1159816.tgz#b5848e8597de01e4738589e7553674c7312c8d2a" - integrity sha512-2cZlHxC5IlgkIWe2pSDmCrDiTzbSJWywjbDDnupOImEBcG31CQgBLV8wWE+5t+C4rimcjHsbzy7CBzf9oFjboA== +devtools-protocol@0.0.1147663: + version "0.0.1147663" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz#4ec5610b39a6250d1f87e6b9c7e16688ed0ac78e" + integrity sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ== diffhtml@1.0.0-beta.20: version "1.0.0-beta.20" @@ -1548,10 +1540,10 @@ editions@^2.2.0: errlop "^2.0.0" semver "^6.3.0" -electron-to-chromium@^1.4.477: - version "1.4.513" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.513.tgz#41a50bf749aa7d8058ffbf7a131fc3327a7b1675" - integrity sha512-cOB0xcInjm+E5qIssHeXJ29BaUyWpMyFKT5RB3bsLENDheCja0wMkHJyiPl0NBE/VzDI7JDuNEQWhe6RitEUcw== +electron-to-chromium@^1.4.431: + version "1.4.445" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.445.tgz#058d2c5f3a2981ab1a37440f5a5e42d15672aa6d" + integrity sha512-++DB+9VK8SBJwC+X1zlMfJ1tMA3F0ipi39GdEp+x3cV2TyBihqAgad8cNMWtLDEkbH39nlDQP7PfGrDr3Dr7HA== ember-cli-babel-plugin-helpers@^1.1.1: version "1.1.1" @@ -1680,19 +1672,18 @@ errlop@^2.0.0: resolved "https://registry.yarnpkg.com/errlop/-/errlop-2.2.0.tgz#1ff383f8f917ae328bebb802d6ca69666a42d21b" integrity sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw== -es-abstract@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" - integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== dependencies: array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.1" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" function.prototype.name "^1.1.5" - get-intrinsic "^1.2.1" + get-intrinsic "^1.2.0" get-symbol-description "^1.0.0" globalthis "^1.0.3" gopd "^1.0.1" @@ -1712,18 +1703,14 @@ es-abstract@^1.22.1: object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - safe-array-concat "^1.0.0" + regexp.prototype.flags "^1.4.3" safe-regex-test "^1.0.0" string.prototype.trim "^1.2.7" string.prototype.trimend "^1.0.6" string.prototype.trimstart "^1.0.6" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.10" + which-typed-array "^1.1.9" es-set-tostringtag@^2.0.1: version "2.0.1" @@ -1904,10 +1891,10 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.0.tgz#f21ebdafda02352f103634b96dd47d9f81ca117b" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" @@ -1936,32 +1923,32 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz#c22c48f48942d08ca824cc526211ae400478a994" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== eslint@^8.37.0, eslint@^8.43.0: - version "8.49.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" - integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== + version "8.43.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.43.0.tgz#3e8c6066a57097adfd9d390b8fc93075f257a094" + integrity sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.49.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.43.0" + "@humanwhocodes/config-array" "^0.11.10" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" - ajv "^6.12.4" + ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" debug "^4.3.2" doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1971,6 +1958,7 @@ eslint@^8.37.0, eslint@^8.43.0: globals "^13.19.0" graphemer "^1.4.0" ignore "^5.2.0" + import-fresh "^3.0.0" imurmurhash "^0.1.4" is-glob "^4.0.0" is-path-inside "^3.0.3" @@ -1980,8 +1968,9 @@ eslint@^8.37.0, eslint@^8.43.0: lodash.merge "^4.6.2" minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.3" + optionator "^0.9.1" strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" text-table "^0.2.0" esm@^3.2.25: @@ -1989,12 +1978,12 @@ esm@^3.2.25: resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.5.2.tgz#e994e7dc33a082a7a82dceaf12883a829353215b" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== dependencies: - acorn "^8.9.0" + acorn "^8.8.0" acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" @@ -2054,9 +2043,9 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-fifo@^1.1.0, fast-fifo@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" - integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.0.tgz#03e381bcbfb29932d7c3afde6e15e83e05ab4d8b" + integrity sha512-IgfweLvEpwyA4WgiQe9Nx6VV2QkML2NkvZnk1oKnIzXgXdWxuhF7zw4DvLTPZJn6PIUneiAXPF24QmoEqHTjyw== fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.1" @@ -2131,15 +2120,14 @@ find-up@^6.3.0: path-exists "^5.0.0" flat-cache@^3.0.4: - version "3.1.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.1.0.tgz#0e54ab4a1a60fe87e2946b6b00657f1c99e1af3f" - integrity sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew== + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^3.2.7" - keyv "^4.5.3" + flatted "^3.1.0" rimraf "^3.0.2" -flatted@^3.2.7: +flatted@^3.1.0: version "3.2.7" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== @@ -2233,16 +2221,16 @@ function-bind@^1.1.1: integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== function.prototype.name@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + version "1.1.5" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== dependencies: call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" -functions-have-names@^1.2.3: +functions-have-names@^1.2.2, functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -2267,7 +2255,7 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== @@ -2366,9 +2354,9 @@ globals@^11.1.0: integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: - version "13.21.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.21.0.tgz#163aae12f34ef502f5153cfbdd3600f36c63c571" - integrity sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg== + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== dependencies: type-fest "^0.20.2" @@ -2500,10 +2488,10 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" -https-proxy-agent@^7.0.0, https-proxy-agent@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz#e2645b846b90e96c6e6f347fb5b2e41f1590b09b" - integrity sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA== +https-proxy-agent@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" + integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== dependencies: agent-base "^7.0.2" debug "4" @@ -2525,7 +2513,7 @@ import-cwd@^3.0.0: dependencies: import-from "^3.0.0" -import-fresh@^3.2.1: +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -2563,7 +2551,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== -internal-slot@^1.0.5: +internal-slot@^1.0.3, internal-slot@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== @@ -2619,10 +2607,10 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-core-module@^2.13.0: - version "2.13.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" - integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== +is-core-module@^2.12.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== dependencies: has "^1.0.3" @@ -2724,11 +2712,15 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: has-symbols "^1.0.2" is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + version "1.1.10" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== dependencies: - which-typed-array "^1.1.11" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" is-unc-path@^1.0.0: version "1.0.0" @@ -2766,11 +2758,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2872,11 +2859,6 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -2908,13 +2890,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -keyv@^4.5.3: - version "4.5.3" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.3.tgz#00873d2b046df737963157bd04f294ca818c9c25" - integrity sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug== - dependencies: - json-buffer "3.0.1" - klaw@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/klaw/-/klaw-3.0.0.tgz#b11bec9cf2492f06756d6e809ab73a2910259146" @@ -2928,65 +2903,65 @@ language-subtag-registry@^0.3.20: integrity sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w== language-tags@^1.0.8: - version "1.0.9" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" - integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + version "1.0.8" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.8.tgz#042b4bdb0d4e771a9f8cc2fdc9bb26a52a367312" + integrity sha512-aWAZwgPLS8hJ20lNPm9HNVs4inexz6S2sQa3wx/+ycuutMNE5/IfYxiWYBbi+9UWCQVaXYCOPUl6gFrPR7+jGg== dependencies: language-subtag-registry "^0.3.20" -lefthook-darwin-arm64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.4.10.tgz#841729b16ea2611d0a4bbc5090de8e53912fd805" - integrity sha512-mHYTdvsevxwQLMtgDKM8igaY7JUwlGpoMQMrjLiuMuW9SSv0Bl8gZtilEWcxOiWxGcIUwV4Xw+90tlwKQlO7Qg== +lefthook-darwin-arm64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.4.3.tgz#b253fbc20041815010da66e8588faf4bbd75c0aa" + integrity sha512-ZFsgIzN+Z0c4RpMMHU/M4J43XFyXYGZI8r0GG4jqVMX+prDBIb/6vpgMdZxK5IozRUmnfLGQPXcVokE9WBHSOg== -lefthook-darwin-x64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.4.10.tgz#63d34cbd72222b75c8123aa90d8ff8a65636bee6" - integrity sha512-rfa9AClAS5gXix0eyv0vV70r7s4jt7dWlR6TSky+rRcxWJ88Vay9U1ZpHlVTAh0karaiHrh6e7AQX+7WbGWUBA== +lefthook-darwin-x64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-darwin-x64/-/lefthook-darwin-x64-1.4.3.tgz#5afa63f7a18cf89495895fc1321cdd749825bf9c" + integrity sha512-O6ZesdJ9MStI38gNfJh0ShExIf0KyHG1lR32F9FUFklFwhcquRM+uIDyDqVCxU3UWqmKwcbTk9AJWMjQZGPLxQ== -lefthook-freebsd-arm64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.4.10.tgz#7eca602866cc39d4b4345e08683437e35735c013" - integrity sha512-Nh4jEg1OQwsQ+i/kt9XIufQONVj6iEhGWwWoyfycT71wHFCrbNy348Q84EjHTltIUAvE/5jrQdnRDOL6pMZ/Tw== +lefthook-freebsd-arm64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.4.3.tgz#070141ccc981658bd7545f40b14814b410f2930e" + integrity sha512-6swb+98Qs6P9V9Rcd2lHWH2LunFEk+kfIPpf6oiPrOHnw3OkfFhQLmawX425Ari7Y9qy9gfDoNe/0/IR7YGmGw== -lefthook-freebsd-x64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.4.10.tgz#00b9f8d42f356cca230f927c279f8fe4b8defbec" - integrity sha512-3DiI2asrtiYvGXLb6H1ATj7yEj14B6A4c33HLmN5J94PP6rVw6xU2G/PIIAz2wi7/W3igEmuT79F8JJT1mqc7A== +lefthook-freebsd-x64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.4.3.tgz#47b4e7cf4c0459b1152e605c047541ec3eec5f0b" + integrity sha512-+58NARATypmIj0kDutd29ozywr6IeA0lVBxsVzq7C5ycYrd31iNak3lnaEvNJvdj5fGVNEL9X7XRojylthZlAg== -lefthook-linux-arm64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.4.10.tgz#8eed8cb53d63326118ff65cd4667dc3a9cb8ac43" - integrity sha512-gXwTaEYYLfIIPX2Z63aijPSqmvZf003OKjhBB1Og74qWDxfhKs4zZXoWEdc1BARq6U9hImKdyOD/zDc31uB4mw== +lefthook-linux-arm64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-linux-arm64/-/lefthook-linux-arm64-1.4.3.tgz#b3caae33a20cc2665ec047a098e7b4e4498d63d1" + integrity sha512-gAWJQEhgheOfPu579fhlcNNm3KoJbNkT11AATKHlFu+esyiCxI8xZVpGwDQVMphO7s43FKbkQJSvIM4tElb6FQ== -lefthook-linux-x64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.4.10.tgz#f2f2480002b5f33f4fe9e500fec2a48ee9734d85" - integrity sha512-svWdDgk2hXpcE37yY27DTbyIgnJuqofrNc30cmHonLO3VQC5CyLwp45CiNtY6qxW0UVBxqSuGuZcB2TPZQfyWQ== +lefthook-linux-x64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-linux-x64/-/lefthook-linux-x64-1.4.3.tgz#ac2990e23a4c39bf774e4094f33c0fbaef79129c" + integrity sha512-mVv/amRqX81nQcizhRRx/X6KKNIkMUG4HdDItWkDazwLAviZ2zv8TRcSaEYBOpriP/dBZm8gt6EhzPpfoWtcJw== -lefthook-windows-arm64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.4.10.tgz#1711146b4d33bcf5a5e8af098ecb874f1a67af22" - integrity sha512-ntP30mgAdcbDP1fqL6CXn/60tLXVVYQo0aDLLcI/oBI2ff1Im6zeBDVtujv33KdDVrx5Mu9qi7bQstgG02PzvA== +lefthook-windows-arm64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-windows-arm64/-/lefthook-windows-arm64-1.4.3.tgz#dc0dcfea32badab031183bdc8cd91bda929cee9b" + integrity sha512-ccClPTC7AvhcbyT6pLzdV8K8e/P0T7p/THGRtcyjkKIU0IS89k95VazDlt22QPzUTc8UMNCQyZ1XY4UDx295jw== -lefthook-windows-x64@1.4.10: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.4.10.tgz#2fbb8cc56384f5145c70f27ea85a59e214a52a15" - integrity sha512-MwEGtGpe6EJPfE5jvtxvHsmn2/sQP7+zo2FUf87o2CafmqAOR/R7EvQ7qeg6z6T33cWxnyQSBN23tV10bKhtOQ== +lefthook-windows-x64@1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook-windows-x64/-/lefthook-windows-x64-1.4.3.tgz#795b1215969c7d0d4007f89bfe660cfc2736075c" + integrity sha512-q1K5kycfqTYLm5/pOCiAFa+hoSFt/29QjHVZAWRmk/nKDIf8MvTWX0tdaEx7/VJuG3cgQT1jM+xiTwSmNUXTKg== lefthook@^1.2.0: - version "1.4.10" - resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.4.10.tgz#2c79ae13c4af93dc9d332c9c2c5620c38c67cd74" - integrity sha512-d0XRT7LoHdPYKNdCQNcIx4arFzTb0fro/PQrwJ1qSLBVlN9ljaYszLqsrVMzTNSPjGU1Pb1FbSw1GMxLG9G8kA== + version "1.4.3" + resolved "https://registry.yarnpkg.com/lefthook/-/lefthook-1.4.3.tgz#cedfd13f13c87a974ea5e055853c7fae0c6df11e" + integrity sha512-zvhAJ9wDQW7F27XYWRfx72L6LuPLu49be+sRUF+DKku1IGT+x3eHjQ9k70pt65lnEq1X8Xl/Xygm3Kwi/piOYg== optionalDependencies: - lefthook-darwin-arm64 "1.4.10" - lefthook-darwin-x64 "1.4.10" - lefthook-freebsd-arm64 "1.4.10" - lefthook-freebsd-x64 "1.4.10" - lefthook-linux-arm64 "1.4.10" - lefthook-linux-x64 "1.4.10" - lefthook-windows-arm64 "1.4.10" - lefthook-windows-x64 "1.4.10" + lefthook-darwin-arm64 "1.4.3" + lefthook-darwin-x64 "1.4.3" + lefthook-freebsd-arm64 "1.4.3" + lefthook-freebsd-x64 "1.4.3" + lefthook-linux-arm64 "1.4.3" + lefthook-linux-x64 "1.4.3" + lefthook-windows-arm64 "1.4.3" + lefthook-windows-x64 "1.4.3" levn@^0.4.1: version "0.4.1" @@ -3131,11 +3106,11 @@ magic-string@^0.25.7: sourcemap-codec "^1.4.8" magic-string@^0.30.0: - version "0.30.3" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.3.tgz#403755dfd9d6b398dfa40635d52e96c5ac095b85" - integrity sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw== + version "0.30.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529" + integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ== dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" + "@jridgewell/sourcemap-codec" "^1.4.13" magnific-popup@1.1.0: version "1.1.0" @@ -3299,16 +3274,16 @@ no-case@^3.0.4: tslib "^2.0.3" node-fetch@^2.6.0, node-fetch@^2.6.12: - version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== dependencies: whatwg-url "^5.0.0" -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.12: + version "2.0.12" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.12.tgz#35627cc224a23bfb06fb3380f2b3afaaa7eb1039" + integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== object-assign@^4.1.0: version "4.1.1" @@ -3349,7 +3324,7 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -optionator@^0.9.3: +optionator@^0.9.1: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== @@ -3417,18 +3392,18 @@ p-locate@^6.0.0: p-limit "^4.0.0" pac-proxy-agent@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz#6b9ddc002ec3ff0ba5fdf4a8a21d363bcc612d75" - integrity sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A== + version "7.0.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b" + integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA== dependencies: "@tootallnate/quickjs-emscripten" "^0.23.0" agent-base "^7.0.2" debug "^4.3.4" get-uri "^6.0.1" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.2" + https-proxy-agent "^7.0.0" pac-resolver "^7.0.0" - socks-proxy-agent "^8.0.2" + socks-proxy-agent "^8.0.1" pac-resolver@^7.0.0: version "7.0.0" @@ -3618,15 +3593,15 @@ punycode@^2.1.0: integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== puppeteer-core@^21.0.3: - version "21.1.1" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.1.1.tgz#59be20b6f69acc2139ba2d9e02a33793b59254ff" - integrity sha512-Tlcajcf44zwfa9Sbwv3T8BtaNMJ69wtpHIxwl2NOBTyTK3D1wppQovXTjfw0TDOm3a16eCfQ+5BMi3vRQ4kuAQ== + version "21.0.3" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.0.3.tgz#201bfbf18a9467dbedb10c3c2c9c43462bb9bb84" + integrity sha512-AGvopfkA0jLbW5Ba0m6kBuvRIpLo76PXUK3zJYkXOr9NI1LknJESyai6TtXc6GUSewMkinmyEDx1pFgq900hqg== dependencies: - "@puppeteer/browsers" "1.7.0" - chromium-bidi "0.4.22" + "@puppeteer/browsers" "1.6.0" + chromium-bidi "0.4.20" cross-fetch "4.0.0" debug "4.3.4" - devtools-protocol "0.0.1159816" + devtools-protocol "0.0.1147663" ws "8.13.0" queue-microtask@^1.2.2: @@ -3670,12 +3645,12 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -regenerator-runtime@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" - integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regexp.prototype.flags@^1.5.0: +regexp.prototype.flags@^1.4.3: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== @@ -3743,11 +3718,11 @@ resolve-package-path@^3.1.0: resolve "^1.17.0" resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.17.0, resolve@^1.22.3: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + version "1.22.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283" + integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw== dependencies: - is-core-module "^2.13.0" + is-core-module "^2.12.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -3819,16 +3794,6 @@ rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -3926,12 +3891,12 @@ snake-case@^3.0.3, snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -socks-proxy-agent@^8.0.1, socks-proxy-agent@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad" - integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== +socks-proxy-agent@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120" + integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ== dependencies: - agent-base "^7.0.2" + agent-base "^7.0.1" debug "^4.3.4" socks "^2.7.1" @@ -3997,45 +3962,45 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: strip-ansi "^6.0.1" string.prototype.matchall@^4.0.5, string.prototype.matchall@^4.0.6: - version "4.0.9" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz#148779de0f75d36b13b15885fec5cadde994520d" - integrity sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz#3bf85722021816dcd1bf38bb714915887ca79fd3" + integrity sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg== dependencies: call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" + get-intrinsic "^1.1.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" - regexp.prototype.flags "^1.5.0" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.4.3" side-channel "^1.0.4" string.prototype.trim@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + version "1.2.7" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== dependencies: call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" string.prototype.trimend@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== dependencies: call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" string.prototype.trimstart@^1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + version "1.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== dependencies: call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" + define-properties "^1.1.4" + es-abstract "^1.20.4" string_decoder@^1.1.1: version "1.3.0" @@ -4273,36 +4238,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - typed-array-length@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" @@ -4313,9 +4248,9 @@ typed-array-length@^1.0.4: is-typed-array "^1.1.9" typescript@^5.1.3: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== + version "5.1.6" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" + integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.6" @@ -4419,9 +4354,9 @@ uuid@^8.3.2: integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-compile-cache@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" - integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== validate-peer-dependencies@^1.1.0: version "1.2.0" @@ -4539,16 +4474,17 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-typed-array@^1.1.10, which-typed-array@^1.1.11: - version "1.1.11" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" - integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== dependencies: available-typed-arrays "^1.0.5" call-bind "^1.0.2" for-each "^0.3.3" gopd "^1.0.1" has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" which@^2.0.1: version "2.0.2" @@ -4558,9 +4494,9 @@ which@^2.0.1: isexe "^2.0.0" workerpool@^6.4.0: - version "6.4.2" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.4.2.tgz#5d086f6fef89adbc4300ca24fcafb7082330e960" - integrity sha512-MrDWwemtC4xNV22kbbZDQQQmxNX+yLm790sgYl2wVD3CWnK7LJY1youI/11wHorAjHjK+GEjUxUh74XoPU71uQ== + version "6.4.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.4.0.tgz#f8d5cfb45fde32fa3b7af72ad617c3369567a462" + integrity sha512-i3KR1mQMNwY2wx20ozq2EjISGtQWDIfV56We+yGJ5yDs8jTwQiLLaqHlkBHITlCuJnYlVRmXegxFxZg7gqI++A== wrap-ansi@^7.0.0: version "7.0.0"