@12-apps/ui 6.39.10 → 6.39.12

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 (60) hide show
  1. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +4 -4
  2. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +2 -2
  3. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +3 -3
  4. package/dist/_internal/components/data-display/HoverCard/HoverCard.hooks.js +1 -1
  5. package/dist/_internal/components/data-display/HoverCard/HoverCard.js +2 -2
  6. package/dist/_internal/components/data-display/index.js +2 -2
  7. package/dist/_internal/components/form/CepField/CepField.js +2 -2
  8. package/dist/_internal/components/form/Input/Input.js +1 -1
  9. package/dist/_internal/components/form/RichTextEditor/RichTextEditor.hooks.js +1 -1
  10. package/dist/_internal/components/form/RichTextEditor/RichTextEditor.js +2 -2
  11. package/dist/_internal/components/form/index.js +4 -4
  12. package/dist/_internal/components/form/total-form/Fields/CepField.js +3 -3
  13. package/dist/_internal/components/form/total-form/Fields/TextField.js +2 -2
  14. package/dist/_internal/components/form/total-form/Fields/index.js +5 -5
  15. package/dist/_internal/components/index.js +6 -6
  16. package/dist/{chunk-F6D6HXZU.js → chunk-7X7ZHJHM.js} +2 -2
  17. package/dist/{chunk-DAHYLPK7.js → chunk-CMV6BRQ3.js} +13 -4
  18. package/dist/chunk-CMV6BRQ3.js.map +1 -0
  19. package/dist/{chunk-774B27QA.js → chunk-EUACQR6N.js} +4 -3
  20. package/dist/chunk-EUACQR6N.js.map +1 -0
  21. package/dist/{chunk-YS67XMOP.js → chunk-I5ZVCY2N.js} +3 -3
  22. package/dist/{chunk-A5B7B4HT.js → chunk-INMKA5SF.js} +2 -2
  23. package/dist/{chunk-VJG7NMGL.js → chunk-IYF246UA.js} +2 -2
  24. package/dist/{chunk-VURQZBFH.js → chunk-JRJCBDGN.js} +16 -3
  25. package/dist/chunk-JRJCBDGN.js.map +1 -0
  26. package/dist/{chunk-7EM4THID.js → chunk-RTEY5COP.js} +2 -2
  27. package/dist/{chunk-2XX45PC5.js → chunk-TGXCG62P.js} +2 -2
  28. package/dist/{chunk-SXYIXCUB.js → chunk-VNWZWQF3.js} +41 -23
  29. package/dist/chunk-VNWZWQF3.js.map +1 -0
  30. package/dist/{chunk-SSS64KYB.js → chunk-Z43N7ASP.js} +2 -2
  31. package/dist/{chunk-6MFMLQ72.js → chunk-ZNDDILNQ.js} +2 -2
  32. package/dist/data-display/DataViews.js +4 -4
  33. package/dist/data-display/HoverCard.js +2 -2
  34. package/dist/form/CepField.js +2 -2
  35. package/dist/form/Input.js +1 -1
  36. package/dist/form/RichTextEditor.js +2 -2
  37. package/dist/form/total-form.js +5 -5
  38. package/dist/types/components/data-display/HoverCard/HoverCard.d.ts.map +1 -1
  39. package/dist/types/components/data-display/HoverCard/HoverCard.hooks.d.ts +1 -0
  40. package/dist/types/components/data-display/HoverCard/HoverCard.hooks.d.ts.map +1 -1
  41. package/dist/types/components/form/Input/Input.d.ts.map +1 -1
  42. package/dist/types/components/form/RichTextEditor/RichTextEditor.hooks.d.ts.map +1 -1
  43. package/package.json +1 -1
  44. package/src/components/data-display/HoverCard/HoverCard.hooks.ts +80 -25
  45. package/src/components/data-display/HoverCard/HoverCard.md +1 -0
  46. package/src/components/data-display/HoverCard/HoverCard.tsx +11 -2
  47. package/src/components/form/Input/Input.tsx +40 -1
  48. package/src/components/form/RichTextEditor/RichTextEditor.hooks.ts +20 -3
  49. package/dist/chunk-774B27QA.js.map +0 -1
  50. package/dist/chunk-DAHYLPK7.js.map +0 -1
  51. package/dist/chunk-SXYIXCUB.js.map +0 -1
  52. package/dist/chunk-VURQZBFH.js.map +0 -1
  53. /package/dist/{chunk-F6D6HXZU.js.map → chunk-7X7ZHJHM.js.map} +0 -0
  54. /package/dist/{chunk-YS67XMOP.js.map → chunk-I5ZVCY2N.js.map} +0 -0
  55. /package/dist/{chunk-A5B7B4HT.js.map → chunk-INMKA5SF.js.map} +0 -0
  56. /package/dist/{chunk-VJG7NMGL.js.map → chunk-IYF246UA.js.map} +0 -0
  57. /package/dist/{chunk-7EM4THID.js.map → chunk-RTEY5COP.js.map} +0 -0
  58. /package/dist/{chunk-2XX45PC5.js.map → chunk-TGXCG62P.js.map} +0 -0
  59. /package/dist/{chunk-SSS64KYB.js.map → chunk-Z43N7ASP.js.map} +0 -0
  60. /package/dist/{chunk-6MFMLQ72.js.map → chunk-ZNDDILNQ.js.map} +0 -0
