@mortenbrudvik/waveui 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +142 -32
- package/dist/components/data-display/InfoButton.cjs +1 -1
- package/dist/components/data-display/InfoButton.cjs.map +1 -1
- package/dist/components/data-display/InfoButton.mjs +90 -82
- package/dist/components/data-display/InfoButton.mjs.map +1 -1
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +19 -18
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/feedback/MessageBarGroup.cjs +2 -0
- package/dist/components/feedback/MessageBarGroup.cjs.map +1 -0
- package/dist/components/feedback/MessageBarGroup.mjs +63 -0
- package/dist/components/feedback/MessageBarGroup.mjs.map +1 -0
- package/dist/components/feedback/ProgressBar.cjs +1 -1
- package/dist/components/feedback/ProgressBar.cjs.map +1 -1
- package/dist/components/feedback/ProgressBar.mjs +41 -39
- package/dist/components/feedback/ProgressBar.mjs.map +1 -1
- package/dist/components/feedback/Toaster.cjs +1 -1
- package/dist/components/feedback/Toaster.cjs.map +1 -1
- package/dist/components/feedback/Toaster.mjs +222 -216
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/layout/Accordion.cjs +1 -1
- package/dist/components/layout/Accordion.cjs.map +1 -1
- package/dist/components/layout/Accordion.mjs +124 -109
- package/dist/components/layout/Accordion.mjs.map +1 -1
- package/dist/components/layout/Carousel.cjs +1 -1
- package/dist/components/layout/Carousel.cjs.map +1 -1
- package/dist/components/layout/Carousel.mjs +207 -193
- package/dist/components/layout/Carousel.mjs.map +1 -1
- package/dist/components/layout/TabList.cjs +1 -1
- package/dist/components/layout/TabList.cjs.map +1 -1
- package/dist/components/layout/TabList.mjs +149 -108
- package/dist/components/layout/TabList.mjs.map +1 -1
- package/dist/components/layout/Tree.cjs.map +1 -1
- package/dist/components/layout/Tree.context.cjs +1 -1
- package/dist/components/layout/Tree.context.cjs.map +1 -1
- package/dist/components/layout/Tree.context.mjs +2 -1
- package/dist/components/layout/Tree.context.mjs.map +1 -1
- package/dist/components/layout/Tree.core.cjs +1 -1
- package/dist/components/layout/Tree.core.cjs.map +1 -1
- package/dist/components/layout/Tree.core.mjs +178 -165
- package/dist/components/layout/Tree.core.mjs.map +1 -1
- package/dist/components/layout/Tree.mjs.map +1 -1
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +154 -168
- package/dist/components/navigation/Menu.popover.mjs.map +1 -1
- package/dist/components/navigation/Nav.cjs +1 -1
- package/dist/components/navigation/Nav.cjs.map +1 -1
- package/dist/components/navigation/Nav.mjs +156 -136
- package/dist/components/navigation/Nav.mjs.map +1 -1
- package/dist/components/navigation/NavDrawer.cjs +1 -1
- package/dist/components/navigation/NavDrawer.cjs.map +1 -1
- package/dist/components/navigation/NavDrawer.mjs +48 -45
- package/dist/components/navigation/NavDrawer.mjs.map +1 -1
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +128 -122
- package/dist/components/overlays/Dialog.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +1 -1
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.mjs +12 -12
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -1
- package/dist/components/overlays/Drawer.cjs.map +1 -1
- package/dist/components/overlays/Drawer.mjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.cjs +1 -1
- package/dist/components/overlays/Drawer.panel.cjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.mjs +97 -81
- package/dist/components/overlays/Drawer.panel.mjs.map +1 -1
- package/dist/components/overlays/Drawer.root.cjs +1 -1
- package/dist/components/overlays/Drawer.root.cjs.map +1 -1
- package/dist/components/overlays/Drawer.root.mjs +34 -31
- package/dist/components/overlays/Drawer.root.mjs.map +1 -1
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +231 -216
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.parts.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.parts.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.parts.mjs +202 -173
- package/dist/components/overlays/TeachingPopover.parts.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.root.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.root.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.root.mjs +108 -99
- package/dist/components/overlays/TeachingPopover.root.mjs.map +1 -1
- package/dist/components/overlays/Tooltip.cjs +1 -1
- package/dist/components/overlays/Tooltip.cjs.map +1 -1
- package/dist/components/overlays/Tooltip.mjs +66 -61
- package/dist/components/overlays/Tooltip.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +26 -23
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/hooks/useCollapsePresence.cjs +2 -0
- package/dist/hooks/useCollapsePresence.cjs.map +1 -0
- package/dist/hooks/useCollapsePresence.mjs +21 -0
- package/dist/hooks/useCollapsePresence.mjs.map +1 -0
- package/dist/hooks/useFocusBeforeClose.cjs +2 -0
- package/dist/hooks/useFocusBeforeClose.cjs.map +1 -0
- package/dist/hooks/useFocusBeforeClose.mjs +33 -0
- package/dist/hooks/useFocusBeforeClose.mjs.map +1 -0
- package/dist/hooks/useMotion.cjs +2 -0
- package/dist/hooks/useMotion.cjs.map +1 -0
- package/dist/hooks/useMotion.mjs +14 -0
- package/dist/hooks/useMotion.mjs.map +1 -0
- package/dist/hooks/usePresenceGroup.cjs +2 -0
- package/dist/hooks/usePresenceGroup.cjs.map +1 -0
- package/dist/hooks/usePresenceGroup.mjs +68 -0
- package/dist/hooks/usePresenceGroup.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +721 -131
- package/dist/index.d.ts +721 -131
- package/dist/index.mjs +136 -135
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +101 -90
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/motion.cjs +2 -0
- package/dist/lib/motion.cjs.map +1 -0
- package/dist/lib/motion.mjs +43 -0
- package/dist/lib/motion.mjs.map +1 -0
- package/dist/styles.css +1 -1
- package/package.json +2 -1
|
@@ -9,34 +9,35 @@ import { InfoButton as o, InfoNoteClassContext as s } from "./InfoButton.mjs";
|
|
|
9
9
|
import * as c from "react";
|
|
10
10
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
11
11
|
//#region src/components/data-display/InfoLabel.tsx
|
|
12
|
-
var d = ({ children: i, label: d, info: f, infoButtonLabel: p = "Information", openOnHover: m,
|
|
13
|
-
let
|
|
14
|
-
buttonId:
|
|
12
|
+
var d = ({ children: i, label: d, info: f, infoButtonLabel: p = "Information", openOnHover: m, motion: h, id: g, htmlFor: _, required: v, size: y = "medium", weight: b, disabled: x, className: S, ref: C, ...w }) => {
|
|
13
|
+
let T = t("InfoLabel", i, d, "label", "children"), E = r("info-label"), D = g || E, O = r("info-label-button"), k = c.useMemo(() => ({
|
|
14
|
+
buttonId: O,
|
|
15
15
|
className: n.info
|
|
16
|
-
}), [
|
|
16
|
+
}), [O]);
|
|
17
17
|
return /* @__PURE__ */ u("span", {
|
|
18
|
-
ref:
|
|
19
|
-
className: e(n.root, "inline-flex items-center gap-0",
|
|
20
|
-
...
|
|
18
|
+
ref: C,
|
|
19
|
+
className: e(n.root, "inline-flex items-center gap-0", S),
|
|
20
|
+
...w,
|
|
21
21
|
children: [/* @__PURE__ */ l(a, {
|
|
22
22
|
className: n.label,
|
|
23
|
-
id:
|
|
24
|
-
htmlFor:
|
|
25
|
-
required:
|
|
26
|
-
size:
|
|
27
|
-
weight:
|
|
28
|
-
disabled:
|
|
29
|
-
children:
|
|
23
|
+
id: D,
|
|
24
|
+
htmlFor: _,
|
|
25
|
+
required: v,
|
|
26
|
+
size: y,
|
|
27
|
+
weight: b,
|
|
28
|
+
disabled: x,
|
|
29
|
+
children: T
|
|
30
30
|
}), /* @__PURE__ */ l(s.Provider, {
|
|
31
|
-
value:
|
|
31
|
+
value: k,
|
|
32
32
|
children: /* @__PURE__ */ l(o, {
|
|
33
|
-
id:
|
|
33
|
+
id: O,
|
|
34
34
|
className: n.infoButton,
|
|
35
35
|
info: f,
|
|
36
|
-
size:
|
|
36
|
+
size: y,
|
|
37
37
|
openOnHover: m,
|
|
38
|
+
motion: h,
|
|
38
39
|
"aria-label": p,
|
|
39
|
-
"aria-labelledby": `${
|
|
40
|
+
"aria-labelledby": `${D} ${O}`
|
|
40
41
|
})
|
|
41
42
|
})]
|
|
42
43
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InfoLabel.mjs","names":["useId","useId$1","React","InfoLabel","rest","content","resolveDeprecatedProp","children","label","generatedLabelId","labelId","id","buttonId","noteClass","infoLabelClassNames","cn","className","Label","InfoNoteClassContext","InfoButton","infoButtonLabel","markFieldLabel"],"sources":["../../../src/components/data-display/InfoLabel.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { infoLabelClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport { useId } from '../../hooks/useId';\nimport { markFieldLabel } from '../input/fieldLabel';\nimport { Label, type LabelProps } from '../input/Label';\nimport { InfoButton, InfoNoteClassContext } from './InfoButton';\n\n/** Properties for the InfoLabel component. */\nexport interface InfoLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'>,\n Pick<LabelProps, 'htmlFor' | 'required' | 'size' | 'weight' | 'disabled'> {\n /** The label content (Fluent's `children`). */\n children?: React.ReactNode;\n /**\n * The label content.\n * @deprecated Use `children`.\n */\n label?: React.ReactNode;\n /** The information the info button's note shows: text, links or other rich content. */\n info: React.ReactNode;\n /**\n * Accessible name of the info button: the second half of its name, after the label text\n * (\"Password Information\"). Localize it here.\n * @default 'Information'\n */\n infoButtonLabel?: string;\n /**\n * Opens the note on a mouse hover, after a short delay, and on keyboard focus, next to a click\n * (see `InfoButton`'s `openOnHover`, which this passes through unchanged).\n * @default true\n */\n openOnHover?: boolean;\n /** Ref to the root `<span>`. */\n ref?: React.Ref<HTMLSpanElement>;\n}\n\n/**\n * A label followed by a button that reveals more information about it (Fluent's InfoLabel): the\n * label renders in a real `<label htmlFor>`, and the button shows `info` — text, links or other\n * rich content — in a note next to it, rendered once whether the note is open or closed (see\n * `InfoButton`, which owns that note and its opening, closing and Tab order).\n *\n * - `children` is the label content; `label` is a deprecated alias (a warning fires once, and\n * `children` wins when both are given).\n * - `htmlFor`, `required`, `size`, `weight` and `disabled` route to the `<label>`; `disabled` dims\n * only the label text, and the info button stays usable.\n * - The button is named \"‹label text› ‹infoButtonLabel›\" through `aria-labelledby`, which points\n * at the `<label>` and at the button's own id (whose `aria-label` supplies the second half), so\n * several InfoLabels on a page are told apart; `infoButtonLabel` localizes that second half.\n * `openOnHover` and `size` reach the button too.\n * - No `controlRef`: InfoLabel is a label, not a form control, so C-ROUTING's composite-control\n * routing does not apply to it; a layout that needs the button's own element renders `InfoButton`\n * next to a `Label` instead.\n *\n * @example\n * <InfoLabel info=\"Use at least 8 characters.\">Password</InfoLabel>\n */\nexport const InfoLabel = ({\n children,\n label,\n info,\n infoButtonLabel = 'Information',\n openOnHover,\n id,\n htmlFor,\n required,\n size = 'medium',\n weight,\n disabled,\n className,\n ref,\n ...rest\n}: InfoLabelProps) => {\n const content = resolveDeprecatedProp('InfoLabel', children, label, 'label', 'children');\n const generatedLabelId = useId('info-label');\n // An empty `id` counts as unset, so the button's name never points at an empty id.\n const labelId = id || generatedLabelId;\n const buttonId = useId('info-label-button');\n // The note of this InfoButton carries the label's `info` class, its 0.8 popup class (P3-00 D8).\n const noteClass = React.useMemo(\n () => ({ buttonId, className: infoLabelClassNames.info }),\n [buttonId],\n );\n return (\n <span\n ref={ref}\n className={cn(infoLabelClassNames.root, 'inline-flex items-center gap-0', className)}\n {...rest}\n >\n <Label\n className={infoLabelClassNames.label}\n id={labelId}\n htmlFor={htmlFor}\n required={required}\n size={size}\n weight={weight}\n disabled={disabled}\n >\n {content}\n </Label>\n <InfoNoteClassContext.Provider value={noteClass}>\n <InfoButton\n id={buttonId}\n className={infoLabelClassNames.infoButton}\n info={info}\n size={size}\n openOnHover={openOnHover}\n aria-label={infoButtonLabel}\n aria-labelledby={`${labelId} ${buttonId}`}\n />\n </InfoNoteClassContext.Provider>\n </span>\n );\n};\n\nInfoLabel.displayName = 'InfoLabel';\nmarkFieldLabel(InfoLabel);\n"],"mappings":";;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"InfoLabel.mjs","names":["useId","useId$1","React","InfoLabel","rest","content","resolveDeprecatedProp","children","label","generatedLabelId","labelId","id","buttonId","noteClass","infoLabelClassNames","cn","className","Label","InfoNoteClassContext","InfoButton","infoButtonLabel","markFieldLabel"],"sources":["../../../src/components/data-display/InfoLabel.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { infoLabelClassNames } from '../../lib/classNames';\nimport { resolveDeprecatedProp } from '../../lib/dev';\nimport type { MotionSlot } from '../../lib/types';\nimport { useId } from '../../hooks/useId';\nimport { markFieldLabel } from '../input/fieldLabel';\nimport { Label, type LabelProps } from '../input/Label';\nimport { InfoButton, InfoNoteClassContext } from './InfoButton';\n\n/** Properties for the InfoLabel component. */\nexport interface InfoLabelProps\n extends\n Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'>,\n Pick<LabelProps, 'htmlFor' | 'required' | 'size' | 'weight' | 'disabled'> {\n /** The label content (Fluent's `children`). */\n children?: React.ReactNode;\n /**\n * The label content.\n * @deprecated Use `children`.\n */\n label?: React.ReactNode;\n /** The information the info button's note shows: text, links or other rich content. */\n info: React.ReactNode;\n /**\n * Accessible name of the info button: the second half of its name, after the label text\n * (\"Password Information\"). Localize it here.\n * @default 'Information'\n */\n infoButtonLabel?: string;\n /**\n * Opens the note on a mouse hover, after a short delay, and on keyboard focus, next to a click\n * (see `InfoButton`'s `openOnHover`, which this passes through unchanged).\n * @default true\n */\n openOnHover?: boolean;\n /**\n * The motion of the info button's note, passed through unchanged (see `InfoButton`'s `motion`:\n * `undefined` is the default fade and slide, `null` none, a value replaces it). Fluent's\n * `Popover` `surfaceMotion`.\n * @default the fade and slide of InfoButton's note\n */\n motion?: MotionSlot | null;\n /** Ref to the root `<span>`. */\n ref?: React.Ref<HTMLSpanElement>;\n}\n\n/**\n * A label followed by a button that reveals more information about it (Fluent's InfoLabel): the\n * label renders in a real `<label htmlFor>`, and the button shows `info` — text, links or other\n * rich content — in a note next to it, rendered once whether the note is open or closed (see\n * `InfoButton`, which owns that note and its opening, closing and Tab order).\n *\n * - `children` is the label content; `label` is a deprecated alias (a warning fires once, and\n * `children` wins when both are given).\n * - `htmlFor`, `required`, `size`, `weight` and `disabled` route to the `<label>`; `disabled` dims\n * only the label text, and the info button stays usable.\n * - The button is named \"‹label text› ‹infoButtonLabel›\" through `aria-labelledby`, which points\n * at the `<label>` and at the button's own id (whose `aria-label` supplies the second half), so\n * several InfoLabels on a page are told apart; `infoButtonLabel` localizes that second half.\n * `openOnHover`, `motion` and `size` reach the button too.\n * - No `controlRef`: InfoLabel is a label, not a form control, so C-ROUTING's composite-control\n * routing does not apply to it; a layout that needs the button's own element renders `InfoButton`\n * next to a `Label` instead.\n *\n * @example\n * <InfoLabel info=\"Use at least 8 characters.\">Password</InfoLabel>\n */\nexport const InfoLabel = ({\n children,\n label,\n info,\n infoButtonLabel = 'Information',\n openOnHover,\n motion,\n id,\n htmlFor,\n required,\n size = 'medium',\n weight,\n disabled,\n className,\n ref,\n ...rest\n}: InfoLabelProps) => {\n const content = resolveDeprecatedProp('InfoLabel', children, label, 'label', 'children');\n const generatedLabelId = useId('info-label');\n // An empty `id` counts as unset, so the button's name never points at an empty id.\n const labelId = id || generatedLabelId;\n const buttonId = useId('info-label-button');\n // The note of this InfoButton carries the label's `info` class, its 0.8 popup class (P3-00 D8).\n const noteClass = React.useMemo(\n () => ({ buttonId, className: infoLabelClassNames.info }),\n [buttonId],\n );\n return (\n <span\n ref={ref}\n className={cn(infoLabelClassNames.root, 'inline-flex items-center gap-0', className)}\n {...rest}\n >\n <Label\n className={infoLabelClassNames.label}\n id={labelId}\n htmlFor={htmlFor}\n required={required}\n size={size}\n weight={weight}\n disabled={disabled}\n >\n {content}\n </Label>\n <InfoNoteClassContext.Provider value={noteClass}>\n <InfoButton\n id={buttonId}\n className={infoLabelClassNames.infoButton}\n info={info}\n size={size}\n openOnHover={openOnHover}\n motion={motion}\n aria-label={infoButtonLabel}\n aria-labelledby={`${labelId} ${buttonId}`}\n />\n </InfoNoteClassContext.Provider>\n </span>\n );\n};\n\nInfoLabel.displayName = 'InfoLabel';\nmarkFieldLabel(InfoLabel);\n"],"mappings":";;;;;;;;;;;AAoEA,IAAaG,KAAa,EACxB,aACA,UACA,SACA,qBAAkB,eAClB,gBACA,WACA,OACA,YACA,aACA,UAAO,UACP,WACA,aACA,cACA,QACA,GAAGC,QACiB;CACpB,IAAMC,IAAUC,EAAsB,aAAaC,GAAUC,GAAO,SAAS,UAAU,GACjFC,IAAmBT,EAAM,YAAY,GAErCU,IAAUC,KAAMF,GAChBG,IAAWZ,EAAM,mBAAmB,GAEpCa,IAAYX,EAAM,eACf;EAAE;EAAU,WAAWY,EAAoB;CAAK,IACvD,CAACF,CAAQ,CACX;CACA,OACE,kBAAC,QAAD;EACO;EACL,WAAWG,EAAGD,EAAoB,MAAM,kCAAkCE,CAAS;EACnF,GAAIZ;EAHN,UAAA,CAKE,kBAACa,GAAD;GACE,WAAWH,EAAoB;GAC/B,IAAIJ;GACK;GACC;GACJ;GACE;GACE;GAET,UAAAL;EACI,CAAA,GACP,kBAACa,EAAqB,UAAtB;GAA+B,OAAOL;GACpC,UAAA,kBAACM,GAAD;IACE,IAAIP;IACJ,WAAWE,EAAoB;IACzB;IACA;IACO;IACL;IACR,cAAYM;IACZ,mBAAiB,GAAGV,EAAQ,GAAGE;GAChC,CAAA;EAC4B,CAAA,CAC3B;;AAEV;AAEA,EAAU,cAAc,aACxBS,EAAelB,CAAS"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../lib/focus.cjs"),a=require("../../hooks/useMergedRefs.cjs"),o=require("../../hooks/usePresence.cjs"),s=require("../../hooks/usePreserveFocus.cjs"),c=require("../../lib/motion.cjs"),l=require("../../hooks/useMotion.cjs"),u=require("../../hooks/usePresenceGroup.cjs");let d=require("react");d=e.__toESM(d,1);let f=require("react/jsx-runtime");function p(e){return e.classList.contains(r.messageBarGroupClassNames.item)&&e.getAttribute(`data-presence`)!==`exiting`}function m(e){if(!e)return null;for(let t=e.nextElementSibling;t;t=t.nextElementSibling){let e=p(t)?i.getFirstTabbable(t):null;if(e)return e}for(let t=e.previousElementSibling;t;t=t.previousElementSibling){let e=p(t)?i.getFirstTabbable(t):null;if(e)return e}return null}var h=({entry:e,motionClassName:n,onExited:i})=>{let{key:l,element:u,visible:p,appear:h}=e,{isMounted:g,ref:_,presenceProps:v}=o.usePresence(p,{appear:h,onExited:()=>i(l)}),y=d.useRef(null),b=a.useMergedRefs(y,_);return s.usePreserveFocus(y,()=>m(y.current),{enabled:p}),g?(0,f.jsx)(`div`,{ref:b,...v,className:t.cn(r.messageBarGroupClassNames.item,c.messageBarGroupItemStructure,n),children:u}):null};h.displayName=`MessageBarGroupItem`;var g=({animate:e=`exit-only`,motion:i,children:a,className:o,ref:s,...p})=>{let{entries:m,skipped:g,onExited:_}=u.usePresenceGroup(a,{appear:e===`both`}),v=l.useMotionClasses(i,e===`both`?`${c.messageBarGroupExitMotion} ${c.messageBarGroupEnterMotion}`:c.messageBarGroupExitMotion),y=g.length>0;return d.useEffect(()=>{y&&n.warnOnce(`MessageBarGroup:children`,"MessageBarGroup: every child should be an element with a key of its own (a MessageBar with `key={id}`); other children render after the bars, without motion.")},[y]),(0,f.jsxs)(`div`,{ref:s,"data-animate":e,...p,className:t.cn(r.messageBarGroupClassNames.root,`flex flex-col gap-2`,o),children:[m.map(e=>(0,f.jsx)(h,{entry:e,motionClassName:v,onExited:_},e.key)),g]})};g.displayName=`MessageBarGroup`,exports.MessageBarGroup=g;
|
|
2
|
+
//# sourceMappingURL=MessageBarGroup.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBarGroup.cjs","names":["messageBarGroupClassNames","getFirstTabbable","usePresence","React","useMergedRefs","cn","messageBarGroupItemStructure","usePresenceGroup","useMotionClasses","messageBarGroupExitMotion","messageBarGroupEnterMotion","require_runtime","require_cn","require_dev","require_classNames","require_focus","require_useMergedRefs","require_usePresence","require_usePreserveFocus","require_motion","require_useMotion","require_usePresenceGroup","react","react_jsx_runtime","isRemainingItem","el","nextBarFocus","item","target","MessageBarGroupItem","entry","presenceRef","visible","onExited","key","itemRef","mergedRef","isMounted","presenceProps","motionClassName","element","MessageBarGroup","rest","children","animate","motion","hasSkipped","skipped","className","entries"],"sources":["../../../src/components/feedback/MessageBarGroup.tsx"],"sourcesContent":["import * as React from 'react';\nimport { messageBarGroupClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { getFirstTabbable } from '../../lib/focus';\nimport {\n messageBarGroupEnterMotion,\n messageBarGroupExitMotion,\n messageBarGroupItemStructure,\n} from '../../lib/motion';\nimport type { MotionSlot } from '../../lib/types';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useMotionClasses } from '../../hooks/useMotion';\nimport { usePresence } from '../../hooks/usePresence';\nimport { usePresenceGroup, type PresenceGroupEntry } from '../../hooks/usePresenceGroup';\nimport { usePreserveFocus } from '../../hooks/usePreserveFocus';\n\n/** Properties for the MessageBarGroup component. */\nexport interface MessageBarGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Which changes animate: `'exit-only'` (a bar removed from the children fades and collapses\n * out) or `'both'` (a bar added after mount also fades and slides in). Bars present at the\n * group's first render never animate. Fluent's `animate`. The root renders it as\n * `data-animate`.\n * @default 'exit-only'\n */\n animate?: 'exit-only' | 'both';\n /**\n * Replaces the bars' motion (both directions); `null` turns it off. The motion is on the element\n * around each bar (`className` stays on the root). By default a removed bar fades out while its\n * row and its bottom margin close over 250 ms with the linear curve, so the bars after it glide\n * up and nothing jumps when it unmounts (the margin makes up for the group's 8px gap, so a\n * different gap in `className` needs a `motion` whose margin matches it); with\n * `animate=\"both\"`, a bar added after mount opens its row and fades in the same way. Under\n * reduced motion bars appear and disappear at once. `null` turns the motion off (the element\n * still renders its `data-presence` phases, which then end at once); a class string or\n * `{ className }` replaces the default classes with yours (see `MotionSlot`), also under a\n * `WaveProvider` with `motion=\"none\"`, which otherwise turns the default off. A WaveUI addition:\n * Fluent's MessageBarGroup has no motion slot (its bar only fades out).\n * @default the collapse and fade above\n */\n motion?: MotionSlot | null;\n /** MessageBar elements, each with a stable `key`. */\n children?: React.ReactNode;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\ninterface MessageBarGroupItemProps {\n entry: PresenceGroupEntry;\n motionClassName: string;\n onExited: (key: string) => void;\n}\n\n/** Whether `el` is the element around a bar that stays: an item that is not exiting. */\nfunction isRemainingItem(el: Element): boolean {\n return (\n el.classList.contains(messageBarGroupClassNames.item) &&\n el.getAttribute('data-presence') !== 'exiting'\n );\n}\n\n/**\n * Where focus goes when the bar of `item` leaves with focus inside it: the first tabbable element\n * of the nearest bar after it that stays and holds one, else of the nearest such bar before it.\n */\nfunction nextBarFocus(item: HTMLElement | null): HTMLElement | null {\n if (!item) return null;\n for (let el = item.nextElementSibling; el; el = el.nextElementSibling) {\n const target = isRemainingItem(el) ? getFirstTabbable(el) : null;\n if (target) return target;\n }\n for (let el = item.previousElementSibling; el; el = el.previousElementSibling) {\n const target = isRemainingItem(el) ? getFirstTabbable(el) : null;\n if (target) return target;\n }\n return null;\n}\n\n// The element around one bar: the presence element, whose motion ends the bar's phases.\nconst MessageBarGroupItem = ({ entry, motionClassName, onExited }: MessageBarGroupItemProps) => {\n const { key, element, visible, appear } = entry;\n // Destructured: react-hooks/refs treats an object whose member is passed to `ref` as a ref.\n const {\n isMounted,\n ref: presenceRef,\n presenceProps,\n } = usePresence(visible, { appear, onExited: () => onExited(key) });\n const itemRef = React.useRef<HTMLDivElement | null>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(itemRef, presenceRef);\n // Focus leaves a removed bar in its removing commit: `enabled` flipping to `false` moves it in\n // the layout phase, while the exiting item is still there.\n usePreserveFocus(itemRef, () => nextBarFocus(itemRef.current), { enabled: visible });\n if (!isMounted) return null;\n return (\n <div\n ref={mergedRef}\n {...presenceProps}\n className={cn(messageBarGroupClassNames.item, messageBarGroupItemStructure, motionClassName)}\n >\n {element}\n </div>\n );\n};\nMessageBarGroupItem.displayName = 'MessageBarGroupItem';\n\n/**\n * A stack of MessageBars that animates the bars it gains and loses, Fluent's MessageBarGroup with\n * its `animate` prop: a bar removed from the children fades out while its row closes, so the bars\n * below glide up instead of jumping (Fluent's bar only fades, and the bars below jump when it is\n * gone), and with `animate=\"both\"` a bar added after mount opens its row and fades in.\n *\n * - **Keys.** Give every bar a stable `key` (`key={message.id}`): the group follows its children\n * by key, so it can keep a removed bar on screen during its exit, in its place, and move bars\n * that are reordered without replacing them. A removed bar that comes back during its exit is\n * shown again. A child without a key of its own, or text, renders after the bars as given,\n * without motion, with a development warning. Any keyed element animates; MessageBar is the\n * one the group is made for.\n * - **Motion.** Bars present at the group's first render (on the server too) never animate. Each\n * bar sits in an element of its own, which renders no box while the bar is shown, so the bars\n * are the stack's own items; while a bar enters or exits, that element clips it while its row\n * opens or closes. An exiting bar is `inert`. See `motion` for the default and how to replace\n * or turn it off; under `prefers-reduced-motion: reduce` a bar is added and removed at once.\n * - **Focus.** When a bar leaves with focus inside it (its Dismiss button was pressed), focus moves\n * in the same commit to the first tabbable element of the nearest bar after it that stays and\n * holds a tabbable element, else of the nearest such bar before it. When no such bar is left,\n * the app decides where focus goes.\n * - **Markup.** A plain `<div>` without a role stacking the bars with an 8px gap; each MessageBar\n * stays its own live region. MessageBarGroup is a component of its own rather than a part of\n * MessageBar, so a page that imports only MessageBar does not load the group's motion.\n *\n * @example\n * <MessageBarGroup animate=\"both\">\n * {messages.map((message) => (\n * <MessageBar key={message.id} status={message.status} onDismiss={() => dismiss(message.id)}>\n * {message.text}\n * </MessageBar>\n * ))}\n * </MessageBarGroup>\n */\nexport const MessageBarGroup = ({\n animate = 'exit-only',\n motion,\n children,\n className,\n ref,\n ...rest\n}: MessageBarGroupProps) => {\n const { entries, skipped, onExited } = usePresenceGroup(children, {\n appear: animate === 'both',\n });\n // The bars' motion: the exit, and the enter with `animate=\"both\"` (composed at run time).\n const motionClassName = useMotionClasses(\n motion,\n animate === 'both'\n ? `${messageBarGroupExitMotion} ${messageBarGroupEnterMotion}`\n : messageBarGroupExitMotion,\n );\n const hasSkipped = skipped.length > 0;\n React.useEffect(() => {\n if (hasSkipped) {\n warnOnce(\n 'MessageBarGroup:children',\n 'MessageBarGroup: every child should be an element with a key of its own (a MessageBar with `key={id}`); other children render after the bars, without motion.',\n );\n }\n }, [hasSkipped]);\n\n return (\n <div\n ref={ref}\n data-animate={animate}\n {...rest}\n className={cn(messageBarGroupClassNames.root, 'flex flex-col gap-2', className)}\n >\n {entries.map((entry) => (\n <MessageBarGroupItem\n key={entry.key}\n entry={entry}\n motionClassName={motionClassName}\n onExited={onExited}\n />\n ))}\n {skipped}\n </div>\n );\n};\nMessageBarGroup.displayName = 'MessageBarGroup';\n"],"mappings":"6gBAuDA,SAASwB,EAAgB,EAAsB,CAC7C,OACEC,EAAG,UAAU,SAASzB,EAAAA,0BAA0B,IAAI,GACpDyB,EAAG,aAAa,eAAe,IAAM,SAEzC,CAMA,SAASC,EAAa,EAA8C,CAClE,GAAI,CAACC,EAAM,OAAO,KAClB,IAAK,IAAIF,EAAKE,EAAK,mBAAoBF,EAAI,EAAKA,EAAG,mBAAoB,CACrE,IAAMG,EAASJ,EAAgBC,CAAE,EAAIxB,EAAAA,iBAAiBwB,CAAE,EAAI,KAC5D,GAAIG,EAAQ,OAAOA,CACrB,CACA,IAAK,IAAIH,EAAKE,EAAK,uBAAwBF,EAAI,EAAKA,EAAG,uBAAwB,CAC7E,IAAMG,EAASJ,EAAgBC,CAAE,EAAIxB,EAAAA,iBAAiBwB,CAAE,EAAI,KAC5D,GAAIG,EAAQ,OAAOA,CACrB,CACA,OAAO,IACT,CAGA,IAAMC,GAAuB,CAAE,QAAO,kBAAiB,cAAyC,CAC9F,GAAM,CAAE,MAAK,UAAS,UAAS,UAAWC,EAEpC,CACJ,YACA,IAAKC,EACL,iBACE7B,EAAAA,YAAY8B,EAAS,CAAE,SAAQ,aAAgBC,EAASC,CAAG,CAAE,CAAC,EAC5DC,EAAUhC,EAAM,OAA8B,IAAI,EAClDiC,EAAYhC,EAAAA,cAA8B+B,EAASJ,CAAW,EAKpE,OAFAb,EAAA,iBAAiBiB,MAAeT,EAAaS,EAAQ,OAAO,EAAG,CAAE,QAASH,CAAQ,CAAC,EAC9EK,GAEH,EAAAd,EAAA,IAAA,CAAC,MAAD,CACE,IAAKa,EACL,GAAIE,EACJ,UAAWjC,EAAAA,GAAGL,EAAAA,0BAA0B,KAAMM,EAAAA,6BAA8BiC,CAAe,EAE1F,SAAAC,CACE,CAAA,EARgB,IAUzB,EACA,EAAoB,YAAc,sBAoClC,IAAaC,GAAmB,CAC9B,UAAU,YACV,SACA,WACA,YACA,MACA,GAAGC,KACuB,CAC1B,GAAM,CAAE,UAAS,UAAS,YAAanC,EAAAA,iBAAiBoC,EAAU,CAChE,OAAQC,IAAY,MACtB,CAAC,EAEKL,EAAkB/B,EAAAA,iBACtBqC,EACAD,IAAY,OACR,GAAGnC,EAAAA,0BAA0B,GAAGC,EAAAA,6BAChCD,EAAAA,yBACN,EACMqC,EAAaC,EAAQ,OAAS,EAUpC,OATAzB,EAAM,cAAgB,CAChBwB,GACFjC,EAAA,SACE,2BACA,+JACF,CAEJ,EAAG,CAACiC,CAAU,CAAC,GAGb,EAAAvB,EAAA,KAAA,CAAC,MAAD,CACO,MACL,eAAcqB,EACd,GAAIF,EACJ,UAAWrC,EAAAA,GAAGL,EAAAA,0BAA0B,KAAM,sBAAuBgD,CAAS,EAJhF,SAAA,CAMGC,EAAQ,IAAK,IACZ,EAAA1B,EAAA,IAAA,CAACM,EAAD,CAES,QACU,kBACP,UACX,EAJMC,EAAM,GAIZ,CACF,EACAiB,CACE,GAET,EACA,EAAgB,YAAc"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
+
import { warnOnce as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { messageBarGroupClassNames as n } from "../../lib/classNames.mjs";
|
|
5
|
+
import { getFirstTabbable as r } from "../../lib/focus.mjs";
|
|
6
|
+
import { useMergedRefs as i } from "../../hooks/useMergedRefs.mjs";
|
|
7
|
+
import { usePresence as a } from "../../hooks/usePresence.mjs";
|
|
8
|
+
import { usePreserveFocus as o } from "../../hooks/usePreserveFocus.mjs";
|
|
9
|
+
import { messageBarGroupEnterMotion as s, messageBarGroupExitMotion as c, messageBarGroupItemStructure as l } from "../../lib/motion.mjs";
|
|
10
|
+
import { useMotionClasses as u } from "../../hooks/useMotion.mjs";
|
|
11
|
+
import { usePresenceGroup as d } from "../../hooks/usePresenceGroup.mjs";
|
|
12
|
+
import * as f from "react";
|
|
13
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
14
|
+
//#region src/components/feedback/MessageBarGroup.tsx
|
|
15
|
+
function h(e) {
|
|
16
|
+
return e.classList.contains(n.item) && e.getAttribute("data-presence") !== "exiting";
|
|
17
|
+
}
|
|
18
|
+
function g(e) {
|
|
19
|
+
if (!e) return null;
|
|
20
|
+
for (let t = e.nextElementSibling; t; t = t.nextElementSibling) {
|
|
21
|
+
let e = h(t) ? r(t) : null;
|
|
22
|
+
if (e) return e;
|
|
23
|
+
}
|
|
24
|
+
for (let t = e.previousElementSibling; t; t = t.previousElementSibling) {
|
|
25
|
+
let e = h(t) ? r(t) : null;
|
|
26
|
+
if (e) return e;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
var _ = ({ entry: t, motionClassName: r, onExited: s }) => {
|
|
31
|
+
let { key: c, element: u, visible: d, appear: m } = t, { isMounted: h, ref: _, presenceProps: v } = a(d, {
|
|
32
|
+
appear: m,
|
|
33
|
+
onExited: () => s(c)
|
|
34
|
+
}), y = f.useRef(null), b = i(y, _);
|
|
35
|
+
return o(y, () => g(y.current), { enabled: d }), h ? /* @__PURE__ */ p("div", {
|
|
36
|
+
ref: b,
|
|
37
|
+
...v,
|
|
38
|
+
className: e(n.item, l, r),
|
|
39
|
+
children: u
|
|
40
|
+
}) : null;
|
|
41
|
+
};
|
|
42
|
+
_.displayName = "MessageBarGroupItem";
|
|
43
|
+
var v = ({ animate: r = "exit-only", motion: i, children: a, className: o, ref: l, ...h }) => {
|
|
44
|
+
let { entries: g, skipped: v, onExited: y } = d(a, { appear: r === "both" }), b = u(i, r === "both" ? `${c} ${s}` : c), x = v.length > 0;
|
|
45
|
+
return f.useEffect(() => {
|
|
46
|
+
x && t("MessageBarGroup:children", "MessageBarGroup: every child should be an element with a key of its own (a MessageBar with `key={id}`); other children render after the bars, without motion.");
|
|
47
|
+
}, [x]), /* @__PURE__ */ m("div", {
|
|
48
|
+
ref: l,
|
|
49
|
+
"data-animate": r,
|
|
50
|
+
...h,
|
|
51
|
+
className: e(n.root, "flex flex-col gap-2", o),
|
|
52
|
+
children: [g.map((e) => /* @__PURE__ */ p(_, {
|
|
53
|
+
entry: e,
|
|
54
|
+
motionClassName: b,
|
|
55
|
+
onExited: y
|
|
56
|
+
}, e.key)), v]
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
v.displayName = "MessageBarGroup";
|
|
60
|
+
//#endregion
|
|
61
|
+
export { v as MessageBarGroup };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=MessageBarGroup.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MessageBarGroup.mjs","names":["React","isRemainingItem","el","messageBarGroupClassNames","nextBarFocus","item","target","getFirstTabbable","MessageBarGroupItem","entry","presenceRef","usePresence","visible","onExited","key","itemRef","mergedRef","useMergedRefs","usePreserveFocus","isMounted","presenceProps","cn","messageBarGroupItemStructure","motionClassName","element","MessageBarGroup","rest","usePresenceGroup","children","animate","useMotionClasses","motion","messageBarGroupExitMotion","messageBarGroupEnterMotion","hasSkipped","skipped","warnOnce","className","entries"],"sources":["../../../src/components/feedback/MessageBarGroup.tsx"],"sourcesContent":["import * as React from 'react';\nimport { messageBarGroupClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { warnOnce } from '../../lib/dev';\nimport { getFirstTabbable } from '../../lib/focus';\nimport {\n messageBarGroupEnterMotion,\n messageBarGroupExitMotion,\n messageBarGroupItemStructure,\n} from '../../lib/motion';\nimport type { MotionSlot } from '../../lib/types';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { useMotionClasses } from '../../hooks/useMotion';\nimport { usePresence } from '../../hooks/usePresence';\nimport { usePresenceGroup, type PresenceGroupEntry } from '../../hooks/usePresenceGroup';\nimport { usePreserveFocus } from '../../hooks/usePreserveFocus';\n\n/** Properties for the MessageBarGroup component. */\nexport interface MessageBarGroupProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Which changes animate: `'exit-only'` (a bar removed from the children fades and collapses\n * out) or `'both'` (a bar added after mount also fades and slides in). Bars present at the\n * group's first render never animate. Fluent's `animate`. The root renders it as\n * `data-animate`.\n * @default 'exit-only'\n */\n animate?: 'exit-only' | 'both';\n /**\n * Replaces the bars' motion (both directions); `null` turns it off. The motion is on the element\n * around each bar (`className` stays on the root). By default a removed bar fades out while its\n * row and its bottom margin close over 250 ms with the linear curve, so the bars after it glide\n * up and nothing jumps when it unmounts (the margin makes up for the group's 8px gap, so a\n * different gap in `className` needs a `motion` whose margin matches it); with\n * `animate=\"both\"`, a bar added after mount opens its row and fades in the same way. Under\n * reduced motion bars appear and disappear at once. `null` turns the motion off (the element\n * still renders its `data-presence` phases, which then end at once); a class string or\n * `{ className }` replaces the default classes with yours (see `MotionSlot`), also under a\n * `WaveProvider` with `motion=\"none\"`, which otherwise turns the default off. A WaveUI addition:\n * Fluent's MessageBarGroup has no motion slot (its bar only fades out).\n * @default the collapse and fade above\n */\n motion?: MotionSlot | null;\n /** MessageBar elements, each with a stable `key`. */\n children?: React.ReactNode;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\ninterface MessageBarGroupItemProps {\n entry: PresenceGroupEntry;\n motionClassName: string;\n onExited: (key: string) => void;\n}\n\n/** Whether `el` is the element around a bar that stays: an item that is not exiting. */\nfunction isRemainingItem(el: Element): boolean {\n return (\n el.classList.contains(messageBarGroupClassNames.item) &&\n el.getAttribute('data-presence') !== 'exiting'\n );\n}\n\n/**\n * Where focus goes when the bar of `item` leaves with focus inside it: the first tabbable element\n * of the nearest bar after it that stays and holds one, else of the nearest such bar before it.\n */\nfunction nextBarFocus(item: HTMLElement | null): HTMLElement | null {\n if (!item) return null;\n for (let el = item.nextElementSibling; el; el = el.nextElementSibling) {\n const target = isRemainingItem(el) ? getFirstTabbable(el) : null;\n if (target) return target;\n }\n for (let el = item.previousElementSibling; el; el = el.previousElementSibling) {\n const target = isRemainingItem(el) ? getFirstTabbable(el) : null;\n if (target) return target;\n }\n return null;\n}\n\n// The element around one bar: the presence element, whose motion ends the bar's phases.\nconst MessageBarGroupItem = ({ entry, motionClassName, onExited }: MessageBarGroupItemProps) => {\n const { key, element, visible, appear } = entry;\n // Destructured: react-hooks/refs treats an object whose member is passed to `ref` as a ref.\n const {\n isMounted,\n ref: presenceRef,\n presenceProps,\n } = usePresence(visible, { appear, onExited: () => onExited(key) });\n const itemRef = React.useRef<HTMLDivElement | null>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(itemRef, presenceRef);\n // Focus leaves a removed bar in its removing commit: `enabled` flipping to `false` moves it in\n // the layout phase, while the exiting item is still there.\n usePreserveFocus(itemRef, () => nextBarFocus(itemRef.current), { enabled: visible });\n if (!isMounted) return null;\n return (\n <div\n ref={mergedRef}\n {...presenceProps}\n className={cn(messageBarGroupClassNames.item, messageBarGroupItemStructure, motionClassName)}\n >\n {element}\n </div>\n );\n};\nMessageBarGroupItem.displayName = 'MessageBarGroupItem';\n\n/**\n * A stack of MessageBars that animates the bars it gains and loses, Fluent's MessageBarGroup with\n * its `animate` prop: a bar removed from the children fades out while its row closes, so the bars\n * below glide up instead of jumping (Fluent's bar only fades, and the bars below jump when it is\n * gone), and with `animate=\"both\"` a bar added after mount opens its row and fades in.\n *\n * - **Keys.** Give every bar a stable `key` (`key={message.id}`): the group follows its children\n * by key, so it can keep a removed bar on screen during its exit, in its place, and move bars\n * that are reordered without replacing them. A removed bar that comes back during its exit is\n * shown again. A child without a key of its own, or text, renders after the bars as given,\n * without motion, with a development warning. Any keyed element animates; MessageBar is the\n * one the group is made for.\n * - **Motion.** Bars present at the group's first render (on the server too) never animate. Each\n * bar sits in an element of its own, which renders no box while the bar is shown, so the bars\n * are the stack's own items; while a bar enters or exits, that element clips it while its row\n * opens or closes. An exiting bar is `inert`. See `motion` for the default and how to replace\n * or turn it off; under `prefers-reduced-motion: reduce` a bar is added and removed at once.\n * - **Focus.** When a bar leaves with focus inside it (its Dismiss button was pressed), focus moves\n * in the same commit to the first tabbable element of the nearest bar after it that stays and\n * holds a tabbable element, else of the nearest such bar before it. When no such bar is left,\n * the app decides where focus goes.\n * - **Markup.** A plain `<div>` without a role stacking the bars with an 8px gap; each MessageBar\n * stays its own live region. MessageBarGroup is a component of its own rather than a part of\n * MessageBar, so a page that imports only MessageBar does not load the group's motion.\n *\n * @example\n * <MessageBarGroup animate=\"both\">\n * {messages.map((message) => (\n * <MessageBar key={message.id} status={message.status} onDismiss={() => dismiss(message.id)}>\n * {message.text}\n * </MessageBar>\n * ))}\n * </MessageBarGroup>\n */\nexport const MessageBarGroup = ({\n animate = 'exit-only',\n motion,\n children,\n className,\n ref,\n ...rest\n}: MessageBarGroupProps) => {\n const { entries, skipped, onExited } = usePresenceGroup(children, {\n appear: animate === 'both',\n });\n // The bars' motion: the exit, and the enter with `animate=\"both\"` (composed at run time).\n const motionClassName = useMotionClasses(\n motion,\n animate === 'both'\n ? `${messageBarGroupExitMotion} ${messageBarGroupEnterMotion}`\n : messageBarGroupExitMotion,\n );\n const hasSkipped = skipped.length > 0;\n React.useEffect(() => {\n if (hasSkipped) {\n warnOnce(\n 'MessageBarGroup:children',\n 'MessageBarGroup: every child should be an element with a key of its own (a MessageBar with `key={id}`); other children render after the bars, without motion.',\n );\n }\n }, [hasSkipped]);\n\n return (\n <div\n ref={ref}\n data-animate={animate}\n {...rest}\n className={cn(messageBarGroupClassNames.root, 'flex flex-col gap-2', className)}\n >\n {entries.map((entry) => (\n <MessageBarGroupItem\n key={entry.key}\n entry={entry}\n motionClassName={motionClassName}\n onExited={onExited}\n />\n ))}\n {skipped}\n </div>\n );\n};\nMessageBarGroup.displayName = 'MessageBarGroup';\n"],"mappings":";;;;;;;;;;;;;;AAuDA,SAASC,EAAgB,GAAsB;CAC7C,OACEC,EAAG,UAAU,SAASC,EAA0B,IAAI,KACpDD,EAAG,aAAa,eAAe,MAAM;AAEzC;AAMA,SAASE,EAAa,GAA8C;CAClE,IAAI,CAACC,GAAM,OAAO;CAClB,KAAK,IAAIH,IAAKG,EAAK,oBAAoBH,GAAI,IAAKA,EAAG,oBAAoB;EACrE,IAAMI,IAASL,EAAgBC,CAAE,IAAIK,EAAiBL,CAAE,IAAI;EAC5D,IAAII,GAAQ,OAAOA;CACrB;CACA,KAAK,IAAIJ,IAAKG,EAAK,wBAAwBH,GAAI,IAAKA,EAAG,wBAAwB;EAC7E,IAAMI,IAASL,EAAgBC,CAAE,IAAIK,EAAiBL,CAAE,IAAI;EAC5D,IAAII,GAAQ,OAAOA;CACrB;CACA,OAAO;AACT;AAGA,IAAME,KAAuB,EAAE,UAAO,oBAAiB,kBAAyC;CAC9F,IAAM,EAAE,QAAK,YAAS,YAAS,cAAWC,GAEpC,EACJ,cACA,KAAKC,GACL,qBACEC,EAAYC,GAAS;EAAE;EAAQ,gBAAgBC,EAASC,CAAG;CAAE,CAAC,GAC5DC,IAAUf,EAAM,OAA8B,IAAI,GAClDgB,IAAYC,EAA8BF,GAASL,CAAW;CAKpE,OAFAQ,EAAiBH,SAAeX,EAAaW,EAAQ,OAAO,GAAG,EAAE,SAASH,EAAQ,CAAC,GAC9EO,IAEH,kBAAC,OAAD;EACE,KAAKH;EACL,GAAII;EACJ,WAAWC,EAAGlB,EAA0B,MAAMmB,GAA8BC,CAAe;EAE1F,UAAAC;CACE,CAAA,IARgB;AAUzB;AACA,EAAoB,cAAc;AAoClC,IAAaC,KAAmB,EAC9B,aAAU,aACV,WACA,aACA,cACA,QACA,GAAGC,QACuB;CAC1B,IAAM,EAAE,YAAS,YAAS,gBAAaC,EAAiBC,GAAU,EAChE,QAAQC,MAAY,OACtB,CAAC,GAEKN,IAAkBO,EACtBC,GACAF,MAAY,SACR,GAAGG,EAA0B,GAAGC,MAChCD,CACN,GACME,IAAaC,EAAQ,SAAS;CAUpC,OATAnC,EAAM,gBAAgB;EACpB,AAAIkC,KACFE,EACE,4BACA,+JACF;CAEJ,GAAG,CAACF,CAAU,CAAC,GAGb,kBAAC,OAAD;EACO;EACL,gBAAcL;EACd,GAAIH;EACJ,WAAWL,EAAGlB,EAA0B,MAAM,uBAAuBkC,CAAS;EAJhF,UAAA,CAMGC,EAAQ,KAAK,MACZ,kBAAC9B,GAAD;GAES;GACU;GACP;EACX,GAJMC,EAAM,GAIZ,CACF,GACA0B,CACE;;AAET;AACA,EAAgB,cAAc"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../hooks/useId.cjs"),a=require("../../hooks/useFieldControl.cjs"),o=require("../../lib/styles.cjs");let
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/classNames.cjs"),i=require("../../hooks/useId.cjs"),a=require("../../hooks/useFieldControl.cjs"),o=require("../../lib/styles.cjs"),s=require("../../lib/motion.cjs"),c=require("../../hooks/useMotion.cjs");let l=require("react");l=e.__toESM(l,1);let u=require("react/jsx-runtime");var d={brand:`bg-primary`,success:`bg-success`,warning:`bg-severe`,error:`bg-error`},f={error:`error`,warning:`warning`,success:`success`};function p(e){return typeof e==`string`&&e.trim()!==``}var m=({value:e,max:m=100,label:h,showLabel:g,color:_,indeterminateMotion:v,id:y,"aria-describedby":b,"aria-invalid":x,"aria-required":S,className:C,ref:w,...T})=>{let E=i.useId(`progress-label`),D=i.useId(`progress`),O=a.useFieldContext(),k=a.useFieldControl({id:y??(O?D:void 0),"aria-describedby":b},{labelable:!1}),A=O?O.validationState??(O.invalid?`error`:`none`):`none`,j=_??f[A]??`brand`,M=e===void 0,N=c.useMotionClasses(v,s.progressIndeterminateMotion),P=Number.isFinite(m)&&m>0,F=M||Number.isFinite(e),I=!M&&P&&F?Math.min(m,Math.max(0,e)):0,L=P?I/m*100:0,R=p(h),z=p(T[`aria-label`]),B=p(T[`aria-labelledby`]),V=k[`aria-labelledby`],H=!R&&!z&&!B&&p(V);l.useEffect(()=>{n.isDev&&(!R&&!z&&!B&&!H&&n.warnOnce(`ProgressBar:name`,"ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`."),g&&!R&&n.warnOnce(`ProgressBar:show-label`,"ProgressBar: `showLabel` renders the `label` prop, which is empty."),P||n.warnOnce(`ProgressBar:max`,`ProgressBar: \`max\` must be a finite number greater than 0 (got ${String(m)}); the bar renders 0%.`),F||n.warnOnce(`ProgressBar:value`,`ProgressBar: \`value\` must be a finite number (got ${String(e)}); the bar renders 0%.`))},[R,z,B,H,g,P,F,m,e]);let U=!!(g&&R),W={role:`progressbar`,"aria-valuenow":M?void 0:I,"aria-valuemin":0,"aria-valuemax":P?m:100,"data-color":j};k.id!==void 0&&(W.id=k.id),k[`aria-describedby`]!==void 0&&(W[`aria-describedby`]=k[`aria-describedby`]),!z&&!B&&(U?W[`aria-labelledby`]=E:R?W[`aria-label`]=h:H&&(W[`aria-labelledby`]=V));for(let[e,t]of Object.entries(T))t!==void 0&&(e!==`aria-label`&&e!==`aria-labelledby`||p(t))&&(W[e]=t);let G=(0,u.jsx)(`div`,{...W,ref:w,className:t.cn(r.progressBarClassNames.root,`h-2 overflow-hidden rounded-full bg-track`,`forced-colors:border`,o.forcedColors.border,C),children:(0,u.jsx)(`div`,{className:t.cn(r.progressBarClassNames.bar,`h-full rounded-full`,d[j],o.forcedColors.selectedLeaf,M&&t.cn(`w-full`,N)),style:M?void 0:{width:`${L}%`}})});return U?(0,u.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,u.jsx)(`span`,{id:E,className:t.cn(r.progressBarClassNames.label,`text-body-1 text-foreground`),children:h}),G]}):G};m.displayName=`ProgressBar`,exports.ProgressBar=m;
|
|
2
2
|
//# sourceMappingURL=ProgressBar.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressBar.cjs","names":["useId","useFieldContext","useFieldControl","isDev","cn","progressBarClassNames","forcedColors","require_runtime","require_cn","require_dev","require_classNames","require_useId","require_useFieldControl","require_styles","react","react_jsx_runtime","fillColorClasses","fieldColors","isName","value","ProgressBar","ariaDescribedBy","_ariaInvalid","_ariaRequired","rest","labelId","ownId","field","fieldProps","id","fieldState","resolvedColor","color","isIndeterminate","validMax","max","validValue","clamped","percentage","hasLabel","label","hasAriaLabel","hasAriaLabelledBy","fieldLabelledBy","hasFieldName","showLabel","visibleLabel","barProps","key","propValue","bar","className"],"sources":["../../../src/components/feedback/ProgressBar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { progressBarClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isDev, warnOnce } from '../../lib/dev';\nimport { forcedColors } from '../../lib/styles';\nimport type { ValidationState } from '../../lib/types';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useId } from '../../hooks/useId';\n\n/** Color of a {@link ProgressBar}'s fill. */\nexport type ProgressBarColor = 'brand' | 'success' | 'warning' | 'error';\n\n/** Properties for the ProgressBar component. */\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Current progress value, clamped to `0…max` for both the fill and `aria-valuenow`. Omit for\n * indeterminate mode. A non-finite value renders 0% (development warning).\n */\n value?: number;\n /**\n * Maximum progress value. A `max` of 0 or less, or a non-finite `max`, renders 0% (development\n * warning) and is reported to assistive technology as 0 of 100.\n * @default 100\n */\n max?: number;\n /**\n * Accessible name of the progress bar: `aria-label` by default, or a visible label with\n * `showLabel`. A progress bar needs a name (`label`, `aria-label` or `aria-labelledby`); a\n * development warning fires without one. A consumer `aria-label` or `aria-labelledby` takes\n * precedence over `label`; an empty or whitespace-only one counts as absent (it is not rendered).\n * Inside a `Field`, the Field's label names the bar when neither `label` nor a consumer name is\n * given.\n */\n label?: string;\n /**\n * Renders `label` as visible text above the bar and names the bar with it (`aria-labelledby`)\n * instead of `aria-label`, unless a consumer `aria-label` or `aria-labelledby` names the bar\n * (keep the visible text in that name, WCAG 2.5.3). The label and the bar are then wrapped in a\n * `div`; `ref`, `className`, `style` and the other props stay on the progress bar element.\n */\n showLabel?: boolean;\n /**\n * Color of the fill. Inside a `Field` it follows the Field's validation state (error, warning,\n * success) unless you set it. `warning` fills with the dark orange of the `severe` color, which\n * keeps 3:1 against the track in every theme. The bar carries `data-color` with the resolved\n * color.\n * @default 'brand'\n */\n color?: ProgressBarColor;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst fillColorClasses: Record<ProgressBarColor, string> = {\n brand: 'bg-primary',\n success: 'bg-success',\n // The warning token (a light yellow) is 1.02:1 on the light track: the severe orange passes 3:1.\n warning: 'bg-severe',\n error: 'bg-error',\n};\n\n/** The fill color a Field's validation state gives the bar (`none` keeps the default). */\nconst fieldColors: Partial<Record<ValidationState, ProgressBarColor>> = {\n error: 'error',\n warning: 'warning',\n success: 'success',\n};\n\n/** Whether a name prop (`label`, `aria-label`, `aria-labelledby`) holds more than whitespace. */\nfunction isName(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\n/**\n * Shows the progress of a task, or that a task is running (indeterminate, `value` omitted).\n *\n * - Name it with `label` (or `aria-label` / `aria-labelledby`); `showLabel` shows the label above\n * the bar.\n * - `value` is clamped to `0…max`; invalid numbers render an empty bar and warn in development.\n * - `color` picks the fill (`brand`, `success`, `warning`, `error`).\n * - Inside a `Field`, the Field's label names a bar that has no name of its own, its validation\n * message and hint describe the bar, and its validation state (error, warning, success) colors\n * the fill unless `color` is set. A progress bar is never invalid or required: the\n * `aria-invalid` and `aria-required` a Field adds are not rendered. Next to another control in\n * a Field's wrapper element, the bar gets an id of its own and leaves the Field's\n * `<label htmlFor>` to that control.\n * - The indeterminate animation follows the writing direction and becomes a full-width pulse for\n * reduced motion. In forced-colors mode the fill uses `Highlight` and the track gets a border.\n *\n * @example\n * <ProgressBar value={uploaded} max={total} label=\"Uploading photos\" showLabel />\n *\n * @example\n * <Field label=\"Upload\" validationState=\"warning\" validationMessage=\"The connection is slow.\">\n * <ProgressBar value={uploaded} max={total} />\n * </Field>\n */\nexport const ProgressBar = ({\n value,\n max = 100,\n label,\n showLabel,\n color,\n id,\n 'aria-describedby': ariaDescribedBy,\n // Field merges both into its first child; neither is allowed on role=\"progressbar\".\n 'aria-invalid': _ariaInvalid,\n 'aria-required': _ariaRequired,\n className,\n ref,\n ...rest\n}: ProgressBarProps) => {\n const labelId = useId('progress-label');\n const ownId = useId('progress');\n const field = useFieldContext();\n // A <label htmlFor> cannot name a progress bar, so inside a Field a bar without an id (Field\n // passes its control id to a first child as `id`) takes its own instead of claiming the\n // control id: that stays with the control the label names (an Input next to the bar in a\n // wrapper). No name props are passed, so with `labelable: false` the merged `aria-labelledby`\n // is exactly the Field's label id (or absent); it is used only when the bar has no name of its\n // own.\n const fieldProps = useFieldControl(\n { id: id ?? (field ? ownId : undefined), 'aria-describedby': ariaDescribedBy },\n { labelable: false },\n );\n // A context built before 0.6 has no validation state: read it from `invalid`.\n const fieldState = field ? (field.validationState ?? (field.invalid ? 'error' : 'none')) : 'none';\n const resolvedColor = color ?? fieldColors[fieldState] ?? 'brand';\n const isIndeterminate = value === undefined;\n const validMax = Number.isFinite(max) && max > 0;\n const validValue = isIndeterminate || Number.isFinite(value);\n /** Clamped once, used for both the fill width and `aria-valuenow`. */\n const clamped =\n !isIndeterminate && validMax && validValue ? Math.min(max, Math.max(0, value)) : 0;\n const percentage = validMax ? (clamped / max) * 100 : 0;\n\n // An empty or whitespace-only `label`, `aria-label` or `aria-labelledby` names nothing: it is\n // treated like `undefined` by the precedence, the rendered attributes and the warning alike.\n const hasLabel = isName(label);\n const hasAriaLabel = isName(rest['aria-label']);\n const hasAriaLabelledBy = isName(rest['aria-labelledby']);\n const fieldLabelledBy = fieldProps['aria-labelledby'];\n const hasFieldName = !hasLabel && !hasAriaLabel && !hasAriaLabelledBy && isName(fieldLabelledBy);\n\n // Development diagnostics (C-DEV): emitted from an effect, once per page.\n React.useEffect(() => {\n if (!isDev) return;\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasFieldName) {\n warnOnce(\n 'ProgressBar:name',\n 'ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`.',\n );\n }\n if (showLabel && !hasLabel) {\n warnOnce(\n 'ProgressBar:show-label',\n 'ProgressBar: `showLabel` renders the `label` prop, which is empty.',\n );\n }\n if (!validMax) {\n warnOnce(\n 'ProgressBar:max',\n `ProgressBar: \\`max\\` must be a finite number greater than 0 (got ${String(max)}); the bar renders 0%.`,\n );\n }\n if (!validValue) {\n warnOnce(\n 'ProgressBar:value',\n `ProgressBar: \\`value\\` must be a finite number (got ${String(value)}); the bar renders 0%.`,\n );\n }\n }, [\n hasLabel,\n hasAriaLabel,\n hasAriaLabelledBy,\n hasFieldName,\n showLabel,\n validMax,\n validValue,\n max,\n value,\n ]);\n\n const visibleLabel = Boolean(showLabel && hasLabel);\n\n /**\n * The bar's attributes. Defaults the consumer may override (C-COMPOSE) apply wherever the\n * consumer's value is `undefined` — also when the key is present, e.g. a wrapper that forwards\n * `aria-label={props['aria-label']}` — so a forwarded `undefined` never strips the role, the\n * values or the name derived from `label`. An empty `aria-label`/`aria-labelledby` is dropped\n * the same way instead of rendering a nameless attribute.\n */\n const barProps: Record<string, unknown> = {\n role: 'progressbar',\n 'aria-valuenow': isIndeterminate ? undefined : clamped,\n 'aria-valuemin': 0,\n 'aria-valuemax': validMax ? max : 100,\n 'data-color': resolvedColor,\n };\n // The consumer's id (or the control id Field passes to its first child), else its own id inside\n // a Field; the consumer's description, then the Field's validation message and hint.\n if (fieldProps.id !== undefined) barProps.id = fieldProps.id;\n if (fieldProps['aria-describedby'] !== undefined) {\n barProps['aria-describedby'] = fieldProps['aria-describedby'];\n }\n // A consumer `aria-label` or `aria-labelledby` wins over the name derived from `label`, also\n // with `showLabel` (the visible label then stays unreferenced text). The Field's label names\n // only a bar without a name of its own.\n if (!hasAriaLabel && !hasAriaLabelledBy) {\n if (visibleLabel) barProps['aria-labelledby'] = labelId;\n else if (hasLabel) barProps['aria-label'] = label;\n else if (hasFieldName) barProps['aria-labelledby'] = fieldLabelledBy;\n }\n for (const [key, propValue] of Object.entries(rest)) {\n if (propValue === undefined) continue;\n if ((key === 'aria-label' || key === 'aria-labelledby') && !isName(propValue)) continue;\n barProps[key] = propValue;\n }\n\n const bar = (\n <div\n {...barProps}\n ref={ref}\n className={cn(\n progressBarClassNames.root,\n 'h-2 overflow-hidden rounded-full bg-track',\n 'forced-colors:border',\n forcedColors.border,\n className,\n )}\n >\n <div\n className={cn(\n progressBarClassNames.bar,\n 'h-full rounded-full',\n fillColorClasses[resolvedColor],\n forcedColors.selectedLeaf,\n isIndeterminate &&\n 'w-2/5 animate-wave-indeterminate wave-rtl:animate-wave-indeterminate-rtl motion-reduce:w-full motion-reduce:translate-x-0 motion-reduce:animate-wave-pulse wave-rtl:motion-reduce:animate-wave-pulse',\n )}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n );\n\n if (!visibleLabel) return bar;\n\n return (\n <div className=\"flex flex-col gap-1\">\n <span id={labelId} className={cn(progressBarClassNames.label, 'text-body-1 text-foreground')}>\n {label}\n </span>\n {bar}\n </div>\n );\n};\n\nProgressBar.displayName = 'ProgressBar';\n"],"mappings":"qWAoDA,IAAMgB,EAAqD,CACzD,MAAO,aACP,QAAS,aAET,QAAS,YACT,MAAO,UACT,EAGMC,EAAkE,CACtE,MAAO,QACP,QAAS,UACT,QAAS,SACX,EAGA,SAASC,EAAO,EAAiC,CAC/C,OAAO,OAAOC,GAAU,UAAYA,EAAM,KAAK,IAAM,EACvD,CA0BA,IAAaC,GAAe,CAC1B,QACA,MAAM,IACN,QACA,YACA,QACA,KACA,mBAAoBC,EAEpB,eAAgBC,EAChB,gBAAiBC,EACjB,YACA,MACA,GAAGC,KACmB,CACtB,IAAMC,EAAUzB,EAAAA,MAAM,gBAAgB,EAChC0B,EAAQ1B,EAAAA,MAAM,UAAU,EACxB2B,EAAQ1B,EAAAA,gBAAgB,EAOxB2B,EAAa1B,EAAAA,gBACjB,CAAE,GAAI2B,IAAOF,EAAQD,EAAQ,IAAA,IAAY,mBAAoBL,CAAgB,EAC7E,CAAE,UAAW,EAAM,CACrB,EAEMS,EAAaH,EAASA,EAAM,kBAAoBA,EAAM,QAAU,QAAU,QAAW,OACrFI,EAAgBC,GAASf,EAAYa,IAAe,QACpDG,EAAkBd,IAAU,IAAA,GAC5Be,EAAW,OAAO,SAASC,CAAG,GAAKA,EAAM,EACzCC,EAAaH,GAAmB,OAAO,SAASd,CAAK,EAErDkB,EACJ,CAACJ,GAAmBC,GAAYE,EAAa,KAAK,IAAID,EAAK,KAAK,IAAI,EAAGhB,CAAK,CAAC,EAAI,EAC7EmB,EAAaJ,EAAYG,EAAUF,EAAO,IAAM,EAIhDI,EAAWrB,EAAOsB,CAAK,EACvBC,EAAevB,EAAOM,EAAK,aAAa,EACxCkB,EAAoBxB,EAAOM,EAAK,kBAAkB,EAClDmB,EAAkBf,EAAW,mBAC7BgB,EAAe,CAACL,GAAY,CAACE,GAAgB,CAACC,GAAqBxB,EAAOyB,CAAe,EAG/F7B,EAAM,cAAgB,CACfX,EAAAA,QACD,CAACoC,GAAY,CAACE,GAAgB,CAACC,GAAqB,CAACE,GACvDnC,EAAA,SACE,mBACA,qIACF,EAEEoC,GAAa,CAACN,GAChB9B,EAAA,SACE,yBACA,oEACF,EAEGyB,GACHzB,EAAA,SACE,kBACA,oEAAoE,OAAO0B,CAAG,EAAE,uBAClF,EAEGC,GACH3B,EAAA,SACE,oBACA,uDAAuD,OAAOU,CAAK,EAAE,uBACvE,EAEJ,EAAG,CACDoB,EACAE,EACAC,EACAE,EACAC,EACAX,EACAE,EACAD,EACAhB,CACF,CAAC,EAED,IAAM2B,EAAe,GAAQD,GAAaN,GASpCQ,EAAoC,CACxC,KAAM,cACN,gBAAiBd,EAAkB,IAAA,GAAYI,EAC/C,gBAAiB,EACjB,gBAAiBH,EAAWC,EAAM,IAClC,aAAcJ,CAChB,EAGIH,EAAW,KAAO,IAAA,KAAW,EAAS,GAAKA,EAAW,IACtDA,EAAW,sBAAwB,IAAA,KACrC,EAAS,oBAAsBA,EAAW,qBAKxC,CAACa,GAAgB,CAACC,IAChBI,EAAc,EAAS,mBAAqBrB,EACvCc,EAAU,EAAS,cAAgBC,EACnCI,IAAc,EAAS,mBAAqBD,IAEvD,IAAK,GAAM,CAACK,EAAKC,KAAc,OAAO,QAAQzB,CAAI,EAC5CyB,IAAc,IAAA,KACbD,IAAQ,cAAgBA,IAAQ,mBAAuB9B,EAAO+B,CAAS,KAC5E,EAASD,GAAOC,GAGlB,IAAMC,GACJ,EAAAnC,EAAA,IAAA,CAAC,MAAD,CACE,GAAIgC,EACC,MACL,UAAW3C,EAAAA,GACTC,EAAAA,sBAAsB,KACtB,4CACA,uBACAC,EAAAA,aAAa,OACb6C,CACF,EAEA,UAAA,EAAApC,EAAA,IAAA,CAAC,MAAD,CACE,UAAWX,EAAAA,GACTC,EAAAA,sBAAsB,IACtB,sBACAW,EAAiBe,GACjBzB,EAAAA,aAAa,aACb2B,GACE,sMACJ,EACA,MAAOA,EAAkB,IAAA,GAAY,CAAE,MAAO,GAAGK,EAAW,EAAG,CAChE,CAAA,CACE,CAAA,EAKP,OAFKQ,GAGH,EAAA/B,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,sBAAf,SAAA,EACE,EAAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAIU,EAAS,UAAWrB,EAAAA,GAAGC,EAAAA,sBAAsB,MAAO,6BAA6B,EACxF,SAAAmC,CACG,CAAA,EACLU,CACE,IARmBA,CAU5B,EAEA,EAAY,YAAc"}
|
|
1
|
+
{"version":3,"file":"ProgressBar.cjs","names":["useId","useFieldContext","useFieldControl","useMotionClasses","progressIndeterminateMotion","isDev","cn","progressBarClassNames","forcedColors","require_runtime","require_cn","require_dev","require_classNames","require_useId","require_useFieldControl","require_styles","require_motion","require_useMotion","react","react_jsx_runtime","fillColorClasses","fieldColors","isName","value","ProgressBar","ariaDescribedBy","_ariaInvalid","_ariaRequired","rest","labelId","ownId","field","fieldProps","id","fieldState","resolvedColor","color","isIndeterminate","indeterminateClasses","indeterminateMotion","validMax","max","validValue","clamped","percentage","hasLabel","label","hasAriaLabel","hasAriaLabelledBy","fieldLabelledBy","hasFieldName","showLabel","visibleLabel","barProps","key","propValue","bar","className"],"sources":["../../../src/components/feedback/ProgressBar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { progressBarClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isDev, warnOnce } from '../../lib/dev';\nimport { progressIndeterminateMotion } from '../../lib/motion';\nimport { forcedColors } from '../../lib/styles';\nimport type { MotionSlot, ValidationState } from '../../lib/types';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useId } from '../../hooks/useId';\nimport { useMotionClasses } from '../../hooks/useMotion';\n\n/** Color of a {@link ProgressBar}'s fill. */\nexport type ProgressBarColor = 'brand' | 'success' | 'warning' | 'error';\n\n/** Properties for the ProgressBar component. */\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Current progress value, clamped to `0…max` for both the fill and `aria-valuenow`. Omit for\n * indeterminate mode. A non-finite value renders 0% (development warning).\n */\n value?: number;\n /**\n * Maximum progress value. A `max` of 0 or less, or a non-finite `max`, renders 0% (development\n * warning) and is reported to assistive technology as 0 of 100.\n * @default 100\n */\n max?: number;\n /**\n * Accessible name of the progress bar: `aria-label` by default, or a visible label with\n * `showLabel`. A progress bar needs a name (`label`, `aria-label` or `aria-labelledby`); a\n * development warning fires without one. A consumer `aria-label` or `aria-labelledby` takes\n * precedence over `label`; an empty or whitespace-only one counts as absent (it is not rendered).\n * Inside a `Field`, the Field's label names the bar when neither `label` nor a consumer name is\n * given.\n */\n label?: string;\n /**\n * Renders `label` as visible text above the bar and names the bar with it (`aria-labelledby`)\n * instead of `aria-label`, unless a consumer `aria-label` or `aria-labelledby` names the bar\n * (keep the visible text in that name, WCAG 2.5.3). The label and the bar are then wrapped in a\n * `div`; `ref`, `className`, `style` and the other props stay on the progress bar element.\n */\n showLabel?: boolean;\n /**\n * Color of the fill. Inside a `Field` it follows the Field's validation state (error, warning,\n * success) unless you set it. `warning` fills with the dark orange of the `severe` color, which\n * keeps 3:1 against the track in every theme. The bar carries `data-color` with the resolved\n * color.\n * @default 'brand'\n */\n color?: ProgressBarColor;\n /**\n * Replaces the motion of the indeterminate fill (no `value`): by default a fill two fifths of\n * the track wide sweeps across it, mirrored in right-to-left, and becomes a full-width pulse\n * for reduced motion. The classes go on the fill and replace the whole default, its width and\n * its reduced-motion counterparts included. `null` draws a static full-width fill; a class\n * string or `{ className }` replaces the classes with plain animation classes (and a width) and\n * their reduced-motion counterparts (the fill has no presence phases). A\n * `WaveProvider` with `motion=\"none\"` turns the default off (a static full-width fill), and a\n * value here still applies under it. A determinate bar has no motion and ignores it. Fluent's\n * ProgressBar `indeterminateMotion` takes a motion slot the same way.\n * @default the sweep described above\n */\n indeterminateMotion?: MotionSlot | null;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst fillColorClasses: Record<ProgressBarColor, string> = {\n brand: 'bg-primary',\n success: 'bg-success',\n // The warning token (a light yellow) is 1.02:1 on the light track: the severe orange passes 3:1.\n warning: 'bg-severe',\n error: 'bg-error',\n};\n\n/** The fill color a Field's validation state gives the bar (`none` keeps the default). */\nconst fieldColors: Partial<Record<ValidationState, ProgressBarColor>> = {\n error: 'error',\n warning: 'warning',\n success: 'success',\n};\n\n/** Whether a name prop (`label`, `aria-label`, `aria-labelledby`) holds more than whitespace. */\nfunction isName(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\n/**\n * Shows the progress of a task, or that a task is running (indeterminate, `value` omitted).\n *\n * - Name it with `label` (or `aria-label` / `aria-labelledby`); `showLabel` shows the label above\n * the bar.\n * - `value` is clamped to `0…max`; invalid numbers render an empty bar and warn in development.\n * - `color` picks the fill (`brand`, `success`, `warning`, `error`).\n * - Inside a `Field`, the Field's label names a bar that has no name of its own, its validation\n * message and hint describe the bar, and its validation state (error, warning, success) colors\n * the fill unless `color` is set. A progress bar is never invalid or required: the\n * `aria-invalid` and `aria-required` a Field adds are not rendered. Next to another control in\n * a Field's wrapper element, the bar gets an id of its own and leaves the Field's\n * `<label htmlFor>` to that control.\n * - The indeterminate animation follows the writing direction and becomes a full-width pulse for\n * reduced motion; `indeterminateMotion` replaces or removes it. In forced-colors mode the fill\n * uses `Highlight` and the track gets a border.\n *\n * @example\n * <ProgressBar value={uploaded} max={total} label=\"Uploading photos\" showLabel />\n *\n * @example\n * <Field label=\"Upload\" validationState=\"warning\" validationMessage=\"The connection is slow.\">\n * <ProgressBar value={uploaded} max={total} />\n * </Field>\n */\nexport const ProgressBar = ({\n value,\n max = 100,\n label,\n showLabel,\n color,\n indeterminateMotion,\n id,\n 'aria-describedby': ariaDescribedBy,\n // Field merges both into its first child; neither is allowed on role=\"progressbar\".\n 'aria-invalid': _ariaInvalid,\n 'aria-required': _ariaRequired,\n className,\n ref,\n ...rest\n}: ProgressBarProps) => {\n const labelId = useId('progress-label');\n const ownId = useId('progress');\n const field = useFieldContext();\n // A <label htmlFor> cannot name a progress bar, so inside a Field a bar without an id (Field\n // passes its control id to a first child as `id`) takes its own instead of claiming the\n // control id: that stays with the control the label names (an Input next to the bar in a\n // wrapper). No name props are passed, so with `labelable: false` the merged `aria-labelledby`\n // is exactly the Field's label id (or absent); it is used only when the bar has no name of its\n // own.\n const fieldProps = useFieldControl(\n { id: id ?? (field ? ownId : undefined), 'aria-describedby': ariaDescribedBy },\n { labelable: false },\n );\n // A context built before 0.6 has no validation state: read it from `invalid`.\n const fieldState = field ? (field.validationState ?? (field.invalid ? 'error' : 'none')) : 'none';\n const resolvedColor = color ?? fieldColors[fieldState] ?? 'brand';\n const isIndeterminate = value === undefined;\n // Called whatever the mode, so the hook order never changes when `value` appears.\n const indeterminateClasses = useMotionClasses(indeterminateMotion, progressIndeterminateMotion);\n const validMax = Number.isFinite(max) && max > 0;\n const validValue = isIndeterminate || Number.isFinite(value);\n /** Clamped once, used for both the fill width and `aria-valuenow`. */\n const clamped =\n !isIndeterminate && validMax && validValue ? Math.min(max, Math.max(0, value)) : 0;\n const percentage = validMax ? (clamped / max) * 100 : 0;\n\n // An empty or whitespace-only `label`, `aria-label` or `aria-labelledby` names nothing: it is\n // treated like `undefined` by the precedence, the rendered attributes and the warning alike.\n const hasLabel = isName(label);\n const hasAriaLabel = isName(rest['aria-label']);\n const hasAriaLabelledBy = isName(rest['aria-labelledby']);\n const fieldLabelledBy = fieldProps['aria-labelledby'];\n const hasFieldName = !hasLabel && !hasAriaLabel && !hasAriaLabelledBy && isName(fieldLabelledBy);\n\n // Development diagnostics (C-DEV): emitted from an effect, once per page.\n React.useEffect(() => {\n if (!isDev) return;\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasFieldName) {\n warnOnce(\n 'ProgressBar:name',\n 'ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`.',\n );\n }\n if (showLabel && !hasLabel) {\n warnOnce(\n 'ProgressBar:show-label',\n 'ProgressBar: `showLabel` renders the `label` prop, which is empty.',\n );\n }\n if (!validMax) {\n warnOnce(\n 'ProgressBar:max',\n `ProgressBar: \\`max\\` must be a finite number greater than 0 (got ${String(max)}); the bar renders 0%.`,\n );\n }\n if (!validValue) {\n warnOnce(\n 'ProgressBar:value',\n `ProgressBar: \\`value\\` must be a finite number (got ${String(value)}); the bar renders 0%.`,\n );\n }\n }, [\n hasLabel,\n hasAriaLabel,\n hasAriaLabelledBy,\n hasFieldName,\n showLabel,\n validMax,\n validValue,\n max,\n value,\n ]);\n\n const visibleLabel = Boolean(showLabel && hasLabel);\n\n /**\n * The bar's attributes. Defaults the consumer may override (C-COMPOSE) apply wherever the\n * consumer's value is `undefined` — also when the key is present, e.g. a wrapper that forwards\n * `aria-label={props['aria-label']}` — so a forwarded `undefined` never strips the role, the\n * values or the name derived from `label`. An empty `aria-label`/`aria-labelledby` is dropped\n * the same way instead of rendering a nameless attribute.\n */\n const barProps: Record<string, unknown> = {\n role: 'progressbar',\n 'aria-valuenow': isIndeterminate ? undefined : clamped,\n 'aria-valuemin': 0,\n 'aria-valuemax': validMax ? max : 100,\n 'data-color': resolvedColor,\n };\n // The consumer's id (or the control id Field passes to its first child), else its own id inside\n // a Field; the consumer's description, then the Field's validation message and hint.\n if (fieldProps.id !== undefined) barProps.id = fieldProps.id;\n if (fieldProps['aria-describedby'] !== undefined) {\n barProps['aria-describedby'] = fieldProps['aria-describedby'];\n }\n // A consumer `aria-label` or `aria-labelledby` wins over the name derived from `label`, also\n // with `showLabel` (the visible label then stays unreferenced text). The Field's label names\n // only a bar without a name of its own.\n if (!hasAriaLabel && !hasAriaLabelledBy) {\n if (visibleLabel) barProps['aria-labelledby'] = labelId;\n else if (hasLabel) barProps['aria-label'] = label;\n else if (hasFieldName) barProps['aria-labelledby'] = fieldLabelledBy;\n }\n for (const [key, propValue] of Object.entries(rest)) {\n if (propValue === undefined) continue;\n if ((key === 'aria-label' || key === 'aria-labelledby') && !isName(propValue)) continue;\n barProps[key] = propValue;\n }\n\n const bar = (\n <div\n {...barProps}\n ref={ref}\n className={cn(\n progressBarClassNames.root,\n 'h-2 overflow-hidden rounded-full bg-track',\n 'forced-colors:border',\n forcedColors.border,\n className,\n )}\n >\n <div\n className={cn(\n progressBarClassNames.bar,\n 'h-full rounded-full',\n fillColorClasses[resolvedColor],\n forcedColors.selectedLeaf,\n isIndeterminate && cn('w-full', indeterminateClasses),\n )}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n );\n\n if (!visibleLabel) return bar;\n\n return (\n <div className=\"flex flex-col gap-1\">\n <span id={labelId} className={cn(progressBarClassNames.label, 'text-body-1 text-foreground')}>\n {label}\n </span>\n {bar}\n </div>\n );\n};\n\nProgressBar.displayName = 'ProgressBar';\n"],"mappings":"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"}
|
|
@@ -5,69 +5,71 @@ import { progressBarClassNames as r } from "../../lib/classNames.mjs";
|
|
|
5
5
|
import { useId as i } from "../../hooks/useId.mjs";
|
|
6
6
|
import { useFieldContext as a, useFieldControl as o } from "../../hooks/useFieldControl.mjs";
|
|
7
7
|
import { forcedColors as s } from "../../lib/styles.mjs";
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
8
|
+
import { progressIndeterminateMotion as c } from "../../lib/motion.mjs";
|
|
9
|
+
import { useMotionClasses as l } from "../../hooks/useMotion.mjs";
|
|
10
|
+
import * as u from "react";
|
|
11
|
+
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
10
12
|
//#region src/components/feedback/ProgressBar.tsx
|
|
11
|
-
var
|
|
13
|
+
var p = {
|
|
12
14
|
brand: "bg-primary",
|
|
13
15
|
success: "bg-success",
|
|
14
16
|
warning: "bg-severe",
|
|
15
17
|
error: "bg-error"
|
|
16
|
-
},
|
|
18
|
+
}, m = {
|
|
17
19
|
error: "error",
|
|
18
20
|
warning: "warning",
|
|
19
21
|
success: "success"
|
|
20
22
|
};
|
|
21
|
-
function
|
|
23
|
+
function h(e) {
|
|
22
24
|
return typeof e == "string" && e.trim() !== "";
|
|
23
25
|
}
|
|
24
|
-
var
|
|
25
|
-
let
|
|
26
|
-
id:
|
|
27
|
-
"aria-describedby":
|
|
28
|
-
}, { labelable: !1 }),
|
|
29
|
-
|
|
30
|
-
t && (!
|
|
26
|
+
var g = ({ value: g, max: _ = 100, label: v, showLabel: y, color: b, indeterminateMotion: x, id: S, "aria-describedby": C, "aria-invalid": w, "aria-required": T, className: E, ref: D, ...O }) => {
|
|
27
|
+
let k = i("progress-label"), A = i("progress"), j = a(), M = o({
|
|
28
|
+
id: S ?? (j ? A : void 0),
|
|
29
|
+
"aria-describedby": C
|
|
30
|
+
}, { labelable: !1 }), N = j ? j.validationState ?? (j.invalid ? "error" : "none") : "none", P = b ?? m[N] ?? "brand", F = g === void 0, I = l(x, c), L = Number.isFinite(_) && _ > 0, R = F || Number.isFinite(g), z = !F && L && R ? Math.min(_, Math.max(0, g)) : 0, B = L ? z / _ * 100 : 0, V = h(v), H = h(O["aria-label"]), U = h(O["aria-labelledby"]), W = M["aria-labelledby"], G = !V && !H && !U && h(W);
|
|
31
|
+
u.useEffect(() => {
|
|
32
|
+
t && (!V && !H && !U && !G && n("ProgressBar:name", "ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`."), y && !V && n("ProgressBar:show-label", "ProgressBar: `showLabel` renders the `label` prop, which is empty."), L || n("ProgressBar:max", `ProgressBar: \`max\` must be a finite number greater than 0 (got ${String(_)}); the bar renders 0%.`), R || n("ProgressBar:value", `ProgressBar: \`value\` must be a finite number (got ${String(g)}); the bar renders 0%.`));
|
|
31
33
|
}, [
|
|
34
|
+
V,
|
|
35
|
+
H,
|
|
36
|
+
U,
|
|
37
|
+
G,
|
|
38
|
+
y,
|
|
32
39
|
L,
|
|
33
40
|
R,
|
|
34
|
-
z,
|
|
35
|
-
V,
|
|
36
41
|
_,
|
|
37
|
-
|
|
38
|
-
P,
|
|
39
|
-
h,
|
|
40
|
-
m
|
|
42
|
+
g
|
|
41
43
|
]);
|
|
42
|
-
let
|
|
44
|
+
let K = !!(y && V), q = {
|
|
43
45
|
role: "progressbar",
|
|
44
|
-
"aria-valuenow":
|
|
46
|
+
"aria-valuenow": F ? void 0 : z,
|
|
45
47
|
"aria-valuemin": 0,
|
|
46
|
-
"aria-valuemax":
|
|
47
|
-
"data-color":
|
|
48
|
+
"aria-valuemax": L ? _ : 100,
|
|
49
|
+
"data-color": P
|
|
48
50
|
};
|
|
49
|
-
|
|
50
|
-
for (let [e, t] of Object.entries(
|
|
51
|
-
let
|
|
52
|
-
...
|
|
53
|
-
ref:
|
|
54
|
-
className: e(r.root, "h-2 overflow-hidden rounded-full bg-track", "forced-colors:border", s.border,
|
|
55
|
-
children: /* @__PURE__ */
|
|
56
|
-
className: e(r.bar, "h-full rounded-full",
|
|
57
|
-
style:
|
|
51
|
+
M.id !== void 0 && (q.id = M.id), M["aria-describedby"] !== void 0 && (q["aria-describedby"] = M["aria-describedby"]), !H && !U && (K ? q["aria-labelledby"] = k : V ? q["aria-label"] = v : G && (q["aria-labelledby"] = W));
|
|
52
|
+
for (let [e, t] of Object.entries(O)) t !== void 0 && (e !== "aria-label" && e !== "aria-labelledby" || h(t)) && (q[e] = t);
|
|
53
|
+
let J = /* @__PURE__ */ d("div", {
|
|
54
|
+
...q,
|
|
55
|
+
ref: D,
|
|
56
|
+
className: e(r.root, "h-2 overflow-hidden rounded-full bg-track", "forced-colors:border", s.border, E),
|
|
57
|
+
children: /* @__PURE__ */ d("div", {
|
|
58
|
+
className: e(r.bar, "h-full rounded-full", p[P], s.selectedLeaf, F && e("w-full", I)),
|
|
59
|
+
style: F ? void 0 : { width: `${B}%` }
|
|
58
60
|
})
|
|
59
61
|
});
|
|
60
|
-
return
|
|
62
|
+
return K ? /* @__PURE__ */ f("div", {
|
|
61
63
|
className: "flex flex-col gap-1",
|
|
62
|
-
children: [/* @__PURE__ */
|
|
63
|
-
id:
|
|
64
|
+
children: [/* @__PURE__ */ d("span", {
|
|
65
|
+
id: k,
|
|
64
66
|
className: e(r.label, "text-body-1 text-foreground"),
|
|
65
|
-
children:
|
|
66
|
-
}),
|
|
67
|
-
}) :
|
|
67
|
+
children: v
|
|
68
|
+
}), J]
|
|
69
|
+
}) : J;
|
|
68
70
|
};
|
|
69
|
-
|
|
71
|
+
g.displayName = "ProgressBar";
|
|
70
72
|
//#endregion
|
|
71
|
-
export {
|
|
73
|
+
export { g as ProgressBar };
|
|
72
74
|
|
|
73
75
|
//# sourceMappingURL=ProgressBar.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProgressBar.mjs","names":["useId","useId$1","React","fillColorClasses","fieldColors","isName","value","ProgressBar","ariaDescribedBy","_ariaInvalid","_ariaRequired","rest","labelId","ownId","field","useFieldContext","fieldProps","useFieldControl","id","fieldState","resolvedColor","color","isIndeterminate","validMax","max","validValue","clamped","percentage","hasLabel","label","hasAriaLabel","hasAriaLabelledBy","fieldLabelledBy","hasFieldName","isDev","warnOnce","showLabel","visibleLabel","barProps","key","propValue","bar","cn","progressBarClassNames","forcedColors","className"],"sources":["../../../src/components/feedback/ProgressBar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { progressBarClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isDev, warnOnce } from '../../lib/dev';\nimport { forcedColors } from '../../lib/styles';\nimport type { ValidationState } from '../../lib/types';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useId } from '../../hooks/useId';\n\n/** Color of a {@link ProgressBar}'s fill. */\nexport type ProgressBarColor = 'brand' | 'success' | 'warning' | 'error';\n\n/** Properties for the ProgressBar component. */\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Current progress value, clamped to `0…max` for both the fill and `aria-valuenow`. Omit for\n * indeterminate mode. A non-finite value renders 0% (development warning).\n */\n value?: number;\n /**\n * Maximum progress value. A `max` of 0 or less, or a non-finite `max`, renders 0% (development\n * warning) and is reported to assistive technology as 0 of 100.\n * @default 100\n */\n max?: number;\n /**\n * Accessible name of the progress bar: `aria-label` by default, or a visible label with\n * `showLabel`. A progress bar needs a name (`label`, `aria-label` or `aria-labelledby`); a\n * development warning fires without one. A consumer `aria-label` or `aria-labelledby` takes\n * precedence over `label`; an empty or whitespace-only one counts as absent (it is not rendered).\n * Inside a `Field`, the Field's label names the bar when neither `label` nor a consumer name is\n * given.\n */\n label?: string;\n /**\n * Renders `label` as visible text above the bar and names the bar with it (`aria-labelledby`)\n * instead of `aria-label`, unless a consumer `aria-label` or `aria-labelledby` names the bar\n * (keep the visible text in that name, WCAG 2.5.3). The label and the bar are then wrapped in a\n * `div`; `ref`, `className`, `style` and the other props stay on the progress bar element.\n */\n showLabel?: boolean;\n /**\n * Color of the fill. Inside a `Field` it follows the Field's validation state (error, warning,\n * success) unless you set it. `warning` fills with the dark orange of the `severe` color, which\n * keeps 3:1 against the track in every theme. The bar carries `data-color` with the resolved\n * color.\n * @default 'brand'\n */\n color?: ProgressBarColor;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst fillColorClasses: Record<ProgressBarColor, string> = {\n brand: 'bg-primary',\n success: 'bg-success',\n // The warning token (a light yellow) is 1.02:1 on the light track: the severe orange passes 3:1.\n warning: 'bg-severe',\n error: 'bg-error',\n};\n\n/** The fill color a Field's validation state gives the bar (`none` keeps the default). */\nconst fieldColors: Partial<Record<ValidationState, ProgressBarColor>> = {\n error: 'error',\n warning: 'warning',\n success: 'success',\n};\n\n/** Whether a name prop (`label`, `aria-label`, `aria-labelledby`) holds more than whitespace. */\nfunction isName(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\n/**\n * Shows the progress of a task, or that a task is running (indeterminate, `value` omitted).\n *\n * - Name it with `label` (or `aria-label` / `aria-labelledby`); `showLabel` shows the label above\n * the bar.\n * - `value` is clamped to `0…max`; invalid numbers render an empty bar and warn in development.\n * - `color` picks the fill (`brand`, `success`, `warning`, `error`).\n * - Inside a `Field`, the Field's label names a bar that has no name of its own, its validation\n * message and hint describe the bar, and its validation state (error, warning, success) colors\n * the fill unless `color` is set. A progress bar is never invalid or required: the\n * `aria-invalid` and `aria-required` a Field adds are not rendered. Next to another control in\n * a Field's wrapper element, the bar gets an id of its own and leaves the Field's\n * `<label htmlFor>` to that control.\n * - The indeterminate animation follows the writing direction and becomes a full-width pulse for\n * reduced motion. In forced-colors mode the fill uses `Highlight` and the track gets a border.\n *\n * @example\n * <ProgressBar value={uploaded} max={total} label=\"Uploading photos\" showLabel />\n *\n * @example\n * <Field label=\"Upload\" validationState=\"warning\" validationMessage=\"The connection is slow.\">\n * <ProgressBar value={uploaded} max={total} />\n * </Field>\n */\nexport const ProgressBar = ({\n value,\n max = 100,\n label,\n showLabel,\n color,\n id,\n 'aria-describedby': ariaDescribedBy,\n // Field merges both into its first child; neither is allowed on role=\"progressbar\".\n 'aria-invalid': _ariaInvalid,\n 'aria-required': _ariaRequired,\n className,\n ref,\n ...rest\n}: ProgressBarProps) => {\n const labelId = useId('progress-label');\n const ownId = useId('progress');\n const field = useFieldContext();\n // A <label htmlFor> cannot name a progress bar, so inside a Field a bar without an id (Field\n // passes its control id to a first child as `id`) takes its own instead of claiming the\n // control id: that stays with the control the label names (an Input next to the bar in a\n // wrapper). No name props are passed, so with `labelable: false` the merged `aria-labelledby`\n // is exactly the Field's label id (or absent); it is used only when the bar has no name of its\n // own.\n const fieldProps = useFieldControl(\n { id: id ?? (field ? ownId : undefined), 'aria-describedby': ariaDescribedBy },\n { labelable: false },\n );\n // A context built before 0.6 has no validation state: read it from `invalid`.\n const fieldState = field ? (field.validationState ?? (field.invalid ? 'error' : 'none')) : 'none';\n const resolvedColor = color ?? fieldColors[fieldState] ?? 'brand';\n const isIndeterminate = value === undefined;\n const validMax = Number.isFinite(max) && max > 0;\n const validValue = isIndeterminate || Number.isFinite(value);\n /** Clamped once, used for both the fill width and `aria-valuenow`. */\n const clamped =\n !isIndeterminate && validMax && validValue ? Math.min(max, Math.max(0, value)) : 0;\n const percentage = validMax ? (clamped / max) * 100 : 0;\n\n // An empty or whitespace-only `label`, `aria-label` or `aria-labelledby` names nothing: it is\n // treated like `undefined` by the precedence, the rendered attributes and the warning alike.\n const hasLabel = isName(label);\n const hasAriaLabel = isName(rest['aria-label']);\n const hasAriaLabelledBy = isName(rest['aria-labelledby']);\n const fieldLabelledBy = fieldProps['aria-labelledby'];\n const hasFieldName = !hasLabel && !hasAriaLabel && !hasAriaLabelledBy && isName(fieldLabelledBy);\n\n // Development diagnostics (C-DEV): emitted from an effect, once per page.\n React.useEffect(() => {\n if (!isDev) return;\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasFieldName) {\n warnOnce(\n 'ProgressBar:name',\n 'ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`.',\n );\n }\n if (showLabel && !hasLabel) {\n warnOnce(\n 'ProgressBar:show-label',\n 'ProgressBar: `showLabel` renders the `label` prop, which is empty.',\n );\n }\n if (!validMax) {\n warnOnce(\n 'ProgressBar:max',\n `ProgressBar: \\`max\\` must be a finite number greater than 0 (got ${String(max)}); the bar renders 0%.`,\n );\n }\n if (!validValue) {\n warnOnce(\n 'ProgressBar:value',\n `ProgressBar: \\`value\\` must be a finite number (got ${String(value)}); the bar renders 0%.`,\n );\n }\n }, [\n hasLabel,\n hasAriaLabel,\n hasAriaLabelledBy,\n hasFieldName,\n showLabel,\n validMax,\n validValue,\n max,\n value,\n ]);\n\n const visibleLabel = Boolean(showLabel && hasLabel);\n\n /**\n * The bar's attributes. Defaults the consumer may override (C-COMPOSE) apply wherever the\n * consumer's value is `undefined` — also when the key is present, e.g. a wrapper that forwards\n * `aria-label={props['aria-label']}` — so a forwarded `undefined` never strips the role, the\n * values or the name derived from `label`. An empty `aria-label`/`aria-labelledby` is dropped\n * the same way instead of rendering a nameless attribute.\n */\n const barProps: Record<string, unknown> = {\n role: 'progressbar',\n 'aria-valuenow': isIndeterminate ? undefined : clamped,\n 'aria-valuemin': 0,\n 'aria-valuemax': validMax ? max : 100,\n 'data-color': resolvedColor,\n };\n // The consumer's id (or the control id Field passes to its first child), else its own id inside\n // a Field; the consumer's description, then the Field's validation message and hint.\n if (fieldProps.id !== undefined) barProps.id = fieldProps.id;\n if (fieldProps['aria-describedby'] !== undefined) {\n barProps['aria-describedby'] = fieldProps['aria-describedby'];\n }\n // A consumer `aria-label` or `aria-labelledby` wins over the name derived from `label`, also\n // with `showLabel` (the visible label then stays unreferenced text). The Field's label names\n // only a bar without a name of its own.\n if (!hasAriaLabel && !hasAriaLabelledBy) {\n if (visibleLabel) barProps['aria-labelledby'] = labelId;\n else if (hasLabel) barProps['aria-label'] = label;\n else if (hasFieldName) barProps['aria-labelledby'] = fieldLabelledBy;\n }\n for (const [key, propValue] of Object.entries(rest)) {\n if (propValue === undefined) continue;\n if ((key === 'aria-label' || key === 'aria-labelledby') && !isName(propValue)) continue;\n barProps[key] = propValue;\n }\n\n const bar = (\n <div\n {...barProps}\n ref={ref}\n className={cn(\n progressBarClassNames.root,\n 'h-2 overflow-hidden rounded-full bg-track',\n 'forced-colors:border',\n forcedColors.border,\n className,\n )}\n >\n <div\n className={cn(\n progressBarClassNames.bar,\n 'h-full rounded-full',\n fillColorClasses[resolvedColor],\n forcedColors.selectedLeaf,\n isIndeterminate &&\n 'w-2/5 animate-wave-indeterminate wave-rtl:animate-wave-indeterminate-rtl motion-reduce:w-full motion-reduce:translate-x-0 motion-reduce:animate-wave-pulse wave-rtl:motion-reduce:animate-wave-pulse',\n )}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n );\n\n if (!visibleLabel) return bar;\n\n return (\n <div className=\"flex flex-col gap-1\">\n <span id={labelId} className={cn(progressBarClassNames.label, 'text-body-1 text-foreground')}>\n {label}\n </span>\n {bar}\n </div>\n );\n};\n\nProgressBar.displayName = 'ProgressBar';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProgressBar.mjs","names":["useId","useId$1","React","fillColorClasses","fieldColors","isName","value","ProgressBar","ariaDescribedBy","_ariaInvalid","_ariaRequired","rest","labelId","ownId","field","useFieldContext","fieldProps","useFieldControl","id","fieldState","resolvedColor","color","isIndeterminate","indeterminateClasses","useMotionClasses","indeterminateMotion","progressIndeterminateMotion","validMax","max","validValue","clamped","percentage","hasLabel","label","hasAriaLabel","hasAriaLabelledBy","fieldLabelledBy","hasFieldName","isDev","warnOnce","showLabel","visibleLabel","barProps","key","propValue","bar","cn","progressBarClassNames","forcedColors","className"],"sources":["../../../src/components/feedback/ProgressBar.tsx"],"sourcesContent":["import * as React from 'react';\nimport { progressBarClassNames } from '../../lib/classNames';\nimport { cn } from '../../lib/cn';\nimport { isDev, warnOnce } from '../../lib/dev';\nimport { progressIndeterminateMotion } from '../../lib/motion';\nimport { forcedColors } from '../../lib/styles';\nimport type { MotionSlot, ValidationState } from '../../lib/types';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useId } from '../../hooks/useId';\nimport { useMotionClasses } from '../../hooks/useMotion';\n\n/** Color of a {@link ProgressBar}'s fill. */\nexport type ProgressBarColor = 'brand' | 'success' | 'warning' | 'error';\n\n/** Properties for the ProgressBar component. */\nexport interface ProgressBarProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Current progress value, clamped to `0…max` for both the fill and `aria-valuenow`. Omit for\n * indeterminate mode. A non-finite value renders 0% (development warning).\n */\n value?: number;\n /**\n * Maximum progress value. A `max` of 0 or less, or a non-finite `max`, renders 0% (development\n * warning) and is reported to assistive technology as 0 of 100.\n * @default 100\n */\n max?: number;\n /**\n * Accessible name of the progress bar: `aria-label` by default, or a visible label with\n * `showLabel`. A progress bar needs a name (`label`, `aria-label` or `aria-labelledby`); a\n * development warning fires without one. A consumer `aria-label` or `aria-labelledby` takes\n * precedence over `label`; an empty or whitespace-only one counts as absent (it is not rendered).\n * Inside a `Field`, the Field's label names the bar when neither `label` nor a consumer name is\n * given.\n */\n label?: string;\n /**\n * Renders `label` as visible text above the bar and names the bar with it (`aria-labelledby`)\n * instead of `aria-label`, unless a consumer `aria-label` or `aria-labelledby` names the bar\n * (keep the visible text in that name, WCAG 2.5.3). The label and the bar are then wrapped in a\n * `div`; `ref`, `className`, `style` and the other props stay on the progress bar element.\n */\n showLabel?: boolean;\n /**\n * Color of the fill. Inside a `Field` it follows the Field's validation state (error, warning,\n * success) unless you set it. `warning` fills with the dark orange of the `severe` color, which\n * keeps 3:1 against the track in every theme. The bar carries `data-color` with the resolved\n * color.\n * @default 'brand'\n */\n color?: ProgressBarColor;\n /**\n * Replaces the motion of the indeterminate fill (no `value`): by default a fill two fifths of\n * the track wide sweeps across it, mirrored in right-to-left, and becomes a full-width pulse\n * for reduced motion. The classes go on the fill and replace the whole default, its width and\n * its reduced-motion counterparts included. `null` draws a static full-width fill; a class\n * string or `{ className }` replaces the classes with plain animation classes (and a width) and\n * their reduced-motion counterparts (the fill has no presence phases). A\n * `WaveProvider` with `motion=\"none\"` turns the default off (a static full-width fill), and a\n * value here still applies under it. A determinate bar has no motion and ignores it. Fluent's\n * ProgressBar `indeterminateMotion` takes a motion slot the same way.\n * @default the sweep described above\n */\n indeterminateMotion?: MotionSlot | null;\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst fillColorClasses: Record<ProgressBarColor, string> = {\n brand: 'bg-primary',\n success: 'bg-success',\n // The warning token (a light yellow) is 1.02:1 on the light track: the severe orange passes 3:1.\n warning: 'bg-severe',\n error: 'bg-error',\n};\n\n/** The fill color a Field's validation state gives the bar (`none` keeps the default). */\nconst fieldColors: Partial<Record<ValidationState, ProgressBarColor>> = {\n error: 'error',\n warning: 'warning',\n success: 'success',\n};\n\n/** Whether a name prop (`label`, `aria-label`, `aria-labelledby`) holds more than whitespace. */\nfunction isName(value: unknown): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\n/**\n * Shows the progress of a task, or that a task is running (indeterminate, `value` omitted).\n *\n * - Name it with `label` (or `aria-label` / `aria-labelledby`); `showLabel` shows the label above\n * the bar.\n * - `value` is clamped to `0…max`; invalid numbers render an empty bar and warn in development.\n * - `color` picks the fill (`brand`, `success`, `warning`, `error`).\n * - Inside a `Field`, the Field's label names a bar that has no name of its own, its validation\n * message and hint describe the bar, and its validation state (error, warning, success) colors\n * the fill unless `color` is set. A progress bar is never invalid or required: the\n * `aria-invalid` and `aria-required` a Field adds are not rendered. Next to another control in\n * a Field's wrapper element, the bar gets an id of its own and leaves the Field's\n * `<label htmlFor>` to that control.\n * - The indeterminate animation follows the writing direction and becomes a full-width pulse for\n * reduced motion; `indeterminateMotion` replaces or removes it. In forced-colors mode the fill\n * uses `Highlight` and the track gets a border.\n *\n * @example\n * <ProgressBar value={uploaded} max={total} label=\"Uploading photos\" showLabel />\n *\n * @example\n * <Field label=\"Upload\" validationState=\"warning\" validationMessage=\"The connection is slow.\">\n * <ProgressBar value={uploaded} max={total} />\n * </Field>\n */\nexport const ProgressBar = ({\n value,\n max = 100,\n label,\n showLabel,\n color,\n indeterminateMotion,\n id,\n 'aria-describedby': ariaDescribedBy,\n // Field merges both into its first child; neither is allowed on role=\"progressbar\".\n 'aria-invalid': _ariaInvalid,\n 'aria-required': _ariaRequired,\n className,\n ref,\n ...rest\n}: ProgressBarProps) => {\n const labelId = useId('progress-label');\n const ownId = useId('progress');\n const field = useFieldContext();\n // A <label htmlFor> cannot name a progress bar, so inside a Field a bar without an id (Field\n // passes its control id to a first child as `id`) takes its own instead of claiming the\n // control id: that stays with the control the label names (an Input next to the bar in a\n // wrapper). No name props are passed, so with `labelable: false` the merged `aria-labelledby`\n // is exactly the Field's label id (or absent); it is used only when the bar has no name of its\n // own.\n const fieldProps = useFieldControl(\n { id: id ?? (field ? ownId : undefined), 'aria-describedby': ariaDescribedBy },\n { labelable: false },\n );\n // A context built before 0.6 has no validation state: read it from `invalid`.\n const fieldState = field ? (field.validationState ?? (field.invalid ? 'error' : 'none')) : 'none';\n const resolvedColor = color ?? fieldColors[fieldState] ?? 'brand';\n const isIndeterminate = value === undefined;\n // Called whatever the mode, so the hook order never changes when `value` appears.\n const indeterminateClasses = useMotionClasses(indeterminateMotion, progressIndeterminateMotion);\n const validMax = Number.isFinite(max) && max > 0;\n const validValue = isIndeterminate || Number.isFinite(value);\n /** Clamped once, used for both the fill width and `aria-valuenow`. */\n const clamped =\n !isIndeterminate && validMax && validValue ? Math.min(max, Math.max(0, value)) : 0;\n const percentage = validMax ? (clamped / max) * 100 : 0;\n\n // An empty or whitespace-only `label`, `aria-label` or `aria-labelledby` names nothing: it is\n // treated like `undefined` by the precedence, the rendered attributes and the warning alike.\n const hasLabel = isName(label);\n const hasAriaLabel = isName(rest['aria-label']);\n const hasAriaLabelledBy = isName(rest['aria-labelledby']);\n const fieldLabelledBy = fieldProps['aria-labelledby'];\n const hasFieldName = !hasLabel && !hasAriaLabel && !hasAriaLabelledBy && isName(fieldLabelledBy);\n\n // Development diagnostics (C-DEV): emitted from an effect, once per page.\n React.useEffect(() => {\n if (!isDev) return;\n if (!hasLabel && !hasAriaLabel && !hasAriaLabelledBy && !hasFieldName) {\n warnOnce(\n 'ProgressBar:name',\n 'ProgressBar: a progress bar needs an accessible name. Pass `label` (add `showLabel` to show it), `aria-label` or `aria-labelledby`.',\n );\n }\n if (showLabel && !hasLabel) {\n warnOnce(\n 'ProgressBar:show-label',\n 'ProgressBar: `showLabel` renders the `label` prop, which is empty.',\n );\n }\n if (!validMax) {\n warnOnce(\n 'ProgressBar:max',\n `ProgressBar: \\`max\\` must be a finite number greater than 0 (got ${String(max)}); the bar renders 0%.`,\n );\n }\n if (!validValue) {\n warnOnce(\n 'ProgressBar:value',\n `ProgressBar: \\`value\\` must be a finite number (got ${String(value)}); the bar renders 0%.`,\n );\n }\n }, [\n hasLabel,\n hasAriaLabel,\n hasAriaLabelledBy,\n hasFieldName,\n showLabel,\n validMax,\n validValue,\n max,\n value,\n ]);\n\n const visibleLabel = Boolean(showLabel && hasLabel);\n\n /**\n * The bar's attributes. Defaults the consumer may override (C-COMPOSE) apply wherever the\n * consumer's value is `undefined` — also when the key is present, e.g. a wrapper that forwards\n * `aria-label={props['aria-label']}` — so a forwarded `undefined` never strips the role, the\n * values or the name derived from `label`. An empty `aria-label`/`aria-labelledby` is dropped\n * the same way instead of rendering a nameless attribute.\n */\n const barProps: Record<string, unknown> = {\n role: 'progressbar',\n 'aria-valuenow': isIndeterminate ? undefined : clamped,\n 'aria-valuemin': 0,\n 'aria-valuemax': validMax ? max : 100,\n 'data-color': resolvedColor,\n };\n // The consumer's id (or the control id Field passes to its first child), else its own id inside\n // a Field; the consumer's description, then the Field's validation message and hint.\n if (fieldProps.id !== undefined) barProps.id = fieldProps.id;\n if (fieldProps['aria-describedby'] !== undefined) {\n barProps['aria-describedby'] = fieldProps['aria-describedby'];\n }\n // A consumer `aria-label` or `aria-labelledby` wins over the name derived from `label`, also\n // with `showLabel` (the visible label then stays unreferenced text). The Field's label names\n // only a bar without a name of its own.\n if (!hasAriaLabel && !hasAriaLabelledBy) {\n if (visibleLabel) barProps['aria-labelledby'] = labelId;\n else if (hasLabel) barProps['aria-label'] = label;\n else if (hasFieldName) barProps['aria-labelledby'] = fieldLabelledBy;\n }\n for (const [key, propValue] of Object.entries(rest)) {\n if (propValue === undefined) continue;\n if ((key === 'aria-label' || key === 'aria-labelledby') && !isName(propValue)) continue;\n barProps[key] = propValue;\n }\n\n const bar = (\n <div\n {...barProps}\n ref={ref}\n className={cn(\n progressBarClassNames.root,\n 'h-2 overflow-hidden rounded-full bg-track',\n 'forced-colors:border',\n forcedColors.border,\n className,\n )}\n >\n <div\n className={cn(\n progressBarClassNames.bar,\n 'h-full rounded-full',\n fillColorClasses[resolvedColor],\n forcedColors.selectedLeaf,\n isIndeterminate && cn('w-full', indeterminateClasses),\n )}\n style={isIndeterminate ? undefined : { width: `${percentage}%` }}\n />\n </div>\n );\n\n if (!visibleLabel) return bar;\n\n return (\n <div className=\"flex flex-col gap-1\">\n <span id={labelId} className={cn(progressBarClassNames.label, 'text-body-1 text-foreground')}>\n {label}\n </span>\n {bar}\n </div>\n );\n};\n\nProgressBar.displayName = 'ProgressBar';\n"],"mappings":"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"}
|