streamlit-sortable-multiselect 0.7.8__tar.gz → 0.7.10__tar.gz

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.
Files changed (19) hide show
  1. {streamlit_sortable_multiselect-0.7.8/streamlit_sortable_multiselect.egg-info → streamlit_sortable_multiselect-0.7.10}/PKG-INFO +244 -11
  2. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/README.md +243 -10
  3. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/pyproject.toml +1 -1
  4. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect/__init__.py +132 -3
  5. streamlit_sortable_multiselect-0.7.10/streamlit_sortable_multiselect/frontend/build/assets/index-B3tedBLe.css +1 -0
  6. streamlit_sortable_multiselect-0.7.10/streamlit_sortable_multiselect/frontend/build/assets/index-BwjO0Ed7.js +67 -0
  7. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect/frontend/build/index.html +2 -2
  8. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10/streamlit_sortable_multiselect.egg-info}/PKG-INFO +244 -11
  9. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect.egg-info/SOURCES.txt +3 -2
  10. streamlit_sortable_multiselect-0.7.10/tests/test_calendar.py +141 -0
  11. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/tests/test_wrapper.py +5 -1
  12. streamlit_sortable_multiselect-0.7.8/streamlit_sortable_multiselect/frontend/build/assets/index-9M_rp0G-.js +0 -67
  13. streamlit_sortable_multiselect-0.7.8/streamlit_sortable_multiselect/frontend/build/assets/index-B1hHAom_.css +0 -1
  14. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/LICENSE +0 -0
  15. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/MANIFEST.in +0 -0
  16. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/setup.cfg +0 -0
  17. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect.egg-info/dependency_links.txt +0 -0
  18. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect.egg-info/requires.txt +0 -0
  19. {streamlit_sortable_multiselect-0.7.8 → streamlit_sortable_multiselect-0.7.10}/streamlit_sortable_multiselect.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: streamlit-sortable-multiselect
3
- Version: 0.7.8
3
+ Version: 0.7.10
4
4
  Summary: A Streamlit custom component for selecting and reordering multiple string values.
5
5
  Author: Kentaro Aoki
6
6
  License-Expression: MIT
@@ -28,7 +28,9 @@ Dynamic: license-file
28
28
 
29
29
  # streamlit-sortable-multiselect
30
30
 
31
- A Streamlit custom component for searching, selecting, and reordering multiple string values.
31
+ A Streamlit custom component for searching, selecting, and reordering options,
32
+ dates, months, and date/month ranges. Selected items can be reordered by dragging
33
+ or using move buttons, and are returned as an ordered `list[str]`.
32
34
 
33
35
  ## Install
34
36
 
@@ -58,6 +60,10 @@ npm run dev
58
60
 
59
61
  ## Usage
60
62
 
