Giter Site home page Giter Site logo

i-like-robots / react-tag-autocomplete Goto Github PK

View Code? Open in Web Editor NEW
112.0 112.0 10.0 2.21 MB

⚛️ A simple, accessible, tagging component ready to drop into your React projects (new repo)

Home Page: https://i-like-robots.github.io/react-tag-autocomplete/

License: ISC License

JavaScript 14.54% HTML 3.35% CSS 2.98% TypeScript 78.99% Shell 0.13%

react-tag-autocomplete's People

Contributors

dependabot[bot] avatar i-like-robots avatar niccai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-tag-autocomplete's Issues

Unable to clear input in #ReactTag

Hi matt,

#I am facing an issue while creating custom ref with clear input.

const api = useRef( [ ] );
api.current =fields.map((_, i) =>api.current[ i ] ?? createRef( ) );
case:
1.I have created a ref inside loop in ReactTags
exp:

here [index] is the Index value of mappping statement

  1. I have created a button to clear this input
    <Button onClick={ ( )=>clear( index ) }>
    clear Input

  2. Whenever i will try to clear input it's working.
    this is my clearInput function:
    const clear = ( i ) => {
    api.current[i].current.input.focus( )
    } ;

This is my api ref response

looping ref

Add delimiters option

The old project had a delimiters option to control what keys (other than return) cause a new tag. How can I get this effect with the new project?

Get `TagRendererProps.onDelete` back in v7, to use as `TagComponentProps.onDelete` from v6

Describe the solution you'd like

In v6 of this component, TagComponentProps had an onDelete prop that came in handy when using tagComponent to customize how tags were rendered.

The new renderTag prop, which according to the migration guide is tagComponent's replacement, does not provide onDelete anymore.

Describe alternatives you've considered

I considered using the new API which is exposed via ref, but it does not include a method to delete a tag, but only to select one.

Additional context

This property was useful if custom tag rendering also had its own delete button.

Allow resetting the input

Because the Input component is providing value attribute, the default HTML behavior of an <input type="reset"> does not clear the <input type="text">, since HTML input does not reset when a value attr is provided or set via setAttribute.

We are able to reset the selected prop but we cannot reset the input value attr as there is no prop to do so.

I can see a few ways here:

  1. Change Input.tsx to not use value as a prop, but rather a useEffect that sets the input value imperatively. This allows the standard HTML type="reset" to clear it
  2. Add a input prop to <ReactTags> that is passed to Input.tsx's value for a fully controlled input

The latter is probably more reacty

Input sizer may have wrong font size assigned in Safari

Expected behaviour

The text input width accurately matches the text content it contains. The hidden "sizer" element accurately mimics the font of the input.

Current behaviour

In Safari the text input may have a smaller width applied which crops the text content. The hidden "sizer" element has the wrong font applied.

Steps to Reproduce

Steps to reproduce the problem:

  1. Load the demo in Safari
  2. Refresh until the bug is seen

Example and screenshots

Screenshot 2023-07-04 at 17 28 21

With the hidden sizer element made visible, the font face and size is clearly wrong:

Screenshot 2023-07-04 at 17 28 47

Additional context

Whilst debugging this issue the CSSStyleDeclaration generated by the input always reports the correct font face and size, even when a breakpoint is applied at the moment the incorrect value is retrieved. The stylesheet is loaded synchronously and script deferred (i.e. waits for stylesheets) so this appears to be a Safari bug.

This issue does not affect the v6 version of this component, nor affects the react-input-autosize component.

onAddition/onDelete handler return value?

One difference I noticed compared to the old version is that the example has return true in the onAddition/onDelete handlers but it does not seem to be mentioned in the individual props’ docs. What is the purpose of the return value?

DelimiterKeys is not working

Hello there!

I don't know if it's just me but the 'delimiterKeys' don't seem to work.
My code is looking like this:

<ReactTags
   allowNew
   labelText="Tags:"
   selected={selectedTag}
   suggestions={[]}
   onAdd={onAdd}
   onDelete={onDelete}
   delimiterKeys={["Enter"]}
   noOptionsText="No matching tags"
   newOptionText={`Add Tag ${newTageName}`}
   onInput={((e) => setNewTageName(e))}
 />

