137 | );
138 | };
139 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | .. role:: raw-html-m2r(raw)
2 | :format: html
3 |
4 |
5 | Streamlit-tags
6 | ==============
7 |
8 | |pypi Version| |conda Version| |PyPi downloads| |Conda downloads|
9 |
10 | A custom component to add Tags in Streamlit.
11 |
12 | .. image:: https://user-images.githubusercontent.com/49101362/114277814-83cb1200-9a35-11eb-8761-9d8bb81ffadc.gif
13 | :alt: ezgif com-gif-maker (1)
14 |
15 |
16 | Please star⭐ the repo and share the usage if you liked it.
17 |
18 | Try out a demo here: |Streamlit App|
19 |
20 | Check out docs here: https://streamlit-tags.readthedocs.io/en/latest/
21 |
22 | Install
23 | -------
24 |
25 | PyPi
26 |
27 | .. code-block::
28 |
29 |
30 | ::
31 |
32 | pip install streamlit-tags
33 |
34 | The installation can also be found on `PyPi`_
35 |
36 | Anaconda
37 | ~~~~
38 |
39 |
40 |
41 | conda install -c gagan3012 streamlit-tags
42 |
43 | The installation can also be found on `Anaconda`_
44 |
45 | Usage
46 | -----
47 |
48 | This library has two main functions to display and use tags:
49 |
50 |
51 | * ``st_tags`` to display the tags feature
52 | * ``st_tags_sidebar`` to display the tags in the sidebar
53 |
54 | Check the ``examples/``\ _ folder of the project a quick start.
55 |
56 | Check out demo here:
57 | https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py
58 |
59 | Definition
60 | ----------
61 |
62 | .. code:: python
63 |
64 | def st_tags(label: str,
65 | text: str,
66 | value: list,
67 | suggestions: list,
68 | key=None) -> list:
69 | '''
70 |
71 | :param suggestions: (List) List of possible suggestions (optional)
72 | :param label: (Str) Label of the Function
73 | :param text: (Str) Instructions for entry
74 | :param value: (List) Initial Value (optional)
75 | :param key: (Str)
76 | An optional string to use as the unique key for the widget.
77 | Assign a key so the component is not remount every time the script is rerun.
78 | :return: (List) Tags
79 |
80 | Note: usage also supports keywords = st_tags()
81 |
82 | '''
83 |
84 |
85 | Note:
86 | ^^^^^
87 |
88 |
89 | * The suggestion and value fields are optional
90 | * Usage also supports ``keywords = st_tags()``
91 |
92 | We also have a function now to embed the tags function to the sidebar:
93 | :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`
94 |
95 | .. _PyPi: https://pypi.org/project/streamlit-tags/
96 |
97 | .. _Anaconda: https://anaconda.org/gagan3012/streamlit-tags
98 |
99 | .. _``examples/``: https://github.com/gagan3012/streamlit-tags/tree/master/examples
100 |
101 |
102 | .. |pypi Version| image:: https://img.shields.io/pypi/v/streamlit-tags.svg?style=flat-square&logo=pypi&logoColor=white
103 | :target: https://pypi.org/project/streamlit-tags/
104 |
105 | .. |conda Version| image:: https://img.shields.io/conda/vn/gagan3012/streamlit-tags.svg?style=flat-square&logo=conda-forge&logoColor=white
106 | :target: https://anaconda.org/gagan3012/streamlit-tags
107 |
108 | .. |PyPi downloads| image:: https://static.pepy.tech/personalized-badge/streamlit-tags?period=total&units=international_system&left_color=grey&right_color=orange&left_text=pip%20downloads
109 | :target: https://pypi.org/project/streamlit-tags/
110 |
111 | .. |Conda downloads| image:: https://img.shields.io/conda/dn/gagan3012/streamlit-tags?label=conda%20downloads
112 | :target: https://anaconda.orggagan3012/streamlit-tags
113 |
114 | .. |Streamlit App| image:: https://static.streamlit.io/badges/streamlit_badge_black_white.svg
115 |
116 | :target: https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py
117 |
--------------------------------------------------------------------------------
/index.rst:
--------------------------------------------------------------------------------
1 | .. role:: raw-html-m2r(raw)
2 | :format: html
3 |
4 |
5 | Streamlit-tags
6 | ==============
7 |
8 | |pypi Version| |conda Version| |PyPi downloads| |Conda downloads|
9 |
10 | A custom component to add Tags in Streamlit.
11 |
12 | .. image:: https://user-images.githubusercontent.com/49101362/114277814-83cb1200-9a35-11eb-8761-9d8bb81ffadc.gif
13 | :alt: ezgif com-gif-maker (1)
14 |
15 |
16 | Please star⭐ the repo and share the usage if you liked it.
17 |
18 | Try out a demo here: |Streamlit App|
19 |
20 | Check out docs here: https://streamlit-tags.readthedocs.io/en/latest/
21 |
22 | Install
23 | -------
24 |
25 | PyPi
26 |
27 | .. code-block::
28 |
29 |
30 | ::
31 |
32 | pip install streamlit-tags
33 |
34 | The installation can also be found on `PyPi`_
35 |
36 | Anaconda
37 | ~~~~
38 |
39 |
40 |
41 | conda install -c gagan3012 streamlit-tags
42 |
43 | The installation can also be found on `Anaconda`_
44 |
45 | Usage
46 | -----
47 |
48 | This library has two main functions to display and use tags:
49 |
50 |
51 | * ``st_tags`` to display the tags feature
52 | * ``st_tags_sidebar`` to display the tags in the sidebar
53 |
54 | Check the ``examples/``\ _ folder of the project a quick start.
55 |
56 | Check out demo here:
57 | https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py
58 |
59 | Definition
60 | ----------
61 |
62 | .. code:: python
63 |
64 | def st_tags(label: str,
65 | text: str,
66 | value: list,
67 | suggestions: list,
68 | key=None) -> list:
69 | '''
70 |
71 | :param suggestions: (List) List of possible suggestions (optional)
72 | :param label: (Str) Label of the Function
73 | :param text: (Str) Instructions for entry
74 | :param value: (List) Initial Value (optional)
75 | :param key: (Str)
76 | An optional string to use as the unique key for the widget.
77 | Assign a key so the component is not remount every time the script is rerun.
78 | :return: (List) Tags
79 |
80 | Note: usage also supports keywords = st_tags()
81 |
82 | '''
83 |
84 |
85 | Note:
86 | ^^^^^
87 |
88 |
89 | * The suggestion and value fields are optional
90 | * Usage also supports ``keywords = st_tags()``
91 |
92 | We also have a function now to embed the tags function to the sidebar:
93 | :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`\ :raw-html-m2r:`~`
94 |
95 | .. _PyPi: https://pypi.org/project/streamlit-tags/
96 |
97 | .. _Anaconda: https://anaconda.org/gagan3012/streamlit-tags
98 |
99 | .. _``examples/``: https://github.com/gagan3012/streamlit-tags/tree/master/examples
100 |
101 |
102 | .. |pypi Version| image:: https://img.shields.io/pypi/v/streamlit-tags.svg?style=flat-square&logo=pypi&logoColor=white
103 | :target: https://pypi.org/project/streamlit-tags/
104 |
105 | .. |conda Version| image:: https://img.shields.io/conda/vn/gagan3012/streamlit-tags.svg?style=flat-square&logo=conda-forge&logoColor=white
106 | :target: https://anaconda.org/gagan3012/streamlit-tags
107 |
108 | .. |PyPi downloads| image:: https://static.pepy.tech/personalized-badge/streamlit-tags?period=total&units=international_system&left_color=grey&right_color=orange&left_text=pip%20downloads
109 | :target: https://pypi.org/project/streamlit-tags/
110 |
111 | .. |Conda downloads| image:: https://img.shields.io/conda/dn/gagan3012/streamlit-tags?label=conda%20downloads
112 | :target: https://anaconda.orggagan3012/streamlit-tags
113 |
114 | .. |Streamlit App| image:: https://static.streamlit.io/badges/streamlit_badge_black_white.svg
115 |
116 | :target: https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py
117 |
--------------------------------------------------------------------------------
/.github/CONTRIBUTIONS.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a code of conduct, please follow it in all your interactions with the project.
7 |
8 | ## Pull Request Process
9 |
10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
11 | build.
12 | 2. Update the README.md with details of changes to the interface, this includes new environment
13 | variables, exposed ports, useful file locations and container parameters.
14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
15 | Pull Request would represent.
16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
17 | do not have permission to do that, you may request the second reviewer to merge it for you.
18 |
19 | ## Code of Conduct
20 |
21 | ### Our Pledge
22 |
23 | In the interest of fostering an open and welcoming environment, we as
24 | contributors and maintainers pledge to making participation in our project and
25 | our community a harassment-free experience for everyone, regardless of age, body
26 | size, disability, ethnicity, gender identity and expression, level of experience,
27 | nationality, personal appearance, race, religion, or sexual identity and
28 | orientation.
29 |
30 | ### Our Standards
31 |
32 | Examples of behavior that contributes to creating a positive environment
33 | include:
34 |
35 | * Using welcoming and inclusive language
36 | * Being respectful of differing viewpoints and experiences
37 | * Gracefully accepting constructive criticism
38 | * Focusing on what is best for the community
39 | * Showing empathy towards other community members
40 |
41 | Examples of unacceptable behavior by participants include:
42 |
43 | * The use of sexualized language or imagery and unwelcome sexual attention or
44 | advances
45 | * Trolling, insulting/derogatory comments, and personal or political attacks
46 | * Public or private harassment
47 | * Publishing others' private information, such as a physical or electronic
48 | address, without explicit permission
49 | * Other conduct which could reasonably be considered inappropriate in a
50 | professional setting
51 |
52 | ### Our Responsibilities
53 |
54 | Project maintainers are responsible for clarifying the standards of acceptable
55 | behavior and are expected to take appropriate and fair corrective action in
56 | response to any instances of unacceptable behavior.
57 |
58 | Project maintainers have the right and responsibility to remove, edit, or
59 | reject comments, commits, code, wiki edits, issues, and other contributions
60 | that are not aligned to this Code of Conduct, or to ban temporarily or
61 | permanently any contributor for other behaviors that they deem inappropriate,
62 | threatening, offensive, or harmful.
63 |
64 | ### Scope
65 |
66 | This Code of Conduct applies both within project spaces and in public spaces
67 | when an individual is representing the project or its community. Examples of
68 | representing a project or community include using an official project e-mail
69 | address, posting via an official social media account, or acting as an appointed
70 | representative at an online or offline event. Representation of a project may be
71 | further defined and clarified by project maintainers.
72 |
73 | ### Enforcement
74 |
75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
77 | complaints will be reviewed and investigated and will result in a response that
78 | is deemed necessary and appropriate to the circumstances. The project team is
79 | obligated to maintain confidentiality with regard to the reporter of an incident.
80 | Further details of specific enforcement policies may be posted separately.
81 |
82 | Project maintainers who do not follow or enforce the Code of Conduct in good
83 | faith may face temporary or permanent repercussions as determined by other
84 | members of the project's leadership.
85 |
86 | ### Attribution
87 |
88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
89 | available at [http://contributor-covenant.org/version/1/4][version]
90 |
91 | [homepage]: http://contributor-covenant.org
92 | [version]: http://contributor-covenant.org/version/1/4/
93 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | When contributing to this repository, please first discuss the change you wish to make via issue,
4 | email, or any other method with the owners of this repository before making a change.
5 |
6 | Please note we have a code of conduct, please follow it in all your interactions with the project.
7 |
8 | ## Pull Request Process
9 |
10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a
11 | build.
12 | 2. Update the README.md with details of changes to the interface, this includes new environment
13 | variables, exposed ports, useful file locations and container parameters.
14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this
15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/).
16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you
17 | do not have permission to do that, you may request the second reviewer to merge it for you.
18 |
19 | ## Code of Conduct
20 |
21 | ### Our Pledge
22 |
23 | In the interest of fostering an open and welcoming environment, we as
24 | contributors and maintainers pledge to making participation in our project and
25 | our community a harassment-free experience for everyone, regardless of age, body
26 | size, disability, ethnicity, gender identity and expression, level of experience,
27 | nationality, personal appearance, race, religion, or sexual identity and
28 | orientation.
29 |
30 | ### Our Standards
31 |
32 | Examples of behavior that contributes to creating a positive environment
33 | include:
34 |
35 | * Using welcoming and inclusive language
36 | * Being respectful of differing viewpoints and experiences
37 | * Gracefully accepting constructive criticism
38 | * Focusing on what is best for the community
39 | * Showing empathy towards other community members
40 |
41 | Examples of unacceptable behavior by participants include:
42 |
43 | * The use of sexualized language or imagery and unwelcome sexual attention or
44 | advances
45 | * Trolling, insulting/derogatory comments, and personal or political attacks
46 | * Public or private harassment
47 | * Publishing others' private information, such as a physical or electronic
48 | address, without explicit permission
49 | * Other conduct which could reasonably be considered inappropriate in a
50 | professional setting
51 |
52 | ### Our Responsibilities
53 |
54 | Project maintainers are responsible for clarifying the standards of acceptable
55 | behavior and are expected to take appropriate and fair corrective action in
56 | response to any instances of unacceptable behavior.
57 |
58 | Project maintainers have the right and responsibility to remove, edit, or
59 | reject comments, commits, code, wiki edits, issues, and other contributions
60 | that are not aligned to this Code of Conduct, or to ban temporarily or
61 | permanently any contributor for other behaviors that they deem inappropriate,
62 | threatening, offensive, or harmful.
63 |
64 | ### Scope
65 |
66 | This Code of Conduct applies both within project spaces and in public spaces
67 | when an individual is representing the project or its community. Examples of
68 | representing a project or community include using an official project e-mail
69 | address, posting via an official social media account, or acting as an appointed
70 | representative at an online or offline event. Representation of a project may be
71 | further defined and clarified by project maintainers.
72 |
73 | ### Enforcement
74 |
75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All
77 | complaints will be reviewed and investigated and will result in a response that
78 | is deemed necessary and appropriate to the circumstances. The project team is
79 | obligated to maintain confidentiality with regard to the reporter of an incident.
80 | Further details of specific enforcement policies may be posted separately.
81 |
82 | Project maintainers who do not follow or enforce the Code of Conduct in good
83 | faith may face temporary or permanent repercussions as determined by other
84 | members of the project's leadership.
85 |
86 | ### Attribution
87 |
88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
89 | available at [http://contributor-covenant.org/version/1/4][version]
90 |
91 | [homepage]: http://contributor-covenant.org
92 | [version]: http://contributor-covenant.org/version/1/4/
93 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | @gagan3012.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Streamlit-tags
2 | [](https://pypi.org/project/streamlit-tags/)
3 | [](https://anaconda.org/conda-forge/streamlit_tags)
4 | [](https://pepy.tech/project/streamlit-tags)
5 | [](https://anaconda.org/gagan3012/streamlit-tags)
6 | [](https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py)
7 | [](https://streamlit-tags.readthedocs.io/en/latest/)
8 |
9 |
10 | 
11 |
12 | A custom component to add Tags in Streamlit.
13 |
14 | [](https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py)
15 |
16 | # Please Upgrade to 1.2.7 version
17 |
18 | ### 📢 Favour:
19 | It would be highly motivating, if you can STAR⭐ this repo if you find it helpful.
20 |
21 |
22 | Try out a demo here: [](https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py)
23 |
24 | Check out docs here: https://streamlit-tags.readthedocs.io/en/latest/
25 | ## Install
26 | ### PyPi
27 | ```
28 | pip install streamlit-tags
29 | ```
30 | The installation can also be found on [**PyPi**](https://pypi.org/project/streamlit-tags/)
31 | ### Anaconda
32 | ```
33 | conda install -c conda-forge streamlit_tags
34 | ```
35 | The installation can also be found on [**Anaconda**](https://anaconda.org/conda-forge/streamlit_tags)
36 | ## Usage
37 | This library has two main functions to display and use tags:
38 | - `st_tags` to display the tags feature
39 | - `st_tags_sidebar` to display the tags in the sidebar
40 | Check the [`examples/`](https://github.com/gagan3012/streamlit-tags/tree/master/examples) folder of the project a quick start.
41 | Check out demo here: https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py
42 | ## Definition
43 | ```python
44 | def st_tags(value: list,
45 | suggestions: list,
46 | label: str,
47 | text: str,
48 | maxtags: int,
49 | key=None) -> list:
50 | '''
51 | :param maxtags: Maximum number of tags allowed maxtags = -1 for unlimited entries
52 | :param suggestions: (List) List of possible suggestions (optional)
53 | :param label: (Str) Label of the Function
54 | :param text: (Str) Instructions for entry
55 | :param value: (List) Initial Value (optional)
56 | :param key: (Str)
57 | An optional string to use as the unique key for the widget.
58 | Assign a key so the component is not remount every time the script is rerun.
59 | :return: (List) Tags
60 |
61 | Note: usage also supports keywords = st_tags()
62 | '''
63 | ```
64 | Note: the suggestion and value fields are optional
65 | #### Note:
66 | - The suggestion and value fields are optional
67 | - Usage also supports `keywords = st_tags()`
68 | - Upgrade to 1.1.9 for being able to control number of tags
69 |
70 | ### We also have a function now to embed the tags function to the sidebar:
71 |
72 | ```python
73 | def st_tags_sidebar(value: list,
74 | suggestions: list,
75 | label: str,
76 | text: str,
77 | maxtags: int,
78 | key=None) -> list:
79 | '''
80 | :param maxtags: Maximum number of tags allowed maxtags = -1 for unlimited entries
81 | :param suggestions: (List) List of possible suggestions (optional)
82 | :param label: (Str) Label of the Function
83 | :param text: (Str) Instructions for entry
84 | :param value: (List) Initial Value (optional)
85 | :param key: (Str)
86 | An optional string to use as the unique key for the widget.
87 | Assign a key so the component is not remount every time the script is rerun.
88 | :return: Tags
89 | '''
90 | ```
91 | #### Note:
92 | - The suggestion and value fields are optional
93 | - Usage also supports `keywords = st_tags_sidebar()`
94 | - Upgrade to 1.1.9 for being able to control number of tags
95 |
96 | ## Example Usage
97 | ```python
98 | keywords = st_tags(
99 | label='# Enter Keywords:',
100 | text='Press enter to add more',
101 | value=['Zero', 'One', 'Two'],
102 | suggestions=['five', 'six', 'seven',
103 | 'eight', 'nine', 'three',
104 | 'eleven', 'ten', 'four'],
105 | maxtags = 4,
106 | key='1')
107 |
108 | keyword = st_tags_sidebar(
109 | label='# Enter Keywords:',
110 | text='Press enter to add more',
111 | value=['Zero', 'One', 'Two'],
112 | suggestions=['five', 'six', 'seven',
113 | 'eight', 'nine', 'three',
114 | 'eleven', 'ten', 'four'],
115 | maxtags = 4,
116 | key='2')
117 | ```
118 | ## Sample Images of the UI:
119 | [](https://share.streamlit.io/gagan3012/streamlit-tags/examples/app.py)
120 |
121 |
--------------------------------------------------------------------------------
/streamlit_tags/__init__.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import streamlit.components.v1 as components
4 | import streamlit as st
5 | import pyarrow
6 |
7 | # Create a _RELEASE constant. We'll set this to False while we're developing
8 | # the component, and True when we're ready to package and distribute it.
9 | # (This is, of course, optional - there are innumerable ways to manage your
10 | # release process.)
11 | _RELEASE = True
12 |
13 | # Declare a Streamlit component. `declare_component` returns a function
14 | # that is used to create instances of the component. We're naming this
15 | # function "_component_func", with an underscore prefix, because we don't want
16 | # to expose it directly to users. Instead, we will create a custom wrapper
17 | # function, below, that will serve as our component's public API.
18 |
19 | # It's worth noting that this call to `declare_component` is the
20 | # *only thing* you need to do to create the binding between Streamlit and
21 | # your component frontend. Everything else we do in this file is simply a
22 | # best practice.
23 |
24 | if not _RELEASE:
25 | _component_func = components.declare_component(
26 | # We give the component a simple, descriptive name ("my_component"
27 | # does not fit this bill, so please choose something better for your
28 | # own component :)
29 | "streamlit_tags",
30 | # Pass `url` here to tell Streamlit that the component will be served
31 | # by the local dev server that you run via `npm run start`.
32 | # (This is useful while your component is in development.)
33 | url="http://localhost:3001",
34 | )
35 | else:
36 | # When we're distributing a production version of the component, we'll
37 | # replace the `url` param with `path`, and point it to to the component's
38 | # build directory:
39 | parent_dir = os.path.dirname(os.path.abspath(__file__))
40 | build_dir = os.path.join(parent_dir, "frontend/build")
41 | _component_func = components.declare_component("streamlit_tags", path=build_dir)
42 |
43 |
44 | # Create a wrapper function for the component. This is an optional
45 | # best practice - we could simply expose the component function returned by
46 | # `declare_component` and call it done. The wrapper allows us to customize
47 | # our component's API: we can pre-process its input args, post-process its
48 | # output value, and add a docstring for users.
49 | def st_tags(value: list = [],
50 | suggestions: list = [],
51 | label: str = "# Enter Keywords",
52 | text: str = "Press enter to add more",
53 | maxtags: int = -1,
54 | key=None) -> list:
55 | '''
56 |
57 | :param maxtags: Maximum number of tags allowed maxtags = -1 for unlimited entries
58 | :param suggestions: (List) List of possible suggestions
59 | :param label: (Str) Label of the Function
60 | :param text: (Str) Instructions for entry
61 | :param value: (List) Initial Value
62 | :param key: (Str)
63 | An optional string to use as the unique key for the widget.
64 | Assign a key so the component is not remount every time the script is rerun.
65 | :return: Tags
66 | '''
67 | import streamlit as st
68 |
69 | st.write(label)
70 | component_value = _component_func(label=label,
71 | text=text,
72 | initialValue=value,
73 | suggestions=suggestions,
74 | maxTags=maxtags,
75 | key=key,
76 | default=value)
77 | return component_value
78 |
79 |
80 | def st_tags_sidebar(value: list = [],
81 | suggestions: list = [],
82 | label: str = "# Enter Keywords",
83 | text: str = "Press enter to add more",
84 | maxtags: int = -1,
85 | key=None) -> list:
86 | '''
87 |
88 | :param maxtags: Maximum number of tags allowed maxtags = -1 for unlimited entries
89 | :param suggestions: (List) List of possible suggestions
90 | :param label: (Str) Label of the Function
91 | :param text: (Str) Instructions for entry
92 | :param value: (List) Initial Value
93 | :param key: (Str)
94 | An optional string to use as the unique key for the widget.
95 | Assign a key so the component is not remount every time the script is rerun.
96 | :return: Tags
97 | '''
98 | import streamlit as st
99 |
100 | with st.sidebar:
101 | st.sidebar.write(label)
102 | component_value = _component_func(label=label,
103 | text=text,
104 | initialValue=value,
105 | suggestions=suggestions,
106 | maxTags=maxtags,
107 | key=key,
108 | default=value)
109 | return component_value
110 |
111 |
112 | # Add some test code to play with the component while it's in development.
113 | # During development, we can run this just as we would any other Streamlit
114 | # app: `$ streamlit run my_component/__init__.py`
115 | if not _RELEASE:
116 | import streamlit as st
117 |
118 | # Create a second instance of our component whose `name` arg will vary
119 | # based on a text_input widget.
120 | #
121 | # We use the special "key" argument to assign a fixed identity to this
122 | # component instance. By default, when a component's arguments change,
123 | # it is considered a new instance and will be re-mounted on the frontend
124 | # and lose its current state. In this case, we want to vary the component's
125 | # "name" argument without having it get recreated.
126 |
127 | keyword = st_tags(label='# Enter Keywords:',
128 | text='Press enter to add more',
129 | value=['Zero', 'One', 'Two'],
130 | suggestions=['five', 'six', 'seven', 'eight', 'nine', 'three', 'eleven', 'ten', 'four'],
131 | maxtags=4,
132 | key='2')
133 |
134 | st.sidebar.write("### Results:")
135 | st.sidebar.write(keyword)
136 |
--------------------------------------------------------------------------------
/streamlit_tags/frontend/src/react-autocomplete-hint/index.tsx:
--------------------------------------------------------------------------------
1 | import React, {
2 | useState,
3 | cloneElement,
4 | useEffect,
5 | useRef,
6 | ReactElement
7 | } from 'react';
8 | import { IHintOption } from './IHintOption';
9 | import {
10 | mergeRefs,
11 | interpolateStyle,
12 | sortAsc,
13 | getFirstDuplicateOption
14 | } from './utils';
15 |
16 | export interface IHintProps {
17 | options: Array | Array;
18 | disableHint?: boolean;
19 | children: ReactElement;
20 | allowTabFill?: boolean;
21 | onFill?(value: string | IHintOption): void;
22 | onHint?(value: string | IHintOption | undefined): void;
23 | valueModifier?(value: string): string;
24 | }
25 |
26 | export const Hint: React.FC = props => {
27 | const child = React.Children.only(props.children);
28 |
29 | if (child.type?.toString()?.toLowerCase() !== 'input') {
30 | throw new TypeError(`react-autocomplete-hint: 'Hint' only accepts an 'input' element as child.`);
31 | }
32 |
33 | const {
34 | options,
35 | disableHint,
36 | allowTabFill,
37 | onFill,
38 | onHint,
39 | valueModifier
40 | } = props;
41 |
42 | const childProps = child.props;
43 |
44 | let inputWrapperRef = useRef(null);
45 | let mainInputRef = useRef(null);
46 | let hintWrapperRef = useRef(null);
47 | let hintRef = useRef(null);
48 | const [unModifiedText, setUnmodifiedText] = useState('');
49 | const [text, setText] = useState('');
50 | const [hint, setHint] = useState('');
51 | const [match, setMatch] = useState();
52 | const [changeEvent, setChangeEvent] = useState>();
53 |
54 | useEffect(() => {
55 | if (typeof options[0] === 'object') {
56 | const duplicate = getFirstDuplicateOption(options as Array);
57 | if (duplicate) {
58 | console.warn(`react-autocomplete-hint: "${duplicate}" occurs more than once and may cause errors. Options should not contain duplicate values!`);
59 | }
60 | }
61 | }, []);
62 |
63 | useEffect(() => {
64 | if (disableHint) {
65 | return;
66 | }
67 |
68 | const inputStyle = mainInputRef.current && window.getComputedStyle(mainInputRef.current);
69 | inputStyle && styleHint(inputWrapperRef, hintWrapperRef, hintRef, inputStyle);
70 | });
71 |
72 | const getMatch = (text: string) => {
73 | if (!text || text === '') {
74 | return;
75 | }
76 |
77 | if (typeof (options[0]) === 'string') {
78 | const match = (options as Array)
79 | .filter(x => x.toLowerCase() !== text.toLowerCase() && x.toLowerCase().startsWith(text.toLowerCase()))
80 | .sort()[0];
81 |
82 | return match;
83 | } else {
84 | const match = (options as Array)
85 | .filter(x => x.label.toLowerCase() !== text.toLowerCase() && x.label.toLowerCase().startsWith(text.toLowerCase()))
86 | .sort((a, b) => sortAsc(a.label, b.label))[0];
87 |
88 | return match;
89 | }
90 | };
91 |
92 | const setHintTextAndId = (text: string) => {
93 | setText(text);
94 |
95 | const match = getMatch(text);
96 | let hint: string;
97 |
98 | if (!match) {
99 | hint = '';
100 | }
101 | else if (typeof match === 'string') {
102 | hint = match.slice(text.length);
103 | } else {
104 | hint = match.label.slice(text.length);
105 | }
106 |
107 | setHint(hint);
108 | setMatch(match);
109 | onHint && onHint(match)
110 | }
111 |
112 | const handleOnFill = () => {
113 | if (hint !== '' && changeEvent) {
114 | changeEvent.target.value = unModifiedText + hint;
115 | childProps.onChange && childProps.onChange(changeEvent);
116 | setHintTextAndId('');
117 |
118 | onFill && onFill(match!);
119 | }
120 | };
121 |
122 | const styleHint = (
123 | inputWrapperRef: React.RefObject,
124 | hintWrapperRef: React.RefObject,
125 | hintRef: React.RefObject,
126 | inputStyle: CSSStyleDeclaration) => {
127 | if (inputWrapperRef?.current?.style) {
128 | inputWrapperRef.current.style.width = inputStyle.width;
129 | }
130 |
131 | if (hintWrapperRef?.current?.style) {
132 | hintWrapperRef.current.style.fontFamily = inputStyle.fontFamily;
133 | hintWrapperRef.current.style.fontSize = inputStyle.fontSize;
134 | hintWrapperRef.current.style.width = inputStyle.width;
135 | hintWrapperRef.current.style.height = inputStyle.height;
136 | hintWrapperRef.current.style.lineHeight = inputStyle.lineHeight;
137 | hintWrapperRef.current.style.boxSizing = inputStyle.boxSizing;
138 | hintWrapperRef.current.style.margin = interpolateStyle(inputStyle, 'margin');
139 | hintWrapperRef.current.style.padding = interpolateStyle(inputStyle, 'padding');
140 | hintWrapperRef.current.style.borderStyle = interpolateStyle(inputStyle, 'border', 'style');
141 | hintWrapperRef.current.style.borderWidth = interpolateStyle(inputStyle, 'border', 'width');
142 | }
143 |
144 | if (hintRef?.current?.style) {
145 | hintRef.current.style.fontFamily = inputStyle.fontFamily;
146 | hintRef.current.style.fontSize = inputStyle.fontSize;
147 | hintRef.current.style.lineHeight = inputStyle.lineHeight;
148 | }
149 | };
150 |
151 | const onChange = (e: React.ChangeEvent) => {
152 | setChangeEvent(e);
153 | e.persist();
154 |
155 | setUnmodifiedText(e.target.value);
156 | const modifiedValue = valueModifier ? valueModifier(e.target.value) : e.target.value;
157 | setHintTextAndId(modifiedValue);
158 |
159 | childProps.onChange && childProps.onChange(e);
160 | };
161 |
162 | const onFocus = (e: React.FocusEvent) => {
163 | setHintTextAndId(e.target.value);
164 | childProps.onFocus && childProps.onFocus(e);
165 | };
166 |
167 | const onBlur = (e: React.FocusEvent) => {
168 | //Only blur it if the new focus isn't the the hint input
169 | if (hintRef?.current !== e.relatedTarget) {
170 | setHintTextAndId('');
171 | childProps.onBlur && childProps.onBlur(e);
172 | }
173 | };
174 |
175 | const ARROWRIGHT = 'ArrowRight';
176 | const TAB = 'Tab';
177 | const onKeyDown = (e: React.KeyboardEvent) => {
178 | const caretIsAtTextEnd = (() => {
179 | // For selectable input types ("text", "search"), only select the hint if
180 | // it's at the end of the input value. For non-selectable types ("email",
181 | // "number"), always select the hint.
182 |
183 | const isNonSelectableType = e.currentTarget.selectionEnd === null;
184 | const caretIsAtTextEnd = isNonSelectableType || e.currentTarget.selectionEnd === e.currentTarget.value.length;
185 |
186 | return caretIsAtTextEnd;
187 | })();
188 |
189 | if (caretIsAtTextEnd && e.key === ARROWRIGHT) {
190 | handleOnFill();
191 | } else if (caretIsAtTextEnd && allowTabFill && e.key === TAB && hint !== '') {
192 | e.preventDefault();
193 | handleOnFill();
194 | }
195 |
196 | childProps.onKeyDown && childProps.onKeyDown(e);
197 | };
198 |
199 | const onHintClick = (e: React.MouseEvent) => {
200 | const hintCaretPosition = e.currentTarget.selectionEnd || 0;
201 |
202 | // If user clicks the position before the first character of the hint,
203 | // move focus to the end of the mainInput text
204 | if (hintCaretPosition === 0) {
205 | mainInputRef.current?.focus();
206 | return;
207 | }
208 |
209 | if (!!hint && hint !== '') {
210 | handleOnFill();
211 | setTimeout(() => {
212 | mainInputRef.current?.focus();
213 | const caretPosition = text.length + hintCaretPosition;
214 | mainInputRef.current?.setSelectionRange(caretPosition, caretPosition);
215 | }, 0);
216 | }
217 | };
218 |
219 | const childRef = cloneElement(child as any).ref;
220 | const mainInput = cloneElement(
221 | child,
222 | {
223 | ...childProps,
224 | style: {
225 | ...childProps.style,
226 | boxSizing: 'border-box'
227 | },
228 | onChange,
229 | onBlur,
230 | onFocus,
231 | onKeyDown,
232 | ref: childRef && typeof (childRef) !== 'string'
233 | ? mergeRefs(childRef, mainInputRef)
234 | : mainInputRef
235 | }
236 | );
237 |
238 | return (
239 |