@unabridged/midwest 0.20.1 → 0.21.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.
@@ -28,6 +28,7 @@ import Pagination from '../../../components/midwest/pagination_component/paginat
28
28
  import ShowIf from '../../../components/midwest/show_if_component/show_if_component_controller.js';
29
29
  import TreeView from '../../../components/midwest/tree_view_component/tree_view_component_controller.js';
30
30
  import CommandPalette from '../../../components/midwest/command_palette_component/command_palette_component_controller.js';
31
+ import Repeatable from '../../../components/midwest/form/repeatable_component/repeatable_component_controller.js';
31
32
 
32
33
  function registerMidwestControllers(application) {
33
34
  application.register("midwest-card", Card);
@@ -60,6 +61,7 @@ function registerMidwestControllers(application) {
60
61
  application.register("midwest-show-if", ShowIf);
61
62
  application.register("midwest-tree-view", TreeView);
62
63
  application.register("midwest-command-palette", CommandPalette);
64
+ application.register("midwest-repeatable", Repeatable);
63
65
  }
64
66
 
65
67
  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'\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;;;;"}
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'\nimport Repeatable from '../../../components/midwest/form/repeatable_component/repeatable_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 application.register('midwest-repeatable', Repeatable)\n /* EXPORTS */\n}\n"],"names":["Confirmation"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCO,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;AAC9D,EAAY,WAAA,CAAA,QAAA,CAAS,sBAAsB,UAAU,CAAA,CAAA;AAEvD;;;;"}
@@ -15,12 +15,14 @@ class FormLiveSummary extends Controller {
15
15
  this.form?.addEventListener("change", this.render);
16
16
  this.form?.addEventListener("midwest-autocomplete:change", this.render);
17
17
  this.form?.addEventListener("midwest-color-picker:update", this.render);
18
+ this.form?.addEventListener("midwest-repeatable:change", this.render);
18
19
  }
19
20
  disconnect() {
20
21
  this.form?.removeEventListener("input", this.render);
21
22
  this.form?.removeEventListener("change", this.render);
22
23
  this.form?.removeEventListener("midwest-autocomplete:change", this.render);
23
24
  this.form?.removeEventListener("midwest-color-picker:update", this.render);
25
+ this.form?.removeEventListener("midwest-repeatable:change", this.render);
24
26
  }
25
27
  get form() {
26
28
  return this.element.closest("form");
@@ -72,6 +74,8 @@ class FormLiveSummary extends Controller {
72
74
  return;
73
75
  if (element.closest(".midwest-tree-view"))
74
76
  return;
77
+ if (element.closest(".midwest-repeatable"))
78
+ return;
75
79
  if (element instanceof HTMLInputElement) {
76
80
  if (SKIPPED_INPUT_TYPES.has(element.type))
77
81
  return;
@@ -152,6 +156,33 @@ class FormLiveSummary extends Controller {
152
156
  });
153
157
  fields.push({ label, value: values.join(", ") || "\u2014" });
154
158
  });
159
+ form.querySelectorAll(".midwest-repeatable").forEach((repeatable) => {
160
+ if (this.element.contains(repeatable))
161
+ return;
162
+ const groupLabel = repeatable.querySelector(".midwest-form-group__top .midwest-label")?.textContent?.trim() || "Items";
163
+ const items = Array.from(
164
+ repeatable.querySelectorAll('[data-midwest-repeatable-target="item"]')
165
+ ).filter((item) => {
166
+ const destroy = item.querySelector('[data-midwest-repeatable-target="destroy"]');
167
+ return destroy?.value !== "1";
168
+ });
169
+ items.forEach((item, i) => {
170
+ const values = Array.from(
171
+ item.querySelectorAll(
172
+ 'input:not([type="hidden"]), textarea, select'
173
+ )
174
+ ).map((input) => {
175
+ if (input instanceof HTMLSelectElement) {
176
+ return Array.from(input.selectedOptions).map((o) => o.text).join(", ");
177
+ }
178
+ return input.value;
179
+ }).filter(Boolean);
180
+ fields.push({
181
+ label: items.length > 1 ? `${groupLabel} ${i + 1}` : groupLabel,
182
+ value: values.join(" \xB7 ") || "\u2014"
183
+ });
184
+ });
185
+ });
155
186
  return fields;