When i press 'Enter', nothing happens. On the demo, it just work when you type the full tag name found in suggestions.

Export compound components instead of one giant component

I'm aware this may be out of scope for your v7 roadmap, but I wanted to share it here.

This is something that Radix/HeadlessUI use and I feel like is more flexible, especially when it comes to layout. The general pattern is to provide a Root that contains the context, and the individual pieces like Input and TagList as pieces that the developer can place in a DOM structure they want, and access the context when wrapped in Root.

This has the added benefit of reducing the number of top-level props — by exporting the lower level components themselves, a developer can take advantage of the native React component props, such as all the event handlers, className, etc, which can cut down on the top-level props like classNames, onInput, isDisabled, placeholderText

Note that you can do this in addition to maintaining a "Default plug-and-play assembly" component that folks who want to just quickly use it can, but offer additional flexibility to reduce prop surface/maintenance as use cases grow.

This was a nice article that I learned the concept from: https://www.smashingmagazine.com/2021/08/compound-components-react/

How to auto-highlight the first option

most @ mention/tag/typeahead UX on the web, auto highlights the first matching item without needing to hit arrow-down to select it. is there a way to have this behavior?

image

OnDelete Launched when object inside a <label>

Expected behaviour

When component is inside a label it should work as usual.

Current behaviour

When component is inside a label it launched onDelete event on object addition and some weird behaviours.

Steps to Reproduce

Steps to reproduce the problem:

  1. Create a component wrapping the with a tag like: <></>
  2. Make that component receive the selected, suggestions, onAdd, onDelete props from parent.
  3. Render the whole component and enjoy the bug.

Additional context

Maybe it's just me, I'm going to add my code below:

const TagPicker: FC<CustomTagPickerProps> = ({labelText, onUpdate, selectedTags, suggestions, ...rest}) => {
    const [component, setComponent] = useState<any>(null);

    return <>
        <label className={styles.Label}>{labelText}<br/>
           <ReactTags
              selected={selectedTags}
              suggestions={suggestions}
              onDelete={(i:number) => {
                  console.log("Delete");
                  const tags = selectedTags.slice(0);
                  tags.splice(i, 1);
                  onUpdate(tags);
              }}
              onAdd={(tag:Tag) => {
                  console.log("Add");
                  onUpdate([...selectedTags, tag]);
              }}
              labelText={labelText}
              allowNew={true}
              allowBackspace={false}
               />
        </label>
        </>
}

onUpdate method is a useState setter method from the parent while selectedTags is the useState value.

IMPORTANT INFO

I solve this issue by adding

onClick = { (e)=>{ e.preventDefault() } }

to the label tag. But I think there should be some issue with the component.

Selecting an option would cause a scroll jump if page is horizontally scrollable

Expected behaviour

Page should keep its horizontal scrolling position when user selects from the options list.

If page using this component has horizontal scrollbars, when user selects an option from the list, page scroll jumps due to this line in useOptions.ts

Current behaviour

The whole page's scroll position changes.

Steps to Reproduce

  1. Go to your demo page
  2. Inspect the page source and go to Elements tab
  3. Add an arbitrary width to the page container to make it horizontally scrollable. <main class="container"> -> <main class="container" style="width:4000px">
  4. From the demo autocomplete component included in the page, try selecting an option

Inconsistent behavior with `onShouldExpand` and `onShouldCollapse`

I'm trying to make the suggestions dropdown to not be displayed unless at least two characters have been input.

In order to do so, and following the docs, I have implemented the callbacks like this.

<ReactTags
  onShouldExpand={(value) => {
    console.log('Should expand', value);
    return value.length > 1;
  }}
  onShouldCollapse={(value) => {
    console.log('Should collapse', value);
    return value.length < 2;
  }}
  // [...]
/>

Expected behavior

The suggestions dropdown appears when the second character is input, and stays displayed as long as 2 or more characters remain.

As soon as the input has 1 or less characters, the suggestions dropdown is collapsed.

Current behaviour

I haven't debugged any further than using the console.logs above, but the onShouldExpand callback is always invoked onInput, but with the previous value. For example, if I have just written foo, it gets called with fo.

