Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(feat) Option to insert multiple images #213

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

dennispassway
Copy link

In my projects I always use the sanity-plugin-media, so thanks for creating it! In many of these projects I also run into that I want to insert multiple images at once in an image array (ie for a carousel or gallery). Searching around, I found that more people have this issue, see the Github issues below or the Sanity Slack:

In this pull request, I add the option to insert multiple images at once. By adding the selectionType 'multiple' option, you can determine that the asset source should pass multiple assets. This is not officially supported, but I figured that is where Sanity wishes to go with the selectionType property, since it currently only supports "single".

In this PR I support "multiple", without breaking- or changing any of the current functionality. If you do not pass the selectionType="multiple" it will work the same.

To make this work in a project, you have to create a custom component that creates a AssetSourceComponent with the property selectionType set to multiple. I will pass mine as an example so you can see how this works:

'use client';

import { AssetFromSource, StringInputProps, set, useFormBuilder } from 'sanity';
import { Button, Stack, Text } from '@sanity/ui';
import { FaRegImages } from 'react-icons/fa';
import React, { Fragment, MouseEventHandler, useCallback, useMemo, useState } from 'react';

export const MultipleImagesInputComponent = (properties: StringInputProps) => {
  const { onChange, value, renderDefault } = properties;
  const formBuilder = useFormBuilder();

  const [showAssetSource, setShowAssetSource] = useState(false);

  // I would love for this not to use internal but it is currently the only way I think.
  const AssetSourceComponent = useMemo(
    () => formBuilder?.__internal?.image?.assetSources[0]?.component,
    [formBuilder?.__internal?.image?.assetSources]
  );

  const handleAssetSourceClosed = useCallback(() => {
    setShowAssetSource(false);
  }, []);

  const handleSelectAssetFromSource = useCallback(
    (assetsFromSource: AssetFromSource[]) => {
      try {
        const assetReferences = assetsFromSource.map((asset) => ({
          _key: randomKey(),
          _type: 'image',
          asset: {
            _ref: asset.value,
            _type: 'reference',
          },
        }));

        const newValue = [...(value || []), ...assetReferences];
        onChange(set(newValue));
      } catch (error) {
        console.error(error);
      } finally {
        setShowAssetSource(false);
      }
    },
    [onChange, value]
  );

  const onMultipleImagesClick: MouseEventHandler<HTMLButtonElement> = useCallback(() => {
    setShowAssetSource(true);
  }, []);

  return (
    <Fragment>
      <Stack space={4}>
        {renderDefault(properties)}
        <Text size={2} muted align="center">
          💡 To upload multiple images, simply drag them on the list above.
        </Text>
        <Button
          onClick={onMultipleImagesClick}
          mode="ghost"
          icon={FaRegImages}
          text="Add multiple images from media"
        />
      </Stack>

      {showAssetSource && !!AssetSourceComponent ? (
        <AssetSourceComponent
          accept="image/*"
          assetType="image"
          onClose={handleAssetSourceClosed}
          onSelect={handleSelectAssetFromSource}
          selectedAssets={[]}
          selectionType="multiple" // This is where the magic happens
        />
      ) : undefined}
    </Fragment>
  );
};

function randomKey() {
  return Math.random().toString(36).slice(2);
}

I hope you will find this functionality useful. If there is a better way to achieve what I'm trying to do I love to hear that as well. Searching around, I found many people with this wish, but no solution, therefore I created this PR.

@dennispassway
Copy link
Author

@robinpyon I'm not sure if you are the right person to tag, if not, could you point me in the right direction? I haven't had a response from any of the maintainers on this PR in 2 weeks and would love to hear your thoughts.

@dennispassway
Copy link
Author

@kmelve I haven't heard anything on this PR for a month now... Do you know who I have to connect to this?

@kmelve
Copy link
Member

kmelve commented Jun 27, 2024

Hi @dennispassway – thanks for your work and contribution here! We're definitively interested in looking at merging this; hopefully we'll find time to get to it over the next couple of weeks 🙇

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants