@mortenbrudvik/waveui 0.11.0 → 0.13.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 +157 -13
- package/dist/components/button/Link.cjs +1 -1
- package/dist/components/button/Link.cjs.map +1 -1
- package/dist/components/button/Link.mjs +4 -4
- package/dist/components/data-display/Avatar.cjs +1 -1
- package/dist/components/data-display/Avatar.cjs.map +1 -1
- package/dist/components/data-display/Avatar.colors.cjs +2 -0
- package/dist/components/data-display/Avatar.colors.cjs.map +1 -0
- package/dist/components/data-display/Avatar.colors.mjs +45 -0
- package/dist/components/data-display/Avatar.colors.mjs.map +1 -0
- package/dist/components/data-display/Avatar.context.cjs +1 -1
- package/dist/components/data-display/Avatar.context.cjs.map +1 -1
- package/dist/components/data-display/Avatar.context.mjs +4 -2
- package/dist/components/data-display/Avatar.context.mjs.map +1 -1
- package/dist/components/data-display/Avatar.mjs +103 -96
- package/dist/components/data-display/Avatar.mjs.map +1 -1
- package/dist/components/data-display/Avatar.sizes.cjs +2 -0
- package/dist/components/data-display/Avatar.sizes.cjs.map +1 -0
- package/dist/components/data-display/Avatar.sizes.mjs +41 -0
- package/dist/components/data-display/Avatar.sizes.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.cjs +1 -1
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.context.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.context.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.context.mjs +9 -0
- package/dist/components/data-display/AvatarGroup.context.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.mjs +65 -122
- package/dist/components/data-display/AvatarGroup.mjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.partition.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.partition.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.partition.mjs +14 -0
- package/dist/components/data-display/AvatarGroup.partition.mjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.parts.cjs +2 -0
- package/dist/components/data-display/AvatarGroup.parts.cjs.map +1 -0
- package/dist/components/data-display/AvatarGroup.parts.mjs +178 -0
- package/dist/components/data-display/AvatarGroup.parts.mjs.map +1 -0
- 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 +12 -12
- package/dist/components/data-display/InteractionTag.cjs +1 -1
- package/dist/components/data-display/InteractionTag.cjs.map +1 -1
- package/dist/components/data-display/InteractionTag.mjs +36 -33
- package/dist/components/data-display/InteractionTag.mjs.map +1 -1
- package/dist/components/data-display/Persona.cjs +1 -1
- package/dist/components/data-display/Persona.cjs.map +1 -1
- package/dist/components/data-display/Persona.mjs +96 -37
- package/dist/components/data-display/Persona.mjs.map +1 -1
- package/dist/components/data-display/PresenceBadge.cjs +1 -1
- package/dist/components/data-display/PresenceBadge.cjs.map +1 -1
- package/dist/components/data-display/PresenceBadge.mjs +42 -28
- package/dist/components/data-display/PresenceBadge.mjs.map +1 -1
- package/dist/components/data-display/Tag.cjs +1 -1
- package/dist/components/data-display/Tag.cjs.map +1 -1
- package/dist/components/data-display/Tag.mjs +111 -108
- package/dist/components/data-display/Tag.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 +235 -235
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.mjs +176 -175
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +188 -187
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +41 -40
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +89 -87
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/TagPicker.root.cjs +1 -1
- package/dist/components/input/TagPicker.root.cjs.map +1 -1
- package/dist/components/input/TagPicker.root.mjs +136 -135
- package/dist/components/input/TagPicker.root.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +156 -154
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/layout/Card.cjs +1 -1
- package/dist/components/layout/Card.cjs.map +1 -1
- package/dist/components/layout/Card.context.cjs +2 -0
- package/dist/components/layout/Card.context.cjs.map +1 -0
- package/dist/components/layout/Card.context.mjs +14 -0
- package/dist/components/layout/Card.context.mjs.map +1 -0
- package/dist/components/layout/Card.mjs +138 -92
- package/dist/components/layout/Card.mjs.map +1 -1
- package/dist/components/layout/Card.preview.cjs +2 -0
- package/dist/components/layout/Card.preview.cjs.map +1 -0
- package/dist/components/layout/Card.preview.mjs +22 -0
- package/dist/components/layout/Card.preview.mjs.map +1 -0
- package/dist/components/layout/Carousel.button.cjs +2 -0
- package/dist/components/layout/Carousel.button.cjs.map +1 -0
- package/dist/components/layout/Carousel.button.mjs +34 -0
- package/dist/components/layout/Carousel.button.mjs.map +1 -0
- package/dist/components/layout/Carousel.cjs +1 -1
- package/dist/components/layout/Carousel.cjs.map +1 -1
- package/dist/components/layout/Carousel.context.cjs +2 -0
- package/dist/components/layout/Carousel.context.cjs.map +1 -0
- package/dist/components/layout/Carousel.context.mjs +24 -0
- package/dist/components/layout/Carousel.context.mjs.map +1 -0
- package/dist/components/layout/Carousel.drag.cjs +2 -0
- package/dist/components/layout/Carousel.drag.cjs.map +1 -0
- package/dist/components/layout/Carousel.drag.mjs +79 -0
- package/dist/components/layout/Carousel.drag.mjs.map +1 -0
- package/dist/components/layout/Carousel.groups.cjs +2 -0
- package/dist/components/layout/Carousel.groups.cjs.map +1 -0
- package/dist/components/layout/Carousel.groups.mjs +23 -0
- package/dist/components/layout/Carousel.groups.mjs.map +1 -0
- package/dist/components/layout/Carousel.mjs +288 -150
- package/dist/components/layout/Carousel.mjs.map +1 -1
- package/dist/components/layout/Carousel.styles.cjs +2 -0
- package/dist/components/layout/Carousel.styles.cjs.map +1 -0
- package/dist/components/layout/Carousel.styles.mjs +30 -0
- package/dist/components/layout/Carousel.styles.mjs.map +1 -0
- package/dist/components/layout/TabList.cjs +1 -1
- package/dist/components/layout/TabList.cjs.map +1 -1
- package/dist/components/layout/TabList.mjs +163 -124
- package/dist/components/layout/TabList.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 +137 -127
- package/dist/components/navigation/Menu.popover.mjs.map +1 -1
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +4 -4
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +123 -123
- package/dist/components/overlays/Dialog.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 +12 -12
- package/dist/components/overlays/Drawer.panel.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 +173 -162
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.mjs +96 -91
- package/dist/components/overlays/TeachingPopover.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 +47 -47
- package/dist/components/overlays/Tooltip.mjs.map +1 -1
- package/dist/components/portal/Portal.cjs +1 -1
- package/dist/components/portal/Portal.cjs.map +1 -1
- package/dist/components/portal/Portal.mjs +5 -5
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.mjs +1 -1
- package/dist/hooks/useDismiss.cjs.map +1 -1
- package/dist/hooks/useDismiss.mjs.map +1 -1
- package/dist/hooks/useFocusTrap.cjs.map +1 -1
- package/dist/hooks/useFocusTrap.mjs.map +1 -1
- package/dist/hooks/useFocusVisible.cjs +2 -0
- package/dist/hooks/useFocusVisible.cjs.map +1 -0
- package/dist/hooks/useFocusVisible.mjs +49 -0
- package/dist/hooks/useFocusVisible.mjs.map +1 -0
- package/dist/hooks/useFocusableGroup.cjs +2 -0
- package/dist/hooks/useFocusableGroup.cjs.map +1 -0
- package/dist/hooks/useFocusableGroup.mjs +70 -0
- package/dist/hooks/useFocusableGroup.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +1 -1
- package/dist/hooks/useModalLayer.cjs.map +1 -1
- package/dist/hooks/useModalLayer.mjs +4 -4
- package/dist/hooks/useModalOpen.cjs +2 -0
- package/dist/hooks/useModalOpen.cjs.map +1 -0
- package/dist/hooks/useModalOpen.mjs +14 -0
- package/dist/hooks/useModalOpen.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +1 -1
- package/dist/hooks/usePopupPosition.cjs.map +1 -1
- package/dist/hooks/usePopupPosition.mjs +82 -53
- package/dist/hooks/usePopupPosition.mjs.map +1 -1
- package/dist/hooks/useResolvedTarget.cjs +2 -0
- package/dist/hooks/useResolvedTarget.cjs.map +1 -0
- package/dist/hooks/useResolvedTarget.mjs +37 -0
- package/dist/hooks/useResolvedTarget.mjs.map +1 -0
- package/dist/hooks/useRovingGrid.cjs +1 -1
- package/dist/hooks/useRovingGrid.cjs.map +1 -1
- package/dist/hooks/useRovingGrid.mjs +8 -57
- package/dist/hooks/useRovingGrid.mjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +142 -107
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1364 -66
- package/dist/index.d.ts +1364 -66
- package/dist/index.mjs +132 -115
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +112 -92
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/initials.cjs +2 -0
- package/dist/lib/initials.cjs.map +1 -0
- package/dist/lib/initials.mjs +21 -0
- package/dist/lib/initials.mjs.map +1 -0
- package/dist/lib/layers.cjs +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs +112 -109
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +102 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InteractionTag.mjs","names":["useId","useId$1","React","noop","createPrimaryRegistry","count","settled","listeners","notify","listener","onChange","INERT_PRIMARY_REGISTRY","InteractionTagContext","INERT_CONTEXT","useInteractionTagContext","reportMissingContext","componentName","isKeyOf","value","table","disabledClasses","cn","dimDisabled","INTERACTION_TAG_DISABLED_CLASSES","mergedAriaDisabledClasses","INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES","disabled","forcedColors","SELECTED_IN_GROUP_MESSAGE","buttonStateProps","held","MERGED_DISABLED_FOCUSABLE_PROPS","InteractionTagRoot","appearanceProp","sizeProp","shapeProp","disabledProp","selectedProp","rest","group","useTagGroupContext","rootRef","mergedRef","useMergedRefs","ref","secondaryRef","primaryTextId","primaries","size","tagSizeClasses","appearance","tagAppearanceClasses","shape","tagShapeClasses","reportedValue","useTagGroupItem","selecting","pressed","selected","look","selectedIgnored","warnOnce","dismiss","useEventCallback","toggle","listItemRole","hiddenByHost","context","role","hidden","interactionTagClassNames","className","InteractionTagPrimary","ariaPressed","tag","hold","useHeldFocus","registerPrimary","hasMedia","slotRendersContent","media","hasIcon","icon","secondary","materialiseSlotContent","secondaryText","hasSecondary","avatarBox","TAG_AVATAR_SIZE","handleClick","isOwnEvent","event","handleKeyDown","isDismissKey","secondaryButton","primaryText","interactionTagPrimaryClassNames","composeEventHandlers","onClick","onKeyDown","onFocus","onBlur","INTERACTION_TAG_BUTTON_BASE_CLASSES","INTERACTION_TAG_PRIMARY_BASE_CLASSES","tagStartInsetClasses","interactionTagPrimaryEndInsetClasses","interactionTagLookClasses","INTERACTION_TAG_PRIMARY_JOINED_CLASSES","focusRing","AvatarSizeContext","renderSlot","tagMediaClasses","tagIconClasses","TAG_TEXT_COLUMN_CLASSES","TAG_SECONDARY_TEXT_CLASSES","BUTTON_CHILD_MESSAGE","InteractionTagSecondary","ariaLabel","ariaLabelledBy","dismissLabelId","contentId","ownRef","unwrapped","unwrapButtonGlyph","children","content","glyph","hasContent","literalTextLabel","hasTextLabel","labelTarget","setLabelTarget","subscribeToContent","observeTextLabel","contentHasTextLabel","hasRenderedTextLabel","hasLabel","hasPrimary","namedByConsumer","labelledBy","joinIds","isRepeatedActivation","interactionTagSecondaryClassNames","INTERACTION_TAG_SECONDARY_BASE_CLASSES","interactionTagSecondarySizeClasses","interactionTagDividerClasses","interactionTagSecondaryShapeClasses","dismissLabel","DismissIcon","TAG_DISMISS_GLYPH_SIZE","InteractionTag"],"sources":["../../../src/components/data-display/InteractionTag.tsx"],"sourcesContent":["import * as React from 'react';\nimport { joinIds } from '../../lib/aria';\nimport { cn } from '../../lib/cn';\nimport {\n interactionTagClassNames,\n interactionTagPrimaryClassNames,\n interactionTagSecondaryClassNames,\n} from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { reportMissingContext, warnOnce } from '../../lib/dev';\nimport { isOwnEvent } from '../../lib/events';\nimport { DismissIcon } from '../../lib/icons';\nimport { hasRenderedTextLabel, hasTextLabel, observeTextLabel } from '../../lib/labelInName';\nimport { materialiseSlotContent, renderSlot, slotRendersContent } from '../../lib/slot';\nimport type { Slot } from '../../lib/slot';\nimport { focusRing, forcedColors } from '../../lib/styles';\nimport type { TagAppearance, TagShape, TagSize } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport {\n MERGED_DISABLED_FOCUSABLE_PROPS,\n mergedAriaDisabledClasses,\n unwrapButtonGlyph,\n} from '../button/Button.slots';\nimport { AvatarSizeContext } from './Avatar.context';\nimport {\n isDismissKey,\n isRepeatedActivation,\n useDismissControlFocus,\n useHeldFocus,\n useTagGroupContext,\n useTagGroupItem,\n} from './TagGroup.context';\nimport {\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_DISABLED_CLASSES,\n INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n INTERACTION_TAG_PRIMARY_BASE_CLASSES,\n INTERACTION_TAG_PRIMARY_JOINED_CLASSES,\n INTERACTION_TAG_SECONDARY_BASE_CLASSES,\n INTERACTION_TAG_SECONDARY_LABEL_CLASSES,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES,\n TAG_AVATAR_SIZE,\n TAG_DISMISS_GLYPH_SIZE,\n TAG_PRIMARY_TEXT_TWO_LINE_CLASSES,\n TAG_SECONDARY_TEXT_CLASSES,\n TAG_TEXT_COLUMN_CLASSES,\n interactionTagDividerClasses,\n interactionTagLookClasses,\n interactionTagPrimaryEndInsetClasses,\n interactionTagSecondaryShapeClasses,\n interactionTagSecondarySizeClasses,\n tagAppearanceClasses,\n tagIconClasses,\n tagMediaClasses,\n tagShapeClasses,\n tagSizeClasses,\n tagStartInsetClasses,\n} from './tagStyles';\nimport type { TagLook } from './tagStyles';\n\n/** Props of InteractionTag: the element that holds the Primary and Secondary buttons. */\nexport interface InteractionTagProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Identifies the tag in a TagGroup: the value `onDismiss` receives and the selection holds. Give\n * every tag of a group its own value.\n * @default a generated id (a development warning in a group that reports values)\n */\n value?: string;\n /**\n * Colour scheme of both buttons: `filled` (a neutral fill), `outline` (a border on the surface\n * behind it) or `brand` (a light brand tint that follows the brand ramp).\n * @default the TagGroup's `appearance`, else 'filled'\n */\n appearance?: TagAppearance;\n /**\n * `medium` (28px tall), `small` (24px) or `extra-small` (20px); an Avatar in the Primary's\n * `media` is 24, 20 or 16px. Fluent's medium tag is 32px.\n * @default the TagGroup's `size`, else 'medium'\n */\n size?: TagSize;\n /**\n * `circular` (a pill) or `rounded` (4px corners). Fluent's default is `rounded`.\n * @default the TagGroup's `shape`, else 'circular'\n */\n shape?: TagShape;\n /**\n * Disables both buttons natively (a disabled TagGroup does too; a part's own `disabled` cannot\n * re-enable it). A button that has focus when it is disabled keeps it, unavailable, until focus\n * leaves it. Rendered as `data-disabled` on the root.\n * @default false\n */\n disabled?: boolean;\n /**\n * Outside a selecting TagGroup: draws the selected look and makes the Primary a toggle:\n * `aria-pressed=\"true\"`, or `\"false\"` for `selected={false}`. Leave it `undefined` for an\n * action that is not a toggle (no `aria-pressed`). Inside a selecting TagGroup (`value`,\n * `defaultValue` or `onValueChange`) the group's `value` decides, and a defined `selected` is\n * ignored (a development warning). Rendered as `data-selected` on the root and both buttons.\n * Disabled wins over the selected look (`aria-pressed` and `data-selected` still render).\n * Fluent's `selected` is a look only.\n */\n selected?: boolean;\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Props of InteractionTag.Primary: the tag's main action (or its toggle in a selecting TagGroup). */\nexport interface InteractionTagPrimaryProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * A visual before the text (an Avatar, sized for the tag: 24, 20 or 16px, unless it sets its\n * own `size`). Decorative (`aria-hidden`): the button is named by its text.\n */\n media?: Slot<'span'>;\n /** A decorative icon before the text (`aria-hidden`), in a 20, 16 or 12px box. */\n icon?: Slot<'span'>;\n /**\n * A second, smaller line under the text. Part of the Primary's name, not of the Secondary's. A\n * small or extra-small tag grows to 28px to fit it.\n */\n secondaryText?: React.ReactNode;\n /**\n * Disables the Primary natively; or-ed with the InteractionTag's `disabled` (it cannot\n * re-enable a disabled tag).\n * @default false\n */\n disabled?: boolean;\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n/** Props of InteractionTag.Secondary: the tag's separate Dismiss button. */\nexport interface InteractionTagSecondaryProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Visually hidden text that names the button with the Primary's text (\"Dismiss Cherry\"). A text\n * label in the children replaces it (\"Remove Cherry\"); an `aria-label` replaces the whole name.\n * Localise it here. Fluent's order is the primary text, then the label (\"Cherry remove\").\n * @default 'Dismiss'\n */\n dismissLabel?: string;\n /**\n * Disables the Secondary natively; or-ed with the InteractionTag's `disabled` (it cannot\n * re-enable a disabled tag).\n * @default false\n */\n disabled?: boolean;\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\n/** What an InteractionTag gives its two buttons (resolved values, never `undefined` but `pressed`). */\ninterface InteractionTagContextValue {\n size: TagSize;\n shape: TagShape;\n /** The look of both buttons: the appearance, or the selected look over it. */\n look: TagLook;\n /** Whether the tag is disabled (its own `disabled`, or its TagGroup's). */\n disabled: boolean;\n /** Whether the tag is selected (`data-selected`). */\n selected: boolean;\n /** The Primary's `aria-pressed`: `undefined` for an action that is not a toggle. */\n pressed: boolean | undefined;\n /** Whether a disabled button dims itself (`false` under a host that dims the tags as a whole). */\n dimDisabled: boolean;\n /** The id of the Primary's text, the second half of the Secondary's name. */\n primaryTextId: string;\n /** Which Primaries render, so the Secondary points at the primary text only while one does. */\n primaries: PrimaryRegistry;\n /** The Secondary, which Delete and Backspace on the Primary click (read at key time). */\n secondaryRef: React.RefObject<HTMLButtonElement | null> | null;\n /**\n * Reports the dismissal to the TagGroup (its `onDismiss(value)`), after the Secondary's\n * `onClick`, and then removes the tag's value from the group's selection (D39).\n */\n dismiss: () => void;\n /** Toggles the tag's value in a selecting TagGroup's selection (the Primary's click). */\n toggle: () => void;\n}\n\nconst noop = () => {};\n\n/**\n * The Primaries an InteractionTag renders, read by its Secondary, whose name points at the\n * primary text only while a Primary renders it (no id reference to a missing element). Until the\n * root's first commit (the server render, hydration and the first client render) a Primary is\n * assumed, so the server HTML holds the whole name and a tag with a Primary renders once; a\n * Secondary without one drops the id after that commit, and takes it again when one mounts. An\n * external store (C-HOOKS): a Primary registers from a layout effect.\n */\ninterface PrimaryRegistry {\n subscribe: (onChange: () => void) => () => void;\n /** Whether the Secondary's name may point at the primary text. */\n hasPrimary: () => boolean;\n /** For a Primary's layout effect: returns its cleanup. */\n register: () => () => void;\n /** For the root's layout effect: from now on the registrations decide. */\n settle: () => void;\n}\n\nfunction createPrimaryRegistry(): PrimaryRegistry {\n let count = 0;\n let settled = false;\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const listener of listeners) listener();\n };\n return {\n subscribe: (onChange) => {\n listeners.add(onChange);\n return () => {\n listeners.delete(onChange);\n };\n },\n hasPrimary: () => !settled || count > 0,\n register: () => {\n count += 1;\n notify();\n return () => {\n count -= 1;\n notify();\n };\n },\n settle: () => {\n if (settled) return;\n settled = true;\n notify();\n },\n };\n}\n\n/** The registry of the inert context: a Primary is always assumed. */\nconst INERT_PRIMARY_REGISTRY: PrimaryRegistry = {\n subscribe: () => noop,\n hasPrimary: () => true,\n register: () => noop,\n settle: noop,\n};\n\n/** Internal: `null` outside an InteractionTag. */\nconst InteractionTagContext = React.createContext<InteractionTagContextValue | null>(null);\nInteractionTagContext.displayName = 'InteractionTagContext';\n\n/** What a part reads outside an InteractionTag in production (C-CONTEXT): an enabled, unnamed tag. */\nconst INERT_CONTEXT: InteractionTagContextValue = {\n size: 'medium',\n shape: 'circular',\n look: 'filled',\n disabled: false,\n selected: false,\n pressed: undefined,\n dimDisabled: true,\n primaryTextId: '',\n primaries: INERT_PRIMARY_REGISTRY,\n secondaryRef: null,\n dismiss: () => {},\n toggle: () => {},\n};\n\nfunction useInteractionTagContext(componentName: string): InteractionTagContextValue {\n const context = React.useContext(InteractionTagContext);\n if (context) return context;\n reportMissingContext(componentName, 'InteractionTag');\n return INERT_CONTEXT;\n}\n\n/** Whether `value` is a key of `table` (an untyped value outside a union falls back). */\nfunction isKeyOf<K extends string>(\n value: unknown,\n table: Readonly<Record<K, unknown>>,\n): value is K {\n return typeof value === 'string' && Object.hasOwn(table, value);\n}\n\n/** The classes of a button's disabled states: dimmed, unless the host dims the tags itself. */\nfunction disabledClasses(disabled: boolean, dimDisabled: boolean): string {\n return cn(\n dimDisabled\n ? [INTERACTION_TAG_DISABLED_CLASSES, mergedAriaDisabledClasses]\n : INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES,\n disabled && forcedColors.disabled,\n );\n}\n\nconst SELECTED_IN_GROUP_MESSAGE =\n \"InteractionTag: `selected` has no effect in a TagGroup that selects (`value`, `defaultValue` or `onValueChange`); the group's `value` decides.\";\n\n/**\n * The state props of a tag button: natively disabled, or, while it keeps the focus it had when it\n * was disabled, the focusable disabled state (its click blocked).\n */\nfunction buttonStateProps(disabled: boolean, held: boolean) {\n if (!disabled) return undefined;\n return held ? MERGED_DISABLED_FOCUSABLE_PROPS : { disabled: true };\n}\n\n// ---------------------------------------------------------------------------\n// Root\n// ---------------------------------------------------------------------------\n\n// The InteractionTag root, documented on the exported `InteractionTag` const.\nconst InteractionTagRoot = ({\n value,\n appearance: appearanceProp,\n size: sizeProp,\n shape: shapeProp,\n disabled: disabledProp = false,\n selected: selectedProp,\n role,\n hidden,\n className,\n children,\n ref,\n ...rest\n}: InteractionTagProps) => {\n const group = useTagGroupContext();\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(rootRef, ref);\n const secondaryRef = React.useRef<HTMLButtonElement>(null);\n const primaryTextId = useId('interaction-tag-text');\n // After the first commit, the Primaries that registered decide the Secondary's name (D43).\n const [primaries] = React.useState(createPrimaryRegistry);\n React.useLayoutEffect(() => {\n primaries.settle();\n }, [primaries]);\n\n // The tag's own look, else its TagGroup's, else the default look.\n const size: TagSize = isKeyOf(sizeProp, tagSizeClasses) ? sizeProp : (group?.size ?? 'medium');\n const appearance: TagAppearance = isKeyOf(appearanceProp, tagAppearanceClasses)\n ? appearanceProp\n : (group?.appearance ?? 'filled');\n const shape: TagShape = isKeyOf(shapeProp, tagShapeClasses)\n ? shapeProp\n : (group?.shape ?? 'circular');\n // A disabled group disables every tag: the tag's own `disabled={false}` cannot re-enable it.\n const disabled = (group?.disabled ?? false) || disabledProp;\n const dimDisabled = group?.dimDisabled ?? true;\n\n // In a group that reports dismissals or selects, the tag's value (else a generated id).\n const reportedValue = useTagGroupItem(rootRef, value);\n // In a selecting TagGroup the group's selection decides (the Primary is always a toggle there);\n // elsewhere a boolean `selected` does, and `undefined` is an action that is no toggle.\n const selecting = group?.selecting ?? false;\n const pressed = selecting\n ? (group?.isSelected(reportedValue) ?? false)\n : typeof selectedProp === 'boolean'\n ? selectedProp\n : undefined;\n const selected = pressed === true;\n // Disabled wins over the selected look; the attributes still reflect the state.\n const look: TagLook = selected && !disabled ? 'selected' : appearance;\n\n const selectedIgnored = selecting && selectedProp !== undefined;\n React.useEffect(() => {\n if (selectedIgnored) warnOnce('InteractionTag:selected-in-group', SELECTED_IN_GROUP_MESSAGE);\n }, [selectedIgnored]);\n\n // The group's `onDismiss(value)`, then the value leaves the selection (D39), in one click.\n const dismiss = useEventCallback(() => {\n group?.dismiss(reportedValue);\n group?.deselect(reportedValue);\n });\n const toggle = useEventCallback(() => {\n group?.toggle(reportedValue);\n });\n\n // In a list TagGroup the root is a list item; the consumer's role wins.\n const listItemRole = group?.mode === 'list' ? 'listitem' : undefined;\n // A host hides the tags it counts instead of showing them (TagPicker's `overflow=\"count\"`).\n const hiddenByHost = value !== undefined && (group?.hiddenValues?.has(value) ?? false);\n\n const context = React.useMemo<InteractionTagContextValue>(\n () => ({\n size,\n shape,\n look,\n disabled,\n selected,\n pressed,\n dimDisabled,\n primaryTextId,\n primaries,\n secondaryRef,\n dismiss,\n toggle,\n }),\n [\n size,\n shape,\n look,\n disabled,\n selected,\n pressed,\n dimDisabled,\n primaryTextId,\n primaries,\n dismiss,\n toggle,\n ],\n );\n\n return (\n <InteractionTagContext.Provider value={context}>\n <div\n data-appearance={appearance}\n data-size={size}\n data-shape={shape}\n data-selected={selected ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n data-wave-tag-item=\"\"\n role={role ?? listItemRole}\n hidden={hiddenByHost || hidden}\n {...rest}\n ref={mergedRef}\n className={cn(\n interactionTagClassNames.root,\n 'group/interaction-tag inline-flex items-stretch',\n className,\n )}\n >\n {children}\n </div>\n </InteractionTagContext.Provider>\n );\n};\nInteractionTagRoot.displayName = 'InteractionTag';\n\n// ---------------------------------------------------------------------------\n// Primary\n// ---------------------------------------------------------------------------\n\n/**\n * The main action of an {@link InteractionTag}: a `<button type=\"button\">` named by its text and\n * `secondaryText` (`media` and `icon` are decorative), with the InteractionTag's look. In a\n * selecting TagGroup it is a toggle (`aria-pressed`): a click, Enter or Space adds the tag's\n * `value` to the group's selection or removes it, after its `onClick` (whose `preventDefault()`\n * cancels the toggle). Elsewhere the InteractionTag's `selected` makes it a toggle. Either state\n * renders its `aria-pressed` over one passed here, which applies only when neither is set. Delete\n * and Backspace on it click the tag's Secondary when there is one. Its props, `ref` and\n * `className` go to the button. Flat name of `InteractionTag.Primary`, for React Server\n * Components.\n */\nexport const InteractionTagPrimary = ({\n media,\n icon,\n secondaryText,\n disabled: disabledProp = false,\n 'aria-pressed': ariaPressed,\n className,\n children,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ref,\n ...rest\n}: InteractionTagPrimaryProps) => {\n const tag = useInteractionTagContext('InteractionTag.Primary');\n const { size, look } = tag;\n const disabled = tag.disabled || disabledProp;\n const hold = useHeldFocus(disabled);\n // Its text names the Secondary while it renders (D43).\n const registerPrimary = tag.primaries.register;\n React.useLayoutEffect(() => registerPrimary(), [registerPrimary]);\n\n // Slots that render nothing render no element and take no room.\n const hasMedia = slotRendersContent(media);\n const hasIcon = slotRendersContent(icon);\n const secondary = materialiseSlotContent(secondaryText);\n const hasSecondary = slotRendersContent(secondary);\n const avatarBox = React.useMemo(() => ({ size: TAG_AVATAR_SIZE[size] }), [size]);\n\n // In a selecting TagGroup a click (also Enter and Space) toggles the tag's value, after the\n // consumer's `onClick`; never for a click from a portal opened from the Primary (C-COMPOSE).\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (!disabled && isOwnEvent(event)) tag.toggle();\n };\n\n // Delete and Backspace dismiss the tag through the Secondary's own click, so whatever cancels\n // that click (its `onClick`'s `preventDefault()`, a disabled or held Secondary) cancels them\n // too. Not from a portal opened from the Primary, and not while the Primary itself is held.\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (disabled || event.target !== event.currentTarget || !isDismissKey(event)) return;\n const secondaryButton = tag.secondaryRef?.current;\n if (!secondaryButton || secondaryButton.disabled) return;\n event.preventDefault();\n secondaryButton.click();\n };\n\n const primaryText = (\n <span\n id={tag.primaryTextId || undefined}\n className={cn(\n interactionTagPrimaryClassNames.primaryText,\n hasSecondary && TAG_PRIMARY_TEXT_TWO_LINE_CLASSES,\n )}\n >\n {children}\n </span>\n );\n\n return (\n <button\n type=\"button\"\n // The tag's state (`selected`, or a selecting TagGroup's value) decides; a consumer\n // `aria-pressed` applies only to a Primary that is no toggle of the tag's.\n aria-pressed={tag.pressed ?? ariaPressed}\n data-selected={tag.selected ? '' : undefined}\n {...rest}\n ref={ref}\n onClick={composeEventHandlers(onClick, handleClick)}\n // After `onClick`: a held Primary's click is blocked, the toggle included.\n {...buttonStateProps(disabled, hold.held)}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, hold.onFocus, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, hold.onBlur, { checkDefaultPrevented: false })}\n className={cn(\n interactionTagPrimaryClassNames.root,\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_PRIMARY_BASE_CLASSES,\n tagSizeClasses[size],\n tagStartInsetClasses[size][hasMedia ? 'media' : hasIcon ? 'icon' : 'text'],\n interactionTagPrimaryEndInsetClasses[size],\n interactionTagLookClasses[look],\n look === 'selected' && [\n forcedColors.selectedContainer,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n ],\n tagShapeClasses[tag.shape],\n INTERACTION_TAG_PRIMARY_JOINED_CLASSES,\n disabledClasses(disabled, tag.dimDisabled),\n focusRing,\n size === 'extra-small' && INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n className,\n )}\n >\n {hasMedia && (\n // An Avatar without its own `size` takes the tag's box.\n <AvatarSizeContext.Provider value={avatarBox}>\n {renderSlot(\n media,\n 'span',\n cn(interactionTagPrimaryClassNames.media, tagMediaClasses[size]),\n { 'aria-hidden': true },\n )}\n </AvatarSizeContext.Provider>\n )}\n {hasIcon &&\n renderSlot(icon, 'span', cn(interactionTagPrimaryClassNames.icon, tagIconClasses[size]), {\n 'aria-hidden': true,\n })}\n {hasSecondary ? (\n <span className={TAG_TEXT_COLUMN_CLASSES}>\n {primaryText}\n {/* A space between the two texts in the button's name (\"Katri Designer\"), whatever a\n name computation makes of the column; the column layout never renders it. */}{' '}\n <span\n className={cn(\n interactionTagPrimaryClassNames.secondaryText,\n TAG_SECONDARY_TEXT_CLASSES,\n )}\n >\n {secondary}\n </span>\n </span>\n ) : (\n primaryText\n )}\n </button>\n );\n};\nInteractionTagPrimary.displayName = 'InteractionTagPrimary';\n\n// ---------------------------------------------------------------------------\n// Secondary\n// ---------------------------------------------------------------------------\n\nconst BUTTON_CHILD_MESSAGE =\n \"InteractionTag.Secondary: its content received a button. A button cannot contain a button: its children became the content of the Dismiss button and its props were dropped. Pass icon content, and handle the dismissal in `onClick` or in the TagGroup's `onDismiss`.\";\n\n/**\n * The separate Dismiss button of an {@link InteractionTag}: a `<button type=\"button\">` after the\n * Primary, named `dismissLabel` plus the Primary's text (\"Dismiss Cherry\"). Its children replace\n * the default dismiss glyph; a text label among them replaces `dismissLabel` in the name (\"Remove\n * Cherry\"), an `aria-label` the whole name. A button passed as its child is unwrapped (its children\n * become the content). Enter, Space, a click, Delete and Backspace call its `onClick`, then, in a\n * TagGroup, the group's `onDismiss(value)`. Its props, `ref` and `className` go to the button.\n * Flat name of `InteractionTag.Secondary`, for React Server Components.\n */\nexport const InteractionTagSecondary = ({\n dismissLabel = 'Dismiss',\n disabled: disabledProp = false,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className,\n children,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ref,\n ...rest\n}: InteractionTagSecondaryProps) => {\n const tag = useInteractionTagContext('InteractionTag.Secondary');\n const { size, look } = tag;\n const disabled = tag.disabled || disabledProp;\n const hold = useHeldFocus(disabled);\n const dismissLabelId = useId('interaction-tag-dismiss');\n const contentId = useId('interaction-tag-dismiss-content');\n const ownRef = React.useRef<HTMLButtonElement>(null);\n const mergedRef = useMergedRefs<HTMLButtonElement>(ownRef, tag.secondaryRef, ref);\n // Unmounting while it has focus (rendered conditionally), the Secondary hands focus to its own\n // tag's Primary; in a TagGroup, when the whole tag goes, the tag's own move applies (D35).\n useDismissControlFocus(ownRef);\n\n // Its children are the glyph inside the Dismiss button: a button there would nest buttons, so\n // it is unwrapped (C-SLOTS glyph rule).\n const { glyph, button: unwrapped } = unwrapButtonGlyph(children as Slot<'span'>);\n React.useEffect(() => {\n if (unwrapped) warnOnce('InteractionTag.Secondary:button-child', BUTTON_CHILD_MESSAGE);\n }, [unwrapped]);\n const content = materialiseSlotContent(glyph);\n const hasContent = slotRendersContent(content);\n const literalTextLabel = hasContent && hasTextLabel(content);\n\n // C-SLOTS naming (WCAG 2.5.3 Label in Name): a text label in the children replaces\n // `dismissLabel` (\"Remove Cherry\"). The literal children decide on the server and on the first\n // render; after mount, the rendered content does (text from components, later changes).\n const [labelTarget, setLabelTarget] = React.useState<HTMLSpanElement | null>(null);\n const subscribeToContent = React.useCallback(\n (onChange: () => void) => (labelTarget ? observeTextLabel(labelTarget, onChange) : noop),\n [labelTarget],\n );\n const contentHasTextLabel = React.useSyncExternalStore(\n subscribeToContent,\n () => (labelTarget ? hasRenderedTextLabel(labelTarget) : literalTextLabel),\n () => literalTextLabel,\n );\n const hasLabel = hasContent && contentHasTextLabel;\n // The primary text joins the name while a Primary renders it.\n const hasPrimary = React.useSyncExternalStore(\n tag.primaries.subscribe,\n tag.primaries.hasPrimary,\n () => true,\n );\n // A consumer `aria-label` replaces the whole name; a consumer `aria-labelledby` replaces ours.\n const namedByConsumer = ariaLabel !== undefined || ariaLabelledBy !== undefined;\n const labelledBy = namedByConsumer\n ? ariaLabelledBy\n : joinIds(hasLabel ? contentId : dismissLabelId, hasPrimary ? tag.primaryTextId : undefined);\n\n // The consumer's `onClick` first (its `preventDefault()` keeps the group from hearing of it),\n // then the TagGroup's `onDismiss(value)`; never for a click from a portal opened inside.\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (isOwnEvent(event)) tag.dismiss();\n };\n // Delete and Backspace dismiss as Enter does: through the button's own click, so whatever\n // cancels a click (its `onClick`'s `preventDefault()`, a held or disabled button) cancels them.\n // A held key dismisses one tag: the browser clicks a button on every repeated Enter, which\n // would reach the next tag's Dismiss control once focus moved there (D35).\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (event.target !== event.currentTarget) return;\n if (isRepeatedActivation(event)) {\n event.preventDefault();\n return;\n }\n if (!isDismissKey(event)) return;\n event.preventDefault();\n event.currentTarget.click();\n };\n\n return (\n <button\n type=\"button\"\n data-wave-tag-dismiss=\"\"\n data-selected={tag.selected ? '' : undefined}\n {...rest}\n ref={mergedRef}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n onClick={composeEventHandlers(onClick, handleClick)}\n {...buttonStateProps(disabled, hold.held)}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, hold.onFocus, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, hold.onBlur, { checkDefaultPrevented: false })}\n className={cn(\n interactionTagSecondaryClassNames.root,\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_SECONDARY_BASE_CLASSES,\n interactionTagSecondarySizeClasses[size],\n interactionTagLookClasses[look],\n look === 'selected' && [\n forcedColors.selectedContainer,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n ],\n interactionTagDividerClasses[look],\n interactionTagSecondaryShapeClasses[tag.shape],\n disabledClasses(disabled, tag.dimDisabled),\n focusRing,\n size === 'extra-small' && INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n className,\n )}\n >\n {!namedByConsumer && (\n <span id={dismissLabelId} className=\"sr-only\">\n {dismissLabel}\n </span>\n )}\n {hasContent ? (\n <span\n id={contentId}\n ref={setLabelTarget}\n className={cn(\n interactionTagSecondaryClassNames.dismissIcon,\n 'inline-flex items-center justify-center',\n // A text label keeps clear of the divider and the tag's end; a glyph needs no room.\n hasLabel && INTERACTION_TAG_SECONDARY_LABEL_CLASSES,\n )}\n >\n {content}\n </span>\n ) : (\n <DismissIcon\n size={TAG_DISMISS_GLYPH_SIZE[size]}\n className={interactionTagSecondaryClassNames.dismissIcon}\n />\n )}\n </button>\n );\n};\nInteractionTagSecondary.displayName = 'InteractionTagSecondary';\n\n// ---------------------------------------------------------------------------\n// Compound\n// ---------------------------------------------------------------------------\n\n/**\n * A tag with a main action and a separate Dismiss button: an element that holds two sibling\n * buttons, `InteractionTag.Primary` (the action) and `InteractionTag.Secondary` (Dismiss), never\n * one inside the other. Use it for a chip the user acts on (opens, toggles) and can also remove;\n * a `Tag` is a chip that only displays, or only dismisses.\n *\n * - **Two Tab stops**, the Primary then the Secondary. In a TagGroup toolbar both join its arrow\n * order (Primary, Secondary, next tag).\n * - **The Secondary is named after the Primary's text**: its `dismissLabel` plus the primary\n * text, \"Dismiss Cherry\" (never the secondary text). A text label in its children replaces\n * `dismissLabel` (\"Remove Cherry\"); an `aria-label` replaces the whole name.\n * - **Delete and Backspace** on either button dismiss the tag through the Secondary's click (a\n * held key dismisses once); without a Secondary they do nothing. Enter, Space and a click on the\n * Secondary dismiss too: remove the tag in its `onClick`, or in a TagGroup's `onDismiss(value)`,\n * which is called after it.\n * - **In a selecting TagGroup** (`value`, `defaultValue` or `onValueChange` on the group) the\n * Primary toggles the tag's `value` in the group's selection (`aria-pressed`, the selected\n * look), and dismissing a selected tag also removes its value from the selection.\n * - **`selected`**, outside a selecting TagGroup, draws the selected look and makes the Primary a\n * toggle (`aria-pressed`); leave it `undefined` for an action that is not a toggle.\n * - **Look**: `size`, `appearance` and `shape`, Tag's sizes and colours (a TagGroup gives its\n * defaults); `disabled` disables both buttons natively. The Primary takes `media` (an Avatar,\n * sized for the tag), `icon` and `secondaryText`.\n * - Fluent's `hasSecondaryAction` is not needed: the Primary squares its end corners next to a\n * Secondary by itself, also when the Secondary is rendered conditionally or wrapped.\n * - React Server Components cannot dot into a client module: import the flat names\n * `InteractionTagPrimary` and `InteractionTagSecondary` there.\n * - Renders `data-appearance`, `data-size` and `data-shape`, and while set `data-selected` and\n * `data-disabled`, on the root; `data-selected` on both buttons.\n *\n * @example\n * <InteractionTag value=\"cherry\">\n * <InteractionTag.Primary icon={<FruitIcon />} onClick={openDetails}>\n * Cherry\n * </InteractionTag.Primary>\n * <InteractionTag.Secondary onClick={() => remove('cherry')} />\n * </InteractionTag>\n */\nexport const InteractionTag = /* @__PURE__ */ Object.assign(InteractionTagRoot, {\n Primary: InteractionTagPrimary,\n Secondary: InteractionTagSecondary,\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"InteractionTag.mjs","names":["useId","useId$1","React","noop","createPrimaryRegistry","count","settled","listeners","notify","listener","onChange","INERT_PRIMARY_REGISTRY","InteractionTagContext","INERT_CONTEXT","useInteractionTagContext","reportMissingContext","componentName","isKeyOf","value","table","disabledClasses","cn","dimDisabled","INTERACTION_TAG_DISABLED_CLASSES","mergedAriaDisabledClasses","INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES","disabled","forcedColors","SELECTED_IN_GROUP_MESSAGE","buttonStateProps","held","MERGED_DISABLED_FOCUSABLE_PROPS","InteractionTagRoot","appearanceProp","sizeProp","shapeProp","disabledProp","selectedProp","rest","group","useTagGroupContext","rootRef","mergedRef","useMergedRefs","ref","secondaryRef","primaryTextId","primaries","size","tagSizeClasses","appearance","tagAppearanceClasses","shape","tagShapeClasses","reportedValue","useTagGroupItem","selecting","pressed","selected","look","selectedIgnored","warnOnce","dismiss","useEventCallback","toggle","listItemRole","hiddenByHost","context","role","hidden","interactionTagClassNames","className","InteractionTagPrimary","ariaPressed","tag","hold","useHeldFocus","registerPrimary","hasMedia","slotRendersContent","media","hasIcon","icon","secondary","materialiseSlotContent","secondaryText","hasSecondary","avatarBox","TAG_AVATAR_SIZE","handleClick","isOwnEvent","event","handleKeyDown","isDismissKey","secondaryButton","primaryText","interactionTagPrimaryClassNames","composeEventHandlers","onClick","onKeyDown","onFocus","onBlur","INTERACTION_TAG_BUTTON_BASE_CLASSES","INTERACTION_TAG_PRIMARY_BASE_CLASSES","tagStartInsetClasses","interactionTagPrimaryEndInsetClasses","interactionTagLookClasses","INTERACTION_TAG_PRIMARY_JOINED_CLASSES","focusRing","AvatarSizeContext","renderSlot","tagMediaClasses","tagIconClasses","TAG_TEXT_COLUMN_CLASSES","TAG_SECONDARY_TEXT_CLASSES","BUTTON_CHILD_MESSAGE","InteractionTagSecondary","ariaLabel","ariaLabelledBy","dismissLabelId","contentId","ownRef","unwrapped","unwrapButtonGlyph","children","content","glyph","hasContent","literalTextLabel","hasTextLabel","labelTarget","setLabelTarget","subscribeToContent","observeTextLabel","contentHasTextLabel","hasRenderedTextLabel","hasLabel","hasPrimary","namedByConsumer","labelledBy","joinIds","isRepeatedActivation","interactionTagSecondaryClassNames","INTERACTION_TAG_SECONDARY_BASE_CLASSES","interactionTagSecondarySizeClasses","interactionTagDividerClasses","interactionTagSecondaryShapeClasses","dismissLabel","DismissIcon","TAG_DISMISS_GLYPH_SIZE","InteractionTag"],"sources":["../../../src/components/data-display/InteractionTag.tsx"],"sourcesContent":["import * as React from 'react';\nimport { joinIds } from '../../lib/aria';\nimport { cn } from '../../lib/cn';\nimport {\n interactionTagClassNames,\n interactionTagPrimaryClassNames,\n interactionTagSecondaryClassNames,\n} from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { reportMissingContext, warnOnce } from '../../lib/dev';\nimport { isOwnEvent } from '../../lib/events';\nimport { DismissIcon } from '../../lib/icons';\nimport { hasRenderedTextLabel, hasTextLabel, observeTextLabel } from '../../lib/labelInName';\nimport { materialiseSlotContent, renderSlot, slotRendersContent } from '../../lib/slot';\nimport type { Slot } from '../../lib/slot';\nimport { focusRing, forcedColors } from '../../lib/styles';\nimport type { TagAppearance, TagShape, TagSize } from '../../lib/types';\nimport { useEventCallback } from '../../hooks/useEventCallback';\nimport { useId } from '../../hooks/useId';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport {\n MERGED_DISABLED_FOCUSABLE_PROPS,\n mergedAriaDisabledClasses,\n unwrapButtonGlyph,\n} from '../button/Button.slots';\nimport { AvatarSizeContext } from './Avatar.context';\nimport {\n isDismissKey,\n isRepeatedActivation,\n useDismissControlFocus,\n useHeldFocus,\n useTagGroupContext,\n useTagGroupItem,\n} from './TagGroup.context';\nimport {\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_DISABLED_CLASSES,\n INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n INTERACTION_TAG_PRIMARY_BASE_CLASSES,\n INTERACTION_TAG_PRIMARY_JOINED_CLASSES,\n INTERACTION_TAG_SECONDARY_BASE_CLASSES,\n INTERACTION_TAG_SECONDARY_LABEL_CLASSES,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES,\n TAG_AVATAR_SIZE,\n TAG_DISMISS_GLYPH_SIZE,\n TAG_PRIMARY_TEXT_TWO_LINE_CLASSES,\n TAG_SECONDARY_TEXT_CLASSES,\n TAG_TEXT_COLUMN_CLASSES,\n interactionTagDividerClasses,\n interactionTagLookClasses,\n interactionTagPrimaryEndInsetClasses,\n interactionTagSecondaryShapeClasses,\n interactionTagSecondarySizeClasses,\n tagAppearanceClasses,\n tagIconClasses,\n tagMediaClasses,\n tagShapeClasses,\n tagSizeClasses,\n tagStartInsetClasses,\n} from './tagStyles';\nimport type { TagLook } from './tagStyles';\n\n/** Props of InteractionTag: the element that holds the Primary and Secondary buttons. */\nexport interface InteractionTagProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Identifies the tag in a TagGroup: the value `onDismiss` receives and the selection holds. Give\n * every tag of a group its own value.\n * @default a generated id (a development warning in a group that reports values)\n */\n value?: string;\n /**\n * Colour scheme of both buttons: `filled` (a neutral fill), `outline` (a border on the surface\n * behind it) or `brand` (a light brand tint that follows the brand ramp).\n * @default the TagGroup's `appearance`, else 'filled'\n */\n appearance?: TagAppearance;\n /**\n * `medium` (28px tall), `small` (24px) or `extra-small` (20px); an Avatar in the Primary's\n * `media` is 24, 20 or 16px. Fluent's medium tag is 32px.\n * @default the TagGroup's `size`, else 'medium'\n */\n size?: TagSize;\n /**\n * `circular` (a pill) or `rounded` (4px corners). Fluent's default is `rounded`.\n * @default the TagGroup's `shape`, else 'circular'\n */\n shape?: TagShape;\n /**\n * Disables both buttons natively (a disabled TagGroup does too; a part's own `disabled` cannot\n * re-enable it). A button that has focus when it is disabled keeps it, unavailable, until focus\n * leaves it. Rendered as `data-disabled` on the root.\n * @default false\n */\n disabled?: boolean;\n /**\n * Outside a selecting TagGroup: draws the selected look and makes the Primary a toggle:\n * `aria-pressed=\"true\"`, or `\"false\"` for `selected={false}`. Leave it `undefined` for an\n * action that is not a toggle (no `aria-pressed`). Inside a selecting TagGroup (`value`,\n * `defaultValue` or `onValueChange`) the group's `value` decides, and a defined `selected` is\n * ignored (a development warning). Rendered as `data-selected` on the root and both buttons.\n * Disabled wins over the selected look (`aria-pressed` and `data-selected` still render).\n * Fluent's `selected` is a look only.\n */\n selected?: boolean;\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Props of InteractionTag.Primary: the tag's main action (or its toggle in a selecting TagGroup). */\nexport interface InteractionTagPrimaryProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * A visual before the text (an Avatar, sized for the tag: 24, 20 or 16px, unless it sets its\n * own `size`). Decorative (`aria-hidden`): the button is named by its text.\n */\n media?: Slot<'span'>;\n /** A decorative icon before the text (`aria-hidden`), in a 20, 16 or 12px box. */\n icon?: Slot<'span'>;\n /**\n * A second, smaller line under the text. Part of the Primary's name, not of the Secondary's. A\n * small or extra-small tag grows to 28px to fit it.\n */\n secondaryText?: React.ReactNode;\n /**\n * Disables the Primary natively; or-ed with the InteractionTag's `disabled` (it cannot\n * re-enable a disabled tag).\n * @default false\n */\n disabled?: boolean;\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n/** Props of InteractionTag.Secondary: the tag's separate Dismiss button. */\nexport interface InteractionTagSecondaryProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /**\n * Visually hidden text that names the button with the Primary's text (\"Dismiss Cherry\"). A text\n * label in the children replaces it (\"Remove Cherry\"); an `aria-label` replaces the whole name.\n * Localise it here. Fluent's order is the primary text, then the label (\"Cherry remove\").\n * @default 'Dismiss'\n */\n dismissLabel?: string;\n /**\n * Disables the Secondary natively; or-ed with the InteractionTag's `disabled` (it cannot\n * re-enable a disabled tag).\n * @default false\n */\n disabled?: boolean;\n ref?: React.Ref<HTMLButtonElement>;\n}\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\n/** What an InteractionTag gives its two buttons (resolved values, never `undefined` but `pressed`). */\ninterface InteractionTagContextValue {\n size: TagSize;\n shape: TagShape;\n /** The look of both buttons: the appearance, or the selected look over it. */\n look: TagLook;\n /** Whether the tag is disabled (its own `disabled`, or its TagGroup's). */\n disabled: boolean;\n /** Whether the tag is selected (`data-selected`). */\n selected: boolean;\n /** The Primary's `aria-pressed`: `undefined` for an action that is not a toggle. */\n pressed: boolean | undefined;\n /** Whether a disabled button dims itself (`false` under a host that dims the tags as a whole). */\n dimDisabled: boolean;\n /** The id of the Primary's text, the second half of the Secondary's name. */\n primaryTextId: string;\n /** Which Primaries render, so the Secondary points at the primary text only while one does. */\n primaries: PrimaryRegistry;\n /** The Secondary, which Delete and Backspace on the Primary click (read at key time). */\n secondaryRef: React.RefObject<HTMLButtonElement | null> | null;\n /**\n * Reports the dismissal to the TagGroup (its `onDismiss(value)`), after the Secondary's\n * `onClick`, and then removes the tag's value from the group's selection (D39).\n */\n dismiss: () => void;\n /** Toggles the tag's value in a selecting TagGroup's selection (the Primary's click). */\n toggle: () => void;\n}\n\nconst noop = () => {};\n\n/**\n * The Primaries an InteractionTag renders, read by its Secondary, whose name points at the\n * primary text only while a Primary renders it (no id reference to a missing element). Until the\n * root's first commit (the server render, hydration and the first client render) a Primary is\n * assumed, so the server HTML holds the whole name and a tag with a Primary renders once; a\n * Secondary without one drops the id after that commit, and takes it again when one mounts. An\n * external store (C-HOOKS): a Primary registers from a layout effect.\n */\ninterface PrimaryRegistry {\n subscribe: (onChange: () => void) => () => void;\n /** Whether the Secondary's name may point at the primary text. */\n hasPrimary: () => boolean;\n /** For a Primary's layout effect: returns its cleanup. */\n register: () => () => void;\n /** For the root's layout effect: from now on the registrations decide. */\n settle: () => void;\n}\n\nfunction createPrimaryRegistry(): PrimaryRegistry {\n let count = 0;\n let settled = false;\n const listeners = new Set<() => void>();\n const notify = () => {\n for (const listener of listeners) listener();\n };\n return {\n subscribe: (onChange) => {\n listeners.add(onChange);\n return () => {\n listeners.delete(onChange);\n };\n },\n hasPrimary: () => !settled || count > 0,\n register: () => {\n count += 1;\n notify();\n return () => {\n count -= 1;\n notify();\n };\n },\n settle: () => {\n if (settled) return;\n settled = true;\n notify();\n },\n };\n}\n\n/** The registry of the inert context: a Primary is always assumed. */\nconst INERT_PRIMARY_REGISTRY: PrimaryRegistry = {\n subscribe: () => noop,\n hasPrimary: () => true,\n register: () => noop,\n settle: noop,\n};\n\n/** Internal: `null` outside an InteractionTag. */\nconst InteractionTagContext = React.createContext<InteractionTagContextValue | null>(null);\nInteractionTagContext.displayName = 'InteractionTagContext';\n\n/** What a part reads outside an InteractionTag in production (C-CONTEXT): an enabled, unnamed tag. */\nconst INERT_CONTEXT: InteractionTagContextValue = {\n size: 'medium',\n shape: 'circular',\n look: 'filled',\n disabled: false,\n selected: false,\n pressed: undefined,\n dimDisabled: true,\n primaryTextId: '',\n primaries: INERT_PRIMARY_REGISTRY,\n secondaryRef: null,\n dismiss: () => {},\n toggle: () => {},\n};\n\nfunction useInteractionTagContext(componentName: string): InteractionTagContextValue {\n const context = React.useContext(InteractionTagContext);\n if (context) return context;\n reportMissingContext(componentName, 'InteractionTag');\n return INERT_CONTEXT;\n}\n\n/** Whether `value` is a key of `table` (an untyped value outside a union falls back). */\nfunction isKeyOf<K extends string>(\n value: unknown,\n table: Readonly<Record<K, unknown>>,\n): value is K {\n return typeof value === 'string' && Object.hasOwn(table, value);\n}\n\n/** The classes of a button's disabled states: dimmed, unless the host dims the tags itself. */\nfunction disabledClasses(disabled: boolean, dimDisabled: boolean): string {\n return cn(\n dimDisabled\n ? [INTERACTION_TAG_DISABLED_CLASSES, mergedAriaDisabledClasses]\n : INTERACTION_TAG_UNDIMMED_DISABLED_CLASSES,\n disabled && forcedColors.disabled,\n );\n}\n\nconst SELECTED_IN_GROUP_MESSAGE =\n \"InteractionTag: `selected` has no effect in a TagGroup that selects (`value`, `defaultValue` or `onValueChange`); the group's `value` decides.\";\n\n/**\n * The state props of a tag button: natively disabled, or, while it keeps the focus it had when it\n * was disabled, the focusable disabled state (its click blocked).\n */\nfunction buttonStateProps(disabled: boolean, held: boolean) {\n if (!disabled) return undefined;\n return held ? MERGED_DISABLED_FOCUSABLE_PROPS : { disabled: true };\n}\n\n// ---------------------------------------------------------------------------\n// Root\n// ---------------------------------------------------------------------------\n\n// The InteractionTag root, documented on the exported `InteractionTag` const.\nconst InteractionTagRoot = ({\n value,\n appearance: appearanceProp,\n size: sizeProp,\n shape: shapeProp,\n disabled: disabledProp = false,\n selected: selectedProp,\n role,\n hidden,\n className,\n children,\n ref,\n ...rest\n}: InteractionTagProps) => {\n const group = useTagGroupContext();\n const rootRef = React.useRef<HTMLDivElement>(null);\n const mergedRef = useMergedRefs<HTMLDivElement>(rootRef, ref);\n const secondaryRef = React.useRef<HTMLButtonElement>(null);\n const primaryTextId = useId('interaction-tag-text');\n // After the first commit, the Primaries that registered decide the Secondary's name (D43).\n const [primaries] = React.useState(createPrimaryRegistry);\n React.useLayoutEffect(() => {\n primaries.settle();\n }, [primaries]);\n\n // The tag's own look, else its TagGroup's, else the default look.\n const size: TagSize = isKeyOf(sizeProp, tagSizeClasses) ? sizeProp : (group?.size ?? 'medium');\n const appearance: TagAppearance = isKeyOf(appearanceProp, tagAppearanceClasses)\n ? appearanceProp\n : (group?.appearance ?? 'filled');\n const shape: TagShape = isKeyOf(shapeProp, tagShapeClasses)\n ? shapeProp\n : (group?.shape ?? 'circular');\n // A disabled group disables every tag: the tag's own `disabled={false}` cannot re-enable it.\n const disabled = (group?.disabled ?? false) || disabledProp;\n const dimDisabled = group?.dimDisabled ?? true;\n\n // In a group that reports dismissals or selects, the tag's value (else a generated id).\n const reportedValue = useTagGroupItem(rootRef, value);\n // In a selecting TagGroup the group's selection decides (the Primary is always a toggle there);\n // elsewhere a boolean `selected` does, and `undefined` is an action that is no toggle.\n const selecting = group?.selecting ?? false;\n const pressed = selecting\n ? (group?.isSelected(reportedValue) ?? false)\n : typeof selectedProp === 'boolean'\n ? selectedProp\n : undefined;\n const selected = pressed === true;\n // Disabled wins over the selected look; the attributes still reflect the state.\n const look: TagLook = selected && !disabled ? 'selected' : appearance;\n\n const selectedIgnored = selecting && selectedProp !== undefined;\n React.useEffect(() => {\n if (selectedIgnored) warnOnce('InteractionTag:selected-in-group', SELECTED_IN_GROUP_MESSAGE);\n }, [selectedIgnored]);\n\n // The group's `onDismiss(value)`, then the value leaves the selection (D39), in one click.\n const dismiss = useEventCallback(() => {\n group?.dismiss(reportedValue);\n group?.deselect(reportedValue);\n });\n const toggle = useEventCallback(() => {\n group?.toggle(reportedValue);\n });\n\n // In a list TagGroup the root is a list item; the consumer's role wins.\n const listItemRole = group?.mode === 'list' ? 'listitem' : undefined;\n // A host hides the tags it counts instead of showing them (TagPicker's `overflow=\"count\"`).\n const hiddenByHost = value !== undefined && (group?.hiddenValues?.has(value) ?? false);\n\n const context = React.useMemo<InteractionTagContextValue>(\n () => ({\n size,\n shape,\n look,\n disabled,\n selected,\n pressed,\n dimDisabled,\n primaryTextId,\n primaries,\n secondaryRef,\n dismiss,\n toggle,\n }),\n [\n size,\n shape,\n look,\n disabled,\n selected,\n pressed,\n dimDisabled,\n primaryTextId,\n primaries,\n dismiss,\n toggle,\n ],\n );\n\n return (\n <InteractionTagContext.Provider value={context}>\n <div\n data-appearance={appearance}\n data-size={size}\n data-shape={shape}\n data-selected={selected ? '' : undefined}\n data-disabled={disabled ? '' : undefined}\n data-wave-tag-item=\"\"\n role={role ?? listItemRole}\n hidden={hiddenByHost || hidden}\n {...rest}\n ref={mergedRef}\n className={cn(\n interactionTagClassNames.root,\n 'group/interaction-tag inline-flex items-stretch',\n className,\n )}\n >\n {children}\n </div>\n </InteractionTagContext.Provider>\n );\n};\nInteractionTagRoot.displayName = 'InteractionTag';\n\n// ---------------------------------------------------------------------------\n// Primary\n// ---------------------------------------------------------------------------\n\n/**\n * The main action of an {@link InteractionTag}: a `<button type=\"button\">` named by its text and\n * `secondaryText` (`media` and `icon` are decorative), with the InteractionTag's look. In a\n * selecting TagGroup it is a toggle (`aria-pressed`): a click, Enter or Space adds the tag's\n * `value` to the group's selection or removes it, after its `onClick` (whose `preventDefault()`\n * cancels the toggle). Elsewhere the InteractionTag's `selected` makes it a toggle. Either state\n * renders its `aria-pressed` over one passed here, which applies only when neither is set. Delete\n * and Backspace on it click the tag's Secondary when there is one. Its props, `ref` and\n * `className` go to the button. Flat name of `InteractionTag.Primary`, for React Server\n * Components.\n */\nexport const InteractionTagPrimary = ({\n media,\n icon,\n secondaryText,\n disabled: disabledProp = false,\n 'aria-pressed': ariaPressed,\n className,\n children,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ref,\n ...rest\n}: InteractionTagPrimaryProps) => {\n const tag = useInteractionTagContext('InteractionTag.Primary');\n const { size, look, shape } = tag;\n const disabled = tag.disabled || disabledProp;\n const hold = useHeldFocus(disabled);\n // Its text names the Secondary while it renders (D43).\n const registerPrimary = tag.primaries.register;\n React.useLayoutEffect(() => registerPrimary(), [registerPrimary]);\n\n // Slots that render nothing render no element and take no room.\n const hasMedia = slotRendersContent(media);\n const hasIcon = slotRendersContent(icon);\n const secondary = materialiseSlotContent(secondaryText);\n const hasSecondary = slotRendersContent(secondary);\n const avatarBox = React.useMemo(\n () => ({\n size: TAG_AVATAR_SIZE[size],\n shape: shape === 'rounded' ? ('square' as const) : ('circular' as const),\n }),\n [size, shape],\n );\n\n // In a selecting TagGroup a click (also Enter and Space) toggles the tag's value, after the\n // consumer's `onClick`; never for a click from a portal opened from the Primary (C-COMPOSE).\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (!disabled && isOwnEvent(event)) tag.toggle();\n };\n\n // Delete and Backspace dismiss the tag through the Secondary's own click, so whatever cancels\n // that click (its `onClick`'s `preventDefault()`, a disabled or held Secondary) cancels them\n // too. Not from a portal opened from the Primary, and not while the Primary itself is held.\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (disabled || event.target !== event.currentTarget || !isDismissKey(event)) return;\n const secondaryButton = tag.secondaryRef?.current;\n if (!secondaryButton || secondaryButton.disabled) return;\n event.preventDefault();\n secondaryButton.click();\n };\n\n const primaryText = (\n <span\n id={tag.primaryTextId || undefined}\n className={cn(\n interactionTagPrimaryClassNames.primaryText,\n hasSecondary && TAG_PRIMARY_TEXT_TWO_LINE_CLASSES,\n )}\n >\n {children}\n </span>\n );\n\n return (\n <button\n type=\"button\"\n // The tag's state (`selected`, or a selecting TagGroup's value) decides; a consumer\n // `aria-pressed` applies only to a Primary that is no toggle of the tag's.\n aria-pressed={tag.pressed ?? ariaPressed}\n data-selected={tag.selected ? '' : undefined}\n {...rest}\n ref={ref}\n onClick={composeEventHandlers(onClick, handleClick)}\n // After `onClick`: a held Primary's click is blocked, the toggle included.\n {...buttonStateProps(disabled, hold.held)}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, hold.onFocus, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, hold.onBlur, { checkDefaultPrevented: false })}\n className={cn(\n interactionTagPrimaryClassNames.root,\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_PRIMARY_BASE_CLASSES,\n tagSizeClasses[size],\n tagStartInsetClasses[size][hasMedia ? 'media' : hasIcon ? 'icon' : 'text'],\n interactionTagPrimaryEndInsetClasses[size],\n interactionTagLookClasses[look],\n look === 'selected' && [\n forcedColors.selectedContainer,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n ],\n tagShapeClasses[tag.shape],\n INTERACTION_TAG_PRIMARY_JOINED_CLASSES,\n disabledClasses(disabled, tag.dimDisabled),\n focusRing,\n size === 'extra-small' && INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n className,\n )}\n >\n {hasMedia && (\n // An Avatar without its own `size` takes the tag's box.\n <AvatarSizeContext.Provider value={avatarBox}>\n {renderSlot(\n media,\n 'span',\n cn(interactionTagPrimaryClassNames.media, tagMediaClasses[size]),\n { 'aria-hidden': true },\n )}\n </AvatarSizeContext.Provider>\n )}\n {hasIcon &&\n renderSlot(icon, 'span', cn(interactionTagPrimaryClassNames.icon, tagIconClasses[size]), {\n 'aria-hidden': true,\n })}\n {hasSecondary ? (\n <span className={TAG_TEXT_COLUMN_CLASSES}>\n {primaryText}\n {/* A space between the two texts in the button's name (\"Katri Designer\"), whatever a\n name computation makes of the column; the column layout never renders it. */}{' '}\n <span\n className={cn(\n interactionTagPrimaryClassNames.secondaryText,\n TAG_SECONDARY_TEXT_CLASSES,\n )}\n >\n {secondary}\n </span>\n </span>\n ) : (\n primaryText\n )}\n </button>\n );\n};\nInteractionTagPrimary.displayName = 'InteractionTagPrimary';\n\n// ---------------------------------------------------------------------------\n// Secondary\n// ---------------------------------------------------------------------------\n\nconst BUTTON_CHILD_MESSAGE =\n \"InteractionTag.Secondary: its content received a button. A button cannot contain a button: its children became the content of the Dismiss button and its props were dropped. Pass icon content, and handle the dismissal in `onClick` or in the TagGroup's `onDismiss`.\";\n\n/**\n * The separate Dismiss button of an {@link InteractionTag}: a `<button type=\"button\">` after the\n * Primary, named `dismissLabel` plus the Primary's text (\"Dismiss Cherry\"). Its children replace\n * the default dismiss glyph; a text label among them replaces `dismissLabel` in the name (\"Remove\n * Cherry\"), an `aria-label` the whole name. A button passed as its child is unwrapped (its children\n * become the content). Enter, Space, a click, Delete and Backspace call its `onClick`, then, in a\n * TagGroup, the group's `onDismiss(value)`. Its props, `ref` and `className` go to the button.\n * Flat name of `InteractionTag.Secondary`, for React Server Components.\n */\nexport const InteractionTagSecondary = ({\n dismissLabel = 'Dismiss',\n disabled: disabledProp = false,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n className,\n children,\n onClick,\n onKeyDown,\n onFocus,\n onBlur,\n ref,\n ...rest\n}: InteractionTagSecondaryProps) => {\n const tag = useInteractionTagContext('InteractionTag.Secondary');\n const { size, look } = tag;\n const disabled = tag.disabled || disabledProp;\n const hold = useHeldFocus(disabled);\n const dismissLabelId = useId('interaction-tag-dismiss');\n const contentId = useId('interaction-tag-dismiss-content');\n const ownRef = React.useRef<HTMLButtonElement>(null);\n const mergedRef = useMergedRefs<HTMLButtonElement>(ownRef, tag.secondaryRef, ref);\n // Unmounting while it has focus (rendered conditionally), the Secondary hands focus to its own\n // tag's Primary; in a TagGroup, when the whole tag goes, the tag's own move applies (D35).\n useDismissControlFocus(ownRef);\n\n // Its children are the glyph inside the Dismiss button: a button there would nest buttons, so\n // it is unwrapped (C-SLOTS glyph rule).\n const { glyph, button: unwrapped } = unwrapButtonGlyph(children as Slot<'span'>);\n React.useEffect(() => {\n if (unwrapped) warnOnce('InteractionTag.Secondary:button-child', BUTTON_CHILD_MESSAGE);\n }, [unwrapped]);\n const content = materialiseSlotContent(glyph);\n const hasContent = slotRendersContent(content);\n const literalTextLabel = hasContent && hasTextLabel(content);\n\n // C-SLOTS naming (WCAG 2.5.3 Label in Name): a text label in the children replaces\n // `dismissLabel` (\"Remove Cherry\"). The literal children decide on the server and on the first\n // render; after mount, the rendered content does (text from components, later changes).\n const [labelTarget, setLabelTarget] = React.useState<HTMLSpanElement | null>(null);\n const subscribeToContent = React.useCallback(\n (onChange: () => void) => (labelTarget ? observeTextLabel(labelTarget, onChange) : noop),\n [labelTarget],\n );\n const contentHasTextLabel = React.useSyncExternalStore(\n subscribeToContent,\n () => (labelTarget ? hasRenderedTextLabel(labelTarget) : literalTextLabel),\n () => literalTextLabel,\n );\n const hasLabel = hasContent && contentHasTextLabel;\n // The primary text joins the name while a Primary renders it.\n const hasPrimary = React.useSyncExternalStore(\n tag.primaries.subscribe,\n tag.primaries.hasPrimary,\n () => true,\n );\n // A consumer `aria-label` replaces the whole name; a consumer `aria-labelledby` replaces ours.\n const namedByConsumer = ariaLabel !== undefined || ariaLabelledBy !== undefined;\n const labelledBy = namedByConsumer\n ? ariaLabelledBy\n : joinIds(hasLabel ? contentId : dismissLabelId, hasPrimary ? tag.primaryTextId : undefined);\n\n // The consumer's `onClick` first (its `preventDefault()` keeps the group from hearing of it),\n // then the TagGroup's `onDismiss(value)`; never for a click from a portal opened inside.\n const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n if (isOwnEvent(event)) tag.dismiss();\n };\n // Delete and Backspace dismiss as Enter does: through the button's own click, so whatever\n // cancels a click (its `onClick`'s `preventDefault()`, a held or disabled button) cancels them.\n // A held key dismisses one tag: the browser clicks a button on every repeated Enter, which\n // would reach the next tag's Dismiss control once focus moved there (D35).\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (event.target !== event.currentTarget) return;\n if (isRepeatedActivation(event)) {\n event.preventDefault();\n return;\n }\n if (!isDismissKey(event)) return;\n event.preventDefault();\n event.currentTarget.click();\n };\n\n return (\n <button\n type=\"button\"\n data-wave-tag-dismiss=\"\"\n data-selected={tag.selected ? '' : undefined}\n {...rest}\n ref={mergedRef}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n onClick={composeEventHandlers(onClick, handleClick)}\n {...buttonStateProps(disabled, hold.held)}\n onKeyDown={composeEventHandlers(onKeyDown, handleKeyDown)}\n onFocus={composeEventHandlers(onFocus, hold.onFocus, { checkDefaultPrevented: false })}\n onBlur={composeEventHandlers(onBlur, hold.onBlur, { checkDefaultPrevented: false })}\n className={cn(\n interactionTagSecondaryClassNames.root,\n INTERACTION_TAG_BUTTON_BASE_CLASSES,\n INTERACTION_TAG_SECONDARY_BASE_CLASSES,\n interactionTagSecondarySizeClasses[size],\n interactionTagLookClasses[look],\n look === 'selected' && [\n forcedColors.selectedContainer,\n INTERACTION_TAG_SELECTED_FORCED_COLORS,\n ],\n interactionTagDividerClasses[look],\n interactionTagSecondaryShapeClasses[tag.shape],\n disabledClasses(disabled, tag.dimDisabled),\n focusRing,\n size === 'extra-small' && INTERACTION_TAG_EXTRA_SMALL_HIT_CLASSES,\n className,\n )}\n >\n {!namedByConsumer && (\n <span id={dismissLabelId} className=\"sr-only\">\n {dismissLabel}\n </span>\n )}\n {hasContent ? (\n <span\n id={contentId}\n ref={setLabelTarget}\n className={cn(\n interactionTagSecondaryClassNames.dismissIcon,\n 'inline-flex items-center justify-center',\n // A text label keeps clear of the divider and the tag's end; a glyph needs no room.\n hasLabel && INTERACTION_TAG_SECONDARY_LABEL_CLASSES,\n )}\n >\n {content}\n </span>\n ) : (\n <DismissIcon\n size={TAG_DISMISS_GLYPH_SIZE[size]}\n className={interactionTagSecondaryClassNames.dismissIcon}\n />\n )}\n </button>\n );\n};\nInteractionTagSecondary.displayName = 'InteractionTagSecondary';\n\n// ---------------------------------------------------------------------------\n// Compound\n// ---------------------------------------------------------------------------\n\n/**\n * A tag with a main action and a separate Dismiss button: an element that holds two sibling\n * buttons, `InteractionTag.Primary` (the action) and `InteractionTag.Secondary` (Dismiss), never\n * one inside the other. Use it for a chip the user acts on (opens, toggles) and can also remove;\n * a `Tag` is a chip that only displays, or only dismisses.\n *\n * - **Two Tab stops**, the Primary then the Secondary. In a TagGroup toolbar both join its arrow\n * order (Primary, Secondary, next tag).\n * - **The Secondary is named after the Primary's text**: its `dismissLabel` plus the primary\n * text, \"Dismiss Cherry\" (never the secondary text). A text label in its children replaces\n * `dismissLabel` (\"Remove Cherry\"); an `aria-label` replaces the whole name.\n * - **Delete and Backspace** on either button dismiss the tag through the Secondary's click (a\n * held key dismisses once); without a Secondary they do nothing. Enter, Space and a click on the\n * Secondary dismiss too: remove the tag in its `onClick`, or in a TagGroup's `onDismiss(value)`,\n * which is called after it.\n * - **In a selecting TagGroup** (`value`, `defaultValue` or `onValueChange` on the group) the\n * Primary toggles the tag's `value` in the group's selection (`aria-pressed`, the selected\n * look), and dismissing a selected tag also removes its value from the selection.\n * - **`selected`**, outside a selecting TagGroup, draws the selected look and makes the Primary a\n * toggle (`aria-pressed`); leave it `undefined` for an action that is not a toggle.\n * - **Look**: `size`, `appearance` and `shape`, Tag's sizes and colours (a TagGroup gives its\n * defaults); `disabled` disables both buttons natively. The Primary takes `media` (an Avatar,\n * sized for the tag), `icon` and `secondaryText`.\n * - Fluent's `hasSecondaryAction` is not needed: the Primary squares its end corners next to a\n * Secondary by itself, also when the Secondary is rendered conditionally or wrapped.\n * - React Server Components cannot dot into a client module: import the flat names\n * `InteractionTagPrimary` and `InteractionTagSecondary` there.\n * - Renders `data-appearance`, `data-size` and `data-shape`, and while set `data-selected` and\n * `data-disabled`, on the root; `data-selected` on both buttons.\n *\n * @example\n * <InteractionTag value=\"cherry\">\n * <InteractionTag.Primary icon={<FruitIcon />} onClick={openDetails}>\n * Cherry\n * </InteractionTag.Primary>\n * <InteractionTag.Secondary onClick={() => remove('cherry')} />\n * </InteractionTag>\n */\nexport const InteractionTag = /* @__PURE__ */ Object.assign(InteractionTagRoot, {\n Primary: InteractionTagPrimary,\n Secondary: InteractionTagSecondary,\n});\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/dev.cjs"),r=require("../../lib/slot.cjs"),i=require("../../lib/classNames.cjs"),a=require("./Avatar.cjs"),o=require("./PresenceBadge.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");function l(e){return e===`extra-small`||e===`small`?`small`:e===`huge`?`large`:`medium`}function u(e){return e===`extra-small`||e===`small`?`medium`:e===`medium`||e===`large`?`large`:`extra-large`}var d={"extra-small":{primary:`text-caption-1`,other:`text-caption-2`},small:{primary:`text-body-1`,other:`text-caption-1`},medium:{primary:`text-body-1`,other:`text-caption-1`},large:{primary:`text-subtitle-2`,other:`text-body-1`},"extra-large":{primary:`text-subtitle-1`,other:`text-body-1`},huge:{primary:`text-title-3`,other:`text-body-2`}},f={after:`inline-flex items-center gap-3`,before:`inline-flex flex-row-reverse items-center gap-3`,below:`inline-flex flex-col items-center gap-2`},p=({name:e,primaryText:p,secondaryText:m,tertiaryText:h,quaternaryText:g,textPosition:_=`after`,textAlignment:v,presenceOnly:y=!1,src:b,size:x=`medium`,status:S,avatar:C,badge:w,className:T,ref:E,...D})=>{let O=v??(_===`below`?`center`:`start`),k=p===void 0?!!e:r.slotRendersContent(p);s.useEffect(()=>{k||n.warnOnce(`Persona:unnamed`,"Persona: it has neither a `name` nor a `primaryText`, so nothing names the person. Pass one of them.")},[k]);let A=w&&r.slotRendersContent(w)?r.renderSlot(w,`span`):S?(0,c.jsx)(o.PresenceBadge,{status:S,size:y?u(x):l(x)}):null,j=d[x],M=[{key:`primaryText`,slot:p??e,className:t.cn(i.personaClassNames.primaryText,j.primary,`font-semibold`)},{key:`secondaryText`,slot:m,className:t.cn(i.personaClassNames.secondaryText,j.other,`text-muted-foreground`)},{key:`tertiaryText`,slot:h,className:t.cn(i.personaClassNames.tertiaryText,j.other,`text-muted-foreground`)},{key:`quaternaryText`,slot:g,className:t.cn(i.personaClassNames.quaternaryText,j.other,`text-muted-foreground`)}];return(0,c.jsxs)(`div`,{ref:E,"data-size":x,"data-text-position":_,"data-text-alignment":O,"data-presence-only":y?``:void 0,className:t.cn(i.personaClassNames.root,f[_],T),...D,children:[y?A&&(0,c.jsx)(`span`,{className:t.cn(i.personaClassNames.badge,`inline-flex shrink-0`),children:A}):(0,c.jsxs)(`div`,{className:`relative inline-flex shrink-0`,children:[C&&r.slotRendersContent(C)?r.renderSlot(C,`span`,i.personaClassNames.avatar):(0,c.jsx)(a.Avatar,{src:b,name:e,size:x===`huge`?72:x,decorative:!0,className:i.personaClassNames.avatar}),A&&(0,c.jsx)(`span`,{className:t.cn(i.personaClassNames.badge,`absolute bottom-0 end-0 inline-flex`),children:A})]}),(0,c.jsx)(`div`,{className:t.cn(`flex flex-col`,O===`center`?`items-center text-center`:`items-start text-start`),children:M.map(({key:e,slot:t,className:n})=>t!==void 0&&r.slotRendersContent(t)&&r.renderSlot(t,`span`,n,{key:e}))})]})};p.displayName=`Persona`,exports.Persona=p;
|
|
2
2
|
//# sourceMappingURL=Persona.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Persona.cjs","names":["slotRendersContent","renderSlot","PresenceBadge","cn","personaClassNames","Avatar","require_runtime","require_cn","require_slot","require_classNames","require_Avatar","require_PresenceBadge","react","react_jsx_runtime","derivePresenceSize","size","Persona","props","badgeNode","badge","status","className","avatar","name","secondaryText"],"sources":["../../../src/components/data-display/Persona.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { personaClassNames } from '../../lib/classNames';\nimport type { PresenceStatus, Size, Slot } from '../../lib/types';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport { Avatar } from './Avatar';\nimport { PresenceBadge } from './PresenceBadge';\n\n/** Properties for the Persona component. */\nexport interface PersonaProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Display name of the person. */\n name: string;\n /** Secondary text such as job title or email. */\n secondaryText?: string;\n /** URL of the person's avatar image. */\n src?: string;\n /** Size of the persona avatar.\n * @default 'medium'\n */\n size?: Size;\n /** Presence status shown as a badge on the avatar. Ignored when a `badge` is given. */\n status?: PresenceStatus;\n /**\n * Slot for a custom avatar element, replacing the built-in one. The name is already visible\n * next to it, so make a custom avatar decorative (e.g. `<Avatar decorative … />`). A value that\n * renders nothing (`null`, `false`, `''`, `0`, `NaN`, or an array, `Set` or generator of only\n * such items) counts as not given.\n */\n avatar?: Slot<'span'>;\n /**\n * Slot for a custom badge element. Takes precedence over `status`. A value that renders nothing\n * (`null`, `false`, `''`, `0`, `NaN`, e.g. `badge={count && <CounterBadge count={count} />}`,\n * or an array, `Set` or generator of only such items) counts as not given.\n */\n badge?: Slot<'span'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction derivePresenceSize(size: Size): Size {\n return size === 'extra-small' || size === 'small' ? 'small' : 'medium';\n}\n\n/**\n * A person's avatar next to their name and optional secondary text (job title, email), with an\n * optional presence badge.\n *\n * The built-in avatar is decorative (`<Avatar decorative>`): the visible name is announced once,\n * not a second time as the avatar's image name. The presence badge stays exposed as a named image.\n *\n * @example\n * <Persona name=\"Jane Doe\" secondaryText=\"Designer\" status=\"available\" />\n */\nexport const Persona = ({\n name,\n secondaryText,\n src,\n size = 'medium',\n status,\n avatar,\n badge,\n className,\n ref,\n ...props\n}: PersonaProps) => {\n // A slot that renders nothing (`badge={count && …}` with count 0, an empty `.map()` result) is\n // not given (C-SLOTS), so the status badge and the built-in avatar apply.\n const badgeNode =\n badge && slotRendersContent(badge) ? (\n renderSlot(badge, 'span')\n ) : status ? (\n <PresenceBadge status={status} size={derivePresenceSize(size)} />\n ) : null;\n\n return (\n <div\n ref={ref}\n className={cn(personaClassNames.root, 'inline-flex items-center gap-3', className)}\n {...props}\n >\n <div className=\"relative inline-flex shrink-0\">\n {avatar && slotRendersContent(avatar) ? (\n renderSlot(avatar, 'span', personaClassNames.avatar)\n ) : (\n <Avatar\n src={src}\n name={name}\n size={size}\n decorative\n className={personaClassNames.avatar}\n />\n )}\n {badgeNode && (\n <span className={cn(personaClassNames.badge, 'absolute bottom-0 end-0 inline-flex')}>\n {badgeNode}\n </span>\n )}\n </div>\n <div className=\"flex flex-col\">\n <span className={cn(personaClassNames.primaryText, 'font-semibold text-body-1')}>\n {name}\n </span>\n {secondaryText && (\n <span\n className={cn(personaClassNames.secondaryText, 'text-caption-1 text-muted-foreground')}\n >\n {secondaryText}\n </span>\n )}\n </div>\n </div>\n );\n};\n\nPersona.displayName = 'Persona';\n"],"mappings":"+SAuCA,SAASc,EAAmB,EAAkB,CAC5C,OAAOC,IAAS,eAAiBA,IAAS,QAAU,QAAU,QAChE,CAYA,IAAaC,GAAW,CACtB,OACA,gBACA,MACA,OAAO,SACP,SACA,SACA,QACA,YACA,MACA,GAAGC,KACe,CAGlB,IAAMC,EACJC,GAASnB,EAAAA,mBAAmBmB,CAAK,EAC/BlB,EAAAA,WAAWkB,EAAO,MAAM,EACtBC,GACF,EAAAP,EAAA,IAAA,CAACX,EAAAA,cAAD,CAAuB,SAAQ,KAAMY,EAAmBC,CAAI,CAAI,CAAA,EAC9D,KAEN,OACE,EAAAF,EAAA,KAAA,CAAC,MAAD,CACO,MACL,UAAWV,EAAAA,GAAGC,EAAAA,kBAAkB,KAAM,iCAAkCiB,CAAS,EACjF,GAAIJ,EAHN,SAAA,EAKE,EAAAJ,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,gCAAf,SAAA,CACGS,GAAUtB,EAAAA,mBAAmBsB,CAAM,EAClCrB,EAAAA,WAAWqB,EAAQ,OAAQlB,EAAAA,kBAAkB,MAAM,GAEnD,EAAAS,EAAA,IAAA,CAACR,EAAAA,OAAD,CACO,MACC,OACA,OACN,WAAA,GACA,UAAWD,EAAAA,kBAAkB,MAC9B,CAAA,EAEFc,IACC,EAAAL,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWV,EAAAA,GAAGC,EAAAA,kBAAkB,MAAO,qCAAqC,EAC/E,SAAAc,CACG,CAAA,CAEL,CACL,CAAA,GAAA,EAAAL,EAAA,KAAA,CAAC,MAAD,CAAK,UAAU,gBAAf,SAAA,EACE,EAAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAWV,EAAAA,GAAGC,EAAAA,kBAAkB,YAAa,2BAA2B,EAC3E,SAAAmB,CACG,CAAA,EACLC,IACC,EAAAX,EAAA,IAAA,CAAC,OAAD,CACE,UAAWV,EAAAA,GAAGC,EAAAA,kBAAkB,cAAe,sCAAsC,EAEpF,SAAAoB,CACG,CAAA,CAEL,CACF,CAAA,CAAA,GAET,EAEA,EAAQ,YAAc"}
|
|
1
|
+
{"version":3,"file":"Persona.cjs","names":["slotRendersContent","renderSlot","PresenceBadge","cn","personaClassNames","Avatar","require_runtime","require_cn","require_dev","require_slot","require_classNames","require_Avatar","require_PresenceBadge","react","react_jsx_runtime","derivePresenceSize","size","derivePresenceOnlySize","textClasses","positionClasses","Persona","props","resolvedAlignment","textAlignment","textPosition","hasPrimary","primaryText","name","badgeNode","badge","status","presenceOnly","text","lines","secondaryText","tertiaryText","quaternaryText","className","avatar","lineClass","slot"],"sources":["../../../src/components/data-display/Persona.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { personaClassNames } from '../../lib/classNames';\nimport { warnOnce } from '../../lib/dev';\nimport type { PresenceStatus, Size, Slot } from '../../lib/types';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport { Avatar } from './Avatar';\nimport { PresenceBadge } from './PresenceBadge';\n\n/** The size of a Persona: the Avatar sizes, and `huge` (a 72px avatar). */\nexport type PersonaSize = Size | 'huge';\n\n/** Properties for the Persona component. */\nexport interface PersonaProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Display name of the person. It gives the avatar its initials and the first text line its text\n * (unless `primaryText` is given). A persona with neither `name` nor `primaryText` warns in\n * development.\n */\n name?: string;\n /**\n * The first text line (the name). A string, an element or an object of `<span>` attributes.\n * @default the `name`\n */\n primaryText?: Slot<'span'>;\n /** The second text line, such as a job title or email. */\n secondaryText?: Slot<'span'>;\n /** The third text line, such as a location. */\n tertiaryText?: Slot<'span'>;\n /** The fourth text line, such as a status message. */\n quaternaryText?: Slot<'span'>;\n /**\n * Where the text sits relative to the avatar, in reading order: after it, before it, or below it.\n * @default 'after'\n */\n textPosition?: 'after' | 'before' | 'below';\n /**\n * How the text lines align with each other.\n * @default 'start' ('center' when the text is below the avatar)\n */\n textAlignment?: 'start' | 'center';\n /**\n * Shows only the presence badge (from `status` or `badge`) in place of the avatar. The text\n * stays.\n * @default false\n */\n presenceOnly?: boolean;\n /** URL of the person's avatar image. */\n src?: string;\n /**\n * Size of the persona: its avatar and its text.\n * @default 'medium'\n */\n size?: PersonaSize;\n /** Presence status shown as a badge on the avatar. Ignored when a `badge` is given. */\n status?: PresenceStatus;\n /**\n * Slot for a custom avatar element, replacing the built-in one. The name is already visible\n * next to it, so make a custom avatar decorative (e.g. `<Avatar decorative … />`). A value that\n * renders nothing (`null`, `false`, `''`, `0`, `NaN`, or an array, `Set` or generator of only\n * such items) counts as not given.\n */\n avatar?: Slot<'span'>;\n /**\n * Slot for a custom badge element. Takes precedence over `status`. A value that renders nothing\n * (`null`, `false`, `''`, `0`, `NaN`, e.g. `badge={count && <CounterBadge count={count} />}`,\n * or an array, `Set` or generator of only such items) counts as not given.\n */\n badge?: Slot<'span'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction derivePresenceSize(size: PersonaSize): Size {\n if (size === 'extra-small' || size === 'small') return 'small';\n return size === 'huge' ? 'large' : 'medium';\n}\n\n/** The size of the presence badge that stands alone (`presenceOnly`). */\nfunction derivePresenceOnlySize(size: PersonaSize): Size {\n if (size === 'extra-small' || size === 'small') return 'medium';\n if (size === 'medium' || size === 'large') return 'large';\n return 'extra-large';\n}\n\n/** Type steps of the first line and of the other lines, per size. Literal strings only. */\nconst textClasses: Readonly<Record<PersonaSize, { primary: string; other: string }>> = {\n 'extra-small': { primary: 'text-caption-1', other: 'text-caption-2' },\n small: { primary: 'text-body-1', other: 'text-caption-1' },\n medium: { primary: 'text-body-1', other: 'text-caption-1' },\n large: { primary: 'text-subtitle-2', other: 'text-body-1' },\n 'extra-large': { primary: 'text-subtitle-1', other: 'text-body-1' },\n huge: { primary: 'text-title-3', other: 'text-body-2' },\n};\n\n/** The layout of the root per text position. Logical: `flex-row-reverse` mirrors in RTL by itself. */\nconst positionClasses = {\n after: 'inline-flex items-center gap-3',\n before: 'inline-flex flex-row-reverse items-center gap-3',\n below: 'inline-flex flex-col items-center gap-2',\n} as const;\n\n/**\n * A person's avatar next to their name and up to three more text lines (job title, location,\n * status), with an optional presence badge. The text can sit after, before or below the avatar\n * (`textPosition`), `presenceOnly` swaps the avatar for the presence badge, and the text scales with\n * `size` up to `huge`.\n *\n * The built-in avatar is decorative (`<Avatar decorative>`): the visible name is announced once,\n * not a second time as the avatar's image name. The presence badge stays exposed as a named image.\n *\n * @example\n * <Persona name=\"Jane Doe\" secondaryText=\"Designer\" tertiaryText=\"Oslo\" status=\"available\" />\n */\nexport const Persona = ({\n name,\n primaryText,\n secondaryText,\n tertiaryText,\n quaternaryText,\n textPosition = 'after',\n textAlignment,\n presenceOnly = false,\n src,\n size = 'medium',\n status,\n avatar,\n badge,\n className,\n ref,\n ...props\n}: PersonaProps) => {\n const resolvedAlignment = textAlignment ?? (textPosition === 'below' ? 'center' : 'start');\n const hasPrimary = primaryText !== undefined ? slotRendersContent(primaryText) : !!name;\n React.useEffect(() => {\n if (!hasPrimary) {\n warnOnce(\n 'Persona:unnamed',\n 'Persona: it has neither a `name` nor a `primaryText`, so nothing names the person. Pass one of them.',\n );\n }\n }, [hasPrimary]);\n\n // A slot that renders nothing (`badge={count && …}` with count 0, an empty `.map()` result) is\n // not given (C-SLOTS), so the status badge and the built-in avatar apply.\n const badgeNode =\n badge && slotRendersContent(badge) ? (\n renderSlot(badge, 'span')\n ) : status ? (\n <PresenceBadge\n status={status}\n size={presenceOnly ? derivePresenceOnlySize(size) : derivePresenceSize(size)}\n />\n ) : null;\n\n const text = textClasses[size];\n const lines = [\n {\n key: 'primaryText',\n slot: primaryText ?? name,\n className: cn(personaClassNames.primaryText, text.primary, 'font-semibold'),\n },\n {\n key: 'secondaryText',\n slot: secondaryText,\n className: cn(personaClassNames.secondaryText, text.other, 'text-muted-foreground'),\n },\n {\n key: 'tertiaryText',\n slot: tertiaryText,\n className: cn(personaClassNames.tertiaryText, text.other, 'text-muted-foreground'),\n },\n {\n key: 'quaternaryText',\n slot: quaternaryText,\n className: cn(personaClassNames.quaternaryText, text.other, 'text-muted-foreground'),\n },\n ] as const;\n\n return (\n <div\n ref={ref}\n data-size={size}\n data-text-position={textPosition}\n data-text-alignment={resolvedAlignment}\n data-presence-only={presenceOnly ? '' : undefined}\n className={cn(personaClassNames.root, positionClasses[textPosition], className)}\n {...props}\n >\n {presenceOnly ? (\n badgeNode && (\n <span className={cn(personaClassNames.badge, 'inline-flex shrink-0')}>{badgeNode}</span>\n )\n ) : (\n <div className=\"relative inline-flex shrink-0\">\n {avatar && slotRendersContent(avatar) ? (\n renderSlot(avatar, 'span', personaClassNames.avatar)\n ) : (\n <Avatar\n src={src}\n name={name}\n size={size === 'huge' ? 72 : size}\n decorative\n className={personaClassNames.avatar}\n />\n )}\n {badgeNode && (\n <span className={cn(personaClassNames.badge, 'absolute bottom-0 end-0 inline-flex')}>\n {badgeNode}\n </span>\n )}\n </div>\n )}\n <div\n className={cn(\n 'flex flex-col',\n resolvedAlignment === 'center' ? 'items-center text-center' : 'items-start text-start',\n )}\n >\n {lines.map(\n ({ key, slot, className: lineClass }) =>\n slot !== undefined &&\n slotRendersContent(slot) &&\n renderSlot(slot, 'span', lineClass, { key }),\n )}\n </div>\n </div>\n );\n};\n\nPersona.displayName = 'Persona';\n"],"mappings":"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"}
|
|
@@ -1,50 +1,109 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../../lib/cn.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import "
|
|
8
|
-
import
|
|
3
|
+
import { warnOnce as t } from "../../lib/dev.mjs";
|
|
4
|
+
import { renderSlot as n, slotRendersContent as r } from "../../lib/slot.mjs";
|
|
5
|
+
import { personaClassNames as i } from "../../lib/classNames.mjs";
|
|
6
|
+
import { Avatar as a } from "./Avatar.mjs";
|
|
7
|
+
import { PresenceBadge as o } from "./PresenceBadge.mjs";
|
|
8
|
+
import * as s from "react";
|
|
9
|
+
import { jsx as c, jsxs as l } from "react/jsx-runtime";
|
|
9
10
|
//#region src/components/data-display/Persona.tsx
|
|
10
|
-
function
|
|
11
|
-
return e === "extra-small" || e === "small" ? "small" : "medium";
|
|
11
|
+
function u(e) {
|
|
12
|
+
return e === "extra-small" || e === "small" ? "small" : e === "huge" ? "large" : "medium";
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
function d(e) {
|
|
15
|
+
return e === "extra-small" || e === "small" ? "medium" : e === "medium" || e === "large" ? "large" : "extra-large";
|
|
16
|
+
}
|
|
17
|
+
var f = {
|
|
18
|
+
"extra-small": {
|
|
19
|
+
primary: "text-caption-1",
|
|
20
|
+
other: "text-caption-2"
|
|
21
|
+
},
|
|
22
|
+
small: {
|
|
23
|
+
primary: "text-body-1",
|
|
24
|
+
other: "text-caption-1"
|
|
25
|
+
},
|
|
26
|
+
medium: {
|
|
27
|
+
primary: "text-body-1",
|
|
28
|
+
other: "text-caption-1"
|
|
29
|
+
},
|
|
30
|
+
large: {
|
|
31
|
+
primary: "text-subtitle-2",
|
|
32
|
+
other: "text-body-1"
|
|
33
|
+
},
|
|
34
|
+
"extra-large": {
|
|
35
|
+
primary: "text-subtitle-1",
|
|
36
|
+
other: "text-body-1"
|
|
37
|
+
},
|
|
38
|
+
huge: {
|
|
39
|
+
primary: "text-title-3",
|
|
40
|
+
other: "text-body-2"
|
|
41
|
+
}
|
|
42
|
+
}, p = {
|
|
43
|
+
after: "inline-flex items-center gap-3",
|
|
44
|
+
before: "inline-flex flex-row-reverse items-center gap-3",
|
|
45
|
+
below: "inline-flex flex-col items-center gap-2"
|
|
46
|
+
}, m = ({ name: m, primaryText: h, secondaryText: g, tertiaryText: _, quaternaryText: v, textPosition: y = "after", textAlignment: b, presenceOnly: x = !1, src: S, size: C = "medium", status: w, avatar: T, badge: E, className: D, ref: O, ...k }) => {
|
|
47
|
+
let A = b ?? (y === "below" ? "center" : "start"), j = h === void 0 ? !!m : r(h);
|
|
48
|
+
s.useEffect(() => {
|
|
49
|
+
j || t("Persona:unnamed", "Persona: it has neither a `name` nor a `primaryText`, so nothing names the person. Pass one of them.");
|
|
50
|
+
}, [j]);
|
|
51
|
+
let M = E && r(E) ? n(E, "span") : w ? /* @__PURE__ */ c(o, {
|
|
52
|
+
status: w,
|
|
53
|
+
size: x ? d(C) : u(C)
|
|
54
|
+
}) : null, N = f[C], P = [
|
|
55
|
+
{
|
|
56
|
+
key: "primaryText",
|
|
57
|
+
slot: h ?? m,
|
|
58
|
+
className: e(i.primaryText, N.primary, "font-semibold")
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: "secondaryText",
|
|
62
|
+
slot: g,
|
|
63
|
+
className: e(i.secondaryText, N.other, "text-muted-foreground")
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
key: "tertiaryText",
|
|
67
|
+
slot: _,
|
|
68
|
+
className: e(i.tertiaryText, N.other, "text-muted-foreground")
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
key: "quaternaryText",
|
|
72
|
+
slot: v,
|
|
73
|
+
className: e(i.quaternaryText, N.other, "text-muted-foreground")
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
return /* @__PURE__ */ l("div", {
|
|
77
|
+
ref: O,
|
|
78
|
+
"data-size": C,
|
|
79
|
+
"data-text-position": y,
|
|
80
|
+
"data-text-alignment": A,
|
|
81
|
+
"data-presence-only": x ? "" : void 0,
|
|
82
|
+
className: e(i.root, p[y], D),
|
|
83
|
+
...k,
|
|
84
|
+
children: [x ? M && /* @__PURE__ */ c("span", {
|
|
85
|
+
className: e(i.badge, "inline-flex shrink-0"),
|
|
86
|
+
children: M
|
|
87
|
+
}) : /* @__PURE__ */ l("div", {
|
|
23
88
|
className: "relative inline-flex shrink-0",
|
|
24
|
-
children: [
|
|
25
|
-
src:
|
|
26
|
-
name:
|
|
27
|
-
size:
|
|
89
|
+
children: [T && r(T) ? n(T, "span", i.avatar) : /* @__PURE__ */ c(a, {
|
|
90
|
+
src: S,
|
|
91
|
+
name: m,
|
|
92
|
+
size: C === "huge" ? 72 : C,
|
|
28
93
|
decorative: !0,
|
|
29
|
-
className:
|
|
30
|
-
}),
|
|
31
|
-
className: e(
|
|
32
|
-
children:
|
|
33
|
-
})]
|
|
34
|
-
}), /* @__PURE__ */ s("div", {
|
|
35
|
-
className: "flex flex-col",
|
|
36
|
-
children: [/* @__PURE__ */ o("span", {
|
|
37
|
-
className: e(r.primaryText, "font-semibold text-body-1"),
|
|
38
|
-
children: l
|
|
39
|
-
}), u && /* @__PURE__ */ o("span", {
|
|
40
|
-
className: e(r.secondaryText, "text-caption-1 text-muted-foreground"),
|
|
41
|
-
children: u
|
|
94
|
+
className: i.avatar
|
|
95
|
+
}), M && /* @__PURE__ */ c("span", {
|
|
96
|
+
className: e(i.badge, "absolute bottom-0 end-0 inline-flex"),
|
|
97
|
+
children: M
|
|
42
98
|
})]
|
|
99
|
+
}), /* @__PURE__ */ c("div", {
|
|
100
|
+
className: e("flex flex-col", A === "center" ? "items-center text-center" : "items-start text-start"),
|
|
101
|
+
children: P.map(({ key: e, slot: t, className: i }) => t !== void 0 && r(t) && n(t, "span", i, { key: e }))
|
|
43
102
|
})]
|
|
44
103
|
});
|
|
45
104
|
};
|
|
46
|
-
|
|
105
|
+
m.displayName = "Persona";
|
|
47
106
|
//#endregion
|
|
48
|
-
export {
|
|
107
|
+
export { m as Persona };
|
|
49
108
|
|
|
50
109
|
//# sourceMappingURL=Persona.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Persona.mjs","names":["derivePresenceSize","size","Persona","props","badgeNode","badge","slotRendersContent","renderSlot","status","PresenceBadge","cn","personaClassNames","className","avatar","Avatar","name","secondaryText"],"sources":["../../../src/components/data-display/Persona.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { personaClassNames } from '../../lib/classNames';\nimport type { PresenceStatus, Size, Slot } from '../../lib/types';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport { Avatar } from './Avatar';\nimport { PresenceBadge } from './PresenceBadge';\n\n/** Properties for the Persona component. */\nexport interface PersonaProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Display name of the person. */\n name: string;\n /** Secondary text such as job title or email. */\n secondaryText?: string;\n /** URL of the person's avatar image. */\n src?: string;\n /** Size of the persona avatar.\n * @default 'medium'\n */\n size?: Size;\n /** Presence status shown as a badge on the avatar. Ignored when a `badge` is given. */\n status?: PresenceStatus;\n /**\n * Slot for a custom avatar element, replacing the built-in one. The name is already visible\n * next to it, so make a custom avatar decorative (e.g. `<Avatar decorative … />`). A value that\n * renders nothing (`null`, `false`, `''`, `0`, `NaN`, or an array, `Set` or generator of only\n * such items) counts as not given.\n */\n avatar?: Slot<'span'>;\n /**\n * Slot for a custom badge element. Takes precedence over `status`. A value that renders nothing\n * (`null`, `false`, `''`, `0`, `NaN`, e.g. `badge={count && <CounterBadge count={count} />}`,\n * or an array, `Set` or generator of only such items) counts as not given.\n */\n badge?: Slot<'span'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction derivePresenceSize(size: Size): Size {\n return size === 'extra-small' || size === 'small' ? 'small' : 'medium';\n}\n\n/**\n * A person's avatar next to their name and optional secondary text (job title, email), with an\n * optional presence badge.\n *\n * The built-in avatar is decorative (`<Avatar decorative>`): the visible name is announced once,\n * not a second time as the avatar's image name. The presence badge stays exposed as a named image.\n *\n * @example\n * <Persona name=\"Jane Doe\" secondaryText=\"Designer\" status=\"available\" />\n */\nexport const Persona = ({\n name,\n secondaryText,\n src,\n size = 'medium',\n status,\n avatar,\n badge,\n className,\n ref,\n ...props\n}: PersonaProps) => {\n // A slot that renders nothing (`badge={count && …}` with count 0, an empty `.map()` result) is\n // not given (C-SLOTS), so the status badge and the built-in avatar apply.\n const badgeNode =\n badge && slotRendersContent(badge) ? (\n renderSlot(badge, 'span')\n ) : status ? (\n <PresenceBadge status={status} size={derivePresenceSize(size)} />\n ) : null;\n\n return (\n <div\n ref={ref}\n className={cn(personaClassNames.root, 'inline-flex items-center gap-3', className)}\n {...props}\n >\n <div className=\"relative inline-flex shrink-0\">\n {avatar && slotRendersContent(avatar) ? (\n renderSlot(avatar, 'span', personaClassNames.avatar)\n ) : (\n <Avatar\n src={src}\n name={name}\n size={size}\n decorative\n className={personaClassNames.avatar}\n />\n )}\n {badgeNode && (\n <span className={cn(personaClassNames.badge, 'absolute bottom-0 end-0 inline-flex')}>\n {badgeNode}\n </span>\n )}\n </div>\n <div className=\"flex flex-col\">\n <span className={cn(personaClassNames.primaryText, 'font-semibold text-body-1')}>\n {name}\n </span>\n {secondaryText && (\n <span\n className={cn(personaClassNames.secondaryText, 'text-caption-1 text-muted-foreground')}\n >\n {secondaryText}\n </span>\n )}\n </div>\n </div>\n );\n};\n\nPersona.displayName = 'Persona';\n"],"mappings":";;;;;;;;;AAuCA,SAASA,EAAmB,GAAkB;CAC5C,OAAOC,MAAS,iBAAiBA,MAAS,UAAU,UAAU;AAChE;AAYA,IAAaC,KAAW,EACtB,SACA,kBACA,QACA,UAAO,UACP,WACA,WACA,UACA,cACA,QACA,GAAGC,QACe;CAGlB,IAAMC,IACJC,KAASC,EAAmBD,CAAK,IAC/BE,EAAWF,GAAO,MAAM,IACtBG,IACF,kBAACC,GAAD;EAAuB;EAAQ,MAAMT,EAAmBC,CAAI;CAAI,CAAA,IAC9D;CAEN,OACE,kBAAC,OAAD;EACO;EACL,WAAWS,EAAGC,EAAkB,MAAM,kCAAkCC,CAAS;EACjF,GAAIT;EAHN,UAAA,CAKE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACGU,KAAUP,EAAmBO,CAAM,IAClCN,EAAWM,GAAQ,QAAQF,EAAkB,MAAM,IAEnD,kBAACG,GAAD;IACO;IACC;IACA;IACN,YAAA;IACA,WAAWH,EAAkB;GAC9B,CAAA,GAEFP,KACC,kBAAC,QAAD;IAAM,WAAWM,EAAGC,EAAkB,OAAO,qCAAqC;IAC/E,UAAAP;GACG,CAAA,CAEL;EACL,CAAA,GAAA,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,QAAD;IAAM,WAAWM,EAAGC,EAAkB,aAAa,2BAA2B;IAC3E,UAAAI;GACG,CAAA,GACLC,KACC,kBAAC,QAAD;IACE,WAAWN,EAAGC,EAAkB,eAAe,sCAAsC;IAEpF,UAAAK;GACG,CAAA,CAEL;EACF,CAAA,CAAA;;AAET;AAEA,EAAQ,cAAc"}
|
|
1
|
+
{"version":3,"file":"Persona.mjs","names":["React","derivePresenceSize","size","derivePresenceOnlySize","textClasses","positionClasses","Persona","props","resolvedAlignment","textAlignment","textPosition","hasPrimary","primaryText","name","slotRendersContent","warnOnce","badgeNode","badge","renderSlot","status","PresenceBadge","presenceOnly","text","lines","cn","personaClassNames","secondaryText","tertiaryText","quaternaryText","className","avatar","Avatar","lineClass","slot"],"sources":["../../../src/components/data-display/Persona.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { personaClassNames } from '../../lib/classNames';\nimport { warnOnce } from '../../lib/dev';\nimport type { PresenceStatus, Size, Slot } from '../../lib/types';\nimport { renderSlot, slotRendersContent } from '../../lib/slot';\nimport { Avatar } from './Avatar';\nimport { PresenceBadge } from './PresenceBadge';\n\n/** The size of a Persona: the Avatar sizes, and `huge` (a 72px avatar). */\nexport type PersonaSize = Size | 'huge';\n\n/** Properties for the Persona component. */\nexport interface PersonaProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Display name of the person. It gives the avatar its initials and the first text line its text\n * (unless `primaryText` is given). A persona with neither `name` nor `primaryText` warns in\n * development.\n */\n name?: string;\n /**\n * The first text line (the name). A string, an element or an object of `<span>` attributes.\n * @default the `name`\n */\n primaryText?: Slot<'span'>;\n /** The second text line, such as a job title or email. */\n secondaryText?: Slot<'span'>;\n /** The third text line, such as a location. */\n tertiaryText?: Slot<'span'>;\n /** The fourth text line, such as a status message. */\n quaternaryText?: Slot<'span'>;\n /**\n * Where the text sits relative to the avatar, in reading order: after it, before it, or below it.\n * @default 'after'\n */\n textPosition?: 'after' | 'before' | 'below';\n /**\n * How the text lines align with each other.\n * @default 'start' ('center' when the text is below the avatar)\n */\n textAlignment?: 'start' | 'center';\n /**\n * Shows only the presence badge (from `status` or `badge`) in place of the avatar. The text\n * stays.\n * @default false\n */\n presenceOnly?: boolean;\n /** URL of the person's avatar image. */\n src?: string;\n /**\n * Size of the persona: its avatar and its text.\n * @default 'medium'\n */\n size?: PersonaSize;\n /** Presence status shown as a badge on the avatar. Ignored when a `badge` is given. */\n status?: PresenceStatus;\n /**\n * Slot for a custom avatar element, replacing the built-in one. The name is already visible\n * next to it, so make a custom avatar decorative (e.g. `<Avatar decorative … />`). A value that\n * renders nothing (`null`, `false`, `''`, `0`, `NaN`, or an array, `Set` or generator of only\n * such items) counts as not given.\n */\n avatar?: Slot<'span'>;\n /**\n * Slot for a custom badge element. Takes precedence over `status`. A value that renders nothing\n * (`null`, `false`, `''`, `0`, `NaN`, e.g. `badge={count && <CounterBadge count={count} />}`,\n * or an array, `Set` or generator of only such items) counts as not given.\n */\n badge?: Slot<'span'>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nfunction derivePresenceSize(size: PersonaSize): Size {\n if (size === 'extra-small' || size === 'small') return 'small';\n return size === 'huge' ? 'large' : 'medium';\n}\n\n/** The size of the presence badge that stands alone (`presenceOnly`). */\nfunction derivePresenceOnlySize(size: PersonaSize): Size {\n if (size === 'extra-small' || size === 'small') return 'medium';\n if (size === 'medium' || size === 'large') return 'large';\n return 'extra-large';\n}\n\n/** Type steps of the first line and of the other lines, per size. Literal strings only. */\nconst textClasses: Readonly<Record<PersonaSize, { primary: string; other: string }>> = {\n 'extra-small': { primary: 'text-caption-1', other: 'text-caption-2' },\n small: { primary: 'text-body-1', other: 'text-caption-1' },\n medium: { primary: 'text-body-1', other: 'text-caption-1' },\n large: { primary: 'text-subtitle-2', other: 'text-body-1' },\n 'extra-large': { primary: 'text-subtitle-1', other: 'text-body-1' },\n huge: { primary: 'text-title-3', other: 'text-body-2' },\n};\n\n/** The layout of the root per text position. Logical: `flex-row-reverse` mirrors in RTL by itself. */\nconst positionClasses = {\n after: 'inline-flex items-center gap-3',\n before: 'inline-flex flex-row-reverse items-center gap-3',\n below: 'inline-flex flex-col items-center gap-2',\n} as const;\n\n/**\n * A person's avatar next to their name and up to three more text lines (job title, location,\n * status), with an optional presence badge. The text can sit after, before or below the avatar\n * (`textPosition`), `presenceOnly` swaps the avatar for the presence badge, and the text scales with\n * `size` up to `huge`.\n *\n * The built-in avatar is decorative (`<Avatar decorative>`): the visible name is announced once,\n * not a second time as the avatar's image name. The presence badge stays exposed as a named image.\n *\n * @example\n * <Persona name=\"Jane Doe\" secondaryText=\"Designer\" tertiaryText=\"Oslo\" status=\"available\" />\n */\nexport const Persona = ({\n name,\n primaryText,\n secondaryText,\n tertiaryText,\n quaternaryText,\n textPosition = 'after',\n textAlignment,\n presenceOnly = false,\n src,\n size = 'medium',\n status,\n avatar,\n badge,\n className,\n ref,\n ...props\n}: PersonaProps) => {\n const resolvedAlignment = textAlignment ?? (textPosition === 'below' ? 'center' : 'start');\n const hasPrimary = primaryText !== undefined ? slotRendersContent(primaryText) : !!name;\n React.useEffect(() => {\n if (!hasPrimary) {\n warnOnce(\n 'Persona:unnamed',\n 'Persona: it has neither a `name` nor a `primaryText`, so nothing names the person. Pass one of them.',\n );\n }\n }, [hasPrimary]);\n\n // A slot that renders nothing (`badge={count && …}` with count 0, an empty `.map()` result) is\n // not given (C-SLOTS), so the status badge and the built-in avatar apply.\n const badgeNode =\n badge && slotRendersContent(badge) ? (\n renderSlot(badge, 'span')\n ) : status ? (\n <PresenceBadge\n status={status}\n size={presenceOnly ? derivePresenceOnlySize(size) : derivePresenceSize(size)}\n />\n ) : null;\n\n const text = textClasses[size];\n const lines = [\n {\n key: 'primaryText',\n slot: primaryText ?? name,\n className: cn(personaClassNames.primaryText, text.primary, 'font-semibold'),\n },\n {\n key: 'secondaryText',\n slot: secondaryText,\n className: cn(personaClassNames.secondaryText, text.other, 'text-muted-foreground'),\n },\n {\n key: 'tertiaryText',\n slot: tertiaryText,\n className: cn(personaClassNames.tertiaryText, text.other, 'text-muted-foreground'),\n },\n {\n key: 'quaternaryText',\n slot: quaternaryText,\n className: cn(personaClassNames.quaternaryText, text.other, 'text-muted-foreground'),\n },\n ] as const;\n\n return (\n <div\n ref={ref}\n data-size={size}\n data-text-position={textPosition}\n data-text-alignment={resolvedAlignment}\n data-presence-only={presenceOnly ? '' : undefined}\n className={cn(personaClassNames.root, positionClasses[textPosition], className)}\n {...props}\n >\n {presenceOnly ? (\n badgeNode && (\n <span className={cn(personaClassNames.badge, 'inline-flex shrink-0')}>{badgeNode}</span>\n )\n ) : (\n <div className=\"relative inline-flex shrink-0\">\n {avatar && slotRendersContent(avatar) ? (\n renderSlot(avatar, 'span', personaClassNames.avatar)\n ) : (\n <Avatar\n src={src}\n name={name}\n size={size === 'huge' ? 72 : size}\n decorative\n className={personaClassNames.avatar}\n />\n )}\n {badgeNode && (\n <span className={cn(personaClassNames.badge, 'absolute bottom-0 end-0 inline-flex')}>\n {badgeNode}\n </span>\n )}\n </div>\n )}\n <div\n className={cn(\n 'flex flex-col',\n resolvedAlignment === 'center' ? 'items-center text-center' : 'items-start text-start',\n )}\n >\n {lines.map(\n ({ key, slot, className: lineClass }) =>\n slot !== undefined &&\n slotRendersContent(slot) &&\n renderSlot(slot, 'span', lineClass, { key }),\n )}\n </div>\n </div>\n );\n};\n\nPersona.displayName = 'Persona';\n"],"mappings":";;;;;;;;;;AAyEA,SAASC,EAAmB,GAAyB;CAEnD,OADIC,MAAS,iBAAiBA,MAAS,UAAgB,UAChDA,MAAS,SAAS,UAAU;AACrC;AAGA,SAASC,EAAuB,GAAyB;CAGvD,OAFID,MAAS,iBAAiBA,MAAS,UAAgB,WACnDA,MAAS,YAAYA,MAAS,UAAgB,UAC3C;AACT;AAGA,IAAME,IAAiF;CACrF,eAAe;EAAE,SAAS;EAAkB,OAAO;CAAiB;CACpE,OAAO;EAAE,SAAS;EAAe,OAAO;CAAiB;CACzD,QAAQ;EAAE,SAAS;EAAe,OAAO;CAAiB;CAC1D,OAAO;EAAE,SAAS;EAAmB,OAAO;CAAc;CAC1D,eAAe;EAAE,SAAS;EAAmB,OAAO;CAAc;CAClE,MAAM;EAAE,SAAS;EAAgB,OAAO;CAAc;AACxD,GAGMC,IAAkB;CACtB,OAAO;CACP,QAAQ;CACR,OAAO;AACT,GAcaC,KAAW,EACtB,SACA,gBACA,kBACA,iBACA,mBACA,kBAAe,SACf,kBACA,kBAAe,IACf,QACA,UAAO,UACP,WACA,WACA,UACA,cACA,QACA,GAAGC,QACe;CAClB,IAAMC,IAAoBC,MAAkBC,MAAiB,UAAU,WAAW,UAC5EC,IAAaC,MAAgB,KAAA,IAA8C,CAAC,CAACC,IAApCC,EAAmBF,CAAW;CAC7E,EAAM,gBAAgB;EACpB,AAAKD,KACHI,EACE,mBACA,sGACF;CAEJ,GAAG,CAACJ,CAAU,CAAC;CAIf,IAAMK,IACJC,KAASH,EAAmBG,CAAK,IAC/BC,EAAWD,GAAO,MAAM,IACtBE,IACF,kBAACC,GAAD;EACU;EACR,MAAMC,IAAelB,EAAuBD,CAAI,IAAID,EAAmBC,CAAI;CAC5E,CAAA,IACC,MAEAoB,IAAOlB,EAAYF,IACnBqB,IAAQ;EACZ;GACE,KAAK;GACL,MAAMX,KAAeC;GACrB,WAAWW,EAAGC,EAAkB,aAAaH,EAAK,SAAS,eAAe;EAC5E;EACA;GACE,KAAK;GACL,MAAMI;GACN,WAAWF,EAAGC,EAAkB,eAAeH,EAAK,OAAO,uBAAuB;EACpF;EACA;GACE,KAAK;GACL,MAAMK;GACN,WAAWH,EAAGC,EAAkB,cAAcH,EAAK,OAAO,uBAAuB;EACnF;EACA;GACE,KAAK;GACL,MAAMM;GACN,WAAWJ,EAAGC,EAAkB,gBAAgBH,EAAK,OAAO,uBAAuB;EACrF;CACF;CAEA,OACE,kBAAC,OAAD;EACO;EACL,aAAWpB;EACX,sBAAoBQ;EACpB,uBAAqBF;EACrB,sBAAoBa,IAAe,KAAK,KAAA;EACxC,WAAWG,EAAGC,EAAkB,MAAMpB,EAAgBK,IAAemB,CAAS;EAC9E,GAAItB;EAPN,UAAA,CASGc,IACCL,KACE,kBAAC,QAAD;GAAM,WAAWQ,EAAGC,EAAkB,OAAO,sBAAsB;GAAI,UAAAT;EAAgB,CAAA,IAGzF,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACGc,KAAUhB,EAAmBgB,CAAM,IAClCZ,EAAWY,GAAQ,QAAQL,EAAkB,MAAM,IAEnD,kBAACM,GAAD;IACO;IACC;IACN,MAAM7B,MAAS,SAAS,KAAKA;IAC7B,YAAA;IACA,WAAWuB,EAAkB;GAC9B,CAAA,GAEFT,KACC,kBAAC,QAAD;IAAM,WAAWQ,EAAGC,EAAkB,OAAO,qCAAqC;IAC/E,UAAAT;GACG,CAAA,CAEL;EAEP,CAAA,GAAA,kBAAC,OAAD;GACE,WAAWQ,EACT,iBACAhB,MAAsB,WAAW,6BAA6B,wBAChE;GAEC,UAAAe,EAAM,KACJ,EAAE,QAAK,SAAM,WAAWS,QACvBC,MAAS,KAAA,KACTnB,EAAmBmB,CAAI,KACvBf,EAAWe,GAAM,QAAQD,GAAW,EAAE,OAAI,CAAC,CAC/C;EACG,CAAA,CACF;;AAET;AAEA,EAAQ,cAAc"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/
|
|
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/styles.cjs"),a=require("../../lib/icons.cjs"),o=require("./Avatar.context.cjs");let s=require("react");s=e.__toESM(s,1);let c=require("react/jsx-runtime");var l={available:{glyph:`check`,Icon:a.PresenceAvailableIcon,className:`bg-presence-available text-presence-glyph`},busy:{glyph:`solid`,Icon:a.PresenceBusyIcon,className:`bg-presence-busy text-presence-busy`},away:{glyph:`clock`,Icon:a.PresenceAwayIcon,className:`bg-presence-away text-presence-glyph`},offline:{glyph:`ring-x`,Icon:a.PresenceOfflineIcon,className:`bg-background text-presence-offline`},"do-not-disturb":{glyph:`bar`,Icon:a.PresenceDndIcon,className:`bg-presence-busy text-presence-glyph`},"out-of-office":{glyph:`arrow`,Icon:a.PresenceOofIcon,className:`bg-presence-oof text-presence-glyph`}},u={available:`Available`,busy:`Busy`,away:`Away`,offline:`Offline`,"do-not-disturb":`Do not disturb`,"out-of-office":`Out of office`},d={dnd:`do-not-disturb`,oof:`out-of-office`};function f(e){if(e===`dnd`||e===`oof`){let t=d[e];return n.warnDeprecated(`PresenceBadge`,`status '${e}'`,`status '${t}'`),t}return e}var p={"extra-small":`size-2`,small:`size-2.5`,medium:`size-3`,large:`size-4`,"extra-large":`size-5`},m=({status:e=`available`,size:n,className:a,ref:d,...m})=>{let h=s.useContext(o.AvatarBadgeSizeContext),g=n??h??`medium`,_=f(e),{glyph:v,Icon:y,className:b}=l[_];return(0,c.jsx)(`span`,{ref:d,role:`img`,"aria-label":u[_],"data-glyph":v,"data-status":_,...m,className:t.cn(r.presenceBadgeClassNames.root,`inline-flex shrink-0 items-center justify-center rounded-full ring-2 ring-background`,`forced-colors:border`,i.forcedColors.border,p[g],b,a),children:(0,c.jsx)(y,{size:`100%`,className:t.cn(r.presenceBadgeClassNames.icon,`size-full`,v===`arrow`&&`wave-rtl:-scale-x-100`)})})};m.displayName=`PresenceBadge`,exports.PresenceBadge=m;
|
|
2
2
|
//# sourceMappingURL=PresenceBadge.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PresenceBadge.cjs","names":["PresenceAvailableIcon","PresenceBusyIcon","PresenceAwayIcon","PresenceOfflineIcon","PresenceDndIcon","PresenceOofIcon","cn","presenceBadgeClassNames","forcedColors","require_runtime","require_cn","require_classNames","require_styles","require_icons","react","react_jsx_runtime","statusStyles","statusLabels","sizeClasses","PresenceBadge","
|
|
1
|
+
{"version":3,"file":"PresenceBadge.cjs","names":["PresenceAvailableIcon","PresenceBusyIcon","PresenceAwayIcon","PresenceOfflineIcon","PresenceDndIcon","PresenceOofIcon","React","AvatarBadgeSizeContext","cn","presenceBadgeClassNames","forcedColors","require_runtime","require_cn","require_dev","require_classNames","require_styles","require_icons","require_Avatar_context","react","react_jsx_runtime","statusStyles","statusLabels","DEPRECATED_STATUS_NAMES","normalizePresenceStatus","status","current","sizeClasses","PresenceBadge","statusProp","sizeProp","props","avatarBadgeSize","size","statusClassName","glyph","className","Icon"],"sources":["../../../src/components/data-display/PresenceBadge.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { presenceBadgeClassNames } from '../../lib/classNames';\nimport {\n PresenceAvailableIcon,\n PresenceAwayIcon,\n PresenceBusyIcon,\n PresenceDndIcon,\n PresenceOfflineIcon,\n PresenceOofIcon,\n} from '../../lib/icons';\nimport type { IconComponent } from '../../lib/icons';\nimport { warnDeprecated } from '../../lib/dev';\nimport { AvatarBadgeSizeContext } from './Avatar.context';\nimport { forcedColors } from '../../lib/styles';\nimport type { DeprecatedPresenceStatus, PresenceStatus, Size } from '../../lib/types';\n\n/** Properties for the PresenceBadge component. */\nexport interface PresenceBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {\n /**\n * Presence status to display. `'dnd'` and `'oof'` are deprecated aliases of `'do-not-disturb'`\n * and `'out-of-office'`: they render the same and warn once in development (removed in 1.0).\n * @default 'available'\n */\n status?: PresenceStatus;\n /**\n * Size of the presence indicator. In the `badge` slot of an Avatar it is sized from the avatar.\n * @default 'medium'\n */\n size?: Size;\n /** Ref to the root `<span>`. */\n ref?: React.Ref<HTMLSpanElement>;\n}\n\n/** The shape drawn for a status, exposed as `data-glyph` (styling hook and test contract). */\ntype PresenceGlyph = 'check' | 'solid' | 'clock' | 'ring-x' | 'bar' | 'arrow';\n\n/**\n * Per status: the glyph name, its shared icon (src/lib/icons.tsx, drawn in a 16×16 box that the\n * badge circle fills) and the colors. Busy is a full disc in `currentColor`: forced-colors mode\n * replaces the background with Canvas but forces `color` to CanvasText, so busy stays a solid dot\n * instead of an empty ring.\n */\nconst statusStyles: Record<\n Exclude<PresenceStatus, DeprecatedPresenceStatus>,\n { glyph: PresenceGlyph; Icon: IconComponent; className: string }\n> = {\n available: {\n glyph: 'check',\n Icon: PresenceAvailableIcon,\n className: 'bg-presence-available text-presence-glyph',\n },\n busy: {\n glyph: 'solid',\n Icon: PresenceBusyIcon,\n className: 'bg-presence-busy text-presence-busy',\n },\n away: {\n glyph: 'clock',\n Icon: PresenceAwayIcon,\n className: 'bg-presence-away text-presence-glyph',\n },\n offline: {\n glyph: 'ring-x',\n Icon: PresenceOfflineIcon,\n className: 'bg-background text-presence-offline',\n },\n 'do-not-disturb': {\n glyph: 'bar',\n Icon: PresenceDndIcon,\n className: 'bg-presence-busy text-presence-glyph',\n },\n 'out-of-office': {\n glyph: 'arrow',\n Icon: PresenceOofIcon,\n className: 'bg-presence-oof text-presence-glyph',\n },\n};\n\nconst statusLabels: Record<Exclude<PresenceStatus, DeprecatedPresenceStatus>, string> = {\n available: 'Available',\n busy: 'Busy',\n away: 'Away',\n offline: 'Offline',\n 'do-not-disturb': 'Do not disturb',\n 'out-of-office': 'Out of office',\n};\n\nconst DEPRECATED_STATUS_NAMES = {\n dnd: 'do-not-disturb',\n oof: 'out-of-office',\n} as const;\n\n/** Maps the deprecated spellings to their Fluent names; warns once for an alias. */\nfunction normalizePresenceStatus(\n status: PresenceStatus,\n): Exclude<PresenceStatus, DeprecatedPresenceStatus> {\n if (status === 'dnd' || status === 'oof') {\n const current = DEPRECATED_STATUS_NAMES[status];\n warnDeprecated('PresenceBadge', `status '${status}'`, `status '${current}'`);\n return current;\n }\n return status;\n}\n\nconst sizeClasses: Record<Size, string> = {\n 'extra-small': 'size-2', // 8px\n small: 'size-2.5', // 10px\n medium: 'size-3', // 12px\n large: 'size-4', // 16px\n 'extra-large': 'size-5', // 20px\n};\n\n/**\n * A person's availability as a small badge, usually placed on an `Avatar` (`badge` prop).\n *\n * Every status has its own shape, so it is not conveyed by color alone: available (check),\n * busy (solid), away (clock), offline (hollow ring with an X), do not disturb (bar), out of office\n * (arrow, mirrored in right-to-left layouts). A background-colored ring separates it from the\n * avatar. It is a named image (`role=\"img\"`, `aria-label` = the status name; pass `aria-label` to\n * localise or extend it) and never a live region.\n *\n * @example\n * <PresenceBadge status=\"busy\" />\n * <PresenceBadge status=\"do-not-disturb\" />\n */\nexport const PresenceBadge = ({\n status: statusProp = 'available',\n size: sizeProp,\n className,\n ref,\n ...props\n}: PresenceBadgeProps) => {\n const avatarBadgeSize = React.useContext(AvatarBadgeSizeContext);\n const size = sizeProp ?? avatarBadgeSize ?? 'medium';\n const status = normalizePresenceStatus(statusProp);\n const { glyph, Icon, className: statusClassName } = statusStyles[status];\n\n return (\n <span\n ref={ref}\n role=\"img\"\n aria-label={statusLabels[status]}\n data-glyph={glyph}\n data-status={status}\n {...props}\n className={cn(\n presenceBadgeClassNames.root,\n 'inline-flex shrink-0 items-center justify-center rounded-full ring-2 ring-background',\n 'forced-colors:border',\n forcedColors.border,\n sizeClasses[size],\n statusClassName,\n className,\n )}\n >\n <Icon\n size=\"100%\"\n className={cn(\n presenceBadgeClassNames.icon,\n 'size-full',\n glyph === 'arrow' && 'wave-rtl:-scale-x-100',\n )}\n />\n </span>\n );\n};\n\nPresenceBadge.displayName = 'PresenceBadge';\n"],"mappings":"wVA2CA,IAAMoB,EAGF,CACF,UAAW,CACT,MAAO,QACP,KAAMpB,EAAAA,sBACN,UAAW,2CACb,EACA,KAAM,CACJ,MAAO,QACP,KAAMC,EAAAA,iBACN,UAAW,qCACb,EACA,KAAM,CACJ,MAAO,QACP,KAAMC,EAAAA,iBACN,UAAW,sCACb,EACA,QAAS,CACP,MAAO,SACP,KAAMC,EAAAA,oBACN,UAAW,qCACb,EACA,iBAAkB,CAChB,MAAO,MACP,KAAMC,EAAAA,gBACN,UAAW,sCACb,EACA,gBAAiB,CACf,MAAO,QACP,KAAMC,EAAAA,gBACN,UAAW,qCACb,CACF,EAEMgB,EAAkF,CACtF,UAAW,YACX,KAAM,OACN,KAAM,OACN,QAAS,UACT,iBAAkB,iBAClB,gBAAiB,eACnB,EAEMC,EAA0B,CAC9B,IAAK,iBACL,IAAK,eACP,EAGA,SAASC,EACP,EACmD,CACnD,GAAIC,IAAW,OAASA,IAAW,MAAO,CACxC,IAAMC,EAAUH,EAAwBE,GAExC,OADAX,EAAA,eAAe,gBAAiB,WAAWW,EAAO,GAAI,WAAWC,EAAQ,EAAE,EACpEA,CACT,CACA,OAAOD,CACT,CAEA,IAAME,EAAoC,CACxC,cAAe,SACf,MAAO,WACP,OAAQ,SACR,MAAO,SACP,cAAe,QACjB,EAeaC,GAAiB,CAC5B,OAAQC,EAAa,YACrB,KAAMC,EACN,YACA,MACA,GAAGC,KACqB,CACxB,IAAMC,EAAkBzB,EAAM,WAAWC,EAAAA,sBAAsB,EACzDyB,EAAOH,GAAYE,GAAmB,SACtCP,EAASD,EAAwBK,CAAU,EAC3C,CAAE,QAAO,OAAM,UAAWK,GAAoBb,EAAaI,GAEjE,OACE,EAAAL,EAAA,IAAA,CAAC,OAAD,CACO,MACL,KAAK,MACL,aAAYE,EAAaG,GACzB,aAAYU,EACZ,cAAaV,EACb,GAAIM,EACJ,UAAWtB,EAAAA,GACTC,EAAAA,wBAAwB,KACxB,uFACA,uBACAC,EAAAA,aAAa,OACbgB,EAAYM,GACZC,EACAE,CACF,EAEA,UAAA,EAAAhB,EAAA,IAAA,CAACiB,EAAD,CACE,KAAK,OACL,UAAW5B,EAAAA,GACTC,EAAAA,wBAAwB,KACxB,YACAyB,IAAU,SAAW,uBACvB,CACD,CAAA,CACG,CAAA,CAEV,EAEA,EAAc,YAAc"}
|