@splunk/react-ui 5.8.0 → 5.9.1

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 (69) hide show
  1. package/Anchor.js +2 -1
  2. package/ButtonSimple.js +1 -1
  3. package/CHANGELOG.md +38 -0
  4. package/Calendar.js +134 -134
  5. package/Clickable.js +131 -94
  6. package/Code.js +177 -170
  7. package/CollapsiblePanel.js +173 -135
  8. package/ColumnLayout.js +69 -45
  9. package/ComboBox.js +1 -0
  10. package/Dropdown.js +87 -72
  11. package/File.js +35 -35
  12. package/LICENSE +1 -1
  13. package/MIGRATION.md +40 -0
  14. package/Markdown.js +331 -306
  15. package/Menu.js +259 -215
  16. package/Modal.js +174 -181
  17. package/Monogram.js +2 -2
  18. package/Multiselect.js +414 -334
  19. package/Number.js +237 -242
  20. package/Search.js +15 -14
  21. package/SelectBase.js +777 -719
  22. package/SimpleTable.d.ts +2 -0
  23. package/SimpleTable.js +433 -0
  24. package/SlidingPanels.js +224 -153
  25. package/SpotLight.d.ts +2 -0
  26. package/SpotLight.js +687 -0
  27. package/Table.js +1232 -1238
  28. package/Text.js +26 -26
  29. package/docker-compose.yml +12 -18
  30. package/docs-llm/Avatar.md +2 -8
  31. package/docs-llm/Collapsible Panel.md +11 -57
  32. package/docs-llm/Column Layout.md +2 -2
  33. package/docs-llm/Divider.md +33 -0
  34. package/docs-llm/Message Bar.md +4 -1
  35. package/docs-llm/Multiselect.md +185 -162
  36. package/docs-llm/Notifications.md +46 -0
  37. package/docs-llm/Table.md +7 -7
  38. package/docs-llm/Tree.md +7 -2
  39. package/docs-llm/Typography.md +1 -1
  40. package/docs-llm/llms.txt +7 -3
  41. package/package.json +9 -11
  42. package/test-runner-jest.config.js +4 -53
  43. package/types/src/CollapsiblePanel/docs/examples/Actions.d.ts +1 -1
  44. package/types/src/ColumnLayout/ColumnLayout.d.ts +2 -2
  45. package/types/src/Divider/docs/examples/VerticalWithAlignItems.d.ts +8 -0
  46. package/types/src/Markdown/Markdown.d.ts +14 -2
  47. package/types/src/Markdown/renderers/MarkdownTable.d.ts +2 -22
  48. package/types/src/Markdown/renderers/MarkdownWrapper.d.ts +11 -0
  49. package/types/src/Markdown/renderers/index.d.ts +3 -1
  50. package/types/src/Multiselect/Compact.d.ts +12 -3
  51. package/types/src/Multiselect/Multiselect.d.ts +12 -3
  52. package/types/src/Multiselect/Normal.d.ts +8 -3
  53. package/types/src/Multiselect/Option.d.ts +6 -3
  54. package/types/src/Multiselect/docs/examples/Disabled.d.ts +1 -0
  55. package/types/src/Multiselect/docs/examples/LoadMoreWithSelectAll.d.ts +9 -0
  56. package/types/src/SelectBase/SelectBase.d.ts +5 -1
  57. package/types/src/SimpleTable/Body.d.ts +25 -0
  58. package/types/src/SimpleTable/Cell.d.ts +20 -0
  59. package/types/src/SimpleTable/Head.d.ts +20 -0
  60. package/types/src/SimpleTable/HeadCell.d.ts +20 -0
  61. package/types/src/SimpleTable/Row.d.ts +20 -0
  62. package/types/src/SimpleTable/SimpleTable.d.ts +37 -0
  63. package/types/src/SimpleTable/index.d.ts +3 -0
  64. package/types/src/SpotLight/SpotLight.d.ts +88 -0
  65. package/types/src/SpotLight/index.d.ts +2 -0
  66. package/types/src/Table/Row.d.ts +1 -1
  67. package/types/src/Table/Table.d.ts +1 -1
  68. package/types/src/Typography/Typography.d.ts +1 -1
  69. package/types/src/Multiselect/docs/examples/LoadMoreOnScrollBottom.d.ts +0 -7
@@ -229,6 +229,8 @@ function NewValues() {
229
229
  'Line Chart',
230
230
  'Map',
231
231
  'Table',
232
+ 'Bar chart',
233
+ 'Bubble chart',
232
234
  ]);
233
235
 
