@brycks/core-front 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/data/List/List.cjs +1 -1
- package/dist/components/data/List/List.cjs.map +1 -1
- package/dist/components/data/List/List.js +1 -1
- package/dist/components/data/List/List.js.map +1 -1
- package/dist/components/data/Table/Table.cjs +1 -1
- package/dist/components/data/Table/Table.cjs.map +1 -1
- package/dist/components/data/Table/Table.js +141 -124
- package/dist/components/data/Table/Table.js.map +1 -1
- package/dist/components/data/TreeView/TreeView.cjs +1 -1
- package/dist/components/data/TreeView/TreeView.cjs.map +1 -1
- package/dist/components/data/TreeView/TreeView.js +1 -1
- package/dist/components/data/TreeView/TreeView.js.map +1 -1
- package/dist/components/feedback/Alert/Alert.cjs +1 -1
- package/dist/components/feedback/Alert/Alert.cjs.map +1 -1
- package/dist/components/feedback/Alert/Alert.js +20 -19
- package/dist/components/feedback/Alert/Alert.js.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.cjs +2 -2
- package/dist/components/feedback/Drawer/Drawer.cjs.map +1 -1
- package/dist/components/feedback/Drawer/Drawer.js +58 -57
- package/dist/components/feedback/Drawer/Drawer.js.map +1 -1
- package/dist/components/feedback/Modal/Modal.cjs +1 -1
- package/dist/components/feedback/Modal/Modal.cjs.map +1 -1
- package/dist/components/feedback/Modal/Modal.js +63 -61
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/components/feedback/Popover/Popover.cjs +2 -2
- package/dist/components/feedback/Popover/Popover.cjs.map +1 -1
- package/dist/components/feedback/Popover/Popover.js +88 -79
- package/dist/components/feedback/Popover/Popover.js.map +1 -1
- package/dist/components/feedback/Toast/Toast.cjs +2 -2
- package/dist/components/feedback/Toast/Toast.cjs.map +1 -1
- package/dist/components/feedback/Toast/Toast.js +102 -93
- package/dist/components/feedback/Toast/Toast.js.map +1 -1
- package/dist/components/form/Combobox/Combobox.cjs +2 -2
- package/dist/components/form/Combobox/Combobox.cjs.map +1 -1
- package/dist/components/form/Combobox/Combobox.js +139 -139
- package/dist/components/form/Combobox/Combobox.js.map +1 -1
- package/dist/components/form/DateInput/DateInput.cjs +1 -1
- package/dist/components/form/DateInput/DateInput.cjs.map +1 -1
- package/dist/components/form/DateInput/DateInput.js +2 -2
- package/dist/components/form/DateInput/DateInput.js.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.cjs.map +1 -1
- package/dist/components/form/DateRangePicker/DateRangePicker.js +34 -34
- package/dist/components/form/DateRangePicker/DateRangePicker.js.map +1 -1
- package/dist/components/form/DropZone/DropZone.cjs +1 -1
- package/dist/components/form/DropZone/DropZone.cjs.map +1 -1
- package/dist/components/form/DropZone/DropZone.js +10 -10
- package/dist/components/form/DropZone/DropZone.js.map +1 -1
- package/dist/components/form/FileInput/FileInput.cjs +1 -1
- package/dist/components/form/FileInput/FileInput.cjs.map +1 -1
- package/dist/components/form/FileInput/FileInput.js +1 -1
- package/dist/components/form/FileInput/FileInput.js.map +1 -1
- package/dist/components/form/FormCard/FormCard.cjs +1 -1
- package/dist/components/form/FormCard/FormCard.cjs.map +1 -1
- package/dist/components/form/FormCard/FormCard.js +9 -9
- package/dist/components/form/FormCard/FormCard.js.map +1 -1
- package/dist/components/form/FormField/FormField.cjs +1 -1
- package/dist/components/form/FormField/FormField.cjs.map +1 -1
- package/dist/components/form/FormField/FormField.js +67 -55
- package/dist/components/form/FormField/FormField.js.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.cjs.map +1 -1
- package/dist/components/form/MultiSelect/MultiSelect.js +2 -3
- package/dist/components/form/MultiSelect/MultiSelect.js.map +1 -1
- package/dist/components/form/Radio/Radio.cjs +1 -1
- package/dist/components/form/Radio/Radio.cjs.map +1 -1
- package/dist/components/form/Radio/Radio.js +20 -20
- package/dist/components/form/Radio/Radio.js.map +1 -1
- package/dist/components/form/TagInput/TagInput.cjs +1 -1
- package/dist/components/form/TagInput/TagInput.cjs.map +1 -1
- package/dist/components/form/TagInput/TagInput.js +104 -102
- package/dist/components/form/TagInput/TagInput.js.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs +1 -1
- package/dist/components/form/TimePicker/TimePicker.cjs.map +1 -1
- package/dist/components/form/TimePicker/TimePicker.js +29 -30
- package/dist/components/form/TimePicker/TimePicker.js.map +1 -1
- package/dist/components/layout/Collapse/Collapse.cjs.map +1 -1
- package/dist/components/layout/Collapse/Collapse.js.map +1 -1
- package/dist/components/media/Image/Image.cjs +1 -1
- package/dist/components/media/Image/Image.cjs.map +1 -1
- package/dist/components/media/Image/Image.js +9 -9
- package/dist/components/media/Image/Image.js.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.cjs.map +1 -1
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js +6 -6
- package/dist/components/media/ImageThumbnail/ImageThumbnail.js.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs +1 -1
- package/dist/components/navigation/Accordion/Accordion.cjs.map +1 -1
- package/dist/components/navigation/Accordion/Accordion.js +0 -1
- package/dist/components/navigation/Accordion/Accordion.js.map +1 -1
- package/dist/components/navigation/Menu/Menu.cjs +1 -1
- package/dist/components/navigation/Menu/Menu.cjs.map +1 -1
- package/dist/components/navigation/Menu/Menu.js +87 -86
- package/dist/components/navigation/Menu/Menu.js.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs +1 -1
- package/dist/components/navigation/Pagination/Pagination.cjs.map +1 -1
- package/dist/components/navigation/Pagination/Pagination.js +107 -99
- package/dist/components/navigation/Pagination/Pagination.js.map +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs +1 -1
- package/dist/components/utility/Avatar/Avatar.cjs.map +1 -1
- package/dist/components/utility/Avatar/Avatar.js +10 -10
- package/dist/components/utility/Avatar/Avatar.js.map +1 -1
- package/dist/components/utility/Logo/Logo.cjs +1 -1
- package/dist/components/utility/Logo/Logo.cjs.map +1 -1
- package/dist/components/utility/Logo/Logo.js +10 -10
- package/dist/components/utility/Logo/Logo.js.map +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs +1 -1
- package/dist/design-system/themes/ThemeProvider.cjs.map +1 -1
- package/dist/design-system/themes/ThemeProvider.js +46 -46
- package/dist/design-system/themes/ThemeProvider.js.map +1 -1
- package/dist/design-system/tokens/zIndex.cjs +1 -1
- package/dist/design-system/tokens/zIndex.cjs.map +1 -1
- package/dist/design-system/tokens/zIndex.js +2 -0
- package/dist/design-system/tokens/zIndex.js.map +1 -1
- package/dist/feedback.d.ts +8 -0
- package/dist/form.d.ts +10 -0
- package/dist/index.d.ts +29 -0
- package/dist/navigation.d.ts +19 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.d.ts +2 -0
- package/package.json +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Collapse.js","sources":["../../../../src/components/layout/Collapse/Collapse.tsx"],"sourcesContent":["/**\n * Collapse Component\n *\n * A component for expandable/collapsible content with smooth animations.\n * Supports controlled and uncontrolled modes.\n *\n * @module components/layout/Collapse\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { durations, easings } from '../../../design-system'\n\nexport interface CollapseProps {\n /** Whether the content is expanded (controlled) */\n isOpen?: boolean\n /** Default expanded state (uncontrolled) */\n defaultIsOpen?: boolean\n /** Content to show when collapsed */\n children: ReactNode\n /** Animation duration in milliseconds */\n duration?: number\n /** Easing function */\n easing?: string\n /** Whether to animate on initial render */\n animateOnMount?: boolean\n /** Whether to unmount content when collapsed */\n unmountOnCollapse?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Collapse = forwardRef<HTMLDivElement, CollapseProps>(function Collapse(\n {\n isOpen: controlledIsOpen,\n defaultIsOpen = false,\n children,\n duration = durations.normal,\n easing = easings.easeOut,\n animateOnMount = false,\n unmountOnCollapse = false,\n className,\n testId,\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen)\n const [height, setHeight] = useState<number | 'auto'>(defaultIsOpen ? 'auto' : 0)\n const [isAnimating, setIsAnimating] = useState(false)\n const [shouldRender, setShouldRender] = useState(defaultIsOpen || !unmountOnCollapse)\n\n const contentRef = useRef<HTMLDivElement>(null)\n const isInitialRender = useRef(true)\n\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen\n\n // Sync internal state with controlled value changes\n useEffect(() => {\n if (controlledIsOpen !== undefined && controlledIsOpen !== internalIsOpen) {\n setInternalIsOpen(controlledIsOpen)\n }\n }, [controlledIsOpen, internalIsOpen])\n\n // Handle animation\n useEffect(() => {\n if (isInitialRender.current) {\n isInitialRender.current = false\n if (!animateOnMount) {\n setHeight(isOpen ? 'auto' : 0)\n setShouldRender(isOpen || !unmountOnCollapse)\n return\n }\n }\n\n const content = contentRef.current\n if (!content) return\n\n if (isOpen) {\n // Expanding\n setShouldRender(true)\n setIsAnimating(true)\n\n // Get the natural height\n const naturalHeight = content.scrollHeight\n\n // Start from 0\n setHeight(0)\n\n // Force reflow\n content.offsetHeight\n\n // Animate to natural height\n requestAnimationFrame(() => {\n setHeight(naturalHeight)\n })\n\n // After animation, set to auto\n const timer = setTimeout(() => {\n setHeight('auto')\n setIsAnimating(false)\n }, duration)\n\n return () => clearTimeout(timer)\n } else {\n // Collapsing\n setIsAnimating(true)\n\n // Get current height\n const currentHeight = content.scrollHeight\n setHeight(currentHeight)\n\n // Force reflow\n content.offsetHeight\n\n // Animate to 0\n requestAnimationFrame(() => {\n setHeight(0)\n })\n\n // After animation, optionally unmount\n const timer = setTimeout(() => {\n setIsAnimating(false)\n if (unmountOnCollapse) {\n setShouldRender(false)\n }\n }, duration)\n\n return () => clearTimeout(timer)\n }\n }, [isOpen, duration, animateOnMount, unmountOnCollapse])\n\n const containerStyle: CSSProperties = {\n overflow: 'hidden',\n height: height,\n transition: isAnimating ? `height ${duration}ms ${easing}` : undefined,\n willChange: isAnimating ? 'height' : undefined,\n }\n\n const contentStyle: CSSProperties = {\n // Prevent margin collapse\n display: 'flow-root',\n }\n\n if (!shouldRender && unmountOnCollapse) {\n return null\n }\n\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-collapse',\n isOpen && 'brycks-collapse--open',\n isAnimating && 'brycks-collapse--animating',\n className\n )}\n style={containerStyle}\n data-testid={testId}\n aria-hidden={!isOpen}\n >\n <div ref={contentRef} style={contentStyle}>\n {children}\n </div>\n </div>\n )\n})\n\nCollapse.displayName = 'Collapse'\n\n// Helper component for creating collapsible sections with header\nexport interface CollapsibleProps {\n /** Header content (always visible) */\n header: ReactNode\n /** Collapsible content */\n children: ReactNode\n /** Whether expanded (controlled) */\n isOpen?: boolean\n /** Default expanded state (uncontrolled) */\n defaultIsOpen?: boolean\n /** Callback when expanded state changes */\n onToggle?: (isOpen: boolean) => void\n /** Whether the collapsible is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Collapsible = forwardRef<HTMLDivElement, CollapsibleProps>(function Collapsible(\n {\n header,\n children,\n isOpen: controlledIsOpen,\n defaultIsOpen = false,\n onToggle,\n disabled = false,\n className,\n testId,\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen)\n\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen\n\n const handleToggle = useCallback(() => {\n if (disabled) return\n\n const newIsOpen = !isOpen\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(newIsOpen)\n }\n onToggle?.(newIsOpen)\n }, [disabled, isOpen, controlledIsOpen, onToggle])\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleToggle()\n }\n },\n [handleToggle]\n )\n\n const containerStyle: CSSProperties = {\n width: '100%',\n }\n\n const headerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n userSelect: 'none',\n }\n\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-collapsible',\n isOpen && 'brycks-collapsible--open',\n disabled && 'brycks-collapsible--disabled',\n className\n )}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-expanded={isOpen}\n aria-disabled={disabled}\n style={headerStyle}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n >\n {header}\n </div>\n <Collapse isOpen={isOpen}>\n {children}\n </Collapse>\n </div>\n )\n})\n\nCollapsible.displayName = 'Collapsible'\n"],"names":["Collapse","forwardRef","controlledIsOpen","defaultIsOpen","children","duration","durations","easing","easings","animateOnMount","unmountOnCollapse","className","testId","ref","internalIsOpen","setInternalIsOpen","useState","height","setHeight","isAnimating","setIsAnimating","shouldRender","setShouldRender","contentRef","useRef","isInitialRender","isOpen","useEffect","content","naturalHeight","timer","currentHeight","containerStyle","contentStyle","jsx","cx","Collapsible","header","onToggle","disabled","handleToggle","useCallback","newIsOpen","handleKeyDown","e","headerStyle","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Collapse.js","sources":["../../../../src/components/layout/Collapse/Collapse.tsx"],"sourcesContent":["/**\n * Collapse Component\n *\n * A component for expandable/collapsible content with smooth animations.\n * Supports controlled and uncontrolled modes.\n *\n * @module components/layout/Collapse\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n useRef,\n useEffect,\n type CSSProperties,\n type ReactNode,\n} from 'react'\nimport { cx } from '../../../utils/styles'\nimport { durations, easings } from '../../../design-system'\n\nexport interface CollapseProps {\n /** Whether the content is expanded (controlled) */\n isOpen?: boolean\n /** Default expanded state (uncontrolled) */\n defaultIsOpen?: boolean\n /** Content to show when collapsed */\n children: ReactNode\n /** Animation duration in milliseconds */\n duration?: number\n /** Easing function */\n easing?: string\n /** Whether to animate on initial render */\n animateOnMount?: boolean\n /** Whether to unmount content when collapsed */\n unmountOnCollapse?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Collapse = forwardRef<HTMLDivElement, CollapseProps>(function Collapse(\n {\n isOpen: controlledIsOpen,\n defaultIsOpen = false,\n children,\n duration = durations.normal,\n easing = easings.easeOut,\n animateOnMount = false,\n unmountOnCollapse = false,\n className,\n testId,\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen)\n const [height, setHeight] = useState<number | 'auto'>(defaultIsOpen ? 'auto' : 0)\n const [isAnimating, setIsAnimating] = useState(false)\n const [shouldRender, setShouldRender] = useState(defaultIsOpen || !unmountOnCollapse)\n\n const contentRef = useRef<HTMLDivElement>(null)\n const isInitialRender = useRef(true)\n\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen\n\n // Sync internal state with controlled value changes\n useEffect(() => {\n if (controlledIsOpen !== undefined && controlledIsOpen !== internalIsOpen) {\n setInternalIsOpen(controlledIsOpen)\n }\n }, [controlledIsOpen, internalIsOpen])\n\n // Handle animation\n useEffect(() => {\n if (isInitialRender.current) {\n isInitialRender.current = false\n if (!animateOnMount) {\n setHeight(isOpen ? 'auto' : 0)\n setShouldRender(isOpen || !unmountOnCollapse)\n return\n }\n }\n\n const content = contentRef.current\n if (!content) return\n\n if (isOpen) {\n // Expanding\n setShouldRender(true)\n setIsAnimating(true)\n\n // Get the natural height\n const naturalHeight = content.scrollHeight\n\n // Start from 0\n setHeight(0)\n\n // Force reflow\n void content.offsetHeight\n\n // Animate to natural height\n requestAnimationFrame(() => {\n setHeight(naturalHeight)\n })\n\n // After animation, set to auto\n const timer = setTimeout(() => {\n setHeight('auto')\n setIsAnimating(false)\n }, duration)\n\n return () => clearTimeout(timer)\n } else {\n // Collapsing\n setIsAnimating(true)\n\n // Get current height\n const currentHeight = content.scrollHeight\n setHeight(currentHeight)\n\n // Force reflow\n void content.offsetHeight\n\n // Animate to 0\n requestAnimationFrame(() => {\n setHeight(0)\n })\n\n // After animation, optionally unmount\n const timer = setTimeout(() => {\n setIsAnimating(false)\n if (unmountOnCollapse) {\n setShouldRender(false)\n }\n }, duration)\n\n return () => clearTimeout(timer)\n }\n }, [isOpen, duration, animateOnMount, unmountOnCollapse])\n\n const containerStyle: CSSProperties = {\n overflow: 'hidden',\n height: height,\n transition: isAnimating ? `height ${duration}ms ${easing}` : undefined,\n willChange: isAnimating ? 'height' : undefined,\n }\n\n const contentStyle: CSSProperties = {\n // Prevent margin collapse\n display: 'flow-root',\n }\n\n if (!shouldRender && unmountOnCollapse) {\n return null\n }\n\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-collapse',\n isOpen && 'brycks-collapse--open',\n isAnimating && 'brycks-collapse--animating',\n className\n )}\n style={containerStyle}\n data-testid={testId}\n aria-hidden={!isOpen}\n >\n <div ref={contentRef} style={contentStyle}>\n {children}\n </div>\n </div>\n )\n})\n\nCollapse.displayName = 'Collapse'\n\n// Helper component for creating collapsible sections with header\nexport interface CollapsibleProps {\n /** Header content (always visible) */\n header: ReactNode\n /** Collapsible content */\n children: ReactNode\n /** Whether expanded (controlled) */\n isOpen?: boolean\n /** Default expanded state (uncontrolled) */\n defaultIsOpen?: boolean\n /** Callback when expanded state changes */\n onToggle?: (isOpen: boolean) => void\n /** Whether the collapsible is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Collapsible = forwardRef<HTMLDivElement, CollapsibleProps>(function Collapsible(\n {\n header,\n children,\n isOpen: controlledIsOpen,\n defaultIsOpen = false,\n onToggle,\n disabled = false,\n className,\n testId,\n },\n ref\n) {\n const [internalIsOpen, setInternalIsOpen] = useState(defaultIsOpen)\n\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : internalIsOpen\n\n const handleToggle = useCallback(() => {\n if (disabled) return\n\n const newIsOpen = !isOpen\n if (controlledIsOpen === undefined) {\n setInternalIsOpen(newIsOpen)\n }\n onToggle?.(newIsOpen)\n }, [disabled, isOpen, controlledIsOpen, onToggle])\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n handleToggle()\n }\n },\n [handleToggle]\n )\n\n const containerStyle: CSSProperties = {\n width: '100%',\n }\n\n const headerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n width: '100%',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n userSelect: 'none',\n }\n\n return (\n <div\n ref={ref}\n className={cx(\n 'brycks-collapsible',\n isOpen && 'brycks-collapsible--open',\n disabled && 'brycks-collapsible--disabled',\n className\n )}\n style={containerStyle}\n data-testid={testId}\n >\n <div\n role=\"button\"\n tabIndex={disabled ? -1 : 0}\n aria-expanded={isOpen}\n aria-disabled={disabled}\n style={headerStyle}\n onClick={handleToggle}\n onKeyDown={handleKeyDown}\n >\n {header}\n </div>\n <Collapse isOpen={isOpen}>\n {children}\n </Collapse>\n </div>\n )\n})\n\nCollapsible.displayName = 'Collapsible'\n"],"names":["Collapse","forwardRef","controlledIsOpen","defaultIsOpen","children","duration","durations","easing","easings","animateOnMount","unmountOnCollapse","className","testId","ref","internalIsOpen","setInternalIsOpen","useState","height","setHeight","isAnimating","setIsAnimating","shouldRender","setShouldRender","contentRef","useRef","isInitialRender","isOpen","useEffect","content","naturalHeight","timer","currentHeight","containerStyle","contentStyle","jsx","cx","Collapsible","header","onToggle","disabled","handleToggle","useCallback","newIsOpen","handleKeyDown","e","headerStyle","jsxs"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),u=require("react"),h=require("../../../utils/styles.cjs"),N={none:"0",sm:"var(--brycks-radius-sm)",md:"var(--brycks-radius-md)",lg:"var(--brycks-radius-lg)",xl:"var(--brycks-radius-xl)",full:"var(--brycks-radius-full)"};function M(e){if(e===void 0)return;if(typeof e=="number")return e;const o=e.split(/[:/]/);if(o.length===2){const n=parseFloat(o[0]),s=parseFloat(o[1]);if(!isNaN(n)&&!isNaN(s)&&s!==0)return n/s}const r=parseFloat(e);return isNaN(r)?void 0:r}const S=u.forwardRef(function({src:o,alt:r,aspectRatio:n,fit:s="cover",loading:R="lazy",fallback:d,placeholder:c,radius:C="none",showBackground:F=!0,onLoad:p,onError:k,className:g,style:y,testId:m,...f},q){const[i,x]=u.useState("loading"),I=u.useCallback(v=>{x("loaded"),p?.(v)},[p]),B=u.useCallback(v=>{x("error"),k?.(v)},[k]),a=M(n),l=N[C]??N.none,b={position:"relative",overflow:"hidden",borderRadius:l,backgroundColor:F&&i==="loading"?"var(--brycks-background-muted)":void 0,...a?{width:"100%",paddingBottom:`${1/a*100}%`}:{}},j={display:"block",objectFit:s,borderRadius:l,...a?{position:"absolute",top:0,left:0,width:"100%",height:"100%"}:{width:y?.width??"100%",height:y?.height??"auto"},opacity:i==="loaded"?1:0,transition:"opacity var(--brycks-duration-normal, 200ms) var(--brycks-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("react/jsx-runtime"),u=require("react"),h=require("../../../utils/styles.cjs"),N={none:"0",sm:"var(--brycks-radius-sm)",md:"var(--brycks-radius-md)",lg:"var(--brycks-radius-lg)",xl:"var(--brycks-radius-xl)",full:"var(--brycks-radius-full)"};function M(e){if(e===void 0)return;if(typeof e=="number")return e;const o=e.split(/[:/]/);if(o.length===2){const n=parseFloat(o[0]),s=parseFloat(o[1]);if(!isNaN(n)&&!isNaN(s)&&s!==0)return n/s}const r=parseFloat(e);return isNaN(r)?void 0:r}const S=u.forwardRef(function({src:o,alt:r,aspectRatio:n,fit:s="cover",loading:R="lazy",fallback:d,placeholder:c,radius:C="none",showBackground:F=!0,onLoad:p,onError:k,className:g,style:y,testId:m,...f},q){const[i,x]=u.useState("loading"),I=u.useCallback(v=>{x("loaded"),p?.(v)},[p]),B=u.useCallback(v=>{x("error"),k?.(v)},[k]),a=M(n),l=N[C]??N.none,b={position:"relative",overflow:"hidden",borderRadius:l,backgroundColor:F&&i==="loading"?"var(--brycks-background-muted)":void 0,...a?{width:"100%",paddingBottom:`${1/a*100}%`}:{}},j={display:"block",objectFit:s,borderRadius:l,...a?{position:"absolute",top:0,left:0,width:"100%",height:"100%"}:{width:y?.width??"100%",height:y?.height??"auto"},opacity:i==="loaded"?1:0,transition:"opacity var(--brycks-duration-normal, 200ms) var(--brycks-ease-out, ease-out)",...y},w={position:"absolute",top:0,left:0,right:0,bottom:0,display:"flex",alignItems:"center",justifyContent:"center",borderRadius:l};return i==="error"?typeof d=="string"?t.jsx("div",{className:h.cx("brycks-image","brycks-image--fallback",g),style:b,"data-testid":m,children:t.jsx("img",{src:d,alt:r,style:{...j,opacity:1},...f})}):t.jsxs("div",{className:h.cx("brycks-image","brycks-image--error",g),style:{...b,backgroundColor:"var(--brycks-background-muted)"},"data-testid":m,role:"img","aria-label":r,children:[a&&t.jsx("div",{style:{paddingBottom:`${1/a*100}%`}}),d&&t.jsx("div",{style:w,children:d})]}):t.jsxs("div",{className:h.cx("brycks-image",i==="loading"&&"brycks-image--loading",i==="loaded"&&"brycks-image--loaded",g),style:a?b:{position:"relative",borderRadius:l},"data-testid":m,children:[i==="loading"&&c&&t.jsx("div",{style:w,children:typeof c=="string"?t.jsx("img",{src:c,alt:"","aria-hidden":"true",style:{width:"100%",height:"100%",objectFit:s,filter:"blur(10px)",transform:"scale(1.1)"}}):c}),t.jsx("img",{ref:q,src:o,alt:r,loading:R,onLoad:I,onError:B,style:j,...f})]})});S.displayName="Image";exports.Image=S;
|
|
2
2
|
//# sourceMappingURL=Image.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.cjs","sources":["../../../../src/components/media/Image/Image.tsx"],"sourcesContent":["/**\r\n * Image Component\r\n *\r\n * Responsive image with lazy loading, fallback support, and aspect ratio control.\r\n * Follows accessibility best practices and design system conventions.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useState,\r\n useCallback,\r\n type CSSProperties,\r\n type ImgHTMLAttributes,\r\n type ReactNode,\r\n type SyntheticEvent,\r\n} from 'react'\r\nimport { cx } from '../../../utils/styles'\r\n\r\nexport type ImageFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\r\nexport type ImageLoading = 'lazy' | 'eager'\r\n\r\nexport interface ImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'placeholder'> {\r\n /** Image source URL */\r\n src: string\r\n /** Alternative text for accessibility (required) */\r\n alt: string\r\n /** Aspect ratio (width/height). If set, maintains ratio */\r\n aspectRatio?: number | string\r\n /** How the image should fit within its container */\r\n fit?: ImageFit\r\n /** Loading strategy */\r\n loading?: ImageLoading\r\n /** Fallback content or URL when image fails to load */\r\n fallback?: ReactNode | string\r\n /** Placeholder shown while loading */\r\n placeholder?: ReactNode | string\r\n /** Border radius using design tokens */\r\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n /** Whether to show a subtle background while loading */\r\n showBackground?: boolean\r\n /** Callback when image loads successfully */\r\n onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Callback when image fails to load */\r\n onError?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n}\r\n\r\nconst radiusMap: Record<string, string> = {\r\n none: '0',\r\n sm: 'var(--brycks-radius-sm)',\r\n md: 'var(--brycks-radius-md)',\r\n lg: 'var(--brycks-radius-lg)',\r\n xl: 'var(--brycks-radius-xl)',\r\n full: 'var(--brycks-radius-full)',\r\n}\r\n\r\nfunction parseAspectRatio(ratio: number | string | undefined): number | undefined {\r\n if (ratio === undefined) return undefined\r\n if (typeof ratio === 'number') return ratio\r\n\r\n // Handle string formats like \"16:9\" or \"16/9\"\r\n const parts = ratio.split(/[:/]/)\r\n if (parts.length === 2) {\r\n const width = parseFloat(parts[0])\r\n const height = parseFloat(parts[1])\r\n if (!isNaN(width) && !isNaN(height) && height !== 0) {\r\n return width / height\r\n }\r\n }\r\n\r\n const parsed = parseFloat(ratio)\r\n return isNaN(parsed) ? undefined : parsed\r\n}\r\n\r\nexport const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\r\n {\r\n src,\r\n alt,\r\n aspectRatio,\r\n fit = 'cover',\r\n loading = 'lazy',\r\n fallback,\r\n placeholder,\r\n radius = 'none',\r\n showBackground = true,\r\n onLoad,\r\n onError,\r\n className,\r\n style,\r\n testId,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\r\n\r\n const handleLoad = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('loaded')\r\n onLoad?.(event)\r\n },\r\n [onLoad]\r\n )\r\n\r\n const handleError = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('error')\r\n onError?.(event)\r\n },\r\n [onError]\r\n )\r\n\r\n const parsedRatio = parseAspectRatio(aspectRatio)\r\n const borderRadius = radiusMap[radius] ?? radiusMap.none\r\n\r\n // Container styles for aspect ratio support\r\n const containerStyle: CSSProperties = {\r\n position: 'relative',\r\n overflow: 'hidden',\r\n borderRadius,\r\n backgroundColor:\r\n showBackground && status === 'loading'\r\n ? 'var(--brycks-background-muted)'\r\n : undefined,\r\n ...(parsedRatio\r\n ? {\r\n width: '100%',\r\n paddingBottom: `${(1 / parsedRatio) * 100}%`,\r\n }\r\n : {}),\r\n }\r\n\r\n const imageStyle: CSSProperties = {\r\n display: 'block',\r\n objectFit: fit,\r\n borderRadius,\r\n ...(parsedRatio\r\n ? {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n }\r\n : {\r\n width: style?.width ?? '100%',\r\n height: style?.height ?? 'auto',\r\n }),\r\n opacity: status === 'loaded' ? 1 : 0,\r\n transition: 'opacity var(--brycks-duration-normal, 200ms) var(--brycks-easing-out, ease-out)',\r\n ...style,\r\n }\r\n\r\n const overlayStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n borderRadius,\r\n }\r\n\r\n // Render fallback content\r\n if (status === 'error') {\r\n if (typeof fallback === 'string') {\r\n // Fallback is an image URL\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--fallback', className)}\r\n style={containerStyle}\r\n data-testid={testId}\r\n >\r\n <img\r\n src={fallback}\r\n alt={alt}\r\n style={{\r\n ...imageStyle,\r\n opacity: 1,\r\n }}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n // Fallback is a ReactNode\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--error', className)}\r\n style={{\r\n ...containerStyle,\r\n backgroundColor: 'var(--brycks-background-muted)',\r\n }}\r\n data-testid={testId}\r\n role=\"img\"\r\n aria-label={alt}\r\n >\r\n {parsedRatio && <div style={{ paddingBottom: `${(1 / parsedRatio) * 100}%` }} />}\r\n {fallback && <div style={overlayStyle}>{fallback}</div>}\r\n </div>\r\n )\r\n }\r\n\r\n // Render image with optional placeholder\r\n return (\r\n <div\r\n className={cx(\r\n 'brycks-image',\r\n status === 'loading' && 'brycks-image--loading',\r\n status === 'loaded' && 'brycks-image--loaded',\r\n className\r\n )}\r\n style={parsedRatio ? containerStyle : { position: 'relative', borderRadius }}\r\n data-testid={testId}\r\n >\r\n {/* Placeholder */}\r\n {status === 'loading' && placeholder && (\r\n <div style={overlayStyle}>\r\n {typeof placeholder === 'string' ? (\r\n <img\r\n src={placeholder}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: fit,\r\n filter: 'blur(10px)',\r\n transform: 'scale(1.1)',\r\n }}\r\n />\r\n ) : (\r\n placeholder\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Main image */}\r\n <img\r\n ref={ref}\r\n src={src}\r\n alt={alt}\r\n loading={loading}\r\n onLoad={handleLoad}\r\n onError={handleError}\r\n style={imageStyle}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n})\r\n\r\nImage.displayName = 'Image'\r\n"],"names":["radiusMap","parseAspectRatio","ratio","parts","width","height","parsed","Image","forwardRef","src","alt","aspectRatio","fit","loading","fallback","placeholder","radius","showBackground","onLoad","onError","className","style","testId","props","ref","status","setStatus","useState","handleLoad","useCallback","event","handleError","parsedRatio","borderRadius","containerStyle","imageStyle","overlayStyle","jsx","cx","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Image.cjs","sources":["../../../../src/components/media/Image/Image.tsx"],"sourcesContent":["/**\r\n * Image Component\r\n *\r\n * Responsive image with lazy loading, fallback support, and aspect ratio control.\r\n * Follows accessibility best practices and design system conventions.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useState,\r\n useCallback,\r\n type CSSProperties,\r\n type ImgHTMLAttributes,\r\n type ReactNode,\r\n type SyntheticEvent,\r\n} from 'react'\r\nimport { cx } from '../../../utils/styles'\r\n\r\nexport type ImageFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\r\nexport type ImageLoading = 'lazy' | 'eager'\r\n\r\nexport interface ImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'placeholder'> {\r\n /** Image source URL */\r\n src: string\r\n /** Alternative text for accessibility (required) */\r\n alt: string\r\n /** Aspect ratio (width/height). If set, maintains ratio */\r\n aspectRatio?: number | string\r\n /** How the image should fit within its container */\r\n fit?: ImageFit\r\n /** Loading strategy */\r\n loading?: ImageLoading\r\n /** Fallback content or URL when image fails to load */\r\n fallback?: ReactNode | string\r\n /** Placeholder shown while loading */\r\n placeholder?: ReactNode | string\r\n /** Border radius using design tokens */\r\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n /** Whether to show a subtle background while loading */\r\n showBackground?: boolean\r\n /** Callback when image loads successfully */\r\n onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Callback when image fails to load */\r\n onError?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n}\r\n\r\nconst radiusMap: Record<string, string> = {\r\n none: '0',\r\n sm: 'var(--brycks-radius-sm)',\r\n md: 'var(--brycks-radius-md)',\r\n lg: 'var(--brycks-radius-lg)',\r\n xl: 'var(--brycks-radius-xl)',\r\n full: 'var(--brycks-radius-full)',\r\n}\r\n\r\nfunction parseAspectRatio(ratio: number | string | undefined): number | undefined {\r\n if (ratio === undefined) return undefined\r\n if (typeof ratio === 'number') return ratio\r\n\r\n // Handle string formats like \"16:9\" or \"16/9\"\r\n const parts = ratio.split(/[:/]/)\r\n if (parts.length === 2) {\r\n const width = parseFloat(parts[0])\r\n const height = parseFloat(parts[1])\r\n if (!isNaN(width) && !isNaN(height) && height !== 0) {\r\n return width / height\r\n }\r\n }\r\n\r\n const parsed = parseFloat(ratio)\r\n return isNaN(parsed) ? undefined : parsed\r\n}\r\n\r\nexport const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\r\n {\r\n src,\r\n alt,\r\n aspectRatio,\r\n fit = 'cover',\r\n loading = 'lazy',\r\n fallback,\r\n placeholder,\r\n radius = 'none',\r\n showBackground = true,\r\n onLoad,\r\n onError,\r\n className,\r\n style,\r\n testId,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\r\n\r\n const handleLoad = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('loaded')\r\n onLoad?.(event)\r\n },\r\n [onLoad]\r\n )\r\n\r\n const handleError = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('error')\r\n onError?.(event)\r\n },\r\n [onError]\r\n )\r\n\r\n const parsedRatio = parseAspectRatio(aspectRatio)\r\n const borderRadius = radiusMap[radius] ?? radiusMap.none\r\n\r\n // Container styles for aspect ratio support\r\n const containerStyle: CSSProperties = {\r\n position: 'relative',\r\n overflow: 'hidden',\r\n borderRadius,\r\n backgroundColor:\r\n showBackground && status === 'loading'\r\n ? 'var(--brycks-background-muted)'\r\n : undefined,\r\n ...(parsedRatio\r\n ? {\r\n width: '100%',\r\n paddingBottom: `${(1 / parsedRatio) * 100}%`,\r\n }\r\n : {}),\r\n }\r\n\r\n const imageStyle: CSSProperties = {\r\n display: 'block',\r\n objectFit: fit,\r\n borderRadius,\r\n ...(parsedRatio\r\n ? {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n }\r\n : {\r\n width: style?.width ?? '100%',\r\n height: style?.height ?? 'auto',\r\n }),\r\n opacity: status === 'loaded' ? 1 : 0,\r\n transition: 'opacity var(--brycks-duration-normal, 200ms) var(--brycks-ease-out, ease-out)',\r\n ...style,\r\n }\r\n\r\n const overlayStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n borderRadius,\r\n }\r\n\r\n // Render fallback content\r\n if (status === 'error') {\r\n if (typeof fallback === 'string') {\r\n // Fallback is an image URL\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--fallback', className)}\r\n style={containerStyle}\r\n data-testid={testId}\r\n >\r\n <img\r\n src={fallback}\r\n alt={alt}\r\n style={{\r\n ...imageStyle,\r\n opacity: 1,\r\n }}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n // Fallback is a ReactNode\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--error', className)}\r\n style={{\r\n ...containerStyle,\r\n backgroundColor: 'var(--brycks-background-muted)',\r\n }}\r\n data-testid={testId}\r\n role=\"img\"\r\n aria-label={alt}\r\n >\r\n {parsedRatio && <div style={{ paddingBottom: `${(1 / parsedRatio) * 100}%` }} />}\r\n {fallback && <div style={overlayStyle}>{fallback}</div>}\r\n </div>\r\n )\r\n }\r\n\r\n // Render image with optional placeholder\r\n return (\r\n <div\r\n className={cx(\r\n 'brycks-image',\r\n status === 'loading' && 'brycks-image--loading',\r\n status === 'loaded' && 'brycks-image--loaded',\r\n className\r\n )}\r\n style={parsedRatio ? containerStyle : { position: 'relative', borderRadius }}\r\n data-testid={testId}\r\n >\r\n {/* Placeholder */}\r\n {status === 'loading' && placeholder && (\r\n <div style={overlayStyle}>\r\n {typeof placeholder === 'string' ? (\r\n <img\r\n src={placeholder}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: fit,\r\n filter: 'blur(10px)',\r\n transform: 'scale(1.1)',\r\n }}\r\n />\r\n ) : (\r\n placeholder\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Main image */}\r\n <img\r\n ref={ref}\r\n src={src}\r\n alt={alt}\r\n loading={loading}\r\n onLoad={handleLoad}\r\n onError={handleError}\r\n style={imageStyle}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n})\r\n\r\nImage.displayName = 'Image'\r\n"],"names":["radiusMap","parseAspectRatio","ratio","parts","width","height","parsed","Image","forwardRef","src","alt","aspectRatio","fit","loading","fallback","placeholder","radius","showBackground","onLoad","onError","className","style","testId","props","ref","status","setStatus","useState","handleLoad","useCallback","event","handleError","parsedRatio","borderRadius","containerStyle","imageStyle","overlayStyle","jsx","cx","jsxs"],"mappings":"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"}
|
|
@@ -33,8 +33,8 @@ const L = z(function({
|
|
|
33
33
|
showBackground: R = !0,
|
|
34
34
|
onLoad: h,
|
|
35
35
|
onError: v,
|
|
36
|
-
className:
|
|
37
|
-
style:
|
|
36
|
+
className: u,
|
|
37
|
+
style: g,
|
|
38
38
|
testId: y,
|
|
39
39
|
...f
|
|
40
40
|
}, B) {
|
|
@@ -68,12 +68,12 @@ const L = z(function({
|
|
|
68
68
|
width: "100%",
|
|
69
69
|
height: "100%"
|
|
70
70
|
} : {
|
|
71
|
-
width:
|
|
72
|
-
height:
|
|
71
|
+
width: g?.width ?? "100%",
|
|
72
|
+
height: g?.height ?? "auto"
|
|
73
73
|
},
|
|
74
74
|
opacity: o === "loaded" ? 1 : 0,
|
|
75
|
-
transition: "opacity var(--brycks-duration-normal, 200ms) var(--brycks-
|
|
76
|
-
...
|
|
75
|
+
transition: "opacity var(--brycks-duration-normal, 200ms) var(--brycks-ease-out, ease-out)",
|
|
76
|
+
...g
|
|
77
77
|
}, x = {
|
|
78
78
|
position: "absolute",
|
|
79
79
|
top: 0,
|
|
@@ -88,7 +88,7 @@ const L = z(function({
|
|
|
88
88
|
return o === "error" ? typeof d == "string" ? /* @__PURE__ */ t(
|
|
89
89
|
"div",
|
|
90
90
|
{
|
|
91
|
-
className: p("brycks-image", "brycks-image--fallback",
|
|
91
|
+
className: p("brycks-image", "brycks-image--fallback", u),
|
|
92
92
|
style: m,
|
|
93
93
|
"data-testid": y,
|
|
94
94
|
children: /* @__PURE__ */ t(
|
|
@@ -107,7 +107,7 @@ const L = z(function({
|
|
|
107
107
|
) : /* @__PURE__ */ N(
|
|
108
108
|
"div",
|
|
109
109
|
{
|
|
110
|
-
className: p("brycks-image", "brycks-image--error",
|
|
110
|
+
className: p("brycks-image", "brycks-image--error", u),
|
|
111
111
|
style: {
|
|
112
112
|
...m,
|
|
113
113
|
backgroundColor: "var(--brycks-background-muted)"
|
|
@@ -127,7 +127,7 @@ const L = z(function({
|
|
|
127
127
|
"brycks-image",
|
|
128
128
|
o === "loading" && "brycks-image--loading",
|
|
129
129
|
o === "loaded" && "brycks-image--loaded",
|
|
130
|
-
|
|
130
|
+
u
|
|
131
131
|
),
|
|
132
132
|
style: a ? m : { position: "relative", borderRadius: c },
|
|
133
133
|
"data-testid": y,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.js","sources":["../../../../src/components/media/Image/Image.tsx"],"sourcesContent":["/**\r\n * Image Component\r\n *\r\n * Responsive image with lazy loading, fallback support, and aspect ratio control.\r\n * Follows accessibility best practices and design system conventions.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useState,\r\n useCallback,\r\n type CSSProperties,\r\n type ImgHTMLAttributes,\r\n type ReactNode,\r\n type SyntheticEvent,\r\n} from 'react'\r\nimport { cx } from '../../../utils/styles'\r\n\r\nexport type ImageFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\r\nexport type ImageLoading = 'lazy' | 'eager'\r\n\r\nexport interface ImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'placeholder'> {\r\n /** Image source URL */\r\n src: string\r\n /** Alternative text for accessibility (required) */\r\n alt: string\r\n /** Aspect ratio (width/height). If set, maintains ratio */\r\n aspectRatio?: number | string\r\n /** How the image should fit within its container */\r\n fit?: ImageFit\r\n /** Loading strategy */\r\n loading?: ImageLoading\r\n /** Fallback content or URL when image fails to load */\r\n fallback?: ReactNode | string\r\n /** Placeholder shown while loading */\r\n placeholder?: ReactNode | string\r\n /** Border radius using design tokens */\r\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n /** Whether to show a subtle background while loading */\r\n showBackground?: boolean\r\n /** Callback when image loads successfully */\r\n onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Callback when image fails to load */\r\n onError?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n}\r\n\r\nconst radiusMap: Record<string, string> = {\r\n none: '0',\r\n sm: 'var(--brycks-radius-sm)',\r\n md: 'var(--brycks-radius-md)',\r\n lg: 'var(--brycks-radius-lg)',\r\n xl: 'var(--brycks-radius-xl)',\r\n full: 'var(--brycks-radius-full)',\r\n}\r\n\r\nfunction parseAspectRatio(ratio: number | string | undefined): number | undefined {\r\n if (ratio === undefined) return undefined\r\n if (typeof ratio === 'number') return ratio\r\n\r\n // Handle string formats like \"16:9\" or \"16/9\"\r\n const parts = ratio.split(/[:/]/)\r\n if (parts.length === 2) {\r\n const width = parseFloat(parts[0])\r\n const height = parseFloat(parts[1])\r\n if (!isNaN(width) && !isNaN(height) && height !== 0) {\r\n return width / height\r\n }\r\n }\r\n\r\n const parsed = parseFloat(ratio)\r\n return isNaN(parsed) ? undefined : parsed\r\n}\r\n\r\nexport const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\r\n {\r\n src,\r\n alt,\r\n aspectRatio,\r\n fit = 'cover',\r\n loading = 'lazy',\r\n fallback,\r\n placeholder,\r\n radius = 'none',\r\n showBackground = true,\r\n onLoad,\r\n onError,\r\n className,\r\n style,\r\n testId,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\r\n\r\n const handleLoad = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('loaded')\r\n onLoad?.(event)\r\n },\r\n [onLoad]\r\n )\r\n\r\n const handleError = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('error')\r\n onError?.(event)\r\n },\r\n [onError]\r\n )\r\n\r\n const parsedRatio = parseAspectRatio(aspectRatio)\r\n const borderRadius = radiusMap[radius] ?? radiusMap.none\r\n\r\n // Container styles for aspect ratio support\r\n const containerStyle: CSSProperties = {\r\n position: 'relative',\r\n overflow: 'hidden',\r\n borderRadius,\r\n backgroundColor:\r\n showBackground && status === 'loading'\r\n ? 'var(--brycks-background-muted)'\r\n : undefined,\r\n ...(parsedRatio\r\n ? {\r\n width: '100%',\r\n paddingBottom: `${(1 / parsedRatio) * 100}%`,\r\n }\r\n : {}),\r\n }\r\n\r\n const imageStyle: CSSProperties = {\r\n display: 'block',\r\n objectFit: fit,\r\n borderRadius,\r\n ...(parsedRatio\r\n ? {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n }\r\n : {\r\n width: style?.width ?? '100%',\r\n height: style?.height ?? 'auto',\r\n }),\r\n opacity: status === 'loaded' ? 1 : 0,\r\n transition: 'opacity var(--brycks-duration-normal, 200ms) var(--brycks-easing-out, ease-out)',\r\n ...style,\r\n }\r\n\r\n const overlayStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n borderRadius,\r\n }\r\n\r\n // Render fallback content\r\n if (status === 'error') {\r\n if (typeof fallback === 'string') {\r\n // Fallback is an image URL\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--fallback', className)}\r\n style={containerStyle}\r\n data-testid={testId}\r\n >\r\n <img\r\n src={fallback}\r\n alt={alt}\r\n style={{\r\n ...imageStyle,\r\n opacity: 1,\r\n }}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n // Fallback is a ReactNode\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--error', className)}\r\n style={{\r\n ...containerStyle,\r\n backgroundColor: 'var(--brycks-background-muted)',\r\n }}\r\n data-testid={testId}\r\n role=\"img\"\r\n aria-label={alt}\r\n >\r\n {parsedRatio && <div style={{ paddingBottom: `${(1 / parsedRatio) * 100}%` }} />}\r\n {fallback && <div style={overlayStyle}>{fallback}</div>}\r\n </div>\r\n )\r\n }\r\n\r\n // Render image with optional placeholder\r\n return (\r\n <div\r\n className={cx(\r\n 'brycks-image',\r\n status === 'loading' && 'brycks-image--loading',\r\n status === 'loaded' && 'brycks-image--loaded',\r\n className\r\n )}\r\n style={parsedRatio ? containerStyle : { position: 'relative', borderRadius }}\r\n data-testid={testId}\r\n >\r\n {/* Placeholder */}\r\n {status === 'loading' && placeholder && (\r\n <div style={overlayStyle}>\r\n {typeof placeholder === 'string' ? (\r\n <img\r\n src={placeholder}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: fit,\r\n filter: 'blur(10px)',\r\n transform: 'scale(1.1)',\r\n }}\r\n />\r\n ) : (\r\n placeholder\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Main image */}\r\n <img\r\n ref={ref}\r\n src={src}\r\n alt={alt}\r\n loading={loading}\r\n onLoad={handleLoad}\r\n onError={handleError}\r\n style={imageStyle}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n})\r\n\r\nImage.displayName = 'Image'\r\n"],"names":["radiusMap","parseAspectRatio","ratio","parts","width","height","parsed","Image","forwardRef","src","alt","aspectRatio","fit","loading","fallback","placeholder","radius","showBackground","onLoad","onError","className","style","testId","props","ref","status","setStatus","useState","handleLoad","useCallback","event","handleError","parsedRatio","borderRadius","containerStyle","imageStyle","overlayStyle","jsx","cx","jsxs"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Image.js","sources":["../../../../src/components/media/Image/Image.tsx"],"sourcesContent":["/**\r\n * Image Component\r\n *\r\n * Responsive image with lazy loading, fallback support, and aspect ratio control.\r\n * Follows accessibility best practices and design system conventions.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useState,\r\n useCallback,\r\n type CSSProperties,\r\n type ImgHTMLAttributes,\r\n type ReactNode,\r\n type SyntheticEvent,\r\n} from 'react'\r\nimport { cx } from '../../../utils/styles'\r\n\r\nexport type ImageFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down'\r\nexport type ImageLoading = 'lazy' | 'eager'\r\n\r\nexport interface ImageProps\r\n extends Omit<ImgHTMLAttributes<HTMLImageElement>, 'placeholder'> {\r\n /** Image source URL */\r\n src: string\r\n /** Alternative text for accessibility (required) */\r\n alt: string\r\n /** Aspect ratio (width/height). If set, maintains ratio */\r\n aspectRatio?: number | string\r\n /** How the image should fit within its container */\r\n fit?: ImageFit\r\n /** Loading strategy */\r\n loading?: ImageLoading\r\n /** Fallback content or URL when image fails to load */\r\n fallback?: ReactNode | string\r\n /** Placeholder shown while loading */\r\n placeholder?: ReactNode | string\r\n /** Border radius using design tokens */\r\n radius?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n /** Whether to show a subtle background while loading */\r\n showBackground?: boolean\r\n /** Callback when image loads successfully */\r\n onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Callback when image fails to load */\r\n onError?: (event: SyntheticEvent<HTMLImageElement>) => void\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n}\r\n\r\nconst radiusMap: Record<string, string> = {\r\n none: '0',\r\n sm: 'var(--brycks-radius-sm)',\r\n md: 'var(--brycks-radius-md)',\r\n lg: 'var(--brycks-radius-lg)',\r\n xl: 'var(--brycks-radius-xl)',\r\n full: 'var(--brycks-radius-full)',\r\n}\r\n\r\nfunction parseAspectRatio(ratio: number | string | undefined): number | undefined {\r\n if (ratio === undefined) return undefined\r\n if (typeof ratio === 'number') return ratio\r\n\r\n // Handle string formats like \"16:9\" or \"16/9\"\r\n const parts = ratio.split(/[:/]/)\r\n if (parts.length === 2) {\r\n const width = parseFloat(parts[0])\r\n const height = parseFloat(parts[1])\r\n if (!isNaN(width) && !isNaN(height) && height !== 0) {\r\n return width / height\r\n }\r\n }\r\n\r\n const parsed = parseFloat(ratio)\r\n return isNaN(parsed) ? undefined : parsed\r\n}\r\n\r\nexport const Image = forwardRef<HTMLImageElement, ImageProps>(function Image(\r\n {\r\n src,\r\n alt,\r\n aspectRatio,\r\n fit = 'cover',\r\n loading = 'lazy',\r\n fallback,\r\n placeholder,\r\n radius = 'none',\r\n showBackground = true,\r\n onLoad,\r\n onError,\r\n className,\r\n style,\r\n testId,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const [status, setStatus] = useState<'loading' | 'loaded' | 'error'>('loading')\r\n\r\n const handleLoad = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('loaded')\r\n onLoad?.(event)\r\n },\r\n [onLoad]\r\n )\r\n\r\n const handleError = useCallback(\r\n (event: SyntheticEvent<HTMLImageElement>) => {\r\n setStatus('error')\r\n onError?.(event)\r\n },\r\n [onError]\r\n )\r\n\r\n const parsedRatio = parseAspectRatio(aspectRatio)\r\n const borderRadius = radiusMap[radius] ?? radiusMap.none\r\n\r\n // Container styles for aspect ratio support\r\n const containerStyle: CSSProperties = {\r\n position: 'relative',\r\n overflow: 'hidden',\r\n borderRadius,\r\n backgroundColor:\r\n showBackground && status === 'loading'\r\n ? 'var(--brycks-background-muted)'\r\n : undefined,\r\n ...(parsedRatio\r\n ? {\r\n width: '100%',\r\n paddingBottom: `${(1 / parsedRatio) * 100}%`,\r\n }\r\n : {}),\r\n }\r\n\r\n const imageStyle: CSSProperties = {\r\n display: 'block',\r\n objectFit: fit,\r\n borderRadius,\r\n ...(parsedRatio\r\n ? {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n width: '100%',\r\n height: '100%',\r\n }\r\n : {\r\n width: style?.width ?? '100%',\r\n height: style?.height ?? 'auto',\r\n }),\r\n opacity: status === 'loaded' ? 1 : 0,\r\n transition: 'opacity var(--brycks-duration-normal, 200ms) var(--brycks-ease-out, ease-out)',\r\n ...style,\r\n }\r\n\r\n const overlayStyle: CSSProperties = {\r\n position: 'absolute',\r\n top: 0,\r\n left: 0,\r\n right: 0,\r\n bottom: 0,\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n borderRadius,\r\n }\r\n\r\n // Render fallback content\r\n if (status === 'error') {\r\n if (typeof fallback === 'string') {\r\n // Fallback is an image URL\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--fallback', className)}\r\n style={containerStyle}\r\n data-testid={testId}\r\n >\r\n <img\r\n src={fallback}\r\n alt={alt}\r\n style={{\r\n ...imageStyle,\r\n opacity: 1,\r\n }}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n }\r\n\r\n // Fallback is a ReactNode\r\n return (\r\n <div\r\n className={cx('brycks-image', 'brycks-image--error', className)}\r\n style={{\r\n ...containerStyle,\r\n backgroundColor: 'var(--brycks-background-muted)',\r\n }}\r\n data-testid={testId}\r\n role=\"img\"\r\n aria-label={alt}\r\n >\r\n {parsedRatio && <div style={{ paddingBottom: `${(1 / parsedRatio) * 100}%` }} />}\r\n {fallback && <div style={overlayStyle}>{fallback}</div>}\r\n </div>\r\n )\r\n }\r\n\r\n // Render image with optional placeholder\r\n return (\r\n <div\r\n className={cx(\r\n 'brycks-image',\r\n status === 'loading' && 'brycks-image--loading',\r\n status === 'loaded' && 'brycks-image--loaded',\r\n className\r\n )}\r\n style={parsedRatio ? containerStyle : { position: 'relative', borderRadius }}\r\n data-testid={testId}\r\n >\r\n {/* Placeholder */}\r\n {status === 'loading' && placeholder && (\r\n <div style={overlayStyle}>\r\n {typeof placeholder === 'string' ? (\r\n <img\r\n src={placeholder}\r\n alt=\"\"\r\n aria-hidden=\"true\"\r\n style={{\r\n width: '100%',\r\n height: '100%',\r\n objectFit: fit,\r\n filter: 'blur(10px)',\r\n transform: 'scale(1.1)',\r\n }}\r\n />\r\n ) : (\r\n placeholder\r\n )}\r\n </div>\r\n )}\r\n\r\n {/* Main image */}\r\n <img\r\n ref={ref}\r\n src={src}\r\n alt={alt}\r\n loading={loading}\r\n onLoad={handleLoad}\r\n onError={handleError}\r\n style={imageStyle}\r\n {...props}\r\n />\r\n </div>\r\n )\r\n})\r\n\r\nImage.displayName = 'Image'\r\n"],"names":["radiusMap","parseAspectRatio","ratio","parts","width","height","parsed","Image","forwardRef","src","alt","aspectRatio","fit","loading","fallback","placeholder","radius","showBackground","onLoad","onError","className","style","testId","props","ref","status","setStatus","useState","handleLoad","useCallback","event","handleError","parsedRatio","borderRadius","containerStyle","imageStyle","overlayStyle","jsx","cx","jsxs"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),w=require("react"),x=require("../../../utils/styles.cjs"),S={sm:{width:60,deleteSize:18},md:{width:80,deleteSize:20},lg:{width:100,deleteSize:24}},l=w.forwardRef(function({src:d,alt:c,isSelected:r=!1,badge:o,onClick:u,onDelete:s,size:i="md",aspectRatio:b="1",disabled:e=!1,className:m,testId:g},y){const t=S[i],h={position:"relative",width:t.width,aspectRatio:b,padding:0,border:r?"2px solid var(--brycks-primary-default)":"2px solid transparent",borderRadius:"var(--brycks-radius-md)",overflow:"hidden",cursor:e?"not-allowed":"pointer",background:"var(--brycks-background-muted)",opacity:e?.5:1,transition:"border-color var(--brycks-duration-fast) var(--brycks-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("react/jsx-runtime"),w=require("react"),x=require("../../../utils/styles.cjs"),S={sm:{width:60,deleteSize:18},md:{width:80,deleteSize:20},lg:{width:100,deleteSize:24}},l=w.forwardRef(function({src:d,alt:c,isSelected:r=!1,badge:o,onClick:u,onDelete:s,size:i="md",aspectRatio:b="1",disabled:e=!1,className:m,testId:g},y){const t=S[i],h={position:"relative",width:t.width,aspectRatio:b,padding:0,border:r?"2px solid var(--brycks-primary-default)":"2px solid transparent",borderRadius:"var(--brycks-radius-md)",overflow:"hidden",cursor:e?"not-allowed":"pointer",background:"var(--brycks-background-muted)",opacity:e?.5:1,transition:"border-color var(--brycks-duration-fast) var(--brycks-ease-out)"},p={width:"100%",height:"100%",objectFit:"cover",display:"block"},k={position:"absolute",top:4,right:4,width:t.deleteSize,height:t.deleteSize,borderRadius:"50%",background:"rgba(0, 0, 0, 0.7)",color:"white",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",fontSize:t.deleteSize*.6,fontWeight:600,lineHeight:1,padding:0,transition:"background var(--brycks-duration-fast) var(--brycks-ease-out)"},f={position:"absolute",bottom:4,left:4,background:"var(--brycks-primary-default)",color:"white",padding:"2px 6px",borderRadius:"var(--brycks-radius-sm)",fontSize:i==="sm"?8:i==="md"?10:11,fontWeight:600,lineHeight:1,textTransform:"uppercase"},v=n=>{n.stopPropagation(),s?.(n)};return a.jsxs("button",{ref:y,type:"button",className:x.cx("brycks-image-thumbnail",r&&"brycks-image-thumbnail--selected",e&&"brycks-image-thumbnail--disabled",m),style:h,onClick:u,disabled:e,"data-testid":g,"aria-pressed":r,children:[a.jsx("img",{src:d,alt:c,style:p}),s&&!e&&a.jsx("button",{type:"button",className:"brycks-image-thumbnail__delete",style:k,onClick:v,"aria-label":"Remove image",children:"×"}),o&&a.jsx("span",{className:"brycks-image-thumbnail__badge",style:f,children:o})]})});l.displayName="ImageThumbnail";exports.ImageThumbnail=l;
|
|
2
2
|
//# sourceMappingURL=ImageThumbnail.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageThumbnail.cjs","sources":["../../../../src/components/media/ImageThumbnail/ImageThumbnail.tsx"],"sourcesContent":["/**\n * ImageThumbnail Component\n *\n * Thumbnail image with selection state, optional badge, and delete action.\n * Designed for image galleries and media selection interfaces.\n */\n\nimport {\n forwardRef,\n type CSSProperties,\n type ReactNode,\n type MouseEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport interface ImageThumbnailProps {\n /** Image source URL */\n src: string\n /** Alternative text for accessibility */\n alt: string\n /** Whether this thumbnail is selected */\n isSelected?: boolean\n /** Badge content (e.g., \"COVER\", \"PRIMARY\") */\n badge?: ReactNode\n /** Callback when thumbnail is clicked */\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Callback when delete button is clicked */\n onDelete?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Size of the thumbnail */\n size?: 'sm' | 'md' | 'lg'\n /** Aspect ratio of the thumbnail */\n aspectRatio?: '1' | '4/3' | '16/9'\n /** Whether the thumbnail is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeMap: Record<string, { width: number; deleteSize: number }> = {\n sm: { width: 60, deleteSize: 18 },\n md: { width: 80, deleteSize: 20 },\n lg: { width: 100, deleteSize: 24 },\n}\n\nexport const ImageThumbnail = forwardRef<HTMLButtonElement, ImageThumbnailProps>(\n function ImageThumbnail(\n {\n src,\n alt,\n isSelected = false,\n badge,\n onClick,\n onDelete,\n size = 'md',\n aspectRatio = '1',\n disabled = false,\n className,\n testId,\n },\n ref\n ) {\n const sizeValue = sizeMap[size]\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: sizeValue.width,\n aspectRatio,\n padding: 0,\n border: isSelected\n ? '2px solid var(--brycks-primary-default)'\n : '2px solid transparent',\n borderRadius: 'var(--brycks-radius-md)',\n overflow: 'hidden',\n cursor: disabled ? 'not-allowed' : 'pointer',\n background: 'var(--brycks-background-muted)',\n opacity: disabled ? 0.5 : 1,\n transition: 'border-color var(--brycks-duration-fast) var(--brycks-
|
|
1
|
+
{"version":3,"file":"ImageThumbnail.cjs","sources":["../../../../src/components/media/ImageThumbnail/ImageThumbnail.tsx"],"sourcesContent":["/**\n * ImageThumbnail Component\n *\n * Thumbnail image with selection state, optional badge, and delete action.\n * Designed for image galleries and media selection interfaces.\n */\n\nimport {\n forwardRef,\n type CSSProperties,\n type ReactNode,\n type MouseEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport interface ImageThumbnailProps {\n /** Image source URL */\n src: string\n /** Alternative text for accessibility */\n alt: string\n /** Whether this thumbnail is selected */\n isSelected?: boolean\n /** Badge content (e.g., \"COVER\", \"PRIMARY\") */\n badge?: ReactNode\n /** Callback when thumbnail is clicked */\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Callback when delete button is clicked */\n onDelete?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Size of the thumbnail */\n size?: 'sm' | 'md' | 'lg'\n /** Aspect ratio of the thumbnail */\n aspectRatio?: '1' | '4/3' | '16/9'\n /** Whether the thumbnail is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeMap: Record<string, { width: number; deleteSize: number }> = {\n sm: { width: 60, deleteSize: 18 },\n md: { width: 80, deleteSize: 20 },\n lg: { width: 100, deleteSize: 24 },\n}\n\nexport const ImageThumbnail = forwardRef<HTMLButtonElement, ImageThumbnailProps>(\n function ImageThumbnail(\n {\n src,\n alt,\n isSelected = false,\n badge,\n onClick,\n onDelete,\n size = 'md',\n aspectRatio = '1',\n disabled = false,\n className,\n testId,\n },\n ref\n ) {\n const sizeValue = sizeMap[size]\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: sizeValue.width,\n aspectRatio,\n padding: 0,\n border: isSelected\n ? '2px solid var(--brycks-primary-default)'\n : '2px solid transparent',\n borderRadius: 'var(--brycks-radius-md)',\n overflow: 'hidden',\n cursor: disabled ? 'not-allowed' : 'pointer',\n background: 'var(--brycks-background-muted)',\n opacity: disabled ? 0.5 : 1,\n transition: 'border-color var(--brycks-duration-fast) var(--brycks-ease-out)',\n }\n\n const imageStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n objectFit: 'cover',\n display: 'block',\n }\n\n const deleteButtonStyle: CSSProperties = {\n position: 'absolute',\n top: 4,\n right: 4,\n width: sizeValue.deleteSize,\n height: sizeValue.deleteSize,\n borderRadius: '50%',\n background: 'rgba(0, 0, 0, 0.7)',\n color: 'white',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: sizeValue.deleteSize * 0.6,\n fontWeight: 600,\n lineHeight: 1,\n padding: 0,\n transition: 'background var(--brycks-duration-fast) var(--brycks-ease-out)',\n }\n\n const badgeStyle: CSSProperties = {\n position: 'absolute',\n bottom: 4,\n left: 4,\n background: 'var(--brycks-primary-default)',\n color: 'white',\n padding: '2px 6px',\n borderRadius: 'var(--brycks-radius-sm)',\n fontSize: size === 'sm' ? 8 : size === 'md' ? 10 : 11,\n fontWeight: 600,\n lineHeight: 1,\n textTransform: 'uppercase',\n }\n\n const handleDelete = (e: MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n onDelete?.(e)\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cx(\n 'brycks-image-thumbnail',\n isSelected && 'brycks-image-thumbnail--selected',\n disabled && 'brycks-image-thumbnail--disabled',\n className\n )}\n style={containerStyle}\n onClick={onClick}\n disabled={disabled}\n data-testid={testId}\n aria-pressed={isSelected}\n >\n <img src={src} alt={alt} style={imageStyle} />\n\n {onDelete && !disabled && (\n <button\n type=\"button\"\n className=\"brycks-image-thumbnail__delete\"\n style={deleteButtonStyle}\n onClick={handleDelete}\n aria-label=\"Remove image\"\n >\n ×\n </button>\n )}\n\n {badge && (\n <span className=\"brycks-image-thumbnail__badge\" style={badgeStyle}>\n {badge}\n </span>\n )}\n </button>\n )\n }\n)\n\nImageThumbnail.displayName = 'ImageThumbnail'\n"],"names":["sizeMap","ImageThumbnail","forwardRef","src","alt","isSelected","badge","onClick","onDelete","size","aspectRatio","disabled","className","testId","ref","sizeValue","containerStyle","imageStyle","deleteButtonStyle","badgeStyle","handleDelete","e","jsxs","cx","jsx"],"mappings":"+KAwCMA,EAAiE,CACrE,GAAI,CAAE,MAAO,GAAI,WAAY,EAAA,EAC7B,GAAI,CAAE,MAAO,GAAI,WAAY,EAAA,EAC7B,GAAI,CAAE,MAAO,IAAK,WAAY,EAAA,CAChC,EAEaC,EAAiBC,EAAAA,WAC5B,SACE,CACE,IAAAC,EACA,IAAAC,EACA,WAAAC,EAAa,GACb,MAAAC,EACA,QAAAC,EACA,SAAAC,EACA,KAAAC,EAAO,KACP,YAAAC,EAAc,IACd,SAAAC,EAAW,GACX,UAAAC,EACA,OAAAC,CAAA,EAEFC,EACA,CACA,MAAMC,EAAYf,EAAQS,CAAI,EAExBO,EAAgC,CACpC,SAAU,WACV,MAAOD,EAAU,MACjB,YAAAL,EACA,QAAS,EACT,OAAQL,EACJ,0CACA,wBACJ,aAAc,0BACd,SAAU,SACV,OAAQM,EAAW,cAAgB,UACnC,WAAY,iCACZ,QAASA,EAAW,GAAM,EAC1B,WAAY,iEAAA,EAGRM,EAA4B,CAChC,MAAO,OACP,OAAQ,OACR,UAAW,QACX,QAAS,OAAA,EAGLC,EAAmC,CACvC,SAAU,WACV,IAAK,EACL,MAAO,EACP,MAAOH,EAAU,WACjB,OAAQA,EAAU,WAClB,aAAc,MACd,WAAY,qBACZ,MAAO,QACP,OAAQ,OACR,OAAQ,UACR,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,SAAUA,EAAU,WAAa,GACjC,WAAY,IACZ,WAAY,EACZ,QAAS,EACT,WAAY,+DAAA,EAGRI,EAA4B,CAChC,SAAU,WACV,OAAQ,EACR,KAAM,EACN,WAAY,gCACZ,MAAO,QACP,QAAS,UACT,aAAc,0BACd,SAAUV,IAAS,KAAO,EAAIA,IAAS,KAAO,GAAK,GACnD,WAAY,IACZ,WAAY,EACZ,cAAe,WAAA,EAGXW,EAAgBC,GAAqC,CACzDA,EAAE,gBAAA,EACFb,IAAWa,CAAC,CACd,EAEA,OACEC,EAAAA,KAAC,SAAA,CACC,IAAAR,EACA,KAAK,SACL,UAAWS,EAAAA,GACT,yBACAlB,GAAc,mCACdM,GAAY,mCACZC,CAAA,EAEF,MAAOI,EACP,QAAAT,EACA,SAAAI,EACA,cAAaE,EACb,eAAcR,EAEd,SAAA,CAAAmB,EAAAA,IAAC,MAAA,CAAI,IAAArB,EAAU,IAAAC,EAAU,MAAOa,EAAY,EAE3CT,GAAY,CAACG,GACZa,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAU,iCACV,MAAON,EACP,QAASE,EACT,aAAW,eACZ,SAAA,GAAA,CAAA,EAKFd,GACCkB,EAAAA,IAAC,OAAA,CAAK,UAAU,gCAAgC,MAAOL,EACpD,SAAAb,CAAA,CACH,CAAA,CAAA,CAAA,CAIR,CACF,EAEAL,EAAe,YAAc"}
|
|
@@ -18,8 +18,8 @@ const S = {
|
|
|
18
18
|
disabled: e = !1,
|
|
19
19
|
className: b,
|
|
20
20
|
testId: u
|
|
21
|
-
},
|
|
22
|
-
const t = S[a],
|
|
21
|
+
}, p) {
|
|
22
|
+
const t = S[a], g = {
|
|
23
23
|
position: "relative",
|
|
24
24
|
width: t.width,
|
|
25
25
|
aspectRatio: m,
|
|
@@ -30,7 +30,7 @@ const S = {
|
|
|
30
30
|
cursor: e ? "not-allowed" : "pointer",
|
|
31
31
|
background: "var(--brycks-background-muted)",
|
|
32
32
|
opacity: e ? 0.5 : 1,
|
|
33
|
-
transition: "border-color var(--brycks-duration-fast) var(--brycks-
|
|
33
|
+
transition: "border-color var(--brycks-duration-fast) var(--brycks-ease-out)"
|
|
34
34
|
}, h = {
|
|
35
35
|
width: "100%",
|
|
36
36
|
height: "100%",
|
|
@@ -54,7 +54,7 @@ const S = {
|
|
|
54
54
|
fontWeight: 600,
|
|
55
55
|
lineHeight: 1,
|
|
56
56
|
padding: 0,
|
|
57
|
-
transition: "background var(--brycks-duration-fast) var(--brycks-
|
|
57
|
+
transition: "background var(--brycks-duration-fast) var(--brycks-ease-out)"
|
|
58
58
|
}, f = {
|
|
59
59
|
position: "absolute",
|
|
60
60
|
bottom: 4,
|
|
@@ -73,7 +73,7 @@ const S = {
|
|
|
73
73
|
return /* @__PURE__ */ v(
|
|
74
74
|
"button",
|
|
75
75
|
{
|
|
76
|
-
ref:
|
|
76
|
+
ref: p,
|
|
77
77
|
type: "button",
|
|
78
78
|
className: x(
|
|
79
79
|
"brycks-image-thumbnail",
|
|
@@ -81,7 +81,7 @@ const S = {
|
|
|
81
81
|
e && "brycks-image-thumbnail--disabled",
|
|
82
82
|
b
|
|
83
83
|
),
|
|
84
|
-
style:
|
|
84
|
+
style: g,
|
|
85
85
|
onClick: c,
|
|
86
86
|
disabled: e,
|
|
87
87
|
"data-testid": u,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageThumbnail.js","sources":["../../../../src/components/media/ImageThumbnail/ImageThumbnail.tsx"],"sourcesContent":["/**\n * ImageThumbnail Component\n *\n * Thumbnail image with selection state, optional badge, and delete action.\n * Designed for image galleries and media selection interfaces.\n */\n\nimport {\n forwardRef,\n type CSSProperties,\n type ReactNode,\n type MouseEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport interface ImageThumbnailProps {\n /** Image source URL */\n src: string\n /** Alternative text for accessibility */\n alt: string\n /** Whether this thumbnail is selected */\n isSelected?: boolean\n /** Badge content (e.g., \"COVER\", \"PRIMARY\") */\n badge?: ReactNode\n /** Callback when thumbnail is clicked */\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Callback when delete button is clicked */\n onDelete?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Size of the thumbnail */\n size?: 'sm' | 'md' | 'lg'\n /** Aspect ratio of the thumbnail */\n aspectRatio?: '1' | '4/3' | '16/9'\n /** Whether the thumbnail is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeMap: Record<string, { width: number; deleteSize: number }> = {\n sm: { width: 60, deleteSize: 18 },\n md: { width: 80, deleteSize: 20 },\n lg: { width: 100, deleteSize: 24 },\n}\n\nexport const ImageThumbnail = forwardRef<HTMLButtonElement, ImageThumbnailProps>(\n function ImageThumbnail(\n {\n src,\n alt,\n isSelected = false,\n badge,\n onClick,\n onDelete,\n size = 'md',\n aspectRatio = '1',\n disabled = false,\n className,\n testId,\n },\n ref\n ) {\n const sizeValue = sizeMap[size]\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: sizeValue.width,\n aspectRatio,\n padding: 0,\n border: isSelected\n ? '2px solid var(--brycks-primary-default)'\n : '2px solid transparent',\n borderRadius: 'var(--brycks-radius-md)',\n overflow: 'hidden',\n cursor: disabled ? 'not-allowed' : 'pointer',\n background: 'var(--brycks-background-muted)',\n opacity: disabled ? 0.5 : 1,\n transition: 'border-color var(--brycks-duration-fast) var(--brycks-
|
|
1
|
+
{"version":3,"file":"ImageThumbnail.js","sources":["../../../../src/components/media/ImageThumbnail/ImageThumbnail.tsx"],"sourcesContent":["/**\n * ImageThumbnail Component\n *\n * Thumbnail image with selection state, optional badge, and delete action.\n * Designed for image galleries and media selection interfaces.\n */\n\nimport {\n forwardRef,\n type CSSProperties,\n type ReactNode,\n type MouseEvent,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport interface ImageThumbnailProps {\n /** Image source URL */\n src: string\n /** Alternative text for accessibility */\n alt: string\n /** Whether this thumbnail is selected */\n isSelected?: boolean\n /** Badge content (e.g., \"COVER\", \"PRIMARY\") */\n badge?: ReactNode\n /** Callback when thumbnail is clicked */\n onClick?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Callback when delete button is clicked */\n onDelete?: (event: MouseEvent<HTMLButtonElement>) => void\n /** Size of the thumbnail */\n size?: 'sm' | 'md' | 'lg'\n /** Aspect ratio of the thumbnail */\n aspectRatio?: '1' | '4/3' | '16/9'\n /** Whether the thumbnail is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nconst sizeMap: Record<string, { width: number; deleteSize: number }> = {\n sm: { width: 60, deleteSize: 18 },\n md: { width: 80, deleteSize: 20 },\n lg: { width: 100, deleteSize: 24 },\n}\n\nexport const ImageThumbnail = forwardRef<HTMLButtonElement, ImageThumbnailProps>(\n function ImageThumbnail(\n {\n src,\n alt,\n isSelected = false,\n badge,\n onClick,\n onDelete,\n size = 'md',\n aspectRatio = '1',\n disabled = false,\n className,\n testId,\n },\n ref\n ) {\n const sizeValue = sizeMap[size]\n\n const containerStyle: CSSProperties = {\n position: 'relative',\n width: sizeValue.width,\n aspectRatio,\n padding: 0,\n border: isSelected\n ? '2px solid var(--brycks-primary-default)'\n : '2px solid transparent',\n borderRadius: 'var(--brycks-radius-md)',\n overflow: 'hidden',\n cursor: disabled ? 'not-allowed' : 'pointer',\n background: 'var(--brycks-background-muted)',\n opacity: disabled ? 0.5 : 1,\n transition: 'border-color var(--brycks-duration-fast) var(--brycks-ease-out)',\n }\n\n const imageStyle: CSSProperties = {\n width: '100%',\n height: '100%',\n objectFit: 'cover',\n display: 'block',\n }\n\n const deleteButtonStyle: CSSProperties = {\n position: 'absolute',\n top: 4,\n right: 4,\n width: sizeValue.deleteSize,\n height: sizeValue.deleteSize,\n borderRadius: '50%',\n background: 'rgba(0, 0, 0, 0.7)',\n color: 'white',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n fontSize: sizeValue.deleteSize * 0.6,\n fontWeight: 600,\n lineHeight: 1,\n padding: 0,\n transition: 'background var(--brycks-duration-fast) var(--brycks-ease-out)',\n }\n\n const badgeStyle: CSSProperties = {\n position: 'absolute',\n bottom: 4,\n left: 4,\n background: 'var(--brycks-primary-default)',\n color: 'white',\n padding: '2px 6px',\n borderRadius: 'var(--brycks-radius-sm)',\n fontSize: size === 'sm' ? 8 : size === 'md' ? 10 : 11,\n fontWeight: 600,\n lineHeight: 1,\n textTransform: 'uppercase',\n }\n\n const handleDelete = (e: MouseEvent<HTMLButtonElement>) => {\n e.stopPropagation()\n onDelete?.(e)\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n className={cx(\n 'brycks-image-thumbnail',\n isSelected && 'brycks-image-thumbnail--selected',\n disabled && 'brycks-image-thumbnail--disabled',\n className\n )}\n style={containerStyle}\n onClick={onClick}\n disabled={disabled}\n data-testid={testId}\n aria-pressed={isSelected}\n >\n <img src={src} alt={alt} style={imageStyle} />\n\n {onDelete && !disabled && (\n <button\n type=\"button\"\n className=\"brycks-image-thumbnail__delete\"\n style={deleteButtonStyle}\n onClick={handleDelete}\n aria-label=\"Remove image\"\n >\n ×\n </button>\n )}\n\n {badge && (\n <span className=\"brycks-image-thumbnail__badge\" style={badgeStyle}>\n {badge}\n </span>\n )}\n </button>\n )\n }\n)\n\nImageThumbnail.displayName = 'ImageThumbnail'\n"],"names":["sizeMap","ImageThumbnail","forwardRef","src","alt","isSelected","badge","onClick","onDelete","size","aspectRatio","disabled","className","testId","ref","sizeValue","containerStyle","imageStyle","deleteButtonStyle","badgeStyle","handleDelete","e","jsxs","cx","jsx"],"mappings":";;;AAwCA,MAAMA,IAAiE;AAAA,EACrE,IAAI,EAAE,OAAO,IAAI,YAAY,GAAA;AAAA,EAC7B,IAAI,EAAE,OAAO,IAAI,YAAY,GAAA;AAAA,EAC7B,IAAI,EAAE,OAAO,KAAK,YAAY,GAAA;AAChC,GAEaC,IAAiBC;AAAA,EAC5B,SACE;AAAA,IACE,KAAAC;AAAA,IACA,KAAAC;AAAA,IACA,YAAAC,IAAa;AAAA,IACb,OAAAC;AAAA,IACA,SAAAC;AAAA,IACA,UAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,aAAAC,IAAc;AAAA,IACd,UAAAC,IAAW;AAAA,IACX,WAAAC;AAAA,IACA,QAAAC;AAAA,EAAA,GAEFC,GACA;AACA,UAAMC,IAAYf,EAAQS,CAAI,GAExBO,IAAgC;AAAA,MACpC,UAAU;AAAA,MACV,OAAOD,EAAU;AAAA,MACjB,aAAAL;AAAA,MACA,SAAS;AAAA,MACT,QAAQL,IACJ,4CACA;AAAA,MACJ,cAAc;AAAA,MACd,UAAU;AAAA,MACV,QAAQM,IAAW,gBAAgB;AAAA,MACnC,YAAY;AAAA,MACZ,SAASA,IAAW,MAAM;AAAA,MAC1B,YAAY;AAAA,IAAA,GAGRM,IAA4B;AAAA,MAChC,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,SAAS;AAAA,IAAA,GAGLC,IAAmC;AAAA,MACvC,UAAU;AAAA,MACV,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAOH,EAAU;AAAA,MACjB,QAAQA,EAAU;AAAA,MAClB,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,UAAUA,EAAU,aAAa;AAAA,MACjC,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,IAAA,GAGRI,IAA4B;AAAA,MAChC,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,SAAS;AAAA,MACT,cAAc;AAAA,MACd,UAAUV,MAAS,OAAO,IAAIA,MAAS,OAAO,KAAK;AAAA,MACnD,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,eAAe;AAAA,IAAA,GAGXW,IAAe,CAACC,MAAqC;AACzD,MAAAA,EAAE,gBAAA,GACFb,IAAWa,CAAC;AAAA,IACd;AAEA,WACE,gBAAAC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAR;AAAA,QACA,MAAK;AAAA,QACL,WAAWS;AAAA,UACT;AAAA,UACAlB,KAAc;AAAA,UACdM,KAAY;AAAA,UACZC;AAAA,QAAA;AAAA,QAEF,OAAOI;AAAA,QACP,SAAAT;AAAA,QACA,UAAAI;AAAA,QACA,eAAaE;AAAA,QACb,gBAAcR;AAAA,QAEd,UAAA;AAAA,UAAA,gBAAAmB,EAAC,OAAA,EAAI,KAAArB,GAAU,KAAAC,GAAU,OAAOa,GAAY;AAAA,UAE3CT,KAAY,CAACG,KACZ,gBAAAa;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,OAAON;AAAA,cACP,SAASE;AAAA,cACT,cAAW;AAAA,cACZ,UAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAKFd,KACC,gBAAAkB,EAAC,QAAA,EAAK,WAAU,iCAAgC,OAAOL,GACpD,UAAAb,EAAA,CACH;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAIR;AACF;AAEAL,EAAe,cAAc;"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),c=require("react"),p=require("../../../utils/styles.cjs"),v=c.createContext(null);function h(){const o=c.useContext(v);if(!o)throw new Error("AccordionItem must be used within an Accordion");return o}const A=c.forwardRef(function({value:t,defaultValue:l=[],onChange:a,allowMultiple:i=!1,variant:d="default",className:s,style:u,children:f,testId:n,...e},x){const[k,g]=c.useState(l),m=t??k,N=c.useCallback(b=>{const E=m.includes(b);let y;E?y=m.filter(R=>R!==b):i?y=[...m,b]:y=[b],t===void 0&&g(y),a?.(y)},[m,i,t,a]),T={display:"flex",flexDirection:"column",gap:d==="separated"?8:0,...u};return r.jsx(v.Provider,{value:{expandedItems:m,toggleItem:N,allowMultiple:i,variant:d},children:r.jsx("div",{ref:x,className:p.cx("brycks-accordion",`brycks-accordion--${d}`,s),style:T,"data-testid":n,...e,children:f})})});A.displayName="Accordion";const C=c.createContext(null);function w(){const o=c.useContext(C);if(!o)throw new Error("AccordionTrigger/AccordionContent must be used within an AccordionItem");return o}const j=c.forwardRef(function({value:t,disabled:l=!1,className:a,style:i,children:d,...s},u){const{expandedItems:f,variant:n}=h(),e=f.includes(t),x={borderBottom:n==="default"?"1px solid var(--brycks-border-muted)":void 0,border:n==="bordered"||n==="separated"?"1px solid var(--brycks-border-default)":void 0,borderRadius:n==="separated"?"var(--brycks-radius-lg)":void 0,overflow:"hidden",...i};return n==="bordered"&&!e&&(x.borderBottom="1px solid var(--brycks-border-default)"),r.jsx(C.Provider,{value:{value:t,isExpanded:e,disabled:l},children:r.jsx("div",{ref:u,className:p.cx("brycks-accordion-item",e&&"brycks-accordion-item--expanded",a),style:x,...s,children:d})})});j.displayName="AccordionItem";function L({isExpanded:o}){return r.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",style:{transform:o?"rotate(180deg)":"rotate(0deg)",transition:"transform 200ms ease-out"},children:r.jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}const I=c.forwardRef(function({icon:t,className:l,style:a,children:i,...d},s){const{toggleItem:u}=h(),{value:f,isExpanded:n,disabled:e}=w(),x=()=>{e||u(f)},k={display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"16px",fontSize:15,fontWeight:500,color:e?"var(--brycks-foreground-muted)":"var(--brycks-foreground-default)",backgroundColor:"transparent",border:"none",cursor:e?"not-allowed":"pointer",textAlign:"left",transition:"background-color 150ms ease-out"
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),c=require("react"),p=require("../../../utils/styles.cjs"),v=c.createContext(null);function h(){const o=c.useContext(v);if(!o)throw new Error("AccordionItem must be used within an Accordion");return o}const A=c.forwardRef(function({value:t,defaultValue:l=[],onChange:a,allowMultiple:i=!1,variant:d="default",className:s,style:u,children:f,testId:n,...e},x){const[k,g]=c.useState(l),m=t??k,N=c.useCallback(b=>{const E=m.includes(b);let y;E?y=m.filter(R=>R!==b):i?y=[...m,b]:y=[b],t===void 0&&g(y),a?.(y)},[m,i,t,a]),T={display:"flex",flexDirection:"column",gap:d==="separated"?8:0,...u};return r.jsx(v.Provider,{value:{expandedItems:m,toggleItem:N,allowMultiple:i,variant:d},children:r.jsx("div",{ref:x,className:p.cx("brycks-accordion",`brycks-accordion--${d}`,s),style:T,"data-testid":n,...e,children:f})})});A.displayName="Accordion";const C=c.createContext(null);function w(){const o=c.useContext(C);if(!o)throw new Error("AccordionTrigger/AccordionContent must be used within an AccordionItem");return o}const j=c.forwardRef(function({value:t,disabled:l=!1,className:a,style:i,children:d,...s},u){const{expandedItems:f,variant:n}=h(),e=f.includes(t),x={borderBottom:n==="default"?"1px solid var(--brycks-border-muted)":void 0,border:n==="bordered"||n==="separated"?"1px solid var(--brycks-border-default)":void 0,borderRadius:n==="separated"?"var(--brycks-radius-lg)":void 0,overflow:"hidden",...i};return n==="bordered"&&!e&&(x.borderBottom="1px solid var(--brycks-border-default)"),r.jsx(C.Provider,{value:{value:t,isExpanded:e,disabled:l},children:r.jsx("div",{ref:u,className:p.cx("brycks-accordion-item",e&&"brycks-accordion-item--expanded",a),style:x,...s,children:d})})});j.displayName="AccordionItem";function L({isExpanded:o}){return r.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",style:{transform:o?"rotate(180deg)":"rotate(0deg)",transition:"transform 200ms ease-out"},children:r.jsx("path",{d:"M4 6l4 4 4-4",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})})}const I=c.forwardRef(function({icon:t,className:l,style:a,children:i,...d},s){const{toggleItem:u}=h(),{value:f,isExpanded:n,disabled:e}=w(),x=()=>{e||u(f)},k={display:"flex",alignItems:"center",justifyContent:"space-between",width:"100%",padding:"16px",fontSize:15,fontWeight:500,color:e?"var(--brycks-foreground-muted)":"var(--brycks-foreground-default)",backgroundColor:"transparent",border:"none",cursor:e?"not-allowed":"pointer",textAlign:"left",transition:"background-color 150ms ease-out",...a};return r.jsxs("button",{ref:s,type:"button","aria-expanded":n,"aria-disabled":e,disabled:e,className:p.cx("brycks-accordion-trigger",l),style:k,onClick:x,onMouseEnter:g=>{e||(g.currentTarget.style.backgroundColor="var(--brycks-background-muted)")},onMouseLeave:g=>{g.currentTarget.style.backgroundColor="transparent"},...d,children:[i,r.jsx("span",{style:{color:"var(--brycks-foreground-muted)",flexShrink:0,marginLeft:12},children:t??r.jsx(L,{isExpanded:n})})]})});I.displayName="AccordionTrigger";const S=c.forwardRef(function({className:t,style:l,children:a,...i},d){const{isExpanded:s}=w(),u={overflow:"hidden",transition:"max-height 200ms ease-out, opacity 200ms ease-out",maxHeight:s?"1000px":"0",opacity:s?1:0},f={padding:"0 16px 16px 16px",color:"var(--brycks-foreground-muted)",fontSize:14,lineHeight:1.6,...l};return r.jsx("div",{ref:d,role:"region","aria-hidden":!s,className:p.cx("brycks-accordion-content",t),style:u,...i,children:r.jsx("div",{style:f,children:a})})});S.displayName="AccordionContent";exports.Accordion=A;exports.AccordionContent=S;exports.AccordionItem=j;exports.AccordionTrigger=I;
|
|
2
2
|
//# sourceMappingURL=Accordion.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.cjs","sources":["../../../../src/components/navigation/Accordion/Accordion.tsx"],"sourcesContent":["/**\n * Accordion Component\n *\n * Collapsible content panels for organizing information.\n * Supports single or multiple expanded panels.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type AccordionVariant = 'default' | 'bordered' | 'separated'\n\ninterface AccordionContextValue {\n expandedItems: string[]\n toggleItem: (value: string) => void\n allowMultiple: boolean\n variant: AccordionVariant\n}\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null)\n\nfunction useAccordionContext() {\n const context = useContext(AccordionContext)\n if (!context) {\n throw new Error('AccordionItem must be used within an Accordion')\n }\n return context\n}\n\nexport interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Expanded items (controlled) */\n value?: string[]\n /** Default expanded items (uncontrolled) */\n defaultValue?: string[]\n /** Callback when items change */\n onChange?: (value: string[]) => void\n /** Allow multiple items to be expanded */\n allowMultiple?: boolean\n /** Accordion variant */\n variant?: AccordionVariant\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Accordion = forwardRef<HTMLDivElement, AccordionProps>(function Accordion(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n allowMultiple = false,\n variant = 'default',\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const expandedItems = controlledValue ?? internalValue\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n const isExpanded = expandedItems.includes(itemValue)\n let newValue: string[]\n\n if (isExpanded) {\n newValue = expandedItems.filter((v) => v !== itemValue)\n } else if (allowMultiple) {\n newValue = [...expandedItems, itemValue]\n } else {\n newValue = [itemValue]\n }\n\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n onChange?.(newValue)\n },\n [expandedItems, allowMultiple, controlledValue, onChange]\n )\n\n const containerStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: variant === 'separated' ? 8 : 0,\n ...style,\n }\n\n return (\n <AccordionContext.Provider value={{ expandedItems, toggleItem, allowMultiple, variant }}>\n <div\n ref={ref}\n className={cx('brycks-accordion', `brycks-accordion--${variant}`, className)}\n style={containerStyle}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n </AccordionContext.Provider>\n )\n})\n\nAccordion.displayName = 'Accordion'\n\n// AccordionItem\nexport interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Item value (unique identifier) */\n value: string\n /** Whether the item is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n}\n\ninterface AccordionItemContextValue {\n value: string\n isExpanded: boolean\n disabled: boolean\n}\n\nconst AccordionItemContext = createContext<AccordionItemContextValue | null>(null)\n\nfunction useAccordionItemContext() {\n const context = useContext(AccordionItemContext)\n if (!context) {\n throw new Error('AccordionTrigger/AccordionContent must be used within an AccordionItem')\n }\n return context\n}\n\nexport const AccordionItem = forwardRef<HTMLDivElement, AccordionItemProps>(function AccordionItem(\n { value, disabled = false, className, style, children, ...props },\n ref\n) {\n const { expandedItems, variant } = useAccordionContext()\n const isExpanded = expandedItems.includes(value)\n\n const itemStyle: CSSProperties = {\n borderBottom: variant === 'default' ? '1px solid var(--brycks-border-muted)' : undefined,\n border: variant === 'bordered' || variant === 'separated' ? '1px solid var(--brycks-border-default)' : undefined,\n borderRadius: variant === 'separated' ? 'var(--brycks-radius-lg)' : undefined,\n overflow: 'hidden',\n ...style,\n }\n\n // Remove bottom border for separated variant (each item has full border)\n if (variant === 'bordered' && !isExpanded) {\n itemStyle.borderBottom = '1px solid var(--brycks-border-default)'\n }\n\n return (\n <AccordionItemContext.Provider value={{ value, isExpanded, disabled }}>\n <div\n ref={ref}\n className={cx('brycks-accordion-item', isExpanded && 'brycks-accordion-item--expanded', className)}\n style={itemStyle}\n {...props}\n >\n {children}\n </div>\n </AccordionItemContext.Provider>\n )\n})\n\nAccordionItem.displayName = 'AccordionItem'\n\n// AccordionTrigger\nexport interface AccordionTriggerProps extends HTMLAttributes<HTMLButtonElement> {\n /** Icon to show (replaces default chevron) */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n}\n\nfunction ChevronIcon({ isExpanded }: { isExpanded: boolean }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-out',\n }}\n >\n <path\n d=\"M4 6l4 4 4-4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\nexport const AccordionTrigger = forwardRef<HTMLButtonElement, AccordionTriggerProps>(function AccordionTrigger(\n { icon, className, style, children, ...props },\n ref\n) {\n const { toggleItem } = useAccordionContext()\n const { value, isExpanded, disabled } = useAccordionItemContext()\n\n const handleClick = () => {\n if (!disabled) {\n toggleItem(value)\n }\n }\n\n const triggerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n padding: '16px',\n fontSize: 15,\n fontWeight: 500,\n color: disabled ? 'var(--brycks-foreground-muted)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 150ms ease-out',\n outline: 'none',\n ...style,\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={isExpanded}\n aria-disabled={disabled}\n disabled={disabled}\n className={cx('brycks-accordion-trigger', className)}\n style={triggerStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {children}\n <span style={{ color: 'var(--brycks-foreground-muted)', flexShrink: 0, marginLeft: 12 }}>\n {icon ?? <ChevronIcon isExpanded={isExpanded} />}\n </span>\n </button>\n )\n})\n\nAccordionTrigger.displayName = 'AccordionTrigger'\n\n// AccordionContent\nexport interface AccordionContentProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(function AccordionContent(\n { className, style, children, ...props },\n ref\n) {\n const { isExpanded } = useAccordionItemContext()\n\n const contentStyle: CSSProperties = {\n overflow: 'hidden',\n transition: 'max-height 200ms ease-out, opacity 200ms ease-out',\n maxHeight: isExpanded ? '1000px' : '0',\n opacity: isExpanded ? 1 : 0,\n }\n\n const innerStyle: CSSProperties = {\n padding: '0 16px 16px 16px',\n color: 'var(--brycks-foreground-muted)',\n fontSize: 14,\n lineHeight: 1.6,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-hidden={!isExpanded}\n className={cx('brycks-accordion-content', className)}\n style={contentStyle}\n {...props}\n >\n <div style={innerStyle}>{children}</div>\n </div>\n )\n})\n\nAccordionContent.displayName = 'AccordionContent'\n"],"names":["AccordionContext","createContext","useAccordionContext","context","useContext","Accordion","forwardRef","controlledValue","defaultValue","onChange","allowMultiple","variant","className","style","children","testId","props","ref","internalValue","setInternalValue","useState","expandedItems","toggleItem","useCallback","itemValue","isExpanded","newValue","v","containerStyle","jsx","cx","AccordionItemContext","useAccordionItemContext","AccordionItem","value","disabled","itemStyle","ChevronIcon","AccordionTrigger","icon","handleClick","triggerStyle","jsxs","e","AccordionContent","contentStyle","innerStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Accordion.cjs","sources":["../../../../src/components/navigation/Accordion/Accordion.tsx"],"sourcesContent":["/**\n * Accordion Component\n *\n * Collapsible content panels for organizing information.\n * Supports single or multiple expanded panels.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type AccordionVariant = 'default' | 'bordered' | 'separated'\n\ninterface AccordionContextValue {\n expandedItems: string[]\n toggleItem: (value: string) => void\n allowMultiple: boolean\n variant: AccordionVariant\n}\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null)\n\nfunction useAccordionContext() {\n const context = useContext(AccordionContext)\n if (!context) {\n throw new Error('AccordionItem must be used within an Accordion')\n }\n return context\n}\n\nexport interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Expanded items (controlled) */\n value?: string[]\n /** Default expanded items (uncontrolled) */\n defaultValue?: string[]\n /** Callback when items change */\n onChange?: (value: string[]) => void\n /** Allow multiple items to be expanded */\n allowMultiple?: boolean\n /** Accordion variant */\n variant?: AccordionVariant\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Accordion = forwardRef<HTMLDivElement, AccordionProps>(function Accordion(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n allowMultiple = false,\n variant = 'default',\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const expandedItems = controlledValue ?? internalValue\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n const isExpanded = expandedItems.includes(itemValue)\n let newValue: string[]\n\n if (isExpanded) {\n newValue = expandedItems.filter((v) => v !== itemValue)\n } else if (allowMultiple) {\n newValue = [...expandedItems, itemValue]\n } else {\n newValue = [itemValue]\n }\n\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n onChange?.(newValue)\n },\n [expandedItems, allowMultiple, controlledValue, onChange]\n )\n\n const containerStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: variant === 'separated' ? 8 : 0,\n ...style,\n }\n\n return (\n <AccordionContext.Provider value={{ expandedItems, toggleItem, allowMultiple, variant }}>\n <div\n ref={ref}\n className={cx('brycks-accordion', `brycks-accordion--${variant}`, className)}\n style={containerStyle}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n </AccordionContext.Provider>\n )\n})\n\nAccordion.displayName = 'Accordion'\n\n// AccordionItem\nexport interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Item value (unique identifier) */\n value: string\n /** Whether the item is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n}\n\ninterface AccordionItemContextValue {\n value: string\n isExpanded: boolean\n disabled: boolean\n}\n\nconst AccordionItemContext = createContext<AccordionItemContextValue | null>(null)\n\nfunction useAccordionItemContext() {\n const context = useContext(AccordionItemContext)\n if (!context) {\n throw new Error('AccordionTrigger/AccordionContent must be used within an AccordionItem')\n }\n return context\n}\n\nexport const AccordionItem = forwardRef<HTMLDivElement, AccordionItemProps>(function AccordionItem(\n { value, disabled = false, className, style, children, ...props },\n ref\n) {\n const { expandedItems, variant } = useAccordionContext()\n const isExpanded = expandedItems.includes(value)\n\n const itemStyle: CSSProperties = {\n borderBottom: variant === 'default' ? '1px solid var(--brycks-border-muted)' : undefined,\n border: variant === 'bordered' || variant === 'separated' ? '1px solid var(--brycks-border-default)' : undefined,\n borderRadius: variant === 'separated' ? 'var(--brycks-radius-lg)' : undefined,\n overflow: 'hidden',\n ...style,\n }\n\n // Remove bottom border for separated variant (each item has full border)\n if (variant === 'bordered' && !isExpanded) {\n itemStyle.borderBottom = '1px solid var(--brycks-border-default)'\n }\n\n return (\n <AccordionItemContext.Provider value={{ value, isExpanded, disabled }}>\n <div\n ref={ref}\n className={cx('brycks-accordion-item', isExpanded && 'brycks-accordion-item--expanded', className)}\n style={itemStyle}\n {...props}\n >\n {children}\n </div>\n </AccordionItemContext.Provider>\n )\n})\n\nAccordionItem.displayName = 'AccordionItem'\n\n// AccordionTrigger\nexport interface AccordionTriggerProps extends HTMLAttributes<HTMLButtonElement> {\n /** Icon to show (replaces default chevron) */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n}\n\nfunction ChevronIcon({ isExpanded }: { isExpanded: boolean }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-out',\n }}\n >\n <path\n d=\"M4 6l4 4 4-4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\nexport const AccordionTrigger = forwardRef<HTMLButtonElement, AccordionTriggerProps>(function AccordionTrigger(\n { icon, className, style, children, ...props },\n ref\n) {\n const { toggleItem } = useAccordionContext()\n const { value, isExpanded, disabled } = useAccordionItemContext()\n\n const handleClick = () => {\n if (!disabled) {\n toggleItem(value)\n }\n }\n\n const triggerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n padding: '16px',\n fontSize: 15,\n fontWeight: 500,\n color: disabled ? 'var(--brycks-foreground-muted)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 150ms ease-out',\n ...style,\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={isExpanded}\n aria-disabled={disabled}\n disabled={disabled}\n className={cx('brycks-accordion-trigger', className)}\n style={triggerStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {children}\n <span style={{ color: 'var(--brycks-foreground-muted)', flexShrink: 0, marginLeft: 12 }}>\n {icon ?? <ChevronIcon isExpanded={isExpanded} />}\n </span>\n </button>\n )\n})\n\nAccordionTrigger.displayName = 'AccordionTrigger'\n\n// AccordionContent\nexport interface AccordionContentProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(function AccordionContent(\n { className, style, children, ...props },\n ref\n) {\n const { isExpanded } = useAccordionItemContext()\n\n const contentStyle: CSSProperties = {\n overflow: 'hidden',\n transition: 'max-height 200ms ease-out, opacity 200ms ease-out',\n maxHeight: isExpanded ? '1000px' : '0',\n opacity: isExpanded ? 1 : 0,\n }\n\n const innerStyle: CSSProperties = {\n padding: '0 16px 16px 16px',\n color: 'var(--brycks-foreground-muted)',\n fontSize: 14,\n lineHeight: 1.6,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-hidden={!isExpanded}\n className={cx('brycks-accordion-content', className)}\n style={contentStyle}\n {...props}\n >\n <div style={innerStyle}>{children}</div>\n </div>\n )\n})\n\nAccordionContent.displayName = 'AccordionContent'\n"],"names":["AccordionContext","createContext","useAccordionContext","context","useContext","Accordion","forwardRef","controlledValue","defaultValue","onChange","allowMultiple","variant","className","style","children","testId","props","ref","internalValue","setInternalValue","useState","expandedItems","toggleItem","useCallback","itemValue","isExpanded","newValue","v","containerStyle","jsx","cx","AccordionItemContext","useAccordionItemContext","AccordionItem","value","disabled","itemStyle","ChevronIcon","AccordionTrigger","icon","handleClick","triggerStyle","jsxs","e","AccordionContent","contentStyle","innerStyle"],"mappings":"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"}
|
|
@@ -115,7 +115,6 @@ const R = b(function({ icon: r, className: a, style: s, children: c, ...i }, d)
|
|
|
115
115
|
cursor: e ? "not-allowed" : "pointer",
|
|
116
116
|
textAlign: "left",
|
|
117
117
|
transition: "background-color 150ms ease-out",
|
|
118
|
-
outline: "none",
|
|
119
118
|
...s
|
|
120
119
|
};
|
|
121
120
|
return /* @__PURE__ */ j(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.js","sources":["../../../../src/components/navigation/Accordion/Accordion.tsx"],"sourcesContent":["/**\n * Accordion Component\n *\n * Collapsible content panels for organizing information.\n * Supports single or multiple expanded panels.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type AccordionVariant = 'default' | 'bordered' | 'separated'\n\ninterface AccordionContextValue {\n expandedItems: string[]\n toggleItem: (value: string) => void\n allowMultiple: boolean\n variant: AccordionVariant\n}\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null)\n\nfunction useAccordionContext() {\n const context = useContext(AccordionContext)\n if (!context) {\n throw new Error('AccordionItem must be used within an Accordion')\n }\n return context\n}\n\nexport interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Expanded items (controlled) */\n value?: string[]\n /** Default expanded items (uncontrolled) */\n defaultValue?: string[]\n /** Callback when items change */\n onChange?: (value: string[]) => void\n /** Allow multiple items to be expanded */\n allowMultiple?: boolean\n /** Accordion variant */\n variant?: AccordionVariant\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Accordion = forwardRef<HTMLDivElement, AccordionProps>(function Accordion(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n allowMultiple = false,\n variant = 'default',\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const expandedItems = controlledValue ?? internalValue\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n const isExpanded = expandedItems.includes(itemValue)\n let newValue: string[]\n\n if (isExpanded) {\n newValue = expandedItems.filter((v) => v !== itemValue)\n } else if (allowMultiple) {\n newValue = [...expandedItems, itemValue]\n } else {\n newValue = [itemValue]\n }\n\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n onChange?.(newValue)\n },\n [expandedItems, allowMultiple, controlledValue, onChange]\n )\n\n const containerStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: variant === 'separated' ? 8 : 0,\n ...style,\n }\n\n return (\n <AccordionContext.Provider value={{ expandedItems, toggleItem, allowMultiple, variant }}>\n <div\n ref={ref}\n className={cx('brycks-accordion', `brycks-accordion--${variant}`, className)}\n style={containerStyle}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n </AccordionContext.Provider>\n )\n})\n\nAccordion.displayName = 'Accordion'\n\n// AccordionItem\nexport interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Item value (unique identifier) */\n value: string\n /** Whether the item is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n}\n\ninterface AccordionItemContextValue {\n value: string\n isExpanded: boolean\n disabled: boolean\n}\n\nconst AccordionItemContext = createContext<AccordionItemContextValue | null>(null)\n\nfunction useAccordionItemContext() {\n const context = useContext(AccordionItemContext)\n if (!context) {\n throw new Error('AccordionTrigger/AccordionContent must be used within an AccordionItem')\n }\n return context\n}\n\nexport const AccordionItem = forwardRef<HTMLDivElement, AccordionItemProps>(function AccordionItem(\n { value, disabled = false, className, style, children, ...props },\n ref\n) {\n const { expandedItems, variant } = useAccordionContext()\n const isExpanded = expandedItems.includes(value)\n\n const itemStyle: CSSProperties = {\n borderBottom: variant === 'default' ? '1px solid var(--brycks-border-muted)' : undefined,\n border: variant === 'bordered' || variant === 'separated' ? '1px solid var(--brycks-border-default)' : undefined,\n borderRadius: variant === 'separated' ? 'var(--brycks-radius-lg)' : undefined,\n overflow: 'hidden',\n ...style,\n }\n\n // Remove bottom border for separated variant (each item has full border)\n if (variant === 'bordered' && !isExpanded) {\n itemStyle.borderBottom = '1px solid var(--brycks-border-default)'\n }\n\n return (\n <AccordionItemContext.Provider value={{ value, isExpanded, disabled }}>\n <div\n ref={ref}\n className={cx('brycks-accordion-item', isExpanded && 'brycks-accordion-item--expanded', className)}\n style={itemStyle}\n {...props}\n >\n {children}\n </div>\n </AccordionItemContext.Provider>\n )\n})\n\nAccordionItem.displayName = 'AccordionItem'\n\n// AccordionTrigger\nexport interface AccordionTriggerProps extends HTMLAttributes<HTMLButtonElement> {\n /** Icon to show (replaces default chevron) */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n}\n\nfunction ChevronIcon({ isExpanded }: { isExpanded: boolean }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-out',\n }}\n >\n <path\n d=\"M4 6l4 4 4-4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\nexport const AccordionTrigger = forwardRef<HTMLButtonElement, AccordionTriggerProps>(function AccordionTrigger(\n { icon, className, style, children, ...props },\n ref\n) {\n const { toggleItem } = useAccordionContext()\n const { value, isExpanded, disabled } = useAccordionItemContext()\n\n const handleClick = () => {\n if (!disabled) {\n toggleItem(value)\n }\n }\n\n const triggerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n padding: '16px',\n fontSize: 15,\n fontWeight: 500,\n color: disabled ? 'var(--brycks-foreground-muted)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 150ms ease-out',\n outline: 'none',\n ...style,\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={isExpanded}\n aria-disabled={disabled}\n disabled={disabled}\n className={cx('brycks-accordion-trigger', className)}\n style={triggerStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {children}\n <span style={{ color: 'var(--brycks-foreground-muted)', flexShrink: 0, marginLeft: 12 }}>\n {icon ?? <ChevronIcon isExpanded={isExpanded} />}\n </span>\n </button>\n )\n})\n\nAccordionTrigger.displayName = 'AccordionTrigger'\n\n// AccordionContent\nexport interface AccordionContentProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(function AccordionContent(\n { className, style, children, ...props },\n ref\n) {\n const { isExpanded } = useAccordionItemContext()\n\n const contentStyle: CSSProperties = {\n overflow: 'hidden',\n transition: 'max-height 200ms ease-out, opacity 200ms ease-out',\n maxHeight: isExpanded ? '1000px' : '0',\n opacity: isExpanded ? 1 : 0,\n }\n\n const innerStyle: CSSProperties = {\n padding: '0 16px 16px 16px',\n color: 'var(--brycks-foreground-muted)',\n fontSize: 14,\n lineHeight: 1.6,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-hidden={!isExpanded}\n className={cx('brycks-accordion-content', className)}\n style={contentStyle}\n {...props}\n >\n <div style={innerStyle}>{children}</div>\n </div>\n )\n})\n\nAccordionContent.displayName = 'AccordionContent'\n"],"names":["AccordionContext","createContext","useAccordionContext","context","useContext","Accordion","forwardRef","controlledValue","defaultValue","onChange","allowMultiple","variant","className","style","children","testId","props","ref","internalValue","setInternalValue","useState","expandedItems","toggleItem","useCallback","itemValue","isExpanded","newValue","v","containerStyle","jsx","cx","AccordionItemContext","useAccordionItemContext","AccordionItem","value","disabled","itemStyle","ChevronIcon","AccordionTrigger","icon","handleClick","triggerStyle","jsxs","e","AccordionContent","contentStyle","innerStyle"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Accordion.js","sources":["../../../../src/components/navigation/Accordion/Accordion.tsx"],"sourcesContent":["/**\n * Accordion Component\n *\n * Collapsible content panels for organizing information.\n * Supports single or multiple expanded panels.\n */\n\nimport {\n forwardRef,\n useState,\n useCallback,\n createContext,\n useContext,\n type CSSProperties,\n type ReactNode,\n type HTMLAttributes,\n} from 'react'\nimport { cx } from '../../../utils/styles'\n\nexport type AccordionVariant = 'default' | 'bordered' | 'separated'\n\ninterface AccordionContextValue {\n expandedItems: string[]\n toggleItem: (value: string) => void\n allowMultiple: boolean\n variant: AccordionVariant\n}\n\nconst AccordionContext = createContext<AccordionContextValue | null>(null)\n\nfunction useAccordionContext() {\n const context = useContext(AccordionContext)\n if (!context) {\n throw new Error('AccordionItem must be used within an Accordion')\n }\n return context\n}\n\nexport interface AccordionProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Expanded items (controlled) */\n value?: string[]\n /** Default expanded items (uncontrolled) */\n defaultValue?: string[]\n /** Callback when items change */\n onChange?: (value: string[]) => void\n /** Allow multiple items to be expanded */\n allowMultiple?: boolean\n /** Accordion variant */\n variant?: AccordionVariant\n /** Custom class name */\n className?: string\n /** Test ID */\n testId?: string\n}\n\nexport const Accordion = forwardRef<HTMLDivElement, AccordionProps>(function Accordion(\n {\n value: controlledValue,\n defaultValue = [],\n onChange,\n allowMultiple = false,\n variant = 'default',\n className,\n style,\n children,\n testId,\n ...props\n },\n ref\n) {\n const [internalValue, setInternalValue] = useState(defaultValue)\n const expandedItems = controlledValue ?? internalValue\n\n const toggleItem = useCallback(\n (itemValue: string) => {\n const isExpanded = expandedItems.includes(itemValue)\n let newValue: string[]\n\n if (isExpanded) {\n newValue = expandedItems.filter((v) => v !== itemValue)\n } else if (allowMultiple) {\n newValue = [...expandedItems, itemValue]\n } else {\n newValue = [itemValue]\n }\n\n if (controlledValue === undefined) {\n setInternalValue(newValue)\n }\n onChange?.(newValue)\n },\n [expandedItems, allowMultiple, controlledValue, onChange]\n )\n\n const containerStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: variant === 'separated' ? 8 : 0,\n ...style,\n }\n\n return (\n <AccordionContext.Provider value={{ expandedItems, toggleItem, allowMultiple, variant }}>\n <div\n ref={ref}\n className={cx('brycks-accordion', `brycks-accordion--${variant}`, className)}\n style={containerStyle}\n data-testid={testId}\n {...props}\n >\n {children}\n </div>\n </AccordionContext.Provider>\n )\n})\n\nAccordion.displayName = 'Accordion'\n\n// AccordionItem\nexport interface AccordionItemProps extends HTMLAttributes<HTMLDivElement> {\n /** Item value (unique identifier) */\n value: string\n /** Whether the item is disabled */\n disabled?: boolean\n /** Custom class name */\n className?: string\n}\n\ninterface AccordionItemContextValue {\n value: string\n isExpanded: boolean\n disabled: boolean\n}\n\nconst AccordionItemContext = createContext<AccordionItemContextValue | null>(null)\n\nfunction useAccordionItemContext() {\n const context = useContext(AccordionItemContext)\n if (!context) {\n throw new Error('AccordionTrigger/AccordionContent must be used within an AccordionItem')\n }\n return context\n}\n\nexport const AccordionItem = forwardRef<HTMLDivElement, AccordionItemProps>(function AccordionItem(\n { value, disabled = false, className, style, children, ...props },\n ref\n) {\n const { expandedItems, variant } = useAccordionContext()\n const isExpanded = expandedItems.includes(value)\n\n const itemStyle: CSSProperties = {\n borderBottom: variant === 'default' ? '1px solid var(--brycks-border-muted)' : undefined,\n border: variant === 'bordered' || variant === 'separated' ? '1px solid var(--brycks-border-default)' : undefined,\n borderRadius: variant === 'separated' ? 'var(--brycks-radius-lg)' : undefined,\n overflow: 'hidden',\n ...style,\n }\n\n // Remove bottom border for separated variant (each item has full border)\n if (variant === 'bordered' && !isExpanded) {\n itemStyle.borderBottom = '1px solid var(--brycks-border-default)'\n }\n\n return (\n <AccordionItemContext.Provider value={{ value, isExpanded, disabled }}>\n <div\n ref={ref}\n className={cx('brycks-accordion-item', isExpanded && 'brycks-accordion-item--expanded', className)}\n style={itemStyle}\n {...props}\n >\n {children}\n </div>\n </AccordionItemContext.Provider>\n )\n})\n\nAccordionItem.displayName = 'AccordionItem'\n\n// AccordionTrigger\nexport interface AccordionTriggerProps extends HTMLAttributes<HTMLButtonElement> {\n /** Icon to show (replaces default chevron) */\n icon?: ReactNode\n /** Custom class name */\n className?: string\n}\n\nfunction ChevronIcon({ isExpanded }: { isExpanded: boolean }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n style={{\n transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-out',\n }}\n >\n <path\n d=\"M4 6l4 4 4-4\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )\n}\n\nexport const AccordionTrigger = forwardRef<HTMLButtonElement, AccordionTriggerProps>(function AccordionTrigger(\n { icon, className, style, children, ...props },\n ref\n) {\n const { toggleItem } = useAccordionContext()\n const { value, isExpanded, disabled } = useAccordionItemContext()\n\n const handleClick = () => {\n if (!disabled) {\n toggleItem(value)\n }\n }\n\n const triggerStyle: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n width: '100%',\n padding: '16px',\n fontSize: 15,\n fontWeight: 500,\n color: disabled ? 'var(--brycks-foreground-muted)' : 'var(--brycks-foreground-default)',\n backgroundColor: 'transparent',\n border: 'none',\n cursor: disabled ? 'not-allowed' : 'pointer',\n textAlign: 'left',\n transition: 'background-color 150ms ease-out',\n ...style,\n }\n\n return (\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={isExpanded}\n aria-disabled={disabled}\n disabled={disabled}\n className={cx('brycks-accordion-trigger', className)}\n style={triggerStyle}\n onClick={handleClick}\n onMouseEnter={(e) => {\n if (!disabled) {\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent'\n }}\n {...props}\n >\n {children}\n <span style={{ color: 'var(--brycks-foreground-muted)', flexShrink: 0, marginLeft: 12 }}>\n {icon ?? <ChevronIcon isExpanded={isExpanded} />}\n </span>\n </button>\n )\n})\n\nAccordionTrigger.displayName = 'AccordionTrigger'\n\n// AccordionContent\nexport interface AccordionContentProps extends HTMLAttributes<HTMLDivElement> {\n /** Custom class name */\n className?: string\n}\n\nexport const AccordionContent = forwardRef<HTMLDivElement, AccordionContentProps>(function AccordionContent(\n { className, style, children, ...props },\n ref\n) {\n const { isExpanded } = useAccordionItemContext()\n\n const contentStyle: CSSProperties = {\n overflow: 'hidden',\n transition: 'max-height 200ms ease-out, opacity 200ms ease-out',\n maxHeight: isExpanded ? '1000px' : '0',\n opacity: isExpanded ? 1 : 0,\n }\n\n const innerStyle: CSSProperties = {\n padding: '0 16px 16px 16px',\n color: 'var(--brycks-foreground-muted)',\n fontSize: 14,\n lineHeight: 1.6,\n ...style,\n }\n\n return (\n <div\n ref={ref}\n role=\"region\"\n aria-hidden={!isExpanded}\n className={cx('brycks-accordion-content', className)}\n style={contentStyle}\n {...props}\n >\n <div style={innerStyle}>{children}</div>\n </div>\n )\n})\n\nAccordionContent.displayName = 'AccordionContent'\n"],"names":["AccordionContext","createContext","useAccordionContext","context","useContext","Accordion","forwardRef","controlledValue","defaultValue","onChange","allowMultiple","variant","className","style","children","testId","props","ref","internalValue","setInternalValue","useState","expandedItems","toggleItem","useCallback","itemValue","isExpanded","newValue","v","containerStyle","jsx","cx","AccordionItemContext","useAccordionItemContext","AccordionItem","value","disabled","itemStyle","ChevronIcon","AccordionTrigger","icon","handleClick","triggerStyle","jsxs","e","AccordionContent","contentStyle","innerStyle"],"mappings":"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"}
|