(null)
+ const ref = forwardedRef || internalRef
+ const hasEllipsis = useEllipsisOverflow({
+ disabled,
+ lines,
+ ref: typeof ref === "object" ? ref : null,
+ })
+
+ const text = React.createElement(
+ tag,
+ {
+ ref,
+ className: cn(
+ !noTooltip && hasEllipsis && "pointer-events-auto",
+ "min-w-0 max-w-full overflow-hidden",
+ !disabled && [
+ lines === 1 ? "text-ellipsis" : "",
+ lines > 1
+ ? `not-supports-[(-webkit-line-clamp:${lines})]:whitespace-nowrap line-clamp-1 whitespace-normal`
+ : "block whitespace-nowrap",
+ ],
+ className
+ ),
+ style: {
+ WebkitLineClamp: lines > 1 ? lines : undefined,
+ lineClamp: lines > 1 ? lines : undefined,
+ },
+ ...props,
+ "data-testid": "one-ellipsis",
+ },
+ children
+ )
+
+ const showTooltip = hasEllipsis && !noTooltip
+
+ return (
+
+
+
+ {text}
+
+ {showTooltip && (
+ {children}
+ )}
+
+
+ )
+ }
+)
+
+PlainEllipsis.displayName = "PlainEllipsis"
+
+export { PlainEllipsis, PlainEllipsis as OneEllipsis }
diff --git a/packages/react/src/lib/OneEllipsis/__stories__/OneEllipsis.stories.tsx b/packages/react/src/lib/OneEllipsis/__stories__/OneEllipsis.stories.tsx
index f98beea260..70660be687 100644
--- a/packages/react/src/lib/OneEllipsis/__stories__/OneEllipsis.stories.tsx
+++ b/packages/react/src/lib/OneEllipsis/__stories__/OneEllipsis.stories.tsx
@@ -2,6 +2,8 @@ import type { Meta, StoryObj } from "@storybook/react-vite"
import { useId, useState } from "react"
+import { withSnapshot } from "@/lib/storybook-utils/parameters"
+
import { OneEllipsis, Tag, tags } from "../OneEllipsis"
const meta = {
@@ -175,3 +177,22 @@ export const ShortTextMultiLine: Story = {
/>
),
}
+
+export const Snapshot: Story = {
+ parameters: withSnapshot({}),
+ args: {
+ children: "Ellipsis snapshot",
+ },
+ render: () => (
+
+
+ A long single-line label that is intentionally constrained
+
+
+ A longer multi-line description that is intentionally constrained to
+ demonstrate line clamping in the consolidated snapshot.
+
+ Short text
+
+ ),
+}
diff --git a/packages/react/src/lib/OneEllipsis/index.tsx b/packages/react/src/lib/OneEllipsis/index.tsx
index 5f0d6e24ee..1751dc3323 100644
--- a/packages/react/src/lib/OneEllipsis/index.tsx
+++ b/packages/react/src/lib/OneEllipsis/index.tsx
@@ -1 +1,2 @@
export * from "./OneEllipsis"
+export { PlainEllipsis } from "./PlainEllipsis"
diff --git a/packages/react/src/lib/OneEllipsis/types.ts b/packages/react/src/lib/OneEllipsis/types.ts
new file mode 100644
index 0000000000..2c0dea2f7d
--- /dev/null
+++ b/packages/react/src/lib/OneEllipsis/types.ts
@@ -0,0 +1,15 @@
+export const tags = [
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "p",
+ "span",
+ "div",
+ "label",
+ "code",
+] as const
+
+export type Tag = (typeof tags)[number]
diff --git a/packages/react/src/lib/OneEllipsis/use-ellipsis-overflow.ts b/packages/react/src/lib/OneEllipsis/use-ellipsis-overflow.ts
new file mode 100644
index 0000000000..f1744c193b
--- /dev/null
+++ b/packages/react/src/lib/OneEllipsis/use-ellipsis-overflow.ts
@@ -0,0 +1,59 @@
+import { useEffect, useState, type RefObject } from "react"
+
+interface UseEllipsisOverflowOptions {
+ disabled: boolean
+ lines: number
+ onChange?: (hasEllipsis: boolean) => void
+ ref: RefObject | null
+}
+
+const checkForEllipsis = (element: HTMLElement, lines: number) => {
+ if (lines > 1) {
+ const lineHeight = parseInt(window.getComputedStyle(element).lineHeight)
+ return element.scrollHeight > lineHeight * lines
+ }
+
+ return element.scrollWidth > element.clientWidth
+}
+
+export function useEllipsisOverflow({
+ disabled,
+ lines,
+ onChange,
+ ref,
+}: UseEllipsisOverflowOptions) {
+ const [hasEllipsis, setHasEllipsis] = useState(false)
+
+ useEffect(
+ function observeEllipsis() {
+ const element = ref?.current
+ if (!element) return
+ if (disabled) {
+ setHasEllipsis(false)
+ onChange?.(false)
+ return
+ }
+
+ const updateEllipsis = () => {
+ const nextHasEllipsis = checkForEllipsis(element, lines)
+ setHasEllipsis(nextHasEllipsis)
+ onChange?.(nextHasEllipsis)
+ }
+
+ updateEllipsis()
+ const animationFrame = requestAnimationFrame(updateEllipsis)
+ const timeout = setTimeout(updateEllipsis, 100)
+ const resizeObserver = new ResizeObserver(updateEllipsis)
+ resizeObserver.observe(element)
+
+ return () => {
+ cancelAnimationFrame(animationFrame)
+ clearTimeout(timeout)
+ resizeObserver.disconnect()
+ }
+ },
+ [disabled, lines, onChange, ref]
+ )
+
+ return hasEllipsis
+}
diff --git a/packages/react/src/lib/emoji-confetti.ts b/packages/react/src/lib/emoji-confetti.ts
new file mode 100644
index 0000000000..64ff6189c1
--- /dev/null
+++ b/packages/react/src/lib/emoji-confetti.ts
@@ -0,0 +1,37 @@
+import confetti from "canvas-confetti"
+import { useCallback, type RefObject } from "react"
+
+import { useReducedMotion } from "./a11y"
+
+export const useEmojiConfetti = () => {
+ const shouldReduceMotion = useReducedMotion()
+
+ const fireEmojiConfetti = useCallback(
+ (emoji: string, elementRef: RefObject) => {
+ const button = elementRef.current
+ if (button) {
+ const rect = button.getBoundingClientRect()
+ const centerX = rect.left + rect.width / 2
+ const centerY = rect.top
+
+ confetti({
+ particleCount: 20,
+ gravity: 0,
+ spread: 360,
+ startVelocity: 10,
+ ticks: 50,
+ origin: {
+ x: centerX / window.innerWidth,
+ y: centerY / window.innerHeight,
+ },
+ shapes: [confetti.shapeFromText({ text: emoji, scalar: 2 })],
+ scalar: 2,
+ disableForReducedMotion: shouldReduceMotion,
+ })
+ }
+ },
+ [shouldReduceMotion]
+ )
+
+ return { fireEmojiConfetti }
+}
diff --git a/packages/react/src/lib/emojis.tsx b/packages/react/src/lib/emojis.tsx
index 1623970752..88513c8de3 100644
--- a/packages/react/src/lib/emojis.tsx
+++ b/packages/react/src/lib/emojis.tsx
@@ -1,10 +1,7 @@
-import confetti from "canvas-confetti"
import { cva, type VariantProps } from "cva"
import { motion } from "motion/react"
-import { RefObject, useCallback } from "react"
import { parse } from "twemoji-parser"
-import { useReducedMotion } from "./a11y"
import { cn } from "./utils"
interface ParseObject {
@@ -133,36 +130,3 @@ const parseEmoji = (emoji: string): ParseObject | null => {
export function getEmojiLabel(emoji: string): string {
return `${emoji} emoji`
}
-
-export const useEmojiConfetti = () => {
- const shouldReduceMotion = useReducedMotion()
-
- const fireEmojiConfetti = useCallback(
- (emoji: string, elementRef: RefObject) => {
- const button = elementRef.current
- if (button) {
- const rect = button.getBoundingClientRect()
- const centerX = rect.left + rect.width / 2
- const centerY = rect.top
-
- confetti({
- particleCount: 20,
- gravity: 0,
- spread: 360,
- startVelocity: 10,
- ticks: 50,
- origin: {
- x: centerX / window.innerWidth,
- y: centerY / window.innerHeight,
- },
- shapes: [confetti.shapeFromText({ text: emoji, scalar: 2 })],
- scalar: 2,
- disableForReducedMotion: shouldReduceMotion,
- })
- }
- },
- [shouldReduceMotion]
- )
-
- return { fireEmojiConfetti }
-}
diff --git a/packages/react/src/lib/exports.ts b/packages/react/src/lib/exports.ts
index 6da3227e1c..56b7f797a7 100644
--- a/packages/react/src/lib/exports.ts
+++ b/packages/react/src/lib/exports.ts
@@ -7,6 +7,7 @@ export { DndProvider } from "./dnd/context"
export { useDndEvents, useDraggable, useDroppableList } from "./dnd/hooks"
export * from "./dnd/types"
export * from "./emojis"
+export { useEmojiConfetti } from "./emoji-confetti"
export { experimentalComponent as experimental } from "./experimental"
export { OneEllipsis } from "./OneEllipsis"
export { PrivacyModeProvider, usePrivacyMode } from "./privacyMode"
diff --git a/packages/react/src/patterns/F0AnalyticsDashboard/components/DashboardItem/DashboardItem.tsx b/packages/react/src/patterns/F0AnalyticsDashboard/components/DashboardItem/DashboardItem.tsx
index 872ff15328..97b9c976bf 100644
--- a/packages/react/src/patterns/F0AnalyticsDashboard/components/DashboardItem/DashboardItem.tsx
+++ b/packages/react/src/patterns/F0AnalyticsDashboard/components/DashboardItem/DashboardItem.tsx
@@ -25,7 +25,7 @@ import {
import { InfoHint, type InfoHintContent } from "@/lib/InfoHint"
import { One as OneIcon } from "@/icons/ai"
import { useAiChat } from "@/kits/ai/F0AiChat/providers/AiChatStateProvider"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { useI18n } from "@/lib/providers/i18n"
import { cn } from "@/lib/utils"
import {
diff --git a/packages/react/src/patterns/Navigation/Sidebar/Chats/SidebarChatItem.tsx b/packages/react/src/patterns/Navigation/Sidebar/Chats/SidebarChatItem.tsx
index 5c2b897955..ace57a3a0a 100644
--- a/packages/react/src/patterns/Navigation/Sidebar/Chats/SidebarChatItem.tsx
+++ b/packages/react/src/patterns/Navigation/Sidebar/Chats/SidebarChatItem.tsx
@@ -3,7 +3,7 @@ import { ButtonInternal } from "@/components/F0Button/internal"
import { F0Icon } from "@/components/F0Icon/F0Icon"
import { PushPin, PushPinSolid } from "@/icons/app"
import { EmojiImage } from "@/lib/emojis"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { useI18n } from "@/lib/providers/i18n"
import { cn, focusRing } from "@/lib/utils"
import { Spinner } from "@/ui/Spinner"
diff --git a/packages/react/src/patterns/Navigation/Sidebar/CompanySelector/index.tsx b/packages/react/src/patterns/Navigation/Sidebar/CompanySelector/index.tsx
index 7dd250ca40..5e354edf31 100644
--- a/packages/react/src/patterns/Navigation/Sidebar/CompanySelector/index.tsx
+++ b/packages/react/src/patterns/Navigation/Sidebar/CompanySelector/index.tsx
@@ -5,7 +5,7 @@ import { AvatarVariant } from "@/components/avatars/F0Avatar"
import { F0AvatarCompany } from "@/components/avatars/F0AvatarCompany"
import { F0Icon, IconType } from "@/components/F0Icon"
import { F0Select } from "@/components/F0Select"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { ChevronDown, Circle } from "@/icons/app"
import { useI18n } from "@/lib/providers/i18n"
import { cn, focusRing } from "@/lib/utils"
diff --git a/packages/react/src/patterns/Navigation/Sidebar/Footer/index.tsx b/packages/react/src/patterns/Navigation/Sidebar/Footer/index.tsx
index ce2edefb64..0a7c2b8026 100644
--- a/packages/react/src/patterns/Navigation/Sidebar/Footer/index.tsx
+++ b/packages/react/src/patterns/Navigation/Sidebar/Footer/index.tsx
@@ -1,6 +1,6 @@
import { F0AvatarPerson } from "@/components/avatars/F0AvatarPerson"
import { F0Button } from "@/components/F0Button"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { Badge } from "@/ui/IconBadge"
import { Tooltip } from "@/experimental/Overlays/Tooltip"
import { Bell as BellIcon, Circle as CircleIcon } from "@/icons/app"
diff --git a/packages/react/src/patterns/Navigation/Sidebar/Menu/index.tsx b/packages/react/src/patterns/Navigation/Sidebar/Menu/index.tsx
index 1bfc93ea57..f2a3a3476d 100644
--- a/packages/react/src/patterns/Navigation/Sidebar/Menu/index.tsx
+++ b/packages/react/src/patterns/Navigation/Sidebar/Menu/index.tsx
@@ -11,7 +11,7 @@ import {
import { AvatarVariant, F0Avatar } from "@/components/avatars/F0Avatar"
import { F0Icon, IconType } from "@/components/F0Icon"
import { F0TagRaw } from "@/components/tags/F0TagRaw"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { Counter } from "@/ui/Counter"
import { Dropdown, DropdownItem } from "@/experimental/Navigation/Dropdown"
import { NavigationItem } from "@/experimental/Navigation/utils"
diff --git a/packages/react/src/patterns/OneDataCollection/components/ActionBar/OneDataCollectionActionBar.tsx b/packages/react/src/patterns/OneDataCollection/components/ActionBar/OneDataCollectionActionBar.tsx
index be3ff0ffb5..5e09d510cd 100644
--- a/packages/react/src/patterns/OneDataCollection/components/ActionBar/OneDataCollectionActionBar.tsx
+++ b/packages/react/src/patterns/OneDataCollection/components/ActionBar/OneDataCollectionActionBar.tsx
@@ -10,7 +10,7 @@ import {
F0ActionBar,
type F0ActionBarRef,
} from "@/components/F0ActionBar"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { useI18n } from "@/lib/providers/i18n"
export type { ActionBarGroup, ActionBarItem, ActionBarStatus, F0ActionBarRef }
diff --git a/packages/react/src/patterns/OneDataCollection/visualizations/collection/List/components/ItemTeaser.tsx b/packages/react/src/patterns/OneDataCollection/visualizations/collection/List/components/ItemTeaser.tsx
index 9792c2c18e..5eca8962b9 100644
--- a/packages/react/src/patterns/OneDataCollection/visualizations/collection/List/components/ItemTeaser.tsx
+++ b/packages/react/src/patterns/OneDataCollection/visualizations/collection/List/components/ItemTeaser.tsx
@@ -1,5 +1,5 @@
import { AvatarVariant, F0Avatar } from "@/components/avatars/F0Avatar"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
export type ItemTeaserProps = {
title: string
diff --git a/packages/react/src/patterns/OneDataCollection/visualizations/collection/Table/components/SortAndHideList/SortAndHideList.tsx b/packages/react/src/patterns/OneDataCollection/visualizations/collection/Table/components/SortAndHideList/SortAndHideList.tsx
index 0f7ccea041..b0edd14407 100644
--- a/packages/react/src/patterns/OneDataCollection/visualizations/collection/Table/components/SortAndHideList/SortAndHideList.tsx
+++ b/packages/react/src/patterns/OneDataCollection/visualizations/collection/Table/components/SortAndHideList/SortAndHideList.tsx
@@ -6,7 +6,7 @@ import { ButtonInternal } from "@/components/F0Button/internal"
import { F0Icon } from "@/components/F0Icon"
import { Switch } from "@/experimental/Forms/Fields/Switch"
import { Delete, Handle, LockLocked } from "@/icons/app"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { useI18n } from "@/lib/providers/i18n"
import { TooltipWrapper } from "@/lib/tooltip-wrapper"
import { cn } from "@/lib/utils"
diff --git a/packages/react/src/patterns/OneFilterPicker/components/FilterList.tsx b/packages/react/src/patterns/OneFilterPicker/components/FilterList.tsx
index 5df6d1e0b3..6576cf9a03 100644
--- a/packages/react/src/patterns/OneFilterPicker/components/FilterList.tsx
+++ b/packages/react/src/patterns/OneFilterPicker/components/FilterList.tsx
@@ -3,7 +3,7 @@ import { useId, useMemo } from "react"
import { F0Button } from "@/components/F0Button"
import { F0Icon } from "@/components/F0Icon"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { ChevronRight } from "@/icons/app"
import { useReducedMotion } from "@/lib/a11y"
import { useI18n } from "@/lib/providers/i18n"
diff --git a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/InFilter.tsx b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/InFilter.tsx
index eaa465d472..a56bcfcf5d 100644
--- a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/InFilter.tsx
+++ b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/InFilter.tsx
@@ -3,7 +3,7 @@
import { useEffect, useMemo, useRef, useState } from "react"
import { F0Checkbox } from "@/components/F0Checkbox"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { F0SearchInput } from "@/components/F0SearchInput"
import { ScrollArea } from "@/ui/scrollarea"
import { Spinner } from "@/ui/Spinner"
diff --git a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterFlatOption.tsx b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterFlatOption.tsx
index 512b4056b2..67cb40efe5 100644
--- a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterFlatOption.tsx
+++ b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterFlatOption.tsx
@@ -1,6 +1,6 @@
"use client"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn, focusRing } from "@/lib/utils"
import { InFilterOptionItem } from "../types"
diff --git a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterOptionRow.tsx b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterOptionRow.tsx
index dfe4d8f641..3b1f81f67c 100644
--- a/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterOptionRow.tsx
+++ b/packages/react/src/patterns/OneFilterPicker/filterTypes/InFilter/components/InFilterOptionRow.tsx
@@ -3,7 +3,7 @@
import { useCallback, useState } from "react"
import { F0Button } from "@/components/F0Button"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { ChevronDown, ChevronRight } from "@/icons/app"
import { useI18n } from "@/lib/providers/i18n"
import { cn, focusRing } from "@/lib/utils"
diff --git a/packages/react/src/sds/Home/ClockIn/ClockInControls/index.tsx b/packages/react/src/sds/Home/ClockIn/ClockInControls/index.tsx
index 178b70c6e6..523dd588bb 100644
--- a/packages/react/src/sds/Home/ClockIn/ClockInControls/index.tsx
+++ b/packages/react/src/sds/Home/ClockIn/ClockInControls/index.tsx
@@ -6,7 +6,7 @@ import { F0Select } from "@/components/F0Select"
import { F0TagRaw } from "@/components/tags/F0TagRaw"
import { SolidPause, SolidPlay, SolidStop } from "@/icons/app"
import { useReducedMotion } from "@/lib/a11y"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import { ClockInGraph, ClockInGraphProps } from "../ClockInGraph"
diff --git a/packages/react/src/sds/chat/F0Chat/components/ChatEmojiAutocomplete.tsx b/packages/react/src/sds/chat/F0Chat/components/ChatEmojiAutocomplete.tsx
index 02c7c2e5e1..6cc3d5ba01 100644
--- a/packages/react/src/sds/chat/F0Chat/components/ChatEmojiAutocomplete.tsx
+++ b/packages/react/src/sds/chat/F0Chat/components/ChatEmojiAutocomplete.tsx
@@ -1,7 +1,7 @@
import { useEffect, useLayoutEffect, useRef } from "react"
import { EmojiImage } from "@/lib/emojis"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import {
diff --git a/packages/react/src/sds/chat/F0Chat/components/ChatMentionPopover.tsx b/packages/react/src/sds/chat/F0Chat/components/ChatMentionPopover.tsx
index c6c3842a50..6312660eaf 100644
--- a/packages/react/src/sds/chat/F0Chat/components/ChatMentionPopover.tsx
+++ b/packages/react/src/sds/chat/F0Chat/components/ChatMentionPopover.tsx
@@ -3,7 +3,7 @@ import { useEffect, useLayoutEffect, useRef } from "react"
import { F0Avatar } from "@/components/avatars/F0Avatar"
import { F0Icon } from "@/components/F0Icon"
import { People } from "@/icons/app"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import { Skeleton } from "@/ui/skeleton"
diff --git a/packages/react/src/sds/chat/F0Chat/components/ChatReactionPill.tsx b/packages/react/src/sds/chat/F0Chat/components/ChatReactionPill.tsx
index 59a769c96f..5e8204281e 100644
--- a/packages/react/src/sds/chat/F0Chat/components/ChatReactionPill.tsx
+++ b/packages/react/src/sds/chat/F0Chat/components/ChatReactionPill.tsx
@@ -2,7 +2,8 @@ import NumberFlow from "@number-flow/react"
import { type ReactNode, useEffect, useRef, useState } from "react"
import { TooltipInternal } from "@/experimental/Overlays/Tooltip"
-import { EmojiImage, getEmojiLabel, useEmojiConfetti } from "@/lib/emojis"
+import { useEmojiConfetti } from "@/lib/emoji-confetti"
+import { EmojiImage, getEmojiLabel } from "@/lib/emojis"
import { cn } from "@/lib/utils"
import { Action } from "@/ui/Action"
diff --git a/packages/react/src/sds/social/Reactions/reaction.tsx b/packages/react/src/sds/social/Reactions/reaction.tsx
index 2846ec6482..38380efce5 100644
--- a/packages/react/src/sds/social/Reactions/reaction.tsx
+++ b/packages/react/src/sds/social/Reactions/reaction.tsx
@@ -2,7 +2,8 @@ import NumberFlow from "@number-flow/react"
import { useEffect, useRef, useState } from "react"
import { TooltipInternal } from "@/experimental/Overlays/Tooltip"
-import { EmojiImage, getEmojiLabel, useEmojiConfetti } from "@/lib/emojis"
+import { useEmojiConfetti } from "@/lib/emoji-confetti"
+import { EmojiImage, getEmojiLabel } from "@/lib/emojis"
import { cn } from "@/lib/utils"
import { Action } from "@/ui/Action"
diff --git a/packages/react/src/ui/value-display/types/country/country.tsx b/packages/react/src/ui/value-display/types/country/country.tsx
index bd68651f9b..7fb3f5b878 100644
--- a/packages/react/src/ui/value-display/types/country/country.tsx
+++ b/packages/react/src/ui/value-display/types/country/country.tsx
@@ -3,7 +3,7 @@
* Used for showing alerts on items in data collections.
*/
import { F0AvatarFlag } from "@/components/avatars/F0AvatarFlag"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { CountryCode } from "@/lib/countries"
import { ValueDisplayRendererContext } from "../../renderers"
diff --git a/packages/react/src/ui/value-display/types/longText/longText.tsx b/packages/react/src/ui/value-display/types/longText/longText.tsx
index b677f4f3d0..950c55ad1c 100644
--- a/packages/react/src/ui/value-display/types/longText/longText.tsx
+++ b/packages/react/src/ui/value-display/types/longText/longText.tsx
@@ -2,7 +2,7 @@
* Long text cell type for displaying multiple lines of text in data collections.
* Uses the OneEllipsis component to truncate the text and show a tooltip with the full text.
*/
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import { tableDisplayClassNames } from "../../const"
diff --git a/packages/react/src/ui/value-display/types/person/person.tsx b/packages/react/src/ui/value-display/types/person/person.tsx
index 0684da1dd1..f2d937a859 100644
--- a/packages/react/src/ui/value-display/types/person/person.tsx
+++ b/packages/react/src/ui/value-display/types/person/person.tsx
@@ -3,7 +3,7 @@
* Shows full name alongside a person avatar with optional badge.
*/
import { F0Avatar } from "@/components/avatars/F0Avatar"
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import { tableDisplayClassNames } from "../../const"
diff --git a/packages/react/src/ui/value-display/types/text/text.tsx b/packages/react/src/ui/value-display/types/text/text.tsx
index 3c9337243b..d0d92f754a 100644
--- a/packages/react/src/ui/value-display/types/text/text.tsx
+++ b/packages/react/src/ui/value-display/types/text/text.tsx
@@ -2,7 +2,7 @@
* Text cell type for displaying text or number values in data collections.
* Supports both direct values and objects with placeholder states.
*/
-import { OneEllipsis } from "@/lib/OneEllipsis"
+import { OneEllipsis } from "@/lib/OneEllipsis/PlainEllipsis"
import { cn } from "@/lib/utils"
import { tableDisplayClassNames } from "../../const"
diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts
index 8c28073e59..b3bcd4bc2e 100644
--- a/packages/react/vite.config.ts
+++ b/packages/react/vite.config.ts
@@ -29,6 +29,11 @@ const isBareRuntimeImport = (id: string) =>
!id.includes("?") &&
!id.startsWith("\0")
+const isPreservedEsmExternal = (id: string, importer?: string) =>
+ isBareRuntimeImport(id) &&
+ !id.startsWith("@atlaskit/pragmatic-drag-and-drop") &&
+ !importer?.includes("/node_modules/")
+
// Add tailwind build
const buildTailwind = process.argv.find((arg) => arg.startsWith("--tailwind"))
if (buildTailwind) {
@@ -176,10 +181,13 @@ export default defineConfig({
copyPublicDir: false,
rollupOptions: {
external: buildPreservedEsm
- ? isBareRuntimeImport
+ ? isPreservedEsmExternal
: [/@copilotkit\/.*/, /@livekit\/.*/, "livekit-client"],
// Workaround to fix rebuild https://github.com/vitejs/vite/issues/19410#issuecomment-2661835482
output: {
+ assetFileNames: buildPreservedEsm
+ ? "_embedded/[hash][extname]"
+ : undefined,
entryFileNames: buildPreservedEsm
? (chunkInfo) =>
chunkInfo.name.includes("node_modules/")