@homebound/beam 4.46.1 → 4.47.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/truss.css CHANGED
@@ -91,16 +91,10 @@
91
91
  .br8 { border-radius: 8px; }
92
92
  /* @truss p:2000 c:brPill */
93
93
  .brPill { border-radius: 999px; }
94
- /* @truss p:2000 c:bra_0_0_0_8px */
95
- .bra_0_0_0_8px { border-radius: 0 0 0 8px; }
96
- /* @truss p:2000 c:bra_0_0_8px_0 */
97
- .bra_0_0_8px_0 { border-radius: 0 0 8px 0; }
98
94
  /* @truss p:2000 c:bra_0_16px_16px_0 */
99
95
  .bra_0_16px_16px_0 { border-radius: 0 16px 16px 0; }
100
96
  /* @truss p:2000 c:bra_0_4px_4px_0 */
101
97
  .bra_0_4px_4px_0 { border-radius: 0 4px 4px 0; }
102
- /* @truss p:2000 c:bra_0_8px_0_0 */
103
- .bra_0_8px_0_0 { border-radius: 0 8px 0 0; }
104
98
  /* @truss p:2000 c:bra_0_8px_8px_0 */
105
99
  .bra_0_8px_8px_0 { border-radius: 0 8px 8px 0; }
106
100
  /* @truss p:2000 c:bra_12px_12px_0_0 */
@@ -113,8 +107,6 @@
113
107
  .bra_50 { border-radius: 50%; }
114
108
  /* @truss p:2000 c:bra_6px */
115
109
  .bra_6px { border-radius: 6px; }
116
- /* @truss p:2000 c:bra_8px_0_0_0 */
117
- .bra_8px_0_0_0 { border-radius: 8px 0 0 0 ; }
118
110
  /* @truss p:2000 c:bra_8px_0_0_8px */
119
111
  .bra_8px_0_0_8px { border-radius: 8px 0 0 8px; }
120
112
  /* @truss p:2000 c:bra_8px_8px_0_0 */
@@ -771,6 +763,10 @@
771
763
  @container entityLockup (max-width: 400px) { .container_entityLockup_max_width_400px_lh_14px.container_entityLockup_max_width_400px_lh_14px { line-height: 14px; } }
772
764
  /* @truss p:3300 c:container_entityLockup_max_width_400px_lh_16px */
773
765
  @container entityLockup (max-width: 400px) { .container_entityLockup_max_width_400px_lh_16px.container_entityLockup_max_width_400px_lh_16px { line-height: 16px; } }
766
+ /* @truss p:4000 c:bblr_8px */
767
+ .bblr_8px { border-bottom-left-radius: 8px; }
768
+ /* @truss p:4000 c:bbrr_8px */
769
+ .bbrr_8px { border-bottom-right-radius: 8px; }
774
770
  /* @truss p:4000 c:bbs_solid */
775
771
  .bbs_solid { border-bottom-style: solid; }
776
772
  /* @truss p:4000 c:bbw_0 */
@@ -795,8 +791,12 @@
795
791
  .brw_1px { border-right-width: 1px; }
796
792
  /* @truss p:4000 c:btlr_12px */
797
793
  .btlr_12px { border-top-left-radius: 12px; }
794
+ /* @truss p:4000 c:btlr_8px */
795
+ .btlr_8px { border-top-left-radius: 8px; }
798
796
  /* @truss p:4000 c:btrr_12px */
799
797
  .btrr_12px { border-top-right-radius: 12px; }
798
+ /* @truss p:4000 c:btrr_8px */
799
+ .btrr_8px { border-top-right-radius: 8px; }
800
800
  /* @truss p:4000 c:bts_solid */
801
801
  .bts_solid { border-top-style: solid; }
802
802
  /* @truss p:4000 c:btw_1px */
@@ -821,6 +821,8 @@
821
821
  .h_16px { height: 16px; }
822
822
  /* @truss p:4000 c:h_18px */
823
823
  .h_18px { height: 18px; }
824
+ /* @truss p:4000 c:h_1lh */
825
+ .h_1lh { height: 1lh; }
824
826
  /* @truss p:4000 c:h_1px */
825
827
  .h_1px { height: 1px; }
826
828
  /* @truss p:4000 c:h_200 */
@@ -1093,8 +1095,6 @@
1093
1095
  .pl_24px { padding-left: 24px; }
1094
1096
  /* @truss p:4000 c:pl_2px */
1095
1097
  .pl_2px { padding-left: 2px; }
1096
- /* @truss p:4000 c:pl_36px */
1097
- .pl_36px { padding-left: 36px; }
1098
1098
  /* @truss p:4000 c:pl_4px */
1099
1099
  .pl_4px { padding-left: 4px; }
1100
1100
  /* @truss p:4000 c:pl_6px */