Regarding onShouldCollapse, it never gets called onInput, but instead, it appears to be called onChange, so it only applies when the input looses focus (for example).

Steps to Reproduce

Using the code snippet above, you should be able to see the console.logs as described in previous point.

Example and screenshots

You can see it here in action on this recording (ignore the UI, I'm migrating from v6 and haven't tackled that yet).

Grabacion.de.pantalla.desde.2023-08-12.13-40-19.webm

Custom tags example only allows one tag

Hi!

This might be a bug because I can't add more than one tag in the "custom tags" example.

/**
* Demo 2 - custom tags
*/
function isValid(value) {
return /^[a-z]{4,12}$/i.test(value)
}
function CustomTags() {
const [selected, setSelected] = useState([])
const onAdd = useCallback(
(newTag) => {
setSelected([...selected, newTag])
},
[selected]
)
const onDelete = useCallback(
(tagIndex) => {
setSelected(selected.filter((_, i) => i !== tagIndex))
},
[selected]
)
const onValidate = useCallback((value) => isValid(value), [])
return (
<>
<p>Enter new tags meeting the requirements below:</p>
<ReactTags
allowNew
ariaDescribedBy="description-2"
closeOnSelect
id="demo-2"
labelText="Enter new tags"
onAdd={onAdd}
onDelete={onDelete}
onValidate={onValidate}
selected={selected}
suggestions={[]}
/>
<p id="description-2" style={{ color: 'gray' }}>
<em>Tags must be between 4 and 12 characters in length and only contain the letters A-Z</em>
</p>
</>
)
}
const container2 = ReactDOM.createRoot(document.getElementById('demo-2'))
container2.render(<CustomTags />)

When I add a second tag the first one gets removed.

I would like to use this component in a project with React 18, that's why I tried the beta version instead of the stable one.

Unable to remove the all suggestion tags.

Hey, Is there any option to clear all the suggestions from the input of react tag and clear input field?

Case: I have a delete all button, I want to delete all suggestions on click that button.
Case: How to clear the input field on click custom clear button.

What are the goals?

Hi, is this version supposed to achieve feature parity with the old extension? At the moment, it looks like it is much less customizable, while the old extension was almost perfect.

For example, for selfoss, I used the following with the old extension in the introducing PR:

<ReactTags
    ref={reactTags}
    tags={source.tags}
    inputAttributes={{
        id: `tags-${sourceId}`, // For associating it with a label
        accessKey: 'g', // For quick jump
        onPaste, // I want to add a reasonable event handler but did not get to it yet.
    }}
    suggestions={tagSuggestions} // I abuse prefix field to add colour to each suggested tag
    onDelete={tagsOnDelete}
    onAddition={tagsOnAddition}
    allowNew={true}
    addOnBlur={true}
    minQueryLength={1} // Looks like the beta uses 0 now, which works for me.
    placeholderText={_('source_tags_placeholder')}
    removeButtonText={_('source_tag_remove_button_label')}
    newTagText={_('source_tags_create_new').replace('{0}', '%value%')} // This will be great.
    classNames={reactTagsClassNames}
    delimiters={['Enter', 'Tab', ',']} // Comma is much more convenient when typing on keyboard
    tagComponent={tagComponent} // Also used to add colour to tags
/>

TypeError: _a.scrollIntoView is not a function

I'm trying to use react testing library to test an interface that uses the combo box.

await userEvent.type(tagsField, "bananas{arrowdown}{enter}");

I get an error

    console.error
      Error: Uncaught [TypeError: _a.scrollIntoView is not a function]

If I add skipClick: true like I see in your tests, the input doesn't go into the tagsField because another field is selected.
Trying to click the field first

await userEvent.click(tagsField);

I get the same error

The code works fine in the browser, it's just failing in the unit test. Any ideas?

Unable to add custom tag ui

Can you please let me know, how can i add own custom ui component as prop in V7 beta.
As currently the behaviour is , on click tag anywhere it is deleted. As I want to delete tag, only click via delete icon.

Ignore tags added twice, instead of removing them

Describe the solution you'd like

