@baseline-ui/mcp 0.0.0-nightly-20251202000557 → 0.0.0-nightly-20251203000617
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/CHANGELOG.md +1 -1
- package/dist/data/component-source.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"Group": "import React from \"react\";\nimport { useHover } from \"react-aria\";\n\nimport type { GroupProps } from \"./Group.types\";\n\nexport const Group = React.forwardRef<HTMLDivElement, GroupProps>(\n (\n {\n className,\n style,\n children,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlock,\n role = \"group\",\n isDisabled,\n ...ariaLabelling\n },\n ref,\n ) => {\n const { hoverProps, isHovered } = useHover({ isDisabled });\n\n return (\n <div\n {...hoverProps}\n role={role}\n data-hovered={isHovered}\n data-disabled={isDisabled}\n data-block-id={dataBlockId}\n data-block-class={dataBlock}\n className={className}\n style={style}\n {...ariaLabelling}\n ref={ref}\n >\n {children}\n </div>\n );\n },\n);\n\nGroup.displayName = \"Group\";\n",
|
|
28
28
|
"I18nProvider": "import { I18nProvider as Provider } from \"react-aria\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\nimport type { LocalizedStrings } from \"react-aria\";\nimport type { I18nProviderProps } from \"./I18Provider.types\";\n\nexport const IntlMessagesProvider = React.createContext<{\n messages: LocalizedStrings;\n shouldLogMissingMessages: boolean;\n hasMissingErrorLoggedFor: React.MutableRefObject<Set<string>>;\n setLang: (lang: string) => void;\n}>({\n messages: {},\n shouldLogMissingMessages: true,\n hasMissingErrorLoggedFor: { current: new Set() },\n setLang: () => {},\n});\n\nexport const I18nProvider: React.FC<I18nProviderProps> = ({\n children,\n messages = {},\n shouldLogMissingMessages = true,\n ...props\n}) => {\n const hasMissingErrorLoggedFor = useRef<Set<string>>(new Set());\n\n const [lang, setLang] = useState(props.locale || \"\");\n\n useEffect(() => {\n hasMissingErrorLoggedFor.current.clear();\n }, [lang, props.locale]);\n\n const messagesValue = React.useMemo(\n () => ({\n messages,\n shouldLogMissingMessages,\n hasMissingErrorLoggedFor,\n setLang,\n }),\n [messages, shouldLogMissingMessages, setLang],\n );\n\n return (\n <Provider {...props}>\n <IntlMessagesProvider.Provider value={messagesValue}>\n {children}\n </IntlMessagesProvider.Provider>\n </Provider>\n );\n};\n\nI18nProvider.displayName = \"I18nProvider\";\n",
|
|
29
29
|
"Icon": "import * as Dompurify from \"dompurify\";\nimport { getOwnerDocument, mergeRefs } from \"@react-aria/utils\";\nimport React, { useId } from \"react\";\n\nimport { invariant } from \"../../utils\";\n\nimport type { IconComponentProps } from \"./Icon.types\";\n\nconst setSizeAttributes = (svgElement: SVGElement, size: number | string) => {\n svgElement.setAttribute(\n \"height\",\n typeof size === \"number\" ? `${size}px` : size,\n );\n svgElement.setAttribute(\n \"width\",\n typeof size === \"number\" ? `${size}px` : size,\n );\n};\n\nconst updateSvgTitle = (svgElement: SVGElement, title: string, id: string) => {\n const titleElement = svgElement.querySelector(\"title\");\n const ownerDocument = getOwnerDocument(svgElement);\n\n if (titleElement) {\n titleElement.textContent = title;\n titleElement.setAttribute(\"id\", id);\n } else {\n const newTitleElement = ownerDocument.createElement(\"title\");\n newTitleElement.textContent = title;\n newTitleElement.setAttribute(\"id\", id);\n svgElement.prepend(newTitleElement);\n }\n};\n\nconst setClassName = (svgElement: SVGElement, className?: string) => {\n if (className) {\n svgElement.classList.add(className);\n }\n};\n\nconst getSanitizedSvgElement = (_svg: string, ownerDocument: Document) => {\n const span = ownerDocument.createElement(\"span\");\n span.innerHTML = Dompurify.default.sanitize(_svg);\n const svgElement = span.querySelector(\"svg\");\n invariant(svgElement, \"Icon: svg prop must be a valid svg string\");\n return svgElement;\n};\n\nconst Icon = React.forwardRef<HTMLSpanElement, IconComponentProps>(\n ({ size, title, className, style, color, ...rest }, ref) => {\n const id = useId();\n const svgRef = React.useRef<HTMLSpanElement>(null);\n\n const _svg = \"svg\" in rest ? rest.svg : undefined;\n\n const svgString = React.useMemo(() => {\n if (_svg) {\n const ownerDocument = getOwnerDocument(svgRef.current);\n\n const svgElement = getSanitizedSvgElement(_svg, ownerDocument);\n if (size) {\n setSizeAttributes(svgElement, size);\n }\n\n if (title) {\n updateSvgTitle(svgElement, title, id);\n }\n\n setClassName(svgElement, className);\n\n return svgElement.outerHTML;\n }\n }, [_svg, size, title, className, id]);\n\n return (\n <span\n className={className}\n ref={mergeRefs(ref, svgRef)}\n style={{ display: \"contents\", ...style, color }}\n dangerouslySetInnerHTML={svgString ? { __html: svgString } : undefined}\n />\n );\n },\n);\n\nIcon.displayName = \"Icon\";\n\nexport { Icon };\n",
|
|
30
|
-
"ImageDropZone": "import { useControlledState } from \"@react-stately/utils\";\nimport React, { useMemo } from \"react\";\nimport {\n VisuallyHidden,\n mergeProps,\n useClipboard,\n useDrop,\n useField,\n useFocusRing,\n useHover,\n} from \"react-aria\";\n\nimport messages from \"./intl\";\nimport { classNames, filterTruthyValues, invariant } from \"../../utils\";\nimport { buttonCn } from \"../ActionButton/ActionButton.css\";\nimport { Box } from \"../Box\";\nimport { freehandCanvasFooterCn } from \"../FreehandCanvas/FreehandCanvas.css\";\nimport { ProgressSpinner } from \"../ProgressSpinner\";\nimport { onDropOrPaste } from \"../FileUpload/hooks/useFileUpload\";\nimport { imageDropZoneCn, opacityNoneCn, previewCn } from \"./ImageDropZone.css\";\nimport { ActionButton } from \"../ActionButton\";\nimport { useI18n, useImage } from \"../../hooks\";\n\nimport type { ActionButtonProps } from \"../ActionButton\";\nimport type { ChangeEventHandler } from \"react\";\nimport type { ImageDropZoneProps } from \"./ImageDropZone.types\";\n\nexport const ImageDropZone = React.forwardRef<\n HTMLDivElement,\n ImageDropZoneProps\n>(\n (\n {\n className,\n style,\n isInline = true,\n accept = \"image/*\",\n defaultImageSrc,\n imageSrc,\n imageAlt,\n pickerButtonLabel,\n isDisabled,\n onDrop,\n onPaste,\n includeCheckeredBackground = true,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n pickerButtonStyle,\n pickerButtonClassName,\n footerClassName,\n footerStyle,\n clearLabel,\n placeholder,\n labelStyle,\n labelClassName,\n ...rest\n },\n ref,\n ) => {\n const elementRef = React.useRef<HTMLLabelElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { formatMessage } = useI18n(messages);\n\n const [url, setUrl] = useControlledState(\n imageSrc,\n defaultImageSrc || null,\n (value) => {\n invariant(typeof value !== \"string\");\n\n rest.onValueChange?.(value ? [value] : []);\n },\n );\n\n const _url = useMemo(() => getImageSrc(url || undefined), [url]);\n\n const { fieldProps, labelProps } = useField({\n ...rest,\n ref: elementRef,\n });\n\n const { dropProps, isDropTarget } = useDrop({\n ref: elementRef,\n onDrop: async (e) => {\n if (isDisabled) return;\n const files = await onDropOrPaste({ items: e.items });\n if (files.length) {\n setUrl(files[0]);\n }\n onDrop?.(e);\n },\n ...rest,\n });\n\n const { clipboardProps } = useClipboard({\n onPaste: async (items) => {\n if (isDisabled) return;\n const files = await onDropOrPaste({ items });\n if (files.length) {\n setUrl(files[0]);\n }\n onPaste?.(items);\n },\n ...rest,\n });\n\n const reset = () => {\n setUrl(null);\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n };\n\n const inputProps = {\n type: \"file\",\n onChange: ((e) => {\n const files = [...(e.target.files as FileList)];\n setUrl(files[0]);\n\n rest.onChange?.(e);\n }) as ChangeEventHandler<HTMLInputElement>,\n accept,\n disabled: isDisabled,\n } as React.ComponentProps<\"input\">;\n\n const { focusProps, isFocused, isFocusVisible } = useFocusRing({\n within: true,\n });\n const { hoverProps, isHovered } = useHover({ isDisabled });\n\n const { imgProps, isLoading, isLoaded } = useImage({\n src: _url,\n alt: imageAlt || \"\",\n });\n\n const chooseFileButtonProps = {\n label: pickerButtonLabel || formatMessage(\"selectImage\"),\n onPress: () => elementRef.current?.click(),\n variant: \"secondary\",\n isDisabled,\n excludeFromTabOrder: true,\n className: classNames(\n buttonCn({ isFocusVisible }),\n {\n [opacityNoneCn]: isDropTarget && !isDisabled,\n },\n pickerButtonClassName,\n ),\n style: pickerButtonStyle,\n } as ActionButtonProps;\n\n const dataAttrs = filterTruthyValues({\n \"data-loaded\": isLoaded,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n \"data-hovered\": isHovered,\n \"data-focused\": isFocused,\n \"data-drop-target\": isDropTarget,\n \"data-disabled\": isDisabled,\n \"data-focus-visible\": isFocusVisible,\n });\n\n return (\n <Box\n {...dataAttrs}\n className={classNames(\"BaselineUI-ImageDropZone\", className)}\n display=\"flex\"\n flexDirection=\"column\"\n alignItems=\"center\"\n style={style}\n ref={ref}\n >\n <label\n {...mergeProps(dropProps, hoverProps, focusProps, labelProps)}\n className={classNames(\n imageDropZoneCn({\n isInline,\n isHovered,\n isDisabled,\n hasLoadedImage: !!_url && isLoaded,\n showFocusRing: isDropTarget || (!!_url && isFocusVisible),\n }),\n labelClassName,\n )}\n style={labelStyle}\n ref={elementRef}\n >\n <VisuallyHidden>\n <input\n {...mergeProps(fieldProps, clipboardProps, inputProps)}\n ref={inputRef}\n />\n </VisuallyHidden>\n\n {!_url && <ActionButton {...chooseFileButtonProps} />}\n\n {!!_url &&\n (isLoading ? (\n <ProgressSpinner />\n ) : (\n <img\n className={previewCn({\n isInline,\n isDisabled,\n hasLoadedImage:\n !!_url && isLoaded && includeCheckeredBackground,\n })}\n {...imgProps}\n />\n ))}\n </label>\n\n {placeholder || clearLabel ? (\n <div\n style={footerStyle}\n className={classNames(\n freehandCanvasFooterCn({ isInline, isDisabled }),\n footerClassName,\n )}\n >\n {(!!_url || !placeholder) && clearLabel ? (\n <ActionButton\n size=\"sm\"\n variant=\"ghost\"\n label={clearLabel}\n isDisabled={isDisabled}\n onPress={reset}\n />\n ) : (\n <ActionButton\n size=\"sm\"\n variant=\"ghost\"\n label={placeholder as string}\n isDisabled={true}\n />\n )}\n </div>\n ) : null}\n </Box>\n );\n },\n);\n\nImageDropZone.displayName = \"ImageDropZone\";\n\nfunction getImageSrc(imageSrc: string | File | undefined) {\n if (imageSrc
|
|
30
|
+
"ImageDropZone": "import { useControlledState } from \"@react-stately/utils\";\nimport React, { useMemo } from \"react\";\nimport {\n VisuallyHidden,\n mergeProps,\n useClipboard,\n useDrop,\n useField,\n useFocusRing,\n useHover,\n} from \"react-aria\";\n\nimport messages from \"./intl\";\nimport { classNames, filterTruthyValues, invariant } from \"../../utils\";\nimport { buttonCn } from \"../ActionButton/ActionButton.css\";\nimport { Box } from \"../Box\";\nimport { freehandCanvasFooterCn } from \"../FreehandCanvas/FreehandCanvas.css\";\nimport { ProgressSpinner } from \"../ProgressSpinner\";\nimport { onDropOrPaste } from \"../FileUpload/hooks/useFileUpload\";\nimport { imageDropZoneCn, opacityNoneCn, previewCn } from \"./ImageDropZone.css\";\nimport { ActionButton } from \"../ActionButton\";\nimport { useI18n, useImage } from \"../../hooks\";\n\nimport type { ActionButtonProps } from \"../ActionButton\";\nimport type { ChangeEventHandler } from \"react\";\nimport type { ImageDropZoneProps } from \"./ImageDropZone.types\";\n\nexport const ImageDropZone = React.forwardRef<\n HTMLDivElement,\n ImageDropZoneProps\n>(\n (\n {\n className,\n style,\n isInline = true,\n accept = \"image/*\",\n defaultImageSrc,\n imageSrc,\n imageAlt,\n pickerButtonLabel,\n isDisabled,\n onDrop,\n onPaste,\n includeCheckeredBackground = true,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n pickerButtonStyle,\n pickerButtonClassName,\n footerClassName,\n footerStyle,\n clearLabel,\n placeholder,\n labelStyle,\n labelClassName,\n ...rest\n },\n ref,\n ) => {\n const elementRef = React.useRef<HTMLLabelElement>(null);\n const inputRef = React.useRef<HTMLInputElement>(null);\n const { formatMessage } = useI18n(messages);\n\n const [url, setUrl] = useControlledState(\n imageSrc,\n defaultImageSrc || null,\n (value) => {\n invariant(typeof value !== \"string\");\n\n rest.onValueChange?.(value ? [value] : []);\n },\n );\n\n const _url = useMemo(() => getImageSrc(url || undefined), [url]);\n\n const { fieldProps, labelProps } = useField({\n ...rest,\n ref: elementRef,\n });\n\n const { dropProps, isDropTarget } = useDrop({\n ref: elementRef,\n onDrop: async (e) => {\n if (isDisabled) return;\n const files = await onDropOrPaste({ items: e.items });\n if (files.length) {\n setUrl(files[0]);\n }\n onDrop?.(e);\n },\n ...rest,\n });\n\n const { clipboardProps } = useClipboard({\n onPaste: async (items) => {\n if (isDisabled) return;\n const files = await onDropOrPaste({ items });\n if (files.length) {\n setUrl(files[0]);\n }\n onPaste?.(items);\n },\n ...rest,\n });\n\n const reset = () => {\n setUrl(null);\n if (inputRef.current) {\n inputRef.current.value = \"\";\n }\n };\n\n const inputProps = {\n type: \"file\",\n onChange: ((e) => {\n const files = [...(e.target.files as FileList)];\n setUrl(files[0]);\n\n rest.onChange?.(e);\n }) as ChangeEventHandler<HTMLInputElement>,\n accept,\n disabled: isDisabled,\n } as React.ComponentProps<\"input\">;\n\n const { focusProps, isFocused, isFocusVisible } = useFocusRing({\n within: true,\n });\n const { hoverProps, isHovered } = useHover({ isDisabled });\n\n const { imgProps, isLoading, isLoaded } = useImage({\n src: _url,\n alt: imageAlt || \"\",\n });\n\n const chooseFileButtonProps = {\n label: pickerButtonLabel || formatMessage(\"selectImage\"),\n onPress: () => elementRef.current?.click(),\n variant: \"secondary\",\n isDisabled,\n excludeFromTabOrder: true,\n className: classNames(\n buttonCn({ isFocusVisible }),\n {\n [opacityNoneCn]: isDropTarget && !isDisabled,\n },\n pickerButtonClassName,\n ),\n style: pickerButtonStyle,\n } as ActionButtonProps;\n\n const dataAttrs = filterTruthyValues({\n \"data-loaded\": isLoaded,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n \"data-hovered\": isHovered,\n \"data-focused\": isFocused,\n \"data-drop-target\": isDropTarget,\n \"data-disabled\": isDisabled,\n \"data-focus-visible\": isFocusVisible,\n });\n\n return (\n <Box\n {...dataAttrs}\n className={classNames(\"BaselineUI-ImageDropZone\", className)}\n display=\"flex\"\n flexDirection=\"column\"\n alignItems=\"center\"\n style={style}\n ref={ref}\n >\n <label\n {...mergeProps(dropProps, hoverProps, focusProps, labelProps)}\n className={classNames(\n imageDropZoneCn({\n isInline,\n isHovered,\n isDisabled,\n hasLoadedImage: !!_url && isLoaded,\n showFocusRing: isDropTarget || (!!_url && isFocusVisible),\n }),\n labelClassName,\n )}\n style={labelStyle}\n ref={elementRef}\n >\n <VisuallyHidden>\n <input\n {...mergeProps(fieldProps, clipboardProps, inputProps)}\n ref={inputRef}\n />\n </VisuallyHidden>\n\n {!_url && <ActionButton {...chooseFileButtonProps} />}\n\n {!!_url &&\n (isLoading ? (\n <ProgressSpinner />\n ) : (\n <img\n className={previewCn({\n isInline,\n isDisabled,\n hasLoadedImage:\n !!_url && isLoaded && includeCheckeredBackground,\n })}\n {...imgProps}\n />\n ))}\n </label>\n\n {placeholder || clearLabel ? (\n <div\n style={footerStyle}\n className={classNames(\n freehandCanvasFooterCn({ isInline, isDisabled }),\n footerClassName,\n )}\n >\n {(!!_url || !placeholder) && clearLabel ? (\n <ActionButton\n size=\"sm\"\n variant=\"ghost\"\n label={clearLabel}\n isDisabled={isDisabled}\n onPress={reset}\n />\n ) : (\n <ActionButton\n size=\"sm\"\n variant=\"ghost\"\n label={placeholder as string}\n isDisabled={true}\n />\n )}\n </div>\n ) : null}\n </Box>\n );\n },\n);\n\nImageDropZone.displayName = \"ImageDropZone\";\n\nfunction getImageSrc(imageSrc: string | File | undefined) {\n if (!imageSrc || typeof imageSrc === \"string\") {\n return imageSrc;\n }\n\n return URL.createObjectURL(imageSrc);\n}\n",
|
|
31
31
|
"ImageGallery": "import { useControlledState } from \"@react-stately/utils\";\nimport React, { useCallback, useContext, useEffect, useState } from \"react\";\nimport { mergeRefs } from \"@react-aria/utils\";\nimport {\n CollectionRendererContext,\n DropIndicator,\n} from \"react-aria-components\";\nimport { sprinkles } from \"@baseline-ui/tokens\";\n\nimport { classNames } from \"../../utils\";\nimport { defineMessages, useI18n } from \"../../hooks\";\nimport { AlertDialog } from \"../AlertDialog\";\nimport { UNSAFE_ListBox as ListBox } from \"../UNSAFE_ListBox\";\nimport { Modal, ModalContent } from \"../Modal\";\nimport { DragPreviewContent } from \"../shared/components/DragPreviewContent\";\nimport {\n dropIndicatorCn,\n imageGalleryCn,\n imageGalleryOptionCn,\n} from \"./ImageGallery.css\";\nimport { ImageGalleryItem } from \"./ImageGalleryItem\";\nimport {\n getByKey,\n imageItemsToListOption,\n listOptionToImageItems,\n moveAfter,\n moveBefore,\n} from \"./utils\";\nimport { getDynamicClassNameForCollectionItem } from \"../../utils/style\";\nimport { useDragAndDrop } from \"../ListBox/hooks/useDragAndDrop\";\n\nimport type { Key } from \"react-aria\";\nimport type { UNSAFE_ListBoxProps as ListBoxProps } from \"../UNSAFE_ListBox\";\nimport type { DroppableCollectionReorderEvent } from \"@react-types/shared\";\nimport type { ImageGalleryProps } from \"./ImageGallery.types\";\n\nconst Image = {\n src: \"src\",\n alt: \"alt\",\n} as const;\n\nexport const ImageSize = {\n sm: 102,\n md: 170,\n} as const;\n\nexport const ImageGallery = React.forwardRef<HTMLDivElement, ImageGalleryProps>(\n (\n {\n className,\n style,\n fit = \"cover\",\n onReorder,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n onDelete,\n imageWidth = ImageSize.sm,\n aspectRatio = 3 / 4,\n items,\n defaultItems = [],\n onKeyDown,\n imageContainerClassName,\n imageClassName,\n labelClassName,\n onListChange,\n renderImage,\n layoutTransition,\n imageDimensions = {\n width: imageWidth,\n aspectRatio,\n },\n imageContainerStyle,\n deleteConfirmationTitle = \"Are you sure you want to delete this item?\",\n ...rest\n },\n ref,\n ) => {\n const { isVirtualized } = useContext(CollectionRendererContext);\n const divRef = React.useRef<HTMLDivElement>(null);\n const [itemsToDelete, setItemsToDelete] = useState<Key[]>([]);\n const { formatMessage } = useI18n();\n\n useEffect(() => {\n if (aspectRatio || imageWidth) {\n console.warn(\n \"ImageGallery: aspectRatio and imageWidth are deprecated. Use imageDimensions instead.\",\n );\n }\n }, [imageWidth, aspectRatio]);\n\n const [selectedKeys, setSelectedKeys] = useControlledState(\n rest.selectedKeys,\n rest.defaultSelectedKeys ?? [],\n rest.onSelectionChange,\n );\n\n const [list, setList] = useControlledState(\n items ? imageItemsToListOption(items) : undefined,\n imageItemsToListOption(defaultItems),\n onListChange\n ? (_items) => {\n onListChange?.(listOptionToImageItems(_items));\n }\n : undefined,\n );\n\n const _onReorder = useCallback(\n (e: DroppableCollectionReorderEvent) => {\n const referenceKey = e.target.key;\n const keysToMove = e.keys;\n\n if (e.target.dropPosition === \"before\") {\n const newList = moveBefore(list, referenceKey, keysToMove);\n setList(newList);\n } else if (e.target.dropPosition === \"after\") {\n const newList = moveAfter(list, referenceKey, keysToMove);\n setList(newList);\n }\n onReorder?.(e);\n },\n [list, onReorder, setList],\n );\n\n const { dragAndDropHooks } = useDragAndDrop({\n onReorder: _onReorder,\n isDisabled: !onReorder,\n renderDragPreview: (items) => (\n <DragPreviewContent\n items={items}\n containerClassName=\".BaselineUI-ImageGallery\"\n previewClassName={imageGalleryOptionCn()}\n itemDataAttribute=\"data-image-key\"\n showCount={true}\n />\n ),\n getItems: (keys) =>\n [...keys].map((key) => {\n const item = getByKey(list, key);\n\n return {\n [Image.src]: item?.src || \"\",\n [Image.alt]: item?.alt || \"\",\n key: key as string,\n };\n }),\n renderDropIndicator(target) {\n return (\n <DropIndicator\n target={target}\n className={classNames(\n dropIndicatorCn({ isVirtualized: !!isVirtualized }),\n \"BaselineUI-DropIndicator\",\n )}\n />\n );\n },\n });\n\n const _onDelete = useCallback(() => {\n if (!onDelete) return;\n\n if (itemsToDelete.length) {\n setList(list.filter((item) => !itemsToDelete.includes(item.id)));\n\n onDelete(itemsToDelete);\n setItemsToDelete([]);\n }\n }, [itemsToDelete, list, onDelete, setList]);\n\n const renderOption = useCallback<\n Exclude<ListBoxProps[\"renderOption\"], undefined>\n >(\n (item, options) => {\n const galleryItem = {\n id: item.id,\n label: item.label,\n src: item.data?.src,\n alt: item.data?.alt,\n };\n\n return (\n <ImageGalleryItem\n key={item.id}\n item={item}\n options={options}\n fit={fit}\n onDelete={\n onDelete\n ? (id: string) => {\n setItemsToDelete([id]);\n }\n : undefined\n }\n renderImage={renderImage}\n className={getDynamicClassNameForCollectionItem(\n imageContainerClassName,\n galleryItem,\n options,\n )}\n imageClassName={imageClassName}\n imageLabelClassName={labelClassName}\n imageDimensions={imageDimensions}\n style={imageContainerStyle}\n layoutTransition={layoutTransition}\n />\n );\n },\n [\n fit,\n onDelete,\n renderImage,\n imageContainerClassName,\n imageClassName,\n labelClassName,\n imageDimensions,\n imageContainerStyle,\n layoutTransition,\n ],\n );\n\n useEffect(() => {\n const container = divRef.current;\n if (!container) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n onKeyDown?.(e);\n\n if (e.key === \"Backspace\" || e.key === \"Delete\") {\n if (!onDelete) return;\n\n const _selectedKeys = [...selectedKeys];\n // If there are selected items, delete them\n // Otherwise, delete the item that was focused\n if (_selectedKeys.length) {\n setItemsToDelete([...selectedKeys]);\n } else {\n const key = (e.target as HTMLUListElement).dataset.key as string;\n setItemsToDelete([key]);\n }\n }\n };\n\n container.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n container.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [onDelete, onKeyDown, selectedKeys]);\n\n return (\n <>\n <ListBox\n {...rest}\n ref={mergeRefs(ref, divRef)}\n style={style}\n className={classNames(\n imageGalleryCn,\n \"BaselineUI-ImageGallery\",\n className,\n )}\n data-block-id={dataBlockId}\n data-block-class={dataBlockClass}\n selectedKeys={selectedKeys}\n items={list}\n dragAndDropHooks={dragAndDropHooks}\n layout=\"grid\"\n orientation=\"vertical\"\n renderOption={renderOption}\n onSelectionChange={setSelectedKeys}\n optionClassName={\n onReorder && !isVirtualized\n ? sprinkles({\n marginLeft: \"sm\",\n })\n : undefined\n }\n />\n <Modal\n isOpen={!![...itemsToDelete].length}\n onOpenChange={(open) => {\n if (!open) {\n setItemsToDelete([]);\n }\n }}\n >\n <ModalContent isDismissable={true}>\n <AlertDialog\n showCloseButton={false}\n title={\n typeof deleteConfirmationTitle === \"function\"\n ? deleteConfirmationTitle(\n selectedKeys === \"all\" ? \"all\" : new Set(selectedKeys),\n )\n : deleteConfirmationTitle\n }\n primaryActionLabel={formatMessage(messages.delete)}\n cancelLabel={formatMessage(messages.cancel)}\n onCancel={() => {\n setItemsToDelete([]);\n }}\n onPrimaryAction={_onDelete}\n autoFocusButton=\"cancel\"\n />\n </ModalContent>\n </Modal>\n </>\n );\n },\n);\n\nImageGallery.displayName = \"ImageGallery\";\n\nexport const messages = defineMessages({\n delete: {\n id: \"delete\",\n defaultMessage: \"Delete\",\n },\n cancel: {\n id: \"cancel\",\n defaultMessage: \"Cancel\",\n },\n loading: {\n id: \"loading\",\n defaultMessage: \"Loading\",\n },\n});\n",
|
|
32
32
|
"InlineAlert": "import {\n CheckmarkCircleFilledIcon,\n ErrorAltCircleFilledIcon,\n InfoCircleFilledIcon,\n WarningFilledIcon,\n XIcon,\n} from \"@baseline-ui/icons/16\";\nimport {\n CheckCircleFilledIcon as CheckFilledIcon20,\n ErrorAltCircleFilledIcon as ErrorAltFilledIcon20,\n InfoCircleFilledIcon as InfoFilledIcon20,\n WarningFilledIcon as WarningFilledIcon20,\n} from \"@baseline-ui/icons/20\";\nimport React from \"react\";\n\nimport messages from \"./intl\";\nimport { classNames } from \"../../utils\";\nimport { ActionButton, ActionIconButton } from \"../\";\nimport {\n contentCn,\n inlineAlertCn,\n inlineAlertDescriptionCn,\n inlineAlertEndCn,\n inlineAlertIconCn,\n inlineAlertTitleCn,\n inlineStartCn,\n} from \"./InlineAlert.css\";\nimport { useI18n } from \"../../hooks\";\n\nimport type { InlineAlertProps } from \"./InlineAlert.types\";\nimport type Messages from \"./intl/en.json\";\n\nconst icons = {\n error: { sm: ErrorAltCircleFilledIcon, md: ErrorAltFilledIcon20 },\n info: { sm: InfoCircleFilledIcon, md: InfoFilledIcon20 },\n success: { sm: CheckmarkCircleFilledIcon, md: CheckFilledIcon20 },\n warning: { sm: WarningFilledIcon, md: WarningFilledIcon20 },\n};\n\nexport const InlineAlert = React.forwardRef<HTMLDivElement, InlineAlertProps>(\n (\n {\n className,\n description,\n actionLabel,\n onAction,\n style,\n variant = \"info\",\n title,\n arrangement = \"single\",\n onClose,\n size = \"sm\",\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n elementProps,\n },\n ref,\n ) => {\n const intl = useI18n<typeof Messages>(messages);\n\n const actionButton = actionLabel && (\n <ActionButton\n variant={arrangement === \"compact\" ? \"tertiary\" : \"ghost\"}\n label={actionLabel}\n onPress={onAction}\n />\n );\n\n const Icon = icons[variant][size];\n\n return (\n <div\n className={classNames(\n inlineAlertCn({\n variant,\n arrangement,\n hasButton: !!actionLabel || !!onClose,\n hasCloseButton: !!onClose,\n }),\n \"BaselineUI-InlineAlert\",\n className,\n )}\n data-block-id={dataBlockId}\n data-block-class={dataBlockClass}\n style={style}\n role=\"alert\"\n ref={ref}\n {...elementProps?.root}\n >\n <div className={inlineStartCn({ arrangement })}>\n <Icon className={inlineAlertIconCn({ variant })} size={16} />\n\n <div\n className={contentCn({ arrangement })}\n {...elementProps?.content}\n >\n <h3\n className={inlineAlertTitleCn({ size })}\n {...elementProps?.title}\n >\n {title}\n </h3>\n <section\n className={inlineAlertDescriptionCn({ size })}\n {...elementProps?.description}\n >\n {description}\n </section>\n </div>\n\n {arrangement === \"compact\" && actionButton}\n </div>\n\n <div className={inlineAlertEndCn({ arrangement })}>\n {arrangement !== \"compact\" && actionButton}\n {onClose ? (\n <ActionIconButton\n variant=\"secondary\"\n icon={XIcon}\n size=\"sm\"\n onPress={onClose}\n aria-label={intl.formatMessage(\"close\")}\n {...elementProps?.close}\n />\n ) : null}\n </div>\n </div>\n );\n },\n);\n\nInlineAlert.displayName = \"InlineAlert\";\n",
|
|
33
33
|
"InlineToolbar": "import { themeVars } from \"@baseline-ui/tokens\";\nimport {\n getActiveElement,\n getOwnerDocument,\n getOwnerWindow,\n mergeRefs,\n nodeContains,\n useViewportSize,\n} from \"@react-aria/utils\";\nimport { useControlledState } from \"@react-stately/utils\";\nimport { useGranularEffect, useGranularLayoutEffect } from \"granular-hooks\";\nimport React, {\n Fragment,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n} from \"react\";\nimport {\n FocusScope,\n mergeProps,\n useInteractOutside,\n useKeyboard,\n useOverlayPosition,\n} from \"react-aria\";\nimport { useOverlayTriggerState } from \"react-stately\";\nimport { useToolbar } from \"@react-aria/toolbar\";\n\nimport { classNames, findFocusableElements, invariant } from \"../../utils\";\nimport { arrowInlineCn, inlineToolbarContentCn } from \"./InlineToolbar.css\";\nimport { InlineToolbarButton } from \"./InlineToolbarButton\";\nimport { Portal } from \"../Portal\";\nimport { Separator } from \"../Separator\";\nimport { useTextSelection } from \"../../hooks\";\n\nimport type { InlineToolbarProps, Item } from \"./InlineToolbar.types\";\n\nexport const InlineToolbar = React.forwardRef<\n HTMLDivElement,\n InlineToolbarProps\n>(\n (\n {\n className,\n onAction,\n items,\n scrollRef,\n placement = \"top\",\n children,\n \"data-block-id\": dataBlockId,\n \"data-block-class\": dataBlockClass,\n disabledKeys,\n isDisabled,\n anchorRect,\n ...rest\n },\n ref,\n ) => {\n const divRef = React.useRef<HTMLDivElement>(null);\n const overlayRef = React.useRef<HTMLDivElement>(null);\n const triggerRef = React.useRef<HTMLDivElement>(null);\n const selectionRef = React.useRef<Selection | null>(null);\n const [selectionRect, setSelectionRect] = useControlledState(\n anchorRect,\n null,\n );\n\n const state = useOverlayTriggerState(rest);\n\n const {\n overlayProps,\n arrowProps,\n placement: placementAxis,\n updatePosition,\n } = useOverlayPosition({\n arrowSize: 13,\n targetRef: triggerRef,\n arrowBoundaryOffset: 8,\n offset: 12,\n overlayRef,\n isOpen: state.isOpen,\n placement,\n scrollRef,\n ...rest,\n });\n\n const size = useViewportSize();\n\n useGranularEffect(\n () => {\n if (selectionRef.current) {\n setSelectionRect(\n selectionRef.current.getRangeAt(0).getBoundingClientRect(),\n );\n }\n },\n [size],\n [setSelectionRect],\n );\n\n const toolbarRef = React.useRef<HTMLDivElement>(null);\n\n const { toolbarProps } = useToolbar(\n {\n ...rest,\n isSingleTabStop: false,\n },\n toolbarRef,\n );\n\n useInteractOutside({\n ref: toolbarRef,\n onInteractOutside() {\n state.close();\n setSelectionRect(null);\n },\n });\n\n useEffect(() => {\n if (isDisabled && state.isOpen) {\n state.close();\n }\n }, [isDisabled, state]);\n\n useTextSelection({\n ref: divRef,\n isDisabled,\n onSelectionChange: (selection) => {\n if (selection.isCollapsed) {\n selectionRef.current = null;\n setSelectionRect(null);\n } else {\n selectionRef.current = selection;\n\n setSelectionRect(selection.getRangeAt(0).getBoundingClientRect());\n }\n },\n });\n\n const handleScroll = useCallback(() => {\n const selection = selectionRef.current;\n if (selection) {\n setSelectionRect(selection.getRangeAt(0).getBoundingClientRect());\n }\n }, [setSelectionRect]);\n\n useGranularEffect(\n () => {\n const ownerDocument = getOwnerDocument(divRef.current);\n\n const _scrollRef = scrollRef?.current ?? ownerDocument.body;\n\n _scrollRef?.addEventListener(\"scroll\", handleScroll);\n\n return () => {\n _scrollRef?.removeEventListener(\"scroll\", handleScroll);\n };\n },\n [scrollRef],\n [updatePosition],\n );\n\n useLayoutEffect(() => {\n if (selectionRect && !state.isOpen) {\n state.open();\n } else if (!selectionRect) {\n state.close();\n }\n }, [selectionRect, state]);\n\n useGranularLayoutEffect(updatePosition, [selectionRect], [updatePosition]);\n\n const _placement =\n placementAxis === \"center\" ? \"top\" : placementAxis || \"top\";\n\n const { keyboardProps } = useKeyboard({\n onKeyDown(e) {\n if (e.key === \"Escape\") {\n state.close();\n setSelectionRect(null);\n } else {\n e.continuePropagation();\n }\n },\n });\n\n const handleToolbarPress = useCallback(\n (item: Item) => {\n invariant(selectionRef.current, \"No selection\");\n onAction?.(item.id, selectionRef.current);\n setSelectionRect(null);\n selectionRef.current?.removeAllRanges();\n },\n [onAction, setSelectionRect],\n );\n\n const _items =\n typeof items === \"function\" ? items(selectionRef.current) : items;\n\n const overlayPositionStyle = useMemo<React.CSSProperties>(() => {\n const ownerWindow = getOwnerWindow(triggerRef.current);\n\n return {\n position: \"absolute\",\n top: (selectionRect?.top || 0) + ownerWindow.scrollY,\n left: (selectionRect?.left || 0) + ownerWindow.scrollX,\n width: selectionRect?.width,\n height: selectionRect?.height,\n visibility: \"hidden\",\n };\n }, [selectionRect]);\n\n const _disabledKeys =\n typeof disabledKeys === \"function\"\n ? disabledKeys(selectionRef.current)\n : disabledKeys;\n\n useEffect(\n function moveFocusToToolbarOnTab() {\n if (!state.isOpen) return;\n\n const ownerDocument = getOwnerDocument(divRef.current);\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Tab\" && state.isOpen && toolbarRef.current) {\n const focusableEls = findFocusableElements(toolbarRef.current);\n\n const first = focusableEls[0] as HTMLElement;\n\n if (!first) return;\n\n const activeElement = getActiveElement(ownerDocument);\n\n const isCurrentlyFocusedElementOutsideToolbar = !nodeContains(\n toolbarRef.current,\n activeElement,\n );\n\n if (isCurrentlyFocusedElementOutsideToolbar) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n ownerDocument.addEventListener(\"keydown\", handleKeyDown);\n\n return () => {\n ownerDocument.removeEventListener(\"keydown\", handleKeyDown);\n };\n },\n [state.isOpen],\n );\n\n return (\n <>\n {React.cloneElement(children, { ref: divRef })}\n\n <Portal>\n <div ref={mergeRefs(triggerRef, ref)} style={overlayPositionStyle} />\n </Portal>\n\n {state.isOpen && selectionRect ? (\n <div\n {...overlayProps}\n ref={overlayRef}\n data-block-id={dataBlockId}\n data-block-class={dataBlockClass}\n className=\"BaselineUI-InlineToolbar\"\n >\n <FocusScope contain={true} restoreFocus={true}>\n <div\n className={classNames(inlineToolbarContentCn, className)}\n {...mergeProps(toolbarProps, keyboardProps)}\n aria-keyshortcuts=\"Tab Shift+Tab ArrowRight ArrowLeft\"\n ref={toolbarRef}\n >\n {_items.map((item, i) => {\n const Icon = item.icon;\n\n return (\n <Fragment key={item.id}>\n <InlineToolbarButton\n onPress={() => {\n handleToolbarPress(item);\n }}\n aria-label={item[\"aria-label\"]}\n isDisabled={new Set(_disabledKeys).has(item.id)}\n >\n {item.label || (Icon && <Icon size={24} />)}\n </InlineToolbarButton>\n {i !== items.length - 1 && (\n <Separator\n orientation=\"vertical\"\n variant=\"secondary\"\n style={{\n backgroundColor: themeVars.color.border.strong,\n }}\n />\n )}\n </Fragment>\n );\n })}\n </div>\n </FocusScope>\n\n <div\n {...arrowProps}\n className={arrowInlineCn({ placement: _placement })}\n />\n </div>\n ) : null}\n </>\n );\n },\n);\n\nInlineToolbar.displayName = \"InlineToolbar\";\n",
|
package/package.json
CHANGED