diff --git a/package.json b/package.json index 7312012ca..bc4cc52c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@homebound/beam", - "version": "2.324.3", + "version": "2.331.1", "author": "Homebound", "license": "MIT", "main": "dist/index.js", @@ -78,7 +78,7 @@ "@homebound/eslint-config": "^1.10.2", "@homebound/rtl-react-router-utils": "1.0.3", "@homebound/rtl-utils": "^2.65.0", - "@homebound/truss": "^1.131.0", + "@homebound/truss": "^1.132.0", "@homebound/tsconfig": "^1.0.3", "@semantic-release/exec": "^6.0.3", "@semantic-release/git": "^10.0.1", diff --git a/src/Css.ts b/src/Css.ts index 4faf58a80..279b06df5 100644 --- a/src/Css.ts +++ b/src/Css.ts @@ -1133,6 +1133,22 @@ class CssBuilder { fd(value: Properties["flexDirection"]) { return this.add("flexDirection", value); } + /** Sets `flexWrap: "wrap"`. */ + get fww() { + return this.add("flexWrap", "wrap"); + } + /** Sets `flexWrap: "wrap-reverse"`. */ + get fwr() { + return this.add("flexWrap", "wrap-reverse"); + } + /** Sets `flexWrap: "nowrap"`. */ + get fwnw() { + return this.add("flexWrap", "nowrap"); + } + /** Sets `flexWrap: value`. */ + flexWrap(value: Properties["flexWrap"]) { + return this.add("flexWrap", value); + } // float /** Sets `float: "left"`. */ diff --git a/src/components/BeamContext.tsx b/src/components/BeamContext.tsx index b45111dad..0679e89cc 100644 --- a/src/components/BeamContext.tsx +++ b/src/components/BeamContext.tsx @@ -69,26 +69,21 @@ export function BeamProvider({ children, ...presentationProps }: BeamProviderPro // We essentially expose the refs, but with our own getters/setters so that we can // have the setters call `tick` to re-render this Provider - const context = useMemo( - () => { - return { - // These two keys need to trigger re-renders on change - modalState: new PretendRefThatTicks(modalRef, tick), - drawerContentStack: new PretendRefThatTicks(drawerContentStackRef, tick), - // The rest we don't need to re-render when these are mutated, so just expose as-is - modalCanCloseChecks: modalCanCloseChecksRef, - modalHeaderDiv, - modalBodyDiv, - modalFooterDiv, - drawerCanCloseChecks, - drawerCanCloseDetailsChecks, - sdHeaderDiv, - }; - }, - // TODO: validate this eslint-disable. It was automatically ignored as part of https://app.shortcut.com/homebound-team/story/40033/enable-react-hooks-exhaustive-deps-for-react-projects - // eslint-disable-next-line react-hooks/exhaustive-deps - [modalBodyDiv, modalFooterDiv], - ); + const context = useMemo(() => { + return { + // These two keys need to trigger re-renders on change + modalState: new PretendRefThatTicks(modalRef, tick), + drawerContentStack: new PretendRefThatTicks(drawerContentStackRef, tick), + // The rest we don't need to re-render when these are mutated, so just expose as-is + modalCanCloseChecks: modalCanCloseChecksRef, + modalHeaderDiv, + modalBodyDiv, + modalFooterDiv, + drawerCanCloseChecks, + drawerCanCloseDetailsChecks, + sdHeaderDiv, + }; + }, [modalBodyDiv, modalFooterDiv, modalHeaderDiv, sdHeaderDiv]); return ( diff --git a/src/components/Icon.stories.tsx b/src/components/Icon.stories.tsx index 92758a847..54a1455e5 100644 --- a/src/components/Icon.stories.tsx +++ b/src/components/Icon.stories.tsx @@ -53,6 +53,8 @@ export const Icon = (props: IconProps) => { "undoCircle", "drag", "move", + "add", + "remove", ]; const alertIcons: IconProps["icon"][] = [ "errorCircle", @@ -142,6 +144,14 @@ export const Icon = (props: IconProps) => { "car", "basement", "cube", + "cart", + "programChange", + "architectural", + "structural", + "mep", + "designPackage", + "updateDesignPackage", + "exteriorStyle", ]; const navigationIcons: IconProps["icon"][] = [ "projects", diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index 0b235c7eb..ccb8bbe8d 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -249,6 +249,18 @@ export const Icons = { d="M6 2H4V20H3V22H7V20H6V15H19C19.5523 15 20 14.5523 20 14V5C20 4.44772 19.5523 4 19 4H6V2ZM6 6V13H18V6H6Z" /> ), + add: ( + <> + + + + ), + remove: ( + <> + + + + ), // Arrows chevronsDown: ( <> @@ -333,7 +345,7 @@ export const Icons = { ), email: ( @@ -740,6 +752,52 @@ export const Icons = { checkCircleFilled: ( ), + cart: ( + <> + + + + + ), + programChange: ( + + ), + architectural: ( + + ), + structural: ( + + ), + mep: ( + + ), + designPackage: ( + + ), + updateDesignPackage: ( + + ), + exteriorStyle: ( + + ), }; export type IconKey = keyof typeof Icons; diff --git a/src/components/Label.tsx b/src/components/Label.tsx index 84e817edc..1f96b1ea2 100644 --- a/src/components/Label.tsx +++ b/src/components/Label.tsx @@ -1,8 +1,11 @@ -import React, { LabelHTMLAttributes } from "react"; +import React, { LabelHTMLAttributes, ReactNode } from "react"; import { VisuallyHidden } from "react-aria"; -import { Css } from "src/Css"; +import { Css, Font, Only, Palette, Xss } from "src/Css"; +import { Icon } from "src"; -interface LabelProps { +type LabelXss = Font | "color"; + +interface LabelProps { // We don't usually have `fooProps`-style props, but this is for/from react-aria labelProps?: LabelHTMLAttributes; label: string; @@ -11,22 +14,38 @@ interface LabelProps { hidden?: boolean; contrast?: boolean; multiline?: boolean; + tooltip?: ReactNode; + // Removes margin bottom if true - This is different from InlineLabel. InlineLabel expects to be rendered visually within the field element. Rather just on the same line. + inline?: boolean; + xss?: X; } /** An internal helper component for rendering form labels. */ -export const Label = React.memo((props: LabelProps) => { - const { labelProps, label, hidden, suffix, contrast = false, ...others } = props; +function LabelComponent, X>>(props: LabelProps) { + const { labelProps, label, hidden, suffix, contrast = false, tooltip, inline, xss, ...others } = props; const labelEl = ( -