diff --git a/.prettierrc.js b/.prettierrc.js index 4debec222..a4c6134fc 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,4 +1,5 @@ module.exports = { + plugins: ["prettier-plugin-organize-imports"], trailingComma: "all", printWidth: 120, }; diff --git a/package.json b/package.json index 19cb939e4..02e7473c8 100644 --- a/package.json +++ b/package.json @@ -118,8 +118,8 @@ "jest-watch-typeahead": "^2.2.2", "mobx": "^6.10.2", "mobx-react": "^9.0.1", - "prettier": "^3.0.3", - "prettier-plugin-organize-imports": "^3.2.3", + "prettier": "^3.3.3", + "prettier-plugin-organize-imports": "^4.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", "semantic-release": "^20.1.0", diff --git a/src/components/ButtonDatePicker.tsx b/src/components/ButtonDatePicker.tsx index 551143bdd..078037371 100644 --- a/src/components/ButtonDatePicker.tsx +++ b/src/components/ButtonDatePicker.tsx @@ -30,10 +30,10 @@ export function ButtonDatePicker(props: ButtonDatePickerProps) { isTextButton(trigger) ? defaultTestId(labelOr(trigger, "buttonDatePicker")) : isNavLinkButton(trigger) - ? defaultTestId(trigger.navLabel) - : isIconButton(trigger) - ? trigger.icon - : trigger.name, + ? defaultTestId(trigger.navLabel) + : isIconButton(trigger) + ? trigger.icon + : trigger.name, ); return ( diff --git a/src/components/ButtonMenu.tsx b/src/components/ButtonMenu.tsx index 539d1214d..13592dc77 100644 --- a/src/components/ButtonMenu.tsx +++ b/src/components/ButtonMenu.tsx @@ -47,10 +47,10 @@ export function ButtonMenu(props: ButtonMenuBaseProps | SelectionButtonMenuProps isTextButton(trigger) ? labelOr(trigger, "buttonMenu") : isNavLinkButton(trigger) - ? defaultTestId(trigger.navLabel) - : isIconButton(trigger) - ? trigger.icon - : trigger.name, + ? defaultTestId(trigger.navLabel) + : isIconButton(trigger) + ? trigger.icon + : trigger.name, ); return ( diff --git a/src/components/ButtonModal.tsx b/src/components/ButtonModal.tsx index 82cfa7948..0cf5132f7 100644 --- a/src/components/ButtonModal.tsx +++ b/src/components/ButtonModal.tsx @@ -33,10 +33,10 @@ export function ButtonModal(props: ButtonModalProps) { isTextButton(trigger) ? labelOr(trigger, "buttonModal") : isNavLinkButton(trigger) - ? defaultTestId(trigger.navLabel) - : isIconButton(trigger) - ? trigger.icon - : trigger.name, + ? defaultTestId(trigger.navLabel) + : isIconButton(trigger) + ? trigger.icon + : trigger.name, ); return ( diff --git a/src/components/Chip.tsx b/src/components/Chip.tsx index 66fb5bdbf..bbc3f7fd0 100644 --- a/src/components/Chip.tsx +++ b/src/components/Chip.tsx @@ -1,9 +1,9 @@ import { ReactNode } from "react"; +import { Icon, IconKey } from "src/components/Icon"; import { usePresentationContext } from "src/components/PresentationContext"; import { maybeTooltip } from "src/components/Tooltip"; import { Css, Margin, Only, Properties, Xss } from "src/Css"; import { useTestIds } from "src/utils/useTestIds"; -import { Icon, IconKey } from "src/components/Icon"; export type ChipType = "caution" | "warning" | "success" | "light" | "dark" | "neutral" | "darkMode" | "info"; diff --git a/src/components/Filters/DateRangeFilter.tsx b/src/components/Filters/DateRangeFilter.tsx index 6e14557f5..d725d8c33 100644 --- a/src/components/Filters/DateRangeFilter.tsx +++ b/src/components/Filters/DateRangeFilter.tsx @@ -2,7 +2,7 @@ import { Matcher } from "react-day-picker"; import { BaseFilter } from "src/components/Filters/BaseFilter"; import { Filter } from "src/components/Filters/types"; import { Label } from "src/components/Label"; -import { DateRangeField, Value } from "src/inputs"; +import { DateRangeField } from "src/inputs"; import { DateRange } from "src/types"; import { TestIds } from "src/utils"; import { defaultTestId } from "src/utils/defaultTestId"; diff --git a/src/components/Filters/MultiFilter.stories.tsx b/src/components/Filters/MultiFilter.stories.tsx index b9fbf31f8..4ed77e533 100644 --- a/src/components/Filters/MultiFilter.stories.tsx +++ b/src/components/Filters/MultiFilter.stories.tsx @@ -1,9 +1,9 @@ import { Meta } from "@storybook/react"; +import { useState } from "react"; import { stageFilter, stageFilterDisabledOptions } from "src/components/Filters/testDomain"; import { Filters, multiFilter } from "src/components/index"; import { HasIdAndName } from "src/types"; import { zeroTo } from "src/utils/sb"; -import { useState } from "react"; export default { component: Filters, diff --git a/src/components/Filters/SingleFilter.tsx b/src/components/Filters/SingleFilter.tsx index 9174c8e8b..4c7687e02 100644 --- a/src/components/Filters/SingleFilter.tsx +++ b/src/components/Filters/SingleFilter.tsx @@ -44,7 +44,7 @@ class SingleFilter extends BaseFilter (o === allOption ? (undefined as any as V) : getOptionValue(o))} - getOptionLabel={(o) => (o === allOption ? nothingSelectedText ?? "All" : getOptionLabel(o))} + getOptionLabel={(o) => (o === allOption ? (nothingSelectedText ?? "All") : getOptionLabel(o))} compact={!vertical} value={value} label={this.label} diff --git a/src/components/Filters/index.ts b/src/components/Filters/index.ts index 5c99813c8..de9a306bc 100644 --- a/src/components/Filters/index.ts +++ b/src/components/Filters/index.ts @@ -6,6 +6,7 @@ export { multiFilter } from "src/components/Filters/MultiFilter"; export { numberRangeFilter } from "src/components/Filters/NumberRangeFilter"; export { singleFilter } from "src/components/Filters/SingleFilter"; export { treeFilter } from "src/components/Filters/TreeFilter"; +export { BaseFilter } from "./BaseFilter"; export { booleanFilter } from "./BooleanFilter"; export { checkboxFilter } from "./CheckboxFilter"; export * from "./FilterModal"; @@ -13,4 +14,3 @@ export * from "./Filters"; export { toggleFilter } from "./ToggleFilter"; export * from "./types"; export * from "./utils"; -export { BaseFilter } from "./BaseFilter"; diff --git a/src/components/Label.tsx b/src/components/Label.tsx index 8f20f5a48..d77ca14cd 100644 --- a/src/components/Label.tsx +++ b/src/components/Label.tsx @@ -1,7 +1,7 @@ import React, { LabelHTMLAttributes, ReactNode } from "react"; import { VisuallyHidden } from "react-aria"; -import { Css, Font, Only, Palette, Xss } from "src/Css"; import { Icon } from "src"; +import { Css, Font, Only, Palette, Xss } from "src/Css"; type LabelXss = Font | "color"; diff --git a/src/components/MaxLines.stories.tsx b/src/components/MaxLines.stories.tsx index 9bad1d69f..e613f5503 100644 --- a/src/components/MaxLines.stories.tsx +++ b/src/components/MaxLines.stories.tsx @@ -1,6 +1,6 @@ -import { MaxLines } from "src/components/MaxLines"; -import { Button, Css } from "src"; import { useMemo, useState } from "react"; +import { Button, Css } from "src"; +import { MaxLines } from "src/components/MaxLines"; export default { component: MaxLines, diff --git a/src/components/MaxLines.tsx b/src/components/MaxLines.tsx index 03066efd5..4685ae267 100644 --- a/src/components/MaxLines.tsx +++ b/src/components/MaxLines.tsx @@ -1,6 +1,6 @@ -import { Css } from "src"; -import { PropsWithChildren, useCallback, useEffect, useRef, useState } from "react"; import { useLayoutEffect, useResizeObserver } from "@react-aria/utils"; +import { PropsWithChildren, useCallback, useEffect, useRef, useState } from "react"; +import { Css } from "src"; export type MaxLinesProps = PropsWithChildren<{ maxLines: number; diff --git a/src/components/Modal/Modal.tsx b/src/components/Modal/Modal.tsx index f6038e361..dcb12ed9a 100644 --- a/src/components/Modal/Modal.tsx +++ b/src/components/Modal/Modal.tsx @@ -7,9 +7,9 @@ import { useBeamContext } from "src/components/BeamContext"; import { IconButton } from "src/components/IconButton"; import { useModal as ourUseModal } from "src/components/Modal/useModal"; import { Css, Only, Xss } from "src/Css"; +import { useBreakpoint } from "src/hooks"; import { useTestIds } from "src/utils"; import { ModalProvider } from "./ModalContext"; -import { useBreakpoint } from "src/hooks"; export type ModalSize = "sm" | "md" | "lg" | "xl" | "xxl"; diff --git a/src/components/Modal/ModalContext.tsx b/src/components/Modal/ModalContext.tsx index a6ae167e1..66eb15988 100644 --- a/src/components/Modal/ModalContext.tsx +++ b/src/components/Modal/ModalContext.tsx @@ -1,4 +1,4 @@ -import { ReactNode, createContext, useContext, useMemo } from "react"; +import { createContext, ReactNode, useContext, useMemo } from "react"; interface ModalContextState { inModal: boolean; diff --git a/src/components/Table/GridTableApi.ts b/src/components/Table/GridTableApi.ts index c382a72c9..d4b3360bd 100644 --- a/src/components/Table/GridTableApi.ts +++ b/src/components/Table/GridTableApi.ts @@ -2,20 +2,10 @@ import { comparer } from "mobx"; import { computedFn } from "mobx-utils"; import { MutableRefObject, useMemo } from "react"; import { VirtuosoHandle } from "react-virtuoso"; -import { - applyRowFn, - createRowLookup, - GridRowLookup, - isGridCellContent, - isJSX, - maybeApplyFunction, - MaybeFn, -} from "src/components/index"; +import { applyRowFn, createRowLookup, GridRowLookup, isGridCellContent, isJSX, MaybeFn } from "src/components/index"; import { GridDataRow } from "src/components/Table/components/Row"; import { DiscriminateUnion, Kinded } from "src/components/Table/types"; import { TableState } from "src/components/Table/utils/TableState"; -import { maybeCall } from "src/utils"; -import { Properties } from "src/Css"; /** * Creates an `api` handle to drive a `GridTable`. diff --git a/src/components/Table/Table.qa.stories.tsx b/src/components/Table/Table.qa.stories.tsx index 7d4f8e600..c24327530 100644 --- a/src/components/Table/Table.qa.stories.tsx +++ b/src/components/Table/Table.qa.stories.tsx @@ -464,10 +464,10 @@ function beamNestedRows(levels: 1 | 2 | 3 | 4 = 1): GridDataRow[] ...(levels === 4 ? greatGrandParents : levels === 3 - ? grandParents - : levels === 2 - ? grandParents.flatMap((gp) => gp.children!) - : grandParents.flatMap((gp) => gp.children!.flatMap((p) => p.children!))), + ? grandParents + : levels === 2 + ? grandParents.flatMap((gp) => gp.children!) + : grandParents.flatMap((gp) => gp.children!.flatMap((p) => p.children!))), ]; } diff --git a/src/components/Table/components/EditColumnsButton.tsx b/src/components/Table/components/EditColumnsButton.tsx index 30b4a8533..84b477832 100644 --- a/src/components/Table/components/EditColumnsButton.tsx +++ b/src/components/Table/components/EditColumnsButton.tsx @@ -37,10 +37,10 @@ export function EditColumnsButton(props: EditColumnsButtonProp isTextButton(trigger) ? labelOr(trigger, "editColumnsButton") : isNavLinkButton(trigger) - ? defaultTestId(trigger.navLabel) - : isIconButton(trigger) - ? trigger.icon - : trigger.name, + ? defaultTestId(trigger.navLabel) + : isIconButton(trigger) + ? trigger.icon + : trigger.name, ); const options = useMemo( diff --git a/src/components/Table/components/Row.tsx b/src/components/Table/components/Row.tsx index c014883cb..1d1759aa2 100644 --- a/src/components/Table/components/Row.tsx +++ b/src/components/Table/components/Row.tsx @@ -217,8 +217,8 @@ function RowImpl(props: RowProps): ReactElement { isGridCellContent(maybeContent) && typeof maybeContent.colspan === "number" ? maybeContent.colspan : isExpandableHeader - ? numExpandedColumns + 1 - : 1; + ? numExpandedColumns + 1 + : 1; const revealOnRowHover = isGridCellContent(maybeContent) ? maybeContent.revealOnRowHover : false; const canSortColumn = @@ -343,10 +343,10 @@ function RowImpl(props: RowProps): ReactElement { (rowStyle?.renderCell || rowStyle?.rowLink) && wrapAction ? rowLinkRenderFn(as, currentColspan) : isHeader || isTotals || isExpandableHeader - ? headerRenderFn(column, as, currentColspan) - : rowStyle?.onClick && wrapAction - ? rowClickRenderFn(as, api, currentColspan) - : defaultRenderFn(as, currentColspan); + ? headerRenderFn(column, as, currentColspan) + : rowStyle?.onClick && wrapAction + ? rowClickRenderFn(as, api, currentColspan) + : defaultRenderFn(as, currentColspan); return renderFn(columnIndex, cellCss, content, row, rowStyle, cellClassNames, cellOnClick, tooltip); }) diff --git a/src/components/Table/utils/ColumnState.ts b/src/components/Table/utils/ColumnState.ts index 99f7ec8bc..f6ae23d5a 100644 --- a/src/components/Table/utils/ColumnState.ts +++ b/src/components/Table/utils/ColumnState.ts @@ -24,7 +24,7 @@ export class ColumnState { ) { this.column = column; // If the user sets `canHide: true`, we default to hidden unless they set `initVisible: true` - this.visible = storage.wasVisible(column.id) ?? (column.canHide ? column.initVisible ?? false : true); + this.visible = storage.wasVisible(column.id) ?? (column.canHide ? (column.initVisible ?? false) : true); if (this.visible && (storage.wasExpanded(column.id) ?? column.initExpanded)) { this.expanded = true; // TODO: verify this eslint ignore diff --git a/src/components/Table/utils/columns.tsx b/src/components/Table/utils/columns.tsx index eccdf4eda..54a45a66a 100644 --- a/src/components/Table/utils/columns.tsx +++ b/src/components/Table/utils/columns.tsx @@ -1,11 +1,11 @@ +import { Icon } from "src"; import { CollapseToggle } from "src/components/Table/components/CollapseToggle"; import { GridDataRow } from "src/components/Table/components/Row"; import { SelectToggle } from "src/components/Table/components/SelectToggle"; import { GridColumn, GridColumnWithId, Kinded, nonKindGridColumnKeys } from "src/components/Table/types"; import { DragData, emptyCell } from "src/components/Table/utils/utils"; -import { isFunction, newMethodMissingProxy } from "src/utils"; -import { Icon } from "src"; import { Css } from "src/Css"; +import { isFunction, newMethodMissingProxy } from "src/utils"; /** Provides default styling for a GridColumn representing a Date. */ export function column(columnDef: GridColumn): GridColumn { @@ -272,8 +272,8 @@ function parseFr(w: string | number | undefined): number | undefined { return typeof w === "number" ? w : typeof w === "undefined" - ? 1 - : typeof w === "string" && w.endsWith("fr") - ? Number(w.replace("fr", "")) - : undefined; + ? 1 + : typeof w === "string" && w.endsWith("fr") + ? Number(w.replace("fr", "")) + : undefined; } diff --git a/src/components/Table/utils/sortRows.ts b/src/components/Table/utils/sortRows.ts index 8c2972eb8..43a16a657 100644 --- a/src/components/Table/utils/sortRows.ts +++ b/src/components/Table/utils/sortRows.ts @@ -121,7 +121,7 @@ export function ensureClientSideSortValueIsSortable( if (process.env.NODE_ENV !== "production" && !isHeader && sortOn === "client" && column.clientSideSort !== false) { const value = sortValue(maybeContent, false); if (!canClientSideSort(value)) { - const columnIdentifier = !column.id.startsWith("beamColumn_") ? column.id : column.name ?? idx; + const columnIdentifier = !column.id.startsWith("beamColumn_") ? column.id : (column.name ?? idx); throw new Error( `Column ${columnIdentifier} passed an unsortable value, use GridCellContent or clientSideSort=false`, ); diff --git a/src/components/Tag.tsx b/src/components/Tag.tsx index d9626da27..53c8bb36a 100644 --- a/src/components/Tag.tsx +++ b/src/components/Tag.tsx @@ -1,8 +1,8 @@ +import { useResizeObserver } from "@react-aria/utils"; +import { ReactNode, useRef, useState } from "react"; import { Icon, IconKey, maybeTooltip } from "src/components"; import { Css, Margin, Only, Xss } from "src/Css"; import { useTestIds } from "src/utils"; -import { ReactNode, useRef, useState } from "react"; -import { useResizeObserver } from "@react-aria/utils"; type TagXss = Margin | "backgroundColor" | "color"; export type TagType = "info" | "caution" | "warning" | "success" | "neutral"; diff --git a/src/components/Tooltip.tsx b/src/components/Tooltip.tsx index 03516595f..83a5e3b9b 100644 --- a/src/components/Tooltip.tsx +++ b/src/components/Tooltip.tsx @@ -78,7 +78,9 @@ function Popper({ triggerRef, content, placement = "auto", bgColor = Palette.Gra // Since we use `display: contents;` on the `triggerRef`, then the element.offsetTop/Left/etc all equal `0`. This would make // the tooltip show in the top left of the document. So instead, we target either the first child, if available, or the parent element as the tooltip target. // It is possible there are no children if the element only has text content, which is the reasoning for the parentElement fallback. - const targetElement = triggerRef.current ? triggerRef.current.children[0] ?? triggerRef.current.parentElement : null; + const targetElement = triggerRef.current + ? (triggerRef.current.children[0] ?? triggerRef.current.parentElement) + : null; const { styles, attributes } = usePopper(targetElement, popperRef.current, { modifiers: [ @@ -117,6 +119,6 @@ export function resolveTooltip( return typeof disabled !== "boolean" && disabled ? disabled : typeof readOnly !== "boolean" && readOnly - ? readOnly - : tooltip ?? undefined; + ? readOnly + : (tooltip ?? undefined); } diff --git a/src/components/index.ts b/src/components/index.ts index d8bddc465..f48381da4 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -21,8 +21,8 @@ export * from "./CssReset"; export * from "./DnDGrid"; export * from "./Filters"; export * from "./Grid"; -export * from "./HelperText"; export { HbLoadingSpinner, HbSpinnerProvider, HB_QUIPS_FLAVOR, HB_QUIPS_MISSION } from "./HbLoadingSpinner"; +export * from "./HelperText"; export * from "./Icon"; export * from "./IconButton"; export * from "./Layout"; diff --git a/src/components/internal/DatePicker/DatePicker.stories.tsx b/src/components/internal/DatePicker/DatePicker.stories.tsx index 7463b8425..94af21931 100644 --- a/src/components/internal/DatePicker/DatePicker.stories.tsx +++ b/src/components/internal/DatePicker/DatePicker.stories.tsx @@ -1,9 +1,9 @@ import { Meta } from "@storybook/react"; +import { format } from "date-fns"; import { useState } from "react"; +import { Css } from "src"; import { DatePicker } from "src/components/internal/DatePicker"; import { jan1, jan10, jan2, jan29 } from "src/forms/formStateDomain"; -import { Css } from "src"; -import { format } from "date-fns"; export default { component: DatePicker, diff --git a/src/components/internal/OverlayTrigger.tsx b/src/components/internal/OverlayTrigger.tsx index 0e57f9494..999769d1a 100644 --- a/src/components/internal/OverlayTrigger.tsx +++ b/src/components/internal/OverlayTrigger.tsx @@ -73,10 +73,10 @@ export function OverlayTrigger(props: OverlayTriggerProps) { isTextButton(trigger) ? defaultTestId(labelOr(trigger, "overlayTrigger")) : isNavLinkButton(trigger) - ? defaultTestId(trigger.navLabel) - : isIconButton(trigger) - ? trigger.icon - : trigger.name, + ? defaultTestId(trigger.navLabel) + : isIconButton(trigger) + ? trigger.icon + : trigger.name, ); return ( diff --git a/src/forms/BoundIconCardField.test.tsx b/src/forms/BoundIconCardField.test.tsx index 732ef7a20..84e78458f 100644 --- a/src/forms/BoundIconCardField.test.tsx +++ b/src/forms/BoundIconCardField.test.tsx @@ -1,6 +1,6 @@ -import { ObjectConfig, ObjectState, createObjectState, required } from "@homebound/form-state"; -import { BoundIconCardField } from "./BoundIconCardField"; +import { createObjectState, ObjectConfig, ObjectState, required } from "@homebound/form-state"; import { click, render } from "src/utils/rtl"; +import { BoundIconCardField } from "./BoundIconCardField"; import { AuthorInput } from "./formStateDomain"; const formConfig: ObjectConfig = { diff --git a/src/forms/BoundIconCardField.tsx b/src/forms/BoundIconCardField.tsx index 4ba82045e..aad2cbd48 100644 --- a/src/forms/BoundIconCardField.tsx +++ b/src/forms/BoundIconCardField.tsx @@ -1,9 +1,9 @@ import { FieldState } from "@homebound/form-state"; -import { IconCard, IconCardProps } from "src/inputs"; -import { defaultLabel } from "src/utils/defaultLabel"; -import { useTestIds } from "src/utils"; import { Observer } from "mobx-react"; import { IconProps } from "src/components"; +import { IconCard, IconCardProps } from "src/inputs"; +import { useTestIds } from "src/utils"; +import { defaultLabel } from "src/utils/defaultLabel"; export type BoundIconCardFieldProps = Omit & { field: FieldState; diff --git a/src/forms/BoundIconCardGroupField.test.tsx b/src/forms/BoundIconCardGroupField.test.tsx index 6498e9dd2..0cf5ef505 100644 --- a/src/forms/BoundIconCardGroupField.test.tsx +++ b/src/forms/BoundIconCardGroupField.test.tsx @@ -1,8 +1,8 @@ +import { createObjectState, ObjectConfig, ObjectState, required } from "@homebound/form-state"; import { IconCardGroupItemOption } from "src/inputs/IconCardGroup"; -import { AuthorInput } from "./formStateDomain"; -import { ObjectConfig, ObjectState, createObjectState, required } from "@homebound/form-state"; -import { BoundIconCardGroupField } from "./BoundIconCardGroupField"; import { click, render } from "src/utils/rtl"; +import { BoundIconCardGroupField } from "./BoundIconCardGroupField"; +import { AuthorInput } from "./formStateDomain"; enum Category { Math, diff --git a/src/forms/BoundIconCardGroupField.tsx b/src/forms/BoundIconCardGroupField.tsx index 151bfd410..4208adec4 100644 --- a/src/forms/BoundIconCardGroupField.tsx +++ b/src/forms/BoundIconCardGroupField.tsx @@ -1,9 +1,9 @@ import { FieldState } from "@homebound/form-state"; import { Observer } from "mobx-react"; +import { Value } from "src/inputs"; import { IconCardGroup, IconCardGroupProps } from "src/inputs/IconCardGroup"; import { useTestIds } from "src/utils"; import { defaultLabel } from "src/utils/defaultLabel"; -import { Value } from "src/inputs"; export type BoundIconCardGroupFieldProps = Omit< IconCardGroupProps, diff --git a/src/forms/BoundSelectField.tsx b/src/forms/BoundSelectField.tsx index 35c75f91c..3477584f6 100644 --- a/src/forms/BoundSelectField.tsx +++ b/src/forms/BoundSelectField.tsx @@ -4,8 +4,8 @@ import { SelectField, SelectFieldProps, Value } from "src/inputs"; import { HasIdIsh, HasNameIsh, Optional } from "src/types"; import { maybeCall } from "src/utils"; import { defaultLabel } from "src/utils/defaultLabel"; -import { useTestIds } from "src/utils/useTestIds"; import { defaultOptionLabel, defaultOptionValue } from "src/utils/options"; +import { useTestIds } from "src/utils/useTestIds"; export type BoundSelectFieldProps = Omit, "value" | "onSelect" | "label"> & { /** Optional, to allow `onSelect` to be overridden to do more than just `field.set`. */ diff --git a/src/forms/FormLines.tsx b/src/forms/FormLines.tsx index ecc27a766..cf3fa9cac 100644 --- a/src/forms/FormLines.tsx +++ b/src/forms/FormLines.tsx @@ -1,7 +1,7 @@ import { Children, cloneElement, ReactNode } from "react"; +import { useModal } from "src/components"; import { PresentationFieldProps, PresentationProvider } from "src/components/PresentationContext"; import { Css } from "src/Css"; -import { useModal } from "src/components"; export type FormWidth = /** 320px. */ diff --git a/src/forms/index.ts b/src/forms/index.ts index c72b4d759..67c8e9967 100644 --- a/src/forms/index.ts +++ b/src/forms/index.ts @@ -3,6 +3,8 @@ export * from "./BoundCheckboxGroupField"; export * from "./BoundChipSelectField"; export * from "./BoundDateField"; export * from "./BoundDateRangeField"; +export * from "./BoundIconCardField"; +export * from "./BoundIconCardGroupField"; export * from "./BoundMultiLineSelectField"; export * from "./BoundMultiSelectField"; export * from "./BoundNumberField"; @@ -15,8 +17,6 @@ export * from "./BoundTextAreaField"; export * from "./BoundTextField"; export * from "./BoundToggleChipGroupField"; export * from "./BoundTreeSelectField"; -export * from "./BoundIconCardField"; -export * from "./BoundIconCardGroupField"; export * from "./FormHeading"; export * from "./FormLines"; export * from "./StaticField"; diff --git a/src/hooks/usePersistedFilter.ts b/src/hooks/usePersistedFilter.ts index 2b4707fbe..6bd23f2cc 100644 --- a/src/hooks/usePersistedFilter.ts +++ b/src/hooks/usePersistedFilter.ts @@ -33,7 +33,7 @@ export function usePersistedFilter({ storageKey, filterDefs }: UsePersistedFi const [{ filter: queryParamsFilter }, setQueryParams] = useQueryParams({ filter: JsonParam }); const [storedFilter, setStoredFilter] = useSessionStorage(storageKey, queryParamsFilter ?? defaultFilter); const isQueryParamFilterValid = hasValidFilterKeys(queryParamsFilter, filterKeys); - const filter: F = isQueryParamFilterValid ? queryParamsFilter : storedFilter ?? defaultFilter; + const filter: F = isQueryParamFilterValid ? queryParamsFilter : (storedFilter ?? defaultFilter); const setFilter = (filter: F) => setQueryParams({ filter }); diff --git a/src/inputs/IconCard.tsx b/src/inputs/IconCard.tsx index 238c0d7f3..5a7c8170c 100644 --- a/src/inputs/IconCard.tsx +++ b/src/inputs/IconCard.tsx @@ -4,7 +4,7 @@ import { useToggleState } from "react-stately"; import { Icon, IconProps, maybeTooltip, resolveTooltip } from "src/components"; import { Css, Palette } from "src/Css"; import { useGetRef } from "src/hooks/useGetRef"; -import { noop, useTestIds } from "src/utils"; +import { useTestIds } from "src/utils"; import { defaultTestId } from "src/utils/defaultTestId"; export interface IconCardProps { diff --git a/src/inputs/IconCardGroup.stories.tsx b/src/inputs/IconCardGroup.stories.tsx index 4d13949d6..8b6fed2ac 100644 --- a/src/inputs/IconCardGroup.stories.tsx +++ b/src/inputs/IconCardGroup.stories.tsx @@ -1,7 +1,7 @@ import { Meta } from "@storybook/react"; -import { IconCardGroup, IconCardGroupItemOption, IconCardGroupProps } from "./IconCardGroup"; import { useState } from "react"; import { Css } from "src/Css"; +import { IconCardGroup, IconCardGroupItemOption, IconCardGroupProps } from "./IconCardGroup"; export default { component: IconCardGroup, diff --git a/src/inputs/IconCardGroup.tsx b/src/inputs/IconCardGroup.tsx index 4640d9834..171d23cdf 100644 --- a/src/inputs/IconCardGroup.tsx +++ b/src/inputs/IconCardGroup.tsx @@ -1,14 +1,14 @@ import { ReactNode, useCallback, useMemo, useState } from "react"; -import { Css } from "src/Css"; +import { mergeProps, useField } from "react-aria"; +import { HelperText } from "src/components/HelperText"; import { IconProps } from "src/components/Icon"; import { Label } from "src/components/Label"; import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; -import { useTestIds } from "src/utils"; +import { Css } from "src/Css"; +import { Value } from "src/inputs"; import { IconCard } from "src/inputs/IconCard"; -import { HelperText } from "src/components/HelperText"; +import { useTestIds } from "src/utils"; import { ErrorMessage } from "./ErrorMessage"; -import { Value } from "src/inputs"; -import { mergeProps, useField } from "react-aria"; export interface IconCardGroupItemOption { icon: IconProps["icon"]; diff --git a/src/inputs/NumberField.tsx b/src/inputs/NumberField.tsx index a5d4e8d7e..b186d185f 100644 --- a/src/inputs/NumberField.tsx +++ b/src/inputs/NumberField.tsx @@ -110,16 +110,16 @@ export function NumberField(props: NumberFieldProps) { type === "percent" ? { style: "percent" } : type === "basisPoints" - ? { style: "percent", minimumFractionDigits: 2 } - : type === "cents" - ? { style: "currency", currency: "USD", minimumFractionDigits: 2 } - : type === "mills" - ? { style: "currency", currency: "USD", minimumFractionDigits: 3 } - : type === "dollars" - ? { style: "currency", currency: "USD", minimumFractionDigits: numFractionDigits ?? 2 } - : type === "days" - ? { style: "unit", unit: "day", unitDisplay: "long" as const, maximumFractionDigits: 0 } - : {}; + ? { style: "percent", minimumFractionDigits: 2 } + : type === "cents" + ? { style: "currency", currency: "USD", minimumFractionDigits: 2 } + : type === "mills" + ? { style: "currency", currency: "USD", minimumFractionDigits: 3 } + : type === "dollars" + ? { style: "currency", currency: "USD", minimumFractionDigits: numFractionDigits ?? 2 } + : type === "days" + ? { style: "unit", unit: "day", unitDisplay: "long" as const, maximumFractionDigits: 0 } + : {}; return { ...defaultFormatOptions, ...typeFormat }; }, [type, numberFormatOptions, defaultFormatOptions, numFractionDigits]); diff --git a/src/inputs/RichTextField.tsx b/src/inputs/RichTextField.tsx index 0823a33ad..8dec38d57 100644 --- a/src/inputs/RichTextField.tsx +++ b/src/inputs/RichTextField.tsx @@ -2,13 +2,13 @@ import { Global } from "@emotion/react"; import DOMPurify from "dompurify"; import { ChangeEvent, createElement, useEffect, useMemo, useRef, useState } from "react"; import { Label } from "src/components/Label"; +import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; import { Css, Palette } from "src/Css"; import { maybeCall, noop } from "src/utils"; import Tribute from "tributejs"; import "tributejs/dist/tribute.css"; import "trix/dist/trix"; import "trix/dist/trix.css"; -import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; export interface RichTextFieldProps extends Pick { /** The initial html value to show in the trix editor. */ diff --git a/src/inputs/SelectField.test.tsx b/src/inputs/SelectField.test.tsx index b369a5477..afd80fd27 100644 --- a/src/inputs/SelectField.test.tsx +++ b/src/inputs/SelectField.test.tsx @@ -1,10 +1,10 @@ -import { clickAndWait, type } from "@homebound/rtl-utils"; +import { clickAndWait } from "@homebound/rtl-utils"; import { fireEvent } from "@testing-library/react"; import { useState } from "react"; +import { AuthorHeight } from "src/forms/formStateDomain"; import { SelectField, SelectFieldProps, Value } from "src/inputs"; import { HasIdAndName, Optional } from "src/types"; import { blur, click, focus, getOptions, render, select, wait } from "src/utils/rtl"; -import { AuthorHeight } from "src/forms/formStateDomain"; describe("SelectFieldTest", () => { it("can set a value", async () => { diff --git a/src/inputs/Switch.tsx b/src/inputs/Switch.tsx index 6ae6c77d3..30a5ba023 100644 --- a/src/inputs/Switch.tsx +++ b/src/inputs/Switch.tsx @@ -2,10 +2,10 @@ import { ReactNode, useRef } from "react"; import { useFocusRing, useHover, useSwitch, VisuallyHidden } from "react-aria"; import { resolveTooltip } from "src/components"; import { Label } from "src/components/Label"; +import { usePresentationContext } from "src/components/PresentationContext"; import { Css, Palette } from "src/Css"; import { Icon } from "../components/Icon"; import { toToggleState, useTestIds } from "../utils"; -import { usePresentationContext } from "src/components/PresentationContext"; export interface SwitchProps { /** Whether the element should receive focus on render. */ diff --git a/src/inputs/TextFieldBase.test.tsx b/src/inputs/TextFieldBase.test.tsx index c7a186aa8..377685e73 100644 --- a/src/inputs/TextFieldBase.test.tsx +++ b/src/inputs/TextFieldBase.test.tsx @@ -1,5 +1,5 @@ import { TextFieldBase } from "src/inputs/TextFieldBase"; -import { render, focus } from "src/utils/rtl"; +import { focus, render } from "src/utils/rtl"; describe(TextFieldBase, () => { it("shows error and helper text", async () => { diff --git a/src/inputs/TextFieldBase.tsx b/src/inputs/TextFieldBase.tsx index 98092e68f..77434e97b 100644 --- a/src/inputs/TextFieldBase.tsx +++ b/src/inputs/TextFieldBase.tsx @@ -18,10 +18,10 @@ import { Css, Only, Palette } from "src/Css"; import { getLabelSuffix } from "src/forms/labelUtils"; import { useGetRef } from "src/hooks/useGetRef"; import { ErrorMessage } from "src/inputs/ErrorMessage"; +import { getFieldWidth } from "src/inputs/utils"; import { BeamTextFieldProps, TextFieldInternalProps, TextFieldXss } from "src/interfaces"; import { defaultTestId } from "src/utils/defaultTestId"; import { useTestIds } from "src/utils/useTestIds"; -import { getFieldWidth } from "src/inputs/utils"; export interface TextFieldBaseProps extends Pick< @@ -121,8 +121,8 @@ export function TextFieldBase>(props: TextFieldB const [bgColor, hoverBgColor, disabledBgColor] = contrast ? [Palette.Gray700, Palette.Gray600, Palette.Gray700] : borderless && !compound - ? [Palette.Gray100, Palette.Gray200, Palette.Gray200] - : [Palette.White, Palette.Gray100, Palette.Gray100]; + ? [Palette.Gray100, Palette.Gray200, Palette.Gray200] + : [Palette.White, Palette.Gray100, Palette.Gray100]; const fieldMaxWidth = getFieldWidth(fullWidth); diff --git a/src/inputs/ToggleChipGroup.tsx b/src/inputs/ToggleChipGroup.tsx index f18d7c2ae..1e0d164d6 100644 --- a/src/inputs/ToggleChipGroup.tsx +++ b/src/inputs/ToggleChipGroup.tsx @@ -3,9 +3,9 @@ import { useCheckboxGroup, useCheckboxGroupItem, useFocusRing, VisuallyHidden } import { CheckboxGroupState, useCheckboxGroupState } from "react-stately"; import { maybeTooltip, resolveTooltip } from "src/components"; import { Label } from "src/components/Label"; +import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; import { Css, Palette, Xss } from "src/Css"; import { useTestIds } from "src/utils/useTestIds"; -import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; type ToggleChipXss = Xss<"color" | "backgroundColor">; diff --git a/src/inputs/TreeSelectField/TreeSelectField.stories.tsx b/src/inputs/TreeSelectField/TreeSelectField.stories.tsx index 01249ac53..adc626320 100644 --- a/src/inputs/TreeSelectField/TreeSelectField.stories.tsx +++ b/src/inputs/TreeSelectField/TreeSelectField.stories.tsx @@ -2,13 +2,13 @@ import { action } from "@storybook/addon-actions"; import { Meta } from "@storybook/react"; import { within } from "@storybook/testing-library"; import { useState } from "react"; +import { Button } from "src/components"; import { Css } from "src/Css"; import { Value } from "src/inputs/index"; import { TreeSelectField, TreeSelectFieldProps } from "src/inputs/TreeSelectField/TreeSelectField"; import { NestedOption } from "src/inputs/TreeSelectField/utils"; import { HasIdAndName } from "src/types"; import { zeroTo } from "src/utils/sb"; -import { Button } from "src/components"; export default { component: TreeSelectField, diff --git a/src/inputs/TreeSelectField/TreeSelectField.test.tsx b/src/inputs/TreeSelectField/TreeSelectField.test.tsx index 032501c59..5087068dd 100644 --- a/src/inputs/TreeSelectField/TreeSelectField.test.tsx +++ b/src/inputs/TreeSelectField/TreeSelectField.test.tsx @@ -1,10 +1,10 @@ import { fireEvent } from "@testing-library/react"; +import { useState } from "react"; import { TreeSelectField } from "src/inputs"; import { NestedOption } from "src/inputs/TreeSelectField/utils"; import { HasIdAndName } from "src/types"; import { noop } from "src/utils"; import { blur, click, focus, getSelected, render, wait } from "src/utils/rtl"; -import { useState } from "react"; describe(TreeSelectField, () => { it("renders", async () => { diff --git a/src/inputs/TreeSelectField/TreeSelectField.tsx b/src/inputs/TreeSelectField/TreeSelectField.tsx index 0d11f0527..89ff38b6f 100644 --- a/src/inputs/TreeSelectField/TreeSelectField.tsx +++ b/src/inputs/TreeSelectField/TreeSelectField.tsx @@ -17,6 +17,7 @@ import { Popover } from "src/components/internal"; import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; import { Css } from "src/Css"; import { Value } from "src/inputs/index"; +import { disabledOptionToKeyedTuple } from "src/inputs/internal/ComboBoxBase"; import { ComboBoxInput } from "src/inputs/internal/ComboBoxInput"; import { ListBox } from "src/inputs/internal/ListBox"; import { @@ -29,11 +30,10 @@ import { TreeFieldState, TreeSelectResponse, } from "src/inputs/TreeSelectField/utils"; +import { getFieldWidth } from "src/inputs/utils"; import { keyToValue, valueToKey } from "src/inputs/Value"; import { BeamFocusableProps } from "src/interfaces"; import { HasIdAndName, Optional } from "src/types"; -import { getFieldWidth } from "src/inputs/utils"; -import { disabledOptionToKeyedTuple } from "src/inputs/internal/ComboBoxBase"; export interface TreeSelectFieldProps extends BeamFocusableProps, PresentationFieldProps { /** Renders `opt` in the dropdown menu, defaults to the `getOptionLabel` prop. `isUnsetOpt` is only defined for single SelectField */ @@ -100,11 +100,11 @@ export function TreeSelectField( !Array.isArray(options) ? [] : defaultCollapsed - ? options.map((o) => getOptionValue(o)) - : options - .flatMap(flattenOptions) - .filter((o) => o.defaultCollapsed) - .map((o) => getOptionValue(o)), + ? options.map((o) => getOptionValue(o)) + : options + .flatMap(flattenOptions) + .filter((o) => o.defaultCollapsed) + .map((o) => getOptionValue(o)), ); // Explicitly ignoring `getOptionValue` as it typically isn't memo'd // eslint-disable-next-line react-hooks/exhaustive-deps @@ -239,8 +239,8 @@ function TreeSelectFieldBase(props: TreeSelectFieldProps getTopLevelSelections(o, selectedKeys, getOptionValue)).map(getOptionLabel) : chipDisplay === "leaf" - ? selectedOptions.filter((o) => !o.children || o.children.length === 0).map(getOptionLabel) - : selectedOptions.map(getOptionLabel); + ? selectedOptions.filter((o) => !o.children || o.children.length === 0).map(getOptionLabel) + : selectedOptions.map(getOptionLabel); const filteredOptions = initialOptions.flatMap((o) => levelOptions(o, 0, false, collapsedKeys, getOptionValue)); @@ -250,10 +250,10 @@ function TreeSelectFieldBase(props: TreeSelectFieldProps 0 - ? selectedOptionsLabels.join(", ") - : selectedOptions.length === 0 - ? nothingSelectedText - : "", + ? selectedOptionsLabels.join(", ") + : selectedOptions.length === 0 + ? nothingSelectedText + : "", filteredOptions, selectedOptions, allOptions: initialOptions, @@ -547,8 +547,8 @@ function TreeSelectFieldBase(props: TreeSelectFieldProps(props: TreeSelectFieldProps levelOptions(o, 0, false, collapsedKeys, getOptionValue)), allowCollapsing: true, })); diff --git a/src/inputs/index.ts b/src/inputs/index.ts index 7000272cc..601f4960a 100644 --- a/src/inputs/index.ts +++ b/src/inputs/index.ts @@ -4,6 +4,7 @@ export * from "./CheckboxGroup"; export * from "./ChipSelectField"; export * from "./DateFields"; export * from "./ErrorMessage"; +export * from "./IconCard"; export * from "./MultiLineSelectField"; export * from "./MultiSelectField"; export * from "./NumberField"; @@ -19,5 +20,4 @@ export type { TextFieldApi } from "./TextField"; export * from "./ToggleButton"; export * from "./ToggleChipGroup"; export * from "./TreeSelectField"; -export * from "./IconCard"; export type { Value } from "./Value"; diff --git a/src/inputs/internal/ComboBoxBase.tsx b/src/inputs/internal/ComboBoxBase.tsx index b5b259426..7da44333f 100644 --- a/src/inputs/internal/ComboBoxBase.tsx +++ b/src/inputs/internal/ComboBoxBase.tsx @@ -1,4 +1,5 @@ import { Selection } from "@react-types/shared"; +import equal from "fast-deep-equal"; import React, { Key, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useButton, useComboBox, useFilter, useOverlayPosition } from "react-aria"; import { Item, useComboBoxState, useMultipleSelectionState } from "react-stately"; @@ -8,11 +9,10 @@ import { PresentationFieldProps, usePresentationContext } from "src/components/P import { Css } from "src/Css"; import { ComboBoxInput } from "src/inputs/internal/ComboBoxInput"; import { ListBox } from "src/inputs/internal/ListBox"; +import { getFieldWidth } from "src/inputs/utils"; import { keyToValue, Value, valueToKey } from "src/inputs/Value"; import { BeamFocusableProps } from "src/interfaces"; -import { getFieldWidth } from "src/inputs/utils"; import { useDebounce } from "use-debounce"; -import equal from "fast-deep-equal"; /** Base props for either `SelectField` or `MultiSelectField`. */ export interface ComboBoxBaseProps extends BeamFocusableProps, PresentationFieldProps { @@ -108,8 +108,8 @@ export function ComboBoxBase(props: ComboBoxBaseProps) unsetLabel && o === unsetOption ? unsetLabel : onAddNew && o === addNewOption - ? addNewOption.name - : propOptionLabel(o), + ? addNewOption.name + : propOptionLabel(o), // propOptionLabel is basically always a lambda, so don't dep on it // eslint-disable-next-line react-hooks/exhaustive-deps [unsetLabel], @@ -119,8 +119,8 @@ export function ComboBoxBase(props: ComboBoxBaseProps) unsetLabel && o === unsetOption ? (undefined as V) : onAddNew && o === addNewOption - ? (addNewOption.id as V) - : propOptionValue(o), + ? (addNewOption.id as V) + : propOptionValue(o), // propOptionValue is basically always a lambda, so don't dep on it // eslint-disable-next-line react-hooks/exhaustive-deps [unsetLabel], @@ -457,10 +457,10 @@ function getInputValue( return selectedOptions.length === 1 ? getOptionLabel(selectedOptions[0]) : readOnly && selectedOptions.length > 0 - ? selectedOptions.map(getOptionLabel).join(", ") - : multiselect && selectedOptions.length === 0 - ? nothingSelectedText - : ""; + ? selectedOptions.map(getOptionLabel).join(", ") + : multiselect && selectedOptions.length === 0 + ? nothingSelectedText + : ""; } /** Transforms/simplifies `optionsOrLoad` into just options, with unsetLabel maybe added. */ diff --git a/src/inputs/internal/ComboBoxInput.tsx b/src/inputs/internal/ComboBoxInput.tsx index 9d359c016..b031d9767 100644 --- a/src/inputs/internal/ComboBoxInput.tsx +++ b/src/inputs/internal/ComboBoxInput.tsx @@ -12,12 +12,12 @@ import { ComboBoxState } from "react-stately"; import { Chips, Icon, Tooltip } from "src/components"; import { PresentationFieldProps, usePresentationContext } from "src/components/PresentationContext"; import { Css } from "src/Css"; +import { useGrowingTextField } from "src/inputs/hooks/useGrowingTextField"; import { TextFieldBase } from "src/inputs/TextFieldBase"; import { useTreeSelectFieldProvider } from "src/inputs/TreeSelectField/TreeSelectField"; import { isLeveledNode } from "src/inputs/TreeSelectField/utils"; import { Value } from "src/inputs/Value"; import { maybeCall } from "src/utils"; -import { useGrowingTextField } from "src/inputs/hooks/useGrowingTextField"; interface ComboBoxInputProps extends PresentationFieldProps { buttonProps: any; diff --git a/src/inputs/internal/Option.tsx b/src/inputs/internal/Option.tsx index fe5d27e39..3a2de902f 100644 --- a/src/inputs/internal/Option.tsx +++ b/src/inputs/internal/Option.tsx @@ -64,8 +64,8 @@ export function Option(props: OptionProps) { ? Palette.Gray400 : Palette.Blue700 : isDisabled - ? Palette.Gray500 - : Palette.White + ? Palette.Gray500 + : Palette.White } /> diff --git a/src/utils/options.ts b/src/utils/options.ts index 5181af4b2..21e32b19e 100644 --- a/src/utils/options.ts +++ b/src/utils/options.ts @@ -13,8 +13,8 @@ export function defaultOptionLabel(opt: O): any { return "name" in opt ? opt.name : "displayName" in opt - ? opt.displayName - : "label" in opt - ? opt.label - : fail(`Option ${JSON.stringify(opt)} has no displayName, label, or name`); + ? opt.displayName + : "label" in opt + ? opt.label + : fail(`Option ${JSON.stringify(opt)} has no displayName, label, or name`); } diff --git a/yarn.lock b/yarn.lock index 0efdb7d8a..82d390a95 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3788,8 +3788,8 @@ __metadata: mobx: ^6.10.2 mobx-react: ^9.0.1 mobx-utils: ^6.0.8 - prettier: ^3.0.3 - prettier-plugin-organize-imports: ^3.2.3 + prettier: ^3.3.3 + prettier-plugin-organize-imports: ^4.1.0 react: ^18.2.0 react-aria: ^3.26.0 react-day-picker: 8.0.7 @@ -17646,6 +17646,20 @@ __metadata: languageName: node linkType: hard +"prettier-plugin-organize-imports@npm:^4.1.0": + version: 4.1.0 + resolution: "prettier-plugin-organize-imports@npm:4.1.0" + peerDependencies: + prettier: ">=2.0" + typescript: ">=2.9" + vue-tsc: ^2.1.0 + peerDependenciesMeta: + vue-tsc: + optional: true + checksum: 43c917959170fa3e30e41f9b3bd314a31462ae34e5568b4dba6b1c8b8da758adf900fdf4999333ab2b60b3d1af541f9521396a5e19df03ab5400a50edc9a75f6 + languageName: node + linkType: hard + "prettier@npm:^2.8.0": version: 2.8.7 resolution: "prettier@npm:2.8.7" @@ -17655,7 +17669,7 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.0.1, prettier@npm:^3.0.3": +"prettier@npm:^3.0.1": version: 3.0.3 resolution: "prettier@npm:3.0.3" bin: @@ -17664,6 +17678,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^3.3.3": + version: 3.3.3 + resolution: "prettier@npm:3.3.3" + bin: + prettier: bin/prettier.cjs + checksum: bc8604354805acfdde6106852d14b045bb20827ad76a5ffc2455b71a8257f94de93f17f14e463fe844808d2ccc87248364a5691488a3304f1031326e62d9276e + languageName: node + linkType: hard + "pretty-format@npm:^27.0.2": version: 27.0.6 resolution: "pretty-format@npm:27.0.6"