234
236
  const handleChange: MultiselectChangeHandler = useCallback((e, { values }) => {
@@ -324,6 +326,8 @@ export default MultiselectError;
324
326
 
325
327
  ### Disabled
326
328
 
329
+ If you absolutely need to disable a `Multiselect` use `"disabled="dimmed"`. This ensures the `Multiselect` does not respond to events, but can still receive focus to so that users can navigate to the `Multiselect` when using assistive technologies.
330
+
327
331
  ```typescript
328
332
  import React, { useCallback, useState } from 'react';
329
333
 
@@ -338,7 +342,7 @@ function Disabled() {
338
342
  }, []);
339
343
 
340
344
  return (
341
- <Multiselect values={selectedValues} onChange={handleChange} disabled inline>
345
+ <Multiselect values={selectedValues} onChange={handleChange} disabled="dimmed" inline>
342
346
  <Multiselect.Option label="Area chart" value="1" />
343
347
  <Multiselect.Option label="Bar chart" value="2" />
344
348
  <Multiselect.Option label="Bubble chart" value="3" />
@@ -613,163 +617,6 @@ export default Fetching;
613
617
 
614
618
 
615
619
 
616
- ### Load more on scroll bottom
617
-
618
- Similar example as fetching but it's also possible to append more Options from a server when the list is scrolled to the bottom. Here, that behavior is simulated. The onScrollBottom prop is a function that should fetch more results and append them to the current Options. Once all items are loaded, the onScrollBottom prop should be set to null.
619
-
620
- ```typescript
621
- import React, { useCallback, useEffect, useMemo, useState } from 'react';
622
-
623
- import useFetchOptions, {
624
- isMovieOption,
625
- Movie,
626
- MovieOption,
627
- } from '@splunk/react-ui/fixtures/useFetchOptions';
628
- import Multiselect, {
629
- MultiselectChangeHandler,
630
- MultiselectFilterChangeHandler,
631
- } from '@splunk/react-ui/Multiselect';
632
- import { _ } from '@splunk/ui-utils/i18n';
633
-
634
-
635
- function LoadMoreOnScrollBottom() {
636
- const [fullCount, setFullCount] = useState(0);
637
- const [isLoading, setIsLoading] = useState(false);
638
- const [isLoadingMore, setIsLoadingMore] = useState(false);
639
- const [options, setOptions] = useState<MovieOption[]>([]);
640
- const [selectedValues, setSelectedValues] = useState<(string | number | boolean)[]>([10, 30]);
641
-
642
-
643
- const { fetch, fetchMore, getFullCount, getSelectedOptions, stop } = useFetchOptions();
644
-
645
- const handleFetch = useCallback(
646
- (keyword?: string) => {
647
- setIsLoading(true);
648
-
649
- fetch(keyword)
650
- .then((fetchedOptions) => {
651
- setIsLoading(false);
652
- setOptions(fetchedOptions);
653
- setFullCount(getFullCount());
654
- })
655
- .catch((error) => {
656
- if (!error.isCanceled) throw error;
657
- });
658
- },
659
- [fetch, getFullCount]
660
- );
661
-
662
- const handleChange: MultiselectChangeHandler = useCallback(
663
- (e, { values }) => {
664
- setSelectedValues(values);
665
- handleFetch();
666
- },
667
- [handleFetch]
668
- );
669
-
670
- const handleFetchMore = useCallback(
671
- (currentOptions: MovieOption[]) => {
672
- setIsLoadingMore(true);
673
-
674
- fetchMore(currentOptions)
675
- .then((fetchedOptions) => {
676
- setOptions(fetchedOptions);
677
- setIsLoading(false);
678
- setIsLoadingMore(false);
679
- setFullCount(getFullCount());
680
- })
681
- .catch((error) => {
682
- if (!error.isCanceled) {
683
- throw error;
684
- }
685
- });
686
- },
687
- [fetchMore, getFullCount]
688
- );
689
-
690
- const handleFilterChange: MultiselectFilterChangeHandler = useCallback(
691
- (e, { keyword }) => {
692
- handleFetch(keyword);
693
- },
694
- [handleFetch]
695
- );
696
-
697
- const handleScrollBottom = useCallback(() => {
698
- if (!isLoadingMore) {
699
- handleFetchMore(options);
700
- }
701
- }, [handleFetchMore, isLoadingMore, options]);
702
-
703
- useEffect(() => {
704
- handleFetch();
705
-
706
- return () => {
707
- stop();
708
- };
709
- }, [handleFetch, stop]);
710
-
711
- const createOption = useCallback(
712
- (movie: Movie | MovieOption, isSelected = false) => (
713
-
714
- <Multiselect.Option
715
- hidden={isSelected}
716
- key={isSelected ? `selected-${movie.id}` : movie.id}
717
- label={movie.title}
718
- matchRanges={isMovieOption(movie) ? movie.matchRanges : undefined}
719
- value={movie.id}
720
- />
721
- ),
722
- []
723
- );
724
-
725
- const generateOptions = useMemo(() => {
726
- // The selected items always have to be in the option list, but can be hidden
727
- let selectedOptions: React.ReactElement[] = [];
728
- if (selectedValues.length) {
729
- const selectedMovies = getSelectedOptions(selectedValues as number[]);
730
- selectedOptions = selectedMovies.map((movie) => createOption(movie, true));
731
- }
732
-
733
- if (isLoading) {
734
- // Only return the select items
735
- return selectedOptions;
736
- }
737
-
738
- const list = options.map((movie) => createOption(movie));
739
- return list.concat(selectedOptions);
740
- }, [createOption, getSelectedOptions, isLoading, options, selectedValues]);
741
-
742
- const footerMessage = useMemo(() => {
743
- if (fullCount > options.length && !isLoading) {
744
- return _('%1 of %2 movies')
745
- .replace('%1', options.length.toString())
746
- .replace('%2', fullCount.toString());
747
- }
748
- return null;
749
- }, [fullCount, options.length, isLoading]);
750
-
751
- return (
752
- <Multiselect
753
- values={selectedValues}
754
- placeholder={_('Select a movie...')}
755
- onChange={handleChange}
756
- controlledFilter
757
- onFilterChange={handleFilterChange}
758
- onScrollBottom={fullCount === options.length ? undefined : handleScrollBottom} // Disable when all items are loaded.
759
- isLoadingOptions={isLoading}
760
- footerMessage={footerMessage}
761
- inline
762
- >
763
- {generateOptions}
764
- </Multiselect>
765
- );
766
- }
767
-
768
- export default LoadMoreOnScrollBottom;
769
- ```
770
-
771
-
772
-
773
620
  ### data
774
621
 
775
622
  ```typescript
@@ -837,6 +684,182 @@ export default Compact;
837
684
 
838
685
 
839
686
 
687
+ ### movies
688
+
689
+ ```typescript
690
+ import React, { useCallback, useMemo, useState } from 'react';
691
+
692
+ import moviesJson from '@splunk/react-ui/fixtures/movies.json';
693
+ import Multiselect, {
694
+ MultiselectChangeHandler,
695
+ MultiselectFilterChangeHandler,
696
+ MultiselectScrollBottomHandler,
697
+ } from '@splunk/react-ui/Multiselect';
698
+ import { keywordLocations, stringToKeywords, testPhrase } from '@splunk/ui-utils/filter';
699
+ import { sprintf } from '@splunk/ui-utils/format';
700
+ import { _ } from '@splunk/ui-utils/i18n';
701
+
702
+ type Movie = {
703
+ id: number;
704
+ title: string;
705
+ };
706
+
707
+ type OptionItem = {
708
+ hidden?: boolean;
709
+ label: string;
710
+ matchRanges?: { start: number; end: number }[];
711
+ value: string | number | boolean;
712
+ };
713
+
714
+ const { movies } = moviesJson as { movies: Movie[] };
715
+
716
+ const pageSize = 20;
717
+
718
+
719
+ function LoadMoreWithSelectAll() {
720
+ const [keyword, setKeyword] = useState('');
721
+ const [loadedCount, setLoadedCount] = useState(pageSize);
722
+ const [values, setValues] = useState<(string | number | boolean)[]>([]);
723
+ const keywords = useMemo(() => stringToKeywords(keyword), [keyword]);
724
+
725
+ const allOptions = useMemo<OptionItem[]>(() => {
726
+ const hasKeyword = keywords.length > 0;
727
+ return movies
728
+ .filter((movie) => !hasKeyword || testPhrase(movie.title, keywords))
729
+ .map((movie) => ({
730
+ label: movie.title,
731
+ matchRanges: hasKeyword
732
+ ? keywordLocations(movie.title, keywords) || undefined
733
+ : undefined,
734
+ value: movie.id,
735
+ }));
736
+ }, [keywords]);
737
+
738
+ const visibleCount = Math.min(loadedCount, allOptions.length);
739
+ const loadedOptions = useMemo(
740
+ () => allOptions.slice(0, visibleCount),
741
+ [allOptions, visibleCount]
742
+ );
743
+ const allOptionValues = useMemo(() => allOptions.map((option) => option.value), [allOptions]);
744
+ const selectedValueSet = useMemo(() => new Set(values), [values]);
745
+ const movieById = useMemo(() => {
746
+ const map = new Map<string | number | boolean, Movie>();
747
+ movies.forEach((movie) => {
748
+ map.set(movie.id, movie);
749
+ });
750
+ return map;
751
+ }, []);
752
+
753
+ const options = useMemo<OptionItem[]>(() => {
754
+ const loadedValueSet = new Set(loadedOptions.map((option) => option.value));
755
+ const hiddenSelectedOptions = values
756
+ .filter((value) => !loadedValueSet.has(value))
757
+ .map((value) => movieById.get(value))
758
+ .filter((movie): movie is Movie => !!movie)
759
+ .map((movie) => ({
760
+ hidden: true,
761
+ label: movie.title,
762
+ matchRanges: keywordLocations(movie.title, keywords) || undefined,
763
+ value: movie.id,
764
+ }));
765
+
766
+ return [...loadedOptions, ...hiddenSelectedOptions];
767
+ }, [keywords, loadedOptions, movieById, values]);
768
+
769
+ const handleChange = useCallback<MultiselectChangeHandler>(
770
+ (_e, { values: nextValues, reason }) => {
771
+ if (reason === 'selectAll') {
772
+ setValues(allOptionValues);
773
+ return;
774
+ }
775
+
776
+ setValues(nextValues);
777
+ },
778
+ [allOptionValues]
779
+ );
780
+
781
+ const handleScrollBottom = useCallback<MultiselectScrollBottomHandler>(() => {
782
+ setLoadedCount((currentCount) => Math.min(currentCount + pageSize, allOptions.length));
783
+ }, [allOptions.length]);
784
+
785
+ const handleFilterChange = useCallback<MultiselectFilterChangeHandler>(
786
+ (_e, { keyword: nextKeyword }) => {
787
+ setKeyword(nextKeyword);
788
+ setLoadedCount(pageSize);
789
+ },
790
+ []
791
+ );
792
+
793
+ const footerMessage = useMemo(() => {
794
+ const selectedInFilteredCount = allOptions.filter((option) =>
795
+ selectedValueSet.has(option.value)
796
+ ).length;
797
+ const hasKeyword = keywords.length > 0;
798
+ const allLoaded = visibleCount >= allOptions.length;
799
+ const selectedCountDisplay = hasKeyword ? selectedInFilteredCount : values.length;
800
+
801
+ if (hasKeyword) {
802
+ if (allLoaded) {
803
+ return sprintf(_('%(selected)d selected / %(matches)d matches'), {
804
+ matches: allOptions.length,
805
+ selected: selectedCountDisplay,
806
+ });
807
+ }
808
+
809
+ return sprintf(_('%(selected)d selected (%(loaded)d loaded / %(matches)d matches)'), {
810
+ loaded: visibleCount,
811
+ matches: allOptions.length,
812
+ selected: selectedCountDisplay,
813
+ });
814
+ }
815
+
816
+ if (allLoaded) {
817
+ return sprintf(_('%(selected)d selected / %(total)d total'), {
818
+ selected: selectedCountDisplay,
819
+ total: allOptions.length,
820
+ });
821
+ }
822
+
823
+ return sprintf(_('%(selected)d selected (%(loaded)d loaded / %(total)d total)'), {
824
+ loaded: visibleCount,
825
+ selected: selectedCountDisplay,
826
+ total: allOptions.length,
827
+ });
828
+ }, [allOptions, keywords.length, selectedValueSet, values.length, visibleCount]);
829
+
830
+ return (
831
+ <Multiselect
832
+ compact
833
+ filter="controlled"
834
+ values={values}
835
+ placeholder={_('Select movies...')}
836
+ menuStyle={{ maxHeight: 640 }}
837
+ onChange={handleChange}
838
+ onFilterChange={handleFilterChange}
839
+ onScrollBottom={visibleCount < allOptions.length ? handleScrollBottom : undefined}
840
+ footerMessage={footerMessage}
841
+ selectAllAppearance="checkbox"
842
+ inline
843
+ >
844
+ {options.map(({ hidden, label, matchRanges, value }) => (
845
+ <Multiselect.Option
846
+ key={`${hidden ? 'selected-' : ''}${value}`}
847
+ // hidden options represent selected values outside the current loaded slice to avoid treating them as new values
848
+ hidden={hidden}
849
+ label={label}
850
+ matchRanges={matchRanges}
851
+ value={value}
852
+ />
853
+ ))}
854
+ </Multiselect>
855
+ );
856
+ }
857
+
858
+ export default LoadMoreWithSelectAll;
859
+ ```
860
+
861
+
862
+
840
863
 
841
864
  ## API
842
865
 
@@ -856,7 +879,7 @@ export default Compact;
856
879
  | defaultPlacement | 'above' \| 'below' \| 'vertical' | no | 'vertical' | The default placement of the dropdown menu. It might be rendered in a different direction depending upon the space available. |
857
880
  | defaultValues | (string \| number \| boolean)[] | no | | Set this property instead of value to keep the value uncontrolled. |
858
881
  | describedBy | string | no | | The id of the description. When placed in a ControlGroup, this is automatically set to the ControlGroup's help component. |
859
- | disabled | boolean | no | | Disable adding and removing. |
882
+ | disabled | boolean \| 'dimmed' \| 'disabled' | no | | Prevents user interaction and adds disabled styling. If set to `dimmed`, the component is able to receive focus. If set to `disabled`, the component is unable to receive focus. |
860
883
  | elementRef | React.Ref<HTMLButtonElement \| HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
861
884
  | error | boolean | no | | Display as in an error. |
862
885
  | filter | boolean \| 'controlled' | no | | Determines whether to show the filter box. When true, the children are automatically filtered based on the label. When controlled, the parent component must provide a onFilterChange callback and update the children. Only supported when `compact=true`. |
@@ -870,7 +893,7 @@ export default Compact;
870
893
  | menuStyle | React.CSSProperties | no | | Style properties to apply to the Menu. This is primarily used to override the width of the menu should it need to be wider than the toggle Button. |
871
894
  | name | string | no | | The name is returned with onChange events, which can be used to identify the control when multiple controls share an onChange callback. |
872
895
  | noOptionsMessage | React.ReactNode | no | _('No matches') | The noOptionsMessage is shown when there are no children and it's not loading, such as when there are no Options matching the filter. This can be customized to the type of content, for example: "No matching dashboards". You can insert other content, such as an error message, or communicate a minimum number of characters to enter to see results. |
873
- | onChange | MultiselectChangeHandler | no | | A callback to receive the change events. If values is set, this callback is required. This must set the values prop to retain the change. |
896
+ | onChange | MultiselectChangeHandler | no | | A callback to receive the change events. If values is set, this callback is required. This must set the values prop to retain the change. Supports custom selection behavior. |
874
897
  | onClose | () => void | no | | A callback function invoked when the popover closes. |
875
898
  | onFilterChange | MultiselectFilterChangeHandler | no | | A callback with the change event and value of the filter box. Providing this callback and setting controlledFilter to true enables you to filter and update the children by other criteria. |
876
899
  | onOpen | () => void | no | | A callback function invoked when the popover opens. |
@@ -879,7 +902,7 @@ export default Compact;
879
902
  | placeholder | string | no | _('Select...') | If 'value' is undefined or doesn't match an item, the Button will display this text. |
880
903
  | prepend | boolean | no | | Prepend removes rounded borders from the left side. |
881
904
  | repositionMode | 'none' \| 'flip' | no | 'flip' | See `repositionMode` on `Popover` for details. |
882
- | selectAllAppearance | 'buttongroup' \| 'checkbox' \| 'none' | no | | **DEPRECATED**: Value 'buttongroup' Determines how to display Select all/Clear all. Only supported when `compact=true`. The 'buttongroup' value is deprecated and will be removed in a future major version. |
905
+ | selectAllAppearance | 'buttongroup' \| 'checkbox' \| 'none' | no | | **DEPRECATED**: Value 'buttongroup' Determines how to display Select all/Clear all. Only supported when `compact=true`. By default, selection applies only to currently loaded options. Use `onChange` for custom selection behavior. The 'buttongroup' value is deprecated and will be removed in a future major version. |
883
906
  | showSelectedValuesFirst | 'nextOpen' \| 'immediately' \| 'never' | no | | When `compact=true`, move selected values to the top of the list on next open (default), immediately, or not at all. |
884
907
  | tabConfirmsNewValue | boolean | no | | Pressing Tab while entering an input confirms the new value. Requires `allowNewValues`. |
885
908
  | values | (string \| number \| boolean)[] | no | | Value will be matched to one of the children to deduce the label and/or icon for the toggle. |
@@ -905,7 +928,7 @@ An option within a `Multiselect`.
905
928
  | children | React.ReactNode | no | | When provided, `children` is rendered instead of the `label`. Caution: The element(s) passed here must be pure. |
906
929
  | description | string | no | | Additional information to explain the option, such as "Recommended". |
907
930
  | descriptionPosition | 'right' \| 'bottom' | no | 'bottom' | The description text may appear to the right of the label or under the label. |
908
- | disabled | boolean | no | | If disabled=true, the option is grayed out and cannot be clicked. |
931
+ | disabled | boolean \| 'dimmed' \| 'disabled' | no | | Prevents user interaction and adds disabled styling. If set to `dimmed`, the component is able to receive focus. If set to `disabled`, the component is unable to receive focus. |
909
932
  | hidden | boolean | no | | Adding hidden options can be useful for resolving the selected display label and icon, when the option should not be in the list. This scenario can arise when Select's filter is controlled, because the selected item may be filtered out; and when a legacy option is valid, but should no longer be displayed as a selectable option. |
910
933
  | icon | React.ReactNode | no | | The icon to show before the label. See the @splunk/react-icons package for drop in icons. Caution: The element(s) passed here must be pure. All icons in the react-icons package are pure. |
911
934
  | label | string | yes | | The text to show for the option when `children` is not defined. When filtering, the `label` is used for matching to the filter text. |
@@ -0,0 +1,46 @@
1
+ # Notifications
2
+
3
+ ## Overview
4
+
5
+ # Notifications
6
+
7
+ Notifications help users understand what happened, what needs attention, and what to do next.
8
+
9
+ There are two notification components in Splunk UI:
10
+ - [Message](./Message) is used for inline, contextual feedback near the content it refers to.
11
+ - [Message Bar](./MessageBar) is used for page-level or system-level communication.
12
+
13
+ These components use standardized icons and [`notificationColors` design tokens](../themes/variables#notification-colors) to communicate consistent tone and urgency, so users can quickly understand what to expect.
14
+
15
+ ## Toast Notifications (Deprecated)
16
+
17
+ Toast notifications are **deprecated** and should not be used for new experiences.
18
+ Even with careful implementation, this pattern still creates significant accessibility and usability barriers.
19
+
20
+ Use persistent, user-dismissible notifications instead:
21
+ - Use [Message](./Message) for inline, contextual feedback.
22
+ - Use [Message Bar](./MessageBar) for page-level or system-level communication.
23
+
24
+ ### Migration Guide
25
+
26
+ Review the CRUD Blueprint sections for [Create confirmation](../../DesignSystem/Blueprints/CRUD/Create#3-confirmation), [Update confirmation](../../DesignSystem/Blueprints/CRUD/Update#3-confirmation) and [Delete feedback](../../DesignSystem/Blueprints/CRUD/Delete#3-feedback) for guidance on scenarios where the toast pattern may have previously been used.
27
+
28
+ Below are suggestions for how to migrate common scenarios:
29
+
30
+ | Current Toast Pattern | Recommended Alternative | Reason |
31
+ |---|---|---|
32
+ | Success message after form submission | Message Bar at top of page, or inline Message next to changed element | Persistent confirmation is visible to all users regardless of timing |
33
+ | Error feedback | Inline Message in form field, or Message Bar at top | Direct association with the error source helps users understand and fix the problem |
34
+ | Temporary status updates | Message Bar for page-level updates, or Message for task-level updates | Clear scope and persistent visibility ensure all users receive the information |
35
+ | Real-time alerts | Message Bar with optional dismiss action | Ensures users see critical information before it's dismissed |
36
+
37
+ ### Further Reading
38
+
39
+ Below are additional resources to understand the issues with toast patterns:
40
+
41
+ - [GitHub Primer: Accessible Notifications and Messages](https://primer.style/accessibility/patterns/accessible-notifications-and-messages/#toasts)
42
+ - [Defining Toast Messages (Adrian Roselli)](https://adrianroselli.com/2020/01/defining-toast-messages.html)
43
+ - [A Toast to an Accessible Toast... to Notifications (Scott O'Hara)](https://www.scottohara.me/blog/2019/07/08/a-toast-to-a11y-toasts.html)
44
+ - [The Problem with Toast Messages and What to Do Instead (Adam Silver)](https://adamsilver.io/blog/the-problem-with-toast-messages-and-what-to-do-instead/)
45
+
46
+
package/docs-llm/Table.md CHANGED
@@ -2452,14 +2452,14 @@ export default Complex;
2452
2452
 
2453
2453
  | Name | Type | Required | Default | Description |
2454
2454
  |------|------|------|------|------|
2455
- | actions | React.ReactElement[] | no | | Adds table-level actions. Not compatible with `onRequestResize`. |
2455
+ | actions | React.ReactElement[] | no | [] | Adds table-level actions. Not compatible with `onRequestResize`. |
2456
2456
  | actionsColumnWidth | number | no | | Specifies the width of the actions column. Adds an empty header for row actions if no table-level actions are present. |
2457
2457
  | children | React.ReactNode | no | | Must be `Table.Head`, `Table.Body`, or `Table.Caption`. |
2458
- | dockOffset | number | no | | Sets the offset from the top of the window. Only applies when `headType` is 'docked'. |
2458
+ | dockOffset | number | no | 0 | Sets the offset from the top of the window. Only applies when `headType` is 'docked'. |
2459
2459
  | dockScrollBar | boolean | no | | Docks the horizontal scroll bar at the bottom of the window when the bottom of the table is below the viewport. |
2460
2460
  | elementRef | React.Ref<HTMLDivElement> | no | | A React ref which is set to the DOM element when the component mounts and null when it unmounts. |
2461
- | headType | 'docked' \| 'fixed' \| 'inline' | no | | Sets the table head type: * `docked`: The head is docked against the window * `fixed` : The head is fixed in the table. The table can scroll independently from the head. * `inline`: The head isn't fixed, but can scroll with the rest of the table. |
2462
- | horizontalOverflow | 'auto' \| 'scroll' | no | | Controls how the Table handles horizontal content overflow: * `auto`: The default behavior for overflow. `HeadCell` content will truncate and `Cell` content will wrap. The Table will scroll horizontally when the container's width exceeds the Table's width. * `scroll`: The Table will scroll horizontally. `HeadCell` content will not truncate and `Cell` content will wrap only for word breaks. |
2461
+ | headType | 'docked' \| 'fixed' \| 'inline' | no | 'inline' | Sets the table head type: * `docked`: The head is docked against the window * `fixed` : The head is fixed in the table. The table can scroll independently from the head. * `inline`: The head isn't fixed, but can scroll with the rest of the table. |
2462
+ | horizontalOverflow | 'auto' \| 'scroll' | no | 'auto' | Controls how the Table handles horizontal content overflow: * `auto`: The default behavior for overflow. `HeadCell` content will truncate and `Cell` content will wrap. The Table will scroll horizontally when the container's width exceeds the Table's width. * `scroll`: The Table will scroll horizontally. `HeadCell` content will not truncate and `Cell` content will wrap only for word breaks. |
2463
2463
  | innerStyle | React.CSSProperties | no | | Style specification for the inner container, which is the scrolling container. |
2464
2464
  | onRequestMoveColumn | TableRequestMoveColumnHandler | no | | An event handler for handle the re-order action of Table. The function is passed an options object with `fromIndex` and `toIndex`. |
2465
2465
  | onRequestMoveRow | TableRequestMoveRowHandler | no | | An event handler to handle the reorder rows action of Table. The function is passed an options object with `fromIndex` and `toIndex`. |
@@ -2468,10 +2468,10 @@ export default Complex;
2468
2468
  | onScroll | React.UIEventHandler<HTMLDivElement> | no | | Callback invoked when a scroll event occurs on the inner scrolling container. |
2469
2469
  | outerStyle | React.CSSProperties | no | | Style specification for the outer container. |
2470
2470
  | pinnedColumns | PinnedColumnsProp | no | | Optionally pin the actions column to the end of the table by passing `pinnedColumns={{ actions: true }}.` When using pinned columns `horizontalOverflow` should be set to `scroll`. |
2471
- | primaryColumnIndex | number | no | | Indicates the column to use as the primary label for each row. |
2471
+ | primaryColumnIndex | number | no | 0 | Indicates the column to use as the primary label for each row. |
2472
2472
  | resizableFillLayout | boolean | no | | Table will fill parent container. Resizable columns can have a `width` of `auto` only with this prop enabled. |
2473
- | rowExpansion | 'single' \| 'multi' \| 'controlled' \| 'none' | no | | Adds a column to the table with an expansion button for each row that has expansion content. Supported values: * `single`: Only one row can be expanded at a time. If another expansion button is clicked, the currently expanded row closes and the new one opens. * `multi`: Allows multiple rows to be expanded at the same time. * `controlled`: Allows the expanded state to be externally managed by `expanded` prop of `Row`. * `none`: The default with no row expansion. |
2474
- | rowSelection | 'all' \| 'some' \| 'none' | no | | When an `onRequestToggleAllRows` handler is defined, this prop determines the appearance of the toggle all rows button. |
2473
+ | rowExpansion | 'single' \| 'multi' \| 'controlled' \| 'none' | no | 'none' | Adds a column to the table with an expansion button for each row that has expansion content. Supported values: * `single`: Only one row can be expanded at a time. If another expansion button is clicked, the currently expanded row closes and the new one opens. * `multi`: Allows multiple rows to be expanded at the same time. * `controlled`: Allows the expanded state to be externally managed by `expanded` prop of `Row`. * `none`: The default with no row expansion. |
2474
+ | rowSelection | 'all' \| 'some' \| 'none' | no | 'none' | When an `onRequestToggleAllRows` handler is defined, this prop determines the appearance of the toggle all rows button. |
2475
2475
  | stripeRows | boolean | no | | Alternate rows are given a darker background to improve readability. |
2476
2476
  | tableStyle | React.CSSProperties | no | | The style attribute for the table. This is primarily useful for setting the CSS table-layout property. |
2477
2477
 
package/docs-llm/Tree.md CHANGED
@@ -163,8 +163,10 @@ import { variables } from '@splunk/themes';
163
163
 
164
164
  const StyledExpansionToggleWrapper = styled.span`
165
165
  display: inline-flex;
166
- padding-inline-end: ${variables.spacingSmall};
167
166
  width: 16px;
167
+ justify-content: center;
168
+ align-items: center;
169
+ padding-inline: ${variables.spacingMedium};
168
170
  `;
169
171
  const StyledSpan = styled.span`
170
172
  display: inline-flex;
@@ -314,9 +316,12 @@ import { variables } from '@splunk/themes';
314
316
  const StyledExpansionToggleWrapper = styled.span`
315
317
  display: inline-flex;
316
318
  width: 16px;
319
+ justify-content: center;
320
+ align-items: center;
321
+ padding-inline: ${variables.spacingMedium};
317
322
  `;
318
323
  const StyledCheckbox = styled(Checkbox)`
319
- padding-inline: ${variables.spacingSmall};
324
+ padding-inline-end: ${variables.spacingSmall};
320
325
  `;
321
326
  const StyledSpan = styled.span`
322
327
  align-items: center;
@@ -68,7 +68,7 @@ Typography renders text content with styling based on the Splunk Design System.
68
68
 
69
69
  | Name | Type | Required | Default | Description |
70
70
  |------|------|------|------|------|
71
- | as | \| 'p' \| 'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6' \| 'span' \| 'blockquote' \| 'dd' \| 'dl' \| 'dt' \| 'figcaption' \| 'figure' \| 'li' \| 'ol' \| 'ul' \| 'pre' \| 'abbr' \| 'cite' \| 'code' \| 'data' \| 'dfn' \| 'em' \| 'u' \| 'time' \| 'sup' \| 'sub' \| 'strong' \| 'small' \| 'samp' \| 's' \| 'var' \| 'ruby' \| 'rt' \| 'rp' | yes | | Tag for the element to render children content into. Use the most semantically appropriate tag. Layout elements like `div` are not allowed; use the `typography` mixin from `@splunk/themes` instead. |
71
+ | as | \| 'p' \| 'h1' \| 'h2' \| 'h3' \| 'h4' \| 'h5' \| 'h6' \| 'span' \| 'blockquote' \| 'dd' \| 'dl' \| 'dt' \| 'figcaption' \| 'figure' \| 'li' \| 'ol' \| 'ul' \| 'pre' \| 'abbr' \| 'cite' \| 'code' \| 'data' \| 'dfn' \| 'em' \| 'label' \| 'u' \| 'time' \| 'sup' \| 'sub' \| 'strong' \| 'small' \| 'samp' \| 's' \| 'var' \| 'ruby' \| 'rt' \| 'rp' | yes | | Tag for the element to render children content into. Use the most semantically appropriate tag. Layout elements like `div` are not allowed; use the `typography` mixin from `@splunk/themes` instead. |
72
72
  | children | React.ReactNode | yes | | Text and inline icons |
73
73
  | color | 'active' \| 'default' \| 'disabled' \| 'inverted' \| 'muted' \| 'inherit' | no | | Set the color to a system-standard color: e.g. `active` for `@splunk/themes/variables.contentColorActive`. |
74
74
  | elementRef | React.Ref<HTMLElement> | no | | A React ref which is set to the DOM element when the component mounts, and null when it unmounts. |
package/docs-llm/llms.txt CHANGED
@@ -17,8 +17,6 @@ A library of UI components, all independent of the Splunk Enterprise environment
17
17
  - **JSON Tree**
18
18
  - **Link**
19
19
  - **Markdown**
20
- - **Message**
21
- - **Message Bar**
22
20
  - **Modal**
23
21
  - **Paginator**
24
22
  - **Progress**
@@ -68,12 +66,17 @@ A library of UI components, all independent of the Splunk Enterprise environment
68
66
  - **Anchor Menu**
69
67
  - **Breadcrumbs**
70
68
 
69
+ ## Notifications
70
+
71
+ - **Notifications**
72
+ - **Message**
73
+ - **Message Bar**
74
+
71
75
  ## Utilities
72
76
 
73
77
  - **AnimationToggle**
74
78
  - **Button Group**
75
79
  - **Clickable**
76
- - **Column Layout**
77
80
  - **Divider**
78
81
  - **Dropdown**
79
82
  - **Layer**
@@ -93,5 +96,6 @@ A library of UI components, all independent of the Splunk Enterprise environment
93
96
  ## Deprecated
94
97
 
95
98
  - **Accordion**
99
+ - **Column Layout**
96
100
  - **Monogram**
97
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splunk/react-ui",
3
- "version": "5.8.0",
3
+ "version": "5.9.1",
4
4
  "description": "Library of React components that implement the Splunk design language",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Splunk Inc.",
@@ -45,17 +45,16 @@
45
45
  "@dnd-kit/sortable": "^8.0.0",
46
46
  "@dnd-kit/utilities": "^3.2.2",
47
47
  "@react-spring/web": "^9.7.5",
48
- "@splunk/react-icons": "^5.8.0",
49
- "@splunk/themes": "^1.5.0",
50
- "@splunk/ui-utils": "^1.12.0",
48
+ "@splunk/react-icons": "^5.10.0",
49
+ "@splunk/themes": "^1.7.0",
50
+ "@splunk/ui-utils": "^1.13.0",
51
51
  "decimal.js-light": "^2.5.1",
52
52
  "intl-tel-input": "^25.3.2",
53
- "lodash": "^4.17.14",
53
+ "lodash": "^4.18.1",
54
54
  "moment": "^2.29.4",
55
55
  "prop-types": "^15.6.2",
56
56
  "react-markdown": "^8.0.7",
57
57
  "remark-gfm": "^1.0.0",
58
- "tinycolor2": "^1.4.1",
59
58
  "use-sync-external-store": "^1.6.0",
60
59
  "use-typed-event-listener": "^3.0.0"
61
60
  },
@@ -63,10 +62,10 @@
63
62
  "@babel/core": "^7.28.0",
64
63
  "@babel/plugin-transform-runtime": "^7.28.0",
65
64
  "@splunk/babel-preset": "^4.0.0",
66
- "@splunk/docs-gen": "^1.4.0",
67
- "@splunk/eslint-config": "^5.0.0",
68
- "@splunk/eslint-plugin-splunk-ui": "^0.1.0",
69
- "@splunk/react-docs": "^1.5.1",
65
+ "@splunk/docs-gen": "^1.5.0",
66
+ "@splunk/eslint-config": "^5.1.0",
67
+ "@splunk/eslint-plugin-splunk-ui": "^0.2.0",
68
+ "@splunk/react-docs": "^1.7.0",
70
69
  "@splunk/stylelint-config": "^5.0.0",
71
70
  "@splunk/test-runner-utils": "^0.4.1",
72
71
  "@splunk/webpack-configs": "^7.0.3",
@@ -90,7 +89,6 @@
90
89
  "@types/react": "^18.2.0",
91
90
  "@types/react-dom": "^18.2.0",
92
91
  "@types/styled-components": "^5.1.0",
93
- "@types/tinycolor2": "^1.4.2",
94
92
  "@types/use-sync-external-store": "^1.5.0",
95
93
  "@types/webpack-env": "^1.15.2",
96
94
  "@typescript-eslint/eslint-plugin": "^8.29.1",