I'm not reporting this as a bug, even though for me it's a bit counter-intuitive behavior, because I see it being used consciously in the countries example.

Currently, when the same tag is added twice, it results in the tag getting actually removed. I guess this is because of the Api.select() method nature, which actually toggles tags.

duplicated-tags.webm

When using this library's v6, tags where actually passed twice to the onAddition callback, and it was easy to ignore duplicates by using a Set.

Now, if you actually want to ignore duplicates, instead of getting them removed, there's no easy workaround unless several event handlers are overwritten.

Because of this, it would be great to support an option disabling the removal on duplicated tags.

Describe alternatives you've considered

I have tried working around this via custom event handlers + API ref, but nothing seems to allow covering all ways to add tags (different keys, clicking on suggestions, selecting suggestions via keyboard, etc).

Allow generic type for suggestions that extends Tag

Currently Tag is expected to have the keys value and label. I'd love to have Typescript recognize additional metadata that I supply with it, e.g. having the suggestions prop be typed as <T extends Tag>?

Thank you!

Render the listbox with a portal

Describe the solution you'd like

Material UI renders its dropdown's listbox somewhere else in the page using a portal. This makes it possible to use the dropdown inside dialogs with it being able to overflow the dialog.

Example:
image

Currently in react-tag-autocomplete, this isn't possible, so if you use the component inside a dialog, it doesn't overflow properly.

In our application, the dropdown doesn't go over the dialog's footer, because the dialog's body has overflow: auto.

image

Using a portal to render the dropdown near the root element should allow this behavior.

Unable to import react-tag-autocomplete in a Remix project

I cannot import react-tag-autocomplete in a barebones Remix project created from the create-remix template.

Here is my example project: https://github.com/lpsinger/remix-react-tag-autocomplete

When I run npm run build in the example project, I get:

The path "react-tag-autocomplete" is imported in app/lib/CountrySelector.tsx but "react-tag-autocomplete" was not found in your node_modules. Did you forget to install it?

When I run npm run dev, the ReactTags example does not load, and I get this error message displayed in the browser:

Error

Process exited with 1

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module 'react-tag-autocomplete'
Require stack:
- /Users/lpsinger/src/my-remix-app/server/index.js
- /Users/lpsinger/src/my-remix-app/server/[eval]
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object. (/Users/lpsinger/src/my-remix-app/app/lib/CountrySelector.tsx:3:27)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)

Roadmap to v7.0.0

Improvements and new features

  • Refactor to use a single shared state (enables richer interactions)
  • Refactor codebase from JS to TS (just for me but also avoids depending on external definitions)
  • Refactor to pass originally suggested tag to onAdd callback
  • Refactor resizable input to never render narrower than the placeholder text
  • Add label sub-component (improves accessibility)
  • Add assistive text notifications for additions and deletions (improves accessibility)
  • Add support for disabled state (new feature)
  • Add support for invalid state and error messages (new feature, improves accessibility)
  • Add support for all expected combobox keyboard behaviours (improves usability and accessibility)
  • Add support for displaying the selected state for options in listbox (improves usability and accessibility)
  • Add support for fully customisable/translatable text
  • Add support for custimisable class names on every component
  • Add new public API for input and listbox control
  • Improve support for overriding built in components/passing custom render props

Other breaking changes

  • Upgrade to React v18 (chore)
  • Rename onAddition prop to onAdd (consistency)
  • Rename tags prop to selected (consistency and clarity)
  • Rename removeButtonText to deleteButtonText (consistency)
  • Rename autoresize prop to allowResize (consistency)
  • Remove suggestionsFilter prop (not needed, use suggestionsTransform)
  • Remove maxSuggestionsLength prop (not needed, use suggestionsTransform)

Please see the changelog and migration guide for more details.

v7 beta – adding tags by click or keyboard arrow up/down

@i-like-robots
In current v7 beta I'm not able to select the option in the listbox by clicking on it or by using up/down key on keyboard and hit enter to add it to the list. It always sets the first item in the suggestions. Even API listobox.activeOption shows same first option selected when clicking on it.
Also, "selected" prop with selected state array removes previously added tags when I try to add another one

Any solutions?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.