@@ -117,12 +117,16 @@ ${rowsWithPaddingAndDividers.join("\n")}
117
117
  function getTextFromTableCellNode(node) {
118
118
  if (node.nodeType === Node.ELEMENT_NODE) {
119
119
  const element = node;
120
- const maybeInput = element.getElementsByTagName("input")[0];
121
- if (maybeInput) return maybeInput.value;
122
- const maybeTextarea = element.getElementsByTagName("textarea")[0];
123
- if (maybeTextarea) return maybeTextarea.value;
124
- const maybeSelect = element.getElementsByTagName("select")[0];
125
- if (maybeSelect) return maybeSelect.value;
120
+ const control = element.querySelector("input, textarea, select");
121
+ if (control) {
122
+ const rest = element.cloneNode(true);
123
+ rest.querySelectorAll("input, textarea, select").forEach((el) => {
124
+ const label = el.closest("label");
125
+ (label ?? el).remove();
126
+ });
127
+ const text = (rest.textContent ?? "").replace(/\s+/g, " ").trim();
128
+ return text ? `${control.value} ${text}` : control.value;
129
+ }
126
130
  }
127
131
  return node.textContent;
128
132
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/rtlUtils.tsx","../../src/utils/helpers.ts"],"sourcesContent":["import {\n blur as _blur,\n change as _change,\n click as _click,\n clickAndWait as _clickAndWait,\n focus as _focus,\n input as _input,\n type as _type,\n typeAndWait as _typeAndWait,\n wait as _wait,\n allowAndWaitForAsyncBehavior,\n type RenderResult,\n} from \"@homebound/rtl-utils\";\nimport { act, fireEvent, prettyDOM } from \"@testing-library/react\";\nimport { fail } from \"src/utils/helpers\";\n\nexport {\n _blur as blur,\n _change as change,\n _click as click,\n _clickAndWait as clickAndWait,\n _focus as focus,\n _input as input,\n _type as type,\n _typeAndWait as typeAndWait,\n _wait as wait,\n};\n\n// This file is a collection of helpers for interacting with Beam components in tests.\n// We keep it separate from the `src/tests/rtl.tsx` file, which is the Beam tests\n// themselves use, which technically does re-export these `rtlUtils.tsx` helpers, but\n// also includes other helpers that are specific to Beam's test suite.\n//\n// (In particular, we cannot include/export any Beam components, i.e. BeamProvider, from\n// this file, because it ends up as a separate bundle in the `package.json` file, which\n// will be treated as separate components/providers than the primary bundle.)\n\nexport function cell(r: RenderResult, row: number, column: number): HTMLElement {\n return cellOf(r, \"gridTable\", row, column);\n}\n\nexport function cellOf(r: RenderResult, tableTestId: string, rowNum: number, column: number): HTMLElement {\n return row(r, rowNum, tableTestId).childNodes[column] as HTMLElement;\n}\n\nexport function cellAnd(r: RenderResult, row: number, column: number, testId: string): HTMLElement {\n return (\n cell(r, row, column).querySelector(`[data-testid=\"${testId}\"]`) ||\n fail(`Element not found ${prettyDOM(cell(r, row, column))}`)\n );\n}\n\nexport function row(r: RenderResult, row: number, tableTestId: string = \"gridTable\"): HTMLElement {\n const dataRows = Array.from(r.getByTestId(tableTestId).querySelectorAll(\"[data-gridrow]\"));\n return dataRows[row] as HTMLElement;\n}\n\nexport function rowAnd(r: RenderResult, rowNum: number, testId: string): HTMLElement {\n const e = row(r, rowNum);\n return e.querySelector(`[data-testid=\"${testId}\"]`) || fail(`Element not found ${prettyDOM(e)}`);\n}\n\n/** Intended to be used to generate a human-readable text\n * representation of a GridTable using the markdown table syntax.\n * * Example Use: expect(tableSnapshot(r)).toMatchInlineSnapshot(`\n \"\n | Name | Value |\n | ------------------------ | ----- |\n | Row 1 | 200 |\n | Row 2 with a longer name | 300 |\n | Row 3 | 1000 |\n \"\n `);\n * */\nexport function tableSnapshot(r: RenderResult, columnNames: string[] = [], tableTestId: string = \"gridTable\"): string {\n const tableEl = r.getByTestId(tableTestId);\n const dataRows = Array.from(tableEl.querySelectorAll(\"[data-gridrow]\"));\n const hasExpandableHeader = !!tableEl.querySelector(`[data-testid=\"expandableColumn\"]`);\n\n let tableDataAsStrings = dataRows.map((row) => {\n return Array.from(row.childNodes).map(getTextFromTableCellNode);\n });\n\n // If the user wants a subset of columns, look for column names\n if (columnNames.length > 0) {\n const headerCells = tableDataAsStrings[0];\n if (headerCells) {\n const columnIndices = columnNames.map((name) => {\n const i = headerCells.indexOf(name);\n if (i === -1) throw new Error(`Could not find header '${name}' in ${headerCells.join(\", \")}`);\n return i;\n });\n tableDataAsStrings = tableDataAsStrings.map((row) => columnIndices.map((index) => row[index]));\n }\n }\n\n return toMarkupTableString(tableDataAsStrings, hasExpandableHeader);\n}\n\nfunction toMarkupTableString(tableRows: (string | null)[][], hasExpandableHeader: boolean): string {\n // Find the largest width of each column to set a consistent width for each row\n const columnWidths = tableRows.reduce((acc, row) => {\n row.forEach((cell, columnIndex) => {\n const cellWidth = cell?.length ?? 0;\n const currentMaxWidth = acc.get(columnIndex) ?? 0;\n if (cellWidth > currentMaxWidth || !currentMaxWidth) acc.set(columnIndex, cellWidth);\n });\n\n return acc;\n }, new Map<number, number>());\n\n const wrapTableRowEnds = (str: string) => `| ${str} |`;\n\n const rowsWithPaddingAndDividers = tableRows.map((tableCells) => {\n const formattedRow = tableCells\n .map((cell, columnIndex) => {\n const cellWidth = columnWidths.get(columnIndex) ?? 0;\n return cell?.padEnd(cellWidth, \" \") || \"\";\n })\n .join(\" | \");\n return wrapTableRowEnds(formattedRow);\n });\n\n const headerDivider = Array.from(columnWidths.values())\n .map((width) => \"-\".repeat(width) ?? \"\")\n .join(\" | \");\n\n const headerDividerRowNumber = hasExpandableHeader ? 2 : 1;\n rowsWithPaddingAndDividers.splice(headerDividerRowNumber, 0, wrapTableRowEnds(headerDivider));\n\n // Pad a newline on top and bottom for cleaner diffs\n return `\\n${rowsWithPaddingAndDividers.join(\"\\n\")}\\n`;\n}\n\n/** Prefer showing a `value` from a mocked input vs. the combined text content from an inputs markup */\nfunction getTextFromTableCellNode(node: ChildNode) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n\n const maybeInput = element.getElementsByTagName(\"input\")[0];\n if (maybeInput) return maybeInput.value;\n\n const maybeTextarea = element.getElementsByTagName(\"textarea\")[0];\n if (maybeTextarea) return maybeTextarea.value;\n\n const maybeSelect = element.getElementsByTagName(\"select\")[0];\n if (maybeSelect) return maybeSelect.value;\n }\n\n return node.textContent;\n}\n\nexport type ScrollWindowOpts = {\n clientHeight?: number;\n scrollHeight?: number;\n};\n\nexport type ScrollWindowWithAnchorOpts = ScrollWindowOpts & {\n /** getBoundingClientRect().top when scrollY is 0. Default 0. */\n anchorTop?: number;\n /** Used to derive default scrollHeight and atBottom checks. Default 1_000_000. */\n maxScroll?: number;\n /** Height of the mocked anchor element (rect height/bottom). Default 50. */\n elementHeight?: number;\n};\n\nfunction setWindowScrollMetrics(y: number, opts?: ScrollWindowOpts): void {\n Object.defineProperty(window, \"scrollY\", { value: y, configurable: true });\n if (opts?.clientHeight != null) {\n Object.defineProperty(document.documentElement, \"clientHeight\", { value: opts.clientHeight, configurable: true });\n }\n if (opts?.scrollHeight != null) {\n Object.defineProperty(document.documentElement, \"scrollHeight\", { value: opts.scrollHeight, configurable: true });\n }\n}\n\n/** Sets window.scrollY, optionally document scroll metrics, and dispatches a scroll event. */\nexport function scrollWindow(y: number, opts?: ScrollWindowOpts): void {\n setWindowScrollMetrics(y, opts);\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** scrollWindow plus a fake getBoundingClientRect on an anchor/spacer element. */\nexport function scrollWindowWithAnchor(anchor: HTMLElement, y: number, opts: ScrollWindowWithAnchorOpts = {}): void {\n const clientHeight = opts.clientHeight ?? 800;\n const maxScroll = opts.maxScroll ?? 1_000_000;\n const scrollHeight = opts.scrollHeight ?? maxScroll + clientHeight;\n const anchorTop = opts.anchorTop ?? 0;\n const elementHeight = opts.elementHeight ?? 50;\n\n setWindowScrollMetrics(y, { clientHeight, scrollHeight });\n const top = anchorTop - y;\n anchor.getBoundingClientRect = () =>\n ({\n top,\n bottom: top + elementHeight,\n left: 0,\n right: 0,\n width: 0,\n height: elementHeight,\n x: 0,\n y: top,\n toJSON() {},\n }) as DOMRect;\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** Mocks document.documentElement clientWidth/clientHeight for viewport measurement tests. */\nexport function mockDocumentViewport(width: number, height: number): void {\n Object.defineProperty(document.documentElement, \"clientWidth\", { configurable: true, get: () => width });\n Object.defineProperty(document.documentElement, \"clientHeight\", { configurable: true, get: () => height });\n}\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.\n *\n * @param value The value or label of the option.\n * */\nexport function select(select: HTMLElement, value: string | string[]) {\n assertListBoxInput(select);\n ensureListBoxOpen(select);\n const optionValues = Array.isArray(value) ? value : [value];\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n}\n\nexport type SelectAndWaitOpts = { addNew?: boolean };\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * When `value` is a single string and the listbox opens empty, types the value to trigger async\n * search before selecting. Multi-select (`value` array) assumes options are already loaded.\n *\n * When `{ addNew: true }`, types the value and selects the `Add \"<value>\"` creatable row.\n */\nexport async function selectAndWait(\n select: HTMLElement,\n value: string | string[],\n opts?: SelectAndWaitOpts,\n): Promise<void> {\n // To work with React 18, we need to execute these as separate steps, otherwise\n // the `ensureListBoxOpen` async render won't flush, and the `selectOption` will fail.\n const optionValues = Array.isArray(value) ? value : [value];\n\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (opts?.addNew) {\n if (Array.isArray(value)) {\n throw new Error(\"selectAndWait addNew option does not support multi-select\");\n }\n await typeForAddNew(select, value);\n return allowAndWaitForAsyncBehavior(() => selectOption(select, `Add \"${value.trim()}\"`));\n }\n if (!Array.isArray(value)) {\n await maybeAutoSearch(select, value);\n }\n\n return allowAndWaitForAsyncBehavior(() => {\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n });\n}\n\nasync function typeForAddNew(select: HTMLElement, value: string): Promise<void> {\n fireEvent.input(select, { target: { value } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\n/** When a combobox opens with no options, type the target label to trigger async search. */\nasync function maybeAutoSearch(select: HTMLElement, searchText: string): Promise<void> {\n if (!hasZeroOptions(select)) return;\n\n // Give lazy-load or debounced search a chance to populate options before typing.\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (!hasZeroOptions(select)) return;\n\n fireEvent.input(select, { target: { value: searchText } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\nfunction getListBoxOptions(select: HTMLElement): HTMLElement[] {\n const listbox = findListBox(select);\n return Array.from(listbox.querySelectorAll(\"[role=option]\")) as HTMLElement[];\n}\n\nfunction hasZeroOptions(select: HTMLElement): boolean {\n return getListBoxOptions(select).length === 0;\n}\n\nfunction ensureListBoxOpen(select: HTMLElement): void {\n const expanded = select.getAttribute(\"aria-expanded\") === \"true\";\n if (!expanded) {\n _click(select);\n }\n}\n\nfunction selectOption(select: HTMLElement, optionValue: string) {\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n // Allow searching for options by their data-key (value) or textContent (label)\n const optionToSelect = Array.from(options).find(\n (o: HTMLElement) => o.dataset.key === optionValue || o.dataset.label === optionValue,\n );\n if (!optionToSelect) {\n throw new Error(`Could not find option with value or text content of ${optionValue}`);\n }\n if (optionToSelect.getAttribute(\"aria-disabled\")) {\n throw new Error(`Cannot select disabled option ${optionValue}`);\n }\n _click(optionToSelect);\n}\n\nexport function getSelected(select: HTMLElement): string[] | string | undefined {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getSelected helper does not support <select> elements\");\n }\n\n if (!isInputOrTextAreaElement(select) && select.dataset.readonly === \"true\") {\n // For read-only fields that render as a 'div'\n return select.textContent ?? undefined;\n }\n\n ensureListBoxOpen(select);\n\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n const selections: string[] = Array.from(options)\n .filter((o: HTMLElement) => o.getAttribute(\"aria-selected\") === \"true\")\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n // Filter out empty strings\n .filter((o) => !!o);\n\n return selections.length > 0 ? (selections.length > 1 ? selections : selections[0]) : undefined;\n}\n\n/** Returns option labels for a SelectField listbox, or a checkbox/radio group root. */\nexport function getOptions(element: HTMLElement): string[] {\n const group = resolveOptionGroup(element);\n if (group) return getGroupOptions(group);\n\n assertListBoxInput(element);\n ensureListBoxOpen(element);\n\n const listbox = findListBox(element);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n return Array.from(options)\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n .filter((o) => !!o);\n}\n\n/** Prefer the element itself when it is a group; otherwise look for a nested group. */\nfunction resolveOptionGroup(element: HTMLElement): HTMLElement | undefined {\n if (isOptionGroup(element)) return element;\n const nested =\n element.querySelector<HTMLElement>('[role=\"radiogroup\"]') ??\n Array.from(element.querySelectorAll<HTMLElement>('[role=\"group\"]')).find(isCheckboxOrRadioGroup);\n return nested;\n}\n\nfunction isOptionGroup(element: HTMLElement): boolean {\n const role = element.getAttribute(\"role\");\n if (role === \"radiogroup\") return true;\n return role === \"group\" && isCheckboxOrRadioGroup(element);\n}\n\nfunction isCheckboxOrRadioGroup(element: HTMLElement): boolean {\n return !!element.querySelector(\"input[type=checkbox], input[type=radio]\");\n}\n\nfunction getGroupOptions(group: HTMLElement): string[] {\n const inputs = Array.from(group.querySelectorAll<HTMLInputElement>(\"input[type=radio], input[type=checkbox]\"));\n return inputs.map(getInputOptionLabel).filter((label) => !!label);\n}\n\nfunction getInputOptionLabel(input: HTMLInputElement): string {\n const ariaLabel = input.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const labelledBy = input.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy.split(/\\s+/)[0]!);\n const text = labelEl?.textContent?.trim();\n if (text) return text;\n }\n\n return input.value || \"\";\n}\n\nfunction findListBox(select: HTMLElement): HTMLElement {\n if (select.tagName === \"DIV\") fail(\"SelectField is readOnly\");\n const listboxId =\n select.getAttribute(\"aria-controls\") ||\n fail(\"aria-controls attribute not found, the SelectField is probably readOnly\");\n return document.getElementById(listboxId) || fail(\"listbox not found\");\n}\n\nfunction assertListBoxInput(select: HTMLElement): select is HTMLInputElement | HTMLTextAreaElement | HTMLButtonElement {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getOptions helper does not support <select> elements\");\n }\n // MenuSelectField's trigger is a button; the other selects type into an input.\n if (!isInputOrTextAreaElement(select) && select.nodeName !== \"BUTTON\") {\n throw new Error(\n `Expected element to be INPUT, TEXTAREA, or BUTTON, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`,\n );\n }\n return true;\n}\n\nfunction isSelectElement(element: HTMLElement): element is HTMLSelectElement {\n return element.nodeName === \"SELECT\";\n}\n\nfunction isInputOrTextAreaElement(element: HTMLElement): element is HTMLInputElement | HTMLTextAreaElement {\n return element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\";\n}\n","import type { MutableRefObject } from \"react\";\nimport type { CheckboxGroupState, ToggleState } from \"react-stately\";\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\n/** Adapts our state to what useToggleState returns in a stateless manner. */\nexport function toToggleState(isSelected: boolean, onChange: (value: boolean) => void): ToggleState {\n return {\n isSelected,\n defaultSelected: false,\n setSelected: onChange,\n toggle: () => onChange(!isSelected),\n };\n}\n\n/** Adapts our state to what use*Group returns in a stateless manner. */\nexport function toGroupState<T extends string>(values: T[], onChange: (value: T[]) => void): CheckboxGroupState {\n const addValue = (value: T) => onChange([...values, value]);\n const removeValue = (value: T) => onChange(values.filter((_value) => _value !== value));\n\n return {\n value: values,\n defaultValue: [],\n setValue: onChange,\n isSelected: (value: T) => values.includes(value),\n addValue,\n removeValue,\n toggleValue: (value: T) => (values.includes(value) ? addValue(value) : removeValue(value)),\n isDisabled: false,\n isReadOnly: false,\n // We do not use the validation state, as our Switch groups do not support error states. However, this field is required by the `CheckboxGroupState` so we need to include it.\n // If we ever update our SwitchGroup component to support error states, we'll need to update this.\n validationState: \"valid\",\n isInvalid: false,\n isRequired: false,\n setInvalid: () => {},\n realtimeValidation: { isInvalid: false, validationErrors: [], validationDetails: {} as ValidityState },\n displayValidation: { isInvalid: false, validationErrors: [], validationDetails: {} as ValidityState },\n updateValidation: () => {},\n resetValidation: () => {},\n commitValidation: () => {},\n };\n}\n\n/**\n * Utility to maybe call a function if undefined with arguments\n *\n * @example\n * maybeCall(onChange, true)\n * maybeCall(onBlur)\n * maybeCall(onSelect, { id: 1, value: \"book 1\"}, true)\n */\nexport function maybeCall(callback: Function | undefined, ...args: any[]) {\n return callback && callback(...args);\n}\n\n/** Casts `Object.keys` to \"what it should be\", as long as your instance doesn't have keys it shouldn't. */\nexport function safeKeys<T>(instance: T): (keyof T)[] {\n return Object.getOwnPropertyNames(instance) as any;\n}\n\n// Returns object with specified key removed\nexport const omitKey = <T, K extends keyof T>(key: K, { [key]: _, ...obj }: T) => obj as T;\n\nexport const noop = (..._: any) => {};\n\ntype Entries<T> = {\n [K in keyof T]: [K, T[K]];\n}[keyof T][];\n\nexport function safeEntries<T extends object>(obj: T): Entries<T> {\n return Object.entries(obj) as any;\n}\n\nexport class EmptyRef<T> implements MutableRefObject<T> {\n get current(): T {\n throw new Error(\"BeamProvider is missing\");\n }\n\n set current(_) {\n throw new Error(\"BeamProvider is missing\");\n }\n}\n\nexport const isAbsoluteUrl = (url: string) => /^(http(s?)):\\/\\//i.test(url);\n\nexport function areArraysEqual(a: any[], b: any[]): boolean {\n return a.length === b.length && a.every((val, idx) => val === b[idx]);\n}\n\nexport function isPromise(obj: any | Promise<any>): obj is Promise<any> {\n return typeof obj === \"object\" && \"then\" in obj && typeof obj.then === \"function\";\n}\n\nexport function isFunction(f: any): f is Function {\n return typeof f === \"function\";\n}\n\nexport function isDefined<T extends any>(param: T | undefined | null): param is T {\n return param !== null && param !== undefined;\n}\n\nexport function pluralize(count: number | unknown[], noun: string, pluralNoun?: string): string {\n if ((Array.isArray(count) ? count.length : count) === 1) return noun;\n return pluralNoun || `${noun}s`;\n}\n"],"mappings":"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","names":["_blur","_change","_click","_clickAndWait","_focus","_input","_type","_typeAndWait","_wait","row","cell","select","_wait","_click"]}
1
+ {"version":3,"sources":["../../src/utils/rtlUtils.tsx","../../src/utils/helpers.ts"],"sourcesContent":["import {\n blur as _blur,\n change as _change,\n click as _click,\n clickAndWait as _clickAndWait,\n focus as _focus,\n input as _input,\n type as _type,\n typeAndWait as _typeAndWait,\n wait as _wait,\n allowAndWaitForAsyncBehavior,\n type RenderResult,\n} from \"@homebound/rtl-utils\";\nimport { act, fireEvent, prettyDOM } from \"@testing-library/react\";\nimport { fail } from \"src/utils/helpers\";\n\nexport {\n _blur as blur,\n _change as change,\n _click as click,\n _clickAndWait as clickAndWait,\n _focus as focus,\n _input as input,\n _type as type,\n _typeAndWait as typeAndWait,\n _wait as wait,\n};\n\n// This file is a collection of helpers for interacting with Beam components in tests.\n// We keep it separate from the `src/tests/rtl.tsx` file, which is the Beam tests\n// themselves use, which technically does re-export these `rtlUtils.tsx` helpers, but\n// also includes other helpers that are specific to Beam's test suite.\n//\n// (In particular, we cannot include/export any Beam components, i.e. BeamProvider, from\n// this file, because it ends up as a separate bundle in the `package.json` file, which\n// will be treated as separate components/providers than the primary bundle.)\n\nexport function cell(r: RenderResult, row: number, column: number): HTMLElement {\n return cellOf(r, \"gridTable\", row, column);\n}\n\nexport function cellOf(r: RenderResult, tableTestId: string, rowNum: number, column: number): HTMLElement {\n return row(r, rowNum, tableTestId).childNodes[column] as HTMLElement;\n}\n\nexport function cellAnd(r: RenderResult, row: number, column: number, testId: string): HTMLElement {\n return (\n cell(r, row, column).querySelector(`[data-testid=\"${testId}\"]`) ||\n fail(`Element not found ${prettyDOM(cell(r, row, column))}`)\n );\n}\n\nexport function row(r: RenderResult, row: number, tableTestId: string = \"gridTable\"): HTMLElement {\n const dataRows = Array.from(r.getByTestId(tableTestId).querySelectorAll(\"[data-gridrow]\"));\n return dataRows[row] as HTMLElement;\n}\n\nexport function rowAnd(r: RenderResult, rowNum: number, testId: string): HTMLElement {\n const e = row(r, rowNum);\n return e.querySelector(`[data-testid=\"${testId}\"]`) || fail(`Element not found ${prettyDOM(e)}`);\n}\n\n/** Intended to be used to generate a human-readable text\n * representation of a GridTable using the markdown table syntax.\n * * Example Use: expect(tableSnapshot(r)).toMatchInlineSnapshot(`\n \"\n | Name | Value |\n | ------------------------ | ----- |\n | Row 1 | 200 |\n | Row 2 with a longer name | 300 |\n | Row 3 | 1000 |\n \"\n `);\n * */\nexport function tableSnapshot(r: RenderResult, columnNames: string[] = [], tableTestId: string = \"gridTable\"): string {\n const tableEl = r.getByTestId(tableTestId);\n const dataRows = Array.from(tableEl.querySelectorAll(\"[data-gridrow]\"));\n const hasExpandableHeader = !!tableEl.querySelector(`[data-testid=\"expandableColumn\"]`);\n\n let tableDataAsStrings = dataRows.map((row) => {\n return Array.from(row.childNodes).map(getTextFromTableCellNode);\n });\n\n // If the user wants a subset of columns, look for column names\n if (columnNames.length > 0) {\n const headerCells = tableDataAsStrings[0];\n if (headerCells) {\n const columnIndices = columnNames.map((name) => {\n const i = headerCells.indexOf(name);\n if (i === -1) throw new Error(`Could not find header '${name}' in ${headerCells.join(\", \")}`);\n return i;\n });\n tableDataAsStrings = tableDataAsStrings.map((row) => columnIndices.map((index) => row[index]));\n }\n }\n\n return toMarkupTableString(tableDataAsStrings, hasExpandableHeader);\n}\n\nfunction toMarkupTableString(tableRows: (string | null)[][], hasExpandableHeader: boolean): string {\n // Find the largest width of each column to set a consistent width for each row\n const columnWidths = tableRows.reduce((acc, row) => {\n row.forEach((cell, columnIndex) => {\n const cellWidth = cell?.length ?? 0;\n const currentMaxWidth = acc.get(columnIndex) ?? 0;\n if (cellWidth > currentMaxWidth || !currentMaxWidth) acc.set(columnIndex, cellWidth);\n });\n\n return acc;\n }, new Map<number, number>());\n\n const wrapTableRowEnds = (str: string) => `| ${str} |`;\n\n const rowsWithPaddingAndDividers = tableRows.map((tableCells) => {\n const formattedRow = tableCells\n .map((cell, columnIndex) => {\n const cellWidth = columnWidths.get(columnIndex) ?? 0;\n return cell?.padEnd(cellWidth, \" \") || \"\";\n })\n .join(\" | \");\n return wrapTableRowEnds(formattedRow);\n });\n\n const headerDivider = Array.from(columnWidths.values())\n .map((width) => \"-\".repeat(width) ?? \"\")\n .join(\" | \");\n\n const headerDividerRowNumber = hasExpandableHeader ? 2 : 1;\n rowsWithPaddingAndDividers.splice(headerDividerRowNumber, 0, wrapTableRowEnds(headerDivider));\n\n // Pad a newline on top and bottom for cleaner diffs\n return `\\n${rowsWithPaddingAndDividers.join(\"\\n\")}\\n`;\n}\n\n/**\n * Prefer a form control's `value` over its markup. When the control shares a cell with other\n * content (a select checkbox or collapse toggle in the same cell as a label), keep that content after the value.\n */\nfunction getTextFromTableCellNode(node: ChildNode) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n const control = element.querySelector(\"input, textarea, select\") as\n HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null;\n if (control) {\n const rest = element.cloneNode(true) as HTMLElement;\n rest.querySelectorAll(\"input, textarea, select\").forEach((el) => {\n const label = el.closest(\"label\");\n (label ?? el).remove();\n });\n const text = (rest.textContent ?? \"\").replace(/\\s+/g, \" \").trim();\n return text ? `${control.value} ${text}` : control.value;\n }\n }\n\n return node.textContent;\n}\n\nexport type ScrollWindowOpts = {\n clientHeight?: number;\n scrollHeight?: number;\n};\n\nexport type ScrollWindowWithAnchorOpts = ScrollWindowOpts & {\n /** getBoundingClientRect().top when scrollY is 0. Default 0. */\n anchorTop?: number;\n /** Used to derive default scrollHeight and atBottom checks. Default 1_000_000. */\n maxScroll?: number;\n /** Height of the mocked anchor element (rect height/bottom). Default 50. */\n elementHeight?: number;\n};\n\nfunction setWindowScrollMetrics(y: number, opts?: ScrollWindowOpts): void {\n Object.defineProperty(window, \"scrollY\", { value: y, configurable: true });\n if (opts?.clientHeight != null) {\n Object.defineProperty(document.documentElement, \"clientHeight\", { value: opts.clientHeight, configurable: true });\n }\n if (opts?.scrollHeight != null) {\n Object.defineProperty(document.documentElement, \"scrollHeight\", { value: opts.scrollHeight, configurable: true });\n }\n}\n\n/** Sets window.scrollY, optionally document scroll metrics, and dispatches a scroll event. */\nexport function scrollWindow(y: number, opts?: ScrollWindowOpts): void {\n setWindowScrollMetrics(y, opts);\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** scrollWindow plus a fake getBoundingClientRect on an anchor/spacer element. */\nexport function scrollWindowWithAnchor(anchor: HTMLElement, y: number, opts: ScrollWindowWithAnchorOpts = {}): void {\n const clientHeight = opts.clientHeight ?? 800;\n const maxScroll = opts.maxScroll ?? 1_000_000;\n const scrollHeight = opts.scrollHeight ?? maxScroll + clientHeight;\n const anchorTop = opts.anchorTop ?? 0;\n const elementHeight = opts.elementHeight ?? 50;\n\n setWindowScrollMetrics(y, { clientHeight, scrollHeight });\n const top = anchorTop - y;\n anchor.getBoundingClientRect = () =>\n ({\n top,\n bottom: top + elementHeight,\n left: 0,\n right: 0,\n width: 0,\n height: elementHeight,\n x: 0,\n y: top,\n toJSON() {},\n }) as DOMRect;\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** Mocks document.documentElement clientWidth/clientHeight for viewport measurement tests. */\nexport function mockDocumentViewport(width: number, height: number): void {\n Object.defineProperty(document.documentElement, \"clientWidth\", { configurable: true, get: () => width });\n Object.defineProperty(document.documentElement, \"clientHeight\", { configurable: true, get: () => height });\n}\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.\n *\n * @param value The value or label of the option.\n * */\nexport function select(select: HTMLElement, value: string | string[]) {\n assertListBoxInput(select);\n ensureListBoxOpen(select);\n const optionValues = Array.isArray(value) ? value : [value];\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n}\n\nexport type SelectAndWaitOpts = { addNew?: boolean };\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * When `value` is a single string and the listbox opens empty, types the value to trigger async\n * search before selecting. Multi-select (`value` array) assumes options are already loaded.\n *\n * When `{ addNew: true }`, types the value and selects the `Add \"<value>\"` creatable row.\n */\nexport async function selectAndWait(\n select: HTMLElement,\n value: string | string[],\n opts?: SelectAndWaitOpts,\n): Promise<void> {\n // To work with React 18, we need to execute these as separate steps, otherwise\n // the `ensureListBoxOpen` async render won't flush, and the `selectOption` will fail.\n const optionValues = Array.isArray(value) ? value : [value];\n\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (opts?.addNew) {\n if (Array.isArray(value)) {\n throw new Error(\"selectAndWait addNew option does not support multi-select\");\n }\n await typeForAddNew(select, value);\n return allowAndWaitForAsyncBehavior(() => selectOption(select, `Add \"${value.trim()}\"`));\n }\n if (!Array.isArray(value)) {\n await maybeAutoSearch(select, value);\n }\n\n return allowAndWaitForAsyncBehavior(() => {\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n });\n}\n\nasync function typeForAddNew(select: HTMLElement, value: string): Promise<void> {\n fireEvent.input(select, { target: { value } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\n/** When a combobox opens with no options, type the target label to trigger async search. */\nasync function maybeAutoSearch(select: HTMLElement, searchText: string): Promise<void> {\n if (!hasZeroOptions(select)) return;\n\n // Give lazy-load or debounced search a chance to populate options before typing.\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (!hasZeroOptions(select)) return;\n\n fireEvent.input(select, { target: { value: searchText } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\nfunction getListBoxOptions(select: HTMLElement): HTMLElement[] {\n const listbox = findListBox(select);\n return Array.from(listbox.querySelectorAll(\"[role=option]\")) as HTMLElement[];\n}\n\nfunction hasZeroOptions(select: HTMLElement): boolean {\n return getListBoxOptions(select).length === 0;\n}\n\nfunction ensureListBoxOpen(select: HTMLElement): void {\n const expanded = select.getAttribute(\"aria-expanded\") === \"true\";\n if (!expanded) {\n _click(select);\n }\n}\n\nfunction selectOption(select: HTMLElement, optionValue: string) {\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n // Allow searching for options by their data-key (value) or textContent (label)\n const optionToSelect = Array.from(options).find(\n (o: HTMLElement) => o.dataset.key === optionValue || o.dataset.label === optionValue,\n );\n if (!optionToSelect) {\n throw new Error(`Could not find option with value or text content of ${optionValue}`);\n }\n if (optionToSelect.getAttribute(\"aria-disabled\")) {\n throw new Error(`Cannot select disabled option ${optionValue}`);\n }\n _click(optionToSelect);\n}\n\nexport function getSelected(select: HTMLElement): string[] | string | undefined {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getSelected helper does not support <select> elements\");\n }\n\n if (!isInputOrTextAreaElement(select) && select.dataset.readonly === \"true\") {\n // For read-only fields that render as a 'div'\n return select.textContent ?? undefined;\n }\n\n ensureListBoxOpen(select);\n\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n const selections: string[] = Array.from(options)\n .filter((o: HTMLElement) => o.getAttribute(\"aria-selected\") === \"true\")\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n // Filter out empty strings\n .filter((o) => !!o);\n\n return selections.length > 0 ? (selections.length > 1 ? selections : selections[0]) : undefined;\n}\n\n/** Returns option labels for a SelectField listbox, or a checkbox/radio group root. */\nexport function getOptions(element: HTMLElement): string[] {\n const group = resolveOptionGroup(element);\n if (group) return getGroupOptions(group);\n\n assertListBoxInput(element);\n ensureListBoxOpen(element);\n\n const listbox = findListBox(element);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n return Array.from(options)\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n .filter((o) => !!o);\n}\n\n/** Prefer the element itself when it is a group; otherwise look for a nested group. */\nfunction resolveOptionGroup(element: HTMLElement): HTMLElement | undefined {\n if (isOptionGroup(element)) return element;\n const nested =\n element.querySelector<HTMLElement>('[role=\"radiogroup\"]') ??\n Array.from(element.querySelectorAll<HTMLElement>('[role=\"group\"]')).find(isCheckboxOrRadioGroup);\n return nested;\n}\n\nfunction isOptionGroup(element: HTMLElement): boolean {\n const role = element.getAttribute(\"role\");\n if (role === \"radiogroup\") return true;\n return role === \"group\" && isCheckboxOrRadioGroup(element);\n}\n\nfunction isCheckboxOrRadioGroup(element: HTMLElement): boolean {\n return !!element.querySelector(\"input[type=checkbox], input[type=radio]\");\n}\n\nfunction getGroupOptions(group: HTMLElement): string[] {\n const inputs = Array.from(group.querySelectorAll<HTMLInputElement>(\"input[type=radio], input[type=checkbox]\"));\n return inputs.map(getInputOptionLabel).filter((label) => !!label);\n}\n\nfunction getInputOptionLabel(input: HTMLInputElement): string {\n const ariaLabel = input.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const labelledBy = input.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy.split(/\\s+/)[0]!);\n const text = labelEl?.textContent?.trim();\n if (text) return text;\n }\n\n return input.value || \"\";\n}\n\nfunction findListBox(select: HTMLElement): HTMLElement {\n if (select.tagName === \"DIV\") fail(\"SelectField is readOnly\");\n const listboxId =\n select.getAttribute(\"aria-controls\") ||\n fail(\"aria-controls attribute not found, the SelectField is probably readOnly\");\n return document.getElementById(listboxId) || fail(\"listbox not found\");\n}\n\nfunction assertListBoxInput(select: HTMLElement): select is HTMLInputElement | HTMLTextAreaElement | HTMLButtonElement {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getOptions helper does not support <select> elements\");\n }\n // MenuSelectField's trigger is a button; the other selects type into an input.\n if (!isInputOrTextAreaElement(select) && select.nodeName !== \"BUTTON\") {\n throw new Error(\n `Expected element to be INPUT, TEXTAREA, or BUTTON, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`,\n );\n }\n return true;\n}\n\nfunction isSelectElement(element: HTMLElement): element is HTMLSelectElement {\n return element.nodeName === \"SELECT\";\n}\n\nfunction isInputOrTextAreaElement(element: HTMLElement): element is HTMLInputElement | HTMLTextAreaElement {\n return element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\";\n}\n","import type { MutableRefObject } from \"react\";\nimport type { CheckboxGroupState, ToggleState } from \"react-stately\";\n\nexport function fail(message?: string): never {\n throw new Error(message || \"Failed\");\n}\n\n/** Adapts our state to what useToggleState returns in a stateless manner. */\nexport function toToggleState(isSelected: boolean, onChange: (value: boolean) => void): ToggleState {\n return {\n isSelected,\n defaultSelected: false,\n setSelected: onChange,\n toggle: () => onChange(!isSelected),\n };\n}\n\n/** Adapts our state to what use*Group returns in a stateless manner. */\nexport function toGroupState<T extends string>(values: T[], onChange: (value: T[]) => void): CheckboxGroupState {\n const addValue = (value: T) => onChange([...values, value]);\n const removeValue = (value: T) => onChange(values.filter((_value) => _value !== value));\n\n return {\n value: values,\n defaultValue: [],\n setValue: onChange,\n isSelected: (value: T) => values.includes(value),\n addValue,\n removeValue,\n toggleValue: (value: T) => (values.includes(value) ? addValue(value) : removeValue(value)),\n isDisabled: false,\n isReadOnly: false,\n // We do not use the validation state, as our Switch groups do not support error states. However, this field is required by the `CheckboxGroupState` so we need to include it.\n // If we ever update our SwitchGroup component to support error states, we'll need to update this.\n validationState: \"valid\",\n isInvalid: false,\n isRequired: false,\n setInvalid: () => {},\n realtimeValidation: { isInvalid: false, validationErrors: [], validationDetails: {} as ValidityState },\n displayValidation: { isInvalid: false, validationErrors: [], validationDetails: {} as ValidityState },\n updateValidation: () => {},\n resetValidation: () => {},\n commitValidation: () => {},\n };\n}\n\n/**\n * Utility to maybe call a function if undefined with arguments\n *\n * @example\n * maybeCall(onChange, true)\n * maybeCall(onBlur)\n * maybeCall(onSelect, { id: 1, value: \"book 1\"}, true)\n */\nexport function maybeCall(callback: Function | undefined, ...args: any[]) {\n return callback && callback(...args);\n}\n\n/** Casts `Object.keys` to \"what it should be\", as long as your instance doesn't have keys it shouldn't. */\nexport function safeKeys<T>(instance: T): (keyof T)[] {\n return Object.getOwnPropertyNames(instance) as any;\n}\n\n// Returns object with specified key removed\nexport const omitKey = <T, K extends keyof T>(key: K, { [key]: _, ...obj }: T) => obj as T;\n\nexport const noop = (..._: any) => {};\n\ntype Entries<T> = {\n [K in keyof T]: [K, T[K]];\n}[keyof T][];\n\nexport function safeEntries<T extends object>(obj: T): Entries<T> {\n return Object.entries(obj) as any;\n}\n\nexport class EmptyRef<T> implements MutableRefObject<T> {\n get current(): T {\n throw new Error(\"BeamProvider is missing\");\n }\n\n set current(_) {\n throw new Error(\"BeamProvider is missing\");\n }\n}\n\nexport const isAbsoluteUrl = (url: string) => /^(http(s?)):\\/\\//i.test(url);\n\nexport function areArraysEqual(a: any[], b: any[]): boolean {\n return a.length === b.length && a.every((val, idx) => val === b[idx]);\n}\n\nexport function isPromise(obj: any | Promise<any>): obj is Promise<any> {\n return typeof obj === \"object\" && \"then\" in obj && typeof obj.then === \"function\";\n}\n\nexport function isFunction(f: any): f is Function {\n return typeof f === \"function\";\n}\n\nexport function isDefined<T extends any>(param: T | undefined | null): param is T {\n return param !== null && param !== undefined;\n}\n\nexport function pluralize(count: number | unknown[], noun: string, pluralNoun?: string): string {\n if ((Array.isArray(count) ? count.length : count) === 1) return noun;\n return pluralNoun || `${noun}s`;\n}\n"],"mappings":"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","names":["_blur","_change","_click","_clickAndWait","_focus","_input","_type","_typeAndWait","_wait","row","cell","select","_wait","_click"]}
@@ -80,12 +80,16 @@ ${rowsWithPaddingAndDividers.join("\n")}
80
80
  function getTextFromTableCellNode(node) {
81
81
  if (node.nodeType === Node.ELEMENT_NODE) {
82
82
  const element = node;
83
- const maybeInput = element.getElementsByTagName("input")[0];
84
- if (maybeInput) return maybeInput.value;
85
- const maybeTextarea = element.getElementsByTagName("textarea")[0];
86
- if (maybeTextarea) return maybeTextarea.value;
87
- const maybeSelect = element.getElementsByTagName("select")[0];
88
- if (maybeSelect) return maybeSelect.value;
83
+ const control = element.querySelector("input, textarea, select");
84
+ if (control) {
85
+ const rest = element.cloneNode(true);
86
+ rest.querySelectorAll("input, textarea, select").forEach((el) => {
87
+ const label = el.closest("label");
88
+ (label ?? el).remove();
89
+ });
90
+ const text = (rest.textContent ?? "").replace(/\s+/g, " ").trim();
91
+ return text ? `${control.value} ${text}` : control.value;
92
+ }
89
93
  }
90
94
  return node.textContent;
91
95
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/rtlUtils.tsx"],"sourcesContent":["import {\n blur as _blur,\n change as _change,\n click as _click,\n clickAndWait as _clickAndWait,\n focus as _focus,\n input as _input,\n type as _type,\n typeAndWait as _typeAndWait,\n wait as _wait,\n allowAndWaitForAsyncBehavior,\n type RenderResult,\n} from \"@homebound/rtl-utils\";\nimport { act, fireEvent, prettyDOM } from \"@testing-library/react\";\nimport { fail } from \"src/utils/helpers\";\n\nexport {\n _blur as blur,\n _change as change,\n _click as click,\n _clickAndWait as clickAndWait,\n _focus as focus,\n _input as input,\n _type as type,\n _typeAndWait as typeAndWait,\n _wait as wait,\n};\n\n// This file is a collection of helpers for interacting with Beam components in tests.\n// We keep it separate from the `src/tests/rtl.tsx` file, which is the Beam tests\n// themselves use, which technically does re-export these `rtlUtils.tsx` helpers, but\n// also includes other helpers that are specific to Beam's test suite.\n//\n// (In particular, we cannot include/export any Beam components, i.e. BeamProvider, from\n// this file, because it ends up as a separate bundle in the `package.json` file, which\n// will be treated as separate components/providers than the primary bundle.)\n\nexport function cell(r: RenderResult, row: number, column: number): HTMLElement {\n return cellOf(r, \"gridTable\", row, column);\n}\n\nexport function cellOf(r: RenderResult, tableTestId: string, rowNum: number, column: number): HTMLElement {\n return row(r, rowNum, tableTestId).childNodes[column] as HTMLElement;\n}\n\nexport function cellAnd(r: RenderResult, row: number, column: number, testId: string): HTMLElement {\n return (\n cell(r, row, column).querySelector(`[data-testid=\"${testId}\"]`) ||\n fail(`Element not found ${prettyDOM(cell(r, row, column))}`)\n );\n}\n\nexport function row(r: RenderResult, row: number, tableTestId: string = \"gridTable\"): HTMLElement {\n const dataRows = Array.from(r.getByTestId(tableTestId).querySelectorAll(\"[data-gridrow]\"));\n return dataRows[row] as HTMLElement;\n}\n\nexport function rowAnd(r: RenderResult, rowNum: number, testId: string): HTMLElement {\n const e = row(r, rowNum);\n return e.querySelector(`[data-testid=\"${testId}\"]`) || fail(`Element not found ${prettyDOM(e)}`);\n}\n\n/** Intended to be used to generate a human-readable text\n * representation of a GridTable using the markdown table syntax.\n * * Example Use: expect(tableSnapshot(r)).toMatchInlineSnapshot(`\n \"\n | Name | Value |\n | ------------------------ | ----- |\n | Row 1 | 200 |\n | Row 2 with a longer name | 300 |\n | Row 3 | 1000 |\n \"\n `);\n * */\nexport function tableSnapshot(r: RenderResult, columnNames: string[] = [], tableTestId: string = \"gridTable\"): string {\n const tableEl = r.getByTestId(tableTestId);\n const dataRows = Array.from(tableEl.querySelectorAll(\"[data-gridrow]\"));\n const hasExpandableHeader = !!tableEl.querySelector(`[data-testid=\"expandableColumn\"]`);\n\n let tableDataAsStrings = dataRows.map((row) => {\n return Array.from(row.childNodes).map(getTextFromTableCellNode);\n });\n\n // If the user wants a subset of columns, look for column names\n if (columnNames.length > 0) {\n const headerCells = tableDataAsStrings[0];\n if (headerCells) {\n const columnIndices = columnNames.map((name) => {\n const i = headerCells.indexOf(name);\n if (i === -1) throw new Error(`Could not find header '${name}' in ${headerCells.join(\", \")}`);\n return i;\n });\n tableDataAsStrings = tableDataAsStrings.map((row) => columnIndices.map((index) => row[index]));\n }\n }\n\n return toMarkupTableString(tableDataAsStrings, hasExpandableHeader);\n}\n\nfunction toMarkupTableString(tableRows: (string | null)[][], hasExpandableHeader: boolean): string {\n // Find the largest width of each column to set a consistent width for each row\n const columnWidths = tableRows.reduce((acc, row) => {\n row.forEach((cell, columnIndex) => {\n const cellWidth = cell?.length ?? 0;\n const currentMaxWidth = acc.get(columnIndex) ?? 0;\n if (cellWidth > currentMaxWidth || !currentMaxWidth) acc.set(columnIndex, cellWidth);\n });\n\n return acc;\n }, new Map<number, number>());\n\n const wrapTableRowEnds = (str: string) => `| ${str} |`;\n\n const rowsWithPaddingAndDividers = tableRows.map((tableCells) => {\n const formattedRow = tableCells\n .map((cell, columnIndex) => {\n const cellWidth = columnWidths.get(columnIndex) ?? 0;\n return cell?.padEnd(cellWidth, \" \") || \"\";\n })\n .join(\" | \");\n return wrapTableRowEnds(formattedRow);\n });\n\n const headerDivider = Array.from(columnWidths.values())\n .map((width) => \"-\".repeat(width) ?? \"\")\n .join(\" | \");\n\n const headerDividerRowNumber = hasExpandableHeader ? 2 : 1;\n rowsWithPaddingAndDividers.splice(headerDividerRowNumber, 0, wrapTableRowEnds(headerDivider));\n\n // Pad a newline on top and bottom for cleaner diffs\n return `\\n${rowsWithPaddingAndDividers.join(\"\\n\")}\\n`;\n}\n\n/** Prefer showing a `value` from a mocked input vs. the combined text content from an inputs markup */\nfunction getTextFromTableCellNode(node: ChildNode) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n\n const maybeInput = element.getElementsByTagName(\"input\")[0];\n if (maybeInput) return maybeInput.value;\n\n const maybeTextarea = element.getElementsByTagName(\"textarea\")[0];\n if (maybeTextarea) return maybeTextarea.value;\n\n const maybeSelect = element.getElementsByTagName(\"select\")[0];\n if (maybeSelect) return maybeSelect.value;\n }\n\n return node.textContent;\n}\n\nexport type ScrollWindowOpts = {\n clientHeight?: number;\n scrollHeight?: number;\n};\n\nexport type ScrollWindowWithAnchorOpts = ScrollWindowOpts & {\n /** getBoundingClientRect().top when scrollY is 0. Default 0. */\n anchorTop?: number;\n /** Used to derive default scrollHeight and atBottom checks. Default 1_000_000. */\n maxScroll?: number;\n /** Height of the mocked anchor element (rect height/bottom). Default 50. */\n elementHeight?: number;\n};\n\nfunction setWindowScrollMetrics(y: number, opts?: ScrollWindowOpts): void {\n Object.defineProperty(window, \"scrollY\", { value: y, configurable: true });\n if (opts?.clientHeight != null) {\n Object.defineProperty(document.documentElement, \"clientHeight\", { value: opts.clientHeight, configurable: true });\n }\n if (opts?.scrollHeight != null) {\n Object.defineProperty(document.documentElement, \"scrollHeight\", { value: opts.scrollHeight, configurable: true });\n }\n}\n\n/** Sets window.scrollY, optionally document scroll metrics, and dispatches a scroll event. */\nexport function scrollWindow(y: number, opts?: ScrollWindowOpts): void {\n setWindowScrollMetrics(y, opts);\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** scrollWindow plus a fake getBoundingClientRect on an anchor/spacer element. */\nexport function scrollWindowWithAnchor(anchor: HTMLElement, y: number, opts: ScrollWindowWithAnchorOpts = {}): void {\n const clientHeight = opts.clientHeight ?? 800;\n const maxScroll = opts.maxScroll ?? 1_000_000;\n const scrollHeight = opts.scrollHeight ?? maxScroll + clientHeight;\n const anchorTop = opts.anchorTop ?? 0;\n const elementHeight = opts.elementHeight ?? 50;\n\n setWindowScrollMetrics(y, { clientHeight, scrollHeight });\n const top = anchorTop - y;\n anchor.getBoundingClientRect = () =>\n ({\n top,\n bottom: top + elementHeight,\n left: 0,\n right: 0,\n width: 0,\n height: elementHeight,\n x: 0,\n y: top,\n toJSON() {},\n }) as DOMRect;\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** Mocks document.documentElement clientWidth/clientHeight for viewport measurement tests. */\nexport function mockDocumentViewport(width: number, height: number): void {\n Object.defineProperty(document.documentElement, \"clientWidth\", { configurable: true, get: () => width });\n Object.defineProperty(document.documentElement, \"clientHeight\", { configurable: true, get: () => height });\n}\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.\n *\n * @param value The value or label of the option.\n * */\nexport function select(select: HTMLElement, value: string | string[]) {\n assertListBoxInput(select);\n ensureListBoxOpen(select);\n const optionValues = Array.isArray(value) ? value : [value];\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n}\n\nexport type SelectAndWaitOpts = { addNew?: boolean };\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * When `value` is a single string and the listbox opens empty, types the value to trigger async\n * search before selecting. Multi-select (`value` array) assumes options are already loaded.\n *\n * When `{ addNew: true }`, types the value and selects the `Add \"<value>\"` creatable row.\n */\nexport async function selectAndWait(\n select: HTMLElement,\n value: string | string[],\n opts?: SelectAndWaitOpts,\n): Promise<void> {\n // To work with React 18, we need to execute these as separate steps, otherwise\n // the `ensureListBoxOpen` async render won't flush, and the `selectOption` will fail.\n const optionValues = Array.isArray(value) ? value : [value];\n\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (opts?.addNew) {\n if (Array.isArray(value)) {\n throw new Error(\"selectAndWait addNew option does not support multi-select\");\n }\n await typeForAddNew(select, value);\n return allowAndWaitForAsyncBehavior(() => selectOption(select, `Add \"${value.trim()}\"`));\n }\n if (!Array.isArray(value)) {\n await maybeAutoSearch(select, value);\n }\n\n return allowAndWaitForAsyncBehavior(() => {\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n });\n}\n\nasync function typeForAddNew(select: HTMLElement, value: string): Promise<void> {\n fireEvent.input(select, { target: { value } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\n/** When a combobox opens with no options, type the target label to trigger async search. */\nasync function maybeAutoSearch(select: HTMLElement, searchText: string): Promise<void> {\n if (!hasZeroOptions(select)) return;\n\n // Give lazy-load or debounced search a chance to populate options before typing.\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (!hasZeroOptions(select)) return;\n\n fireEvent.input(select, { target: { value: searchText } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\nfunction getListBoxOptions(select: HTMLElement): HTMLElement[] {\n const listbox = findListBox(select);\n return Array.from(listbox.querySelectorAll(\"[role=option]\")) as HTMLElement[];\n}\n\nfunction hasZeroOptions(select: HTMLElement): boolean {\n return getListBoxOptions(select).length === 0;\n}\n\nfunction ensureListBoxOpen(select: HTMLElement): void {\n const expanded = select.getAttribute(\"aria-expanded\") === \"true\";\n if (!expanded) {\n _click(select);\n }\n}\n\nfunction selectOption(select: HTMLElement, optionValue: string) {\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n // Allow searching for options by their data-key (value) or textContent (label)\n const optionToSelect = Array.from(options).find(\n (o: HTMLElement) => o.dataset.key === optionValue || o.dataset.label === optionValue,\n );\n if (!optionToSelect) {\n throw new Error(`Could not find option with value or text content of ${optionValue}`);\n }\n if (optionToSelect.getAttribute(\"aria-disabled\")) {\n throw new Error(`Cannot select disabled option ${optionValue}`);\n }\n _click(optionToSelect);\n}\n\nexport function getSelected(select: HTMLElement): string[] | string | undefined {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getSelected helper does not support <select> elements\");\n }\n\n if (!isInputOrTextAreaElement(select) && select.dataset.readonly === \"true\") {\n // For read-only fields that render as a 'div'\n return select.textContent ?? undefined;\n }\n\n ensureListBoxOpen(select);\n\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n const selections: string[] = Array.from(options)\n .filter((o: HTMLElement) => o.getAttribute(\"aria-selected\") === \"true\")\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n // Filter out empty strings\n .filter((o) => !!o);\n\n return selections.length > 0 ? (selections.length > 1 ? selections : selections[0]) : undefined;\n}\n\n/** Returns option labels for a SelectField listbox, or a checkbox/radio group root. */\nexport function getOptions(element: HTMLElement): string[] {\n const group = resolveOptionGroup(element);\n if (group) return getGroupOptions(group);\n\n assertListBoxInput(element);\n ensureListBoxOpen(element);\n\n const listbox = findListBox(element);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n return Array.from(options)\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n .filter((o) => !!o);\n}\n\n/** Prefer the element itself when it is a group; otherwise look for a nested group. */\nfunction resolveOptionGroup(element: HTMLElement): HTMLElement | undefined {\n if (isOptionGroup(element)) return element;\n const nested =\n element.querySelector<HTMLElement>('[role=\"radiogroup\"]') ??\n Array.from(element.querySelectorAll<HTMLElement>('[role=\"group\"]')).find(isCheckboxOrRadioGroup);\n return nested;\n}\n\nfunction isOptionGroup(element: HTMLElement): boolean {\n const role = element.getAttribute(\"role\");\n if (role === \"radiogroup\") return true;\n return role === \"group\" && isCheckboxOrRadioGroup(element);\n}\n\nfunction isCheckboxOrRadioGroup(element: HTMLElement): boolean {\n return !!element.querySelector(\"input[type=checkbox], input[type=radio]\");\n}\n\nfunction getGroupOptions(group: HTMLElement): string[] {\n const inputs = Array.from(group.querySelectorAll<HTMLInputElement>(\"input[type=radio], input[type=checkbox]\"));\n return inputs.map(getInputOptionLabel).filter((label) => !!label);\n}\n\nfunction getInputOptionLabel(input: HTMLInputElement): string {\n const ariaLabel = input.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const labelledBy = input.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy.split(/\\s+/)[0]!);\n const text = labelEl?.textContent?.trim();\n if (text) return text;\n }\n\n return input.value || \"\";\n}\n\nfunction findListBox(select: HTMLElement): HTMLElement {\n if (select.tagName === \"DIV\") fail(\"SelectField is readOnly\");\n const listboxId =\n select.getAttribute(\"aria-controls\") ||\n fail(\"aria-controls attribute not found, the SelectField is probably readOnly\");\n return document.getElementById(listboxId) || fail(\"listbox not found\");\n}\n\nfunction assertListBoxInput(select: HTMLElement): select is HTMLInputElement | HTMLTextAreaElement | HTMLButtonElement {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getOptions helper does not support <select> elements\");\n }\n // MenuSelectField's trigger is a button; the other selects type into an input.\n if (!isInputOrTextAreaElement(select) && select.nodeName !== \"BUTTON\") {\n throw new Error(\n `Expected element to be INPUT, TEXTAREA, or BUTTON, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`,\n );\n }\n return true;\n}\n\nfunction isSelectElement(element: HTMLElement): element is HTMLSelectElement {\n return element.nodeName === \"SELECT\";\n}\n\nfunction isInputOrTextAreaElement(element: HTMLElement): element is HTMLInputElement | HTMLTextAreaElement {\n return element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\";\n}\n"],"mappings":"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","names":["row","cell","select"]}
1
+ {"version":3,"sources":["../../src/utils/rtlUtils.tsx"],"sourcesContent":["import {\n blur as _blur,\n change as _change,\n click as _click,\n clickAndWait as _clickAndWait,\n focus as _focus,\n input as _input,\n type as _type,\n typeAndWait as _typeAndWait,\n wait as _wait,\n allowAndWaitForAsyncBehavior,\n type RenderResult,\n} from \"@homebound/rtl-utils\";\nimport { act, fireEvent, prettyDOM } from \"@testing-library/react\";\nimport { fail } from \"src/utils/helpers\";\n\nexport {\n _blur as blur,\n _change as change,\n _click as click,\n _clickAndWait as clickAndWait,\n _focus as focus,\n _input as input,\n _type as type,\n _typeAndWait as typeAndWait,\n _wait as wait,\n};\n\n// This file is a collection of helpers for interacting with Beam components in tests.\n// We keep it separate from the `src/tests/rtl.tsx` file, which is the Beam tests\n// themselves use, which technically does re-export these `rtlUtils.tsx` helpers, but\n// also includes other helpers that are specific to Beam's test suite.\n//\n// (In particular, we cannot include/export any Beam components, i.e. BeamProvider, from\n// this file, because it ends up as a separate bundle in the `package.json` file, which\n// will be treated as separate components/providers than the primary bundle.)\n\nexport function cell(r: RenderResult, row: number, column: number): HTMLElement {\n return cellOf(r, \"gridTable\", row, column);\n}\n\nexport function cellOf(r: RenderResult, tableTestId: string, rowNum: number, column: number): HTMLElement {\n return row(r, rowNum, tableTestId).childNodes[column] as HTMLElement;\n}\n\nexport function cellAnd(r: RenderResult, row: number, column: number, testId: string): HTMLElement {\n return (\n cell(r, row, column).querySelector(`[data-testid=\"${testId}\"]`) ||\n fail(`Element not found ${prettyDOM(cell(r, row, column))}`)\n );\n}\n\nexport function row(r: RenderResult, row: number, tableTestId: string = \"gridTable\"): HTMLElement {\n const dataRows = Array.from(r.getByTestId(tableTestId).querySelectorAll(\"[data-gridrow]\"));\n return dataRows[row] as HTMLElement;\n}\n\nexport function rowAnd(r: RenderResult, rowNum: number, testId: string): HTMLElement {\n const e = row(r, rowNum);\n return e.querySelector(`[data-testid=\"${testId}\"]`) || fail(`Element not found ${prettyDOM(e)}`);\n}\n\n/** Intended to be used to generate a human-readable text\n * representation of a GridTable using the markdown table syntax.\n * * Example Use: expect(tableSnapshot(r)).toMatchInlineSnapshot(`\n \"\n | Name | Value |\n | ------------------------ | ----- |\n | Row 1 | 200 |\n | Row 2 with a longer name | 300 |\n | Row 3 | 1000 |\n \"\n `);\n * */\nexport function tableSnapshot(r: RenderResult, columnNames: string[] = [], tableTestId: string = \"gridTable\"): string {\n const tableEl = r.getByTestId(tableTestId);\n const dataRows = Array.from(tableEl.querySelectorAll(\"[data-gridrow]\"));\n const hasExpandableHeader = !!tableEl.querySelector(`[data-testid=\"expandableColumn\"]`);\n\n let tableDataAsStrings = dataRows.map((row) => {\n return Array.from(row.childNodes).map(getTextFromTableCellNode);\n });\n\n // If the user wants a subset of columns, look for column names\n if (columnNames.length > 0) {\n const headerCells = tableDataAsStrings[0];\n if (headerCells) {\n const columnIndices = columnNames.map((name) => {\n const i = headerCells.indexOf(name);\n if (i === -1) throw new Error(`Could not find header '${name}' in ${headerCells.join(\", \")}`);\n return i;\n });\n tableDataAsStrings = tableDataAsStrings.map((row) => columnIndices.map((index) => row[index]));\n }\n }\n\n return toMarkupTableString(tableDataAsStrings, hasExpandableHeader);\n}\n\nfunction toMarkupTableString(tableRows: (string | null)[][], hasExpandableHeader: boolean): string {\n // Find the largest width of each column to set a consistent width for each row\n const columnWidths = tableRows.reduce((acc, row) => {\n row.forEach((cell, columnIndex) => {\n const cellWidth = cell?.length ?? 0;\n const currentMaxWidth = acc.get(columnIndex) ?? 0;\n if (cellWidth > currentMaxWidth || !currentMaxWidth) acc.set(columnIndex, cellWidth);\n });\n\n return acc;\n }, new Map<number, number>());\n\n const wrapTableRowEnds = (str: string) => `| ${str} |`;\n\n const rowsWithPaddingAndDividers = tableRows.map((tableCells) => {\n const formattedRow = tableCells\n .map((cell, columnIndex) => {\n const cellWidth = columnWidths.get(columnIndex) ?? 0;\n return cell?.padEnd(cellWidth, \" \") || \"\";\n })\n .join(\" | \");\n return wrapTableRowEnds(formattedRow);\n });\n\n const headerDivider = Array.from(columnWidths.values())\n .map((width) => \"-\".repeat(width) ?? \"\")\n .join(\" | \");\n\n const headerDividerRowNumber = hasExpandableHeader ? 2 : 1;\n rowsWithPaddingAndDividers.splice(headerDividerRowNumber, 0, wrapTableRowEnds(headerDivider));\n\n // Pad a newline on top and bottom for cleaner diffs\n return `\\n${rowsWithPaddingAndDividers.join(\"\\n\")}\\n`;\n}\n\n/**\n * Prefer a form control's `value` over its markup. When the control shares a cell with other\n * content (a select checkbox or collapse toggle in the same cell as a label), keep that content after the value.\n */\nfunction getTextFromTableCellNode(node: ChildNode) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const element = node as HTMLElement;\n const control = element.querySelector(\"input, textarea, select\") as\n HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement | null;\n if (control) {\n const rest = element.cloneNode(true) as HTMLElement;\n rest.querySelectorAll(\"input, textarea, select\").forEach((el) => {\n const label = el.closest(\"label\");\n (label ?? el).remove();\n });\n const text = (rest.textContent ?? \"\").replace(/\\s+/g, \" \").trim();\n return text ? `${control.value} ${text}` : control.value;\n }\n }\n\n return node.textContent;\n}\n\nexport type ScrollWindowOpts = {\n clientHeight?: number;\n scrollHeight?: number;\n};\n\nexport type ScrollWindowWithAnchorOpts = ScrollWindowOpts & {\n /** getBoundingClientRect().top when scrollY is 0. Default 0. */\n anchorTop?: number;\n /** Used to derive default scrollHeight and atBottom checks. Default 1_000_000. */\n maxScroll?: number;\n /** Height of the mocked anchor element (rect height/bottom). Default 50. */\n elementHeight?: number;\n};\n\nfunction setWindowScrollMetrics(y: number, opts?: ScrollWindowOpts): void {\n Object.defineProperty(window, \"scrollY\", { value: y, configurable: true });\n if (opts?.clientHeight != null) {\n Object.defineProperty(document.documentElement, \"clientHeight\", { value: opts.clientHeight, configurable: true });\n }\n if (opts?.scrollHeight != null) {\n Object.defineProperty(document.documentElement, \"scrollHeight\", { value: opts.scrollHeight, configurable: true });\n }\n}\n\n/** Sets window.scrollY, optionally document scroll metrics, and dispatches a scroll event. */\nexport function scrollWindow(y: number, opts?: ScrollWindowOpts): void {\n setWindowScrollMetrics(y, opts);\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** scrollWindow plus a fake getBoundingClientRect on an anchor/spacer element. */\nexport function scrollWindowWithAnchor(anchor: HTMLElement, y: number, opts: ScrollWindowWithAnchorOpts = {}): void {\n const clientHeight = opts.clientHeight ?? 800;\n const maxScroll = opts.maxScroll ?? 1_000_000;\n const scrollHeight = opts.scrollHeight ?? maxScroll + clientHeight;\n const anchorTop = opts.anchorTop ?? 0;\n const elementHeight = opts.elementHeight ?? 50;\n\n setWindowScrollMetrics(y, { clientHeight, scrollHeight });\n const top = anchorTop - y;\n anchor.getBoundingClientRect = () =>\n ({\n top,\n bottom: top + elementHeight,\n left: 0,\n right: 0,\n width: 0,\n height: elementHeight,\n x: 0,\n y: top,\n toJSON() {},\n }) as DOMRect;\n act(() => {\n window.dispatchEvent(new Event(\"scroll\"));\n });\n}\n\n/** Mocks document.documentElement clientWidth/clientHeight for viewport measurement tests. */\nexport function mockDocumentViewport(width: number, height: number): void {\n Object.defineProperty(document.documentElement, \"clientWidth\", { configurable: true, get: () => width });\n Object.defineProperty(document.documentElement, \"clientHeight\", { configurable: true, get: () => height });\n}\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * For select fields that support multiple selections, subsequent calls to this function will toggle the selection state of an option.\n *\n * @param value The value or label of the option.\n * */\nexport function select(select: HTMLElement, value: string | string[]) {\n assertListBoxInput(select);\n ensureListBoxOpen(select);\n const optionValues = Array.isArray(value) ? value : [value];\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n}\n\nexport type SelectAndWaitOpts = { addNew?: boolean };\n\n/**\n * Selects an option from the Beam SelectField, MultiSelectField, and TreeSelectField components.\n *\n * When `value` is a single string and the listbox opens empty, types the value to trigger async\n * search before selecting. Multi-select (`value` array) assumes options are already loaded.\n *\n * When `{ addNew: true }`, types the value and selects the `Add \"<value>\"` creatable row.\n */\nexport async function selectAndWait(\n select: HTMLElement,\n value: string | string[],\n opts?: SelectAndWaitOpts,\n): Promise<void> {\n // To work with React 18, we need to execute these as separate steps, otherwise\n // the `ensureListBoxOpen` async render won't flush, and the `selectOption` will fail.\n const optionValues = Array.isArray(value) ? value : [value];\n\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (opts?.addNew) {\n if (Array.isArray(value)) {\n throw new Error(\"selectAndWait addNew option does not support multi-select\");\n }\n await typeForAddNew(select, value);\n return allowAndWaitForAsyncBehavior(() => selectOption(select, `Add \"${value.trim()}\"`));\n }\n if (!Array.isArray(value)) {\n await maybeAutoSearch(select, value);\n }\n\n return allowAndWaitForAsyncBehavior(() => {\n optionValues.forEach((optionValue) => selectOption(select, optionValue));\n });\n}\n\nasync function typeForAddNew(select: HTMLElement, value: string): Promise<void> {\n fireEvent.input(select, { target: { value } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\n/** When a combobox opens with no options, type the target label to trigger async search. */\nasync function maybeAutoSearch(select: HTMLElement, searchText: string): Promise<void> {\n if (!hasZeroOptions(select)) return;\n\n // Give lazy-load or debounced search a chance to populate options before typing.\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n if (!hasZeroOptions(select)) return;\n\n fireEvent.input(select, { target: { value: searchText } });\n await _wait();\n await allowAndWaitForAsyncBehavior(() => ensureListBoxOpen(select));\n}\n\nfunction getListBoxOptions(select: HTMLElement): HTMLElement[] {\n const listbox = findListBox(select);\n return Array.from(listbox.querySelectorAll(\"[role=option]\")) as HTMLElement[];\n}\n\nfunction hasZeroOptions(select: HTMLElement): boolean {\n return getListBoxOptions(select).length === 0;\n}\n\nfunction ensureListBoxOpen(select: HTMLElement): void {\n const expanded = select.getAttribute(\"aria-expanded\") === \"true\";\n if (!expanded) {\n _click(select);\n }\n}\n\nfunction selectOption(select: HTMLElement, optionValue: string) {\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n // Allow searching for options by their data-key (value) or textContent (label)\n const optionToSelect = Array.from(options).find(\n (o: HTMLElement) => o.dataset.key === optionValue || o.dataset.label === optionValue,\n );\n if (!optionToSelect) {\n throw new Error(`Could not find option with value or text content of ${optionValue}`);\n }\n if (optionToSelect.getAttribute(\"aria-disabled\")) {\n throw new Error(`Cannot select disabled option ${optionValue}`);\n }\n _click(optionToSelect);\n}\n\nexport function getSelected(select: HTMLElement): string[] | string | undefined {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getSelected helper does not support <select> elements\");\n }\n\n if (!isInputOrTextAreaElement(select) && select.dataset.readonly === \"true\") {\n // For read-only fields that render as a 'div'\n return select.textContent ?? undefined;\n }\n\n ensureListBoxOpen(select);\n\n const listbox = findListBox(select);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n const selections: string[] = Array.from(options)\n .filter((o: HTMLElement) => o.getAttribute(\"aria-selected\") === \"true\")\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n // Filter out empty strings\n .filter((o) => !!o);\n\n return selections.length > 0 ? (selections.length > 1 ? selections : selections[0]) : undefined;\n}\n\n/** Returns option labels for a SelectField listbox, or a checkbox/radio group root. */\nexport function getOptions(element: HTMLElement): string[] {\n const group = resolveOptionGroup(element);\n if (group) return getGroupOptions(group);\n\n assertListBoxInput(element);\n ensureListBoxOpen(element);\n\n const listbox = findListBox(element);\n const options: NodeListOf<HTMLElement> = listbox.querySelectorAll(\"[role=option]\");\n\n return Array.from(options)\n .map((o: HTMLElement) => o.dataset.label ?? o.dataset.key ?? \"\")\n .filter((o) => !!o);\n}\n\n/** Prefer the element itself when it is a group; otherwise look for a nested group. */\nfunction resolveOptionGroup(element: HTMLElement): HTMLElement | undefined {\n if (isOptionGroup(element)) return element;\n const nested =\n element.querySelector<HTMLElement>('[role=\"radiogroup\"]') ??\n Array.from(element.querySelectorAll<HTMLElement>('[role=\"group\"]')).find(isCheckboxOrRadioGroup);\n return nested;\n}\n\nfunction isOptionGroup(element: HTMLElement): boolean {\n const role = element.getAttribute(\"role\");\n if (role === \"radiogroup\") return true;\n return role === \"group\" && isCheckboxOrRadioGroup(element);\n}\n\nfunction isCheckboxOrRadioGroup(element: HTMLElement): boolean {\n return !!element.querySelector(\"input[type=checkbox], input[type=radio]\");\n}\n\nfunction getGroupOptions(group: HTMLElement): string[] {\n const inputs = Array.from(group.querySelectorAll<HTMLInputElement>(\"input[type=radio], input[type=checkbox]\"));\n return inputs.map(getInputOptionLabel).filter((label) => !!label);\n}\n\nfunction getInputOptionLabel(input: HTMLInputElement): string {\n const ariaLabel = input.getAttribute(\"aria-label\");\n if (ariaLabel) return ariaLabel;\n\n const labelledBy = input.getAttribute(\"aria-labelledby\");\n if (labelledBy) {\n const labelEl = document.getElementById(labelledBy.split(/\\s+/)[0]!);\n const text = labelEl?.textContent?.trim();\n if (text) return text;\n }\n\n return input.value || \"\";\n}\n\nfunction findListBox(select: HTMLElement): HTMLElement {\n if (select.tagName === \"DIV\") fail(\"SelectField is readOnly\");\n const listboxId =\n select.getAttribute(\"aria-controls\") ||\n fail(\"aria-controls attribute not found, the SelectField is probably readOnly\");\n return document.getElementById(listboxId) || fail(\"listbox not found\");\n}\n\nfunction assertListBoxInput(select: HTMLElement): select is HTMLInputElement | HTMLTextAreaElement | HTMLButtonElement {\n if (isSelectElement(select)) {\n throw new Error(\"Beam getOptions helper does not support <select> elements\");\n }\n // MenuSelectField's trigger is a button; the other selects type into an input.\n if (!isInputOrTextAreaElement(select) && select.nodeName !== \"BUTTON\") {\n throw new Error(\n `Expected element to be INPUT, TEXTAREA, or BUTTON, but got ${select.nodeName}. This field may be read-only. In that case we cannot get the list of options`,\n );\n }\n return true;\n}\n\nfunction isSelectElement(element: HTMLElement): element is HTMLSelectElement {\n return element.nodeName === \"SELECT\";\n}\n\nfunction isInputOrTextAreaElement(element: HTMLElement): element is HTMLInputElement | HTMLTextAreaElement {\n return element.nodeName === \"INPUT\" || element.nodeName === \"TEXTAREA\";\n}\n"],"mappings":";;;;;AAAA;AAAA,EACE,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,eAAe;AAAA,EACf,QAAQ;AAAA,EACR;AAAA,OAEK;AACP,SAAS,KAAK,WAAW,iBAAiB;AAwBnC,SAAS,KAAK,GAAiBA,MAAa,QAA6B;AAC9E,SAAO,OAAO,GAAG,aAAaA,MAAK,MAAM;AAC3C;AAEO,SAAS,OAAO,GAAiB,aAAqB,QAAgB,QAA6B;AACxG,SAAO,IAAI,GAAG,QAAQ,WAAW,EAAE,WAAW,MAAM;AACtD;AAEO,SAAS,QAAQ,GAAiBA,MAAa,QAAgB,QAA6B;AACjG,SACE,KAAK,GAAGA,MAAK,MAAM,EAAE,cAAc,iBAAiB,MAAM,IAAI,KAC9D,KAAK,qBAAqB,UAAU,KAAK,GAAGA,MAAK,MAAM,CAAC,CAAC,EAAE;AAE/D;AAEO,SAAS,IAAI,GAAiBA,MAAa,cAAsB,aAA0B;AAChG,QAAM,WAAW,MAAM,KAAK,EAAE,YAAY,WAAW,EAAE,iBAAiB,gBAAgB,CAAC;AACzF,SAAO,SAASA,IAAG;AACrB;AAEO,SAAS,OAAO,GAAiB,QAAgB,QAA6B;AACnF,QAAM,IAAI,IAAI,GAAG,MAAM;AACvB,SAAO,EAAE,cAAc,iBAAiB,MAAM,IAAI,KAAK,KAAK,qBAAqB,UAAU,CAAC,CAAC,EAAE;AACjG;AAcO,SAAS,cAAc,GAAiB,cAAwB,CAAC,GAAG,cAAsB,aAAqB;AACpH,QAAM,UAAU,EAAE,YAAY,WAAW;AACzC,QAAM,WAAW,MAAM,KAAK,QAAQ,iBAAiB,gBAAgB,CAAC;AACtE,QAAM,sBAAsB,CAAC,CAAC,QAAQ,cAAc,kCAAkC;AAEtF,MAAI,qBAAqB,SAAS,IAAI,CAACA,SAAQ;AAC7C,WAAO,MAAM,KAAKA,KAAI,UAAU,EAAE,IAAI,wBAAwB;AAAA,EAChE,CAAC;AAGD,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,cAAc,mBAAmB,CAAC;AACxC,QAAI,aAAa;AACf,YAAM,gBAAgB,YAAY,IAAI,CAAC,SAAS;AAC9C,cAAM,IAAI,YAAY,QAAQ,IAAI;AAClC,YAAI,MAAM,GAAI,OAAM,IAAI,MAAM,0BAA0B,IAAI,QAAQ,YAAY,KAAK,IAAI,CAAC,EAAE;AAC5F,eAAO;AAAA,MACT,CAAC;AACD,2BAAqB,mBAAmB,IAAI,CAACA,SAAQ,cAAc,IAAI,CAAC,UAAUA,KAAI,KAAK,CAAC,CAAC;AAAA,IAC/F;AAAA,EACF;AAEA,SAAO,oBAAoB,oBAAoB,mBAAmB;AACpE;AAEA,SAAS,oBAAoB,WAAgC,qBAAsC;AAEjG,QAAM,eAAe,UAAU,OAAO,CAAC,KAAKA,SAAQ;AAClD,IAAAA,KAAI,QAAQ,CAACC,OAAM,gBAAgB;AACjC,YAAM,YAAYA,OAAM,UAAU;AAClC,YAAM,kBAAkB,IAAI,IAAI,WAAW,KAAK;AAChD,UAAI,YAAY,mBAAmB,CAAC,gBAAiB,KAAI,IAAI,aAAa,SAAS;AAAA,IACrF,CAAC;AAED,WAAO;AAAA,EACT,GAAG,oBAAI,IAAoB,CAAC;AAE5B,QAAM,mBAAmB,CAAC,QAAgB,KAAK,GAAG;AAElD,QAAM,6BAA6B,UAAU,IAAI,CAAC,eAAe;AAC/D,UAAM,eAAe,WAClB,IAAI,CAACA,OAAM,gBAAgB;AAC1B,YAAM,YAAY,aAAa,IAAI,WAAW,KAAK;AACnD,aAAOA,OAAM,OAAO,WAAW,GAAG,KAAK;AAAA,IACzC,CAAC,EACA,KAAK,KAAK;AACb,WAAO,iBAAiB,YAAY;AAAA,EACtC,CAAC;AAED,QAAM,gBAAgB,MAAM,KAAK,aAAa,OAAO,CAAC,EACnD,IAAI,CAAC,UAAU,IAAI,OAAO,KAAK,KAAK,EAAE,EACtC,KAAK,KAAK;AAEb,QAAM,yBAAyB,sBAAsB,IAAI;AACzD,6BAA2B,OAAO,wBAAwB,GAAG,iBAAiB,aAAa,CAAC;AAG5F,SAAO;AAAA,EAAK,2BAA2B,KAAK,IAAI,CAAC;AAAA;AACnD;AAMA,SAAS,yBAAyB,MAAiB;AACjD,MAAI,KAAK,aAAa,KAAK,cAAc;AACvC,UAAM,UAAU;AAChB,UAAM,UAAU,QAAQ,cAAc,yBAAyB;AAE/D,QAAI,SAAS;AACX,YAAM,OAAO,QAAQ,UAAU,IAAI;AACnC,WAAK,iBAAiB,yBAAyB,EAAE,QAAQ,CAAC,OAAO;AAC/D,cAAM,QAAQ,GAAG,QAAQ,OAAO;AAChC,SAAC,SAAS,IAAI,OAAO;AAAA,MACvB,CAAC;AACD,YAAM,QAAQ,KAAK,eAAe,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAChE,aAAO,OAAO,GAAG,QAAQ,KAAK,IAAI,IAAI,KAAK,QAAQ;AAAA,IACrD;AAAA,EACF;AAEA,SAAO,KAAK;AACd;AAgBA,SAAS,uBAAuB,GAAW,MAA+B;AACxE,SAAO,eAAe,QAAQ,WAAW,EAAE,OAAO,GAAG,cAAc,KAAK,CAAC;AACzE,MAAI,MAAM,gBAAgB,MAAM;AAC9B,WAAO,eAAe,SAAS,iBAAiB,gBAAgB,EAAE,OAAO,KAAK,cAAc,cAAc,KAAK,CAAC;AAAA,EAClH;AACA,MAAI,MAAM,gBAAgB,MAAM;AAC9B,WAAO,eAAe,SAAS,iBAAiB,gBAAgB,EAAE,OAAO,KAAK,cAAc,cAAc,KAAK,CAAC;AAAA,EAClH;AACF;AAGO,SAAS,aAAa,GAAW,MAA+B;AACrE,yBAAuB,GAAG,IAAI;AAC9B,MAAI,MAAM;AACR,WAAO,cAAc,IAAI,MAAM,QAAQ,CAAC;AAAA,EAC1C,CAAC;AACH;AAGO,SAAS,uBAAuB,QAAqB,GAAW,OAAmC,CAAC,GAAS;AAClH,QAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,eAAe,KAAK,gBAAgB,YAAY;AACtD,QAAM,YAAY,KAAK,aAAa;AACpC,QAAM,gBAAgB,KAAK,iBAAiB;AAE5C,yBAAuB,GAAG,EAAE,cAAc,aAAa,CAAC;AACxD,QAAM,MAAM,YAAY;AACxB,SAAO,wBAAwB,OAC5B;AAAA,IACC;AAAA,IACA,QAAQ,MAAM;AAAA,IACd,MAAM;AAAA,IACN,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,GAAG;AAAA,IACH,GAAG;AAAA,IACH,SAAS;AAAA,IAAC;AAAA,EACZ;AACF,MAAI,MAAM;AACR,WAAO,cAAc,IAAI,MAAM,QAAQ,CAAC;AAAA,EAC1C,CAAC;AACH;AAGO,SAAS,qBAAqB,OAAe,QAAsB;AACxE,SAAO,eAAe,SAAS,iBAAiB,eAAe,EAAE,cAAc,MAAM,KAAK,MAAM,MAAM,CAAC;AACvG,SAAO,eAAe,SAAS,iBAAiB,gBAAgB,EAAE,cAAc,MAAM,KAAK,MAAM,OAAO,CAAC;AAC3G;AASO,SAAS,OAAOC,SAAqB,OAA0B;AACpE,qBAAmBA,OAAM;AACzB,oBAAkBA,OAAM;AACxB,QAAM,eAAe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAC1D,eAAa,QAAQ,CAAC,gBAAgB,aAAaA,SAAQ,WAAW,CAAC;AACzE;AAYA,eAAsB,cACpBA,SACA,OACA,MACe;AAGf,QAAM,eAAe,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AAE1D,QAAM,6BAA6B,MAAM,kBAAkBA,OAAM,CAAC;AAClE,MAAI,MAAM,QAAQ;AAChB,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,IAAI,MAAM,2DAA2D;AAAA,IAC7E;AACA,UAAM,cAAcA,SAAQ,KAAK;AACjC,WAAO,6BAA6B,MAAM,aAAaA,SAAQ,QAAQ,MAAM,KAAK,CAAC,GAAG,CAAC;AAAA,EACzF;AACA,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,UAAM,gBAAgBA,SAAQ,KAAK;AAAA,EACrC;AAEA,SAAO,6BAA6B,MAAM;AACxC,iBAAa,QAAQ,CAAC,gBAAgB,aAAaA,SAAQ,WAAW,CAAC;AAAA,EACzE,CAAC;AACH;AAEA,eAAe,cAAcA,SAAqB,OAA8B;AAC9E,YAAU,MAAMA,SAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC7C,QAAM,MAAM;AACZ,QAAM,6BAA6B,MAAM,kBAAkBA,OAAM,CAAC;AACpE;AAGA,eAAe,gBAAgBA,SAAqB,YAAmC;AACrF,MAAI,CAAC,eAAeA,OAAM,EAAG;AAG7B,QAAM,MAAM;AACZ,QAAM,6BAA6B,MAAM,kBAAkBA,OAAM,CAAC;AAClE,MAAI,CAAC,eAAeA,OAAM,EAAG;AAE7B,YAAU,MAAMA,SAAQ,EAAE,QAAQ,EAAE,OAAO,WAAW,EAAE,CAAC;AACzD,QAAM,MAAM;AACZ,QAAM,6BAA6B,MAAM,kBAAkBA,OAAM,CAAC;AACpE;AAEA,SAAS,kBAAkBA,SAAoC;AAC7D,QAAM,UAAU,YAAYA,OAAM;AAClC,SAAO,MAAM,KAAK,QAAQ,iBAAiB,eAAe,CAAC;AAC7D;AAEA,SAAS,eAAeA,SAA8B;AACpD,SAAO,kBAAkBA,OAAM,EAAE,WAAW;AAC9C;AAEA,SAAS,kBAAkBA,SAA2B;AACpD,QAAM,WAAWA,QAAO,aAAa,eAAe,MAAM;AAC1D,MAAI,CAAC,UAAU;AACb,WAAOA,OAAM;AAAA,EACf;AACF;AAEA,SAAS,aAAaA,SAAqB,aAAqB;AAC9D,QAAM,UAAU,YAAYA,OAAM;AAClC,QAAM,UAAmC,QAAQ,iBAAiB,eAAe;AAEjF,QAAM,iBAAiB,MAAM,KAAK,OAAO,EAAE;AAAA,IACzC,CAAC,MAAmB,EAAE,QAAQ,QAAQ,eAAe,EAAE,QAAQ,UAAU;AAAA,EAC3E;AACA,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI,MAAM,uDAAuD,WAAW,EAAE;AAAA,EACtF;AACA,MAAI,eAAe,aAAa,eAAe,GAAG;AAChD,UAAM,IAAI,MAAM,iCAAiC,WAAW,EAAE;AAAA,EAChE;AACA,SAAO,cAAc;AACvB;AAEO,SAAS,YAAYA,SAAoD;AAC9E,MAAI,gBAAgBA,OAAM,GAAG;AAC3B,UAAM,IAAI,MAAM,4DAA4D;AAAA,EAC9E;AAEA,MAAI,CAAC,yBAAyBA,OAAM,KAAKA,QAAO,QAAQ,aAAa,QAAQ;AAE3E,WAAOA,QAAO,eAAe;AAAA,EAC/B;AAEA,oBAAkBA,OAAM;AAExB,QAAM,UAAU,YAAYA,OAAM;AAClC,QAAM,UAAmC,QAAQ,iBAAiB,eAAe;AAEjF,QAAM,aAAuB,MAAM,KAAK,OAAO,EAC5C,OAAO,CAAC,MAAmB,EAAE,aAAa,eAAe,MAAM,MAAM,EACrE,IAAI,CAAC,MAAmB,EAAE,QAAQ,SAAS,EAAE,QAAQ,OAAO,EAAE,EAE9D,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AAEpB,SAAO,WAAW,SAAS,IAAK,WAAW,SAAS,IAAI,aAAa,WAAW,CAAC,IAAK;AACxF;AAGO,SAAS,WAAW,SAAgC;AACzD,QAAM,QAAQ,mBAAmB,OAAO;AACxC,MAAI,MAAO,QAAO,gBAAgB,KAAK;AAEvC,qBAAmB,OAAO;AAC1B,oBAAkB,OAAO;AAEzB,QAAM,UAAU,YAAY,OAAO;AACnC,QAAM,UAAmC,QAAQ,iBAAiB,eAAe;AAEjF,SAAO,MAAM,KAAK,OAAO,EACtB,IAAI,CAAC,MAAmB,EAAE,QAAQ,SAAS,EAAE,QAAQ,OAAO,EAAE,EAC9D,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;AACtB;AAGA,SAAS,mBAAmB,SAA+C;AACzE,MAAI,cAAc,OAAO,EAAG,QAAO;AACnC,QAAM,SACJ,QAAQ,cAA2B,qBAAqB,KACxD,MAAM,KAAK,QAAQ,iBAA8B,gBAAgB,CAAC,EAAE,KAAK,sBAAsB;AACjG,SAAO;AACT;AAEA,SAAS,cAAc,SAA+B;AACpD,QAAM,OAAO,QAAQ,aAAa,MAAM;AACxC,MAAI,SAAS,aAAc,QAAO;AAClC,SAAO,SAAS,WAAW,uBAAuB,OAAO;AAC3D;AAEA,SAAS,uBAAuB,SAA+B;AAC7D,SAAO,CAAC,CAAC,QAAQ,cAAc,yCAAyC;AAC1E;AAEA,SAAS,gBAAgB,OAA8B;AACrD,QAAM,SAAS,MAAM,KAAK,MAAM,iBAAmC,yCAAyC,CAAC;AAC7G,SAAO,OAAO,IAAI,mBAAmB,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,KAAK;AAClE;AAEA,SAAS,oBAAoB,OAAiC;AAC5D,QAAM,YAAY,MAAM,aAAa,YAAY;AACjD,MAAI,UAAW,QAAO;AAEtB,QAAM,aAAa,MAAM,aAAa,iBAAiB;AACvD,MAAI,YAAY;AACd,UAAM,UAAU,SAAS,eAAe,WAAW,MAAM,KAAK,EAAE,CAAC,CAAE;AACnE,UAAM,OAAO,SAAS,aAAa,KAAK;AACxC,QAAI,KAAM,QAAO;AAAA,EACnB;AAEA,SAAO,MAAM,SAAS;AACxB;AAEA,SAAS,YAAYA,SAAkC;AACrD,MAAIA,QAAO,YAAY,MAAO,MAAK,yBAAyB;AAC5D,QAAM,YACJA,QAAO,aAAa,eAAe,KACnC,KAAK,yEAAyE;AAChF,SAAO,SAAS,eAAe,SAAS,KAAK,KAAK,mBAAmB;AACvE;AAEA,SAAS,mBAAmBA,SAA2F;AACrH,MAAI,gBAAgBA,OAAM,GAAG;AAC3B,UAAM,IAAI,MAAM,2DAA2D;AAAA,EAC7E;AAEA,MAAI,CAAC,yBAAyBA,OAAM,KAAKA,QAAO,aAAa,UAAU;AACrE,UAAM,IAAI;AAAA,MACR,8DAA8DA,QAAO,QAAQ;AAAA,IAC/E;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,SAAoD;AAC3E,SAAO,QAAQ,aAAa;AAC9B;AAEA,SAAS,yBAAyB,SAAyE;AACzG,SAAO,QAAQ,aAAa,WAAW,QAAQ,aAAa;AAC9D;","names":["row","cell","select"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "4.46.1",
3
+ "version": "4.47.1",
4
4
  "type": "module",
5
5
  "author": "Homebound",
6
6
  "license": "MIT",