@neo4j-ndl/react 4.17.0 → 4.18.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.
Files changed (90) hide show
  1. package/lib/cjs/ai/chat-title/ChatTitle.js +43 -0
  2. package/lib/cjs/ai/chat-title/ChatTitle.js.map +1 -0
  3. package/lib/cjs/ai/chat-title/index.js +38 -0
  4. package/lib/cjs/ai/chat-title/index.js.map +1 -0
  5. package/lib/cjs/ai/chat-title/stories/chat-title-default.story.js +30 -0
  6. package/lib/cjs/ai/chat-title/stories/chat-title-default.story.js.map +1 -0
  7. package/lib/cjs/ai/chat-title/stories/index.js +32 -0
  8. package/lib/cjs/ai/chat-title/stories/index.js.map +1 -0
  9. package/lib/cjs/ai/index.js +3 -1
  10. package/lib/cjs/ai/index.js.map +1 -1
  11. package/lib/cjs/ai/response/stories/response-full-example.story.js +4 -4
  12. package/lib/cjs/ai/response/stories/response-full-example.story.js.map +1 -1
  13. package/lib/cjs/data-grid/stories/datagrid-search-and-filters.stories.js +3 -4
  14. package/lib/cjs/data-grid/stories/datagrid-search-and-filters.stories.js.map +1 -1
  15. package/lib/cjs/drawer/Drawer.js.map +1 -1
  16. package/lib/cjs/hooks/use-debounce-callback/index.js.map +1 -1
  17. package/lib/cjs/next/tree-view/TreeView.js.map +1 -1
  18. package/lib/cjs/popover/Popover.js.map +1 -1
  19. package/lib/cjs/popover/use-popover.js.map +1 -1
  20. package/lib/cjs/slider/Slider.js.map +1 -1
  21. package/lib/cjs/spotlight/SpotlightTarget.js.map +1 -1
  22. package/lib/cjs/spotlight/use-spotlight.js.map +1 -1
  23. package/lib/cjs/text-input/TextInput.js.map +1 -1
  24. package/lib/cjs/text-overflow/TextOverflow.js +1 -1
  25. package/lib/cjs/text-overflow/TextOverflow.js.map +1 -1
  26. package/lib/cjs/text-overflow/text-overflow-utils.js +3 -3
  27. package/lib/cjs/text-overflow/text-overflow-utils.js.map +1 -1
  28. package/lib/cjs/text-overflow/use-truncate-with-button.js +2 -2
  29. package/lib/cjs/text-overflow/use-truncate-with-button.js.map +1 -1
  30. package/lib/cjs/tooltip/Tooltip.js.map +1 -1
  31. package/lib/cjs/tooltip/use-tooltip.js.map +1 -1
  32. package/lib/cjs/tree-view/TreeViewItem.js.map +1 -1
  33. package/lib/esm/ai/chat-title/ChatTitle.js +39 -0
  34. package/lib/esm/ai/chat-title/ChatTitle.js.map +1 -0
  35. package/lib/esm/ai/chat-title/index.js +22 -0
  36. package/lib/esm/ai/chat-title/index.js.map +1 -0
  37. package/lib/esm/ai/chat-title/stories/chat-title-default.story.js +28 -0
  38. package/lib/esm/ai/chat-title/stories/chat-title-default.story.js.map +1 -0
  39. package/lib/esm/ai/chat-title/stories/index.js +25 -0
  40. package/lib/esm/ai/chat-title/stories/index.js.map +1 -0
  41. package/lib/esm/ai/index.js +1 -0
  42. package/lib/esm/ai/index.js.map +1 -1
  43. package/lib/esm/ai/response/stories/response-full-example.story.js +4 -4
  44. package/lib/esm/ai/response/stories/response-full-example.story.js.map +1 -1
  45. package/lib/esm/data-grid/stories/datagrid-search-and-filters.stories.js +3 -4
  46. package/lib/esm/data-grid/stories/datagrid-search-and-filters.stories.js.map +1 -1
  47. package/lib/esm/drawer/Drawer.js.map +1 -1
  48. package/lib/esm/hooks/use-debounce-callback/index.js.map +1 -1
  49. package/lib/esm/next/tree-view/TreeView.js.map +1 -1
  50. package/lib/esm/popover/Popover.js.map +1 -1
  51. package/lib/esm/popover/use-popover.js.map +1 -1
  52. package/lib/esm/slider/Slider.js.map +1 -1
  53. package/lib/esm/spotlight/SpotlightTarget.js.map +1 -1
  54. package/lib/esm/spotlight/use-spotlight.js.map +1 -1
  55. package/lib/esm/text-input/TextInput.js.map +1 -1
  56. package/lib/esm/text-overflow/TextOverflow.js +1 -1
  57. package/lib/esm/text-overflow/TextOverflow.js.map +1 -1
  58. package/lib/esm/text-overflow/text-overflow-utils.js +3 -3
  59. package/lib/esm/text-overflow/text-overflow-utils.js.map +1 -1
  60. package/lib/esm/text-overflow/use-truncate-with-button.js +2 -2
  61. package/lib/esm/text-overflow/use-truncate-with-button.js.map +1 -1
  62. package/lib/esm/tooltip/Tooltip.js.map +1 -1
  63. package/lib/esm/tooltip/use-tooltip.js.map +1 -1
  64. package/lib/esm/tree-view/TreeViewItem.js.map +1 -1
  65. package/lib/types/ai/chat-title/ChatTitle.d.ts +27 -0
  66. package/lib/types/ai/chat-title/ChatTitle.d.ts.map +1 -0
  67. package/lib/types/ai/chat-title/index.d.ts +22 -0
  68. package/lib/types/ai/chat-title/index.d.ts.map +1 -0
  69. package/lib/types/ai/chat-title/stories/chat-title-default.story.d.ts +24 -0
  70. package/lib/types/ai/chat-title/stories/chat-title-default.story.d.ts.map +1 -0
  71. package/lib/types/ai/chat-title/stories/index.d.ts +23 -0
  72. package/lib/types/ai/chat-title/stories/index.d.ts.map +1 -0
  73. package/lib/types/ai/index.d.ts +1 -0
  74. package/lib/types/ai/index.d.ts.map +1 -1
  75. package/lib/types/data-grid/stories/datagrid-search-and-filters.stories.d.ts.map +1 -1
  76. package/lib/types/drawer/Drawer.d.ts.map +1 -1
  77. package/lib/types/hooks/use-debounce-callback/index.d.ts.map +1 -1
  78. package/lib/types/next/tree-view/TreeView.d.ts.map +1 -1
  79. package/lib/types/popover/Popover.d.ts.map +1 -1
  80. package/lib/types/popover/use-popover.d.ts.map +1 -1
  81. package/lib/types/slider/Slider.d.ts.map +1 -1
  82. package/lib/types/spotlight/SpotlightTarget.d.ts.map +1 -1
  83. package/lib/types/spotlight/use-spotlight.d.ts.map +1 -1
  84. package/lib/types/text-input/TextInput.d.ts.map +1 -1
  85. package/lib/types/text-overflow/text-overflow-utils.d.ts +1 -1
  86. package/lib/types/text-overflow/text-overflow-utils.d.ts.map +1 -1
  87. package/lib/types/tooltip/Tooltip.d.ts.map +1 -1
  88. package/lib/types/tooltip/use-tooltip.d.ts.map +1 -1
  89. package/lib/types/tree-view/TreeViewItem.d.ts.map +1 -1
  90. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/slider/Slider.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport React, { useCallback, useEffect } from 'react';\nimport {\n mergeProps,\n useFocusRing,\n useSlider,\n useSliderThumb,\n VisuallyHidden,\n} from 'react-aria';\nimport { type SliderState, useSliderState } from 'react-stately';\n\nimport {\n type HtmlAttributes,\n type PolymorphicCommonProps,\n} from '../_common/types';\nimport { Tooltip } from '../tooltip';\n\ntype SliderPropsBase = {\n /** Input props of the underlying input element */\n inputProps?: HtmlAttributes<'input'>;\n /** Determines the step size that will be added or removed from the current value when moving the slider button */\n step?: number;\n /** Whether the slider is disabled */\n isDisabled?: boolean;\n /** The minimum value possible to choose */\n minValue?: number;\n /** The maximum value possible to choose */\n maxValue?: number;\n /** Whether to display a tooltip with the current value when the slider is being dragged */\n showValues?: boolean;\n /** Whether to display visual indicators for each step in the slider */\n showSteps?: boolean;\n};\n\ntype SingleSlider = SliderPropsBase & {\n /** Type of the slider */\n type?: 'single';\n /** Current value of the single slider. **Only required when the type is 'single'**. */\n value: number;\n /** Callback function triggered when the slider value(s) changes. The function parameter varies depending on the slider type, for single slider, it is a number and for range slider, it is an array of two numbers. */\n onChange: (value: number) => void;\n};\n\ntype RangeSlider = SliderPropsBase & {\n /** Type of the slider */\n type: 'range';\n /** Current values of the range slider as an array of two numbers `[min, max]`. **Only required when the type is 'range'**.*/\n values: [number, number];\n /** Callback function triggered when the slider value(s) changes. The function parameter varies depending on the slider type, for single slider, it is a number and for range slider, it is an array of two numbers. */\n onChange: (value: [number, number]) => void;\n};\n\n/**\n * @remarks\n * The `type` prop is used to determine the type of the slider. It can be `single` or `range`. The `value` prop is required when the `type` is `single` and `values` is required when the `type` is `range`. It also affects the `onChange` prop type.\n */\ntype SliderProps = SingleSlider | RangeSlider;\n\nexport const Slider = <T extends React.ElementType = 'div'>({\n as,\n inputProps = {},\n className,\n style,\n minValue = 0,\n maxValue = 100,\n isDisabled = false,\n showSteps = false,\n showValues = false,\n step = 1,\n type = 'single',\n onChange,\n htmlAttributes,\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, SliderProps>) => {\n const trackRef = React.useRef<HTMLDivElement | null>(null);\n\n const castedValue =\n type === 'range'\n ? (restProps as RangeSlider).values\n : (restProps as SingleSlider).value;\n\n const castedOnChange =\n type === 'range'\n ? (onChange as RangeSlider['onChange'])\n : (onChange as SingleSlider['onChange']);\n\n const state = useSliderState<typeof castedValue>({\n defaultValue: castedValue,\n isDisabled,\n maxValue,\n minValue,\n numberFormatter: new Intl.NumberFormat('en-US'),\n // oxlint-disable-next-line no-explicit-any\n onChange: castedOnChange as any,\n step,\n });\n\n const { setThumbValue } = state;\n\n const { groupProps, trackProps } = useSlider(\n { 'aria-label': 'slider' },\n state,\n trackRef,\n );\n\n const updatesSliderValue = useCallback(\n (newValue: number | [number, number]) => {\n if (type === 'single' && typeof newValue === 'number') {\n setThumbValue(0, newValue);\n } else if (type === 'range' && Array.isArray(newValue)) {\n setThumbValue(0, newValue[0]);\n setThumbValue(1, newValue[1]);\n }\n },\n [type, setThumbValue],\n );\n\n useEffect(() => {\n updatesSliderValue(castedValue);\n // Needed to make the slider work with controlled values\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [castedValue]);\n\n const Component: React.ElementType = as ?? 'div';\n\n return (\n <Component\n className={classNames('ndl-slider', className)}\n style={style}\n role=\"presentation\"\n ref={ref}\n {...groupProps}\n {...restProps}\n {...htmlAttributes}\n >\n {/* The track element holds the visible track line, the filled track line and the thumb. */}\n <div\n {...trackProps}\n ref={trackRef as React.RefObject<HTMLDivElement>}\n className={classNames('ndl-track', {\n 'ndl-is-disabled': state.isDisabled,\n })}\n >\n {/* Circular marks, acting as indicators for the steps */}\n {showSteps && (\n <TrackMarks state={state} min={minValue} max={maxValue} />\n )}\n <FilledTrack state={state} />\n <Thumb\n index={0}\n state={state}\n trackRef={trackRef as React.RefObject<HTMLDivElement>}\n showValues={showValues}\n inputForwardedProps={inputProps}\n />\n {type === 'range' && (\n <Thumb\n index={1}\n state={state}\n trackRef={trackRef as React.RefObject<HTMLDivElement>}\n showValues={showValues}\n inputForwardedProps={inputProps}\n />\n )}\n </div>\n </Component>\n );\n};\n\nSlider.displayName = 'Slider';\n\nfunction FilledTrack({ state }: { state: SliderState }) {\n let width: number;\n let left: number;\n if (state.values.length === 1) {\n width = state.getValuePercent(state.values[0]) * 100;\n left = 0;\n } else {\n width =\n state.getValuePercent(state.values[1]) * 100 -\n state.getValuePercent(state.values[0]) * 100;\n left = state.getValuePercent(state.values[0]) * 100;\n }\n\n return (\n <div\n className=\"ndl-filled-track\"\n style={{\n left: `${left}%`,\n width: `${width}%`,\n }}\n />\n );\n}\n\nfunction TrackMarks({\n state,\n max,\n min,\n}: {\n state: SliderState;\n max: number;\n min: number;\n}) {\n const markNo = Math.round((max - min) / state.step);\n\n return (\n <div role=\"presentation\" className=\"ndl-track-marks\">\n {Array.from({ length: markNo - 1 }).map((_, index) => {\n const percent = (index / markNo) * 100;\n\n let isFilled;\n if (state.values.length === 1) {\n isFilled = state.getValuePercent(state.values[0]) * 100 > percent;\n } else {\n isFilled =\n state.getValuePercent(state.values[0]) * 100 < percent &&\n state.getValuePercent(state.values[1]) * 100 > percent;\n }\n\n return (\n <div\n key={`track-mark-${index}`}\n className={classNames('ndl-track-mark', {\n 'ndl-on-active-track': isFilled,\n })}\n style={{\n left: `${((index + 1) / markNo) * 100}%`,\n }}\n />\n );\n })}\n </div>\n );\n}\n\nfunction Thumb(props: {\n index: number;\n state: SliderState;\n showValues?: boolean;\n trackRef: React.RefObject<HTMLDivElement>;\n inputForwardedProps: HtmlAttributes<'input'>;\n}) {\n const { state, trackRef, index, inputForwardedProps } = props;\n const inputRef = React.useRef(null);\n const { thumbProps, inputProps, isDragging } = useSliderThumb(\n {\n index,\n inputRef,\n name: 'slider-thumb',\n trackRef,\n },\n state,\n );\n\n const { focusProps, isFocusVisible } = useFocusRing();\n\n /**\n * Solve issue with:\n * Warning: Received NaN for the `value` attribute. If this is expected, cast the value to a string.\n * Receiving NaN for other attributes also, like `max`. Waiting for a fix in react-aria.\n * @see https://github.com/adobe/react-spectrum/issues/5859\n * @see https://github.com/adobe/react-spectrum/pull/5861\n */\n const mergedProps = mergeProps(\n inputProps,\n focusProps,\n // Omitting aria-valuetext double announcements, unless explicitly provided\n { 'aria-valuetext': '' },\n inputForwardedProps,\n );\n const value =\n mergedProps.value !== undefined || mergedProps.value === 0\n ? mergedProps.value\n : '';\n\n return (\n <Tooltip\n isDisabled={props.showValues !== true}\n isOpen={isDragging || undefined}\n placement=\"top\"\n type=\"simple\"\n >\n <Tooltip.Trigger hasButtonWrapper>\n <div\n {...thumbProps}\n className={classNames('ndl-thumb', {\n 'ndl-focus': isFocusVisible,\n 'ndl-is-dragging': isDragging,\n })}\n >\n <VisuallyHidden>\n <input ref={inputRef} {...mergedProps} />\n </VisuallyHidden>\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content>{value}</Tooltip.Content>\n </Tooltip>\n );\n}\n"]}
1
+ {"version":3,"file":"Slider.js","sourceRoot":"","sources":["../../../src/slider/Slider.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport React, { useCallback, useEffect } from 'react';\nimport {\n mergeProps,\n useFocusRing,\n useSlider,\n useSliderThumb,\n VisuallyHidden,\n} from 'react-aria';\nimport { type SliderState, useSliderState } from 'react-stately';\n\nimport {\n type HtmlAttributes,\n type PolymorphicCommonProps,\n} from '../_common/types';\nimport { Tooltip } from '../tooltip';\n\ntype SliderPropsBase = {\n /** Input props of the underlying input element */\n inputProps?: HtmlAttributes<'input'>;\n /** Determines the step size that will be added or removed from the current value when moving the slider button */\n step?: number;\n /** Whether the slider is disabled */\n isDisabled?: boolean;\n /** The minimum value possible to choose */\n minValue?: number;\n /** The maximum value possible to choose */\n maxValue?: number;\n /** Whether to display a tooltip with the current value when the slider is being dragged */\n // TODO v5: decide if this naming is okay, or change it\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showValues?: boolean;\n /** Whether to display visual indicators for each step in the slider */\n // TODO v5: decide if this naming is okay, or change it\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showSteps?: boolean;\n};\n\ntype SingleSlider = SliderPropsBase & {\n /** Type of the slider */\n type?: 'single';\n /** Current value of the single slider. **Only required when the type is 'single'**. */\n value: number;\n /** Callback function triggered when the slider value(s) changes. The function parameter varies depending on the slider type, for single slider, it is a number and for range slider, it is an array of two numbers. */\n onChange: (value: number) => void;\n};\n\ntype RangeSlider = SliderPropsBase & {\n /** Type of the slider */\n type: 'range';\n /** Current values of the range slider as an array of two numbers `[min, max]`. **Only required when the type is 'range'**.*/\n values: [number, number];\n /** Callback function triggered when the slider value(s) changes. The function parameter varies depending on the slider type, for single slider, it is a number and for range slider, it is an array of two numbers. */\n onChange: (value: [number, number]) => void;\n};\n\n/**\n * @remarks\n * The `type` prop is used to determine the type of the slider. It can be `single` or `range`. The `value` prop is required when the `type` is `single` and `values` is required when the `type` is `range`. It also affects the `onChange` prop type.\n */\ntype SliderProps = SingleSlider | RangeSlider;\n\nexport const Slider = <T extends React.ElementType = 'div'>({\n as,\n inputProps = {},\n className,\n style,\n minValue = 0,\n maxValue = 100,\n isDisabled = false,\n showSteps = false,\n showValues = false,\n step = 1,\n type = 'single',\n onChange,\n htmlAttributes,\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, SliderProps>) => {\n const trackRef = React.useRef<HTMLDivElement | null>(null);\n\n const castedValue =\n type === 'range'\n ? (restProps as RangeSlider).values\n : (restProps as SingleSlider).value;\n\n const castedOnChange =\n type === 'range'\n ? (onChange as RangeSlider['onChange'])\n : (onChange as SingleSlider['onChange']);\n\n const state = useSliderState<typeof castedValue>({\n defaultValue: castedValue,\n isDisabled,\n maxValue,\n minValue,\n numberFormatter: new Intl.NumberFormat('en-US'),\n // oxlint-disable-next-line no-explicit-any\n onChange: castedOnChange as any,\n step,\n });\n\n const { setThumbValue } = state;\n\n const { groupProps, trackProps } = useSlider(\n { 'aria-label': 'slider' },\n state,\n trackRef,\n );\n\n const updatesSliderValue = useCallback(\n (newValue: number | [number, number]) => {\n if (type === 'single' && typeof newValue === 'number') {\n setThumbValue(0, newValue);\n } else if (type === 'range' && Array.isArray(newValue)) {\n setThumbValue(0, newValue[0]);\n setThumbValue(1, newValue[1]);\n }\n },\n [type, setThumbValue],\n );\n\n useEffect(() => {\n updatesSliderValue(castedValue);\n // Needed to make the slider work with controlled values\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [castedValue]);\n\n const Component: React.ElementType = as ?? 'div';\n\n return (\n <Component\n className={classNames('ndl-slider', className)}\n style={style}\n role=\"presentation\"\n ref={ref}\n {...groupProps}\n {...restProps}\n {...htmlAttributes}\n >\n {/* The track element holds the visible track line, the filled track line and the thumb. */}\n <div\n {...trackProps}\n ref={trackRef as React.RefObject<HTMLDivElement>}\n className={classNames('ndl-track', {\n 'ndl-is-disabled': state.isDisabled,\n })}\n >\n {/* Circular marks, acting as indicators for the steps */}\n {showSteps && (\n <TrackMarks state={state} min={minValue} max={maxValue} />\n )}\n <FilledTrack state={state} />\n <Thumb\n index={0}\n state={state}\n trackRef={trackRef as React.RefObject<HTMLDivElement>}\n showValues={showValues}\n inputForwardedProps={inputProps}\n />\n {type === 'range' && (\n <Thumb\n index={1}\n state={state}\n trackRef={trackRef as React.RefObject<HTMLDivElement>}\n showValues={showValues}\n inputForwardedProps={inputProps}\n />\n )}\n </div>\n </Component>\n );\n};\n\nSlider.displayName = 'Slider';\n\nfunction FilledTrack({ state }: { state: SliderState }) {\n let width: number;\n let left: number;\n if (state.values.length === 1) {\n width = state.getValuePercent(state.values[0]) * 100;\n left = 0;\n } else {\n width =\n state.getValuePercent(state.values[1]) * 100 -\n state.getValuePercent(state.values[0]) * 100;\n left = state.getValuePercent(state.values[0]) * 100;\n }\n\n return (\n <div\n className=\"ndl-filled-track\"\n style={{\n left: `${left}%`,\n width: `${width}%`,\n }}\n />\n );\n}\n\nfunction TrackMarks({\n state,\n max,\n min,\n}: {\n state: SliderState;\n max: number;\n min: number;\n}) {\n const markNo = Math.round((max - min) / state.step);\n\n return (\n <div role=\"presentation\" className=\"ndl-track-marks\">\n {Array.from({ length: markNo - 1 }).map((_, index) => {\n const percent = (index / markNo) * 100;\n\n let isFilled;\n if (state.values.length === 1) {\n isFilled = state.getValuePercent(state.values[0]) * 100 > percent;\n } else {\n isFilled =\n state.getValuePercent(state.values[0]) * 100 < percent &&\n state.getValuePercent(state.values[1]) * 100 > percent;\n }\n\n return (\n <div\n key={`track-mark-${index}`}\n className={classNames('ndl-track-mark', {\n 'ndl-on-active-track': isFilled,\n })}\n style={{\n left: `${((index + 1) / markNo) * 100}%`,\n }}\n />\n );\n })}\n </div>\n );\n}\n\nfunction Thumb(props: {\n index: number;\n state: SliderState;\n // TODO v5: decide if this naming is okay, or change it\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showValues?: boolean;\n trackRef: React.RefObject<HTMLDivElement>;\n inputForwardedProps: HtmlAttributes<'input'>;\n}) {\n const { state, trackRef, index, inputForwardedProps } = props;\n const inputRef = React.useRef(null);\n const { thumbProps, inputProps, isDragging } = useSliderThumb(\n {\n index,\n inputRef,\n name: 'slider-thumb',\n trackRef,\n },\n state,\n );\n\n const { focusProps, isFocusVisible } = useFocusRing();\n\n /**\n * Solve issue with:\n * Warning: Received NaN for the `value` attribute. If this is expected, cast the value to a string.\n * Receiving NaN for other attributes also, like `max`. Waiting for a fix in react-aria.\n * @see https://github.com/adobe/react-spectrum/issues/5859\n * @see https://github.com/adobe/react-spectrum/pull/5861\n */\n const mergedProps = mergeProps(\n inputProps,\n focusProps,\n // Omitting aria-valuetext double announcements, unless explicitly provided\n { 'aria-valuetext': '' },\n inputForwardedProps,\n );\n const value =\n mergedProps.value !== undefined || mergedProps.value === 0\n ? mergedProps.value\n : '';\n\n return (\n <Tooltip\n isDisabled={props.showValues !== true}\n isOpen={isDragging || undefined}\n placement=\"top\"\n type=\"simple\"\n >\n <Tooltip.Trigger hasButtonWrapper>\n <div\n {...thumbProps}\n className={classNames('ndl-thumb', {\n 'ndl-focus': isFocusVisible,\n 'ndl-is-dragging': isDragging,\n })}\n >\n <VisuallyHidden>\n <input ref={inputRef} {...mergedProps} />\n </VisuallyHidden>\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content>{value}</Tooltip.Content>\n </Tooltip>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"SpotlightTarget.js","sourceRoot":"","sources":["../../../src/spotlight/SpotlightTarget.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { FloatingPortal, useMergeRefs } from '@floating-ui/react';\nimport classNames from 'classnames';\nimport React, { useEffect } from 'react';\n\nimport { type PolymorphicCommonProps } from '../_common/types';\nimport { ConditionalWrap } from '../conditional-wrap';\nimport { useSpotlightContext } from './SpotlightProvider';\nimport {\n type IndicatorPlacement,\n type IndicatorVariant,\n useIndicator,\n} from './use-indicator';\n\ntype SpotlightTargetProps = {\n /** The id of the wrapper. This should match a `target` prop in a `Spotlight`, to indicate that this is where it should be rendered when open */\n id: string;\n /** A boolean that controls if the pulse animation should be used or not */\n hasPulse?: boolean;\n /** A string that controls the style of the indicator. It can be either \"point\" or \"border\" */\n indicatorVariant?: IndicatorVariant;\n /** A string that controls the placement of the indicator. A combination of \"middle\", \"top\", \"right\", \"bottom\" and \"left\" separated by a dash, e.g. \"top-right\" */\n indicatorPlacement?: IndicatorPlacement;\n /** An inline style CSS property to control the border radius of the wrapper */\n borderRadius?: React.CSSProperties['borderRadius'];\n /** The content to wrap */\n children?: React.ReactNode;\n /** Fit the target size to the children. */\n shouldFitToChildren?: boolean;\n /**\n * When true, merges the spotlight target props directly with the child element instead of wrapping it in a div.\n *\n * This is useful for applying spotlight functionality to existing interactive elements (buttons, links, etc.)\n * while preserving their original behavior, styling, and accessibility attributes.\n *\n * @example\n * ```tsx\n * <SpotlightTarget id=\"my-button\" asChild>\n * <FilledButton>Click me</FilledButton>\n * </SpotlightTarget>\n * ```\n *\n * @warning Only use with interactive elements that can receive focus and handle click events\n * @warning The child element's `id` will be overridden with the target's `id`\n */\n asChild?: boolean;\n};\n\nexport const SpotlightTarget = ({\n id,\n hasPulse = true,\n indicatorVariant = 'border',\n indicatorPlacement = 'top-right',\n borderRadius,\n shouldFitToChildren = false,\n children,\n className,\n htmlAttributes,\n style,\n as,\n ref,\n asChild,\n ...restProps\n}: PolymorphicCommonProps<'div', SpotlightTargetProps>) => {\n const Component = as ?? 'div';\n\n const {\n isActiveSpotlight,\n isOpen,\n setIsOpen,\n registerTarget,\n unregisterTarget,\n setActiveSpotlight,\n } = useSpotlightContext();\n\n const internalRef = React.useRef<HTMLElement>(null);\n const childRef =\n asChild && React.isValidElement(children)\n ? (\n children as React.ReactElement<unknown> & {\n ref?: React.Ref<HTMLElement>;\n }\n ).ref\n : undefined;\n const mergedRefs = useMergeRefs<HTMLElement>([\n ref as React.RefObject<HTMLElement>,\n internalRef as React.RefObject<HTMLElement>,\n childRef as React.Ref<HTMLElement> | undefined,\n ]);\n useEffect(() => {\n if (internalRef.current !== null) {\n registerTarget(id, internalRef as React.RefObject<HTMLElement>);\n }\n return () => unregisterTarget(id);\n }, [id, registerTarget, unregisterTarget]);\n\n const isActive = isActiveSpotlight(id);\n const indicator = useIndicator({\n hasPulse,\n indicatorPlacement,\n indicatorVariant,\n isOpen: isActive,\n targetRef: internalRef,\n });\n\n if (asChild === true && React.isValidElement(children)) {\n const child = children as React.ReactElement<{\n className?: string;\n style?: React.CSSProperties;\n onClick?: (e: React.MouseEvent<HTMLElement>) => void;\n onKeyDown?: (e: React.KeyboardEvent<HTMLElement>) => void;\n }>;\n\n const onClick = (e: React.MouseEvent<HTMLElement>) => {\n if (isActive) {\n // When spotlight is active, always prevent the child's click handler\n e.preventDefault();\n\n if (!isOpen) {\n setIsOpen(true);\n }\n // Don't call child.props?.onClick when spotlight is active\n return;\n }\n\n // Only call the child's click handler when spotlight is not active\n child.props?.onClick?.(e);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n if (isActive && !isOpen && (e.code === 'Enter' || e.code === 'Space')) {\n e.preventDefault();\n setIsOpen(true);\n return;\n }\n\n if (isActive && e.code === 'Escape') {\n e.preventDefault();\n setActiveSpotlight(null);\n return;\n }\n\n child.props?.onKeyDown?.(e);\n };\n\n // IMPORTANT: do NOT force role/tabIndex here; preserves Composite semantics for the SideNavigation\n const mergedProps = {\n id,\n onClick,\n onKeyDown,\n ref: mergedRefs,\n style: {\n ...style,\n ...child.props.style,\n },\n // Avoid overriding the child's own role/tabIndex with any passed htmlAttributes\n ...(htmlAttributes\n ? { ...htmlAttributes, role: undefined, tabIndex: undefined }\n : {}),\n };\n\n return (\n <>\n {React.cloneElement(child, mergedProps as Record<string, unknown>)}\n <ConditionalWrap\n shouldWrap={isActive && isOpen}\n wrap={(wrapChildren) => (\n <FloatingPortal>{wrapChildren}</FloatingPortal>\n )}\n >\n {indicator.context.open && (\n <div\n className={indicator.indicatorClasses}\n ref={indicator.context.refs.setFloating}\n style={{ ...indicator.floatingStyles, ...indicator.style }}\n />\n )}\n </ConditionalWrap>\n </>\n );\n }\n\n const classes = classNames(\n 'ndl-spotlight-target',\n {\n 'ndl-spotlight-target-fit-to-children': shouldFitToChildren,\n 'ndl-spotlight-target-open': isOpen && isActive,\n },\n className,\n );\n\n const inertClasses = classNames(\n 'ndl-spotlight-target-inert',\n {\n 'ndl-spotlight-target-inert-fit-to-children': shouldFitToChildren,\n },\n className,\n );\n\n return (\n <>\n <Component\n role={isActive ? 'button' : undefined}\n id={id}\n ref={mergedRefs}\n className={classes}\n onClick={(e) => {\n if (isActive) {\n e.preventDefault();\n e.stopPropagation();\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }\n }}\n style={{ borderRadius, ...style }}\n onKeyDown={(e) => {\n if (\n isActive &&\n !isOpen &&\n (e.code === 'Enter' || e.code === 'Space')\n ) {\n setIsOpen(true);\n e.preventDefault();\n } else if (e.code === 'Escape' && isActive) {\n setActiveSpotlight(null);\n }\n }}\n tabIndex={isActive ? 0 : undefined}\n {...(isActive && { 'aria-label': 'Open spotlight' })}\n {...restProps}\n {...htmlAttributes}\n >\n <ConditionalWrap\n shouldWrap={isActive}\n wrap={(children) => (\n <div inert aria-disabled className={inertClasses}>\n {children}\n </div>\n )}\n >\n {children}\n </ConditionalWrap>\n </Component>\n <ConditionalWrap\n shouldWrap={isActive && isOpen}\n wrap={(wrapChildren) => <FloatingPortal>{wrapChildren}</FloatingPortal>}\n >\n {indicator.context.open && (\n <div\n className={indicator.indicatorClasses}\n ref={indicator.context.refs.setFloating}\n style={{ ...indicator.floatingStyles, ...indicator.style }}\n />\n )}\n </ConditionalWrap>\n </>\n );\n};\n"]}
1
+ {"version":3,"file":"SpotlightTarget.js","sourceRoot":"","sources":["../../../src/spotlight/SpotlightTarget.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport { FloatingPortal, useMergeRefs } from '@floating-ui/react';\nimport classNames from 'classnames';\nimport React, { useEffect } from 'react';\n\nimport { type PolymorphicCommonProps } from '../_common/types';\nimport { ConditionalWrap } from '../conditional-wrap';\nimport { useSpotlightContext } from './SpotlightProvider';\nimport {\n type IndicatorPlacement,\n type IndicatorVariant,\n useIndicator,\n} from './use-indicator';\n\ntype SpotlightTargetProps = {\n /** The id of the wrapper. This should match a `target` prop in a `Spotlight`, to indicate that this is where it should be rendered when open */\n id: string;\n /** A boolean that controls if the pulse animation should be used or not */\n hasPulse?: boolean;\n /** A string that controls the style of the indicator. It can be either \"point\" or \"border\" */\n indicatorVariant?: IndicatorVariant;\n /** A string that controls the placement of the indicator. A combination of \"middle\", \"top\", \"right\", \"bottom\" and \"left\" separated by a dash, e.g. \"top-right\" */\n indicatorPlacement?: IndicatorPlacement;\n /** An inline style CSS property to control the border radius of the wrapper */\n borderRadius?: React.CSSProperties['borderRadius'];\n /** The content to wrap */\n children?: React.ReactNode;\n /** Fit the target size to the children. */\n shouldFitToChildren?: boolean;\n /**\n * When true, merges the spotlight target props directly with the child element instead of wrapping it in a div.\n *\n * This is useful for applying spotlight functionality to existing interactive elements (buttons, links, etc.)\n * while preserving their original behavior, styling, and accessibility attributes.\n *\n * @example\n * ```tsx\n * <SpotlightTarget id=\"my-button\" asChild>\n * <FilledButton>Click me</FilledButton>\n * </SpotlightTarget>\n * ```\n *\n * @warning Only use with interactive elements that can receive focus and handle click events\n * @warning The child element's `id` will be overridden with the target's `id`\n */\n // TODO v5: decide if this naming is okay, don't see how to follow the rule without a name that is tooo long\n // eslint-disable-next-line @typescript-eslint/naming-convention\n asChild?: boolean;\n};\n\nexport const SpotlightTarget = ({\n id,\n hasPulse = true,\n indicatorVariant = 'border',\n indicatorPlacement = 'top-right',\n borderRadius,\n shouldFitToChildren = false,\n children,\n className,\n htmlAttributes,\n style,\n as,\n ref,\n asChild,\n ...restProps\n}: PolymorphicCommonProps<'div', SpotlightTargetProps>) => {\n const Component = as ?? 'div';\n\n const {\n isActiveSpotlight,\n isOpen,\n setIsOpen,\n registerTarget,\n unregisterTarget,\n setActiveSpotlight,\n } = useSpotlightContext();\n\n const internalRef = React.useRef<HTMLElement>(null);\n const childRef =\n asChild && React.isValidElement(children)\n ? (\n children as React.ReactElement<unknown> & {\n ref?: React.Ref<HTMLElement>;\n }\n ).ref\n : undefined;\n const mergedRefs = useMergeRefs<HTMLElement>([\n ref as React.RefObject<HTMLElement>,\n internalRef as React.RefObject<HTMLElement>,\n childRef as React.Ref<HTMLElement> | undefined,\n ]);\n useEffect(() => {\n if (internalRef.current !== null) {\n registerTarget(id, internalRef as React.RefObject<HTMLElement>);\n }\n return () => unregisterTarget(id);\n }, [id, registerTarget, unregisterTarget]);\n\n const isActive = isActiveSpotlight(id);\n const indicator = useIndicator({\n hasPulse,\n indicatorPlacement,\n indicatorVariant,\n isOpen: isActive,\n targetRef: internalRef,\n });\n\n if (asChild === true && React.isValidElement(children)) {\n const child = children as React.ReactElement<{\n className?: string;\n style?: React.CSSProperties;\n onClick?: (e: React.MouseEvent<HTMLElement>) => void;\n onKeyDown?: (e: React.KeyboardEvent<HTMLElement>) => void;\n }>;\n\n const onClick = (e: React.MouseEvent<HTMLElement>) => {\n if (isActive) {\n // When spotlight is active, always prevent the child's click handler\n e.preventDefault();\n\n if (!isOpen) {\n setIsOpen(true);\n }\n // Don't call child.props?.onClick when spotlight is active\n return;\n }\n\n // Only call the child's click handler when spotlight is not active\n child.props?.onClick?.(e);\n };\n\n const onKeyDown = (e: React.KeyboardEvent<HTMLElement>) => {\n if (isActive && !isOpen && (e.code === 'Enter' || e.code === 'Space')) {\n e.preventDefault();\n setIsOpen(true);\n return;\n }\n\n if (isActive && e.code === 'Escape') {\n e.preventDefault();\n setActiveSpotlight(null);\n return;\n }\n\n child.props?.onKeyDown?.(e);\n };\n\n // IMPORTANT: do NOT force role/tabIndex here; preserves Composite semantics for the SideNavigation\n const mergedProps = {\n id,\n onClick,\n onKeyDown,\n ref: mergedRefs,\n style: {\n ...style,\n ...child.props.style,\n },\n // Avoid overriding the child's own role/tabIndex with any passed htmlAttributes\n ...(htmlAttributes\n ? { ...htmlAttributes, role: undefined, tabIndex: undefined }\n : {}),\n };\n\n return (\n <>\n {React.cloneElement(child, mergedProps as Record<string, unknown>)}\n <ConditionalWrap\n shouldWrap={isActive && isOpen}\n wrap={(wrapChildren) => (\n <FloatingPortal>{wrapChildren}</FloatingPortal>\n )}\n >\n {indicator.context.open && (\n <div\n className={indicator.indicatorClasses}\n ref={indicator.context.refs.setFloating}\n style={{ ...indicator.floatingStyles, ...indicator.style }}\n />\n )}\n </ConditionalWrap>\n </>\n );\n }\n\n const classes = classNames(\n 'ndl-spotlight-target',\n {\n 'ndl-spotlight-target-fit-to-children': shouldFitToChildren,\n 'ndl-spotlight-target-open': isOpen && isActive,\n },\n className,\n );\n\n const inertClasses = classNames(\n 'ndl-spotlight-target-inert',\n {\n 'ndl-spotlight-target-inert-fit-to-children': shouldFitToChildren,\n },\n className,\n );\n\n return (\n <>\n <Component\n role={isActive ? 'button' : undefined}\n id={id}\n ref={mergedRefs}\n className={classes}\n onClick={(e) => {\n if (isActive) {\n e.preventDefault();\n e.stopPropagation();\n\n if (!isOpen) {\n setIsOpen(true);\n }\n }\n }}\n style={{ borderRadius, ...style }}\n onKeyDown={(e) => {\n if (\n isActive &&\n !isOpen &&\n (e.code === 'Enter' || e.code === 'Space')\n ) {\n setIsOpen(true);\n e.preventDefault();\n } else if (e.code === 'Escape' && isActive) {\n setActiveSpotlight(null);\n }\n }}\n tabIndex={isActive ? 0 : undefined}\n {...(isActive && { 'aria-label': 'Open spotlight' })}\n {...restProps}\n {...htmlAttributes}\n >\n <ConditionalWrap\n shouldWrap={isActive}\n wrap={(children) => (\n <div inert aria-disabled className={inertClasses}>\n {children}\n </div>\n )}\n >\n {children}\n </ConditionalWrap>\n </Component>\n <ConditionalWrap\n shouldWrap={isActive && isOpen}\n wrap={(wrapChildren) => <FloatingPortal>{wrapChildren}</FloatingPortal>}\n >\n {indicator.context.open && (\n <div\n className={indicator.indicatorClasses}\n ref={indicator.context.refs.setFloating}\n style={{ ...indicator.floatingStyles, ...indicator.style }}\n />\n )}\n </ConditionalWrap>\n </>\n );\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"use-spotlight.js","sourceRoot":"","sources":["../../../src/spotlight/use-spotlight.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n autoUpdate,\n flip,\n offset,\n type Placement,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useInteractions,\n type UseInteractionsReturn,\n useRole,\n useTransitionStyles,\n} from '@floating-ui/react';\nimport { tokens } from '@neo4j-ndl/base';\nimport { useMemo, useState } from 'react';\n\nexport interface SpotlightOptions {\n isInitialOpen?: boolean;\n placement?: Placement;\n isOpen?: boolean;\n onOpenChange?: (open: boolean, event?: Event) => void;\n anchorElement?: Element | null;\n anchorElementAsPortalAnchor?: boolean;\n initialFocus?: number | React.MutableRefObject<HTMLElement | null>;\n closeOnClickOutside?: boolean;\n strategy?: 'fixed' | 'absolute';\n}\n\nexport interface UseSpotlightReturn\n extends UseInteractionsReturn, ReturnType<typeof useFloating> {\n isOpen: boolean;\n setIsOpen: (isOpen: boolean) => void;\n labelId: string | undefined;\n transitionStyles: React.CSSProperties;\n anchorElementAsPortalAnchor: boolean | undefined;\n initialFocus: number | React.MutableRefObject<HTMLElement | null> | undefined;\n}\n\nexport function useSpotlight({\n isInitialOpen = false,\n placement = 'bottom',\n isOpen: controlledOpen,\n onOpenChange: setControlledOpen,\n anchorElement,\n anchorElementAsPortalAnchor,\n initialFocus,\n closeOnClickOutside,\n strategy = 'absolute',\n}: SpotlightOptions = {}): UseSpotlightReturn {\n const [isOpenUncontrolled, setIsOpenUncontrolled] = useState(isInitialOpen);\n const [labelId, setLabelId] = useState<string | undefined>();\n const [descriptionId, setDescriptionId] = useState<string | undefined>();\n const isOpen = controlledOpen ?? isOpenUncontrolled;\n const setIsOpen = setControlledOpen ?? setIsOpenUncontrolled;\n const data = useFloating({\n elements: {\n reference: anchorElement,\n },\n middleware: [\n offset(10),\n flip({\n crossAxis: placement.includes('-'),\n fallbackAxisSideDirection: 'end',\n padding: 5,\n }),\n shift({ padding: 5 }),\n ],\n onOpenChange: (open, event) => {\n setIsOpen(open);\n setControlledOpen?.(open, event);\n },\n open: isOpen,\n placement: placement,\n strategy,\n whileElementsMounted: autoUpdate,\n });\n const context = data.context;\n\n const click = useClick(context, {\n enabled: controlledOpen === undefined,\n });\n\n const dismiss = useDismiss(context, {\n outsidePress: closeOnClickOutside,\n });\n const role = useRole(context, {\n role: 'dialog',\n });\n\n const interactions = useInteractions([click, dismiss, role]);\n\n const { styles: transitionStyles } = useTransitionStyles(context, {\n duration: Number.parseInt(tokens.motion.duration.quick) ?? 0,\n });\n\n return useMemo(\n () => ({\n isOpen,\n setIsOpen,\n ...interactions,\n ...data,\n anchorElementAsPortalAnchor,\n descriptionId,\n initialFocus,\n labelId,\n setDescriptionId,\n setLabelId,\n transitionStyles,\n }),\n [\n isOpen,\n setIsOpen,\n interactions,\n data,\n transitionStyles,\n labelId,\n anchorElementAsPortalAnchor,\n descriptionId,\n initialFocus,\n ],\n );\n}\n"]}
1
+ {"version":3,"file":"use-spotlight.js","sourceRoot":"","sources":["../../../src/spotlight/use-spotlight.tsx"],"names":[],"mappings":";;AAgEA,oCAmFC;AAnJD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,8CAa4B;AAC5B,0CAAyC;AACzC,iCAA0C;AA6B1C,SAAgB,YAAY,CAAC,EAC3B,aAAa,GAAG,KAAK,EACrB,SAAS,GAAG,QAAQ,EACpB,MAAM,EAAE,cAAc,EACtB,YAAY,EAAE,iBAAiB,EAC/B,aAAa,EACb,2BAA2B,EAC3B,YAAY,EACZ,mBAAmB,EACnB,QAAQ,GAAG,UAAU,MACD,EAAE;;IACtB,MAAM,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,GAAG,IAAA,gBAAQ,EAAC,aAAa,CAAC,CAAC;IAC5E,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,IAAA,gBAAQ,GAAsB,CAAC;IAC7D,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,IAAA,gBAAQ,GAAsB,CAAC;IACzE,MAAM,MAAM,GAAG,cAAc,aAAd,cAAc,cAAd,cAAc,GAAI,kBAAkB,CAAC;IACpD,MAAM,SAAS,GAAG,iBAAiB,aAAjB,iBAAiB,cAAjB,iBAAiB,GAAI,qBAAqB,CAAC;IAC7D,MAAM,IAAI,GAAG,IAAA,mBAAW,EAAC;QACvB,QAAQ,EAAE;YACR,SAAS,EAAE,aAAa;SACzB;QACD,UAAU,EAAE;YACV,IAAA,cAAM,EAAC,EAAE,CAAC;YACV,IAAA,YAAI,EAAC;gBACH,SAAS,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAClC,yBAAyB,EAAE,KAAK;gBAChC,OAAO,EAAE,CAAC;aACX,CAAC;YACF,IAAA,aAAK,EAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;SACtB;QACD,YAAY,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC5B,SAAS,CAAC,IAAI,CAAC,CAAC;YAChB,iBAAiB,aAAjB,iBAAiB,uBAAjB,iBAAiB,CAAG,IAAI,EAAE,KAAK,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,EAAE,MAAM;QACZ,SAAS,EAAE,SAAS;QACpB,QAAQ;QACR,oBAAoB,EAAE,kBAAU;KACjC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAE7B,MAAM,KAAK,GAAG,IAAA,gBAAQ,EAAC,OAAO,EAAE;QAC9B,OAAO,EAAE,cAAc,KAAK,SAAS;KACtC,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,OAAO,EAAE;QAClC,YAAY,EAAE,mBAAmB;KAClC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,IAAA,eAAO,EAAC,OAAO,EAAE;QAC5B,IAAI,EAAE,QAAQ;KACf,CAAC,CAAC;IAEH,MAAM,YAAY,GAAG,IAAA,uBAAe,EAAC,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;IAE7D,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAA,2BAAmB,EAAC,OAAO,EAAE;QAChE,QAAQ,EAAE,MAAA,MAAM,CAAC,QAAQ,CAAC,aAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,mCAAI,CAAC;KAC7D,CAAC,CAAC;IAEH,OAAO,IAAA,eAAO,EACZ,GAAG,EAAE,CAAC,6CACJ,MAAM;QACN,SAAS,IACN,YAAY,GACZ,IAAI,KACP,2BAA2B;QAC3B,aAAa;QACb,YAAY;QACZ,OAAO;QACP,gBAAgB;QAChB,UAAU;QACV,gBAAgB,IAChB,EACF;QACE,MAAM;QACN,SAAS;QACT,YAAY;QACZ,IAAI;QACJ,gBAAgB;QAChB,OAAO;QACP,2BAA2B;QAC3B,aAAa;QACb,YAAY;KACb,CACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport {\n autoUpdate,\n flip,\n offset,\n type Placement,\n shift,\n useClick,\n useDismiss,\n useFloating,\n useInteractions,\n type UseInteractionsReturn,\n useRole,\n useTransitionStyles,\n} from '@floating-ui/react';\nimport { tokens } from '@neo4j-ndl/base';\nimport { useMemo, useState } from 'react';\n\nexport interface SpotlightOptions {\n isInitialOpen?: boolean;\n placement?: Placement;\n isOpen?: boolean;\n onOpenChange?: (open: boolean, event?: Event) => void;\n anchorElement?: Element | null;\n // TODO v5: fix boolean naming convention\n // eslint-disable-next-line @typescript-eslint/naming-convention\n anchorElementAsPortalAnchor?: boolean;\n initialFocus?: number | React.MutableRefObject<HTMLElement | null>;\n // TODO v5: fix boolean naming convention\n // eslint-disable-next-line @typescript-eslint/naming-convention\n closeOnClickOutside?: boolean;\n strategy?: 'fixed' | 'absolute';\n}\n\nexport interface UseSpotlightReturn\n extends UseInteractionsReturn, ReturnType<typeof useFloating> {\n isOpen: boolean;\n setIsOpen: (isOpen: boolean) => void;\n labelId: string | undefined;\n transitionStyles: React.CSSProperties;\n // eslint-disable-next-line @typescript-eslint/naming-convention\n anchorElementAsPortalAnchor: boolean | undefined;\n initialFocus: number | React.MutableRefObject<HTMLElement | null> | undefined;\n}\n\nexport function useSpotlight({\n isInitialOpen = false,\n placement = 'bottom',\n isOpen: controlledOpen,\n onOpenChange: setControlledOpen,\n anchorElement,\n anchorElementAsPortalAnchor,\n initialFocus,\n closeOnClickOutside,\n strategy = 'absolute',\n}: SpotlightOptions = {}): UseSpotlightReturn {\n const [isOpenUncontrolled, setIsOpenUncontrolled] = useState(isInitialOpen);\n const [labelId, setLabelId] = useState<string | undefined>();\n const [descriptionId, setDescriptionId] = useState<string | undefined>();\n const isOpen = controlledOpen ?? isOpenUncontrolled;\n const setIsOpen = setControlledOpen ?? setIsOpenUncontrolled;\n const data = useFloating({\n elements: {\n reference: anchorElement,\n },\n middleware: [\n offset(10),\n flip({\n crossAxis: placement.includes('-'),\n fallbackAxisSideDirection: 'end',\n padding: 5,\n }),\n shift({ padding: 5 }),\n ],\n onOpenChange: (open, event) => {\n setIsOpen(open);\n setControlledOpen?.(open, event);\n },\n open: isOpen,\n placement: placement,\n strategy,\n whileElementsMounted: autoUpdate,\n });\n const context = data.context;\n\n const click = useClick(context, {\n enabled: controlledOpen === undefined,\n });\n\n const dismiss = useDismiss(context, {\n outsidePress: closeOnClickOutside,\n });\n const role = useRole(context, {\n role: 'dialog',\n });\n\n const interactions = useInteractions([click, dismiss, role]);\n\n const { styles: transitionStyles } = useTransitionStyles(context, {\n duration: Number.parseInt(tokens.motion.duration.quick) ?? 0,\n });\n\n return useMemo(\n () => ({\n isOpen,\n setIsOpen,\n ...interactions,\n ...data,\n anchorElementAsPortalAnchor,\n descriptionId,\n initialFocus,\n labelId,\n setDescriptionId,\n setLabelId,\n transitionStyles,\n }),\n [\n isOpen,\n setIsOpen,\n interactions,\n data,\n transitionStyles,\n labelId,\n anchorElementAsPortalAnchor,\n descriptionId,\n initialFocus,\n ],\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../src/text-input/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport classNames from 'classnames';\nimport {\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n useId,\n useMemo,\n} from 'react';\n\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport { type CommonProps, type TooltipObjectProps } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\nimport { needleWarningMessage } from '../_common/utils';\nimport { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';\nimport { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';\nimport { XMarkIconOutline } from '../icons/generated/heroIcons/XMarkIconOutline';\nimport { LoadingSpinner } from '../loading-spinner';\nimport { Skeleton } from '../skeleton';\nimport { Tooltip } from '../tooltip';\nimport { Typography } from '../typography';\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n *\n * @remarks\n * When `isSkeletonLoading` is true, the input is rendered as a loading skeleton and the `skeletonProps` prop is used to configure the skeleton. For more information, see the Skeleton documentation.\n */\ntype TextInputProps = {\n /** Assistive text displayed below the input */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the input. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Leading element rendered inside the input */\n leadingElement?: ReactElement;\n\n /** Trailing element rendered inside the input */\n trailingElement?: ReactElement;\n\n /** Size of the input */\n size?: 'small' | 'medium' | 'large';\n\n /** Whether the input is read-only */\n isReadOnly?: boolean;\n\n /**\n * Whether to display the Required/Optional label next to the field label.\n * Shows Required if isRequired is true, otherwise shows Optional.\n * @default false\n */\n showRequiredOrOptionalLabel?: boolean;\n\n /** Whether the input is disabled */\n isDisabled?: boolean;\n\n /** Whether the input is required */\n isRequired?: boolean;\n\n /** The current value of the input */\n value?: React.ComponentPropsWithoutRef<'input'>['value'];\n\n /** Placeholder text displayed when the input is empty */\n placeholder?: React.ComponentPropsWithoutRef<'input'>['placeholder'];\n\n /** Callback function triggered when the input value changes */\n onChange?: React.ComponentPropsWithoutRef<'input'>['onChange'];\n\n /** Whether the input should take the full available width */\n isFluid?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n /** The label displayed above the input */\n label?: string | React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether to render skeletons instead of content */\n isSkeletonLoading?: boolean;\n\n /** Additional props forwarded to the underlying Skeleton components */\n skeletonProps?: React.ComponentProps<typeof Skeleton>;\n\n /** Whether to show the clear button */\n isClearable?: boolean;\n\n /** Whether to show the loading spinner */\n isLoading?: boolean;\n};\n\n/**\n *\n *\n * TextInput Component\n *\n *\n */\n\nexport const TextInput = ({\n label,\n isFluid,\n errorText,\n helpText,\n leadingElement,\n trailingElement,\n showRequiredOrOptionalLabel = false,\n moreInformationText,\n size = 'medium',\n placeholder,\n value,\n tooltipProps,\n htmlAttributes,\n isDisabled,\n isReadOnly,\n isRequired,\n onChange,\n isClearable = false,\n className,\n style,\n isSkeletonLoading = false,\n isLoading = false,\n skeletonProps,\n ref,\n ...restProps\n}: CommonProps<'input', TextInputProps>) => {\n const [currentValue, handleChange] = useSemiControlledInput({\n inputType: 'text',\n isControlled: value !== undefined,\n onChange,\n state: value ?? '',\n });\n const hintId = useId();\n const helpTextId = useId();\n const errorTextId = useId();\n\n const containerWrappingClasses = classNames(`ndl-text-input`, className, {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': leadingElement || trailingElement || errorText,\n 'ndl-has-leading-icon': leadingElement,\n 'ndl-has-trailing-icon': trailingElement || errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n });\n\n const hasEmptyLabelValue =\n label === undefined || label === null || label === '';\n\n const labelWrappingClasses = classNames('ndl-form-item-label', {\n 'ndl-fluid': isFluid,\n 'ndl-form-item-no-label': hasEmptyLabelValue,\n });\n\n const combinedHtmlInputAttributes: InputHTMLAttributes<HTMLInputElement> = {\n ...htmlAttributes,\n className: classNames('ndl-input', htmlAttributes?.className),\n };\n const ariaLabel = combinedHtmlInputAttributes['aria-label'];\n const isCustomLabel = Boolean(label) && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel =\n isCustomLabel && (ariaLabel === undefined || ariaLabel === '');\n const shouldRenderHint = isClearable || isLoading;\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isClearable && event.key === 'Escape' && Boolean(currentValue)) {\n event.preventDefault();\n event.stopPropagation();\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }\n htmlAttributes?.onKeyDown?.(event);\n };\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextInput without a label does not have an aria label, be sure to include an aria label for screen readers. Link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n const informationIconClasses = classNames({\n 'ndl-information-icon-large': size === 'large',\n 'ndl-information-icon-small': size === 'small' || size === 'medium',\n });\n\n const combinedAriaDescribedby = useMemo(() => {\n const ariaDescribedby = [];\n\n if (hintId && shouldRenderHint) {\n ariaDescribedby.push(hintId);\n }\n if (helpText && !errorText) {\n ariaDescribedby.push(helpTextId);\n } else if (errorText) {\n ariaDescribedby.push(errorTextId);\n }\n return ariaDescribedby.join(' ');\n }, [hintId, shouldRenderHint, helpText, errorText, helpTextId, errorTextId]);\n\n return (\n <div className={containerWrappingClasses} style={style}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n {!hasEmptyLabelValue && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-label-text-wrapper\">\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-label-text\"\n >\n {label}\n </Typography>\n {Boolean(moreInformationText) && (\n <Tooltip {...tooltipProps?.root} type=\"simple\">\n <Tooltip.Trigger\n {...tooltipProps?.trigger}\n className={informationIconClasses}\n hasButtonWrapper\n >\n <div\n tabIndex={0}\n role=\"button\"\n aria-label=\"Information icon\"\n >\n <InformationCircleIconOutline />\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content {...tooltipProps?.content}>\n {moreInformationText}\n </Tooltip.Content>\n </Tooltip>\n )}\n {showRequiredOrOptionalLabel && (\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-form-item-optional\"\n >\n {isRequired === true ? 'Required' : 'Optional'}\n </Typography>\n )}\n </div>\n </Skeleton>\n )}\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-input-wrapper\">\n {(leadingElement || (isLoading && !trailingElement)) && (\n <div className=\"ndl-element-leading ndl-element\">\n {isLoading ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n leadingElement\n )}\n </div>\n )}\n <div\n className={classNames('ndl-input-container', {\n 'ndl-clearable': isClearable,\n })}\n >\n <input\n ref={ref}\n readOnly={isReadOnly}\n disabled={isDisabled}\n required={isRequired}\n value={currentValue}\n placeholder={placeholder}\n type=\"text\"\n onChange={handleChange}\n aria-describedby={combinedAriaDescribedby}\n aria-invalid={Boolean(errorText)}\n {...combinedHtmlInputAttributes}\n onKeyDown={handleInputKeyDown}\n {...restProps}\n />\n {shouldRenderHint && (\n <span\n id={hintId}\n className=\"ndl-text-input-hint\"\n aria-hidden={true}\n >\n {isLoading && 'Loading '}\n {isClearable && 'Press Escape to clear input.'}\n </span>\n )}\n {isClearable && Boolean(currentValue) && (\n <div className=\"ndl-element-clear ndl-element\">\n <button\n tabIndex={-1}\n aria-hidden={true}\n type=\"button\"\n title=\"Clear input (Esc)\"\n onClick={() => {\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }}\n >\n <XMarkIconOutline className=\"n-size-4\" />\n </button>\n </div>\n )}\n </div>\n {trailingElement && (\n <div className=\"ndl-element-trailing ndl-element\">\n {isLoading && !leadingElement ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n trailingElement\n )}\n </div>\n )}\n </div>\n </Skeleton>\n </label>\n {Boolean(helpText) && !errorText && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n isLoading={isSkeletonLoading}\n >\n <Typography\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n className=\"ndl-form-message\"\n htmlAttributes={{\n 'aria-live': 'polite',\n id: helpTextId,\n }}\n >\n {helpText}\n </Typography>\n </Skeleton>\n )}\n {Boolean(errorText) && (\n // TODO v4: We might want to have a min width for the container for the messages to help skeleton loading.\n // Currently the message fills 100% of the width while the rest of the text input has a set width.\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n width=\"fit-content\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-form-message\">\n <div className=\"ndl-error-icon\">\n <ExclamationCircleIconSolid />\n </div>\n <Typography\n className=\"ndl-error-text\"\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n htmlAttributes={{\n 'aria-live': 'polite',\n id: errorTextId,\n }}\n >\n {errorText}\n </Typography>\n </div>\n </Skeleton>\n )}\n </div>\n );\n};\n"]}
1
+ {"version":3,"file":"TextInput.js","sourceRoot":"","sources":["../../../src/text-input/TextInput.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport classNames from 'classnames';\nimport {\n type InputHTMLAttributes,\n type ReactElement,\n type ReactNode,\n useId,\n useMemo,\n} from 'react';\n\nimport { customLabelAndNoAriaLabelWarningMessage } from '../_common/messages';\nimport { type CommonProps, type TooltipObjectProps } from '../_common/types';\nimport { useSemiControlledInput } from '../_common/use-semi-controlled-input';\nimport { needleWarningMessage } from '../_common/utils';\nimport { ExclamationCircleIconSolid } from '../icons/generated/heroIcons/ExclamationCircleIconSolid';\nimport { InformationCircleIconOutline } from '../icons/generated/heroIcons/InformationCircleIconOutline';\nimport { XMarkIconOutline } from '../icons/generated/heroIcons/XMarkIconOutline';\nimport { LoadingSpinner } from '../loading-spinner';\nimport { Skeleton } from '../skeleton';\nimport { Tooltip } from '../tooltip';\nimport { Typography } from '../typography';\n\n/**\n * @remarks\n * When `moreInformationText` is provided, a tooltip is rendered next to the label, and the `tooltipProps` prop is used to configure the tooltip. The `TooltipObjectProps` type is defined as: `{ root?: Partial<React.ComponentProps<typeof Tooltip>>; trigger?: Partial<React.ComponentProps<typeof Tooltip.Trigger>>; content?: Partial<React.ComponentProps<typeof Tooltip.Content>>; }`, see the Tooltip component for more details.\n *\n * @remarks\n * When `isSkeletonLoading` is true, the input is rendered as a loading skeleton and the `skeletonProps` prop is used to configure the skeleton. For more information, see the Skeleton documentation.\n */\ntype TextInputProps = {\n /** Assistive text displayed below the input */\n helpText?: string | ReactNode;\n\n /** Error message displayed below the input. When provided, it overrides `helpText` and shows an error icon */\n errorText?: string | ReactNode;\n\n /** Leading element rendered inside the input */\n leadingElement?: ReactElement;\n\n /** Trailing element rendered inside the input */\n trailingElement?: ReactElement;\n\n /** Size of the input */\n size?: 'small' | 'medium' | 'large';\n\n /** Whether the input is read-only */\n isReadOnly?: boolean;\n\n /**\n * Whether to display the Required/Optional label next to the field label.\n * Shows Required if isRequired is true, otherwise shows Optional.\n * @default false\n */\n // TODO v5: decide if this naming is okay, or change it\n // eslint-disable-next-line @typescript-eslint/naming-convention\n showRequiredOrOptionalLabel?: boolean;\n\n /** Whether the input is disabled */\n isDisabled?: boolean;\n\n /** Whether the input is required */\n isRequired?: boolean;\n\n /** The current value of the input */\n value?: React.ComponentPropsWithoutRef<'input'>['value'];\n\n /** Placeholder text displayed when the input is empty */\n placeholder?: React.ComponentPropsWithoutRef<'input'>['placeholder'];\n\n /** Callback function triggered when the input value changes */\n onChange?: React.ComponentPropsWithoutRef<'input'>['onChange'];\n\n /** Whether the input should take the full available width */\n isFluid?: boolean;\n\n /** Text displayed in the information tooltip shown next to the label */\n moreInformationText?: React.ReactNode;\n\n /** The label displayed above the input */\n label?: string | React.ReactNode;\n\n /** Props for the Tooltip component used by the information icon */\n tooltipProps?: TooltipObjectProps;\n\n /** Whether to render skeletons instead of content */\n isSkeletonLoading?: boolean;\n\n /** Additional props forwarded to the underlying Skeleton components */\n skeletonProps?: React.ComponentProps<typeof Skeleton>;\n\n /** Whether to show the clear button */\n isClearable?: boolean;\n\n /** Whether to show the loading spinner */\n isLoading?: boolean;\n};\n\n/**\n *\n *\n * TextInput Component\n *\n *\n */\n\nexport const TextInput = ({\n label,\n isFluid,\n errorText,\n helpText,\n leadingElement,\n trailingElement,\n showRequiredOrOptionalLabel = false,\n moreInformationText,\n size = 'medium',\n placeholder,\n value,\n tooltipProps,\n htmlAttributes,\n isDisabled,\n isReadOnly,\n isRequired,\n onChange,\n isClearable = false,\n className,\n style,\n isSkeletonLoading = false,\n isLoading = false,\n skeletonProps,\n ref,\n ...restProps\n}: CommonProps<'input', TextInputProps>) => {\n const [currentValue, handleChange] = useSemiControlledInput({\n inputType: 'text',\n isControlled: value !== undefined,\n onChange,\n state: value ?? '',\n });\n const hintId = useId();\n const helpTextId = useId();\n const errorTextId = useId();\n\n const containerWrappingClasses = classNames(`ndl-text-input`, className, {\n 'ndl-disabled': isDisabled,\n 'ndl-has-error': errorText,\n 'ndl-has-icon': leadingElement || trailingElement || errorText,\n 'ndl-has-leading-icon': leadingElement,\n 'ndl-has-trailing-icon': trailingElement || errorText,\n 'ndl-large': size === 'large',\n 'ndl-medium': size === 'medium',\n 'ndl-read-only': isReadOnly,\n 'ndl-small': size === 'small',\n });\n\n const hasEmptyLabelValue =\n label === undefined || label === null || label === '';\n\n const labelWrappingClasses = classNames('ndl-form-item-label', {\n 'ndl-fluid': isFluid,\n 'ndl-form-item-no-label': hasEmptyLabelValue,\n });\n\n const combinedHtmlInputAttributes: InputHTMLAttributes<HTMLInputElement> = {\n ...htmlAttributes,\n className: classNames('ndl-input', htmlAttributes?.className),\n };\n const ariaLabel = combinedHtmlInputAttributes['aria-label'];\n const isCustomLabel = Boolean(label) && typeof label !== 'string';\n const hasCustomLabelAndNoAriaLabel =\n isCustomLabel && (ariaLabel === undefined || ariaLabel === '');\n const shouldRenderHint = isClearable || isLoading;\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n if (isClearable && event.key === 'Escape' && Boolean(currentValue)) {\n event.preventDefault();\n event.stopPropagation();\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }\n htmlAttributes?.onKeyDown?.(event);\n };\n\n useMemo(() => {\n if (!label && !ariaLabel) {\n needleWarningMessage(\n 'A TextInput without a label does not have an aria label, be sure to include an aria label for screen readers. Link: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI',\n );\n }\n\n if (hasCustomLabelAndNoAriaLabel) {\n needleWarningMessage(customLabelAndNoAriaLabelWarningMessage);\n }\n }, [label, ariaLabel, hasCustomLabelAndNoAriaLabel]);\n\n const informationIconClasses = classNames({\n 'ndl-information-icon-large': size === 'large',\n 'ndl-information-icon-small': size === 'small' || size === 'medium',\n });\n\n const combinedAriaDescribedby = useMemo(() => {\n const ariaDescribedby = [];\n\n if (hintId && shouldRenderHint) {\n ariaDescribedby.push(hintId);\n }\n if (helpText && !errorText) {\n ariaDescribedby.push(helpTextId);\n } else if (errorText) {\n ariaDescribedby.push(errorTextId);\n }\n return ariaDescribedby.join(' ');\n }, [hintId, shouldRenderHint, helpText, errorText, helpTextId, errorTextId]);\n\n return (\n <div className={containerWrappingClasses} style={style}>\n {/* We enable implicit label wrapping */}\n {/* Source: https://dequeuniversity.com/rules/axe/4.2/label?application=axeAPI */}\n <label className={labelWrappingClasses}>\n {!hasEmptyLabelValue && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-label-text-wrapper\">\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-label-text\"\n >\n {label}\n </Typography>\n {Boolean(moreInformationText) && (\n <Tooltip {...tooltipProps?.root} type=\"simple\">\n <Tooltip.Trigger\n {...tooltipProps?.trigger}\n className={informationIconClasses}\n hasButtonWrapper\n >\n <div\n tabIndex={0}\n role=\"button\"\n aria-label=\"Information icon\"\n >\n <InformationCircleIconOutline />\n </div>\n </Tooltip.Trigger>\n <Tooltip.Content {...tooltipProps?.content}>\n {moreInformationText}\n </Tooltip.Content>\n </Tooltip>\n )}\n {showRequiredOrOptionalLabel && (\n <Typography\n variant={size === 'large' ? 'body-large' : 'body-medium'}\n className=\"ndl-form-item-optional\"\n >\n {isRequired === true ? 'Required' : 'Optional'}\n </Typography>\n )}\n </div>\n </Skeleton>\n )}\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-input-wrapper\">\n {(leadingElement || (isLoading && !trailingElement)) && (\n <div className=\"ndl-element-leading ndl-element\">\n {isLoading ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n leadingElement\n )}\n </div>\n )}\n <div\n className={classNames('ndl-input-container', {\n 'ndl-clearable': isClearable,\n })}\n >\n <input\n ref={ref}\n readOnly={isReadOnly}\n disabled={isDisabled}\n required={isRequired}\n value={currentValue}\n placeholder={placeholder}\n type=\"text\"\n onChange={handleChange}\n aria-describedby={combinedAriaDescribedby}\n aria-invalid={Boolean(errorText)}\n {...combinedHtmlInputAttributes}\n onKeyDown={handleInputKeyDown}\n {...restProps}\n />\n {shouldRenderHint && (\n <span\n id={hintId}\n className=\"ndl-text-input-hint\"\n aria-hidden={true}\n >\n {isLoading && 'Loading '}\n {isClearable && 'Press Escape to clear input.'}\n </span>\n )}\n {isClearable && Boolean(currentValue) && (\n <div className=\"ndl-element-clear ndl-element\">\n <button\n tabIndex={-1}\n aria-hidden={true}\n type=\"button\"\n title=\"Clear input (Esc)\"\n onClick={() => {\n handleChange?.({\n target: { value: '' },\n } as React.ChangeEvent<HTMLInputElement>);\n }}\n >\n <XMarkIconOutline className=\"n-size-4\" />\n </button>\n </div>\n )}\n </div>\n {trailingElement && (\n <div className=\"ndl-element-trailing ndl-element\">\n {isLoading && !leadingElement ? (\n <LoadingSpinner\n size={size === 'large' ? 'medium' : 'small'}\n className={\n size === 'large'\n ? 'ndl-medium-spinner'\n : 'ndl-small-spinner'\n }\n />\n ) : (\n trailingElement\n )}\n </div>\n )}\n </div>\n </Skeleton>\n </label>\n {Boolean(helpText) && !errorText && (\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n isLoading={isSkeletonLoading}\n >\n <Typography\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n className=\"ndl-form-message\"\n htmlAttributes={{\n 'aria-live': 'polite',\n id: helpTextId,\n }}\n >\n {helpText}\n </Typography>\n </Skeleton>\n )}\n {Boolean(errorText) && (\n // TODO v4: We might want to have a min width for the container for the messages to help skeleton loading.\n // Currently the message fills 100% of the width while the rest of the text input has a set width.\n <Skeleton\n onBackground=\"weak\"\n shape=\"rectangular\"\n width=\"fit-content\"\n {...skeletonProps}\n isLoading={isSkeletonLoading}\n >\n <div className=\"ndl-form-message\">\n <div className=\"ndl-error-icon\">\n <ExclamationCircleIconSolid />\n </div>\n <Typography\n className=\"ndl-error-text\"\n variant={size === 'large' ? 'body-medium' : 'body-small'}\n htmlAttributes={{\n 'aria-live': 'polite',\n id: errorTextId,\n }}\n >\n {errorText}\n </Typography>\n </div>\n </Skeleton>\n )}\n </div>\n );\n};\n"]}
@@ -71,7 +71,7 @@ const TextOverflow = (_a) => {
71
71
  const characterTruncatedContent = (0, react_1.useMemo)(() => {
72
72
  if (maxCharacters !== undefined && expandButton === undefined) {
73
73
  const result = (0, text_overflow_utils_1.truncateReactNodeByCharacters)(children, maxCharacters);
74
- return result.needsTruncation ? result.truncatedContent : null;
74
+ return result.shouldTruncation ? result.truncatedContent : null;
75
75
  }
76
76
  return null;
77
77
  }, [maxCharacters, expandButton, children]);
@@ -1 +1 @@
1
- {"version":3,"file":"TextOverflow.js","sourceRoot":"","sources":["../../../src/text-overflow/TextOverflow.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport type React from 'react';\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\nimport type {\n PolymorphicCommonProps,\n TooltipObjectProps,\n} from '../_common/types';\nimport { TextLink } from '../text-link';\nimport { Tooltip } from '../tooltip';\nimport { Typography } from '../typography';\nimport { COLLAPSE_BUTTON_TEXT, ELLIPSIS_CHAR } from './constants';\nimport {\n getTextContent,\n truncateReactNodeByCharacters,\n} from './text-overflow-utils';\nimport { useTruncateWithButton } from './use-truncate-with-button';\n\ntype TextOverflowProps = {\n /** The content to be truncated. Can be text, Typography components, or complex JSX. */\n children: React.ReactNode;\n\n /**\n * Controls the expand/collapse UI.\n * - string: show expand/collapse button with custom text (e.g., \"View more\")\n * - undefined: content is not expandable, only truncated with ellipsis\n * @default undefined\n */\n expandButton?: 'view-more' | 'ellipsis';\n\n /**\n * Maximum number of characters to display. Takes precedence over line-based truncation when set.\n */\n maxCharacters?: number;\n\n /**\n * Number of lines to show before truncation.\n * Uses CSS line-clamp for non-expandable content.\n * Uses DOM measurement for expandable content.\n * **Note**: Ignored if `maxCharacters` is explicitly set to a custom value.\n */\n lines?: number;\n\n /**\n * Whether to show tooltip with full text on hover when content is truncated.\n * @default true\n */\n shouldShowTooltip?: boolean;\n\n /** Props to pass to tooltip component */\n tooltipProps?: TooltipObjectProps;\n\n /** Callback function called when content is expanded or collapsed */\n onExpandedToggle?: (isExpanded: boolean) => void;\n\n /**\n * The typography variant to use for the text.\n * @default 'body-medium'\n */\n typographyVariant?: React.ComponentProps<typeof Typography>['variant'];\n};\n\nconst expandButtonTexts = {\n ellipsis: ELLIPSIS_CHAR,\n 'view-more': 'View more',\n};\n\nexport const TextOverflow = <T extends React.ElementType = 'div'>({\n as,\n children,\n className,\n htmlAttributes,\n lines,\n tooltipProps,\n onExpandedToggle,\n expandButton,\n maxCharacters,\n shouldShowTooltip = true,\n typographyVariant = 'body-medium',\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, TextOverflowProps>) => {\n const contentRef = useRef<HTMLDivElement>(null);\n const textElementRef = useRef<HTMLSpanElement>(null);\n const [isTooltipOpen, setIsTooltipOpen] = useState(false);\n\n // Use truncate with button hook when expandButton is provided\n const shouldUseTruncateWithButton = expandButton !== undefined;\n const truncateWithButtonResult = useTruncateWithButton({\n button: expandButtonTexts[expandButton!] || 'View more',\n buttonType: expandButton,\n closeTooltip: () => setIsTooltipOpen(false),\n content: children,\n // Disable expensive calculations when no expand button is needed\n isDisabled: !shouldUseTruncateWithButton,\n lineClamp: lines ?? 1,\n maxCharacters,\n onExpandedToggle,\n });\n\n // Handle character-based truncation when no expand button is used\n const characterTruncatedContent = useMemo(() => {\n if (maxCharacters !== undefined && expandButton === undefined) {\n const result = truncateReactNodeByCharacters(children, maxCharacters);\n return result.needsTruncation ? result.truncatedContent : null;\n }\n return null;\n }, [maxCharacters, expandButton, children]);\n\n // Memoize text content extraction to avoid repeated traversals\n const textContent = useMemo(() => getTextContent(children), [children]);\n\n // Memoize tooltip truncation detection logic\n const checkTruncationForTooltip = useCallback(() => {\n if (shouldUseTruncateWithButton) {\n return truncateWithButtonResult.isTruncated;\n }\n\n // Character based truncation\n if (maxCharacters !== undefined) {\n return characterTruncatedContent !== null;\n }\n\n const element = textElementRef.current;\n if (element === null) {\n return false;\n }\n\n // Regular multiline truncation\n if (lines !== undefined && lines > 1) {\n return element.scrollHeight > element.clientHeight;\n }\n\n // Regular single line truncation\n return element.scrollWidth > element.clientWidth;\n }, [\n shouldUseTruncateWithButton,\n truncateWithButtonResult.isTruncated,\n maxCharacters,\n characterTruncatedContent,\n lines,\n ]);\n\n const renderContent = () => {\n const isMultiline = typeof lines === 'number' && lines > 1;\n\n const textStyle = {\n '--ndl-line-clamp': isMultiline ? lines.toString() : undefined,\n } as React.CSSProperties;\n\n const textClasses = classNames({\n 'ndl-text-overflow-multi-line': isMultiline,\n 'ndl-text-overflow-single-line':\n !isMultiline && maxCharacters === undefined,\n });\n\n if (shouldUseTruncateWithButton) {\n return (\n <div ref={truncateWithButtonResult.containerRef}>\n <div\n className={truncateWithButtonResult.isExpanded ? '' : textClasses}\n style={textStyle}\n >\n {truncateWithButtonResult.contentToRender}\n {truncateWithButtonResult.isTruncated && (\n <TextLink\n as=\"button\"\n className={classNames('ndl-text-overflow-toggle', {\n 'ndl-text-overflow-toggle-margin-left':\n expandButton !== 'ellipsis' ||\n truncateWithButtonResult.isExpanded,\n })}\n htmlAttributes={{\n onClick: truncateWithButtonResult.toggleExpand,\n }}\n >\n {truncateWithButtonResult.isExpanded\n ? COLLAPSE_BUTTON_TEXT\n : expandButtonTexts[expandButton!]}\n </TextLink>\n )}\n </div>\n <div\n ref={truncateWithButtonResult.measureRef}\n style={{\n position: 'absolute',\n top: '-9999px',\n visibility: 'hidden',\n }}\n />\n </div>\n );\n }\n\n return (\n <span ref={textElementRef} className={textClasses} style={textStyle}>\n {characterTruncatedContent ?? children}\n </span>\n );\n };\n\n const isTooltipDisabled =\n !shouldShowTooltip ||\n (expandButton !== undefined && truncateWithButtonResult.isExpanded);\n\n return (\n <Tooltip\n {...tooltipProps?.root}\n type=\"simple\"\n isDisabled={isTooltipDisabled}\n isOpen={isTooltipOpen}\n onOpenChange={(open) => {\n if (open) {\n setIsTooltipOpen(checkTruncationForTooltip());\n } else {\n setIsTooltipOpen(false);\n }\n }}\n >\n <Tooltip.Trigger {...tooltipProps?.trigger} hasButtonWrapper>\n <Typography\n as={as ?? 'div'}\n ref={ref}\n variant={typographyVariant}\n className={classNames('ndl-text-overflow', className)}\n htmlAttributes={{\n ...htmlAttributes,\n }}\n {...restProps}\n {...(!isTooltipDisabled &&\n expandButton === undefined && {\n tabIndex: 0,\n })}\n >\n <div className=\"ndl-text-overflow-content\" ref={contentRef}>\n {renderContent()}\n </div>\n </Typography>\n </Tooltip.Trigger>\n <Tooltip.Content\n className={classNames(\n 'ndl-text-overflow-tooltip-content',\n tooltipProps?.content?.className,\n )}\n {...tooltipProps?.content}\n >\n {textContent}\n </Tooltip.Content>\n </Tooltip>\n );\n};\n"]}
1
+ {"version":3,"file":"TextOverflow.js","sourceRoot":"","sources":["../../../src/text-overflow/TextOverflow.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport classNames from 'classnames';\nimport type React from 'react';\nimport { useCallback, useMemo, useRef, useState } from 'react';\n\nimport type {\n PolymorphicCommonProps,\n TooltipObjectProps,\n} from '../_common/types';\nimport { TextLink } from '../text-link';\nimport { Tooltip } from '../tooltip';\nimport { Typography } from '../typography';\nimport { COLLAPSE_BUTTON_TEXT, ELLIPSIS_CHAR } from './constants';\nimport {\n getTextContent,\n truncateReactNodeByCharacters,\n} from './text-overflow-utils';\nimport { useTruncateWithButton } from './use-truncate-with-button';\n\ntype TextOverflowProps = {\n /** The content to be truncated. Can be text, Typography components, or complex JSX. */\n children: React.ReactNode;\n\n /**\n * Controls the expand/collapse UI.\n * - string: show expand/collapse button with custom text (e.g., \"View more\")\n * - undefined: content is not expandable, only truncated with ellipsis\n * @default undefined\n */\n expandButton?: 'view-more' | 'ellipsis';\n\n /**\n * Maximum number of characters to display. Takes precedence over line-based truncation when set.\n */\n maxCharacters?: number;\n\n /**\n * Number of lines to show before truncation.\n * Uses CSS line-clamp for non-expandable content.\n * Uses DOM measurement for expandable content.\n * **Note**: Ignored if `maxCharacters` is explicitly set to a custom value.\n */\n lines?: number;\n\n /**\n * Whether to show tooltip with full text on hover when content is truncated.\n * @default true\n */\n shouldShowTooltip?: boolean;\n\n /** Props to pass to tooltip component */\n tooltipProps?: TooltipObjectProps;\n\n /** Callback function called when content is expanded or collapsed */\n onExpandedToggle?: (isExpanded: boolean) => void;\n\n /**\n * The typography variant to use for the text.\n * @default 'body-medium'\n */\n typographyVariant?: React.ComponentProps<typeof Typography>['variant'];\n};\n\nconst expandButtonTexts = {\n ellipsis: ELLIPSIS_CHAR,\n 'view-more': 'View more',\n};\n\nexport const TextOverflow = <T extends React.ElementType = 'div'>({\n as,\n children,\n className,\n htmlAttributes,\n lines,\n tooltipProps,\n onExpandedToggle,\n expandButton,\n maxCharacters,\n shouldShowTooltip = true,\n typographyVariant = 'body-medium',\n ref,\n ...restProps\n}: PolymorphicCommonProps<T, TextOverflowProps>) => {\n const contentRef = useRef<HTMLDivElement>(null);\n const textElementRef = useRef<HTMLSpanElement>(null);\n const [isTooltipOpen, setIsTooltipOpen] = useState(false);\n\n // Use truncate with button hook when expandButton is provided\n const shouldUseTruncateWithButton = expandButton !== undefined;\n const truncateWithButtonResult = useTruncateWithButton({\n button: expandButtonTexts[expandButton!] || 'View more',\n buttonType: expandButton,\n closeTooltip: () => setIsTooltipOpen(false),\n content: children,\n // Disable expensive calculations when no expand button is needed\n isDisabled: !shouldUseTruncateWithButton,\n lineClamp: lines ?? 1,\n maxCharacters,\n onExpandedToggle,\n });\n\n // Handle character-based truncation when no expand button is used\n const characterTruncatedContent = useMemo(() => {\n if (maxCharacters !== undefined && expandButton === undefined) {\n const result = truncateReactNodeByCharacters(children, maxCharacters);\n return result.shouldTruncation ? result.truncatedContent : null;\n }\n return null;\n }, [maxCharacters, expandButton, children]);\n\n // Memoize text content extraction to avoid repeated traversals\n const textContent = useMemo(() => getTextContent(children), [children]);\n\n // Memoize tooltip truncation detection logic\n const checkTruncationForTooltip = useCallback(() => {\n if (shouldUseTruncateWithButton) {\n return truncateWithButtonResult.isTruncated;\n }\n\n // Character based truncation\n if (maxCharacters !== undefined) {\n return characterTruncatedContent !== null;\n }\n\n const element = textElementRef.current;\n if (element === null) {\n return false;\n }\n\n // Regular multiline truncation\n if (lines !== undefined && lines > 1) {\n return element.scrollHeight > element.clientHeight;\n }\n\n // Regular single line truncation\n return element.scrollWidth > element.clientWidth;\n }, [\n shouldUseTruncateWithButton,\n truncateWithButtonResult.isTruncated,\n maxCharacters,\n characterTruncatedContent,\n lines,\n ]);\n\n const renderContent = () => {\n const isMultiline = typeof lines === 'number' && lines > 1;\n\n const textStyle = {\n '--ndl-line-clamp': isMultiline ? lines.toString() : undefined,\n } as React.CSSProperties;\n\n const textClasses = classNames({\n 'ndl-text-overflow-multi-line': isMultiline,\n 'ndl-text-overflow-single-line':\n !isMultiline && maxCharacters === undefined,\n });\n\n if (shouldUseTruncateWithButton) {\n return (\n <div ref={truncateWithButtonResult.containerRef}>\n <div\n className={truncateWithButtonResult.isExpanded ? '' : textClasses}\n style={textStyle}\n >\n {truncateWithButtonResult.contentToRender}\n {truncateWithButtonResult.isTruncated && (\n <TextLink\n as=\"button\"\n className={classNames('ndl-text-overflow-toggle', {\n 'ndl-text-overflow-toggle-margin-left':\n expandButton !== 'ellipsis' ||\n truncateWithButtonResult.isExpanded,\n })}\n htmlAttributes={{\n onClick: truncateWithButtonResult.toggleExpand,\n }}\n >\n {truncateWithButtonResult.isExpanded\n ? COLLAPSE_BUTTON_TEXT\n : expandButtonTexts[expandButton!]}\n </TextLink>\n )}\n </div>\n <div\n ref={truncateWithButtonResult.measureRef}\n style={{\n position: 'absolute',\n top: '-9999px',\n visibility: 'hidden',\n }}\n />\n </div>\n );\n }\n\n return (\n <span ref={textElementRef} className={textClasses} style={textStyle}>\n {characterTruncatedContent ?? children}\n </span>\n );\n };\n\n const isTooltipDisabled =\n !shouldShowTooltip ||\n (expandButton !== undefined && truncateWithButtonResult.isExpanded);\n\n return (\n <Tooltip\n {...tooltipProps?.root}\n type=\"simple\"\n isDisabled={isTooltipDisabled}\n isOpen={isTooltipOpen}\n onOpenChange={(open) => {\n if (open) {\n setIsTooltipOpen(checkTruncationForTooltip());\n } else {\n setIsTooltipOpen(false);\n }\n }}\n >\n <Tooltip.Trigger {...tooltipProps?.trigger} hasButtonWrapper>\n <Typography\n as={as ?? 'div'}\n ref={ref}\n variant={typographyVariant}\n className={classNames('ndl-text-overflow', className)}\n htmlAttributes={{\n ...htmlAttributes,\n }}\n {...restProps}\n {...(!isTooltipDisabled &&\n expandButton === undefined && {\n tabIndex: 0,\n })}\n >\n <div className=\"ndl-text-overflow-content\" ref={contentRef}>\n {renderContent()}\n </div>\n </Typography>\n </Tooltip.Trigger>\n <Tooltip.Content\n className={classNames(\n 'ndl-text-overflow-tooltip-content',\n tooltipProps?.content?.className,\n )}\n {...tooltipProps?.content}\n >\n {textContent}\n </Tooltip.Content>\n </Tooltip>\n );\n};\n"]}
@@ -58,7 +58,7 @@ const truncateReactNodeByCharacters = (node, maxCharacters, shouldAddEllipsis =
58
58
  // Get the total character count first to determine if truncation is needed
59
59
  const totalLength = (0, exports.getTextContent)(normalizedNode).length;
60
60
  if (totalLength <= maxCharacters) {
61
- return { needsTruncation: false, truncatedContent: null };
61
+ return { shouldTruncation: false, truncatedContent: null };
62
62
  }
63
63
  let charCount = 0;
64
64
  let hasReachedLimit = false;
@@ -156,10 +156,10 @@ const truncateReactNodeByCharacters = (node, maxCharacters, shouldAddEllipsis =
156
156
  // Add ellipsis if needed
157
157
  if (shouldAddEllipsis && finalResult !== null) {
158
158
  const withEllipsis = react_1.default.createElement(react_1.default.Fragment, null, finalResult, constants_1.ELLIPSIS_CHAR);
159
- return { needsTruncation: true, truncatedContent: withEllipsis };
159
+ return { shouldTruncation: true, truncatedContent: withEllipsis };
160
160
  }
161
161
  return {
162
- needsTruncation: true,
162
+ shouldTruncation: true,
163
163
  truncatedContent: finalResult,
164
164
  };
165
165
  };
@@ -1 +1 @@
1
- {"version":3,"file":"text-overflow-utils.js","sourceRoot":"","sources":["../../../src/text-overflow/text-overflow-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport React, { type ReactNode } from 'react';\n\nimport { ELLIPSIS_CHAR, ESTIMATION_FACTORS } from './constants';\n\ntype ReactNodeTruncationResult = {\n needsTruncation: boolean;\n truncatedContent: React.ReactNode | null;\n};\n\n/**\n * Recursively extracts plain text from React nodes\n */\nexport const getTextContent = (node: React.ReactNode): string => {\n if (typeof node === 'string') {\n return node;\n }\n if (typeof node === 'number') {\n return node.toString();\n }\n if (React.isValidElement(node)) {\n // Type assertion to access props safely\n const element = node as React.ReactElement<{ children?: ReactNode }>;\n return getTextContent(element.props.children);\n }\n if (Array.isArray(node)) {\n return node.map(getTextContent).join('');\n }\n return '';\n};\n\n/**\n * Truncates React node content by character count while preserving element structure.\n */\nexport const truncateReactNodeByCharacters = (\n node: React.ReactNode,\n maxCharacters: number,\n shouldAddEllipsis = true,\n): ReactNodeTruncationResult => {\n // Handle the case where node is an array (React children)\n const normalizedNode = Array.isArray(node)\n ? React.createElement(React.Fragment, null, ...node)\n : node;\n\n // Get the total character count first to determine if truncation is needed\n const totalLength = getTextContent(normalizedNode).length;\n\n if (totalLength <= maxCharacters) {\n return { needsTruncation: false, truncatedContent: null };\n }\n\n let charCount = 0;\n let hasReachedLimit = false;\n\n const truncateNode = (currentNode: React.ReactNode): React.ReactNode => {\n // Stop processing if character limit is reached\n if (hasReachedLimit || charCount >= maxCharacters) {\n hasReachedLimit = true;\n return null;\n }\n\n // Handle arrays of children (mixed content case)\n if (Array.isArray(currentNode)) {\n const truncatedChildren: React.ReactNode[] = [];\n\n for (const child of currentNode) {\n if (hasReachedLimit || charCount >= maxCharacters) {\n break;\n }\n\n const truncatedChild = truncateNode(child);\n if (truncatedChild !== null) {\n truncatedChildren.push(truncatedChild);\n }\n }\n\n return truncatedChildren.length > 0 ? truncatedChildren : null;\n }\n\n if (typeof currentNode === 'string') {\n const availableChars = maxCharacters - charCount;\n\n if (currentNode.length <= availableChars) {\n charCount += currentNode.length;\n return currentNode;\n }\n\n // Truncate at character limit, preferring word boundaries\n let truncated = currentNode.substring(0, availableChars);\n const lastSpaceIndex = truncated.lastIndexOf(' ');\n\n if (lastSpaceIndex > availableChars * ESTIMATION_FACTORS.WORD_BOUNDARY) {\n truncated = truncated.substring(0, lastSpaceIndex);\n }\n\n truncated = truncated.trim();\n charCount += truncated.length;\n hasReachedLimit = true;\n return truncated;\n }\n\n if (typeof currentNode === 'number') {\n const str = currentNode.toString();\n const availableChars = maxCharacters - charCount;\n\n if (str.length <= availableChars) {\n charCount += str.length;\n return currentNode;\n }\n\n const truncated = str.substring(0, availableChars);\n charCount += truncated.length;\n hasReachedLimit = true;\n return truncated;\n }\n\n if (!React.isValidElement(currentNode)) {\n return currentNode;\n }\n\n const { children } = currentNode.props as { children?: ReactNode };\n if (children === null || children === undefined) {\n return currentNode;\n }\n\n if (typeof children === 'string') {\n const truncatedChild = truncateNode(children);\n if (truncatedChild === null) {\n return null;\n }\n return React.cloneElement(currentNode, {}, truncatedChild);\n }\n\n if (Array.isArray(children)) {\n const truncatedChildren: React.ReactNode[] = [];\n for (const child of children) {\n if (hasReachedLimit || charCount >= maxCharacters) {\n break;\n }\n\n const truncatedChild = truncateNode(child);\n if (truncatedChild !== null) {\n truncatedChildren.push(truncatedChild);\n }\n }\n\n if (truncatedChildren.length === 0) {\n return null;\n }\n return React.cloneElement(currentNode, {}, ...truncatedChildren);\n }\n\n // Single React element child\n const truncatedChild = truncateNode(children);\n if (truncatedChild === null) {\n return null;\n }\n return React.cloneElement(currentNode, {}, truncatedChild);\n };\n\n const truncatedResult = truncateNode(normalizedNode);\n\n // Convert array results to proper React elements\n const finalResult = Array.isArray(truncatedResult)\n ? React.createElement(React.Fragment, null, ...truncatedResult)\n : truncatedResult;\n\n // Add ellipsis if needed\n if (shouldAddEllipsis && finalResult !== null) {\n const withEllipsis = React.createElement(\n React.Fragment,\n null,\n finalResult,\n ELLIPSIS_CHAR,\n );\n return { needsTruncation: true, truncatedContent: withEllipsis };\n }\n\n return {\n needsTruncation: true,\n truncatedContent: finalResult,\n };\n};\n"]}
1
+ {"version":3,"file":"text-overflow-utils.js","sourceRoot":"","sources":["../../../src/text-overflow/text-overflow-utils.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,kDAA8C;AAE9C,2CAAgE;AAOhE;;GAEG;AACI,MAAM,cAAc,GAAG,CAAC,IAAqB,EAAU,EAAE;IAC9D,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,eAAK,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,wCAAwC;QACxC,MAAM,OAAO,GAAG,IAAoD,CAAC;QACrE,OAAO,IAAA,sBAAc,EAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,sBAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAhBW,QAAA,cAAc,kBAgBzB;AAEF;;GAEG;AACI,MAAM,6BAA6B,GAAG,CAC3C,IAAqB,EACrB,aAAqB,EACrB,iBAAiB,GAAG,IAAI,EACG,EAAE;IAC7B,0DAA0D;IAC1D,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QACxC,CAAC,CAAC,eAAK,CAAC,aAAa,CAAC,eAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;QACpD,CAAC,CAAC,IAAI,CAAC;IAET,2EAA2E;IAC3E,MAAM,WAAW,GAAG,IAAA,sBAAc,EAAC,cAAc,CAAC,CAAC,MAAM,CAAC;IAE1D,IAAI,WAAW,IAAI,aAAa,EAAE,CAAC;QACjC,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IAC7D,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,MAAM,YAAY,GAAG,CAAC,WAA4B,EAAmB,EAAE;QACrE,gDAAgD;QAChD,IAAI,eAAe,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;YAClD,eAAe,GAAG,IAAI,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,iDAAiD;QACjD,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/B,MAAM,iBAAiB,GAAsB,EAAE,CAAC;YAEhD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;gBAChC,IAAI,eAAe,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;oBAClD,MAAM;gBACR,CAAC;gBAED,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC3C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;oBAC5B,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;YAED,OAAO,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,CAAC;QAED,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC;YAEjD,IAAI,WAAW,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;gBACzC,SAAS,IAAI,WAAW,CAAC,MAAM,CAAC;gBAChC,OAAO,WAAW,CAAC;YACrB,CAAC;YAED,0DAA0D;YAC1D,IAAI,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YACzD,MAAM,cAAc,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAElD,IAAI,cAAc,GAAG,cAAc,GAAG,8BAAkB,CAAC,aAAa,EAAE,CAAC;gBACvE,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YACrD,CAAC;YAED,SAAS,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;YAC7B,SAAS,IAAI,SAAS,CAAC,MAAM,CAAC;YAC9B,eAAe,GAAG,IAAI,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,cAAc,GAAG,aAAa,GAAG,SAAS,CAAC;YAEjD,IAAI,GAAG,CAAC,MAAM,IAAI,cAAc,EAAE,CAAC;gBACjC,SAAS,IAAI,GAAG,CAAC,MAAM,CAAC;gBACxB,OAAO,WAAW,CAAC;YACrB,CAAC;YAED,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;YACnD,SAAS,IAAI,SAAS,CAAC,MAAM,CAAC;YAC9B,eAAe,GAAG,IAAI,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,IAAI,CAAC,eAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,CAAC;YACvC,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,MAAM,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC,KAAiC,CAAC;QACnE,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChD,OAAO,WAAW,CAAC;QACrB,CAAC;QAED,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACjC,MAAM,cAAc,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,eAAK,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,MAAM,iBAAiB,GAAsB,EAAE,CAAC;YAChD,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;gBAC7B,IAAI,eAAe,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;oBAClD,MAAM;gBACR,CAAC;gBAED,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBAC3C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;oBAC5B,iBAAiB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;YAED,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACnC,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,eAAK,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,EAAE,GAAG,iBAAiB,CAAC,CAAC;QACnE,CAAC;QAED,6BAA6B;QAC7B,MAAM,cAAc,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,eAAK,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,EAAE,cAAc,CAAC,CAAC;IAC7D,CAAC,CAAC;IAEF,MAAM,eAAe,GAAG,YAAY,CAAC,cAAc,CAAC,CAAC;IAErD,iDAAiD;IACjD,MAAM,WAAW,GAAG,KAAK,CAAC,OAAO,CAAC,eAAe,CAAC;QAChD,CAAC,CAAC,eAAK,CAAC,aAAa,CAAC,eAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,eAAe,CAAC;QAC/D,CAAC,CAAC,eAAe,CAAC;IAEpB,yBAAyB;IACzB,IAAI,iBAAiB,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QAC9C,MAAM,YAAY,GAAG,eAAK,CAAC,aAAa,CACtC,eAAK,CAAC,QAAQ,EACd,IAAI,EACJ,WAAW,EACX,yBAAa,CACd,CAAC;QACF,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,CAAC;IACpE,CAAC;IAED,OAAO;QACL,gBAAgB,EAAE,IAAI;QACtB,gBAAgB,EAAE,WAAW;KAC9B,CAAC;AACJ,CAAC,CAAC;AApJW,QAAA,6BAA6B,iCAoJxC","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\nimport React, { type ReactNode } from 'react';\n\nimport { ELLIPSIS_CHAR, ESTIMATION_FACTORS } from './constants';\n\ntype ReactNodeTruncationResult = {\n shouldTruncation: boolean;\n truncatedContent: React.ReactNode | null;\n};\n\n/**\n * Recursively extracts plain text from React nodes\n */\nexport const getTextContent = (node: React.ReactNode): string => {\n if (typeof node === 'string') {\n return node;\n }\n if (typeof node === 'number') {\n return node.toString();\n }\n if (React.isValidElement(node)) {\n // Type assertion to access props safely\n const element = node as React.ReactElement<{ children?: ReactNode }>;\n return getTextContent(element.props.children);\n }\n if (Array.isArray(node)) {\n return node.map(getTextContent).join('');\n }\n return '';\n};\n\n/**\n * Truncates React node content by character count while preserving element structure.\n */\nexport const truncateReactNodeByCharacters = (\n node: React.ReactNode,\n maxCharacters: number,\n shouldAddEllipsis = true,\n): ReactNodeTruncationResult => {\n // Handle the case where node is an array (React children)\n const normalizedNode = Array.isArray(node)\n ? React.createElement(React.Fragment, null, ...node)\n : node;\n\n // Get the total character count first to determine if truncation is needed\n const totalLength = getTextContent(normalizedNode).length;\n\n if (totalLength <= maxCharacters) {\n return { shouldTruncation: false, truncatedContent: null };\n }\n\n let charCount = 0;\n let hasReachedLimit = false;\n\n const truncateNode = (currentNode: React.ReactNode): React.ReactNode => {\n // Stop processing if character limit is reached\n if (hasReachedLimit || charCount >= maxCharacters) {\n hasReachedLimit = true;\n return null;\n }\n\n // Handle arrays of children (mixed content case)\n if (Array.isArray(currentNode)) {\n const truncatedChildren: React.ReactNode[] = [];\n\n for (const child of currentNode) {\n if (hasReachedLimit || charCount >= maxCharacters) {\n break;\n }\n\n const truncatedChild = truncateNode(child);\n if (truncatedChild !== null) {\n truncatedChildren.push(truncatedChild);\n }\n }\n\n return truncatedChildren.length > 0 ? truncatedChildren : null;\n }\n\n if (typeof currentNode === 'string') {\n const availableChars = maxCharacters - charCount;\n\n if (currentNode.length <= availableChars) {\n charCount += currentNode.length;\n return currentNode;\n }\n\n // Truncate at character limit, preferring word boundaries\n let truncated = currentNode.substring(0, availableChars);\n const lastSpaceIndex = truncated.lastIndexOf(' ');\n\n if (lastSpaceIndex > availableChars * ESTIMATION_FACTORS.WORD_BOUNDARY) {\n truncated = truncated.substring(0, lastSpaceIndex);\n }\n\n truncated = truncated.trim();\n charCount += truncated.length;\n hasReachedLimit = true;\n return truncated;\n }\n\n if (typeof currentNode === 'number') {\n const str = currentNode.toString();\n const availableChars = maxCharacters - charCount;\n\n if (str.length <= availableChars) {\n charCount += str.length;\n return currentNode;\n }\n\n const truncated = str.substring(0, availableChars);\n charCount += truncated.length;\n hasReachedLimit = true;\n return truncated;\n }\n\n if (!React.isValidElement(currentNode)) {\n return currentNode;\n }\n\n const { children } = currentNode.props as { children?: ReactNode };\n if (children === null || children === undefined) {\n return currentNode;\n }\n\n if (typeof children === 'string') {\n const truncatedChild = truncateNode(children);\n if (truncatedChild === null) {\n return null;\n }\n return React.cloneElement(currentNode, {}, truncatedChild);\n }\n\n if (Array.isArray(children)) {\n const truncatedChildren: React.ReactNode[] = [];\n for (const child of children) {\n if (hasReachedLimit || charCount >= maxCharacters) {\n break;\n }\n\n const truncatedChild = truncateNode(child);\n if (truncatedChild !== null) {\n truncatedChildren.push(truncatedChild);\n }\n }\n\n if (truncatedChildren.length === 0) {\n return null;\n }\n return React.cloneElement(currentNode, {}, ...truncatedChildren);\n }\n\n // Single React element child\n const truncatedChild = truncateNode(children);\n if (truncatedChild === null) {\n return null;\n }\n return React.cloneElement(currentNode, {}, truncatedChild);\n };\n\n const truncatedResult = truncateNode(normalizedNode);\n\n // Convert array results to proper React elements\n const finalResult = Array.isArray(truncatedResult)\n ? React.createElement(React.Fragment, null, ...truncatedResult)\n : truncatedResult;\n\n // Add ellipsis if needed\n if (shouldAddEllipsis && finalResult !== null) {\n const withEllipsis = React.createElement(\n React.Fragment,\n null,\n finalResult,\n ELLIPSIS_CHAR,\n );\n return { shouldTruncation: true, truncatedContent: withEllipsis };\n }\n\n return {\n shouldTruncation: true,\n truncatedContent: finalResult,\n };\n};\n"]}
@@ -114,8 +114,8 @@ function useTruncateWithButton({ content, lineClamp, button, onExpandedToggle, m
114
114
  // Character-based truncation takes precedence
115
115
  if (typeof maxCharacters === 'number') {
116
116
  const result = (0, text_overflow_utils_1.truncateReactNodeByCharacters)(content, maxCharacters);
117
- setIsTruncated(result.needsTruncation);
118
- setTruncatedContent(result.needsTruncation ? result.truncatedContent : content);
117
+ setIsTruncated(result.shouldTruncation);
118
+ setTruncatedContent(result.shouldTruncation ? result.truncatedContent : content);
119
119
  return;
120
120
  }
121
121
  // Fallback to line-based truncation
@@ -1 +1 @@
1
- {"version":3,"file":"use-truncate-with-button.js","sourceRoot":"","sources":["../../../src/text-overflow/use-truncate-with-button.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport { tokens } from '@neo4j-ndl/base';\nimport {\n type ReactNode,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useDebounceCallback } from '../hooks';\nimport {\n getTextContent,\n truncateReactNodeByCharacters,\n} from './text-overflow-utils';\n\n// Cache for computed styles to avoid repeated getComputedStyle calls\nconst styleCache = new WeakMap<HTMLElement, CSSStyleDeclaration>();\n\n// Helper function to copy relevant styles for measurement\nconst copyStylesForMeasurement = (\n measureElement: HTMLElement,\n sourceElement: HTMLElement,\n) => {\n // Use cached styles if available\n let sourceStyles = styleCache.get(sourceElement);\n if (sourceStyles === undefined) {\n sourceStyles = window.getComputedStyle(sourceElement);\n styleCache.set(sourceElement, sourceStyles);\n }\n\n measureElement.style.position = 'absolute';\n measureElement.style.visibility = 'hidden';\n measureElement.style.top = '-9999px';\n measureElement.style.left = '-9999px';\n measureElement.style.width = sourceStyles.width;\n measureElement.style.fontFamily = sourceStyles.fontFamily;\n measureElement.style.fontSize = sourceStyles.fontSize;\n measureElement.style.fontWeight = sourceStyles.fontWeight;\n measureElement.style.lineHeight = sourceStyles.lineHeight;\n measureElement.style.letterSpacing = sourceStyles.letterSpacing;\n measureElement.style.wordSpacing = sourceStyles.wordSpacing;\n measureElement.style.overflow = 'hidden';\n measureElement.style.wordBreak = 'break-word';\n};\n\n// Helper function to find the optimal truncation point using optimized binary search\nconst findTruncationPoint = (\n content: ReactNode,\n allText: string,\n measureElement: HTMLElement,\n maxHeight: number,\n button: ReactNode,\n buttonType?: 'view-more' | 'ellipsis',\n) => {\n let low = 0;\n let high = allText.length;\n let bestFitContent: ReactNode = null;\n\n // Pre-calculate button text to avoid repeated string operations\n const buttonText = typeof button === 'string' ? button : 'View more';\n const buttonMargin = buttonType !== 'ellipsis' ? tokens.space[4] : '0';\n\n // Create reusable DOM elements to avoid repeated creation\n const tempSpan = document.createElement('span');\n const btnSpan = document.createElement('span');\n btnSpan.style.display = 'inline-block';\n btnSpan.style.marginLeft = buttonMargin;\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const testText = allText.slice(0, mid);\n\n measureElement.innerHTML = '';\n\n // Reuse span elements\n tempSpan.textContent =\n buttonType === 'ellipsis' ? testText : `${testText}\\u2026`;\n measureElement.appendChild(tempSpan);\n\n btnSpan.textContent = buttonText;\n measureElement.appendChild(btnSpan);\n\n if (measureElement.scrollHeight <= maxHeight) {\n bestFitContent = truncateReactNodeByCharacters(\n content,\n mid,\n buttonType !== 'ellipsis',\n ).truncatedContent;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return bestFitContent;\n};\n\ninterface UseTruncateOptions {\n button: ReactNode;\n content: ReactNode;\n lineClamp: number;\n onExpandedToggle?: (isExpanded: boolean) => void;\n maxCharacters?: number;\n buttonType?: 'view-more' | 'ellipsis';\n closeTooltip?: () => void;\n /**\n * When true, skips all expensive DOM calculations and measurements.\n * Useful for performance optimization when the hook functionality isn't needed.\n */\n isDisabled?: boolean;\n}\n\nexport function useTruncateWithButton({\n content,\n lineClamp,\n button,\n onExpandedToggle,\n maxCharacters,\n buttonType,\n closeTooltip,\n isDisabled,\n}: UseTruncateOptions) {\n const containerRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLDivElement>(null);\n\n const [isExpanded, setIsExpanded] = useState(false);\n const [isTruncated, setIsTruncated] = useState(false);\n const [truncatedContent, setTruncatedContent] = useState<ReactNode>(content);\n\n // Memoize text content to avoid repeated traversals\n const textContent = useMemo(() => getTextContent(content), [content]);\n\n const toggleExpand = useCallback(() => {\n if (isDisabled === true) {\n return;\n }\n\n const shouldExpand = !isExpanded;\n setIsExpanded(shouldExpand);\n\n if (shouldExpand) {\n onExpandedToggle?.(true);\n closeTooltip?.();\n } else {\n onExpandedToggle?.(false);\n }\n }, [isExpanded, onExpandedToggle, closeTooltip, isDisabled]);\n\n const recalculateTruncation = useCallback(() => {\n // If disabled, don't perform any calculations\n if (isDisabled === true) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // Character-based truncation takes precedence\n if (typeof maxCharacters === 'number') {\n const result = truncateReactNodeByCharacters(content, maxCharacters);\n setIsTruncated(result.needsTruncation);\n setTruncatedContent(\n result.needsTruncation ? result.truncatedContent : content,\n );\n return;\n }\n\n // Fallback to line-based truncation\n if (!measureRef.current || !containerRef.current) {\n return;\n }\n\n const measure = measureRef.current;\n const container = containerRef.current;\n\n copyStylesForMeasurement(measure, container);\n const containerStyles = window.getComputedStyle(container);\n const lineHeight = parseFloat(containerStyles.lineHeight);\n const maxHeight = lineHeight * lineClamp;\n\n const allText = textContent;\n\n // Early exit if no text content\n if (allText.length === 0) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // First, check if truncation is needed at all\n measure.innerHTML = '';\n const fullTextSpan = document.createElement('span');\n fullTextSpan.textContent = allText;\n measure.appendChild(fullTextSpan);\n\n const isTruncationNeeded = measure.scrollHeight > maxHeight;\n\n if (!isTruncationNeeded) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // Binary search for truncation point\n const bestFitContent = findTruncationPoint(\n content,\n allText,\n measure,\n maxHeight,\n button,\n buttonType,\n );\n\n setIsTruncated(true);\n setTruncatedContent(bestFitContent);\n }, [\n content,\n button,\n lineClamp,\n maxCharacters,\n buttonType,\n isDisabled,\n textContent,\n ]);\n\n // Create debounced version of recalculateTruncation for resize events\n const debouncedRecalculateTruncation = useDebounceCallback(\n recalculateTruncation,\n 100,\n );\n\n // Initial calculation and resize handling\n useLayoutEffect(() => {\n // If disabled, don't set up any observers or event listeners\n if (isDisabled === true) {\n return;\n }\n\n recalculateTruncation();\n\n // Set up resize observer for container size changes\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n debouncedRecalculateTruncation();\n });\n\n resizeObserver.observe(container);\n\n // Also observe parent element to catch container size changes\n if (container.parentElement) {\n resizeObserver.observe(container.parentElement);\n }\n\n // Handle window resize events\n const handleWindowResize = () => {\n debouncedRecalculateTruncation();\n };\n\n window.addEventListener('resize', handleWindowResize);\n\n return () => {\n resizeObserver.disconnect();\n window.removeEventListener('resize', handleWindowResize);\n };\n }, [recalculateTruncation, debouncedRecalculateTruncation, isDisabled]);\n\n // Compute the final content to render based on expanded state\n const contentToRender = isExpanded ? content : truncatedContent;\n\n return {\n containerRef,\n contentToRender,\n isExpanded,\n isTruncated,\n measureRef,\n toggleExpand,\n };\n}\n"]}
1
+ {"version":3,"file":"use-truncate-with-button.js","sourceRoot":"","sources":["../../../src/text-overflow/use-truncate-with-button.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport { tokens } from '@neo4j-ndl/base';\nimport {\n type ReactNode,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport { useDebounceCallback } from '../hooks';\nimport {\n getTextContent,\n truncateReactNodeByCharacters,\n} from './text-overflow-utils';\n\n// Cache for computed styles to avoid repeated getComputedStyle calls\nconst styleCache = new WeakMap<HTMLElement, CSSStyleDeclaration>();\n\n// Helper function to copy relevant styles for measurement\nconst copyStylesForMeasurement = (\n measureElement: HTMLElement,\n sourceElement: HTMLElement,\n) => {\n // Use cached styles if available\n let sourceStyles = styleCache.get(sourceElement);\n if (sourceStyles === undefined) {\n sourceStyles = window.getComputedStyle(sourceElement);\n styleCache.set(sourceElement, sourceStyles);\n }\n\n measureElement.style.position = 'absolute';\n measureElement.style.visibility = 'hidden';\n measureElement.style.top = '-9999px';\n measureElement.style.left = '-9999px';\n measureElement.style.width = sourceStyles.width;\n measureElement.style.fontFamily = sourceStyles.fontFamily;\n measureElement.style.fontSize = sourceStyles.fontSize;\n measureElement.style.fontWeight = sourceStyles.fontWeight;\n measureElement.style.lineHeight = sourceStyles.lineHeight;\n measureElement.style.letterSpacing = sourceStyles.letterSpacing;\n measureElement.style.wordSpacing = sourceStyles.wordSpacing;\n measureElement.style.overflow = 'hidden';\n measureElement.style.wordBreak = 'break-word';\n};\n\n// Helper function to find the optimal truncation point using optimized binary search\nconst findTruncationPoint = (\n content: ReactNode,\n allText: string,\n measureElement: HTMLElement,\n maxHeight: number,\n button: ReactNode,\n buttonType?: 'view-more' | 'ellipsis',\n) => {\n let low = 0;\n let high = allText.length;\n let bestFitContent: ReactNode = null;\n\n // Pre-calculate button text to avoid repeated string operations\n const buttonText = typeof button === 'string' ? button : 'View more';\n const buttonMargin = buttonType !== 'ellipsis' ? tokens.space[4] : '0';\n\n // Create reusable DOM elements to avoid repeated creation\n const tempSpan = document.createElement('span');\n const btnSpan = document.createElement('span');\n btnSpan.style.display = 'inline-block';\n btnSpan.style.marginLeft = buttonMargin;\n\n while (low <= high) {\n const mid = Math.floor((low + high) / 2);\n const testText = allText.slice(0, mid);\n\n measureElement.innerHTML = '';\n\n // Reuse span elements\n tempSpan.textContent =\n buttonType === 'ellipsis' ? testText : `${testText}\\u2026`;\n measureElement.appendChild(tempSpan);\n\n btnSpan.textContent = buttonText;\n measureElement.appendChild(btnSpan);\n\n if (measureElement.scrollHeight <= maxHeight) {\n bestFitContent = truncateReactNodeByCharacters(\n content,\n mid,\n buttonType !== 'ellipsis',\n ).truncatedContent;\n low = mid + 1;\n } else {\n high = mid - 1;\n }\n }\n\n return bestFitContent;\n};\n\ninterface UseTruncateOptions {\n button: ReactNode;\n content: ReactNode;\n lineClamp: number;\n onExpandedToggle?: (isExpanded: boolean) => void;\n maxCharacters?: number;\n buttonType?: 'view-more' | 'ellipsis';\n closeTooltip?: () => void;\n /**\n * When true, skips all expensive DOM calculations and measurements.\n * Useful for performance optimization when the hook functionality isn't needed.\n */\n isDisabled?: boolean;\n}\n\nexport function useTruncateWithButton({\n content,\n lineClamp,\n button,\n onExpandedToggle,\n maxCharacters,\n buttonType,\n closeTooltip,\n isDisabled,\n}: UseTruncateOptions) {\n const containerRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLDivElement>(null);\n\n const [isExpanded, setIsExpanded] = useState(false);\n const [isTruncated, setIsTruncated] = useState(false);\n const [truncatedContent, setTruncatedContent] = useState<ReactNode>(content);\n\n // Memoize text content to avoid repeated traversals\n const textContent = useMemo(() => getTextContent(content), [content]);\n\n const toggleExpand = useCallback(() => {\n if (isDisabled === true) {\n return;\n }\n\n const shouldExpand = !isExpanded;\n setIsExpanded(shouldExpand);\n\n if (shouldExpand) {\n onExpandedToggle?.(true);\n closeTooltip?.();\n } else {\n onExpandedToggle?.(false);\n }\n }, [isExpanded, onExpandedToggle, closeTooltip, isDisabled]);\n\n const recalculateTruncation = useCallback(() => {\n // If disabled, don't perform any calculations\n if (isDisabled === true) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // Character-based truncation takes precedence\n if (typeof maxCharacters === 'number') {\n const result = truncateReactNodeByCharacters(content, maxCharacters);\n setIsTruncated(result.shouldTruncation);\n setTruncatedContent(\n result.shouldTruncation ? result.truncatedContent : content,\n );\n return;\n }\n\n // Fallback to line-based truncation\n if (!measureRef.current || !containerRef.current) {\n return;\n }\n\n const measure = measureRef.current;\n const container = containerRef.current;\n\n copyStylesForMeasurement(measure, container);\n const containerStyles = window.getComputedStyle(container);\n const lineHeight = parseFloat(containerStyles.lineHeight);\n const maxHeight = lineHeight * lineClamp;\n\n const allText = textContent;\n\n // Early exit if no text content\n if (allText.length === 0) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // First, check if truncation is needed at all\n measure.innerHTML = '';\n const fullTextSpan = document.createElement('span');\n fullTextSpan.textContent = allText;\n measure.appendChild(fullTextSpan);\n\n const isTruncationNeeded = measure.scrollHeight > maxHeight;\n\n if (!isTruncationNeeded) {\n setIsTruncated(false);\n setTruncatedContent(content);\n return;\n }\n\n // Binary search for truncation point\n const bestFitContent = findTruncationPoint(\n content,\n allText,\n measure,\n maxHeight,\n button,\n buttonType,\n );\n\n setIsTruncated(true);\n setTruncatedContent(bestFitContent);\n }, [\n content,\n button,\n lineClamp,\n maxCharacters,\n buttonType,\n isDisabled,\n textContent,\n ]);\n\n // Create debounced version of recalculateTruncation for resize events\n const debouncedRecalculateTruncation = useDebounceCallback(\n recalculateTruncation,\n 100,\n );\n\n // Initial calculation and resize handling\n useLayoutEffect(() => {\n // If disabled, don't set up any observers or event listeners\n if (isDisabled === true) {\n return;\n }\n\n recalculateTruncation();\n\n // Set up resize observer for container size changes\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const resizeObserver = new ResizeObserver(() => {\n debouncedRecalculateTruncation();\n });\n\n resizeObserver.observe(container);\n\n // Also observe parent element to catch container size changes\n if (container.parentElement) {\n resizeObserver.observe(container.parentElement);\n }\n\n // Handle window resize events\n const handleWindowResize = () => {\n debouncedRecalculateTruncation();\n };\n\n window.addEventListener('resize', handleWindowResize);\n\n return () => {\n resizeObserver.disconnect();\n window.removeEventListener('resize', handleWindowResize);\n };\n }, [recalculateTruncation, debouncedRecalculateTruncation, isDisabled]);\n\n // Compute the final content to render based on expanded state\n const contentToRender = isExpanded ? content : truncatedContent;\n\n return {\n containerRef,\n contentToRender,\n isExpanded,\n isTruncated,\n measureRef,\n toggleExpand,\n };\n}\n"]}