63
+ The default `input_mode="options"` provides searchable options. For calendar
64
+ inputs, see [Calendar Input](#calendar-input), including date ranges, single
65
+ months, selection bounds, and Japanese labels and messages.
66
+
61
67
  ```python
62
68
  import streamlit as st
63
69
  from streamlit_sortable_multiselect import sortable_multiselect
@@ -90,15 +96,22 @@ st.write(selected)
90
96
 
91
97
  ## Settings
92
98
 
93
- `sortable_multiselect` returns the selected option values as a `list[str]` in the current display order.
99
+ `sortable_multiselect` returns selected values as a `list[str]` in the current
100
+ display order. Calendar values use the formats in [Returned Values](#returned-values).
94
101
 
95
102
  | Argument | Type | Default | Description |
96
103
  | --- | --- | --- | --- |
97
104
  | `label` | `str` | required | Label displayed above the component. |
98
- | `options` | `Sequence[str \| Mapping[str, Any]]` | required | Available options. Each option can be a plain string, or a dictionary with `label`, `value`, and optional `icon_url`. Option values must be unique. |
99
- | `default` | `Sequence[str] \| None` | `None` | Initially selected values, in the initial order. Changing the values or their order replaces the current selection. Values must exist in `options` and must not contain duplicates. |
100
- | `placeholder` | `str` | `"Select..."` | Placeholder shown in the search/add input when options are available. |
101
- | `disabled` | `bool` | `False` | Disables searching, selecting, removing, dragging, and move buttons. |
105
+ | `options` | `Sequence[str \| Mapping[str, Any]]` | `()` | Available options. Each option can be a plain string, or a dictionary with `label`, `value`, and optional `icon_url` and `color`. Option values must be unique. In calendar modes, optional entries supply labels, icons, and colors for matching calendar values. |
106
+ | `default` | `Sequence[str] \| None` | `None` | Initially selected values, in the initial order. Changing the values or their order replaces the current selection. In options mode, values must exist in `options`. Calendar defaults must match the mode and bounds. Duplicates are not allowed. |
107
+ | `default_revision` | `str \| int \| None` | `None` | Change this value to reapply `default` when its values and order are unchanged. |
108
+ | `input_mode` | `str` | `"options"` | `"options"`, `"date"`, `"month"`, or `"date_month"`. Mixed mode offers one switch between date ranges and single months. Date-only and month-only modes offer Single/Range controls. |
109
+ | `min_value` | `str \| datetime.date \| None` | `None` | Inclusive lower bound in calendar modes. Accepts `YYYY-MM-DD`, `YYYY-MM`, or a date object. |
110
+ | `max_value` | `str \| datetime.date \| None` | `None` | Inclusive upper bound in calendar modes. Accepts `YYYY-MM-DD`, `YYYY-MM`, or a date object. |
111
+ | `max_range_days` | `int \| None` | `None` | Maximum number of days in each date range, including start and end. Must be positive. `None` means unlimited. Does not limit single values or month ranges. Requires a calendar mode. |
112
+ | `calendar_labels` | `Mapping[str, str] \| None` | `None` | Overrides calendar switches, the Add button, field labels, accessibility group names, and validation messages. See [Calendar Input](#calendar-input) for all keys. Unspecified entries retain their English defaults. |
113
+ | `placeholder` | `str` | `"Select..."` | Placeholder shown in the search/add input when options are available. Used in options mode. |
114
+ | `disabled` | `bool` | `False` | Disables searching, calendar inputs and switches, adding, removing, dragging, and move buttons. |
102
115
  | `show_move_buttons` | `bool` | `True` | Shows up/down buttons on selected items. Drag sorting remains available unless `disabled=True`. |
103
116
  | `show_numbers` | `bool` | `False` | Shows 1-based position numbers before selected item labels. |
104
117
  | `base_color` | `str \| Mapping[str, str] \| None` | `None` | Fallback color for every selected item. See [Colors](#colors). |
@@ -109,13 +122,13 @@ st.write(selected)
109
122
  | `tooltip_color` | `str \| Mapping[str, str] \| None` | `None` | Color of the tooltip shown for labels that do not fit. `None` uses the built-in dark tooltip. See [Labels](#labels). |
110
123
  | `max_selections` | `int \| None` | `None` | Maximum number of selected items. `None` means no limit. Use `0` to prevent any selections. |
111
124
  | `single_select_display` | `bool` | `False` | With `max_selections=1`, displays the selected item inside the search control and replaces it when another option is selected. |
112
- | `max_selections_placeholder` | `str` | `"Selection limit reached"` | Placeholder shown when `max_selections` has been reached. This takes precedence over `placeholder` and `no_options_placeholder`, except in single-selection display mode. |
125
+ | `max_selections_placeholder` | `str` | `"Selection limit reached"` | Placeholder shown when `max_selections` has been reached in options mode; a status message in calendar modes. Takes precedence over other placeholders. Not shown in inline single-selection mode, which permits replacement. |
113
126
  | `empty_message` | `str` | `"No items selected"` | Message shown where the selected list appears when no items are selected. |
114
- | `no_options_placeholder` | `str` | `"No more options"` | Placeholder shown when every option is already selected and there are no more options to add. |
127
+ | `no_options_placeholder` | `str` | `"No more options"` | Placeholder shown when every option is already selected and there are no more options to add. Used in options mode. |
115
128
  | `selected_position` | `str` | `"bottom"` | Position of the selected item list relative to the search/add input. Use `"bottom"` or `"top"`. |
116
129
  | `icon_size` | `int` | `20` | Icon display size in pixels for `icon_url` images. Images are displayed inside a square area while preserving their aspect ratio. |
117
- | `options_max_height` | `int` | `190` | Maximum height in pixels for the available options dropdown. |
118
- | `suggestions_api_url` | `str \| None` | `None` | Absolute HTTP(S) endpoint used to fetch suggestions in the browser. `None` disables API suggestions. |
130
+ | `options_max_height` | `int` | `190` | Maximum height in pixels for the available options dropdown. Used in options mode. |
131
+ | `suggestions_api_url` | `str \| None` | `None` | Absolute HTTP(S) endpoint used to fetch suggestions in the browser. `None` disables API suggestions. Only supported in options mode. |
119
132
  | `suggestions_query_param` | `str` | `"q"` | Query parameter name used to send the current search text. |
120
133
  | `suggestions_response_path` | `str` | `""` | Dot-separated path to the suggestions array in the JSON response. Empty means the response root. |
121
134
  | `suggestions_label_path` | `str` | `"label"` | Dot-separated path to each suggestion's display label. |
@@ -129,6 +142,24 @@ st.write(selected)
129
142
  | `suggestions_error_message` | `str` | `"Failed to load suggestions"` | Message shown when the request or response cannot be processed. |
130
143
  | `key` | `str \| None` | `None` | Optional Streamlit component key. Use this when rendering multiple sortable multiselects. |
131
144
 
145
+ To reset a component to the same `default` after the user changes its selection,
146
+ increment or otherwise change `default_revision`:
147
+
148
+ ```python
149
+ if "reset_revision" not in st.session_state:
150
+ st.session_state.reset_revision = 0
151
+
152
+ if st.button("Reset languages"):
153
+ st.session_state.reset_revision += 1
154
+
155
+ selected = sortable_multiselect(
156
+ "Languages",
157
+ options=["Python", "TypeScript", "Rust"],
158
+ default=["Python"],
159
+ default_revision=st.session_state.reset_revision,
160
+ )
161
+ ```
162
+
132
163
  Option dictionaries use this shape:
133
164
 
134
165
  ```python
@@ -260,6 +291,182 @@ option replaces the current value instead of adding another one. Use the remove
260
291
  inside the selected item to clear it. `single_select_display=True` without
261
292
  `max_selections=1` raises `ValueError`.
262
293
 
294
+ In calendar modes, the selected item is displayed inside the calendar control.
295
+ Adding another calendar value replaces it. A date range counts as one selected item.
296
+
297
+ ## Calendar Input
298
+
299
+ ### Input Modes
300
+
301
+ `input_mode` selects the input method for the whole component:
302
+
303
+ | Mode | Picker controls | Items added |
304
+ | --- | --- | --- |
305
+ | `"options"` (default) | Searchable dropdown and optional API suggestions | Values from options or API results |
306
+ | `"date"` | Date input with a Single/Range switch | One date or one date range |
307
+ | `"month"` | Month input with a Single/Range switch | One month or one month range |
308
+ | `"date_month"` | One Date (range)/Month (single) switch | One date range or one month |
309
+
310
+ Use `input_mode="date_month"` to add date ranges and single months to one sortable
311
+ list. One switch selects Date (range) or Month (single). Date (range) shows Start
312
+ and End inputs; Month (single) shows one month input. Press Add to append the
313
+ selection. A range is one item, not an expanded sequence. Use `"date"` or `"month"`
314
+ for a fixed precision with a separate Single/Range switch.
315
+
316
+ ```python
317
+ import streamlit as st
318
+ from streamlit_sortable_multiselect import sortable_multiselect
319
+
320
+ selected = sortable_multiselect(
321
+ "Reporting periods",
322
+ input_mode="date_month",
323
+ min_value="2026-01-01",
324
+ max_value="2027-12-31",
325
+ max_range_days=31,
326
+ default=["2026-10-01/2026-10-24", "2026-11"],
327
+ show_numbers=True,
328
+ key="reporting_periods",
329
+ )
330
+ st.write("Selected order:", selected)
331
+ ```
332
+
333
+ Mixed mode initially shows the date-range inputs. Switching to Month (single)
334
+ clears unfinished inputs and keeps items already added to the sortable list.
335
+
336
+ ### Calendar Labels
337
+
338
+ Override `calendar_labels` to display Japanese or another language. The settings
339
+ apply to switch text, the Add button, field labels, accessibility group names,
340
+ and validation messages. They do not change returned values. Supported keys and
341
+ defaults are:
342
+
343
+ | Key | Default | Used in |
344
+ | --- | --- | --- |
345
+ | `date_range` | `"Date (range)"` | `date_month` |
346
+ | `month_single` | `"Month (single)"` | `date_month` |
347
+ | `single` | `"Single"` | `date`, `month` |
348
+ | `range` | `"Range"` | `date`, `month` |
349
+ | `add` | `"Add"` | Add button |
350
+ | `start` | `"Start"` | Range start field and its accessible name |
351
+ | `end` | `"End"` | Range end field and its accessible name |
352
+ | `date` | `"Date"` | Single-date field and its accessible name |
353
+ | `month` | `"Month"` | Single-month field and its accessible name |
354
+ | `calendar_input` | `"Calendar input"` | Accessible name of the mixed-mode switch group |
355
+ | `selection_kind` | `"Selection kind"` | Accessible name of the Single/Range switch group |
356
+ | `invalid_value` | `"Choose a valid value within the allowed range, with start on or before end."` | Invalid date, bounds, or reversed range |
357
+ | `duplicate_value` | `"This item is already selected."` | Exact duplicate selection |
358
+ | `incomplete_selection` | `"Complete the selection before adding it."` | Add or Enter with missing input |
359
+ | `range_too_long` | `"Choose a date range of at most {max_range_days} days (including both endpoints)."` | Date range longer than `max_range_days` |
360
+
361
+ Only specify the labels you want to override. Unknown keys, non-string values,
362
+ and empty or whitespace-only labels raise an error. In `range_too_long`, every
363
+ `{max_range_days}` placeholder is replaced with the configured limit; a message
364
+ without the placeholder is also allowed. Native calendar localization follows
365
+ the browser and operating system. Set `empty_message` for the empty selected
366
+ list and `max_selections_placeholder` for the selection-count limit message.
367
+
368
+ ### Japanese Example
369
+
370
+ ```python
371
+ import streamlit as st
372
+ from streamlit_sortable_multiselect import sortable_multiselect
373
+
374
+ selected = sortable_multiselect(
375
+ "Reporting periods",
376
+ input_mode="date_month",
377
+ min_value="2026-01-01",
378
+ max_value="2027-12-31",
379
+ max_range_days=31,
380
+ default=["2026-10-01/2026-10-24", "2026-11", "2027-01"],
381
+ show_numbers=True,
382
+ max_selections=8,
383
+ calendar_labels={
384
+ "date_range": "日付(範囲)",
385
+ "month_single": "年月(単一)",
386
+ "single": "単一",
387
+ "range": "範囲",
388
+ "add": "追加",
389
+ "start": "開始日",
390
+ "end": "終了日",
391
+ "date": "日付",
392
+ "month": "年月",
393
+ "calendar_input": "入力方法",
394
+ "selection_kind": "選択方法",
395
+ "invalid_value": "選択範囲を確認してください。",
396
+ "duplicate_value": "この項目は選択済みです。",
397
+ "incomplete_selection": "追加する値をすべて入力してください。",
398
+ "range_too_long": "{max_range_days}日以内で指定してください。",
399
+ },
400
+ empty_message="期間が選択されていません。",
401
+ max_selections_placeholder="選択数の上限に達しました。",
402
+ key="periods",
403
+ )
404
+ st.write(selected)
405
+ ```
406
+
407
+ ### Returned Values
408
+
409
+ Across the calendar modes, the returned `list[str]` retains the selected order
410
+ and identifies precision by format:
411
+
412
+ | Selection | Returned value |
413
+ | --- | --- |
414
+ | Date | `"2026-10-24"` |
415
+ | Month | `"2026-10"` |
416
+ | Date range | `"2026-10-01/2026-10-31"` |
417
+ | Month range | `"2026-10/2026-12"` |
418
+
419
+ Ranges include both endpoints, require the same precision at each end, and must
420
+ start on or before their end. Overlapping ranges are allowed; identical items
421
+ cannot be added twice. Dates and months may coexist in mixed mode. Switching
422
+ precision clears the unfinished input and preserves added items.
423
+
424
+ ### Bounds and Range Length
425
+
426
+ Bounds are optional. A `YYYY-MM` lower bound expands to the first day of that
427
+ month and an upper bound to its last day. Month selections compare by month:
428
+ `min_value="2026-01-15"` still permits the month `"2026-01"`, while date selections
429
+ must be on or after January 15. Changing bounds or input mode removes selected
430
+ items that are no longer valid.
431
+
432
+ Set `max_range_days=31` to allow at most 31 days in each date range. Both endpoints
433
+ count: January 1 through January 31 is 31 days; January 1 through February 1 is
434
+ 32 days and cannot be added. `max_range_days=1` allows only same-day date ranges.
435
+ The end picker uses the earlier of `max_value` and the start date plus
436
+ `max_range_days - 1` days. Invalid defaults and option metadata values raise an
437
+ error, and reducing the limit removes date ranges that exceed it. This limit
438
+ does not restrict single months or month ranges; `min_value` and `max_value`
439
+ still apply. It is available only in calendar modes.
440
+
441
+ | Setting | What it limits | Example |
442
+ | --- | --- | --- |
443
+ | `min_value` / `max_value` | Earliest/latest date or month that can be selected | `"2026-01-01"` through `"2027-12-31"` |
444
+ | `max_range_days` | Inclusive duration of each date range | `31` permits January 1 through January 31 |
445
+ | `max_selections` | Number of items in the list | `8` permits eight items, each a single value or a whole range |
446
+
447
+ Use a `datetime.date` object or an ISO string for bounds. `datetime.datetime`
448
+ objects are not accepted. Calendar defaults remain strings, such as
449
+ `"2026-10"` and `"2026-10-01/2026-10-31"`.
450
+
451
+ ### Shared Settings
452
+
453
+ Existing ordering, numbering, colors, selection limits, disabled states,
454
+ `selected_position`, `default_revision`, and inline single selection apply to
455
+ calendar items. `options` is optional and can supply metadata for known calendar
456
+ values; it does not restrict which valid values the picker accepts. API
457
+ suggestions are available only in options mode. Search placeholders and dropdown
458
+ height do not affect calendar inputs; `max_selections_placeholder` appears as a
459
+ status message when the limit is reached.
460
+
461
+ ### Browser Support
462
+
463
+ Date and month inputs use the browser's native picker, whose presentation and
464
+ language depend on the browser and operating system. Browsers without a native
465
+ month picker can accept `YYYY-MM` as text; the same validation applies. Calendar
466
+ values are strings without timezone conversion. See
467
+ [`examples/calendar_input.py`](examples/calendar_input.py) for mixed, date-only,
468
+ month-only, and form examples, including Japanese messages.
469
+
263
470
  ## API Suggestions
264
471
 
265
472
  Set `suggestions_api_url` to request suggestions as the user types. Static `options` that match the query are shown first, followed by API results. Duplicate `value` entries prefer the static option.
@@ -308,6 +515,9 @@ Changing the input cancels the previous in-flight request. Set `options=[]` to
308
515
  use only API results. Selected API values remain selected when a later query
309
516
  returns different suggestions.
310
517
 
518
+ ## Examples
519
+
520
+ See [`examples/README.md`](examples/README.md) for a description of each example.
311
521
  Build the frontend before packaging or using release mode:
312
522
 
313
523
  ```bash
@@ -319,6 +529,7 @@ Run the example app:
319
529
 
320
530
  ```bash
321
531
  streamlit run examples/basic.py
532
+ streamlit run examples/calendar_input.py
322
533
  streamlit run examples/color_by_id.py
323
534
  streamlit run examples/tooltip_labels.py
324
535
  streamlit run examples/api_suggestions.py
@@ -345,6 +556,28 @@ browser, it works only when the browser and Streamlit run on the same machine.
345
556
  For Docker, another computer, or a hosted Streamlit app, configure
346
557
  `suggestions_api_url` with a browser-accessible HTTPS endpoint instead.
347
558
 
559
+ ## Troubleshooting
560
+
561
+ If a new argument such as `calendar_labels` or `max_range_days` raises
562
+ `TypeError: sortable_multiselect() got an unexpected keyword argument ...`,
563
+ check the package path and function signature in the Python environment used
564
+ to run Streamlit:
565
+
566
+ ```bash
567
+ python -c 'import inspect; import streamlit_sortable_multiselect as sms; print(sms.__file__); print(inspect.signature(sms.sortable_multiselect))'
568
+ ```
569
+
570
+ For repository development, install the local package in that environment with
571
+ `python -m pip install -e ".[dev]"`. If the signature includes the argument but
572
+ an existing Streamlit process still reports it as unexpected, stop that process
573
+ and restart it to load the updated Python module:
574
+
575
+ ```bash
576
+ python -m streamlit run examples/calendar_input.py
577
+ ```
578
+
579
+ After rebuilding frontend assets, reload the app page to pick up the updated UI.
580
+
348
581
  ## Release
349
582
 
350
583
  Build and check the distribution files:
@@ -1,6 +1,8 @@
1
1
  # streamlit-sortable-multiselect
2
2
 
3
- A Streamlit custom component for searching, selecting, and reordering multiple string values.
3
+ A Streamlit custom component for searching, selecting, and reordering options,
4
+ dates, months, and date/month ranges. Selected items can be reordered by dragging
5
+ or using move buttons, and are returned as an ordered `list[str]`.
4
6
 
5
7
  ## Install
6
8
 
@@ -30,6 +32,10 @@ npm run dev
30
32
 
31
33
  ## Usage
32
34
 
35
+ The default `input_mode="options"` provides searchable options. For calendar
36
+ inputs, see [Calendar Input](#calendar-input), including date ranges, single
37
+ months, selection bounds, and Japanese labels and messages.
38
+
33
39
  ```python
34
40
  import streamlit as st
35
41
  from streamlit_sortable_multiselect import sortable_multiselect
@@ -62,15 +68,22 @@ st.write(selected)
62
68
 
63
69
  ## Settings
64
70
 
65
- `sortable_multiselect` returns the selected option values as a `list[str]` in the current display order.
71
+ `sortable_multiselect` returns selected values as a `list[str]` in the current
72
+ display order. Calendar values use the formats in [Returned Values](#returned-values).
66
73
 
67
74
  | Argument | Type | Default | Description |
68
75
  | --- | --- | --- | --- |
69
76
  | `label` | `str` | required | Label displayed above the component. |
70
- | `options` | `Sequence[str \| Mapping[str, Any]]` | required | Available options. Each option can be a plain string, or a dictionary with `label`, `value`, and optional `icon_url`. Option values must be unique. |
71
- | `default` | `Sequence[str] \| None` | `None` | Initially selected values, in the initial order. Changing the values or their order replaces the current selection. Values must exist in `options` and must not contain duplicates. |
72
- | `placeholder` | `str` | `"Select..."` | Placeholder shown in the search/add input when options are available. |
73
- | `disabled` | `bool` | `False` | Disables searching, selecting, removing, dragging, and move buttons. |
77
+ | `options` | `Sequence[str \| Mapping[str, Any]]` | `()` | Available options. Each option can be a plain string, or a dictionary with `label`, `value`, and optional `icon_url` and `color`. Option values must be unique. In calendar modes, optional entries supply labels, icons, and colors for matching calendar values. |
78
+ | `default` | `Sequence[str] \| None` | `None` | Initially selected values, in the initial order. Changing the values or their order replaces the current selection. In options mode, values must exist in `options`. Calendar defaults must match the mode and bounds. Duplicates are not allowed. |
79
+ | `default_revision` | `str \| int \| None` | `None` | Change this value to reapply `default` when its values and order are unchanged. |
80
+ | `input_mode` | `str` | `"options"` | `"options"`, `"date"`, `"month"`, or `"date_month"`. Mixed mode offers one switch between date ranges and single months. Date-only and month-only modes offer Single/Range controls. |
81
+ | `min_value` | `str \| datetime.date \| None` | `None` | Inclusive lower bound in calendar modes. Accepts `YYYY-MM-DD`, `YYYY-MM`, or a date object. |
82
+ | `max_value` | `str \| datetime.date \| None` | `None` | Inclusive upper bound in calendar modes. Accepts `YYYY-MM-DD`, `YYYY-MM`, or a date object. |
83
+ | `max_range_days` | `int \| None` | `None` | Maximum number of days in each date range, including start and end. Must be positive. `None` means unlimited. Does not limit single values or month ranges. Requires a calendar mode. |
84
+ | `calendar_labels` | `Mapping[str, str] \| None` | `None` | Overrides calendar switches, the Add button, field labels, accessibility group names, and validation messages. See [Calendar Input](#calendar-input) for all keys. Unspecified entries retain their English defaults. |
85
+ | `placeholder` | `str` | `"Select..."` | Placeholder shown in the search/add input when options are available. Used in options mode. |
86
+ | `disabled` | `bool` | `False` | Disables searching, calendar inputs and switches, adding, removing, dragging, and move buttons. |
74
87
  | `show_move_buttons` | `bool` | `True` | Shows up/down buttons on selected items. Drag sorting remains available unless `disabled=True`. |
75
88
  | `show_numbers` | `bool` | `False` | Shows 1-based position numbers before selected item labels. |
76
89
  | `base_color` | `str \| Mapping[str, str] \| None` | `None` | Fallback color for every selected item. See [Colors](#colors). |
@@ -81,13 +94,13 @@ st.write(selected)
81
94
  | `tooltip_color` | `str \| Mapping[str, str] \| None` | `None` | Color of the tooltip shown for labels that do not fit. `None` uses the built-in dark tooltip. See [Labels](#labels). |
82
95
  | `max_selections` | `int \| None` | `None` | Maximum number of selected items. `None` means no limit. Use `0` to prevent any selections. |
83
96
  | `single_select_display` | `bool` | `False` | With `max_selections=1`, displays the selected item inside the search control and replaces it when another option is selected. |
84
- | `max_selections_placeholder` | `str` | `"Selection limit reached"` | Placeholder shown when `max_selections` has been reached. This takes precedence over `placeholder` and `no_options_placeholder`, except in single-selection display mode. |
97
+ | `max_selections_placeholder` | `str` | `"Selection limit reached"` | Placeholder shown when `max_selections` has been reached in options mode; a status message in calendar modes. Takes precedence over other placeholders. Not shown in inline single-selection mode, which permits replacement. |
85
98
  | `empty_message` | `str` | `"No items selected"` | Message shown where the selected list appears when no items are selected. |
86
- | `no_options_placeholder` | `str` | `"No more options"` | Placeholder shown when every option is already selected and there are no more options to add. |
99
+ | `no_options_placeholder` | `str` | `"No more options"` | Placeholder shown when every option is already selected and there are no more options to add. Used in options mode. |
87
100
  | `selected_position` | `str` | `"bottom"` | Position of the selected item list relative to the search/add input. Use `"bottom"` or `"top"`. |
88
101
  | `icon_size` | `int` | `20` | Icon display size in pixels for `icon_url` images. Images are displayed inside a square area while preserving their aspect ratio. |
89
- | `options_max_height` | `int` | `190` | Maximum height in pixels for the available options dropdown. |
90
- | `suggestions_api_url` | `str \| None` | `None` | Absolute HTTP(S) endpoint used to fetch suggestions in the browser. `None` disables API suggestions. |
102
+ | `options_max_height` | `int` | `190` | Maximum height in pixels for the available options dropdown. Used in options mode. |
103
+ | `suggestions_api_url` | `str \| None` | `None` | Absolute HTTP(S) endpoint used to fetch suggestions in the browser. `None` disables API suggestions. Only supported in options mode. |
91
104
  | `suggestions_query_param` | `str` | `"q"` | Query parameter name used to send the current search text. |
92
105
  | `suggestions_response_path` | `str` | `""` | Dot-separated path to the suggestions array in the JSON response. Empty means the response root. |
93
106
  | `suggestions_label_path` | `str` | `"label"` | Dot-separated path to each suggestion's display label. |
@@ -101,6 +114,24 @@ st.write(selected)
101
114
  | `suggestions_error_message` | `str` | `"Failed to load suggestions"` | Message shown when the request or response cannot be processed. |
102
115
  | `key` | `str \| None` | `None` | Optional Streamlit component key. Use this when rendering multiple sortable multiselects. |
103
116
 
117
+ To reset a component to the same `default` after the user changes its selection,
118
+ increment or otherwise change `default_revision`:
119
+
120
+ ```python
121
+ if "reset_revision" not in st.session_state:
122
+ st.session_state.reset_revision = 0
123
+
124
+ if st.button("Reset languages"):
125
+ st.session_state.reset_revision += 1
126
+
127
+ selected = sortable_multiselect(
128
+ "Languages",
129
+ options=["Python", "TypeScript", "Rust"],
130
+ default=["Python"],
131
+ default_revision=st.session_state.reset_revision,
132
+ )
133
+ ```
134
+
104
135
  Option dictionaries use this shape:
105
136
 
106
137
  ```python
@@ -232,6 +263,182 @@ option replaces the current value instead of adding another one. Use the remove
232
263
  inside the selected item to clear it. `single_select_display=True` without
233
264
  `max_selections=1` raises `ValueError`.
234
265
 
266
+ In calendar modes, the selected item is displayed inside the calendar control.
267
+ Adding another calendar value replaces it. A date range counts as one selected item.
268
+
269
+ ## Calendar Input
270
+
271
+ ### Input Modes
272
+
273
+ `input_mode` selects the input method for the whole component:
274
+
275
+ | Mode | Picker controls | Items added |
276
+ | --- | --- | --- |
277
+ | `"options"` (default) | Searchable dropdown and optional API suggestions | Values from options or API results |
278
+ | `"date"` | Date input with a Single/Range switch | One date or one date range |
279
+ | `"month"` | Month input with a Single/Range switch | One month or one month range |
280
+ | `"date_month"` | One Date (range)/Month (single) switch | One date range or one month |
281
+
282
+ Use `input_mode="date_month"` to add date ranges and single months to one sortable
283
+ list. One switch selects Date (range) or Month (single). Date (range) shows Start
284
+ and End inputs; Month (single) shows one month input. Press Add to append the
285
+ selection. A range is one item, not an expanded sequence. Use `"date"` or `"month"`
286
+ for a fixed precision with a separate Single/Range switch.
287
+
288
+ ```python
289
+ import streamlit as st
290
+ from streamlit_sortable_multiselect import sortable_multiselect
291
+
292
+ selected = sortable_multiselect(
293
+ "Reporting periods",
294
+ input_mode="date_month",
295
+ min_value="2026-01-01",
296
+ max_value="2027-12-31",
297
+ max_range_days=31,
298
+ default=["2026-10-01/2026-10-24", "2026-11"],
299
+ show_numbers=True,
300
+ key="reporting_periods",
301
+ )
302
+ st.write("Selected order:", selected)
303
+ ```
304
+
305
+ Mixed mode initially shows the date-range inputs. Switching to Month (single)
306
+ clears unfinished inputs and keeps items already added to the sortable list.
307
+
308
+ ### Calendar Labels
309
+
310
+ Override `calendar_labels` to display Japanese or another language. The settings
311
+ apply to switch text, the Add button, field labels, accessibility group names,
312
+ and validation messages. They do not change returned values. Supported keys and
313
+ defaults are:
314
+
315
+ | Key | Default | Used in |
316
+ | --- | --- | --- |
317
+ | `date_range` | `"Date (range)"` | `date_month` |
318
+ | `month_single` | `"Month (single)"` | `date_month` |
319
+ | `single` | `"Single"` | `date`, `month` |
320
+ | `range` | `"Range"` | `date`, `month` |
321
+ | `add` | `"Add"` | Add button |
322
+ | `start` | `"Start"` | Range start field and its accessible name |
323
+ | `end` | `"End"` | Range end field and its accessible name |
324
+ | `date` | `"Date"` | Single-date field and its accessible name |
325
+ | `month` | `"Month"` | Single-month field and its accessible name |
326
+ | `calendar_input` | `"Calendar input"` | Accessible name of the mixed-mode switch group |
327
+ | `selection_kind` | `"Selection kind"` | Accessible name of the Single/Range switch group |
328
+ | `invalid_value` | `"Choose a valid value within the allowed range, with start on or before end."` | Invalid date, bounds, or reversed range |
329
+ | `duplicate_value` | `"This item is already selected."` | Exact duplicate selection |
330
+ | `incomplete_selection` | `"Complete the selection before adding it."` | Add or Enter with missing input |
331
+ | `range_too_long` | `"Choose a date range of at most {max_range_days} days (including both endpoints)."` | Date range longer than `max_range_days` |
332
+
333
+ Only specify the labels you want to override. Unknown keys, non-string values,
334
+ and empty or whitespace-only labels raise an error. In `range_too_long`, every
335
+ `{max_range_days}` placeholder is replaced with the configured limit; a message
336
+ without the placeholder is also allowed. Native calendar localization follows
337
+ the browser and operating system. Set `empty_message` for the empty selected
338
+ list and `max_selections_placeholder` for the selection-count limit message.
339
+
340
+ ### Japanese Example
341
+
342
+ ```python
343
+ import streamlit as st
344
+ from streamlit_sortable_multiselect import sortable_multiselect
345
+
346
+ selected = sortable_multiselect(
347
+ "Reporting periods",
348
+ input_mode="date_month",
349
+ min_value="2026-01-01",
350
+ max_value="2027-12-31",
351
+ max_range_days=31,
352
+ default=["2026-10-01/2026-10-24", "2026-11", "2027-01"],
353
+ show_numbers=True,
354
+ max_selections=8,
355
+ calendar_labels={
356
+ "date_range": "日付(範囲)",
357
+ "month_single": "年月(単一)",
358
+ "single": "単一",
359
+ "range": "範囲",
360
+ "add": "追加",
361
+ "start": "開始日",
362
+ "end": "終了日",
363
+ "date": "日付",
364
+ "month": "年月",
365
+ "calendar_input": "入力方法",
366
+ "selection_kind": "選択方法",
367
+ "invalid_value": "選択範囲を確認してください。",
368
+ "duplicate_value": "この項目は選択済みです。",
369
+ "incomplete_selection": "追加する値をすべて入力してください。",
370
+ "range_too_long": "{max_range_days}日以内で指定してください。",
371
+ },
372
+ empty_message="期間が選択されていません。",
373
+ max_selections_placeholder="選択数の上限に達しました。",
374
+ key="periods",
375
+ )
376
+ st.write(selected)
377
+ ```
378
+
379
+ ### Returned Values
380
+
381
+ Across the calendar modes, the returned `list[str]` retains the selected order
382
+ and identifies precision by format:
383
+
384
+ | Selection | Returned value |
385
+ | --- | --- |
386
+ | Date | `"2026-10-24"` |
387
+ | Month | `"2026-10"` |
388
+ | Date range | `"2026-10-01/2026-10-31"` |
389
+ | Month range | `"2026-10/2026-12"` |
390
+
391
+ Ranges include both endpoints, require the same precision at each end, and must
392
+ start on or before their end. Overlapping ranges are allowed; identical items
393
+ cannot be added twice. Dates and months may coexist in mixed mode. Switching
394
+ precision clears the unfinished input and preserves added items.
395
+
396
+ ### Bounds and Range Length
397
+
398
+ Bounds are optional. A `YYYY-MM` lower bound expands to the first day of that
399
+ month and an upper bound to its last day. Month selections compare by month:
400
+ `min_value="2026-01-15"` still permits the month `"2026-01"`, while date selections
401
+ must be on or after January 15. Changing bounds or input mode removes selected
402
+ items that are no longer valid.
403
+
404
+ Set `max_range_days=31` to allow at most 31 days in each date range. Both endpoints
405
+ count: January 1 through January 31 is 31 days; January 1 through February 1 is
406
+ 32 days and cannot be added. `max_range_days=1` allows only same-day date ranges.
407
+ The end picker uses the earlier of `max_value` and the start date plus
408
+ `max_range_days - 1` days. Invalid defaults and option metadata values raise an
409
+ error, and reducing the limit removes date ranges that exceed it. This limit
410
+ does not restrict single months or month ranges; `min_value` and `max_value`
411
+ still apply. It is available only in calendar modes.
412
+
413
+ | Setting | What it limits | Example |
414
+ | --- | --- | --- |
415
+ | `min_value` / `max_value` | Earliest/latest date or month that can be selected | `"2026-01-01"` through `"2027-12-31"` |
416
+ | `max_range_days` | Inclusive duration of each date range | `31` permits January 1 through January 31 |
417
+ | `max_selections` | Number of items in the list | `8` permits eight items, each a single value or a whole range |
418
+
419
+ Use a `datetime.date` object or an ISO string for bounds. `datetime.datetime`
420
+ objects are not accepted. Calendar defaults remain strings, such as
421
+ `"2026-10"` and `"2026-10-01/2026-10-31"`.
422
+
423
+ ### Shared Settings
424
+
425
+ Existing ordering, numbering, colors, selection limits, disabled states,
426
+ `selected_position`, `default_revision`, and inline single selection apply to
427
+ calendar items. `options` is optional and can supply metadata for known calendar
428
+ values; it does not restrict which valid values the picker accepts. API
429
+ suggestions are available only in options mode. Search placeholders and dropdown
430
+ height do not affect calendar inputs; `max_selections_placeholder` appears as a
431
+ status message when the limit is reached.
432
+
433
+ ### Browser Support
434
+
435
+ Date and month inputs use the browser's native picker, whose presentation and
436
+ language depend on the browser and operating system. Browsers without a native
437
+ month picker can accept `YYYY-MM` as text; the same validation applies. Calendar
438
+ values are strings without timezone conversion. See
439
+ [`examples/calendar_input.py`](examples/calendar_input.py) for mixed, date-only,
440
+ month-only, and form examples, including Japanese messages.
441
+
235
442
  ## API Suggestions
236
443
 
237
444
  Set `suggestions_api_url` to request suggestions as the user types. Static `options` that match the query are shown first, followed by API results. Duplicate `value` entries prefer the static option.
@@ -280,6 +487,9 @@ Changing the input cancels the previous in-flight request. Set `options=[]` to
280
487
  use only API results. Selected API values remain selected when a later query
281
488
  returns different suggestions.
282
489
 
490
+ ## Examples
491
+
492
+ See [`examples/README.md`](examples/README.md) for a description of each example.
283
493
  Build the frontend before packaging or using release mode:
284
494
 
285
495
  ```bash
@@ -291,6 +501,7 @@ Run the example app:
291
501
 
292
502
  ```bash
293
503
  streamlit run examples/basic.py
504
+ streamlit run examples/calendar_input.py
294
505
  streamlit run examples/color_by_id.py
295
506
  streamlit run examples/tooltip_labels.py
296
507
  streamlit run examples/api_suggestions.py
@@ -317,6 +528,28 @@ browser, it works only when the browser and Streamlit run on the same machine.
317
528
  For Docker, another computer, or a hosted Streamlit app, configure
318
529
  `suggestions_api_url` with a browser-accessible HTTPS endpoint instead.
319
530
 
531
+ ## Troubleshooting
532
+
533
+ If a new argument such as `calendar_labels` or `max_range_days` raises
534
+ `TypeError: sortable_multiselect() got an unexpected keyword argument ...`,
535
+ check the package path and function signature in the Python environment used
536
+ to run Streamlit:
537
+
538
+ ```bash
539
+ python -c 'import inspect; import streamlit_sortable_multiselect as sms; print(sms.__file__); print(inspect.signature(sms.sortable_multiselect))'
540
+ ```
541
+
542
+ For repository development, install the local package in that environment with
543
+ `python -m pip install -e ".[dev]"`. If the signature includes the argument but
544
+ an existing Streamlit process still reports it as unexpected, stop that process
545
+ and restart it to load the updated Python module:
546
+
547
+ ```bash
548
+ python -m streamlit run examples/calendar_input.py
549
+ ```
550
+
551
+ After rebuilding frontend assets, reload the app page to pick up the updated UI.
552
+
320
553
  ## Release
321
554
 
322
555
  Build and check the distribution files:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "streamlit-sortable-multiselect"
7
- version = "0.7.8"
7
+ version = "0.7.10"
8
8
  description = "A Streamlit custom component for selecting and reordering multiple string values."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"