@unabridged/midwest 0.19.2 → 0.20.0
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/README.md +1 -1
- package/app/assets/javascript/midwest/index.ts +6 -0
- package/app/assets/javascript/midwest/template_helpers.ts +27 -0
- package/app/assets/javascript/midwest.js +656 -0
- package/app/assets/javascript/midwest.js.map +1 -1
- package/app/assets/stylesheets/midwest.css +1 -1
- package/app/assets/stylesheets/midwest.tailwind.css +5 -1
- package/dist/css/midwest.css +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js +6 -0
- package/dist/javascript/collection/app/assets/javascript/midwest/index.js.map +1 -1
- package/dist/javascript/collection/app/assets/javascript/midwest/template_helpers.js +10 -0
- package/dist/javascript/collection/app/assets/javascript/midwest/template_helpers.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/card_component/card_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/command_palette_component/command_palette_component_controller.js +350 -0
- package/dist/javascript/collection/app/components/midwest/command_palette_component/command_palette_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js +24 -0
- package/dist/javascript/collection/app/components/midwest/form/live_summary_component/live_summary_component_controller.js.map +1 -1
- package/dist/javascript/collection/app/components/midwest/show_if_component/show_if_component_controller.js +80 -0
- package/dist/javascript/collection/app/components/midwest/show_if_component/show_if_component_controller.js.map +1 -0
- package/dist/javascript/collection/app/components/midwest/tree_view_component/tree_view_component_controller.js +204 -0
- package/dist/javascript/collection/app/components/midwest/tree_view_component/tree_view_component_controller.js.map +1 -0
- package/dist/javascript/midwest.js +656 -0
- package/dist/javascript/midwest.js.map +1 -1
- package/package.json +1 -1
|
@@ -25,6 +25,9 @@ import HorizontalScroll from '../../../components/midwest/horizontal_scroll_comp
|
|
|
25
25
|
import Table from '../../../components/midwest/table_component/table_component_controller.js';
|
|
26
26
|
import LoadMore from '../../../components/midwest/table_component/load_more_controller.js';
|
|
27
27
|
import Pagination from '../../../components/midwest/pagination_component/pagination_component_controller.js';
|
|
28
|
+
import ShowIf from '../../../components/midwest/show_if_component/show_if_component_controller.js';
|
|
29
|
+
import TreeView from '../../../components/midwest/tree_view_component/tree_view_component_controller.js';
|
|
30
|
+
import CommandPalette from '../../../components/midwest/command_palette_component/command_palette_component_controller.js';
|
|
28
31
|
|
|
29
32
|
function registerMidwestControllers(application) {
|
|
30
33
|
application.register("midwest-card", Card);
|
|
@@ -54,6 +57,9 @@ function registerMidwestControllers(application) {
|
|
|
54
57
|
application.register("midwest-table", Table);
|
|
55
58
|
application.register("midwest-load-more", LoadMore);
|
|
56
59
|
application.register("midwest-pagination", Pagination);
|
|
60
|
+
application.register("midwest-show-if", ShowIf);
|
|
61
|
+
application.register("midwest-tree-view", TreeView);
|
|
62
|
+
application.register("midwest-command-palette", CommandPalette);
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
export { Banner, Card, Chart, CountdownTimer, registerMidwestControllers };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../../../../app/assets/javascript/midwest/index.ts"],"sourcesContent":["import Card from '../../../components/midwest/card_component/card_component_controller'\nimport Banner from '../../../components/midwest/banner_component/banner_component_controller'\nimport Input from '../../../components/midwest/form/input_component/input_component_controller'\nimport File from '../../../components/midwest/form/file_component/file_component_controller'\nimport Dropdown from '../../../components/midwest/dropdown_component/dropdown_component_controller'\nimport Prose from '../../../components/midwest/prose_component/prose_component_controller'\nimport Dialog from '../../../components/midwest/dialog_component/dialog_component_controller'\nimport Tabs from '../../../components/midwest/tabs_component/tabs_component_controller'\nimport Tooltip from '../../../components/midwest/tooltip_component/tooltip_component_controller'\nimport Carousel from '../../../components/midwest/carousel_component/carousel_component_controller'\nimport FormLiveSummary from '../../../components/midwest/form/live_summary_component/live_summary_component_controller'\nimport Form from '../../../components/midwest/form/form_controller'\nimport CountdownTimer from '../../../components/midwest/countdown_timer_component/countdown_timer_component_controller'\nimport Badge from '../../../components/midwest/badge_component/badge_component_controller'\nimport Confirmation from '../../../components/midwest/confirmation_component/confirmation_component_controller'\nimport AvatarGroup from '../../../components/midwest/avatar_group_component/avatar_group_component_controller'\nimport Chart from '../../../components/midwest/chart_component/chart_component_controller'\nimport Range from '../../../components/midwest/form/range_component/range_component_controller'\nimport Rating from '../../../components/midwest/rating_component/rating_component_controller'\nimport Autocomplete from '../../../components/midwest/form/autocomplete_component/autocomplete_component_controller'\nimport Image from '../../../components/midwest/image_component/image_component_controller'\nimport ColorPicker from '../../../components/midwest/form/color_picker_component/color_picker_component_controller'\nimport Notification from '../../../components/midwest/notification_component/notification_component_controller'\nimport HorizontalScroll from '../../../components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller'\nimport Table from '../../../components/midwest/table_component/table_component_controller'\nimport LoadMore from '../../../components/midwest/table_component/load_more_controller'\nimport Pagination from '../../../components/midwest/pagination_component/pagination_component_controller'\n/* IMPORTS */\n\nexport { Card, Banner, CountdownTimer, Chart }\n\nexport function registerMidwestControllers (application: any) {\n application.register('midwest-card', Card)\n application.register('midwest-banner', Banner)\n application.register('midwest-countdown-timer', CountdownTimer)\n application.register('midwest-input', Input)\n application.register('midwest-file', File)\n application.register('midwest-dropdown', Dropdown)\n application.register('midwest-prose', Prose)\n application.register('midwest-dialog', Dialog)\n application.register('midwest-tabs', Tabs)\n application.register('midwest-tooltip', Tooltip)\n application.register('midwest-carousel', Carousel)\n application.register('midwest-form-live-summary', FormLiveSummary)\n application.register('midwest-form', Form)\n application.register('midwest-badge', Badge)\n application.register('midwest-confirmation', Confirmation)\n application.register('midwest-avatar-group', AvatarGroup)\n application.register('midwest-chart', Chart)\n application.register('midwest-range', Range)\n application.register('midwest-rating', Rating)\n application.register('midwest-autocomplete', Autocomplete)\n application.register('midwest-image', Image)\n application.register('midwest-color-picker', ColorPicker)\n application.register('midwest-notification', Notification)\n application.register('midwest-horizontal-scroll', HorizontalScroll)\n application.register('midwest-table', Table)\n application.register('midwest-load-more', LoadMore)\n application.register('midwest-pagination', Pagination)\n /* EXPORTS */\n}\n"],"names":["Confirmation"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../../app/assets/javascript/midwest/index.ts"],"sourcesContent":["import Card from '../../../components/midwest/card_component/card_component_controller'\nimport Banner from '../../../components/midwest/banner_component/banner_component_controller'\nimport Input from '../../../components/midwest/form/input_component/input_component_controller'\nimport File from '../../../components/midwest/form/file_component/file_component_controller'\nimport Dropdown from '../../../components/midwest/dropdown_component/dropdown_component_controller'\nimport Prose from '../../../components/midwest/prose_component/prose_component_controller'\nimport Dialog from '../../../components/midwest/dialog_component/dialog_component_controller'\nimport Tabs from '../../../components/midwest/tabs_component/tabs_component_controller'\nimport Tooltip from '../../../components/midwest/tooltip_component/tooltip_component_controller'\nimport Carousel from '../../../components/midwest/carousel_component/carousel_component_controller'\nimport FormLiveSummary from '../../../components/midwest/form/live_summary_component/live_summary_component_controller'\nimport Form from '../../../components/midwest/form/form_controller'\nimport CountdownTimer from '../../../components/midwest/countdown_timer_component/countdown_timer_component_controller'\nimport Badge from '../../../components/midwest/badge_component/badge_component_controller'\nimport Confirmation from '../../../components/midwest/confirmation_component/confirmation_component_controller'\nimport AvatarGroup from '../../../components/midwest/avatar_group_component/avatar_group_component_controller'\nimport Chart from '../../../components/midwest/chart_component/chart_component_controller'\nimport Range from '../../../components/midwest/form/range_component/range_component_controller'\nimport Rating from '../../../components/midwest/rating_component/rating_component_controller'\nimport Autocomplete from '../../../components/midwest/form/autocomplete_component/autocomplete_component_controller'\nimport Image from '../../../components/midwest/image_component/image_component_controller'\nimport ColorPicker from '../../../components/midwest/form/color_picker_component/color_picker_component_controller'\nimport Notification from '../../../components/midwest/notification_component/notification_component_controller'\nimport HorizontalScroll from '../../../components/midwest/horizontal_scroll_component/horizontal_scroll_component_controller'\nimport Table from '../../../components/midwest/table_component/table_component_controller'\nimport LoadMore from '../../../components/midwest/table_component/load_more_controller'\nimport Pagination from '../../../components/midwest/pagination_component/pagination_component_controller'\nimport ShowIf from '../../../components/midwest/show_if_component/show_if_component_controller'\nimport TreeView from '../../../components/midwest/tree_view_component/tree_view_component_controller'\nimport CommandPalette from '../../../components/midwest/command_palette_component/command_palette_component_controller'\n/* IMPORTS */\n\nexport { Card, Banner, CountdownTimer, Chart }\n\nexport function registerMidwestControllers (application: any) {\n application.register('midwest-card', Card)\n application.register('midwest-banner', Banner)\n application.register('midwest-countdown-timer', CountdownTimer)\n application.register('midwest-input', Input)\n application.register('midwest-file', File)\n application.register('midwest-dropdown', Dropdown)\n application.register('midwest-prose', Prose)\n application.register('midwest-dialog', Dialog)\n application.register('midwest-tabs', Tabs)\n application.register('midwest-tooltip', Tooltip)\n application.register('midwest-carousel', Carousel)\n application.register('midwest-form-live-summary', FormLiveSummary)\n application.register('midwest-form', Form)\n application.register('midwest-badge', Badge)\n application.register('midwest-confirmation', Confirmation)\n application.register('midwest-avatar-group', AvatarGroup)\n application.register('midwest-chart', Chart)\n application.register('midwest-range', Range)\n application.register('midwest-rating', Rating)\n application.register('midwest-autocomplete', Autocomplete)\n application.register('midwest-image', Image)\n application.register('midwest-color-picker', ColorPicker)\n application.register('midwest-notification', Notification)\n application.register('midwest-horizontal-scroll', HorizontalScroll)\n application.register('midwest-table', Table)\n application.register('midwest-load-more', LoadMore)\n application.register('midwest-pagination', Pagination)\n application.register('midwest-show-if', ShowIf)\n application.register('midwest-tree-view', TreeView)\n application.register('midwest-command-palette', CommandPalette)\n /* EXPORTS */\n}\n"],"names":["Confirmation"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCO,SAAS,2BAA4B,WAAkB,EAAA;AAC5D,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,kBAAkB,MAAM,CAAA,CAAA;AAC7C,EAAY,WAAA,CAAA,QAAA,CAAS,2BAA2B,cAAc,CAAA,CAAA;AAC9D,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,oBAAoB,QAAQ,CAAA,CAAA;AACjD,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,kBAAkB,MAAM,CAAA,CAAA;AAC7C,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,mBAAmB,OAAO,CAAA,CAAA;AAC/C,EAAY,WAAA,CAAA,QAAA,CAAS,oBAAoB,QAAQ,CAAA,CAAA;AACjD,EAAY,WAAA,CAAA,QAAA,CAAS,6BAA6B,eAAe,CAAA,CAAA;AACjE,EAAY,WAAA,CAAA,QAAA,CAAS,gBAAgB,IAAI,CAAA,CAAA;AACzC,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,wBAAwBA,sBAAY,CAAA,CAAA;AACzD,EAAY,WAAA,CAAA,QAAA,CAAS,wBAAwB,WAAW,CAAA,CAAA;AACxD,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,kBAAkB,MAAM,CAAA,CAAA;AAC7C,EAAY,WAAA,CAAA,QAAA,CAAS,wBAAwB,YAAY,CAAA,CAAA;AACzD,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,wBAAwB,WAAW,CAAA,CAAA;AACxD,EAAY,WAAA,CAAA,QAAA,CAAS,wBAAwB,YAAY,CAAA,CAAA;AACzD,EAAY,WAAA,CAAA,QAAA,CAAS,6BAA6B,gBAAgB,CAAA,CAAA;AAClE,EAAY,WAAA,CAAA,QAAA,CAAS,iBAAiB,KAAK,CAAA,CAAA;AAC3C,EAAY,WAAA,CAAA,QAAA,CAAS,qBAAqB,QAAQ,CAAA,CAAA;AAClD,EAAY,WAAA,CAAA,QAAA,CAAS,sBAAsB,UAAU,CAAA,CAAA;AACrD,EAAY,WAAA,CAAA,QAAA,CAAS,mBAAmB,MAAM,CAAA,CAAA;AAC9C,EAAY,WAAA,CAAA,QAAA,CAAS,qBAAqB,QAAQ,CAAA,CAAA;AAClD,EAAY,WAAA,CAAA,QAAA,CAAS,2BAA2B,cAAc,CAAA,CAAA;AAEhE;;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function cloneTemplate(template) {
|
|
2
|
+
const fragment = template.content.cloneNode(true);
|
|
3
|
+
const el = fragment.firstElementChild;
|
|
4
|
+
if (!el)
|
|
5
|
+
throw new Error("Template has no element child");
|
|
6
|
+
return el;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { cloneTemplate };
|
|
10
|
+
//# sourceMappingURL=template_helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template_helpers.js","sources":["../../../../../../../app/assets/javascript/midwest/template_helpers.ts"],"sourcesContent":["/**\n * Clones a <template> element's content and returns the first element child.\n * Throws if the template is missing or has no element child.\n */\nexport function cloneTemplate<T extends HTMLElement = HTMLElement> (\n template: HTMLTemplateElement\n): T {\n const fragment = template.content.cloneNode(true) as DocumentFragment\n const el = fragment.firstElementChild as T | null\n if (!el) throw new Error('Template has no element child')\n return el\n}\n\n/**\n * Fills text content into a cloned template node by selector.\n * Only sets content for selectors that match an element.\n */\nexport function fillTemplate (\n root: HTMLElement,\n data: Record<string, string | undefined>\n): void {\n for (const [selector, value] of Object.entries(data)) {\n if (value == null) continue\n const el = root.querySelector(selector)\n if (el) el.textContent = value\n }\n}\n"],"names":[],"mappings":"AAIO,SAAS,cACd,QACG,EAAA;AACH,EAAA,MAAM,QAAW,GAAA,QAAA,CAAS,OAAQ,CAAA,SAAA,CAAU,IAAI,CAAA,CAAA;AAChD,EAAA,MAAM,KAAK,QAAS,CAAA,iBAAA,CAAA;AACpB,EAAA,IAAI,CAAC,EAAA;AAAI,IAAM,MAAA,IAAI,MAAM,+BAA+B,CAAA,CAAA;AACxD,EAAO,OAAA,EAAA,CAAA;AACT;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"card_component_controller.js","sources":["../../../../../../../app/components/midwest/card_component/card_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Card extends Controller<HTMLFormElement> {\n static targets = ['back', 'front']\n static values = {\n originalHeight: { type: Number, default: 0 },\n backHeight: { type: Number, default: 0 }\n }\n\n declare readonly hasBackTarget: boolean\n declare readonly hasFrontTarget: boolean\n declare readonly backTarget: HTMLInputElement\n declare readonly backTargets: HTMLInputElement[]\n declare readonly frontTarget: HTMLInputElement\n declare readonly frontTargets: HTMLInputElement[]\n\n declare originalHeightValue: number\n declare backHeightValue: number\n declare readonly hasOriginalHeightValue: boolean\n declare readonly hasBackHeightValue: boolean\n\n private resizeHandler: (() => void) | null = null\n\n connect () {\n this.applyReady()\n }\n\n disconnect () {\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler)\n this.resizeHandler = null\n }\n }\n\n get flippable () {\n return this.element.classList.contains('flippable')\n }\n\n async applyReady () {\n if (this.flippable) {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n this.element.classList.add('flip-ready')\n\n this.resizeHandler = () => {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n }\n window.addEventListener('resize', this.resizeHandler)\n }\n }\n\n originalHeightValueChanged () {\n this.element.style.setProperty('--min-height', `${this.originalHeightValue}px`)\n }\n\n backHeightValueChanged () {\n this.element.style.setProperty('--flipped-min-height', `${this.backHeightValue}px`)\n }\n\n flip () {\n this.element.classList.toggle('flipped')\n }\n}\n"],"names":[],"mappings":";;AAGA,MAAqB,aAAa,UAA4B,CAAA;AAAA,EAC5D,OAAO,OAAA,GAAU,CAAC,MAAA,EAAQ,OAAO,CAAA,CAAA;AAAA,EACjC,OAAO,MAAS,GAAA;AAAA,IACd,cAAgB,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,IAC3C,UAAY,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,GACzC,CAAA;AAAA,EAcQ,aAAqC,GAAA,IAAA,CAAA;AAAA,EAE7C,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,UAAW,EAAA,CAAA;AAAA,GAClB;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAI,KAAK,aAAe,EAAA;AACtB,MAAO,MAAA,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AACvD,MAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAA;AAAA,KACvB;AAAA,GACF;AAAA,EAEA,IAAI,SAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,OAAA,CAAQ,SAAU,CAAA,QAAA,CAAS,WAAW,CAAA,CAAA;AAAA,GACpD;AAAA,EAEA,MAAM,UAAc,GAAA;AAClB,IAAA,IAAI,KAAK,SAAW,EAAA;AAClB,MAAK,IAAA,CAAA,mBAAA,GAAsB,KAAK,WAAY,CAAA,YAAA,CAAA;AAC5C,MAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAW,CAAA,YAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"card_component_controller.js","sources":["../../../../../../../app/components/midwest/card_component/card_component_controller.ts"],"sourcesContent":["\nimport { Controller } from '@hotwired/stimulus'\n\nexport default class Card extends Controller<HTMLFormElement> {\n static targets = ['back', 'front']\n static values = {\n originalHeight: { type: Number, default: 0 },\n backHeight: { type: Number, default: 0 }\n }\n\n declare readonly hasBackTarget: boolean\n declare readonly hasFrontTarget: boolean\n declare readonly backTarget: HTMLInputElement\n declare readonly backTargets: HTMLInputElement[]\n declare readonly frontTarget: HTMLInputElement\n declare readonly frontTargets: HTMLInputElement[]\n\n declare originalHeightValue: number\n declare backHeightValue: number\n declare readonly hasOriginalHeightValue: boolean\n declare readonly hasBackHeightValue: boolean\n\n private resizeHandler: (() => void) | null = null\n\n connect () {\n this.applyReady()\n }\n\n disconnect () {\n if (this.resizeHandler) {\n window.removeEventListener('resize', this.resizeHandler)\n this.resizeHandler = null\n }\n }\n\n get flippable () {\n return this.element.classList.contains('flippable')\n }\n\n async applyReady () {\n if (this.flippable) {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n\n this.element.classList.add('flip-ready')\n\n this.resizeHandler = () => {\n this.originalHeightValue = this.frontTarget.offsetHeight\n this.backHeightValue = this.backTarget.offsetHeight\n }\n window.addEventListener('resize', this.resizeHandler)\n }\n }\n\n originalHeightValueChanged () {\n this.element.style.setProperty('--min-height', `${this.originalHeightValue}px`)\n }\n\n backHeightValueChanged () {\n this.element.style.setProperty('--flipped-min-height', `${this.backHeightValue}px`)\n }\n\n flip () {\n this.element.classList.toggle('flipped')\n }\n}\n"],"names":[],"mappings":";;AAGA,MAAqB,aAAa,UAA4B,CAAA;AAAA,EAC5D,OAAO,OAAA,GAAU,CAAC,MAAA,EAAQ,OAAO,CAAA,CAAA;AAAA,EACjC,OAAO,MAAS,GAAA;AAAA,IACd,cAAgB,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,IAC3C,UAAY,EAAA,EAAE,IAAM,EAAA,MAAA,EAAQ,SAAS,CAAE,EAAA;AAAA,GACzC,CAAA;AAAA,EAcQ,aAAqC,GAAA,IAAA,CAAA;AAAA,EAE7C,OAAW,GAAA;AACT,IAAA,IAAA,CAAK,UAAW,EAAA,CAAA;AAAA,GAClB;AAAA,EAEA,UAAc,GAAA;AACZ,IAAA,IAAI,KAAK,aAAe,EAAA;AACtB,MAAO,MAAA,CAAA,mBAAA,CAAoB,QAAU,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AACvD,MAAA,IAAA,CAAK,aAAgB,GAAA,IAAA,CAAA;AAAA,KACvB;AAAA,GACF;AAAA,EAEA,IAAI,SAAa,GAAA;AACf,IAAA,OAAO,IAAK,CAAA,OAAA,CAAQ,SAAU,CAAA,QAAA,CAAS,WAAW,CAAA,CAAA;AAAA,GACpD;AAAA,EAEA,MAAM,UAAc,GAAA;AAClB,IAAA,IAAI,KAAK,SAAW,EAAA;AAClB,MAAK,IAAA,CAAA,mBAAA,GAAsB,KAAK,WAAY,CAAA,YAAA,CAAA;AAC5C,MAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAW,CAAA,YAAA,CAAA;AAEvC,MAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,GAAA,CAAI,YAAY,CAAA,CAAA;AAEvC,MAAA,IAAA,CAAK,gBAAgB,MAAM;AACzB,QAAK,IAAA,CAAA,mBAAA,GAAsB,KAAK,WAAY,CAAA,YAAA,CAAA;AAC5C,QAAK,IAAA,CAAA,eAAA,GAAkB,KAAK,UAAW,CAAA,YAAA,CAAA;AAAA,OACzC,CAAA;AACA,MAAO,MAAA,CAAA,gBAAA,CAAiB,QAAU,EAAA,IAAA,CAAK,aAAa,CAAA,CAAA;AAAA,KACtD;AAAA,GACF;AAAA,EAEA,0BAA8B,GAAA;AAC5B,IAAA,IAAA,CAAK,QAAQ,KAAM,CAAA,WAAA,CAAY,cAAgB,EAAA,CAAA,EAAG,KAAK,mBAAuB,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,GAChF;AAAA,EAEA,sBAA0B,GAAA;AACxB,IAAA,IAAA,CAAK,QAAQ,KAAM,CAAA,WAAA,CAAY,sBAAwB,EAAA,CAAA,EAAG,KAAK,eAAmB,CAAA,EAAA,CAAA,CAAA,CAAA;AAAA,GACpF;AAAA,EAEA,IAAQ,GAAA;AACN,IAAK,IAAA,CAAA,OAAA,CAAQ,SAAU,CAAA,MAAA,CAAO,SAAS,CAAA,CAAA;AAAA,GACzC;AACF;;;;"}
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import { Controller } from '@hotwired/stimulus';
|
|
2
|
+
import { cloneTemplate } from '../../../assets/javascript/midwest/template_helpers.js';
|
|
3
|
+
|
|
4
|
+
class CommandPalette extends Controller {
|
|
5
|
+
static targets = ["input", "list", "empty", "body", "turboList", "itemTemplate", "groupTemplate"];
|
|
6
|
+
static values = {
|
|
7
|
+
hotkey: { type: String, default: "k" },
|
|
8
|
+
items: { type: Array, default: [] },
|
|
9
|
+
src: { type: String, default: "" },
|
|
10
|
+
turboFrameUrl: { type: String, default: "" }
|
|
11
|
+
};
|
|
12
|
+
highlightedIndex = -1;
|
|
13
|
+
fetchAbort = null;
|
|
14
|
+
searchTimer;
|
|
15
|
+
allItems = [];
|
|
16
|
+
connect() {
|
|
17
|
+
this.allItems = this.itemsValue;
|
|
18
|
+
document.addEventListener("keydown", this.handleGlobalKeydown);
|
|
19
|
+
this.element.addEventListener("click", this.handleBackdropClick);
|
|
20
|
+
if (!this.turboFrameUrlValue) {
|
|
21
|
+
this.renderItems(this.allItems);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
disconnect() {
|
|
25
|
+
document.removeEventListener("keydown", this.handleGlobalKeydown);
|
|
26
|
+
this.element.removeEventListener("click", this.handleBackdropClick);
|
|
27
|
+
if (this.fetchAbort)
|
|
28
|
+
this.fetchAbort.abort();
|
|
29
|
+
if (this.searchTimer)
|
|
30
|
+
clearTimeout(this.searchTimer);
|
|
31
|
+
}
|
|
32
|
+
// ── Turbo frame lifecycle ───────────────────────────────────────────
|
|
33
|
+
turboListTargetConnected(el) {
|
|
34
|
+
el.addEventListener("turbo:frame-load", this.onFrameLoad);
|
|
35
|
+
}
|
|
36
|
+
turboListTargetDisconnected(el) {
|
|
37
|
+
el.removeEventListener("turbo:frame-load", this.onFrameLoad);
|
|
38
|
+
}
|
|
39
|
+
onFrameLoad = () => {
|
|
40
|
+
if (!this.hasListTarget)
|
|
41
|
+
return;
|
|
42
|
+
const items = this.listTarget.querySelectorAll(".command-palette-item");
|
|
43
|
+
if (items.length > 0) {
|
|
44
|
+
this.highlightedIndex = 0;
|
|
45
|
+
this.updateHighlight();
|
|
46
|
+
this.emptyTarget.hidden = true;
|
|
47
|
+
if (this.hasListTarget)
|
|
48
|
+
this.listTarget.hidden = false;
|
|
49
|
+
} else {
|
|
50
|
+
this.emptyTarget.hidden = false;
|
|
51
|
+
if (this.hasListTarget)
|
|
52
|
+
this.listTarget.hidden = true;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
// ── Public actions ──────────────────────────────────────────────────
|
|
56
|
+
open() {
|
|
57
|
+
if (this.element.open)
|
|
58
|
+
return;
|
|
59
|
+
this.element.showModal();
|
|
60
|
+
this.inputTarget.value = "";
|
|
61
|
+
this.highlightedIndex = -1;
|
|
62
|
+
if (this.turboFrameUrlValue) {
|
|
63
|
+
this.navigateFrame("");
|
|
64
|
+
} else {
|
|
65
|
+
this.renderItems(this.allItems);
|
|
66
|
+
}
|
|
67
|
+
requestAnimationFrame(() => this.inputTarget.focus());
|
|
68
|
+
}
|
|
69
|
+
close() {
|
|
70
|
+
if (!this.element.open)
|
|
71
|
+
return;
|
|
72
|
+
this.element.close();
|
|
73
|
+
}
|
|
74
|
+
filter() {
|
|
75
|
+
const query = this.inputTarget.value.trim().toLowerCase();
|
|
76
|
+
if (this.turboFrameUrlValue) {
|
|
77
|
+
this.debouncedNavigateFrame(query);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (this.srcValue && query.length > 0) {
|
|
81
|
+
this.fetchRemote(query);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (query.length === 0) {
|
|
85
|
+
this.renderItems(this.allItems);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const filtered = this.allItems.filter((item) => {
|
|
89
|
+
const haystack = `${item.label} ${item.description || ""} ${item.group || ""}`.toLowerCase();
|
|
90
|
+
return haystack.includes(query);
|
|
91
|
+
});
|
|
92
|
+
this.renderItems(filtered);
|
|
93
|
+
}
|
|
94
|
+
navigate(event) {
|
|
95
|
+
const items = this.visibleItems;
|
|
96
|
+
switch (event.key) {
|
|
97
|
+
case "ArrowDown":
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1);
|
|
100
|
+
this.updateHighlight();
|
|
101
|
+
break;
|
|
102
|
+
case "ArrowUp":
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0);
|
|
105
|
+
this.updateHighlight();
|
|
106
|
+
break;
|
|
107
|
+
case "Enter":
|
|
108
|
+
event.preventDefault();
|
|
109
|
+
if (this.highlightedIndex >= 0 && this.highlightedIndex < items.length) {
|
|
110
|
+
this.selectItem(items[this.highlightedIndex]);
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case "Escape":
|
|
114
|
+
event.preventDefault();
|
|
115
|
+
this.close();
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
select(event) {
|
|
120
|
+
const el = event.target.closest(".command-palette-item");
|
|
121
|
+
if (!el)
|
|
122
|
+
return;
|
|
123
|
+
const index = parseInt(el.dataset.index || "-1", 10);
|
|
124
|
+
const items = this.visibleItems;
|
|
125
|
+
if (index >= 0 && index < items.length) {
|
|
126
|
+
this.selectItem(items[index]);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// ── Remote search ───────────────────────────────────────────────────
|
|
130
|
+
fetchRemote(query) {
|
|
131
|
+
if (this.fetchAbort)
|
|
132
|
+
this.fetchAbort.abort();
|
|
133
|
+
if (this.searchTimer)
|
|
134
|
+
clearTimeout(this.searchTimer);
|
|
135
|
+
this.searchTimer = window.setTimeout(async () => {
|
|
136
|
+
this.fetchAbort = new AbortController();
|
|
137
|
+
try {
|
|
138
|
+
const url = new URL(this.srcValue, window.location.origin);
|
|
139
|
+
url.searchParams.set("q", query);
|
|
140
|
+
const response = await fetch(url.toString(), {
|
|
141
|
+
headers: { Accept: "application/json" },
|
|
142
|
+
signal: this.fetchAbort.signal
|
|
143
|
+
});
|
|
144
|
+
if (response.ok) {
|
|
145
|
+
const data = await response.json();
|
|
146
|
+
this.renderItems(data);
|
|
147
|
+
}
|
|
148
|
+
} catch (e) {
|
|
149
|
+
if (e.name !== "AbortError")
|
|
150
|
+
throw e;
|
|
151
|
+
}
|
|
152
|
+
}, 200);
|
|
153
|
+
}
|
|
154
|
+
// ── Turbo frame navigation ──────────────────────────────────────────
|
|
155
|
+
navigateFrame(query) {
|
|
156
|
+
if (!this.hasTurboListTarget)
|
|
157
|
+
return;
|
|
158
|
+
const url = new URL(this.turboFrameUrlValue, window.location.href);
|
|
159
|
+
if (query)
|
|
160
|
+
url.searchParams.set("q", query);
|
|
161
|
+
this.turboListTarget.setAttribute("src", url.toString());
|
|
162
|
+
}
|
|
163
|
+
debouncedNavigateFrame(query) {
|
|
164
|
+
if (this.searchTimer)
|
|
165
|
+
clearTimeout(this.searchTimer);
|
|
166
|
+
this.searchTimer = window.setTimeout(() => {
|
|
167
|
+
this.navigateFrame(query);
|
|
168
|
+
}, 200);
|
|
169
|
+
}
|
|
170
|
+
// ── Rendering ───────────────────────────────────────────────────────
|
|
171
|
+
renderItems(items) {
|
|
172
|
+
if (!this.hasListTarget)
|
|
173
|
+
return;
|
|
174
|
+
this.listTarget.innerHTML = "";
|
|
175
|
+
this.highlightedIndex = -1;
|
|
176
|
+
if (items.length === 0) {
|
|
177
|
+
this.emptyTarget.hidden = false;
|
|
178
|
+
this.listTarget.hidden = true;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
this.emptyTarget.hidden = true;
|
|
182
|
+
this.listTarget.hidden = false;
|
|
183
|
+
const groups = /* @__PURE__ */ new Map();
|
|
184
|
+
for (const item of items) {
|
|
185
|
+
const group = item.group || "";
|
|
186
|
+
if (!groups.has(group))
|
|
187
|
+
groups.set(group, []);
|
|
188
|
+
groups.get(group).push(item);
|
|
189
|
+
}
|
|
190
|
+
let index = 0;
|
|
191
|
+
for (const [groupName, groupItems] of groups) {
|
|
192
|
+
if (groupName) {
|
|
193
|
+
this.listTarget.appendChild(this.buildGroup(groupName));
|
|
194
|
+
}
|
|
195
|
+
for (const item of groupItems) {
|
|
196
|
+
this.listTarget.appendChild(this.buildItem(item, index));
|
|
197
|
+
index++;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (items.length > 0) {
|
|
201
|
+
this.highlightedIndex = 0;
|
|
202
|
+
this.updateHighlight();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
buildGroup(name) {
|
|
206
|
+
const li = cloneTemplate(this.groupTemplateTarget);
|
|
207
|
+
const h6 = li.querySelector(".midwest-label");
|
|
208
|
+
if (h6)
|
|
209
|
+
h6.textContent = name;
|
|
210
|
+
return li;
|
|
211
|
+
}
|
|
212
|
+
buildItem(item, index) {
|
|
213
|
+
const li = cloneTemplate(this.itemTemplateTarget);
|
|
214
|
+
li.dataset.index = String(index);
|
|
215
|
+
if (item.url)
|
|
216
|
+
li.dataset.url = item.url;
|
|
217
|
+
if (item.action)
|
|
218
|
+
li.dataset.paletteAction = item.action;
|
|
219
|
+
if (item.method)
|
|
220
|
+
li.dataset.turboMethod = item.method;
|
|
221
|
+
if (item.confirm)
|
|
222
|
+
li.dataset.turboConfirm = item.confirm;
|
|
223
|
+
const iconSpan = li.querySelector(".command-palette-item-icon");
|
|
224
|
+
if (item.icon) {
|
|
225
|
+
iconSpan.innerHTML = this.getIconSvg(item.icon);
|
|
226
|
+
iconSpan.hidden = false;
|
|
227
|
+
} else {
|
|
228
|
+
iconSpan.remove();
|
|
229
|
+
}
|
|
230
|
+
const label = li.querySelector(".command-palette-item-label");
|
|
231
|
+
label.textContent = item.label;
|
|
232
|
+
const desc = li.querySelector(".command-palette-item-description");
|
|
233
|
+
if (item.description) {
|
|
234
|
+
desc.textContent = item.description;
|
|
235
|
+
desc.hidden = false;
|
|
236
|
+
} else {
|
|
237
|
+
desc.remove();
|
|
238
|
+
}
|
|
239
|
+
const shortcutSpan = li.querySelector(".command-palette-item-shortcut");
|
|
240
|
+
if (item.shortcut) {
|
|
241
|
+
item.shortcut.split("+").forEach((key) => {
|
|
242
|
+
const kbd = document.createElement("kbd");
|
|
243
|
+
kbd.className = "midwest-kbd";
|
|
244
|
+
kbd.textContent = key.trim();
|
|
245
|
+
shortcutSpan.appendChild(kbd);
|
|
246
|
+
});
|
|
247
|
+
shortcutSpan.hidden = false;
|
|
248
|
+
} else {
|
|
249
|
+
shortcutSpan.remove();
|
|
250
|
+
}
|
|
251
|
+
return li;
|
|
252
|
+
}
|
|
253
|
+
// ── Selection ───────────────────────────────────────────────────────
|
|
254
|
+
selectItem(item) {
|
|
255
|
+
if (item.confirm && !window.confirm(item.confirm))
|
|
256
|
+
return;
|
|
257
|
+
this.close();
|
|
258
|
+
if (item.url) {
|
|
259
|
+
this.visit(item.url, item.method);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (item.action) {
|
|
263
|
+
this.element.dispatchEvent(
|
|
264
|
+
new CustomEvent("midwest-command-palette:action", {
|
|
265
|
+
bubbles: true,
|
|
266
|
+
detail: { action: item.action, item }
|
|
267
|
+
})
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
visit(url, method) {
|
|
272
|
+
if (method && method.toLowerCase() !== "get") {
|
|
273
|
+
const link = document.createElement("a");
|
|
274
|
+
link.href = url;
|
|
275
|
+
link.dataset.turboMethod = method;
|
|
276
|
+
link.style.display = "none";
|
|
277
|
+
document.body.appendChild(link);
|
|
278
|
+
link.click();
|
|
279
|
+
link.remove();
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
const turbo = window.Turbo;
|
|
283
|
+
if (turbo?.visit) {
|
|
284
|
+
turbo.visit(url);
|
|
285
|
+
} else {
|
|
286
|
+
window.location.href = url;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
// ── Highlight ───────────────────────────────────────────────────────
|
|
290
|
+
get visibleItems() {
|
|
291
|
+
if (!this.hasListTarget)
|
|
292
|
+
return [];
|
|
293
|
+
const items = [];
|
|
294
|
+
const els = this.listTarget.querySelectorAll(".command-palette-item");
|
|
295
|
+
for (const el of els) {
|
|
296
|
+
items.push({
|
|
297
|
+
label: el.querySelector(".command-palette-item-label")?.textContent || "",
|
|
298
|
+
url: el.dataset.url,
|
|
299
|
+
action: el.dataset.paletteAction,
|
|
300
|
+
method: el.dataset.turboMethod,
|
|
301
|
+
confirm: el.dataset.turboConfirm
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return items;
|
|
305
|
+
}
|
|
306
|
+
updateHighlight() {
|
|
307
|
+
if (!this.hasListTarget)
|
|
308
|
+
return;
|
|
309
|
+
const items = this.listTarget.querySelectorAll(".command-palette-item");
|
|
310
|
+
items.forEach((el, i) => {
|
|
311
|
+
el.setAttribute("aria-selected", String(i === this.highlightedIndex));
|
|
312
|
+
});
|
|
313
|
+
const highlighted = items[this.highlightedIndex];
|
|
314
|
+
if (highlighted) {
|
|
315
|
+
highlighted.scrollIntoView({ block: "nearest" });
|
|
316
|
+
this.inputTarget.setAttribute("aria-activedescendant", highlighted.id || "");
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// ── Hotkey ──────────────────────────────────────────────────────────
|
|
320
|
+
handleGlobalKeydown = (event) => {
|
|
321
|
+
if ((event.metaKey || event.ctrlKey) && event.key === this.hotkeyValue) {
|
|
322
|
+
event.preventDefault();
|
|
323
|
+
if (this.element.open) {
|
|
324
|
+
this.close();
|
|
325
|
+
} else {
|
|
326
|
+
this.open();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
handleBackdropClick = (event) => {
|
|
331
|
+
if (event.target === this.element)
|
|
332
|
+
this.close();
|
|
333
|
+
};
|
|
334
|
+
// ── Helpers ─────────────────────────────────────────────────────────
|
|
335
|
+
getIconSvg(name) {
|
|
336
|
+
const existing = document.querySelector(`.Midwest-Icon__Svg[aria-label="${name}"]`);
|
|
337
|
+
if (existing)
|
|
338
|
+
return existing.outerHTML;
|
|
339
|
+
const allIcons = document.querySelectorAll(".Midwest-Icon__Svg");
|
|
340
|
+
for (const icon of allIcons) {
|
|
341
|
+
if (icon.getAttribute("aria-label")?.toLowerCase() === name.toLowerCase()) {
|
|
342
|
+
return icon.outerHTML;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return "";
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export { CommandPalette as default };
|
|
350
|
+
//# sourceMappingURL=command_palette_component_controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command_palette_component_controller.js","sources":["../../../../../../../app/components/midwest/command_palette_component/command_palette_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\nimport { cloneTemplate } from '../../../assets/javascript/midwest/template_helpers'\n\ninterface PaletteItem {\n label: string\n description?: string\n icon?: string\n url?: string\n action?: string\n group?: string\n shortcut?: string\n method?: string\n confirm?: string\n}\n\nexport default class CommandPalette extends Controller<HTMLDialogElement> {\n static targets = ['input', 'list', 'empty', 'body', 'turboList', 'itemTemplate', 'groupTemplate']\n\n static values = {\n hotkey: { type: String, default: 'k' },\n items: { type: Array, default: [] },\n src: { type: String, default: '' },\n turboFrameUrl: { type: String, default: '' }\n }\n\n declare readonly inputTarget: HTMLInputElement\n declare readonly listTarget: HTMLElement\n declare readonly emptyTarget: HTMLElement\n declare readonly bodyTarget: HTMLElement\n declare readonly turboListTarget: HTMLElement\n declare readonly hasTurboListTarget: boolean\n declare readonly hasListTarget: boolean\n declare readonly itemTemplateTarget: HTMLTemplateElement\n declare readonly groupTemplateTarget: HTMLTemplateElement\n\n declare hotkeyValue: string\n declare itemsValue: PaletteItem[]\n declare srcValue: string\n declare turboFrameUrlValue: string\n\n private highlightedIndex = -1\n private fetchAbort: AbortController | null = null\n private searchTimer: number | undefined\n private allItems: PaletteItem[] = []\n\n connect () {\n this.allItems = this.itemsValue\n document.addEventListener('keydown', this.handleGlobalKeydown)\n this.element.addEventListener('click', this.handleBackdropClick)\n\n // Only render client-side items when not in turbo-frame mode\n if (!this.turboFrameUrlValue) {\n this.renderItems(this.allItems)\n }\n }\n\n disconnect () {\n document.removeEventListener('keydown', this.handleGlobalKeydown)\n this.element.removeEventListener('click', this.handleBackdropClick)\n if (this.fetchAbort) this.fetchAbort.abort()\n if (this.searchTimer) clearTimeout(this.searchTimer)\n }\n\n // ── Turbo frame lifecycle ───────────────────────────────────────────\n\n turboListTargetConnected (el: HTMLElement) {\n el.addEventListener('turbo:frame-load', this.onFrameLoad)\n }\n\n turboListTargetDisconnected (el: HTMLElement) {\n el.removeEventListener('turbo:frame-load', this.onFrameLoad)\n }\n\n private onFrameLoad = () => {\n if (!this.hasListTarget) return\n\n const items = this.listTarget.querySelectorAll<HTMLElement>('.command-palette-item')\n if (items.length > 0) {\n this.highlightedIndex = 0\n this.updateHighlight()\n this.emptyTarget.hidden = true\n if (this.hasListTarget) this.listTarget.hidden = false\n } else {\n this.emptyTarget.hidden = false\n if (this.hasListTarget) this.listTarget.hidden = true\n }\n }\n\n // ── Public actions ──────────────────────────────────────────────────\n\n open () {\n if (this.element.open) return\n this.element.showModal()\n this.inputTarget.value = ''\n this.highlightedIndex = -1\n\n if (this.turboFrameUrlValue) {\n this.navigateFrame('')\n } else {\n this.renderItems(this.allItems)\n }\n\n requestAnimationFrame(() => this.inputTarget.focus())\n }\n\n close () {\n if (!this.element.open) return\n this.element.close()\n }\n\n filter () {\n const query = this.inputTarget.value.trim().toLowerCase()\n\n if (this.turboFrameUrlValue) {\n this.debouncedNavigateFrame(query)\n return\n }\n\n if (this.srcValue && query.length > 0) {\n this.fetchRemote(query)\n return\n }\n\n if (query.length === 0) {\n this.renderItems(this.allItems)\n return\n }\n\n const filtered = this.allItems.filter(item => {\n const haystack = `${item.label} ${item.description || ''} ${item.group || ''}`.toLowerCase()\n return haystack.includes(query)\n })\n\n this.renderItems(filtered)\n }\n\n navigate (event: KeyboardEvent) {\n const items = this.visibleItems\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault()\n this.highlightedIndex = Math.min(this.highlightedIndex + 1, items.length - 1)\n this.updateHighlight()\n break\n case 'ArrowUp':\n event.preventDefault()\n this.highlightedIndex = Math.max(this.highlightedIndex - 1, 0)\n this.updateHighlight()\n break\n case 'Enter':\n event.preventDefault()\n if (this.highlightedIndex >= 0 && this.highlightedIndex < items.length) {\n this.selectItem(items[this.highlightedIndex])\n }\n break\n case 'Escape':\n event.preventDefault()\n this.close()\n break\n }\n }\n\n select (event: Event) {\n const el = (event.target as HTMLElement).closest<HTMLElement>('.command-palette-item')\n if (!el) return\n const index = parseInt(el.dataset.index || '-1', 10)\n const items = this.visibleItems\n if (index >= 0 && index < items.length) {\n this.selectItem(items[index])\n }\n }\n\n // ── Remote search ───────────────────────────────────────────────────\n\n private fetchRemote (query: string) {\n if (this.fetchAbort) this.fetchAbort.abort()\n if (this.searchTimer) clearTimeout(this.searchTimer)\n\n this.searchTimer = window.setTimeout(async () => {\n this.fetchAbort = new AbortController()\n try {\n const url = new URL(this.srcValue, window.location.origin)\n url.searchParams.set('q', query)\n const response = await fetch(url.toString(), {\n headers: { Accept: 'application/json' },\n signal: this.fetchAbort.signal\n })\n if (response.ok) {\n const data: PaletteItem[] = await response.json()\n this.renderItems(data)\n }\n } catch (e) {\n if ((e as Error).name !== 'AbortError') throw e\n }\n }, 200)\n }\n\n // ── Turbo frame navigation ──────────────────────────────────────────\n\n private navigateFrame (query: string) {\n if (!this.hasTurboListTarget) return\n const url = new URL(this.turboFrameUrlValue, window.location.href)\n if (query) url.searchParams.set('q', query)\n this.turboListTarget.setAttribute('src', url.toString())\n }\n\n private debouncedNavigateFrame (query: string) {\n if (this.searchTimer) clearTimeout(this.searchTimer)\n\n this.searchTimer = window.setTimeout(() => {\n this.navigateFrame(query)\n }, 200)\n }\n\n // ── Rendering ───────────────────────────────────────────────────────\n\n private renderItems (items: PaletteItem[]) {\n if (!this.hasListTarget) return\n\n this.listTarget.innerHTML = ''\n this.highlightedIndex = -1\n\n if (items.length === 0) {\n this.emptyTarget.hidden = false\n this.listTarget.hidden = true\n return\n }\n\n this.emptyTarget.hidden = true\n this.listTarget.hidden = false\n\n // Group items\n const groups = new Map<string, PaletteItem[]>()\n for (const item of items) {\n const group = item.group || ''\n if (!groups.has(group)) groups.set(group, [])\n groups.get(group)!.push(item) // eslint-disable-line @typescript-eslint/no-non-null-assertion\n }\n\n let index = 0\n for (const [groupName, groupItems] of groups) {\n if (groupName) {\n this.listTarget.appendChild(this.buildGroup(groupName))\n }\n\n for (const item of groupItems) {\n this.listTarget.appendChild(this.buildItem(item, index))\n index++\n }\n }\n\n // Highlight first item\n if (items.length > 0) {\n this.highlightedIndex = 0\n this.updateHighlight()\n }\n }\n\n private buildGroup (name: string): HTMLElement {\n const li = cloneTemplate(this.groupTemplateTarget)\n const h6 = li.querySelector('.midwest-label')\n if (h6) h6.textContent = name\n return li\n }\n\n private buildItem (item: PaletteItem, index: number): HTMLElement {\n const li = cloneTemplate(this.itemTemplateTarget)\n li.dataset.index = String(index)\n\n if (item.url) li.dataset.url = item.url\n if (item.action) li.dataset.paletteAction = item.action\n if (item.method) li.dataset.turboMethod = item.method\n if (item.confirm) li.dataset.turboConfirm = item.confirm\n\n // Icon\n const iconSpan = li.querySelector('.command-palette-item-icon') as HTMLElement\n if (item.icon) {\n iconSpan.innerHTML = this.getIconSvg(item.icon)\n iconSpan.hidden = false\n } else {\n iconSpan.remove()\n }\n\n // Label\n const label = li.querySelector('.command-palette-item-label') as Element\n label.textContent = item.label\n\n // Description\n const desc = li.querySelector('.command-palette-item-description') as HTMLElement\n if (item.description) {\n desc.textContent = item.description\n desc.hidden = false\n } else {\n desc.remove()\n }\n\n // Shortcut\n const shortcutSpan = li.querySelector('.command-palette-item-shortcut') as HTMLElement\n if (item.shortcut) {\n item.shortcut.split('+').forEach(key => {\n const kbd = document.createElement('kbd')\n kbd.className = 'midwest-kbd'\n kbd.textContent = key.trim()\n shortcutSpan.appendChild(kbd)\n })\n shortcutSpan.hidden = false\n } else {\n shortcutSpan.remove()\n }\n\n return li\n }\n\n // ── Selection ───────────────────────────────────────────────────────\n\n private selectItem (item: PaletteItem) {\n if (item.confirm && !window.confirm(item.confirm)) return\n\n this.close()\n\n if (item.url) {\n this.visit(item.url, item.method)\n return\n }\n\n if (item.action) {\n this.element.dispatchEvent(\n new CustomEvent('midwest-command-palette:action', {\n bubbles: true,\n detail: { action: item.action, item }\n })\n )\n }\n }\n\n private visit (url: string, method?: string) {\n if (method && method.toLowerCase() !== 'get') {\n // Non-GET methods: create a temporary link with data-turbo-method\n // and let Turbo handle the request\n const link = document.createElement('a')\n link.href = url\n link.dataset.turboMethod = method\n link.style.display = 'none'\n document.body.appendChild(link)\n link.click()\n link.remove()\n return\n }\n\n const turbo = (window as any).Turbo\n if (turbo?.visit) {\n turbo.visit(url)\n } else {\n window.location.href = url\n }\n }\n\n // ── Highlight ───────────────────────────────────────────────────────\n\n private get visibleItems (): PaletteItem[] {\n if (!this.hasListTarget) return []\n\n const items: PaletteItem[] = []\n const els = this.listTarget.querySelectorAll<HTMLElement>('.command-palette-item')\n for (const el of els) {\n items.push({\n label: el.querySelector('.command-palette-item-label')?.textContent || '',\n url: el.dataset.url,\n action: el.dataset.paletteAction,\n method: el.dataset.turboMethod,\n confirm: el.dataset.turboConfirm\n })\n }\n return items\n }\n\n private updateHighlight () {\n if (!this.hasListTarget) return\n\n const items = this.listTarget.querySelectorAll<HTMLElement>('.command-palette-item')\n items.forEach((el, i) => {\n el.setAttribute('aria-selected', String(i === this.highlightedIndex))\n })\n\n const highlighted = items[this.highlightedIndex]\n if (highlighted) {\n highlighted.scrollIntoView({ block: 'nearest' })\n this.inputTarget.setAttribute('aria-activedescendant', highlighted.id || '')\n }\n }\n\n // ── Hotkey ──────────────────────────────────────────────────────────\n\n private handleGlobalKeydown = (event: KeyboardEvent) => {\n if ((event.metaKey || event.ctrlKey) && event.key === this.hotkeyValue) {\n event.preventDefault()\n if (this.element.open) {\n this.close()\n } else {\n this.open()\n }\n }\n }\n\n private handleBackdropClick = (event: Event) => {\n if (event.target === this.element) this.close()\n }\n\n // ── Helpers ─────────────────────────────────────────────────────────\n\n private getIconSvg (name: string): string {\n const existing = document.querySelector(`.Midwest-Icon__Svg[aria-label=\"${name}\"]`)\n if (existing) return existing.outerHTML\n\n const allIcons = document.querySelectorAll('.Midwest-Icon__Svg')\n for (const icon of allIcons) {\n if (icon.getAttribute('aria-label')?.toLowerCase() === name.toLowerCase()) {\n return icon.outerHTML\n }\n }\n\n return ''\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -66,8 +66,12 @@ class FormLiveSummary extends Controller {
|
|
|
66
66
|
return;
|
|
67
67
|
if (this.element.contains(element))
|
|
68
68
|
return;
|
|
69
|
+
if (element.closest("fieldset.midwest-show-if[hidden]"))
|
|
70
|
+
return;
|
|
69
71
|
if (element instanceof HTMLButtonElement)
|
|
70
72
|
return;
|
|
73
|
+
if (element.closest(".midwest-tree-view"))
|
|
74
|
+
return;
|
|
71
75
|
if (element instanceof HTMLInputElement) {
|
|
72
76
|
if (SKIPPED_INPUT_TYPES.has(element.type))
|
|
73
77
|
return;
|
|
@@ -128,6 +132,26 @@ class FormLiveSummary extends Controller {
|
|
|
128
132
|
const selected = Array.from(ac.querySelectorAll(".midwest-autocomplete-tokens .value")).map((el) => el.textContent?.trim()).filter(Boolean).join(", ");
|
|
129
133
|
fields.push({ label, value: selected || "\u2014" });
|
|
130
134
|
});
|
|
135
|
+
const seenTreeNames = /* @__PURE__ */ new Set();
|
|
136
|
+
form.querySelectorAll(".midwest-tree-view").forEach((tree) => {
|
|
137
|
+
if (this.element.contains(tree))
|
|
138
|
+
return;
|
|
139
|
+
const checked = Array.from(
|
|
140
|
+
tree.querySelectorAll(".tree-node-checkbox:checked")
|
|
141
|
+
);
|
|
142
|
+
const firstName = checked[0]?.name || tree.querySelectorAll(".tree-node-checkbox")[0]?.name;
|
|
143
|
+
if (!firstName)
|
|
144
|
+
return;
|
|
145
|
+
if (seenTreeNames.has(firstName))
|
|
146
|
+
return;
|
|
147
|
+
seenTreeNames.add(firstName);
|
|
148
|
+
const label = this.prettifyName(firstName.replace(/\[\]$/, ""));
|
|
149
|
+
const values = checked.map((cb) => {
|
|
150
|
+
const nodeLabel = cb.closest(".midwest-tree-node")?.querySelector(":scope > .tree-node-trigger > .tree-node-label");
|
|
151
|
+
return nodeLabel?.textContent?.trim() || cb.value;
|
|
152
|
+
});
|
|
153
|
+
fields.push({ label, value: values.join(", ") || "\u2014" });
|
|
154
|
+
});
|
|
131
155
|
return fields;
|
|
132
156
|
}
|
|
133
157
|
// Builds a small inline colour swatch to display alongside a colour value.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live_summary_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/live_summary_component/live_summary_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types that should never appear in a form live summary.\nconst SKIPPED_INPUT_TYPES = new Set([\n 'hidden', 'submit', 'reset', 'button', 'image'\n])\n\ninterface FieldSummary {\n label: string\n value: string\n /** When set, a colour swatch is prepended to the value cell. */\n swatchColor?: string\n}\n\nexport default class FormLiveSummary extends Controller<HTMLElement> {\n static targets = ['list']\n\n declare readonly listTarget: HTMLElement\n\n connect () {\n this.render()\n this.form?.addEventListener('input', this.render)\n this.form?.addEventListener('change', this.render)\n this.form?.addEventListener('midwest-autocomplete:change', this.render)\n this.form?.addEventListener('midwest-color-picker:update', this.render)\n }\n\n disconnect () {\n this.form?.removeEventListener('input', this.render)\n this.form?.removeEventListener('change', this.render)\n this.form?.removeEventListener('midwest-autocomplete:change', this.render)\n this.form?.removeEventListener('midwest-color-picker:update', this.render)\n }\n\n private get form (): HTMLFormElement | null {\n return this.element.closest('form')\n }\n\n private render = () => {\n const fields = this.collectFields()\n\n if (fields.length === 0) {\n this.listTarget.replaceChildren(\n Object.assign(document.createElement('p'), {\n className: 'midwest-form-live-summary-empty',\n textContent: 'No values to display.'\n })\n )\n return\n }\n\n const dl = document.createElement('dl')\n dl.className = 'midwest-form-live-summary-list'\n\n fields.forEach(({ label, value, swatchColor }) => {\n const dt = Object.assign(document.createElement('dt'), {\n className: 'midwest-form-live-summary-term',\n textContent: label\n })\n const dd = document.createElement('dd')\n dd.className = 'midwest-form-live-summary-definition'\n\n if (swatchColor !== undefined) {\n dd.append(this.buildSwatch(swatchColor), value || '—')\n } else {\n dd.textContent = value || '—'\n }\n\n dl.append(dt, dd)\n })\n\n this.listTarget.replaceChildren(dl)\n }\n\n private collectFields (): FieldSummary[] {\n const form = this.form\n if (!form) return []\n\n const fields: FieldSummary[] = []\n const seenRadioNames = new Set<string>()\n\n Array.from(form.elements).forEach(el => {\n const element = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n\n if (!element.name) return\n\n // Skip elements that live inside the summary itself.\n if (this.element.contains(element)) return\n\n // Skip all button elements regardless of how they are declared.\n if (element instanceof HTMLButtonElement) return\n\n if (element instanceof HTMLInputElement) {\n if (SKIPPED_INPUT_TYPES.has(element.type)) return\n\n if (element.type === 'radio') {\n if (seenRadioNames.has(element.name)) return\n seenRadioNames.add(element.name)\n\n const checked = form.querySelector<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${CSS.escape(element.name)}\"]:checked`\n )\n if (!checked) return\n\n fields.push({\n label: this.groupLabelFor(element),\n value: this.labelFor(checked) || checked.value\n })\n return\n }\n\n if (element.type === 'checkbox') {\n fields.push({\n label: this.labelFor(element),\n value: element.checked ? 'Yes' : 'No'\n })\n return\n }\n }\n\n if (element instanceof HTMLSelectElement) {\n fields.push({\n label: this.labelFor(element),\n value: Array.from(element.selectedOptions).map(o => o.text).join(', ') || '—'\n })\n return\n }\n\n // Text-like inputs and textareas only reach this point.\n fields.push({\n label: this.labelFor(element),\n value: element.value\n })\n })\n\n // Color picker components store their value in a hidden input tagged with\n // data-midwest-color-picker-target=\"input\". The standard loop skips hidden\n // inputs, so query them separately and render with an inline colour swatch.\n form.querySelectorAll<HTMLInputElement>('[data-midwest-color-picker-target=\"input\"]').forEach(input => {\n if (this.element.contains(input)) return\n if (!input.name) return\n\n // Prefer the label inside the picker's own form-group header; fall back\n // to a label[for] match or a prettified version of the input name.\n const picker = input.closest<HTMLElement>('.midwest-color-picker')\n const labelEl = picker?.querySelector<HTMLElement>('.midwest-form-group__top label') ??\n this.form?.querySelector<HTMLElement>(`label[for=\"${CSS.escape(input.id)}\"]`)\n const label = labelEl?.textContent?.trim() ||\n this.prettifyName(input.name.replace(/\\[.*\\]$/, ''))\n\n const value = input.value\n const display = value.startsWith('#') ? value : (value ? value.charAt(0).toUpperCase() + value.slice(1) : '—')\n\n fields.push({ label, value: display, swatchColor: value || undefined })\n })\n\n // Autocomplete components use a nameless combobox input + hidden inputs —\n // neither surfaces through the standard form.elements loop. Query them\n // separately so their selected badge labels appear in the summary.\n // Note: labelFor(input) doesn't work here because InputComponent assigns\n // its own id to the <input>, which won't match the <label>'s for attribute.\n form.querySelectorAll<HTMLElement>('.midwest-autocomplete').forEach(ac => {\n if (this.element.contains(ac)) return\n if (!ac.querySelector('[role=\"combobox\"]')) return\n\n const labelEl = ac.querySelector<HTMLElement>('label')\n const label = labelEl?.textContent?.trim() ||\n this.prettifyName((ac.dataset.name ?? '').replace(/\\[.*\\]$/, ''))\n\n const selected = Array.from(ac.querySelectorAll<HTMLElement>('.midwest-autocomplete-tokens .value'))\n .map(el => el.textContent?.trim())\n .filter(Boolean)\n .join(', ')\n fields.push({ label, value: selected || '—' })\n })\n\n return fields\n }\n\n // Builds a small inline colour swatch to display alongside a colour value.\n // Hex values are applied as an inline background-color; named theme colours\n // use a scoped theme-{color} class so the CSS variable cascade does the work.\n // An empty/transparent value renders a diagonal-stripe placeholder.\n private buildSwatch (color: string): HTMLElement {\n const swatch = document.createElement('span')\n swatch.className = 'midwest-form-live-summary-swatch'\n\n if (color.startsWith('#')) {\n swatch.style.backgroundColor = color\n } else if (color && color !== 'transparent') {\n swatch.classList.add(`theme-${color}`, 'bg-theme-6')\n } else {\n swatch.classList.add('is-transparent')\n }\n\n return swatch\n }\n\n // Finds the label associated with a specific element via `for` attribute,\n // wrapping label, or falls back to a prettified version of the element name.\n private labelFor (el: Element): string {\n const id = (el as HTMLElement).id\n if (id) {\n const label = this.form?.querySelector(`label[for=\"${CSS.escape(id)}\"]`)\n if (label) return label.textContent?.trim() ?? ''\n }\n const wrapper = el.closest('label')\n if (wrapper) return wrapper.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // For radio groups, prefer the containing fieldset legend over the\n // individual radio's label, then fall back to prettifying the name.\n private groupLabelFor (el: Element): string {\n const legend = el.closest('fieldset')?.querySelector('legend')\n if (legend) return legend.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // Converts \"user[first_name]\" or \"first_name\" into \"First name\".\n private prettifyName (name: string): string {\n return name\n .replace(/\\[.*?\\]/g, '')\n .replace(/_/g, ' ')\n .replace(/^\\w/, c => c.toUpperCase())\n .trim()\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"live_summary_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/live_summary_component/live_summary_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\n// Input types that should never appear in a form live summary.\nconst SKIPPED_INPUT_TYPES = new Set([\n 'hidden', 'submit', 'reset', 'button', 'image'\n])\n\ninterface FieldSummary {\n label: string\n value: string\n /** When set, a colour swatch is prepended to the value cell. */\n swatchColor?: string\n}\n\nexport default class FormLiveSummary extends Controller<HTMLElement> {\n static targets = ['list']\n\n declare readonly listTarget: HTMLElement\n\n connect () {\n this.render()\n this.form?.addEventListener('input', this.render)\n this.form?.addEventListener('change', this.render)\n this.form?.addEventListener('midwest-autocomplete:change', this.render)\n this.form?.addEventListener('midwest-color-picker:update', this.render)\n }\n\n disconnect () {\n this.form?.removeEventListener('input', this.render)\n this.form?.removeEventListener('change', this.render)\n this.form?.removeEventListener('midwest-autocomplete:change', this.render)\n this.form?.removeEventListener('midwest-color-picker:update', this.render)\n }\n\n private get form (): HTMLFormElement | null {\n return this.element.closest('form')\n }\n\n private render = () => {\n const fields = this.collectFields()\n\n if (fields.length === 0) {\n this.listTarget.replaceChildren(\n Object.assign(document.createElement('p'), {\n className: 'midwest-form-live-summary-empty',\n textContent: 'No values to display.'\n })\n )\n return\n }\n\n const dl = document.createElement('dl')\n dl.className = 'midwest-form-live-summary-list'\n\n fields.forEach(({ label, value, swatchColor }) => {\n const dt = Object.assign(document.createElement('dt'), {\n className: 'midwest-form-live-summary-term',\n textContent: label\n })\n const dd = document.createElement('dd')\n dd.className = 'midwest-form-live-summary-definition'\n\n if (swatchColor !== undefined) {\n dd.append(this.buildSwatch(swatchColor), value || '—')\n } else {\n dd.textContent = value || '—'\n }\n\n dl.append(dt, dd)\n })\n\n this.listTarget.replaceChildren(dl)\n }\n\n private collectFields (): FieldSummary[] {\n const form = this.form\n if (!form) return []\n\n const fields: FieldSummary[] = []\n const seenRadioNames = new Set<string>()\n\n Array.from(form.elements).forEach(el => {\n const element = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n\n if (!element.name) return\n\n // Skip elements that live inside the summary itself.\n if (this.element.contains(element)) return\n\n // Skip elements inside a hidden ShowIf fieldset — they are disabled\n // and excluded from form submission, so omit them from the summary.\n if (element.closest('fieldset.midwest-show-if[hidden]')) return\n\n // Skip all button elements regardless of how they are declared.\n if (element instanceof HTMLButtonElement) return\n\n // Skip tree-view checkboxes — they are collected separately below.\n if (element.closest('.midwest-tree-view')) return\n\n if (element instanceof HTMLInputElement) {\n if (SKIPPED_INPUT_TYPES.has(element.type)) return\n\n if (element.type === 'radio') {\n if (seenRadioNames.has(element.name)) return\n seenRadioNames.add(element.name)\n\n const checked = form.querySelector<HTMLInputElement>(\n `input[type=\"radio\"][name=\"${CSS.escape(element.name)}\"]:checked`\n )\n if (!checked) return\n\n fields.push({\n label: this.groupLabelFor(element),\n value: this.labelFor(checked) || checked.value\n })\n return\n }\n\n if (element.type === 'checkbox') {\n fields.push({\n label: this.labelFor(element),\n value: element.checked ? 'Yes' : 'No'\n })\n return\n }\n }\n\n if (element instanceof HTMLSelectElement) {\n fields.push({\n label: this.labelFor(element),\n value: Array.from(element.selectedOptions).map(o => o.text).join(', ') || '—'\n })\n return\n }\n\n // Text-like inputs and textareas only reach this point.\n fields.push({\n label: this.labelFor(element),\n value: element.value\n })\n })\n\n // Color picker components store their value in a hidden input tagged with\n // data-midwest-color-picker-target=\"input\". The standard loop skips hidden\n // inputs, so query them separately and render with an inline colour swatch.\n form.querySelectorAll<HTMLInputElement>('[data-midwest-color-picker-target=\"input\"]').forEach(input => {\n if (this.element.contains(input)) return\n if (!input.name) return\n\n // Prefer the label inside the picker's own form-group header; fall back\n // to a label[for] match or a prettified version of the input name.\n const picker = input.closest<HTMLElement>('.midwest-color-picker')\n const labelEl = picker?.querySelector<HTMLElement>('.midwest-form-group__top label') ??\n this.form?.querySelector<HTMLElement>(`label[for=\"${CSS.escape(input.id)}\"]`)\n const label = labelEl?.textContent?.trim() ||\n this.prettifyName(input.name.replace(/\\[.*\\]$/, ''))\n\n const value = input.value\n const display = value.startsWith('#') ? value : (value ? value.charAt(0).toUpperCase() + value.slice(1) : '—')\n\n fields.push({ label, value: display, swatchColor: value || undefined })\n })\n\n // Autocomplete components use a nameless combobox input + hidden inputs —\n // neither surfaces through the standard form.elements loop. Query them\n // separately so their selected badge labels appear in the summary.\n // Note: labelFor(input) doesn't work here because InputComponent assigns\n // its own id to the <input>, which won't match the <label>'s for attribute.\n form.querySelectorAll<HTMLElement>('.midwest-autocomplete').forEach(ac => {\n if (this.element.contains(ac)) return\n if (!ac.querySelector('[role=\"combobox\"]')) return\n\n const labelEl = ac.querySelector<HTMLElement>('label')\n const label = labelEl?.textContent?.trim() ||\n this.prettifyName((ac.dataset.name ?? '').replace(/\\[.*\\]$/, ''))\n\n const selected = Array.from(ac.querySelectorAll<HTMLElement>('.midwest-autocomplete-tokens .value'))\n .map(el => el.textContent?.trim())\n .filter(Boolean)\n .join(', ')\n fields.push({ label, value: selected || '—' })\n })\n\n // Tree view components render multiple checkboxes sharing the same name\n // (e.g. \"category_ids[]\"). Aggregate the checked nodes into a single\n // comma-separated summary row instead of listing each checkbox separately.\n const seenTreeNames = new Set<string>()\n form.querySelectorAll<HTMLElement>('.midwest-tree-view').forEach(tree => {\n if (this.element.contains(tree)) return\n\n const checked = Array.from(\n tree.querySelectorAll<HTMLInputElement>('.tree-node-checkbox:checked')\n )\n\n // Derive label from the first checkbox's name attribute.\n const firstName = checked[0]?.name || tree.querySelectorAll<HTMLInputElement>('.tree-node-checkbox')[0]?.name\n if (!firstName) return\n if (seenTreeNames.has(firstName)) return\n seenTreeNames.add(firstName)\n\n const label = this.prettifyName(firstName.replace(/\\[\\]$/, ''))\n const values = checked.map(cb => {\n const nodeLabel = cb.closest('.midwest-tree-node')\n ?.querySelector<HTMLElement>(':scope > .tree-node-trigger > .tree-node-label')\n return nodeLabel?.textContent?.trim() || cb.value\n })\n\n fields.push({ label, value: values.join(', ') || '—' })\n })\n\n return fields\n }\n\n // Builds a small inline colour swatch to display alongside a colour value.\n // Hex values are applied as an inline background-color; named theme colours\n // use a scoped theme-{color} class so the CSS variable cascade does the work.\n // An empty/transparent value renders a diagonal-stripe placeholder.\n private buildSwatch (color: string): HTMLElement {\n const swatch = document.createElement('span')\n swatch.className = 'midwest-form-live-summary-swatch'\n\n if (color.startsWith('#')) {\n swatch.style.backgroundColor = color\n } else if (color && color !== 'transparent') {\n swatch.classList.add(`theme-${color}`, 'bg-theme-6')\n } else {\n swatch.classList.add('is-transparent')\n }\n\n return swatch\n }\n\n // Finds the label associated with a specific element via `for` attribute,\n // wrapping label, or falls back to a prettified version of the element name.\n private labelFor (el: Element): string {\n const id = (el as HTMLElement).id\n if (id) {\n const label = this.form?.querySelector(`label[for=\"${CSS.escape(id)}\"]`)\n if (label) return label.textContent?.trim() ?? ''\n }\n const wrapper = el.closest('label')\n if (wrapper) return wrapper.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // For radio groups, prefer the containing fieldset legend over the\n // individual radio's label, then fall back to prettifying the name.\n private groupLabelFor (el: Element): string {\n const legend = el.closest('fieldset')?.querySelector('legend')\n if (legend) return legend.textContent?.trim() ?? ''\n return this.prettifyName((el as HTMLInputElement).name ?? '')\n }\n\n // Converts \"user[first_name]\" or \"first_name\" into \"First name\".\n private prettifyName (name: string): string {\n return name\n .replace(/\\[.*?\\]/g, '')\n .replace(/_/g, ' ')\n .replace(/^\\w/, c => c.toUpperCase())\n .trim()\n }\n}\n"],"names":[],"mappings":"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"}
|