@expressivecss/expressive 0.12.0 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +231 -1
- package/README.md +37 -1
- package/dist/css/expressive.css +5111 -36
- package/dist/css/expressive.css.map +1 -1
- package/dist/css/expressive.min.css +1 -1
- package/dist/css/expressive.min.css.map +1 -1
- package/dist/fonts/material-symbols-outlined.woff2 +0 -0
- package/dist/fonts/material-symbols-rounded.woff2 +0 -0
- package/dist/fonts/material-symbols-sharp.woff2 +0 -0
- package/dist/js/chunks/{chunk-HLDXZ7XB.mjs → chunk-3CLXLPYS.mjs} +2 -2
- package/dist/js/chunks/chunk-3DHK5CZU.mjs +105 -0
- package/dist/js/chunks/chunk-3DHK5CZU.mjs.map +7 -0
- package/dist/js/chunks/chunk-4PWAPV6F.mjs +7 -0
- package/dist/js/chunks/chunk-4PWAPV6F.mjs.map +7 -0
- package/dist/js/chunks/{chunk-HB6IW7QQ.mjs → chunk-55IA2XUC.mjs} +2 -2
- package/dist/js/chunks/chunk-CCWDV5CR.mjs +292 -0
- package/dist/js/chunks/chunk-CCWDV5CR.mjs.map +7 -0
- package/dist/js/chunks/chunk-DTKR54I6.mjs +270 -0
- package/dist/js/chunks/chunk-DTKR54I6.mjs.map +7 -0
- package/dist/js/chunks/chunk-GVGT6MIU.mjs +47 -0
- package/dist/js/chunks/chunk-GVGT6MIU.mjs.map +7 -0
- package/dist/js/chunks/chunk-HKT2S7VM.mjs +48 -0
- package/dist/js/chunks/chunk-HKT2S7VM.mjs.map +7 -0
- package/dist/js/chunks/chunk-K4CJCRGE.mjs +262 -0
- package/dist/js/chunks/chunk-K4CJCRGE.mjs.map +7 -0
- package/dist/js/chunks/chunk-LNCCYGPC.mjs +163 -0
- package/dist/js/chunks/chunk-LNCCYGPC.mjs.map +7 -0
- package/dist/js/chunks/chunk-NQLC3YMW.mjs +1 -0
- package/dist/js/chunks/chunk-O5XPWXIQ.mjs +406 -0
- package/dist/js/chunks/chunk-O5XPWXIQ.mjs.map +7 -0
- package/dist/js/chunks/chunk-P3G3QHII.mjs +166 -0
- package/dist/js/chunks/chunk-P3G3QHII.mjs.map +7 -0
- package/dist/js/chunks/{chunk-H2WA4XHH.mjs → chunk-PLYXLSH3.mjs} +4 -4
- package/dist/js/chunks/chunk-QKWPQK5N.mjs +179 -0
- package/dist/js/chunks/chunk-QKWPQK5N.mjs.map +7 -0
- package/dist/js/chunks/chunk-RHRQKTTX.mjs +139 -0
- package/dist/js/chunks/chunk-RHRQKTTX.mjs.map +7 -0
- package/dist/js/chunks/chunk-SPETGK25.mjs +59 -0
- package/dist/js/chunks/chunk-SPETGK25.mjs.map +7 -0
- package/dist/js/chunks/{chunk-YSBCHYXP.mjs → chunk-U2OTHOTI.mjs} +116 -12
- package/dist/js/chunks/chunk-U2OTHOTI.mjs.map +7 -0
- package/dist/js/chunks/chunk-VTLBW7QS.mjs +124 -0
- package/dist/js/chunks/chunk-VTLBW7QS.mjs.map +7 -0
- package/dist/js/chunks/{chunk-RFZZCYVU.mjs → chunk-XGHORT7J.mjs} +2 -2
- package/dist/js/chunks/{chunk-HNFSMIBY.mjs → chunk-XH6BEEMY.mjs} +69 -16
- package/dist/js/chunks/chunk-XH6BEEMY.mjs.map +7 -0
- package/dist/js/expressive.cjs +2209 -32
- package/dist/js/expressive.cjs.map +4 -4
- package/dist/js/expressive.js +2209 -32
- package/dist/js/expressive.js.map +4 -4
- package/dist/js/expressive.min.js +10 -10
- package/dist/js/expressive.min.js.map +4 -4
- package/dist/js/expressive.mjs +68 -20
- package/dist/js/expressive.mjs.map +1 -1
- package/dist/js/internal/behaviors/forms.mjs +1 -1
- package/dist/js/internal/components/autocomplete.mjs +2 -2
- package/dist/js/internal/components/barChart.mjs +10 -0
- package/dist/js/internal/components/barChart.mjs.map +7 -0
- package/dist/js/internal/components/chips.mjs +3 -3
- package/dist/js/internal/components/columnChart.mjs +9 -0
- package/dist/js/internal/components/columnChart.mjs.map +7 -0
- package/dist/js/internal/components/commandPalette.mjs +9 -0
- package/dist/js/internal/components/commandPalette.mjs.map +7 -0
- package/dist/js/internal/components/datepicker.mjs +3 -3
- package/dist/js/internal/components/heatmapChart.mjs +9 -0
- package/dist/js/internal/components/heatmapChart.mjs.map +7 -0
- package/dist/js/internal/components/index.mjs +65 -17
- package/dist/js/internal/components/lineChart.mjs +12 -0
- package/dist/js/internal/components/lineChart.mjs.map +7 -0
- package/dist/js/internal/components/menu.mjs +1 -1
- package/dist/js/internal/components/messageScroller.mjs +9 -0
- package/dist/js/internal/components/messageScroller.mjs.map +7 -0
- package/dist/js/internal/components/mixedChart.mjs +10 -0
- package/dist/js/internal/components/mixedChart.mjs.map +7 -0
- package/dist/js/internal/components/pieChart.mjs +9 -0
- package/dist/js/internal/components/pieChart.mjs.map +7 -0
- package/dist/js/internal/components/questionnaire.mjs +9 -0
- package/dist/js/internal/components/questionnaire.mjs.map +7 -0
- package/dist/js/internal/components/radarChart.mjs +9 -0
- package/dist/js/internal/components/radarChart.mjs.map +7 -0
- package/dist/js/internal/components/radialChart.mjs +9 -0
- package/dist/js/internal/components/radialChart.mjs.map +7 -0
- package/dist/js/internal/components/registry.mjs +23 -11
- package/dist/js/internal/components/richTextEditor.mjs +9 -0
- package/dist/js/internal/components/richTextEditor.mjs.map +7 -0
- package/dist/js/internal/components/select.mjs +2 -2
- package/dist/js/modular.mjs +68 -20
- package/dist/types/behaviors/forms.d.ts +22 -0
- package/dist/types/components/barChart.d.ts +24 -0
- package/dist/types/components/columnChart.d.ts +21 -0
- package/dist/types/components/commandPalette.d.ts +96 -0
- package/dist/types/components/heatmapChart.d.ts +49 -0
- package/dist/types/components/index.d.ts +12 -0
- package/dist/types/components/lineChart.d.ts +134 -0
- package/dist/types/components/menu.d.ts +31 -0
- package/dist/types/components/messageScroller.d.ts +111 -0
- package/dist/types/components/mixedChart.d.ts +25 -0
- package/dist/types/components/pieChart.d.ts +40 -0
- package/dist/types/components/questionnaire.d.ts +96 -0
- package/dist/types/components/radarChart.d.ts +39 -0
- package/dist/types/components/radialChart.d.ts +45 -0
- package/dist/types/components/registry.d.ts +44 -0
- package/dist/types/components/richTextEditor.d.ts +71 -0
- package/dist/types/modular.d.ts +10 -1
- package/package.json +4 -1
- package/src/sass/README.md +3 -6
- package/src/sass/abstracts/_index.scss +1 -1
- package/src/sass/abstracts/_mixins.scss +226 -0
- package/src/sass/abstracts/_variables.scss +14 -0
- package/src/sass/base/_typography.scss +45 -0
- package/src/sass/components/_accordion.scss +161 -0
- package/src/sass/components/_aura.scss +119 -0
- package/src/sass/components/_avatar.scss +86 -0
- package/src/sass/components/_bar-chart.scss +285 -0
- package/src/sass/components/_bottom-sheet.scss +1 -0
- package/src/sass/components/_button-groups.scss +13 -3
- package/src/sass/components/_cards.scss +16 -13
- package/src/sass/components/_column-chart.scss +134 -0
- package/src/sass/components/_command-palette.scss +140 -0
- package/src/sass/components/_countdown.scss +89 -0
- package/src/sass/components/_data-table.scss +188 -0
- package/src/sass/components/_dialog.scss +1 -0
- package/src/sass/components/_empty-state.scss +78 -0
- package/src/sass/components/_expanding-card.scss +3 -0
- package/src/sass/components/_heatmap-chart.scss +156 -0
- package/src/sass/components/_index.scss +27 -0
- package/src/sass/components/_kpi.scss +162 -0
- package/src/sass/components/_line-chart.scss +102 -0
- package/src/sass/components/_marquee.scss +111 -0
- package/src/sass/components/_menu.scss +10 -0
- package/src/sass/components/_message-scroller.scss +66 -0
- package/src/sass/components/_message.scss +202 -0
- package/src/sass/components/_mixed-chart.scss +157 -0
- package/src/sass/components/_navigation-bar.scss +1 -0
- package/src/sass/components/_navigation-rail.scss +9 -0
- package/src/sass/components/_pie-chart.scss +203 -0
- package/src/sass/components/_popover.scss +112 -0
- package/src/sass/components/_questionnaire.scss +144 -0
- package/src/sass/components/_radar-chart.scss +205 -0
- package/src/sass/components/_radial-chart.scss +174 -0
- package/src/sass/components/_rich-text-editor.scss +99 -0
- package/src/sass/components/_search.scss +1 -0
- package/src/sass/components/_side-sheet.scss +1 -0
- package/src/sass/components/_skeleton.scss +81 -0
- package/src/sass/components/_snackbar.scss +1 -0
- package/src/sass/components/_stat.scss +86 -0
- package/src/sass/components/_stepper.scss +190 -0
- package/src/sass/components/_timeline.scss +114 -0
- package/src/sass/components/_toolbar.scss +1 -0
- package/src/sass/components/_tooltip.scss +2 -0
- package/src/sass/components/_tree.scss +139 -0
- package/src/sass/components/forms/_drop-zone.scss +128 -0
- package/src/sass/components/forms/_index.scss +2 -0
- package/src/sass/components/forms/_input-fields.scss +133 -2
- package/src/sass/components/forms/_rating.scss +165 -0
- package/src/sass/tokens/_reference.scss +3 -15
- package/src/sass/utilities/_index.scss +2 -0
- package/src/sass/utilities/_scroll-area.scss +35 -0
- package/src/sass/utilities/_shapes.scss +164 -0
- package/dist/js/chunks/chunk-G3I5H2U3.mjs +0 -7
- package/dist/js/chunks/chunk-G3I5H2U3.mjs.map +0 -7
- package/dist/js/chunks/chunk-HNFSMIBY.mjs.map +0 -7
- package/dist/js/chunks/chunk-PSSHQWCX.mjs +0 -100
- package/dist/js/chunks/chunk-PSSHQWCX.mjs.map +0 -7
- package/dist/js/chunks/chunk-WWPAPHMA.mjs +0 -1
- package/dist/js/chunks/chunk-YSBCHYXP.mjs.map +0 -7
- /package/dist/js/chunks/{chunk-HLDXZ7XB.mjs.map → chunk-3CLXLPYS.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-HB6IW7QQ.mjs.map → chunk-55IA2XUC.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-WWPAPHMA.mjs.map → chunk-NQLC3YMW.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-H2WA4XHH.mjs.map → chunk-PLYXLSH3.mjs.map} +0 -0
- /package/dist/js/chunks/{chunk-RFZZCYVU.mjs.map → chunk-XGHORT7J.mjs.map} +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/questionnaire.ts"],
|
|
4
|
+
"sourcesContent": ["import { Utils } from '../core/utils';\nimport { Component, BaseOptions, InitElements, InitElement } from '../core/component';\n\nexport interface QuestionnaireOptions extends BaseOptions {\n /**\n * Text above the progress bar. `{current}` and `{total}` are replaced with\n * the question number and the number of questions. `data-progress-label`\n * on the form sets it.\n * @default 'Question {current} of {total}'\n */\n progressLabel: string;\n /**\n * Error shown when a question has no `.questionnaire-error` of its own and\n * the browser gives no validation message, as for a `data-required` group\n * of checkboxes.\n * @default 'Choose an answer to continue.'\n */\n requiredMessage: string;\n}\n\nconst _defaults: QuestionnaireOptions = {\n progressLabel: 'Question {current} of {total}',\n requiredMessage: 'Choose an answer to continue.'\n};\n\nconst NAVIGATION = ['previous', 'skip', 'next'];\n\ntype Control = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\n\n/**\n * A multi-step questionnaire: a <form class=\"questionnaire\"> whose\n * <fieldset> children are the questions, shown one at a time, and a <footer>\n * of buttons. `value=\"previous\"`, `value=\"skip\"` and `value=\"next\"` mark the\n * navigation buttons; a submit button sends the form on the last question.\n *\n * A question is required when one of its controls is `required`, or when the\n * fieldset has `data-required` (at least one enabled checkbox, held as a\n * custom validity on the first one). Next and every way of submitting check\n * it with the browser's own validation; an optional question gets Skip, which\n * clears its answer. A disabled fieldset is left out, so a page can switch\n * questions on and off from earlier answers.\n *\n * Without JavaScript every question shows at once and the submit button sends\n * the form. The answers are ordinary form controls, so FormData reads them.\n */\nexport class Questionnaire extends Component<QuestionnaireOptions> {\n declare el: HTMLFormElement;\n private _active: HTMLFieldSetElement | null = null;\n private _progress: HTMLElement;\n private _progressText: HTMLElement;\n private _progressBar: HTMLProgressElement;\n private _generated: HTMLElement[] = [];\n private _generatedIds: HTMLElement[] = [];\n private _observer: MutationObserver;\n /** Set while one submission's invalid events arrive, so only the first opens. */\n private _reporting = false;\n\n constructor(el: HTMLFormElement, options: Partial<QuestionnaireOptions>) {\n super(el, options, Questionnaire);\n this.el['Expressive_Questionnaire'] = this;\n const progressLabel = el.dataset.progressLabel;\n this.options = {\n ...Questionnaire.defaults,\n ...(progressLabel ? { progressLabel } : {}),\n ...options\n };\n\n this._progress = document.createElement('div');\n this._progress.className = 'questionnaire-progress';\n this._progressText = document.createElement('span');\n this._progressText.id = `questionnaire-progress-${Utils.guid()}`;\n this._progressBar = document.createElement('progress');\n this._progressBar.className = 'progress';\n this._progressBar.setAttribute('aria-labelledby', this._progressText.id);\n this._progress.append(this._progressText, this._progressBar);\n this.el.prepend(this._progress);\n\n for (const item of this._fieldsets()) {\n const ids = Array.from(item.querySelectorAll<HTMLElement>(':scope > p:not(.questionnaire-error)'))\n .map((p) => this._ensureId(p, 'questionnaire-description'));\n if (ids.length && !item.hasAttribute('aria-describedby')) {\n item.setAttribute('aria-describedby', ids.join(' '));\n this._generatedIds.push(item);\n }\n }\n\n this._active = this.items[0] ?? null;\n this._syncRequired();\n this._render();\n // A page enabling or disabling a question from an earlier answer changes\n // the count and the buttons.\n this._observer = new MutationObserver(() => {\n this._syncRequired();\n this._render();\n });\n this._observer.observe(this.el, { attributes: true, subtree: true, attributeFilter: ['disabled'] });\n this.el.addEventListener('click', this._handleClick);\n this.el.addEventListener('keydown', this._handleKeydown);\n this.el.addEventListener('input', this._handleInput);\n // invalid does not bubble.\n this.el.addEventListener('invalid', this._handleInvalid, true);\n }\n\n static get defaults(): QuestionnaireOptions {\n return _defaults;\n }\n\n /**\n * Initializes instance of Questionnaire.\n * @param el HTML element.\n * @param options Component options.\n */\n static init(el: HTMLElement, options?: Partial<QuestionnaireOptions>): Questionnaire;\n /**\n * Initializes instances of Questionnaire.\n * @param els HTML elements.\n * @param options Component options.\n */\n static init(\n els: InitElements<InitElement>,\n options?: Partial<QuestionnaireOptions>\n ): Questionnaire[];\n /**\n * Initializes instances of Questionnaire.\n * @param els HTML elements.\n * @param options Component options.\n */\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<QuestionnaireOptions> = {}\n ): Questionnaire | Questionnaire[] {\n return super.init(els, options, Questionnaire);\n }\n\n static getInstance(el: HTMLElement): Questionnaire {\n return el['Expressive_Questionnaire'];\n }\n\n /** The questions that apply: every fieldset child that is not disabled. */\n get items(): HTMLFieldSetElement[] {\n return this._fieldsets().filter((item) => !item.disabled);\n }\n\n /** Position of the shown question in `items`. */\n get index(): number {\n return this.items.indexOf(this._active);\n }\n\n /** Shows the question at `index` without checking the current one. */\n goTo = (index: number) => {\n const item = this.items[index];\n if (!item) return;\n this._active = item;\n this._render();\n const controls = this._controls(item).filter((control) => !control.disabled);\n (controls.find((control) => (control as HTMLInputElement).checked) ?? controls[0])?.focus();\n };\n\n /** Checks the shown question and moves to the next one if it is answered. */\n next = () => {\n if (this._validate(this._active)) this.goTo(this.index + 1);\n };\n\n /** Moves to the previous question. */\n previous = () => this.goTo(this.index - 1);\n\n /** Clears the answer to the shown question and moves to the next one. */\n skip = () => {\n if (!this._active) return;\n for (const control of this._controls(this._active)) {\n const isChoice = control instanceof HTMLInputElement && (control.type === 'radio' || control.type === 'checkbox');\n if (isChoice ? !control.checked : !control.value) continue;\n if (isChoice) control.checked = false;\n else control.value = '';\n control.dispatchEvent(new Event('change', { bubbles: true }));\n }\n this.goTo(this.index + 1);\n };\n\n destroy() {\n this._observer.disconnect();\n this.el.removeEventListener('click', this._handleClick);\n this.el.removeEventListener('keydown', this._handleKeydown);\n this.el.removeEventListener('input', this._handleInput);\n this.el.removeEventListener('invalid', this._handleInvalid, true);\n for (const item of this._fieldsets()) {\n if (item.hasAttribute('data-required')) for (const control of this._controls(item)) control.setCustomValidity('');\n item.hidden = false;\n this._setInvalid(item, false);\n }\n for (const button of this._buttons()) button.hidden = false;\n this._progress.remove();\n for (const el of this._generated) el.remove();\n for (const el of this._generatedIds) {\n el.removeAttribute(el instanceof HTMLFieldSetElement ? 'aria-describedby' : 'id');\n }\n this.el['Expressive_Questionnaire'] = undefined;\n }\n\n private _fieldsets() {\n return Array.from(this.el.querySelectorAll<HTMLFieldSetElement>(':scope > fieldset'));\n }\n\n /** The footer's navigation and submit buttons. */\n private _buttons() {\n return Array.from(this.el.querySelectorAll<HTMLButtonElement>(':scope > footer > button')).filter(\n (button) => NAVIGATION.includes(button.value) || button.type === 'submit'\n );\n }\n\n private _controls(item: HTMLFieldSetElement) {\n return Array.from(item.elements).filter(\n (el): el is Control =>\n el instanceof HTMLTextAreaElement || el instanceof HTMLSelectElement ||\n (el instanceof HTMLInputElement && el.type !== 'button' && el.type !== 'submit')\n );\n }\n\n private _required(item: HTMLFieldSetElement) {\n return item.hasAttribute('data-required') || this._controls(item).some((control) => control.required);\n }\n\n private _ensureId(el: HTMLElement, prefix: string) {\n if (!el.id) {\n el.id = `${prefix}-${Utils.guid()}`;\n this._generatedIds.push(el);\n }\n return el.id;\n }\n\n private _render() {\n const items = this.items;\n // The shown question was switched off: carry on from the next one.\n if (!items.includes(this._active)) {\n const all = this._fieldsets();\n const after = all.slice(all.indexOf(this._active) + 1).find((item) => !item.disabled);\n this._active = after ?? items[items.length - 1] ?? null;\n }\n const index = items.indexOf(this._active);\n const last = index === items.length - 1;\n for (const item of this._fieldsets()) item.hidden = item !== this._active;\n for (const button of this._buttons()) {\n if (button.value === 'previous') button.hidden = index <= 0;\n else if (button.value === 'skip') button.hidden = last || !this._active || this._required(this._active);\n else if (button.value === 'next') button.hidden = last;\n else button.hidden = !last;\n }\n this._progressText.textContent = this.options.progressLabel\n .replace('{current}', String(index + 1))\n .replace('{total}', String(items.length));\n this._progressBar.max = Math.max(items.length, 1);\n this._progressBar.value = index + 1;\n }\n\n /**\n * Puts \"choose at least one\" on the first enabled checkbox of each\n * data-required group with none checked, so the browser's validation, and\n * every way of submitting, sees it. A disabled checkbox is not sent, so it\n * does not count.\n */\n private _syncRequired() {\n for (const item of this._fieldsets()) {\n if (!item.hasAttribute('data-required')) continue;\n const boxes = this._controls(item).filter(\n (control): control is HTMLInputElement => control instanceof HTMLInputElement && control.type === 'checkbox'\n );\n const enabled = boxes.filter((box) => !box.disabled);\n for (const box of boxes) box.setCustomValidity('');\n if (enabled.length && !enabled.some((box) => box.checked)) {\n const error = item.querySelector<HTMLElement>(':scope > .questionnaire-error:not([data-generated])');\n enabled[0].setCustomValidity(error?.textContent.trim() || this.options.requiredMessage);\n }\n }\n }\n\n /** The first control in the question that still needs an answer. */\n private _invalidControl(item: HTMLFieldSetElement): Control | undefined {\n return this._controls(item).find((control) => control.willValidate && !control.validity.valid);\n }\n\n /** Shows the question's error and returns false when it needs an answer. */\n private _validate(item: HTMLFieldSetElement | null) {\n this._syncRequired();\n const invalid = item && this._invalidControl(item);\n if (!invalid) return true;\n let error = item.querySelector<HTMLElement>(':scope > .questionnaire-error');\n if (!error) {\n error = document.createElement('p');\n error.className = 'questionnaire-error';\n error.dataset.generated = '';\n error.textContent = invalid.validationMessage || this.options.requiredMessage;\n item.append(error);\n this._generated.push(error);\n }\n this._setInvalid(item, true);\n invalid.focus();\n return false;\n }\n\n private _setInvalid(item: HTMLFieldSetElement, invalid: boolean) {\n item.classList.toggle('invalid', invalid);\n const error = item.querySelector<HTMLElement>(':scope > .questionnaire-error');\n const described = (item.getAttribute('aria-describedby') ?? '').split(' ').filter((id) => id && id !== error?.id);\n if (invalid && error) described.push(this._ensureId(error, 'questionnaire-error'));\n if (described.length) item.setAttribute('aria-describedby', described.join(' '));\n else item.removeAttribute('aria-describedby');\n for (const control of this._controls(item)) {\n if (invalid) control.setAttribute('aria-invalid', 'true');\n else control.removeAttribute('aria-invalid');\n }\n if (!invalid && this._generated.includes(error)) {\n error.remove();\n this._generated.splice(this._generated.indexOf(error), 1);\n }\n }\n\n private _handleClick = (e: MouseEvent) => {\n const button = (e.target as Element).closest?.('button');\n if (!button || !this._buttons().includes(button)) return;\n if (NAVIGATION.includes(button.value)) {\n // Also stops a navigation button written without type=\"button\" from\n // submitting the form.\n e.preventDefault();\n this[button.value as 'previous' | 'skip' | 'next']();\n return;\n }\n // Submit by click or Enter: catch answers a script set without an event.\n this._syncRequired();\n };\n\n // Enter in a field moves on instead of submitting the form early.\n private _handleKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter' || e.defaultPrevented || e.isComposing) return;\n if (!(e.target instanceof HTMLInputElement) || this.index >= this.items.length - 1) return;\n e.preventDefault();\n this.next();\n };\n\n // A submission found an unanswered question, possibly a hidden one. Open the\n // first instead of letting the browser report a control it cannot show.\n // One submission fires its invalid events in a single task.\n private _handleInvalid = (e: Event) => {\n const item = this.items.find((item) => item.contains(e.target as Node));\n if (!item) return;\n e.preventDefault();\n if (this._reporting) return;\n this._reporting = true;\n setTimeout(() => (this._reporting = false));\n this._active = item;\n this._render();\n this._validate(item);\n };\n\n // An answer clears the question's error.\n private _handleInput = (e: Event) => {\n this._syncRequired();\n const item = (e.target as Element).closest?.('fieldset');\n if (item instanceof HTMLFieldSetElement && item.classList.contains('invalid')) this._setInvalid(item, false);\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["item"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ColumnChart
|
|
3
|
+
} from "./chunk-SPETGK25.mjs";
|
|
4
|
+
|
|
5
|
+
// src/ts/components/barChart.ts
|
|
6
|
+
var BarChart = class extends ColumnChart {
|
|
7
|
+
get _type() {
|
|
8
|
+
return "bar-chart";
|
|
9
|
+
}
|
|
10
|
+
get _key() {
|
|
11
|
+
return "Expressive_BarChart";
|
|
12
|
+
}
|
|
13
|
+
get _horizontal() {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
static init(els, options = {}) {
|
|
17
|
+
return super.init(els, options);
|
|
18
|
+
}
|
|
19
|
+
static getInstance(el) {
|
|
20
|
+
return el["Expressive_BarChart"];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The column chart's spans; CSS reads their --top and --bottom across the
|
|
24
|
+
* plot. With .values, a copy of the bars without their clipping holds each
|
|
25
|
+
* cell's text, so text longer than a short bar can run past its end.
|
|
26
|
+
*/
|
|
27
|
+
_draw() {
|
|
28
|
+
const bars = super._draw();
|
|
29
|
+
bars.className = "bar-chart-bars";
|
|
30
|
+
bars.classList.toggle("rtl", getComputedStyle(this.el).direction === "rtl");
|
|
31
|
+
if (!this.el.classList.contains("values")) return bars;
|
|
32
|
+
const values = bars.cloneNode(true);
|
|
33
|
+
values.classList.replace("bar-chart-bars", "bar-chart-values");
|
|
34
|
+
values.querySelectorAll("span[data-text]").forEach((span) => {
|
|
35
|
+
span.textContent = span.dataset.text;
|
|
36
|
+
});
|
|
37
|
+
const layers = document.createElement("div");
|
|
38
|
+
layers.className = "bar-chart-layers";
|
|
39
|
+
layers.append(bars, values);
|
|
40
|
+
return layers;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
BarChart
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=chunk-GVGT6MIU.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/barChart.ts"],
|
|
4
|
+
"sourcesContent": ["import { InitElements, InitElement } from '../core/component';\nimport { ColumnChart, ColumnChartOptions } from './columnChart';\n\nexport type BarChartOptions = ColumnChartOptions;\n\n/**\n * Bar chart. A column chart turned on its side: each row of the <table> is\n * a band of bars that grow from zero along the inline axis, with its label\n * beside it. The up and down arrows move the tooltip between rows.\n *\n * Re-run `BarChart.init(el)` after changing the table.\n */\nexport class BarChart extends ColumnChart {\n protected get _type() {\n return 'bar-chart';\n }\n\n protected get _key() {\n return 'Expressive_BarChart';\n }\n\n protected get _horizontal() {\n return true;\n }\n\n static init(el: HTMLElement, options?: Partial<BarChartOptions>): BarChart;\n static init(els: InitElements<InitElement>, options?: Partial<BarChartOptions>): BarChart[];\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<BarChartOptions> = {}\n ): BarChart | BarChart[] {\n return super.init(els as HTMLElement, options) as BarChart | BarChart[];\n }\n\n static getInstance(el: HTMLElement): BarChart {\n return el['Expressive_BarChart'];\n }\n\n /**\n * The column chart's spans; CSS reads their --top and --bottom across the\n * plot. With .values, a copy of the bars without their clipping holds each\n * cell's text, so text longer than a short bar can run past its end.\n */\n protected _draw(): Element {\n const bars = super._draw() as HTMLElement;\n bars.className = 'bar-chart-bars';\n // Read here rather than with :dir(), which misses CSS `direction`.\n bars.classList.toggle('rtl', getComputedStyle(this.el).direction === 'rtl');\n if (!this.el.classList.contains('values')) return bars;\n\n const values = bars.cloneNode(true) as HTMLElement;\n values.classList.replace('bar-chart-bars', 'bar-chart-values');\n values.querySelectorAll<HTMLElement>('span[data-text]').forEach((span) => {\n span.textContent = span.dataset.text;\n });\n const layers = document.createElement('div');\n layers.className = 'bar-chart-layers';\n layers.append(bars, values);\n return layers;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;AAYO,IAAM,WAAN,cAAuB,YAAY;AAAA,EACxC,IAAc,QAAQ;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,OAAO;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,cAAc;AAC1B,WAAO;AAAA,EACT;AAAA,EAIA,OAAO,KACL,KACA,UAAoC,CAAC,GACd;AACvB,WAAO,MAAM,KAAK,KAAoB,OAAO;AAAA,EAC/C;AAAA,EAEA,OAAO,YAAY,IAA2B;AAC5C,WAAO,GAAG,qBAAqB;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,QAAiB;AACzB,UAAM,OAAO,MAAM,MAAM;AACzB,SAAK,YAAY;AAEjB,SAAK,UAAU,OAAO,OAAO,iBAAiB,KAAK,EAAE,EAAE,cAAc,KAAK;AAC1E,QAAI,CAAC,KAAK,GAAG,UAAU,SAAS,QAAQ,EAAG,QAAO;AAElD,UAAM,SAAS,KAAK,UAAU,IAAI;AAClC,WAAO,UAAU,QAAQ,kBAAkB,kBAAkB;AAC7D,WAAO,iBAA8B,iBAAiB,EAAE,QAAQ,CAAC,SAAS;AACxE,WAAK,cAAc,KAAK,QAAQ;AAAA,IAClC,CAAC;AACD,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,YAAY;AACnB,WAAO,OAAO,MAAM,MAAM;AAC1B,WAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ColumnChart
|
|
3
|
+
} from "./chunk-SPETGK25.mjs";
|
|
4
|
+
import {
|
|
5
|
+
LineChart
|
|
6
|
+
} from "./chunk-O5XPWXIQ.mjs";
|
|
7
|
+
|
|
8
|
+
// src/ts/components/mixedChart.ts
|
|
9
|
+
var has = (series, name) => series.className.split(/\s+/).includes(name);
|
|
10
|
+
var MixedChart = class extends ColumnChart {
|
|
11
|
+
get _type() {
|
|
12
|
+
return "mixed-chart";
|
|
13
|
+
}
|
|
14
|
+
get _key() {
|
|
15
|
+
return "Expressive_MixedChart";
|
|
16
|
+
}
|
|
17
|
+
get _points() {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
static init(els, options = {}) {
|
|
21
|
+
return super.init(els, options);
|
|
22
|
+
}
|
|
23
|
+
static getInstance(el) {
|
|
24
|
+
return el["Expressive_MixedChart"];
|
|
25
|
+
}
|
|
26
|
+
/** The start scale, then the end scale; each includes zero if it has columns. */
|
|
27
|
+
_scale(series, min, max) {
|
|
28
|
+
const end = series.filter((each) => has(each, "end"));
|
|
29
|
+
const start = series.filter((each) => !end.includes(each));
|
|
30
|
+
const columns = (list) => list.some((each) => has(each, "column"));
|
|
31
|
+
super._scale(end, this._number("endMin"), this._number("endMax"), columns(end));
|
|
32
|
+
return super._scale(start, min, max, columns(start));
|
|
33
|
+
}
|
|
34
|
+
/** Columns behind, then the lines and areas over them. */
|
|
35
|
+
_draw() {
|
|
36
|
+
const marks = document.createElement("div");
|
|
37
|
+
marks.className = "mixed-chart-marks";
|
|
38
|
+
const columns = super._draw(this.series.filter((series) => has(series, "column")));
|
|
39
|
+
columns.className = "mixed-chart-columns";
|
|
40
|
+
marks.append(columns, LineChart.prototype["_draw"].call(this, this.series.filter((series) => !has(series, "column"))));
|
|
41
|
+
return marks;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export {
|
|
46
|
+
MixedChart
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=chunk-HKT2S7VM.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/mixedChart.ts"],
|
|
4
|
+
"sourcesContent": ["import { InitElements, InitElement } from '../core/component';\nimport { ColumnChart } from './columnChart';\nimport { LineChart, LineChartOptions, Series } from './lineChart';\n\nexport type MixedChartOptions = LineChartOptions;\n\n/** Whether a series header cell has a class. */\nconst has = (series: Series, name: string) => series.className.split(/\\s+/).includes(name);\n\n/**\n * Mixed chart. It reads its <table> like LineChart, and draws each series\n * by its header cell's class: `column` as columns from zero, `area` as a\n * line with a fill under it, and anything else as a line. Series with\n * `end` are drawn against a second scale, set by `data-end-min` and\n * `data-end-max`, so values of different sizes or units share the plot.\n *\n * Re-run `MixedChart.init(el)` after changing the table.\n */\nexport class MixedChart extends ColumnChart {\n protected get _type() {\n return 'mixed-chart';\n }\n\n protected get _key() {\n return 'Expressive_MixedChart';\n }\n\n protected get _points() {\n return true;\n }\n\n static init(el: HTMLElement, options?: Partial<MixedChartOptions>): MixedChart;\n static init(els: InitElements<InitElement>, options?: Partial<MixedChartOptions>): MixedChart[];\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<MixedChartOptions> = {}\n ): MixedChart | MixedChart[] {\n return super.init(els as HTMLElement, options) as MixedChart | MixedChart[];\n }\n\n static getInstance(el: HTMLElement): MixedChart {\n return el['Expressive_MixedChart'];\n }\n\n /** The start scale, then the end scale; each includes zero if it has columns. */\n protected _scale(series: Series[], min: number | null, max: number | null) {\n const end = series.filter((each) => has(each, 'end'));\n const start = series.filter((each) => !end.includes(each));\n const columns = (list: Series[]) => list.some((each) => has(each, 'column'));\n super._scale(end, this._number('endMin'), this._number('endMax'), columns(end));\n return super._scale(start, min, max, columns(start));\n }\n\n /** Columns behind, then the lines and areas over them. */\n protected _draw(): Element {\n const marks = document.createElement('div');\n marks.className = 'mixed-chart-marks';\n const columns = super._draw(this.series.filter((series) => has(series, 'column')));\n columns.className = 'mixed-chart-columns';\n marks.append(columns, LineChart.prototype['_draw'].call(this, this.series.filter((series) => !has(series, 'column'))));\n return marks;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;AAOA,IAAM,MAAM,CAAC,QAAgB,SAAiB,OAAO,UAAU,MAAM,KAAK,EAAE,SAAS,IAAI;AAWlF,IAAM,aAAN,cAAyB,YAAY;AAAA,EAC1C,IAAc,QAAQ;AACpB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,OAAO;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,IAAc,UAAU;AACtB,WAAO;AAAA,EACT;AAAA,EAIA,OAAO,KACL,KACA,UAAsC,CAAC,GACZ;AAC3B,WAAO,MAAM,KAAK,KAAoB,OAAO;AAAA,EAC/C;AAAA,EAEA,OAAO,YAAY,IAA6B;AAC9C,WAAO,GAAG,uBAAuB;AAAA,EACnC;AAAA;AAAA,EAGU,OAAO,QAAkB,KAAoB,KAAoB;AACzE,UAAM,MAAM,OAAO,OAAO,CAAC,SAAS,IAAI,MAAM,KAAK,CAAC;AACpD,UAAM,QAAQ,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC;AACzD,UAAM,UAAU,CAAC,SAAmB,KAAK,KAAK,CAAC,SAAS,IAAI,MAAM,QAAQ,CAAC;AAC3E,UAAM,OAAO,KAAK,KAAK,QAAQ,QAAQ,GAAG,KAAK,QAAQ,QAAQ,GAAG,QAAQ,GAAG,CAAC;AAC9E,WAAO,MAAM,OAAO,OAAO,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,EACrD;AAAA;AAAA,EAGU,QAAiB;AACzB,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAClB,UAAM,UAAU,MAAM,MAAM,KAAK,OAAO,OAAO,CAAC,WAAW,IAAI,QAAQ,QAAQ,CAAC,CAAC;AACjF,YAAQ,YAAY;AACpB,UAAM,OAAO,SAAS,UAAU,UAAU,OAAO,EAAE,KAAK,MAAM,KAAK,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,QAAQ,QAAQ,CAAC,CAAC,CAAC;AACrH,WAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Utils
|
|
3
|
+
} from "./chunk-6OMRGML6.mjs";
|
|
4
|
+
import {
|
|
5
|
+
Component
|
|
6
|
+
} from "./chunk-LTWPGFBR.mjs";
|
|
7
|
+
|
|
8
|
+
// src/ts/components/commandPalette.ts
|
|
9
|
+
var _defaults = {
|
|
10
|
+
shortcut: "k",
|
|
11
|
+
closeOnRun: true
|
|
12
|
+
};
|
|
13
|
+
var APPLE = typeof navigator !== "undefined" && /Mac|iPhone|iPad|iPod/.test(navigator.platform);
|
|
14
|
+
var fold = (text) => text.normalize("NFD").replace(/\p{Diacritic}/gu, "").toLowerCase();
|
|
15
|
+
var CommandPalette = class _CommandPalette extends Component {
|
|
16
|
+
constructor(el, options) {
|
|
17
|
+
super(el, options, _CommandPalette);
|
|
18
|
+
this._active = null;
|
|
19
|
+
this._generatedIds = [];
|
|
20
|
+
/** Wires and refilters commands the page adds or removes later. */
|
|
21
|
+
this._observer = null;
|
|
22
|
+
/** Opens the palette as a modal dialog with the search input focused. */
|
|
23
|
+
this.open = () => {
|
|
24
|
+
if (!this.el.open) this.el.showModal();
|
|
25
|
+
this.input?.focus();
|
|
26
|
+
};
|
|
27
|
+
/** Closes the palette. The dialog returns focus to where it was. */
|
|
28
|
+
this.close = () => {
|
|
29
|
+
if (this.el.open) this.el.close();
|
|
30
|
+
};
|
|
31
|
+
this._handleInput = () => this._filter();
|
|
32
|
+
this._handleKeydown = (e) => {
|
|
33
|
+
if (e.key === Utils.keys.ARROW_DOWN || e.key === Utils.keys.ARROW_UP) {
|
|
34
|
+
e.preventDefault();
|
|
35
|
+
this._move(e.key === Utils.keys.ARROW_DOWN ? 1 : -1);
|
|
36
|
+
} else if (e.key === Utils.keys.ENTER && !e.isComposing && e.keyCode !== 229 && this._active) {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
this._run(this._active);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
this._handleListClick = (e) => {
|
|
42
|
+
const item = e.target.closest('[role="option"]');
|
|
43
|
+
if (!item || !this.list.contains(item) || item.getAttribute("aria-disabled") === "true") return;
|
|
44
|
+
const action = this._action(item);
|
|
45
|
+
if (action && !action.contains(e.target)) {
|
|
46
|
+
action.click();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (this.options.closeOnRun) this.close();
|
|
50
|
+
};
|
|
51
|
+
this._handlePointerMove = (e) => {
|
|
52
|
+
const item = e.target.closest('[role="option"]');
|
|
53
|
+
if (item && this.list.contains(item) && item.getAttribute("aria-disabled") !== "true") this._setActive(item);
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Each opening starts from the full list. The close event is queued, so a
|
|
57
|
+
* palette reopened straight away may already be open again; its new search
|
|
58
|
+
* is left alone.
|
|
59
|
+
*/
|
|
60
|
+
this._handleClose = () => {
|
|
61
|
+
if (this.el.open) return;
|
|
62
|
+
this.input.value = "";
|
|
63
|
+
this._filter();
|
|
64
|
+
};
|
|
65
|
+
this._handleShortcut = (e) => {
|
|
66
|
+
const { shortcut } = this.options;
|
|
67
|
+
if (!shortcut || e.defaultPrevented || e.altKey || e.shiftKey) return;
|
|
68
|
+
if (!(APPLE ? e.metaKey && !e.ctrlKey : e.ctrlKey && !e.metaKey)) return;
|
|
69
|
+
const letter = shortcut.toLowerCase();
|
|
70
|
+
const latin = /^[a-z]$/i.test(e.key);
|
|
71
|
+
const hit = e.key.toLowerCase() === letter || !latin && /^[a-z]$/.test(letter) && e.code === `Key${letter.toUpperCase()}`;
|
|
72
|
+
if (!hit) return;
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
if (this.el.open) this.close();
|
|
75
|
+
else this.open();
|
|
76
|
+
};
|
|
77
|
+
this.el["Expressive_CommandPalette"] = this;
|
|
78
|
+
const shortcut = el.dataset.shortcut;
|
|
79
|
+
this.options = {
|
|
80
|
+
..._CommandPalette.defaults,
|
|
81
|
+
...shortcut !== void 0 ? { shortcut: shortcut || null } : {},
|
|
82
|
+
...options
|
|
83
|
+
};
|
|
84
|
+
this.input = el.querySelector(":scope > input");
|
|
85
|
+
this.list = el.querySelector(":scope > :is(ul, ol)");
|
|
86
|
+
if (!this.input || !this.list) {
|
|
87
|
+
console.error("CommandPalette needs an <input> and a <ul> as children of the dialog.");
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
this._setupAccessibility();
|
|
91
|
+
this._filter();
|
|
92
|
+
this._observer = new MutationObserver(() => this._filter(true));
|
|
93
|
+
this._observer.observe(this.list, {
|
|
94
|
+
childList: true,
|
|
95
|
+
subtree: true,
|
|
96
|
+
attributes: true,
|
|
97
|
+
attributeFilter: ["hidden", "disabled"]
|
|
98
|
+
});
|
|
99
|
+
this.input.addEventListener("input", this._handleInput);
|
|
100
|
+
this.input.addEventListener("keydown", this._handleKeydown);
|
|
101
|
+
this.list.addEventListener("click", this._handleListClick);
|
|
102
|
+
this.list.addEventListener("pointermove", this._handlePointerMove);
|
|
103
|
+
this.el.addEventListener("close", this._handleClose);
|
|
104
|
+
document.addEventListener("keydown", this._handleShortcut);
|
|
105
|
+
}
|
|
106
|
+
static get defaults() {
|
|
107
|
+
return _defaults;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Initializes instances of CommandPalette.
|
|
111
|
+
* @param els HTML elements.
|
|
112
|
+
* @param options Component options.
|
|
113
|
+
*/
|
|
114
|
+
static init(els, options = {}) {
|
|
115
|
+
return super.init(els, options, _CommandPalette);
|
|
116
|
+
}
|
|
117
|
+
static getInstance(el) {
|
|
118
|
+
return el["Expressive_CommandPalette"];
|
|
119
|
+
}
|
|
120
|
+
/** If the palette is open. */
|
|
121
|
+
get isOpen() {
|
|
122
|
+
return this.el.open;
|
|
123
|
+
}
|
|
124
|
+
destroy() {
|
|
125
|
+
this._observer?.disconnect();
|
|
126
|
+
document.removeEventListener("keydown", this._handleShortcut);
|
|
127
|
+
this.el.removeEventListener("close", this._handleClose);
|
|
128
|
+
if (this.input && this.list) {
|
|
129
|
+
this.input.removeEventListener("input", this._handleInput);
|
|
130
|
+
this.input.removeEventListener("keydown", this._handleKeydown);
|
|
131
|
+
this.list.removeEventListener("click", this._handleListClick);
|
|
132
|
+
this.list.removeEventListener("pointermove", this._handlePointerMove);
|
|
133
|
+
for (const name of ["role", "aria-controls", "aria-expanded", "aria-autocomplete", "aria-activedescendant"]) {
|
|
134
|
+
this.input.removeAttribute(name);
|
|
135
|
+
}
|
|
136
|
+
this.list.removeAttribute("role");
|
|
137
|
+
for (const item of this._items()) {
|
|
138
|
+
for (const name of ["role", "aria-selected", "aria-disabled", "data-filtered"]) item.removeAttribute(name);
|
|
139
|
+
item.classList.remove("active");
|
|
140
|
+
this._action(item)?.removeAttribute("tabindex");
|
|
141
|
+
}
|
|
142
|
+
for (const label of this._labels()) {
|
|
143
|
+
label.removeAttribute("role");
|
|
144
|
+
label.removeAttribute("data-filtered");
|
|
145
|
+
}
|
|
146
|
+
for (const el of this._generatedIds) el.removeAttribute("id");
|
|
147
|
+
const empty = this._empty();
|
|
148
|
+
if (empty) empty.hidden = false;
|
|
149
|
+
}
|
|
150
|
+
this.el["Expressive_CommandPalette"] = void 0;
|
|
151
|
+
}
|
|
152
|
+
_items() {
|
|
153
|
+
return Array.from(this.list.children).filter(
|
|
154
|
+
(child) => child instanceof HTMLElement && !child.classList.contains("label")
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
_labels() {
|
|
158
|
+
return Array.from(this.list.querySelectorAll(":scope > .label"));
|
|
159
|
+
}
|
|
160
|
+
_empty() {
|
|
161
|
+
return this.el.querySelector(":scope > .command-palette-empty");
|
|
162
|
+
}
|
|
163
|
+
_action(item) {
|
|
164
|
+
return item.querySelector(":scope > :is(a[href], button)");
|
|
165
|
+
}
|
|
166
|
+
_ensureId(el, prefix) {
|
|
167
|
+
if (!el.id) {
|
|
168
|
+
el.id = `${prefix}-${Utils.guid()}`;
|
|
169
|
+
this._generatedIds.push(el);
|
|
170
|
+
}
|
|
171
|
+
return el.id;
|
|
172
|
+
}
|
|
173
|
+
_setupAccessibility() {
|
|
174
|
+
this.list.setAttribute("role", "listbox");
|
|
175
|
+
this.input.setAttribute("role", "combobox");
|
|
176
|
+
this.input.setAttribute("aria-controls", this._ensureId(this.list, "command-palette-list"));
|
|
177
|
+
this.input.setAttribute("aria-expanded", "true");
|
|
178
|
+
this.input.setAttribute("aria-autocomplete", "list");
|
|
179
|
+
}
|
|
180
|
+
/** Every command, including ones added since the last pass, is an option. */
|
|
181
|
+
_wireItems() {
|
|
182
|
+
for (const item of this._items()) {
|
|
183
|
+
if (item.getAttribute("role") === "option") continue;
|
|
184
|
+
item.setAttribute("role", "option");
|
|
185
|
+
this._ensureId(item, "command-palette-option");
|
|
186
|
+
this._action(item)?.setAttribute("tabindex", "-1");
|
|
187
|
+
}
|
|
188
|
+
for (const label of this._labels()) label.setAttribute("role", "none");
|
|
189
|
+
}
|
|
190
|
+
/** Commands on screen: neither hidden by the page nor filtered out. */
|
|
191
|
+
_shown() {
|
|
192
|
+
return this._items().filter((item) => !item.hidden && !item.hasAttribute("data-filtered"));
|
|
193
|
+
}
|
|
194
|
+
/** Shown commands the arrows and Enter can reach: disabled ones are skipped. */
|
|
195
|
+
_visible() {
|
|
196
|
+
return this._shown().filter((item) => item.getAttribute("aria-disabled") !== "true");
|
|
197
|
+
}
|
|
198
|
+
/** A disabled link or button cannot run, so its option says so. */
|
|
199
|
+
_isDisabled(item) {
|
|
200
|
+
const action = this._action(item);
|
|
201
|
+
return !!action && (action.matches(":disabled") || action.getAttribute("aria-disabled") === "true");
|
|
202
|
+
}
|
|
203
|
+
_setActive(item) {
|
|
204
|
+
if (this._active === item) return;
|
|
205
|
+
this._active?.classList.remove("active");
|
|
206
|
+
this._active?.removeAttribute("aria-selected");
|
|
207
|
+
this._active = item;
|
|
208
|
+
if (item) {
|
|
209
|
+
item.classList.add("active");
|
|
210
|
+
item.setAttribute("aria-selected", "true");
|
|
211
|
+
this.input.setAttribute("aria-activedescendant", item.id);
|
|
212
|
+
item.scrollIntoView({ block: "nearest" });
|
|
213
|
+
} else {
|
|
214
|
+
this.input.removeAttribute("aria-activedescendant");
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Shows the commands matching the query. Filtering marks rows with
|
|
219
|
+
* data-filtered rather than hidden, so a command the page hides stays
|
|
220
|
+
* hidden. `keepActive` holds the active command while it is still
|
|
221
|
+
* reachable, for list changes the user did not make.
|
|
222
|
+
*/
|
|
223
|
+
_filter(keepActive = false) {
|
|
224
|
+
this._wireItems();
|
|
225
|
+
const terms = fold(this.input.value).split(/\s+/).filter(Boolean);
|
|
226
|
+
for (const item of this._items()) {
|
|
227
|
+
const keywords = item.dataset.keywords ?? this._action(item)?.dataset.keywords ?? "";
|
|
228
|
+
const text = fold(`${item.textContent} ${keywords}`);
|
|
229
|
+
item.toggleAttribute("data-filtered", !terms.every((term) => text.includes(term)));
|
|
230
|
+
if (this._isDisabled(item)) item.setAttribute("aria-disabled", "true");
|
|
231
|
+
else item.removeAttribute("aria-disabled");
|
|
232
|
+
}
|
|
233
|
+
for (const label of this._labels()) {
|
|
234
|
+
let next = label.nextElementSibling;
|
|
235
|
+
let any = false;
|
|
236
|
+
while (next && !next.classList.contains("label")) {
|
|
237
|
+
if (!next.hidden && !next.hasAttribute("data-filtered")) any = true;
|
|
238
|
+
next = next.nextElementSibling;
|
|
239
|
+
}
|
|
240
|
+
label.toggleAttribute("data-filtered", !any);
|
|
241
|
+
}
|
|
242
|
+
const visible = this._visible();
|
|
243
|
+
const empty = this._empty();
|
|
244
|
+
if (empty) empty.hidden = this._shown().length > 0;
|
|
245
|
+
this._setActive(keepActive && visible.includes(this._active) ? this._active : visible[0] ?? null);
|
|
246
|
+
}
|
|
247
|
+
_move(step) {
|
|
248
|
+
const visible = this._visible();
|
|
249
|
+
if (!visible.length) return;
|
|
250
|
+
const index = visible.indexOf(this._active);
|
|
251
|
+
this._setActive(visible[(index + step + visible.length) % visible.length]);
|
|
252
|
+
}
|
|
253
|
+
/** Runs a command by clicking its link or button; the click handler closes. */
|
|
254
|
+
_run(item) {
|
|
255
|
+
(this._action(item) ?? item).click();
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export {
|
|
260
|
+
CommandPalette
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=chunk-K4CJCRGE.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/ts/components/commandPalette.ts"],
|
|
4
|
+
"sourcesContent": ["import { Utils } from '../core/utils';\nimport { Component, BaseOptions, InitElements, InitElement, Openable } from '../core/component';\n\nexport interface CommandPaletteOptions extends BaseOptions {\n /**\n * Letter that toggles the palette together with Command on Apple platforms\n * or Ctrl elsewhere. A key event the page has already handled is left\n * alone. `null` turns the shortcut off. `data-shortcut` on the dialog sets\n * it; an empty `data-shortcut` turns it off.\n * @default 'k'\n */\n shortcut: string | null;\n /**\n * If true, the palette closes after a command runs.\n * @default true\n */\n closeOnRun: boolean;\n}\n\nconst _defaults: CommandPaletteOptions = {\n shortcut: 'k',\n closeOnRun: true\n};\n\n// On Apple platforms Ctrl+letter is text editing (Ctrl+K deletes to the end\n// of the line), so only Command opens the palette there.\nconst APPLE = typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/.test(navigator.platform);\n\n/** Case- and accent-insensitive text for matching. */\nconst fold = (text: string) =>\n text.normalize('NFD').replace(/\\p{Diacritic}/gu, '').toLowerCase();\n\n/**\n * A command palette: a native modal <dialog class=\"command-palette\"> holding\n * a search input and a list of commands. Typing filters the list; the arrow\n * keys move through what is left and Enter runs it, while focus stays in the\n * input. The dialog owns modality, Escape and returning focus.\n *\n * The input is a combobox and the list a listbox of options, with the active\n * option reported through aria-activedescendant. A command is the link or\n * button inside an option; running it clicks that element, so a page wires\n * commands with ordinary hrefs and click handlers.\n */\nexport class CommandPalette extends Component<CommandPaletteOptions> implements Openable {\n declare el: HTMLDialogElement;\n /** The search input. */\n input: HTMLInputElement;\n /** The list of commands. */\n list: HTMLElement;\n private _active: HTMLElement | null = null;\n private _generatedIds: HTMLElement[] = [];\n /** Wires and refilters commands the page adds or removes later. */\n private _observer: MutationObserver | null = null;\n\n constructor(el: HTMLDialogElement, options: Partial<CommandPaletteOptions>) {\n super(el, options, CommandPalette);\n this.el['Expressive_CommandPalette'] = this;\n const shortcut = el.dataset.shortcut;\n this.options = {\n ...CommandPalette.defaults,\n ...(shortcut !== undefined ? { shortcut: shortcut || null } : {}),\n ...options\n };\n this.input = el.querySelector(':scope > input');\n this.list = el.querySelector(':scope > :is(ul, ol)');\n if (!this.input || !this.list) {\n console.error('CommandPalette needs an <input> and a <ul> as children of the dialog.');\n return;\n }\n this._setupAccessibility();\n this._filter();\n // A page adding commands while the user arrows through the list keeps\n // their place.\n this._observer = new MutationObserver(() => this._filter(true));\n // Also refilter when the page hides, shows, disables or enables a command.\n // Not aria-disabled: _filter writes that itself, which would loop.\n this._observer.observe(this.list, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['hidden', 'disabled']\n });\n this.input.addEventListener('input', this._handleInput);\n this.input.addEventListener('keydown', this._handleKeydown);\n this.list.addEventListener('click', this._handleListClick);\n this.list.addEventListener('pointermove', this._handlePointerMove);\n this.el.addEventListener('close', this._handleClose);\n document.addEventListener('keydown', this._handleShortcut);\n }\n\n static get defaults(): CommandPaletteOptions {\n return _defaults;\n }\n\n /**\n * Initializes instance of CommandPalette.\n * @param el HTML element.\n * @param options Component options.\n */\n static init(el: HTMLElement, options?: Partial<CommandPaletteOptions>): CommandPalette;\n /**\n * Initializes instances of CommandPalette.\n * @param els HTML elements.\n * @param options Component options.\n */\n static init(\n els: InitElements<InitElement>,\n options?: Partial<CommandPaletteOptions>\n ): CommandPalette[];\n /**\n * Initializes instances of CommandPalette.\n * @param els HTML elements.\n * @param options Component options.\n */\n static init(\n els: HTMLElement | InitElements<InitElement>,\n options: Partial<CommandPaletteOptions> = {}\n ): CommandPalette | CommandPalette[] {\n return super.init(els, options, CommandPalette);\n }\n\n static getInstance(el: HTMLElement): CommandPalette {\n return el['Expressive_CommandPalette'];\n }\n\n /** If the palette is open. */\n get isOpen() {\n return this.el.open;\n }\n\n /** Opens the palette as a modal dialog with the search input focused. */\n open = () => {\n if (!this.el.open) this.el.showModal();\n this.input?.focus();\n };\n\n /** Closes the palette. The dialog returns focus to where it was. */\n close = () => {\n if (this.el.open) this.el.close();\n };\n\n destroy() {\n this._observer?.disconnect();\n document.removeEventListener('keydown', this._handleShortcut);\n this.el.removeEventListener('close', this._handleClose);\n if (this.input && this.list) {\n this.input.removeEventListener('input', this._handleInput);\n this.input.removeEventListener('keydown', this._handleKeydown);\n this.list.removeEventListener('click', this._handleListClick);\n this.list.removeEventListener('pointermove', this._handlePointerMove);\n for (const name of ['role', 'aria-controls', 'aria-expanded', 'aria-autocomplete', 'aria-activedescendant']) {\n this.input.removeAttribute(name);\n }\n this.list.removeAttribute('role');\n for (const item of this._items()) {\n for (const name of ['role', 'aria-selected', 'aria-disabled', 'data-filtered']) item.removeAttribute(name);\n item.classList.remove('active');\n this._action(item)?.removeAttribute('tabindex');\n }\n for (const label of this._labels()) {\n label.removeAttribute('role');\n label.removeAttribute('data-filtered');\n }\n for (const el of this._generatedIds) el.removeAttribute('id');\n const empty = this._empty();\n if (empty) empty.hidden = false;\n }\n this.el['Expressive_CommandPalette'] = undefined;\n }\n\n private _items() {\n return Array.from(this.list.children).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.classList.contains('label')\n );\n }\n\n private _labels() {\n return Array.from(this.list.querySelectorAll<HTMLElement>(':scope > .label'));\n }\n\n private _empty() {\n return this.el.querySelector<HTMLElement>(':scope > .command-palette-empty');\n }\n\n private _action(item: HTMLElement) {\n return item.querySelector<HTMLElement>(':scope > :is(a[href], button)');\n }\n\n private _ensureId(el: HTMLElement, prefix: string) {\n if (!el.id) {\n el.id = `${prefix}-${Utils.guid()}`;\n this._generatedIds.push(el);\n }\n return el.id;\n }\n\n private _setupAccessibility() {\n this.list.setAttribute('role', 'listbox');\n this.input.setAttribute('role', 'combobox');\n this.input.setAttribute('aria-controls', this._ensureId(this.list, 'command-palette-list'));\n this.input.setAttribute('aria-expanded', 'true');\n this.input.setAttribute('aria-autocomplete', 'list');\n }\n\n /** Every command, including ones added since the last pass, is an option. */\n private _wireItems() {\n for (const item of this._items()) {\n if (item.getAttribute('role') === 'option') continue;\n item.setAttribute('role', 'option');\n this._ensureId(item, 'command-palette-option');\n // Focus stays in the input; the commands are reached with the arrows.\n this._action(item)?.setAttribute('tabindex', '-1');\n }\n // A listbox holds only options; a group heading is a visual divider.\n for (const label of this._labels()) label.setAttribute('role', 'none');\n }\n\n /** Commands on screen: neither hidden by the page nor filtered out. */\n private _shown() {\n return this._items().filter((item) => !item.hidden && !item.hasAttribute('data-filtered'));\n }\n\n /** Shown commands the arrows and Enter can reach: disabled ones are skipped. */\n private _visible() {\n return this._shown().filter((item) => item.getAttribute('aria-disabled') !== 'true');\n }\n\n /** A disabled link or button cannot run, so its option says so. */\n private _isDisabled(item: HTMLElement) {\n const action = this._action(item);\n return !!action && (action.matches(':disabled') || action.getAttribute('aria-disabled') === 'true');\n }\n\n private _setActive(item: HTMLElement | null) {\n if (this._active === item) return;\n this._active?.classList.remove('active');\n this._active?.removeAttribute('aria-selected');\n this._active = item;\n if (item) {\n item.classList.add('active');\n item.setAttribute('aria-selected', 'true');\n this.input.setAttribute('aria-activedescendant', item.id);\n item.scrollIntoView({ block: 'nearest' });\n } else {\n this.input.removeAttribute('aria-activedescendant');\n }\n }\n\n /**\n * Shows the commands matching the query. Filtering marks rows with\n * data-filtered rather than hidden, so a command the page hides stays\n * hidden. `keepActive` holds the active command while it is still\n * reachable, for list changes the user did not make.\n */\n private _filter(keepActive = false) {\n this._wireItems();\n const terms = fold(this.input.value).split(/\\s+/).filter(Boolean);\n for (const item of this._items()) {\n // data-keywords may sit on the row or on its link or button.\n const keywords = item.dataset.keywords ?? this._action(item)?.dataset.keywords ?? '';\n const text = fold(`${item.textContent} ${keywords}`);\n item.toggleAttribute('data-filtered', !terms.every((term) => text.includes(term)));\n if (this._isDisabled(item)) item.setAttribute('aria-disabled', 'true');\n else item.removeAttribute('aria-disabled');\n }\n // A heading stays only while one of the commands under it does.\n for (const label of this._labels()) {\n let next = label.nextElementSibling as HTMLElement | null;\n let any = false;\n while (next && !next.classList.contains('label')) {\n if (!next.hidden && !next.hasAttribute('data-filtered')) any = true;\n next = next.nextElementSibling as HTMLElement | null;\n }\n label.toggleAttribute('data-filtered', !any);\n }\n const visible = this._visible();\n const empty = this._empty();\n if (empty) empty.hidden = this._shown().length > 0;\n this._setActive(keepActive && visible.includes(this._active) ? this._active : visible[0] ?? null);\n }\n\n private _move(step: number) {\n const visible = this._visible();\n if (!visible.length) return;\n const index = visible.indexOf(this._active);\n this._setActive(visible[(index + step + visible.length) % visible.length]);\n }\n\n /** Runs a command by clicking its link or button; the click handler closes. */\n private _run(item: HTMLElement) {\n (this._action(item) ?? item).click();\n }\n\n _handleInput = () => this._filter();\n\n _handleKeydown = (e: KeyboardEvent) => {\n if (e.key === Utils.keys.ARROW_DOWN || e.key === Utils.keys.ARROW_UP) {\n e.preventDefault();\n this._move(e.key === Utils.keys.ARROW_DOWN ? 1 : -1);\n } else if (e.key === Utils.keys.ENTER && !e.isComposing && e.keyCode !== 229 && this._active) {\n // keyCode 229 is the Enter that confirms an IME composition in Safari,\n // which reports isComposing false for it.\n e.preventDefault();\n this._run(this._active);\n }\n };\n\n _handleListClick = (e: MouseEvent) => {\n const item = (<Element>e.target).closest<HTMLElement>('[role=\"option\"]');\n if (!item || !this.list.contains(item) || item.getAttribute('aria-disabled') === 'true') return;\n const action = this._action(item);\n // A click on the row's padding runs its command; that click comes back\n // through here and closes the palette.\n if (action && !action.contains(<Node>e.target)) {\n action.click();\n return;\n }\n if (this.options.closeOnRun) this.close();\n };\n\n _handlePointerMove = (e: PointerEvent) => {\n const item = (<Element>e.target).closest<HTMLElement>('[role=\"option\"]');\n if (item && this.list.contains(item) && item.getAttribute('aria-disabled') !== 'true') this._setActive(item);\n };\n\n /**\n * Each opening starts from the full list. The close event is queued, so a\n * palette reopened straight away may already be open again; its new search\n * is left alone.\n */\n _handleClose = () => {\n if (this.el.open) return;\n this.input.value = '';\n this._filter();\n };\n\n _handleShortcut = (e: KeyboardEvent) => {\n const { shortcut } = this.options;\n if (!shortcut || e.defaultPrevented || e.altKey || e.shiftKey) return;\n if (!(APPLE ? e.metaKey && !e.ctrlKey : e.ctrlKey && !e.metaKey)) return;\n // A non-Latin layout reports its own letter in e.key, so fall back to the\n // physical key there. A Latin layout matches on the letter it types.\n const letter = shortcut.toLowerCase();\n const latin = /^[a-z]$/i.test(e.key);\n const hit = e.key.toLowerCase() === letter ||\n (!latin && /^[a-z]$/.test(letter) && e.code === `Key${letter.toUpperCase()}`);\n if (!hit) return;\n e.preventDefault();\n if (this.el.open) this.close();\n else this.open();\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|