156
187
  }
157
188
  // 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 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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"}
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 this.form?.addEventListener('midwest-repeatable:change', 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 this.form?.removeEventListener('midwest-repeatable:change', 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 // Skip repeatable fields — templates, destroyed items, and active items\n // are all collected separately below as grouped summaries.\n if (element.closest('.midwest-repeatable')) 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 // Repeatable components contain nested attribute fields grouped inside\n // item wrappers. Summarise each active item as its own row, skipping\n // the hidden clone template and any items marked for destruction.\n form.querySelectorAll<HTMLElement>('.midwest-repeatable').forEach(repeatable => {\n if (this.element.contains(repeatable)) return\n\n const groupLabel = repeatable.querySelector<HTMLElement>('.midwest-form-group__top .midwest-label')\n ?.textContent?.trim() || 'Items'\n\n const items = Array.from(\n repeatable.querySelectorAll<HTMLElement>('[data-midwest-repeatable-target=\"item\"]')\n ).filter(item => {\n const destroy = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n return destroy?.value !== '1'\n })\n\n items.forEach((item, i) => {\n const values = Array.from(\n item.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n 'input:not([type=\"hidden\"]), textarea, select'\n )\n )\n .map(input => {\n if (input instanceof HTMLSelectElement) {\n return Array.from(input.selectedOptions).map(o => o.text).join(', ')\n }\n return input.value\n })\n .filter(Boolean)\n\n fields.push({\n label: items.length > 1 ? `${groupLabel} ${i + 1}` : groupLabel,\n value: values.join(' · ') || '—'\n })\n })\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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"}
@@ -0,0 +1,248 @@
1
+ import { Controller } from '@hotwired/stimulus';
2
+
3
+ class Repeatable extends Controller {
4
+ static targets = ["container", "item", "empty", "template", "addButton", "removeButton", "destroy"];
5
+ static values = {
6
+ min: { type: Number, default: 0 },
7
+ max: { type: Number, default: null },
8
+ templateId: { type: String, default: "" },
9
+ items: { type: Array, default: [] }
10
+ };
11
+ // ── Lifecycle ──────────────────────────────────────────────
12
+ connect() {
13
+ this.reindex();
14
+ }
15
+ // ── Actions ────────────────────────────────────────────────
16
+ add(event) {
17
+ event?.preventDefault();
18
+ if (this.maxValue !== null && this.itemsValue.length >= this.maxValue)
19
+ return;
20
+ const template = this.findTemplate();
21
+ if (!template)
22
+ return;
23
+ const newItem = template.cloneNode(true);
24
+ const nextIndex = this.nextAvailableIndex;
25
+ newItem.removeAttribute("id");
26
+ newItem.style.removeProperty("display");
27
+ newItem.setAttribute("data-midwest-repeatable-target", "item");
28
+ this.updateItemIndices(newItem, nextIndex);
29
+ this.resetItemFields(newItem);
30
+ newItem.classList.add("midwest-repeatable-item--adding");
31
+ this.containerTarget.appendChild(newItem);
32
+ setTimeout(() => {
33
+ newItem.classList.remove("midwest-repeatable-item--adding");
34
+ }, 300);
35
+ this.reindex();
36
+ }
37
+ remove(event) {
38
+ event?.preventDefault();
39
+ const button = event.currentTarget;
40
+ const item = button.closest('[data-midwest-repeatable-target="item"]');
41
+ if (!item)
42
+ return;
43
+ if (this.activeItems.length <= this.minValue)
44
+ return;
45
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
46
+ if (destroyInput) {
47
+ destroyInput.value = "1";
48
+ }
49
+ item.classList.add("midwest-repeatable-item--removing");
50
+ setTimeout(() => {
51
+ item.remove();
52
+ this.reindex();
53
+ }, 300);
54
+ }
55
+ removeAll(event) {
56
+ event?.preventDefault();
57
+ const active = this.activeItems;
58
+ if (active.length <= this.minValue)
59
+ return;
60
+ const toRemove = active.slice(this.minValue);
61
+ toRemove.forEach((item) => {
62
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
63
+ if (destroyInput)
64
+ destroyInput.value = "1";
65
+ item.classList.add("midwest-repeatable-item--removing");
66
+ });
67
+ setTimeout(() => {
68
+ toRemove.forEach((item) => item.remove());
69
+ this.reindex();
70
+ }, 300);
71
+ }
72
+ // ── Core: reindex builds state from DOM ────────────────────
73
+ reindex() {
74
+ const items = this.activeItems;
75
+ const states = items.map((item) => {
76
+ const index = this.extractIndex(item);
77
+ const { valid, errors } = this.validateItem(item);
78
+ return { index, valid, errors };
79
+ });
80
+ this.itemsValue = states;
81
+ this.setFieldsetErrors(states);
82
+ this.updateUI();
83
+ }
84
+ // ── Validation ─────────────────────────────────────────────
85
+ validateItem(item) {
86
+ const fields = item.querySelectorAll(
87
+ 'input:not([type="hidden"]), textarea, select'
88
+ );
89
+ const errors = [];
90
+ let valid = true;
91
+ fields.forEach((field) => {
92
+ if (!field.checkValidity()) {
93
+ valid = false;
94
+ const label = item.querySelector(`label[for="${field.id}"]`);
95
+ const name = label?.textContent?.trim() || field.name || "Field";
96
+ errors.push(`${name}: ${field.validationMessage}`);
97
+ }
98
+ });
99
+ return { valid, errors };
100
+ }
101
+ // ── Fieldset error management ──────────────────────────────
102
+ setFieldsetErrors(states) {
103
+ const invalidItems = states.filter((s) => !s.valid);
104
+ if (invalidItems.length > 0) {
105
+ this.element.setAttribute("data-repeatable-errors", JSON.stringify(
106
+ invalidItems.map((s) => ({ index: s.index, errors: s.errors }))
107
+ ));
108
+ this.element.setAttribute("aria-invalid", "true");
109
+ } else {
110
+ this.element.removeAttribute("data-repeatable-errors");
111
+ this.element.removeAttribute("aria-invalid");
112
+ }
113
+ this.activeItems.forEach((item) => {
114
+ const index = this.extractIndex(item);
115
+ const state = states.find((s) => s.index === index);
116
+ if (state && !state.valid) {
117
+ item.setAttribute("data-repeatable-invalid", "true");
118
+ item.setAttribute("data-repeatable-item-errors", JSON.stringify(state.errors));
119
+ } else {
120
+ item.removeAttribute("data-repeatable-invalid");
121
+ item.removeAttribute("data-repeatable-item-errors");
122
+ }
123
+ });
124
+ }
125
+ // ── Optional: query-selector-based index rebuild ───────────
126
+ queryItems() {
127
+ return Array.from(
128
+ this.containerTarget.querySelectorAll('[data-midwest-repeatable-target="item"]')
129
+ ).filter((item) => {
130
+ const d = item.querySelector('[data-midwest-repeatable-target="destroy"]');
131
+ return d?.value !== "1";
132
+ }).map((item) => {
133
+ const index = this.extractIndex(item);
134
+ const { valid, errors } = this.validateItem(item);
135
+ return { index, valid, errors };
136
+ });
137
+ }
138
+ // ── Stimulus value-changed callback ────────────────────────
139
+ itemsValueChanged() {
140
+ this.dispatch("change", {
141
+ detail: { count: this.itemsValue.length, items: this.itemsValue }
142
+ });
143
+ }
144
+ // ── Private helpers ────────────────────────────────────────
145
+ findTemplate() {
146
+ const active = this.activeItems;
147
+ if (active.length > 0)
148
+ return active[0];
149
+ if (this.itemTargets.length > 0)
150
+ return this.itemTargets[0];
151
+ if (this.hasTemplateTarget)
152
+ return this.templateTarget;
153
+ return null;
154
+ }
155
+ extractIndex(item) {
156
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
157
+ if (destroyInput?.name) {
158
+ const match = destroyInput.name.match(/\[(\d+)\]\[_destroy\]$/);
159
+ if (match)
160
+ return parseInt(match[1], 10);
161
+ }
162
+ const anyInput = item.querySelector("[name]");
163
+ if (anyInput?.name) {
164
+ const match = anyInput.name.match(/\[(\d+)\]/);
165
+ if (match)
166
+ return parseInt(match[1], 10);
167
+ }
168
+ return 0;
169
+ }
170
+ get nextAvailableIndex() {
171
+ const indices = this.itemsValue.map((s) => s.index);
172
+ if (indices.length === 0)
173
+ return 0;
174
+ return Math.max(...indices) + 1;
175
+ }
176
+ resetItemFields(item) {
177
+ const fields = item.querySelectorAll(
178
+ 'input:not([data-midwest-repeatable-target="destroy"]), textarea, select'
179
+ );
180
+ fields.forEach((field) => {
181
+ if (field instanceof HTMLInputElement) {
182
+ if (field.type === "checkbox" || field.type === "radio") {
183
+ field.checked = false;
184
+ } else {
185
+ field.value = "";
186
+ }
187
+ } else if (field instanceof HTMLSelectElement) {
188
+ field.selectedIndex = 0;
189
+ } else {
190
+ field.value = "";
191
+ }
192
+ });
193
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
194
+ if (destroyInput)
195
+ destroyInput.value = "0";
196
+ item.removeAttribute("data-repeatable-invalid");
197
+ item.removeAttribute("data-repeatable-item-errors");
198
+ }
199
+ updateItemIndices(item, newIndex) {
200
+ item.querySelectorAll("[name]").forEach((input) => {
201
+ if (input.name?.includes("[")) {
202
+ input.name = input.name.replace(/\[(\d+|new_\w+|__INDEX__)\]\[/g, `[${newIndex}][`);
203
+ }
204
+ });
205
+ item.querySelectorAll("[id]").forEach((el) => {
206
+ if (el.id?.match(/(_\d+_|_new_\w+_|___INDEX___)/)) {
207
+ el.id = el.id.replace(/(_\d+_|_new_\w+_|___INDEX___)/g, `_${newIndex}_`);
208
+ }
209
+ });
210
+ item.querySelectorAll("[for]").forEach((label) => {
211
+ if (label.htmlFor?.match(/(_\d+_|_new_\w+_|___INDEX___)/)) {
212
+ label.htmlFor = label.htmlFor.replace(/(_\d+_|_new_\w+_|___INDEX___)/g, `_${newIndex}_`);
213
+ }
214
+ });
215
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
216
+ if (destroyInput?.name) {
217
+ destroyInput.name = destroyInput.name.replace(
218
+ /\[(\d+|new_\w+|__INDEX__)\]\[_destroy\]/,
219
+ `[${newIndex}][_destroy]`
220
+ );
221
+ }
222
+ }
223
+ updateUI() {
224
+ const count = this.itemsValue.length;
225
+ if (this.hasAddButtonTarget) {
226
+ const atMax = this.maxValue !== null && count >= this.maxValue;
227
+ this.addButtonTarget.disabled = atMax;
228
+ this.addButtonTarget.classList.toggle("disabled", atMax);
229
+ }
230
+ this.removeButtonTargets.forEach((button) => {
231
+ const atMin = count <= this.minValue;
232
+ button.disabled = atMin;
233
+ button.classList.toggle("disabled", atMin);
234
+ });
235
+ if (this.hasEmptyTarget) {
236
+ this.emptyTarget.classList.toggle("hidden", count > 0);
237
+ }
238
+ }
239
+ get activeItems() {
240
+ return this.itemTargets.filter((item) => {
241
+ const destroyInput = item.querySelector('[data-midwest-repeatable-target="destroy"]');
242
+ return destroyInput?.value !== "1";
243
+ });
244
+ }
245
+ }
246
+
247
+ export { Repeatable as default };
248
+ //# sourceMappingURL=repeatable_component_controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeatable_component_controller.js","sources":["../../../../../../../../app/components/midwest/form/repeatable_component/repeatable_component_controller.ts"],"sourcesContent":["import { Controller } from '@hotwired/stimulus'\n\ninterface ItemState {\n index: number\n valid: boolean\n errors: string[]\n}\n\nexport default class Repeatable extends Controller<HTMLFieldSetElement> {\n static targets = ['container', 'item', 'empty', 'template', 'addButton', 'removeButton', 'destroy']\n\n static values = {\n min: { type: Number, default: 0 },\n max: { type: Number, default: null },\n templateId: { type: String, default: '' },\n items: { type: Array, default: [] }\n }\n\n declare containerTarget: HTMLElement\n declare hasEmptyTarget: boolean\n declare emptyTarget: HTMLElement\n declare hasTemplateTarget: boolean\n declare templateTarget: HTMLElement\n declare hasAddButtonTarget: boolean\n declare addButtonTarget: HTMLButtonElement\n declare itemTargets: HTMLElement[]\n declare removeButtonTargets: HTMLButtonElement[]\n declare destroyTargets: HTMLInputElement[]\n\n declare minValue: number\n declare maxValue: number | null\n declare templateIdValue: string\n declare itemsValue: ItemState[]\n\n // ── Lifecycle ──────────────────────────────────────────────\n\n connect () {\n this.reindex()\n }\n\n // ── Actions ────────────────────────────────────────────────\n\n add (event?: Event) {\n event?.preventDefault()\n\n if (this.maxValue !== null && this.itemsValue.length >= this.maxValue) return\n\n const template = this.findTemplate()\n if (!template) return\n\n const newItem = template.cloneNode(true) as HTMLElement\n const nextIndex = this.nextAvailableIndex\n\n // Prepare the cloned node as a live item\n newItem.removeAttribute('id')\n newItem.style.removeProperty('display')\n newItem.setAttribute('data-midwest-repeatable-target', 'item')\n this.updateItemIndices(newItem, nextIndex)\n this.resetItemFields(newItem)\n\n newItem.classList.add('midwest-repeatable-item--adding')\n\n // HTML first: append to DOM\n this.containerTarget.appendChild(newItem)\n\n setTimeout(() => {\n newItem.classList.remove('midwest-repeatable-item--adding')\n }, 300)\n\n // Then rebuild state from DOM\n this.reindex()\n }\n\n remove (event: Event) {\n event?.preventDefault()\n\n const button = event.currentTarget as HTMLElement\n const item = button.closest('[data-midwest-repeatable-target=\"item\"]') as HTMLElement\n if (!item) return\n\n if (this.activeItems.length <= this.minValue) return\n\n // Mark for Rails nested attribute destruction\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n if (destroyInput) {\n destroyInput.value = '1'\n }\n\n item.classList.add('midwest-repeatable-item--removing')\n\n setTimeout(() => {\n // HTML first: remove from DOM\n item.remove()\n // Then rebuild state\n this.reindex()\n }, 300)\n }\n\n removeAll (event?: Event) {\n event?.preventDefault()\n\n const active = this.activeItems\n if (active.length <= this.minValue) return\n\n const toRemove = active.slice(this.minValue)\n\n // Mark all for destruction and start animation\n toRemove.forEach(item => {\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n if (destroyInput) destroyInput.value = '1'\n item.classList.add('midwest-repeatable-item--removing')\n })\n\n setTimeout(() => {\n // HTML first: remove all from DOM\n toRemove.forEach(item => item.remove())\n // Then rebuild state once\n this.reindex()\n }, 300)\n }\n\n // ── Core: reindex builds state from DOM ────────────────────\n\n reindex () {\n const items = this.activeItems\n const states: ItemState[] = items.map(item => {\n const index = this.extractIndex(item)\n const { valid, errors } = this.validateItem(item)\n return { index, valid, errors }\n })\n\n // Store state as Stimulus array value\n this.itemsValue = states\n\n // Set errors on the fieldset for navigation / display\n this.setFieldsetErrors(states)\n\n // Update button states and empty indicator\n this.updateUI()\n }\n\n // ── Validation ─────────────────────────────────────────────\n\n validateItem (item: HTMLElement): { valid: boolean; errors: string[] } {\n const fields = item.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n 'input:not([type=\"hidden\"]), textarea, select'\n )\n const errors: string[] = []\n let valid = true\n\n fields.forEach(field => {\n if (!field.checkValidity()) {\n valid = false\n const label = item.querySelector<HTMLLabelElement>(`label[for=\"${field.id}\"]`)\n const name = label?.textContent?.trim() || field.name || 'Field'\n errors.push(`${name}: ${field.validationMessage}`)\n }\n })\n\n return { valid, errors }\n }\n\n // ── Fieldset error management ──────────────────────────────\n\n private setFieldsetErrors (states: ItemState[]) {\n const invalidItems = states.filter(s => !s.valid)\n\n if (invalidItems.length > 0) {\n this.element.setAttribute('data-repeatable-errors', JSON.stringify(\n invalidItems.map(s => ({ index: s.index, errors: s.errors }))\n ))\n this.element.setAttribute('aria-invalid', 'true')\n } else {\n this.element.removeAttribute('data-repeatable-errors')\n this.element.removeAttribute('aria-invalid')\n }\n\n // Mark individual items with their error state\n this.activeItems.forEach(item => {\n const index = this.extractIndex(item)\n const state = states.find(s => s.index === index)\n if (state && !state.valid) {\n item.setAttribute('data-repeatable-invalid', 'true')\n item.setAttribute('data-repeatable-item-errors', JSON.stringify(state.errors))\n } else {\n item.removeAttribute('data-repeatable-invalid')\n item.removeAttribute('data-repeatable-item-errors')\n }\n })\n }\n\n // ── Optional: query-selector-based index rebuild ───────────\n\n queryItems (): ItemState[] {\n return Array.from(\n this.containerTarget.querySelectorAll<HTMLElement>('[data-midwest-repeatable-target=\"item\"]')\n )\n .filter(item => {\n const d = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n return d?.value !== '1'\n })\n .map(item => {\n const index = this.extractIndex(item)\n const { valid, errors } = this.validateItem(item)\n return { index, valid, errors }\n })\n }\n\n // ── Stimulus value-changed callback ────────────────────────\n\n itemsValueChanged () {\n this.dispatch('change', {\n detail: { count: this.itemsValue.length, items: this.itemsValue }\n })\n }\n\n // ── Private helpers ────────────────────────────────────────\n\n private findTemplate (): HTMLElement | null {\n // Prefer an active item as source (has correct field structure)\n const active = this.activeItems\n if (active.length > 0) return active[0]\n\n // Fall back to any item target\n if (this.itemTargets.length > 0) return this.itemTargets[0]\n\n // Use the hidden template target\n if (this.hasTemplateTarget) return this.templateTarget\n\n return null\n }\n\n private extractIndex (item: HTMLElement): number {\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n if (destroyInput?.name) {\n const match = destroyInput.name.match(/\\[(\\d+)\\]\\[_destroy\\]$/)\n if (match) return parseInt(match[1], 10)\n }\n\n // Fallback: check any named input\n const anyInput = item.querySelector<HTMLInputElement>('[name]')\n if (anyInput?.name) {\n const match = anyInput.name.match(/\\[(\\d+)\\]/)\n if (match) return parseInt(match[1], 10)\n }\n\n return 0\n }\n\n private get nextAvailableIndex (): number {\n const indices = this.itemsValue.map(s => s.index)\n if (indices.length === 0) return 0\n return Math.max(...indices) + 1\n }\n\n private resetItemFields (item: HTMLElement) {\n const fields = item.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\n 'input:not([data-midwest-repeatable-target=\"destroy\"]), textarea, select'\n )\n\n fields.forEach(field => {\n if (field instanceof HTMLInputElement) {\n if (field.type === 'checkbox' || field.type === 'radio') {\n field.checked = false\n } else {\n field.value = ''\n }\n } else if (field instanceof HTMLSelectElement) {\n field.selectedIndex = 0\n } else {\n field.value = ''\n }\n })\n\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n if (destroyInput) destroyInput.value = '0'\n\n // Clear any lingering error markers\n item.removeAttribute('data-repeatable-invalid')\n item.removeAttribute('data-repeatable-item-errors')\n }\n\n private updateItemIndices (item: HTMLElement, newIndex: number) {\n // Update name attributes\n item.querySelectorAll<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>('[name]').forEach(input => {\n if (input.name?.includes('[')) {\n input.name = input.name.replace(/\\[(\\d+|new_\\w+|__INDEX__)\\]\\[/g, `[${newIndex}][`)\n }\n })\n\n // Update id attributes (for label associations)\n item.querySelectorAll<HTMLElement>('[id]').forEach(el => {\n if (el.id?.match(/(_\\d+_|_new_\\w+_|___INDEX___)/)) {\n el.id = el.id.replace(/(_\\d+_|_new_\\w+_|___INDEX___)/g, `_${newIndex}_`)\n }\n })\n\n // Update for attributes (labels)\n item.querySelectorAll<HTMLLabelElement>('[for]').forEach(label => {\n if (label.htmlFor?.match(/(_\\d+_|_new_\\w+_|___INDEX___)/)) {\n label.htmlFor = label.htmlFor.replace(/(_\\d+_|_new_\\w+_|___INDEX___)/g, `_${newIndex}_`)\n }\n })\n\n // Update destroy field name specifically\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n if (destroyInput?.name) {\n destroyInput.name = destroyInput.name.replace(\n /\\[(\\d+|new_\\w+|__INDEX__)\\]\\[_destroy\\]/,\n `[${newIndex}][_destroy]`\n )\n }\n }\n\n private updateUI () {\n const count = this.itemsValue.length\n\n // Add button\n if (this.hasAddButtonTarget) {\n const atMax = this.maxValue !== null && count >= this.maxValue\n this.addButtonTarget.disabled = atMax\n this.addButtonTarget.classList.toggle('disabled', atMax)\n }\n\n // Remove buttons\n this.removeButtonTargets.forEach(button => {\n const atMin = count <= this.minValue\n button.disabled = atMin\n button.classList.toggle('disabled', atMin)\n })\n\n // Empty state\n if (this.hasEmptyTarget) {\n this.emptyTarget.classList.toggle('hidden', count > 0)\n }\n }\n\n private get activeItems (): HTMLElement[] {\n return this.itemTargets.filter(item => {\n const destroyInput = item.querySelector<HTMLInputElement>('[data-midwest-repeatable-target=\"destroy\"]')\n return destroyInput?.value !== '1'\n })\n }\n}\n"],"names":[],"mappings":"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"}