@@ -16,6 +16,13 @@ const SANITIZE_CONFIG = {
16
16
  KEEP_CONTENT: true,
17
17
  };
18
18
 
19
+ // The one way editor html reaches the DOM. Both writes (the render-path effect
20
+ // and the over-limit restore) use it, so they cannot drift to different configs.
21
+ const sanitize = (html: string): string => DOMPurify.sanitize(html, SANITIZE_CONFIG);
22
+
23
+ // INVARIANT: only ever pass SANITISED html here. Assigning innerHTML to a
24
+ // detached element still fetches `<img src>` and fires its `onerror`, so raw
25
+ // markup would execute. Its one caller passes `sanitizedContent`.
19
26
  const textLengthOf = (html: string): number => {
20
27
  const probe = document.createElement('div');
21
28
  probe.innerHTML = html;
@@ -34,6 +41,11 @@ const useEditorContent = ({
34
41
  onChange?: (value: string) => void;
35
42
  maxLength?: number;
36
43
  }) => {
44
+ // `content` holds UNSANITISED html: the caller's raw `value` (read once, at
45
+ // mount) until the first accepted input, and the editor's raw live innerHTML
46
+ // after it. Every write of it to the DOM must go through `sanitize` below.
47
+ // INVARIANT: if syncing a later `value` is ever added, the new value reaches
48
+ // the DOM through the same sanitiser, never by a direct innerHTML write.
37
49
  const [content, setContent] = useState(value ?? '');
38
50
 
39
51
  const handleContentChange = useCallback(() => {
@@ -42,12 +54,17 @@ const useEditorContent = ({
42
54
  const newContent = editorRef.current.innerHTML;
43
55
 
44
56
  // Over the limit, put the last accepted content back rather than truncating
45
- // mid-markup.
57
+ // mid-markup. `content` may be the caller's raw `value`, so the restore is
58
+ // sanitised exactly as the render path is: writing it raw ran an `onerror`
59
+ // handler carried in `value` (FUT-2685).
46
60
  if (maxLength && (editorRef.current.textContent || '').length > maxLength) {
47
- editorRef.current.innerHTML = content;
61
+ editorRef.current.innerHTML = sanitize(content);
48
62
  return;
49
63
  }
50
64
 
65
+ // Emitting the live DOM is safe only because nothing but `sanitize()` ever
66
+ // writes it: the editor renders empty and the effect below fills it. Give
67
+ // the first render its own markup and this must emit `sanitize(newContent)`.
51
68
  setContent(newContent);
52
69
  onChange?.(newContent);
53
70
  }, [maxLength, onChange, content, editorRef]);
@@ -121,7 +138,7 @@ export const useRichTextEditor = ({
121
138
  [disabled, readOnly, handleContentChange],
122
139
  );
123
140
 
124
- const sanitizedContent = DOMPurify.sanitize(content, SANITIZE_CONFIG);
141
+ const sanitizedContent = sanitize(content);
125
142
 
126
143
  // Reflect the sanitized result back when it differs from what is on screen.
127
144
  useEffect(() => {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/RichTextEditor/RichTextEditor.hooks.ts"],"sourcesContent":["import DOMPurify from 'dompurify';\nimport type React from 'react';\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { applyFormatToRange } from './RichTextEditor.format';\n\n// Deliberately narrow: anything not listed is stripped, and no data-* attributes\n// survive, so pasted markup cannot smuggle in behaviour.\nconst SANITIZE_CONFIG = {\n ALLOWED_TAGS: [\n 'p', 'br', 'strong', 'em', 'u', 's', 'a', 'img', 'ul', 'ol', 'li',\n 'blockquote', 'pre', 'code', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'span', 'div',\n ],\n ALLOWED_ATTR: ['href', 'src', 'alt', 'target', 'rel', 'style', 'class'],\n ALLOW_DATA_ATTR: false,\n KEEP_CONTENT: true,\n};\n\nconst textLengthOf = (html: string): number => {\n const probe = document.createElement('div');\n probe.innerHTML = html;\n return probe.textContent?.length || 0;\n};\n\n// The editable content and the limit that guards it.\nconst useEditorContent = ({\n editorRef,\n value,\n onChange,\n maxLength,\n}: {\n editorRef: React.RefObject<HTMLDivElement | null>;\n value?: string;\n onChange?: (value: string) => void;\n maxLength?: number;\n}) => {\n const [content, setContent] = useState(value ?? '');\n\n const handleContentChange = useCallback(() => {\n if (!editorRef.current) return;\n\n const newContent = editorRef.current.innerHTML;\n\n // Over the limit, put the last accepted content back rather than truncating\n // mid-markup.\n if (maxLength && (editorRef.current.textContent || '').length > maxLength) {\n editorRef.current.innerHTML = content;\n return;\n }\n\n setContent(newContent);\n onChange?.(newContent);\n }, [maxLength, onChange, content, editorRef]);\n\n return { content, handleContentChange };\n};\n\nconst useFocusState = ({ onFocus, onBlur }: { onFocus?: () => void; onBlur?: () => void }) => {\n const [isFocused, setIsFocused] = useState(false);\n\n const handleFocus = useCallback(() => {\n setIsFocused(true);\n onFocus?.();\n }, [onFocus]);\n\n const handleBlur = useCallback(() => {\n setIsFocused(false);\n onBlur?.();\n }, [onBlur]);\n\n return { isFocused, handleFocus, handleBlur };\n};\n\nexport const useRichTextEditor = ({\n value,\n onChange,\n onFocus,\n onBlur,\n disabled,\n readOnly,\n maxLength,\n}: {\n value?: string;\n onChange?: (value: string) => void;\n onFocus?: () => void;\n onBlur?: () => void;\n disabled?: boolean;\n readOnly?: boolean;\n maxLength?: number;\n}) => {\n const editorRef = useRef<HTMLDivElement>(null);\n const { content, handleContentChange } = useEditorContent({\n editorRef,\n value,\n onChange,\n maxLength,\n });\n const { isFocused, handleFocus, handleBlur } = useFocusState({ onFocus, onBlur });\n\n const applyFormat = useCallback(\n (formatType: string, formatValue?: string) => {\n if (disabled || readOnly || !editorRef.current) return;\n\n const selection = window.getSelection();\n // Nothing selected: give the editor focus so the next keystroke lands.\n if (!selection || selection.rangeCount === 0) {\n editorRef.current.focus();\n return;\n }\n\n applyFormatToRange({\n formatType,\n value: formatValue,\n range: selection.getRangeAt(0),\n editor: editorRef.current,\n });\n\n handleContentChange();\n editorRef.current.focus();\n },\n [disabled, readOnly, handleContentChange],\n );\n\n const sanitizedContent = DOMPurify.sanitize(content, SANITIZE_CONFIG);\n\n // Reflect the sanitized result back when it differs from what is on screen.\n useEffect(() => {\n if (editorRef.current && editorRef.current.innerHTML !== sanitizedContent) {\n editorRef.current.innerHTML = sanitizedContent;\n }\n }, [sanitizedContent]);\n\n return {\n editorRef,\n isFocused,\n characterCount: textLengthOf(sanitizedContent),\n handleContentChange,\n handleFocus,\n handleBlur,\n applyFormat,\n };\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/HoverCard/HoverCard.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport Card from '@mui/material/Card/index.js';\nimport CardContent from '@mui/material/CardContent/index.js';\nimport Popover from '@mui/material/Popover/index.js';\nimport { styled, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { rem } from '../../../tokens/relative';\nimport { withDefaults } from '../../../utils/withDefaults';\n\nimport { HoverCardContent } from './HoverCard.content';\nimport { useHoverCard } from './HoverCard.hooks';\nimport { arrowSx, cardSx, getAnchorOrigin, getTransformOrigin, sideOf } from './HoverCard.styles';\nimport type { CardStyleFlags } from './HoverCard.styles';\nimport type { HoverCardAnimation, HoverCardPlacement, HoverCardProps } from './HoverCard.types';\n\nconst ArrowContainer = styled('div')<{ placement: HoverCardPlacement; offset?: number }>(\n ({ theme, placement }) => ({ ...arrowSx(theme, placement) }),\n);\n\nconst StyledCard = styled(Card, {\n shouldForwardProp: (prop) =>\n !['customVariant', 'glow', 'pulse', 'animation'].includes(prop as string),\n})<CardStyleFlags>(({ theme, ...flags }) => ({ ...cardSx(theme, flags) }));\n\nconst StyledPopover = styled(Popover, {\n shouldForwardProp: (prop) => prop !== 'customAnimation',\n})<{ customAnimation?: HoverCardAnimation }>(({ customAnimation }) => ({\n // The popover only positions; StyledCard draws the surface.\n '& .MuiPopover-paper': {\n backgroundColor: 'transparent',\n boxShadow: 'none',\n overflow: 'visible',\n ...(customAnimation === 'scale' && { transformOrigin: 'center' }),\n },\n}));\n\nconst DEFAULTS = {\n variant: 'default',\n glow: false,\n pulse: false,\n placement: 'bottom',\n showArrow: false,\n animation: 'fade',\n enterDelay: 700,\n exitDelay: 0,\n loading: false,\n touchEnabled: true,\n disabled: false,\n} satisfies Partial<HoverCardProps>;\n\ntype ResolvedProps = HoverCardProps & Required<Pick<HoverCardProps, keyof typeof DEFAULTS>>;\n\n/** Padding is the variant's own: detailed roomier, minimal tighter. */\nconst CONTENT_PADDING: Record<string, number> = { detailed: 3, minimal: 1.5 };\n\n/**\n * The card is nudged off the anchor on whichever side it sits — `offset` design\n * px (8 unless the caller says otherwise), through the theme's type scale.\n */\nconst offsetMargin = (theme: Theme, placement: HoverCardPlacement, offset: number | undefined) => {\n const side = sideOf(placement);\n const key = ({ top: 'mt', bottom: 'mb', left: 'ml', right: 'mr' } as const)[side];\n return { [key]: rem(theme, offset ?? 8) };\n};\n\n/**\n * The card's cap: 400 design px unless the caller says otherwise. `sx` has always\n * read a number of 1 or less as a fraction of the parent, and that stays so.\n */\nconst capOf = (theme: Theme, maxWidth: number | undefined): string => {\n const cap = maxWidth ?? 400;\n return cap <= 1 && cap !== 0 ? `${cap * 100}%` : rem(theme, cap);\n};\n\nexport const HoverCard = React.forwardRef<HTMLDivElement, HoverCardProps>((props, ref) => {\n const {\n variant, glow, pulse, title, description, avatar, trigger, placement, showArrow,\n animation, enterDelay, exitDelay, maxWidth, loading, loadingComponent, loadingText, touchEnabled,\n offset, disabled, onOpen, onClose, children, dataTestId,\n ...rest\n } = withDefaults(props, DEFAULTS) as ResolvedProps;\n\n const { anchorEl, isOpen, handleClose, triggerHandlers, cardHandlers } = useHoverCard({\n disabled,\n touchEnabled,\n enterDelay,\n exitDelay,\n onOpen,\n onClose,\n });\n\n const triggerProps = {\n ...triggerHandlers,\n style: { cursor: disabled ? 'default' : 'pointer' },\n 'data-testid': dataTestId ? `${dataTestId}-trigger` : 'hover-card-trigger',\n };\n\n const triggerElement = trigger ? (\n React.cloneElement(trigger, triggerProps)\n ) : (\n <span {...triggerProps} style={{ display: 'inline-block', ...triggerProps.style }}>\n {children}\n </span>\n );\n\n const padding = CONTENT_PADDING[variant] ?? 2;\n\n return (\n <>\n {triggerElement}\n <StyledPopover\n ref={ref}\n open={isOpen && !disabled}\n anchorEl={anchorEl}\n onClose={handleClose}\n anchorOrigin={getAnchorOrigin(placement)}\n transformOrigin={getTransformOrigin(placement)}\n {...cardHandlers}\n disableAutoFocus\n disableEnforceFocus\n disableRestoreFocus\n customAnimation={animation}\n slotProps={{ paper: { style: { pointerEvents: 'auto' } } }}\n {...rest}\n >\n <Box sx={{ position: 'relative' }}>\n {showArrow && <ArrowContainer placement={placement} offset={offset} />}\n <StyledCard\n customVariant={variant}\n glow={glow}\n pulse={pulse}\n animation={animation}\n data-testid={dataTestId || 'hover-card-content'}\n sx={(theme) => ({ maxWidth: capOf(theme, maxWidth), ...offsetMargin(theme, placement, offset) })}\n >\n <CardContent sx={{ p: padding, '&:last-child': { pb: padding } }}>\n <HoverCardContent\n loadingText={loadingText} variant={variant} title={title}\n description={description}\n avatar={avatar}\n loading={loading}\n loadingComponent={loadingComponent}\n dataTestId={dataTestId}\n >\n {children}\n </HoverCardContent>\n </CardContent>\n </StyledCard>\n </Box>\n </StyledPopover>\n </>\n );\n});\n\nHoverCard.displayName = 'HoverCard';\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/data-display/HoverCard/HoverCard.hooks.ts"],"sourcesContent":["import React from 'react';\n\ninterface HandlerInput {\n isTouchDevice: boolean;\n touchEnabled: boolean;\n enterDelay: number;\n openCard: (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>) => void;\n closeCard: () => void;\n exitTimeoutRef: React.MutableRefObject<number | undefined>;\n}\n\n/**\n * The pointer and touch handlers, over the open/close pair. Touch gets a\n * long-press because there is no hover to respond to; the card's own handlers\n * keep it open while the pointer is travelling onto it.\n */\nconst useHoverHandlers = ({\n isTouchDevice,\n touchEnabled,\n enterDelay,\n openCard,\n closeCard,\n exitTimeoutRef,\n}: HandlerInput) => {\n const [touchTimeout, setTouchTimeout] = React.useState<number>();\n\n /** A touch device with touch disabled has no hover to respond to. */\n const hoverIgnored = isTouchDevice && !touchEnabled;\n\n const cancelTouch = React.useCallback(() => {\n if (touchTimeout) {\n window.clearTimeout(touchTimeout);\n setTouchTimeout(undefined);\n }\n }, [touchTimeout]);\n\n React.useEffect(\n () => () => {\n if (touchTimeout) window.clearTimeout(touchTimeout);\n },\n [touchTimeout],\n );\n\n const triggerHandlers = {\n onMouseEnter: (event: React.MouseEvent<HTMLElement>) => {\n if (hoverIgnored) return;\n openCard(event);\n },\n onMouseLeave: () => {\n if (hoverIgnored) return;\n closeCard();\n },\n onTouchStart: (event: React.TouchEvent<HTMLElement>) => {\n if (!touchEnabled) return;\n if (touchTimeout) window.clearTimeout(touchTimeout);\n setTouchTimeout(window.setTimeout(() => openCard(event), enterDelay));\n },\n // End and cancel do the same thing: the press did not become a long press.\n onTouchEnd: cancelTouch,\n onTouchCancel: cancelTouch,\n };\n\n /** Moving onto the card keeps it open; leaving it starts the exit delay. */\n const cardHandlers = {\n onMouseEnter: () => {\n if (exitTimeoutRef.current) window.clearTimeout(exitTimeoutRef.current);\n },\n onMouseLeave: closeCard,\n };\n\n return { triggerHandlers, cardHandlers };\n};\n\n/** Escape dismisses the card while it is open. */\nconst useEscapeKey = (active: boolean, onEscape: () => void) => {\n React.useEffect(() => {\n if (!active) return;\n\n const handleEscape = (event: globalThis.KeyboardEvent) => {\n if (event.key === 'Escape') onEscape();\n };\n\n document.addEventListener('keydown', handleEscape);\n return () => document.removeEventListener('keydown', handleEscape);\n }, [active, onEscape]);\n};\n\ninterface HoverCardTimingInput {\n disabled: boolean;\n touchEnabled: boolean;\n enterDelay: number;\n exitDelay: number;\n onOpen?: () => void;\n onClose?: () => void;\n}\n\n/**\n * When the card is open, and the delays that decide it.\n *\n * Three timers are in play: the enter delay before opening, the exit delay\n * before closing (so the pointer can travel from the trigger onto the card\n * without dismissing it), and the long-press timer on touch. Each cancels the\n * others' pending work, which is why they live together.\n */\nexport const useHoverCard = ({\n disabled,\n touchEnabled,\n enterDelay,\n exitDelay,\n onOpen,\n onClose,\n}: HoverCardTimingInput) => {\n const [anchorEl, setAnchorEl] = React.useState<HTMLElement | null>(null);\n const [isOpen, setIsOpen] = React.useState(false);\n const [isTouchDevice, setIsTouchDevice] = React.useState(false);\n const enterTimeoutRef = React.useRef<number | undefined>(undefined);\n const exitTimeoutRef = React.useRef<number | undefined>(undefined);\n\n // Probed in an effect, not during render, so SSR and hydration stay intact.\n React.useEffect(() => {\n setIsTouchDevice('ontouchstart' in window);\n }, []);\n\n const openCard = React.useCallback(\n (event: React.MouseEvent<HTMLElement> | React.TouchEvent<HTMLElement>) => {\n if (disabled) return;\n\n if (exitTimeoutRef.current) {\n window.clearTimeout(exitTimeoutRef.current);\n }\n\n const target = event.currentTarget;\n enterTimeoutRef.current = window.setTimeout(() => {\n setAnchorEl(target);\n setIsOpen(true);\n onOpen?.();\n }, enterDelay);\n },\n [disabled, enterDelay, onOpen],\n );\n\n const closeCard = React.useCallback(() => {\n if (enterTimeoutRef.current) {\n window.clearTimeout(enterTimeoutRef.current);\n }\n\n exitTimeoutRef.current = window.setTimeout(() => {\n setIsOpen(false);\n setAnchorEl(null);\n onClose?.();\n }, exitDelay);\n }, [exitDelay, onClose]);\n\n const handleClose = React.useCallback(() => {\n setIsOpen(false);\n setAnchorEl(null);\n onClose?.();\n }, [onClose]);\n\n const { triggerHandlers, cardHandlers } = useHoverHandlers({\n isTouchDevice,\n touchEnabled,\n enterDelay,\n openCard,\n closeCard,\n exitTimeoutRef,\n });\n\n useEscapeKey(isOpen, handleClose);\n\n React.useEffect(\n () => () => {\n if (enterTimeoutRef.current) window.clearTimeout(enterTimeoutRef.current);\n if (exitTimeoutRef.current) window.clearTimeout(exitTimeoutRef.current);\n },\n [],\n );\n\n return { anchorEl, isOpen, handleClose, triggerHandlers, cardHandlers };\n};\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/form/Input/Input.tsx"],"sourcesContent":["import CircularProgress from '@mui/material/CircularProgress/index.js';\nimport InputAdornment from '@mui/material/InputAdornment/index.js';\nimport { styled, useTheme } from '@mui/material/styles/index.js';\nimport React from 'react';\n\nimport { INPUT_LOADING } from './Input.metrics';\nimport { TextFieldSlim } from './text-field-slim';\n\nimport {\n filledStyles,\n floatingLabelStyles,\n glowStyles,\n inputBaseStyles,\n inputRadiusStyles,\n muiVariantFor,\n outlinedStyles,\n pulseStyles,\n SIZE_MAP,\n} from './Input.styles';\nimport type { InputProps } from './Input.types';\nimport { splitTestId } from '../../../platform/test-id';\nimport { fieldControlStyles } from '../../../tokens/field-height';\nimport { rem } from '../../../tokens/relative';\nimport type { SizeValue } from '../../../tokens/vocabulary';\n\n/**\n * `TextFieldSlim`, not `TextField` — see `text-field-slim.tsx`. MUI's own\n * `TextField` imports `Select` unconditionally, and through it `Menu`,\n * `Popover`, `Modal` and seven more component modules, so every screen with one\n * text box shipped a dropdown it can never render. Same composition, same DOM,\n * same prop routing; the select branch is the only thing missing.\n */\nconst StyledTextField = styled(TextFieldSlim, {\n shouldForwardProp: (prop) =>\n !['customVariant', 'fieldSize', 'floating', 'glow', 'pulse', 'loading'].includes(prop as string),\n})<{\n customVariant?: InputProps['variant'];\n fieldSize: SizeValue;\n floating?: boolean;\n glow?: boolean;\n pulse?: boolean;\n loading?: boolean;\n}>(({ theme, customVariant, fieldSize, floating, glow, pulse, loading }) => ({\n position: 'relative',\n // The theme's field height for this size (outlined family, one line).\n ...fieldControlStyles(theme, fieldSize),\n opacity: loading ? INPUT_LOADING.opacity : 1,\n\n ...(glow ? glowStyles(theme) : {}),\n ...(pulse ? pulseStyles(theme, fieldSize) : {}),\n ...(floating ? floatingLabelStyles(theme) : {}),\n\n '& .MuiInputBase-root': {\n transition: 'all 0.3s ease',\n ...inputRadiusStyles(theme, customVariant),\n ...inputBaseStyles(theme, customVariant),\n },\n\n '& .MuiOutlinedInput-root': outlinedStyles(theme),\n '& .MuiFilledInput-root': filledStyles(theme),\n}));\n\n/** Only one adornment shows at a time: the spinner replaces the caller's while loading. */\nconst EndAdornment: React.FC<{ loading: boolean; endAdornment?: React.ReactNode }> = ({\n loading,\n endAdornment,\n}) => {\n const theme = useTheme();\n if (loading) {\n return (\n <InputAdornment position=\"end\">\n <CircularProgress size={rem(theme, INPUT_LOADING.spinnerSize)} />\n </InputAdornment>\n );\n }\n\n if (!endAdornment) return null;\n\n return <InputAdornment position=\"end\">{endAdornment}</InputAdornment>;\n};\n\n/** While loading the field is inert: no clicks, and disabled to assistive tech. */\nconst interactionProps = (\n loading: boolean,\n onClick: InputProps['onClick'],\n disabled?: boolean,\n) => ({\n disabled: loading || disabled,\n onClick: loading ? undefined : onClick,\n});\n\nexport const Input = React.forwardRef<HTMLInputElement, InputProps>(\n (\n {\n variant = 'outlined',\n size = 'md',\n label,\n error,\n helperText,\n startAdornment,\n endAdornment,\n fullWidth = true,\n floating = false,\n glow = false,\n pulse = false,\n loading = false,\n onClick,\n onFocus,\n onBlur,\n 'aria-label': ariaLabel,\n ...rest\n },\n ref,\n ) => {\n const { testId: dataTestId, rest: props } = splitTestId(rest);\n return (\n <StyledTextField\n ref={ref}\n variant={muiVariantFor(variant)}\n customVariant={variant}\n fieldSize={size}\n floating={floating}\n glow={glow}\n pulse={pulse}\n loading={loading}\n label={label}\n error={error}\n helperText={helperText}\n fullWidth={fullWidth}\n {...interactionProps(loading, onClick, props.disabled)}\n onFocus={onFocus}\n onBlur={onBlur}\n /*\n * `aria-label` has to ride `inputProps` to reach the `<input>` (FUT-755).\n * Spread with the rest it lands on the FormControl DIV that the text\n * field renders as its root, which carries no role — so the field kept\n * no accessible name, and a source grep saying \"this input is labelled\"\n * disagreed with the DOM. The reports search box and the block-title\n * inputs were both named in source and anonymous to a screen reader.\n */\n inputProps={{\n 'data-testid': dataTestId,\n ...(ariaLabel === undefined ? {} : { 'aria-label': ariaLabel }),\n }}\n InputProps={{\n startAdornment: startAdornment && (\n <InputAdornment position=\"start\">{startAdornment}</InputAdornment>\n ),\n endAdornment: <EndAdornment loading={loading} endAdornment={endAdornment} />,\n }}\n {...SIZE_MAP[size]}\n {...props}\n />\n );\n },\n);\n\nInput.displayName = 'Input';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,sBAAsB;AAC7B,OAAO,oBAAoB;AAC3B,SAAS,QAAQ,gBAAgB;AACjC,OAAO,WAAW;AAoEV;AAvCR,IAAM,kBAAkB,OAAO,eAAe;AAAA,EAC5C,mBAAmB,CAAC,SAClB,CAAC,CAAC,iBAAiB,aAAa,YAAY,QAAQ,SAAS,SAAS,EAAE,SAAS,IAAc;AACnG,CAAC,EAOE,CAAC,EAAE,OAAO,eAAe,WAAW,UAAU,MAAM,OAAO,QAAQ,OAAO;AAAA,EAC3E,UAAU;AAAA;AAAA,EAEV,GAAG,mBAAmB,OAAO,SAAS;AAAA,EACtC,SAAS,UAAU,cAAc,UAAU;AAAA,EAE3C,GAAI,OAAO,WAAW,KAAK,IAAI,CAAC;AAAA,EAChC,GAAI,QAAQ,YAAY,OAAO,SAAS,IAAI,CAAC;AAAA,EAC7C,GAAI,WAAW,oBAAoB,KAAK,IAAI,CAAC;AAAA,EAE7C,wBAAwB;AAAA,IACtB,YAAY;AAAA,IACZ,GAAG,kBAAkB,OAAO,aAAa;AAAA,IACzC,GAAG,gBAAgB,OAAO,aAAa;AAAA,EACzC;AAAA,EAEA,4BAA4B,eAAe,KAAK;AAAA,EAChD,0BAA0B,aAAa,KAAK;AAC9C,EAAE;AAGF,IAAM,eAA+E,CAAC;AAAA,EACpF;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AACvB,MAAI,SAAS;AACX,WACE,oBAAC,kBAAe,UAAS,OACvB,8BAAC,oBAAiB,MAAM,IAAI,OAAO,cAAc,WAAW,GAAG,GACjE;AAAA,EAEJ;AAEA,MAAI,CAAC,aAAc,QAAO;AAE1B,SAAO,oBAAC,kBAAe,UAAS,OAAO,wBAAa;AACtD;AAGA,IAAM,mBAAmB,CACvB,SACA,SACA,cACI;AAAA,EACJ,UAAU,WAAW;AAAA,EACrB,SAAS,UAAU,SAAY;AACjC;AAEO,IAAM,QAAQ,MAAM;AAAA,EACzB,CACE;AAAA,IACE,UAAU;AAAA,IACV,OAAO;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc;AAAA,IACd,GAAG;AAAA,EACL,GACA,QACG;AACH,UAAM,EAAE,QAAQ,YAAY,MAAM,MAAM,IAAI,YAAY,IAAI;AAC5D,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,SAAS,cAAc,OAAO;AAAA,QAC9B,eAAe;AAAA,QACf,WAAW;AAAA,QACX;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACC,GAAG,iBAAiB,SAAS,SAAS,MAAM,QAAQ;AAAA,QACrD;AAAA,QACA;AAAA,QASA,YAAY;AAAA,UACV,eAAe;AAAA,UACf,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,cAAc,UAAU;AAAA,QAC/D;AAAA,QACA,YAAY;AAAA,UACV,gBAAgB,kBACd,oBAAC,kBAAe,UAAS,SAAS,0BAAe;AAAA,UAEnD,cAAc,oBAAC,gBAAa,SAAkB,cAA4B;AAAA,QAC5E;AAAA,QACC,GAAG,SAAS,IAAI;AAAA,QAChB,GAAG;AAAA;AAAA,IACN;AAAA,EAEJ;AACF;AAEA,MAAM,cAAc;","names":[]}