@mezzanine-ui/react 1.0.0-beta.2 → 1.0.0-beta.4

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 (193) hide show
  1. package/Anchor/Anchor.d.ts +51 -18
  2. package/Anchor/Anchor.js +15 -15
  3. package/Anchor/AnchorGroup.d.ts +34 -0
  4. package/Anchor/AnchorGroup.js +37 -0
  5. package/Anchor/AnchorItem.d.ts +30 -0
  6. package/Anchor/AnchorItem.js +65 -0
  7. package/Anchor/index.d.ts +2 -0
  8. package/Anchor/index.js +1 -0
  9. package/Anchor/utils.d.ts +13 -0
  10. package/Anchor/utils.js +95 -0
  11. package/AutoComplete/AutoComplete.d.ts +217 -0
  12. package/AutoComplete/AutoComplete.js +433 -0
  13. package/AutoComplete/index.d.ts +2 -0
  14. package/AutoComplete/index.js +1 -0
  15. package/AutoComplete/useAutoCompleteCreation.d.ts +33 -0
  16. package/AutoComplete/useAutoCompleteCreation.js +201 -0
  17. package/AutoComplete/useAutoCompleteKeyboard.d.ts +31 -0
  18. package/AutoComplete/useAutoCompleteKeyboard.js +149 -0
  19. package/AutoComplete/useAutoCompleteSearch.d.ts +16 -0
  20. package/AutoComplete/useAutoCompleteSearch.js +69 -0
  21. package/AutoComplete/useCreationTracker.d.ts +17 -0
  22. package/AutoComplete/useCreationTracker.js +47 -0
  23. package/Breadcrumb/Breadcrumb.js +16 -21
  24. package/Breadcrumb/BreadcrumbDropdown.d.ts +11 -0
  25. package/Breadcrumb/BreadcrumbDropdown.js +22 -0
  26. package/Breadcrumb/BreadcrumbItem.d.ts +2 -3
  27. package/Breadcrumb/BreadcrumbItem.js +13 -31
  28. package/Breadcrumb/BreadcrumbOverflowMenu.d.ts +7 -0
  29. package/Breadcrumb/BreadcrumbOverflowMenu.js +77 -0
  30. package/Breadcrumb/BreadcrumbOverflowMenuDropdown.d.ts +11 -0
  31. package/Breadcrumb/BreadcrumbOverflowMenuDropdown.js +21 -0
  32. package/Breadcrumb/BreadcrumbOverflowMenuItem.d.ts +3 -0
  33. package/Breadcrumb/BreadcrumbOverflowMenuItem.js +27 -0
  34. package/Breadcrumb/typings.d.ts +21 -39
  35. package/Button/Button.js +13 -11
  36. package/Button/index.d.ts +1 -1
  37. package/Button/typings.d.ts +27 -4
  38. package/Checkbox/index.d.ts +4 -5
  39. package/Checkbox/index.js +1 -5
  40. package/ContentHeader/ContentHeader.d.ts +160 -0
  41. package/ContentHeader/ContentHeader.js +54 -0
  42. package/ContentHeader/index.d.ts +2 -0
  43. package/ContentHeader/index.js +1 -0
  44. package/ContentHeader/utils.d.ts +23 -0
  45. package/ContentHeader/utils.js +215 -0
  46. package/Description/Description.d.ts +12 -22
  47. package/Description/Description.js +4 -24
  48. package/Dropdown/Dropdown.d.ts +46 -1
  49. package/Dropdown/Dropdown.js +99 -14
  50. package/Dropdown/DropdownAction.d.ts +1 -1
  51. package/Dropdown/DropdownAction.js +1 -4
  52. package/Dropdown/DropdownItem.d.ts +28 -1
  53. package/Dropdown/DropdownItem.js +56 -14
  54. package/Dropdown/DropdownItemCard.d.ts +2 -2
  55. package/Dropdown/DropdownItemCard.js +20 -16
  56. package/Dropdown/DropdownStatus.js +29 -0
  57. package/Dropdown/dropdownKeydownHandler.d.ts +2 -1
  58. package/Dropdown/dropdownKeydownHandler.js +73 -0
  59. package/Dropdown/highlightText.js +5 -1
  60. package/Dropdown/shortcutTextHandler.d.ts +24 -0
  61. package/Dropdown/shortcutTextHandler.js +171 -0
  62. package/Empty/Empty.js +2 -1
  63. package/Empty/icons/EmptyMainNotificationIcon.d.ts +4 -0
  64. package/Empty/icons/EmptyMainNotificationIcon.js +9 -0
  65. package/Empty/typings.d.ts +2 -2
  66. package/FilterArea/Filter.d.ts +32 -0
  67. package/FilterArea/Filter.js +23 -0
  68. package/FilterArea/FilterArea.d.ts +58 -0
  69. package/FilterArea/FilterArea.js +31 -0
  70. package/FilterArea/FilterLine.d.ts +11 -0
  71. package/FilterArea/FilterLine.js +13 -0
  72. package/FilterArea/index.d.ts +6 -0
  73. package/FilterArea/index.js +3 -0
  74. package/Form/FormField.js +3 -1
  75. package/Input/Input.d.ts +35 -7
  76. package/Input/Input.js +48 -14
  77. package/Input/index.d.ts +1 -1
  78. package/Modal/MediaPreviewModal.d.ts +54 -0
  79. package/Modal/MediaPreviewModal.js +158 -0
  80. package/Modal/Modal.d.ts +103 -11
  81. package/Modal/Modal.js +14 -9
  82. package/Modal/ModalBodyForVerification.d.ts +59 -0
  83. package/Modal/ModalBodyForVerification.js +99 -0
  84. package/Modal/ModalControl.d.ts +2 -2
  85. package/Modal/ModalControl.js +1 -1
  86. package/Modal/ModalFooter.d.ts +119 -1
  87. package/Modal/ModalFooter.js +15 -3
  88. package/Modal/ModalHeader.d.ts +26 -7
  89. package/Modal/ModalHeader.js +33 -7
  90. package/Modal/index.d.ts +6 -5
  91. package/Modal/index.js +2 -2
  92. package/Modal/useModalContainer.d.ts +12 -3
  93. package/Modal/useModalContainer.js +28 -6
  94. package/Navigation/Navigation.d.ts +7 -2
  95. package/Navigation/Navigation.js +36 -35
  96. package/Navigation/NavigationHeader.d.ts +4 -0
  97. package/Navigation/NavigationHeader.js +3 -2
  98. package/Navigation/NavigationOption.d.ts +8 -3
  99. package/Navigation/NavigationOption.js +46 -11
  100. package/Navigation/NavigationOptionCategory.js +1 -0
  101. package/Navigation/NavigationOverflowMenu.d.ts +6 -0
  102. package/Navigation/NavigationOverflowMenu.js +90 -0
  103. package/Navigation/NavigationOverflowMenuOption.d.ts +7 -0
  104. package/Navigation/NavigationOverflowMenuOption.js +68 -0
  105. package/Navigation/NavigationUserMenu.d.ts +4 -2
  106. package/Navigation/NavigationUserMenu.js +13 -5
  107. package/Navigation/context.d.ts +3 -2
  108. package/Navigation/useVisibleItems.d.ts +5 -0
  109. package/Navigation/useVisibleItems.js +54 -0
  110. package/NotificationCenter/NotificationCenter.d.ts +124 -0
  111. package/NotificationCenter/NotificationCenter.js +279 -0
  112. package/NotificationCenter/NotificationCenterDrawer.d.ts +109 -0
  113. package/NotificationCenter/index.d.ts +3 -0
  114. package/NotificationCenter/index.js +1 -0
  115. package/PageFooter/PageFooter.d.ts +19 -9
  116. package/PageFooter/PageFooter.js +10 -10
  117. package/PageHeader/PageHeader.d.ts +32 -25
  118. package/PageHeader/PageHeader.js +49 -43
  119. package/ResultState/ResultState.d.ts +9 -0
  120. package/ResultState/ResultState.js +36 -4
  121. package/Scrollbar/Scrollbar.d.ts +9 -0
  122. package/Scrollbar/Scrollbar.js +78 -0
  123. package/Scrollbar/index.d.ts +2 -0
  124. package/Scrollbar/index.js +1 -0
  125. package/Scrollbar/typings.d.ts +47 -0
  126. package/Select/SelectTrigger.js +5 -4
  127. package/Select/index.d.ts +0 -2
  128. package/Select/index.js +0 -1
  129. package/Select/typings.d.ts +6 -1
  130. package/Selection/Selection.js +1 -1
  131. package/Selection/SelectionGroup.d.ts +28 -0
  132. package/Slider/useSlider.js +1 -1
  133. package/Table/Table.d.ts +2 -120
  134. package/Table/Table.js +148 -53
  135. package/Table/TableContext.d.ts +11 -12
  136. package/Table/components/TableActionsCell.js +12 -4
  137. package/Table/components/TableBody.js +2 -1
  138. package/Table/components/TableBulkActions.js +1 -19
  139. package/Table/components/TableColGroup.d.ts +1 -4
  140. package/Table/components/TableColGroup.js +15 -16
  141. package/Table/components/TableCollectableCell.d.ts +17 -0
  142. package/Table/components/TableCollectableCell.js +54 -0
  143. package/Table/components/TableDragOrPinHandleCell.d.ts +20 -0
  144. package/Table/components/TableDragOrPinHandleCell.js +58 -0
  145. package/Table/components/TableExpandedRow.js +11 -2
  146. package/Table/components/TableHeader.js +12 -10
  147. package/Table/components/TableRow.js +38 -13
  148. package/Table/components/TableSelectionCell.js +1 -1
  149. package/Table/components/TableToggleableCell.d.ts +16 -0
  150. package/Table/components/TableToggleableCell.js +51 -0
  151. package/Table/components/index.d.ts +4 -1
  152. package/Table/components/index.js +3 -0
  153. package/Table/hooks/typings.d.ts +18 -4
  154. package/Table/hooks/useTableExpansion.d.ts +2 -2
  155. package/Table/hooks/useTableExpansion.js +5 -5
  156. package/Table/hooks/useTableFixedOffsets.d.ts +6 -2
  157. package/Table/hooks/useTableFixedOffsets.js +60 -26
  158. package/Table/hooks/useTableScroll.d.ts +9 -3
  159. package/Table/hooks/useTableScroll.js +34 -7
  160. package/Table/hooks/useTableVirtualization.d.ts +2 -1
  161. package/Table/hooks/useTableVirtualization.js +2 -8
  162. package/Table/index.d.ts +4 -3
  163. package/Table/index.js +3 -0
  164. package/Table/typings.d.ts +172 -0
  165. package/Table/utils/useTableRowSelection.js +13 -5
  166. package/Tag/TagGroup.d.ts +3 -0
  167. package/Tag/index.d.ts +2 -0
  168. package/Tag/index.js +1 -0
  169. package/Transition/Slide.d.ts +9 -2
  170. package/Transition/Slide.js +7 -4
  171. package/Tree/TreeNode.js +1 -1
  172. package/Upload/UploadPictureCard.js +1 -1
  173. package/index.d.ts +37 -21
  174. package/index.js +25 -11
  175. package/package.json +6 -4
  176. package/Modal/ModalActions.d.ts +0 -9
  177. package/Modal/ModalActions.js +0 -20
  178. package/Modal/ModalBody.d.ts +0 -7
  179. package/Modal/ModalBody.js +0 -14
  180. package/Notification/Notification.d.ts +0 -54
  181. package/Notification/Notification.js +0 -76
  182. package/Notification/index.d.ts +0 -3
  183. package/Notification/index.js +0 -1
  184. package/PageToolbar/PageToolbar.d.ts +0 -114
  185. package/PageToolbar/PageToolbar.js +0 -23
  186. package/PageToolbar/index.d.ts +0 -2
  187. package/PageToolbar/index.js +0 -1
  188. package/PageToolbar/utils.d.ts +0 -23
  189. package/PageToolbar/utils.js +0 -165
  190. package/Select/AutoComplete.d.ts +0 -107
  191. package/Select/AutoComplete.js +0 -114
  192. package/Table/components/TableDragHandleCell.d.ts +0 -11
  193. package/Table/components/TableDragHandleCell.js +0 -44
@@ -0,0 +1,31 @@
1
+ import { Dispatch, KeyboardEvent, KeyboardEventHandler, Ref, SetStateAction } from 'react';
2
+ import { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';
3
+ import { SelectValue } from '../Select/typings';
4
+ type UseAutoCompleteKeyboardParams = {
5
+ activeIndex: number | null;
6
+ addable: boolean;
7
+ createSeparators: string[];
8
+ dropdownOptions: DropdownOption[];
9
+ handleBulkCreate: (texts: string[]) => void;
10
+ handleDropdownSelect: (option: DropdownOption) => void;
11
+ inputRef?: Ref<HTMLInputElement>;
12
+ inputPropsOnKeyDown?: KeyboardEventHandler<HTMLInputElement>;
13
+ isMultiple: boolean;
14
+ mode: 'single' | 'multiple';
15
+ onFocus: (focus: boolean) => void;
16
+ open: boolean;
17
+ processBulkCreate: (text: string) => string[];
18
+ searchText: string;
19
+ searchTextExistWithoutOption: boolean;
20
+ setActiveIndex: Dispatch<SetStateAction<number | null>>;
21
+ setListboxHasVisualFocus: (focus: boolean) => void;
22
+ setInsertText: (value: string) => void;
23
+ setSearchText: (value: string) => void;
24
+ toggleOpen: (newOpen: boolean | ((prev: boolean) => boolean)) => void;
25
+ value: SelectValue[] | SelectValue | null | undefined;
26
+ wrappedOnChange: (chooseOption: SelectValue | null) => SelectValue[] | SelectValue | null;
27
+ };
28
+ export declare function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, toggleOpen, value, wrappedOnChange, }: UseAutoCompleteKeyboardParams): {
29
+ handleInputKeyDown: (e: KeyboardEvent<HTMLInputElement>) => void;
30
+ };
31
+ export {};
@@ -0,0 +1,149 @@
1
+ import { useCallback } from 'react';
2
+ import { createDropdownKeydownHandler } from '../Dropdown/dropdownKeydownHandler.js';
3
+
4
+ function isMultipleValue(value) {
5
+ return Array.isArray(value);
6
+ }
7
+ function useAutoCompleteKeyboard({ activeIndex, addable, createSeparators, dropdownOptions, handleBulkCreate, handleDropdownSelect, inputPropsOnKeyDown, inputRef, mode, onFocus, open, processBulkCreate, searchText, searchTextExistWithoutOption, setActiveIndex, setInsertText, setListboxHasVisualFocus, setSearchText, toggleOpen, value, wrappedOnChange, }) {
8
+ const handleKeyDown = useCallback((e) => createDropdownKeydownHandler({
9
+ activeIndex,
10
+ onEnterSelect: (option) => {
11
+ handleDropdownSelect(option);
12
+ if (mode === 'single') {
13
+ toggleOpen(false);
14
+ onFocus(false);
15
+ }
16
+ },
17
+ onEscape: () => {
18
+ var _a;
19
+ toggleOpen(false);
20
+ setActiveIndex(null);
21
+ setListboxHasVisualFocus(false);
22
+ if (inputRef && typeof inputRef !== 'function') {
23
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.blur();
24
+ }
25
+ },
26
+ open,
27
+ options: dropdownOptions,
28
+ setActiveIndex,
29
+ setListboxHasVisualFocus,
30
+ setOpen: (newOpen) => {
31
+ if (newOpen && !open) {
32
+ toggleOpen(true);
33
+ }
34
+ else if (!newOpen && open) {
35
+ toggleOpen(false);
36
+ }
37
+ },
38
+ })(e), [
39
+ activeIndex,
40
+ dropdownOptions,
41
+ handleDropdownSelect,
42
+ inputRef,
43
+ mode,
44
+ onFocus,
45
+ open,
46
+ setActiveIndex,
47
+ setListboxHasVisualFocus,
48
+ toggleOpen,
49
+ ]);
50
+ const handleEnterKey = useCallback((e) => {
51
+ if (e.key === 'Enter' && open) {
52
+ if (addable && searchText) {
53
+ const hasSeparator = createSeparators.some((sep) => searchText.includes(sep));
54
+ if (hasSeparator && mode === 'multiple') {
55
+ e.preventDefault();
56
+ e.stopPropagation();
57
+ const textsToCreate = processBulkCreate(searchText);
58
+ if (textsToCreate.length > 0) {
59
+ handleBulkCreate(textsToCreate);
60
+ setSearchText('');
61
+ setInsertText('');
62
+ return true;
63
+ }
64
+ }
65
+ if (!hasSeparator && searchTextExistWithoutOption) {
66
+ e.preventDefault();
67
+ e.stopPropagation();
68
+ const textsToCreate = processBulkCreate(searchText);
69
+ if (textsToCreate.length > 0) {
70
+ handleBulkCreate(textsToCreate);
71
+ setSearchText('');
72
+ setInsertText('');
73
+ }
74
+ return true;
75
+ }
76
+ }
77
+ if (activeIndex === null && dropdownOptions.length > 0) {
78
+ e.preventDefault();
79
+ e.stopPropagation();
80
+ const optionToSelect = dropdownOptions[0];
81
+ if (optionToSelect) {
82
+ handleDropdownSelect(optionToSelect);
83
+ if (mode === 'single') {
84
+ toggleOpen(false);
85
+ onFocus(false);
86
+ }
87
+ }
88
+ return true;
89
+ }
90
+ }
91
+ return false;
92
+ }, [
93
+ activeIndex,
94
+ addable,
95
+ createSeparators,
96
+ dropdownOptions,
97
+ handleBulkCreate,
98
+ handleDropdownSelect,
99
+ mode,
100
+ onFocus,
101
+ open,
102
+ processBulkCreate,
103
+ searchText,
104
+ searchTextExistWithoutOption,
105
+ setInsertText,
106
+ setSearchText,
107
+ toggleOpen,
108
+ ]);
109
+ const handleInputKeyDown = useCallback((e) => {
110
+ if (handleEnterKey(e))
111
+ return;
112
+ if (mode === 'multiple' &&
113
+ isMultipleValue(value) &&
114
+ value.length > 0 &&
115
+ !searchText) {
116
+ if (e.key === 'Backspace') {
117
+ e.preventDefault();
118
+ const lastValue = value[value.length - 1];
119
+ if (lastValue) {
120
+ wrappedOnChange(lastValue);
121
+ }
122
+ return;
123
+ }
124
+ if (e.key === 'Delete') {
125
+ e.preventDefault();
126
+ const firstValue = value[0];
127
+ if (firstValue) {
128
+ wrappedOnChange(firstValue);
129
+ }
130
+ return;
131
+ }
132
+ }
133
+ handleKeyDown(e);
134
+ inputPropsOnKeyDown === null || inputPropsOnKeyDown === void 0 ? void 0 : inputPropsOnKeyDown(e);
135
+ }, [
136
+ handleEnterKey,
137
+ handleKeyDown,
138
+ inputPropsOnKeyDown,
139
+ mode,
140
+ searchText,
141
+ value,
142
+ wrappedOnChange,
143
+ ]);
144
+ return {
145
+ handleInputKeyDown,
146
+ };
147
+ }
148
+
149
+ export { useAutoCompleteKeyboard };
@@ -0,0 +1,16 @@
1
+ type UseAutoCompleteSearchParams = {
2
+ asyncData: boolean;
3
+ loading: boolean;
4
+ onSearch?: (input: string) => void | Promise<void>;
5
+ searchDebounceTime: number;
6
+ };
7
+ type RunSearchOptions = {
8
+ immediate?: boolean;
9
+ };
10
+ export declare function useAutoCompleteSearch({ asyncData, loading, onSearch, searchDebounceTime, }: UseAutoCompleteSearchParams): {
11
+ cancelSearch: () => void;
12
+ internalLoading: boolean;
13
+ isLoading: boolean;
14
+ runSearch: (searchValue: string, options?: RunSearchOptions) => void;
15
+ };
16
+ export {};
@@ -0,0 +1,69 @@
1
+ import debounce from 'lodash/debounce';
2
+ import { useState, useRef, useCallback, useMemo, useEffect } from 'react';
3
+
4
+ function useAutoCompleteSearch({ asyncData, loading, onSearch, searchDebounceTime, }) {
5
+ const [internalLoading, setInternalLoading] = useState(false);
6
+ const requestSeqRef = useRef(0);
7
+ const executeSearch = useCallback((searchValue) => {
8
+ if (!onSearch) {
9
+ if (asyncData)
10
+ setInternalLoading(false);
11
+ return;
12
+ }
13
+ if (!asyncData) {
14
+ onSearch(searchValue);
15
+ return;
16
+ }
17
+ const currentSeq = requestSeqRef.current + 1;
18
+ requestSeqRef.current = currentSeq;
19
+ setInternalLoading(true);
20
+ try {
21
+ const result = onSearch(searchValue);
22
+ const finalize = () => {
23
+ if (requestSeqRef.current === currentSeq) {
24
+ setInternalLoading(false);
25
+ }
26
+ };
27
+ if (result instanceof Promise) {
28
+ result.finally(finalize);
29
+ }
30
+ else {
31
+ finalize();
32
+ }
33
+ }
34
+ catch (error) {
35
+ // Handle synchronous errors that occur before Promise creation
36
+ // Reset loading state to prevent UI from being stuck in loading state
37
+ if (requestSeqRef.current === currentSeq) {
38
+ setInternalLoading(false);
39
+ }
40
+ // Re-throw error to allow calling code to handle it
41
+ // This is necessary because the error occurred synchronously and the caller
42
+ // should be aware of it (e.g., for error logging or user notification)
43
+ throw error;
44
+ }
45
+ }, [asyncData, onSearch]);
46
+ const debouncedSearch = useMemo(() => debounce((value) => executeSearch(value), searchDebounceTime), [executeSearch, searchDebounceTime]);
47
+ useEffect(() => () => debouncedSearch.cancel(), [debouncedSearch]);
48
+ const runSearch = useCallback((searchValue, options) => {
49
+ if (options === null || options === void 0 ? void 0 : options.immediate) {
50
+ debouncedSearch.cancel();
51
+ executeSearch(searchValue);
52
+ return;
53
+ }
54
+ if (!searchValue) {
55
+ debouncedSearch.cancel();
56
+ executeSearch(searchValue);
57
+ return;
58
+ }
59
+ debouncedSearch(searchValue);
60
+ }, [debouncedSearch, executeSearch]);
61
+ return {
62
+ cancelSearch: debouncedSearch.cancel,
63
+ internalLoading,
64
+ isLoading: asyncData ? internalLoading || loading : loading,
65
+ runSearch,
66
+ };
67
+ }
68
+
69
+ export { useAutoCompleteSearch };
@@ -0,0 +1,17 @@
1
+ import { SelectValue } from '../Select/typings';
2
+ type CreationTracker = {
3
+ newlyCreatedIds: Set<string>;
4
+ unselectedCreatedIds: Set<string>;
5
+ allCreatedIds: Set<string>;
6
+ };
7
+ export declare function useCreationTracker(): {
8
+ creationTrackerRef: import("react").RefObject<CreationTracker>;
9
+ filterUnselected: (options: SelectValue[]) => SelectValue<string>[];
10
+ clearUnselected: () => void;
11
+ markCreated: (id: string) => void;
12
+ clearNewlyCreated: (ids?: string[]) => void;
13
+ markUnselected: (ids: string[]) => void;
14
+ isNewlyCreated: (id: string) => boolean;
15
+ isCreated: (id: string) => boolean;
16
+ };
17
+ export {};
@@ -0,0 +1,47 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ function useCreationTracker() {
4
+ const creationTrackerRef = useRef({
5
+ newlyCreatedIds: new Set(),
6
+ unselectedCreatedIds: new Set(),
7
+ allCreatedIds: new Set(),
8
+ });
9
+ const filterUnselected = useCallback((options) => options.filter((opt) => !creationTrackerRef.current.unselectedCreatedIds.has(opt.id)), [creationTrackerRef]);
10
+ const clearUnselected = useCallback(() => {
11
+ creationTrackerRef.current.unselectedCreatedIds.clear();
12
+ }, []);
13
+ const clearNewlyCreated = useCallback((ids) => {
14
+ if (!ids) {
15
+ creationTrackerRef.current.newlyCreatedIds.clear();
16
+ return;
17
+ }
18
+ ids.forEach((id) => {
19
+ creationTrackerRef.current.newlyCreatedIds.delete(id);
20
+ });
21
+ }, []);
22
+ const markCreated = useCallback((id) => {
23
+ creationTrackerRef.current.newlyCreatedIds.add(id);
24
+ creationTrackerRef.current.allCreatedIds.add(id);
25
+ }, []);
26
+ const markUnselected = useCallback((ids) => {
27
+ ids.forEach((id) => {
28
+ if (creationTrackerRef.current.allCreatedIds.has(id)) {
29
+ creationTrackerRef.current.unselectedCreatedIds.add(id);
30
+ }
31
+ });
32
+ }, []);
33
+ const isNewlyCreated = useCallback((id) => creationTrackerRef.current.newlyCreatedIds.has(id), []);
34
+ const isCreated = useCallback((id) => creationTrackerRef.current.allCreatedIds.has(id), []);
35
+ return {
36
+ creationTrackerRef,
37
+ filterUnselected,
38
+ clearUnselected,
39
+ markCreated,
40
+ clearNewlyCreated,
41
+ markUnselected,
42
+ isNewlyCreated,
43
+ isCreated,
44
+ };
45
+ }
46
+
47
+ export { useCreationTracker };
@@ -1,9 +1,10 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { forwardRef, isValidElement, cloneElement } from 'react';
3
- import { SlashIcon } from '@mezzanine-ui/icons';
4
3
  import { breadcrumbClasses } from '@mezzanine-ui/core/breadcrumb';
5
- import BreadcrumbItem from './BreadcrumbItem.js';
4
+ import { SlashIcon } from '@mezzanine-ui/icons';
6
5
  import { flattenChildren } from '../utils/flatten-children.js';
6
+ import BreadcrumbItem from './BreadcrumbItem.js';
7
+ import { BreadcrumbOverflowMenu } from './BreadcrumbOverflowMenu.js';
7
8
  import Icon from '../Icon/Icon.js';
8
9
  import cx from 'clsx';
9
10
 
@@ -13,32 +14,26 @@ const renderItemWithProps = (item, appendProps) => {
13
14
  }
14
15
  return jsx(BreadcrumbItem, { ...item, ...appendProps });
15
16
  };
17
+ const convertToPropsWithId = (item) => {
18
+ if (isValidElement(item)) {
19
+ return { id: item.props.id || item.props.name, ...item.props };
20
+ }
21
+ return { id: item.id || item.name, ...item };
22
+ };
16
23
  const renderItems = (items, condensed) => {
17
24
  if (!items) {
18
25
  return null;
19
26
  }
20
27
  const lastIndex = items.length - 1;
28
+ const hasOverflowDropdownIcon = !condensed || items.length > 2;
29
+ const collapsedProps = hasOverflowDropdownIcon
30
+ ? condensed
31
+ ? items.map((v) => convertToPropsWithId(v)).slice(0, lastIndex - 1)
32
+ : items.map((v) => convertToPropsWithId(v)).slice(2, lastIndex - 1)
33
+ : [];
21
34
  return (jsxs(Fragment, { children: [!condensed &&
22
35
  lastIndex >= 0 &&
23
- renderItemWithProps(items[0], { current: lastIndex === 0 }), !condensed && lastIndex >= 1 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[1], { current: lastIndex === 1 })] })), !condensed && items.length <= 4 && (jsxs(Fragment, { children: [lastIndex >= 2 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[2], { current: lastIndex === 2 })] })), lastIndex === 3 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[3], { current: true })] }))] })), (items.length > 4 || condensed) && (jsxs(Fragment, { children: [!condensed && jsx(Icon, { icon: SlashIcon, size: 14 }), (!condensed || items.length > 2) && (jsxs(Fragment, { children: [jsx(BreadcrumbItem, { options: (condensed
24
- ? items.slice(0, lastIndex - 1)
25
- : items.slice(2, lastIndex - 1)).map((item) => {
26
- if (isValidElement(item)) {
27
- const { props } = item;
28
- return {
29
- label: props.label,
30
- href: props.href,
31
- target: props.target,
32
- id: props.id,
33
- };
34
- }
35
- return {
36
- label: item.label,
37
- href: item.href,
38
- target: item.target,
39
- id: item.id,
40
- };
41
- }) }), jsx(Icon, { icon: SlashIcon, size: 14 })] })), lastIndex - 1 >= 0 && (jsxs(Fragment, { children: [renderItemWithProps(items[lastIndex - 1]), jsx(Icon, { icon: SlashIcon, size: 14 })] })), renderItemWithProps(items[lastIndex], { current: true })] }))] }));
36
+ renderItemWithProps(items[0], { current: lastIndex === 0 }), !condensed && lastIndex >= 1 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[1], { current: lastIndex === 1 })] })), !condensed && items.length <= 4 && (jsxs(Fragment, { children: [lastIndex >= 2 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[2], { current: lastIndex === 2 })] })), lastIndex === 3 && (jsxs(Fragment, { children: [jsx(Icon, { icon: SlashIcon, size: 14 }), renderItemWithProps(items[3], { current: true })] }))] })), (items.length > 4 || condensed) && (jsxs(Fragment, { children: [!condensed && jsx(Icon, { icon: SlashIcon, size: 14 }), hasOverflowDropdownIcon && (jsxs(Fragment, { children: [jsx(BreadcrumbOverflowMenu, { collapsedProps: collapsedProps }), jsx(Icon, { icon: SlashIcon, size: 14 })] })), lastIndex - 1 >= 0 && (jsxs(Fragment, { children: [renderItemWithProps(items[lastIndex - 1]), jsx(Icon, { icon: SlashIcon, size: 14 })] })), renderItemWithProps(items[lastIndex], { current: true })] }))] }));
42
37
  };
43
38
  /**
44
39
  * The react component for `mezzanine` breadcrumb.
@@ -0,0 +1,11 @@
1
+ declare const BreadcrumbDropdown: import("react").ForwardRefExoticComponent<Omit<import("../Dropdown").DropdownProps, "children"> & {
2
+ className?: string;
3
+ current?: boolean;
4
+ href?: never;
5
+ id?: string;
6
+ name: string;
7
+ onClick?: () => void;
8
+ open?: boolean;
9
+ target?: never;
10
+ } & import("react").RefAttributes<HTMLSpanElement>>;
11
+ export default BreadcrumbDropdown;
@@ -0,0 +1,22 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { forwardRef, useState } from 'react';
3
+ import { ChevronDownIcon } from '@mezzanine-ui/icons';
4
+ import { breadcrumbItemClasses } from '@mezzanine-ui/core/breadcrumb';
5
+ import Typography from '../Typography/Typography.js';
6
+ import Dropdown from '../Dropdown/Dropdown.js';
7
+ import Rotate from '../Transition/Rotate.js';
8
+ import Icon from '../Icon/Icon.js';
9
+ import cx from 'clsx';
10
+
11
+ const BreadcrumbDropdown = forwardRef(function BreadcrumbDropdown(props, ref) {
12
+ const { className, current, name, onClick, open: openProp, options, ...rest } = props;
13
+ const [_open, setOpen] = useState(false);
14
+ const open = openProp !== null && openProp !== void 0 ? openProp : _open;
15
+ const handleClick = () => {
16
+ setOpen(!open);
17
+ onClick === null || onClick === void 0 ? void 0 : onClick();
18
+ };
19
+ return (jsx("span", { className: cx(breadcrumbItemClasses.host, className), ref: ref, children: jsx(Dropdown, { onClose: () => setOpen(false), onOpen: () => handleClick(), options: options, placement: "bottom-start", ...rest, children: jsxs("button", { className: cx(breadcrumbItemClasses.trigger, open && breadcrumbItemClasses.expanded, current && breadcrumbItemClasses.current), type: "button", children: [name && (jsx(Typography, { variant: current ? 'caption-highlight' : 'caption', children: name })), jsx(Rotate, { in: open, children: jsx(Icon, { className: breadcrumbItemClasses.icon, icon: ChevronDownIcon, size: 14 }) })] }) }) }));
20
+ });
21
+
22
+ export { BreadcrumbDropdown as default };
@@ -1,4 +1,3 @@
1
- declare const BreadcrumbItem: import("react").ForwardRefExoticComponent<Omit<Omit<import("..").ComponentPropsWithoutKeyAndRef<"button">, "expand" | "label" | "component" | "current" | "options" | "href" | "target"> & (import("./typings").BreadcrumbDropdownItemProps | import("./typings").BreadcrumbItemTextProps | import("./typings").BreadcrumbLinkItemProps), "component"> & {
2
- component?: import("./typings").BreadcrumbItemComponent | undefined;
3
- } & import("react").RefAttributes<HTMLElement>>;
1
+ import type { BreadcrumbItemProps } from './typings';
2
+ declare const BreadcrumbItem: import("react").ForwardRefExoticComponent<BreadcrumbItemProps & import("react").RefAttributes<HTMLSpanElement>>;
4
3
  export default BreadcrumbItem;
@@ -1,45 +1,27 @@
1
- import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { forwardRef, useState } from 'react';
3
- import { ChevronDownIcon, DotHorizontalIcon } from '@mezzanine-ui/icons';
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { forwardRef } from 'react';
4
3
  import { breadcrumbItemClasses } from '@mezzanine-ui/core/breadcrumb';
5
4
  import Typography from '../Typography/Typography.js';
6
- import Rotate from '../Transition/Rotate.js';
7
- import Icon from '../Icon/Icon.js';
8
- import Menu from '../Menu/Menu.js';
9
- import MenuItem from '../Menu/MenuItem.js';
5
+ import BreadcrumbDropdown from './BreadcrumbDropdown.js';
10
6
  import cx from 'clsx';
11
7
 
12
8
  const BreadcrumbItem = forwardRef(function BreadcrumbItem(props, ref) {
13
- const { className, component, current, expand: expandProp, label, onClick, onTouchEnd, options, ...rest } = props;
14
- const [_expand, setExpand] = useState(false);
15
- const expand = expandProp !== null && expandProp !== void 0 ? expandProp : _expand;
16
- const Component = (() => {
9
+ if ('options' in props)
10
+ return jsx(BreadcrumbDropdown, { ...props });
11
+ const { className, component, current, href, name, onClick, rel, target, ...rest } = props;
12
+ const TriggerComponent = (() => {
17
13
  if (component)
18
14
  return component;
19
- if ('onClick' in props || 'options' in props) {
20
- return 'button';
21
- }
22
- if (!current && 'href' in props && typeof props.href === 'string') {
15
+ if ((!current && 'href' in props && typeof props.href === 'string') ||
16
+ 'onClick' in props) {
23
17
  return 'a';
24
18
  }
25
- return 'div';
19
+ return 'span';
26
20
  })();
27
- const handleClick = (e) => {
28
- setExpand(!expand);
29
- onClick === null || onClick === void 0 ? void 0 : onClick(e);
30
- };
31
- const handleTouchEnd = (e) => {
32
- setExpand(!expand);
33
- onTouchEnd === null || onTouchEnd === void 0 ? void 0 : onTouchEnd(e);
21
+ const handleClick = () => {
22
+ onClick === null || onClick === void 0 ? void 0 : onClick();
34
23
  };
35
- return (jsxs(Component, { ...rest, "aria-expanded": options ? expand : undefined, "aria-haspopup": options ? 'true' : undefined, className: cx(breadcrumbItemClasses.host, expand && breadcrumbItemClasses.expanded, current && breadcrumbItemClasses.current, className), onClick: Component === 'button' ? handleClick : undefined, onTouchEnd: Component === 'button' ? handleTouchEnd : undefined, ref: ref, children: [label && (jsx(Typography, { variant: current ? 'caption-highlight' : 'caption', children: label })), 'options' in props &&
36
- (label ? (
37
- /* normal dropdown icon item */
38
- jsx(Rotate, { in: expand, children: jsx(Icon, { className: breadcrumbItemClasses.icon, icon: ChevronDownIcon, size: 14 }) })) : (
39
- /* overflow dropdown icon item */
40
- jsx(Icon, { className: breadcrumbItemClasses.icon, icon: DotHorizontalIcon, size: 14 }))), options && expand && (jsx(Menu, { className: breadcrumbItemClasses.menu, children: options
41
- .filter((v) => v.label)
42
- .map((option) => (jsx(MenuItem, { children: option.label }, option.id || option.label))) }))] }));
24
+ return (jsx("span", { ...rest, className: cx(breadcrumbItemClasses.host, className), ref: ref, children: jsx(TriggerComponent, { className: cx(breadcrumbItemClasses.trigger, current && breadcrumbItemClasses.current), href: TriggerComponent === 'a' ? href : undefined, onClick: TriggerComponent === 'a' ? handleClick : undefined, rel: TriggerComponent === 'a' ? rel : undefined, target: TriggerComponent === 'a' ? target : undefined, children: name && (jsx(Typography, { variant: current ? 'caption-highlight' : 'caption', children: name })) }) }));
43
25
  });
44
26
 
45
27
  export { BreadcrumbItem as default };
@@ -0,0 +1,7 @@
1
+ import { HtmlHTMLAttributes } from 'react';
2
+ import { BreadcrumbItemProps } from './typings';
3
+ export declare const BreadcrumbOverflowMenu: (props: HtmlHTMLAttributes<HTMLButtonElement> & {
4
+ collapsedProps: (BreadcrumbItemProps & {
5
+ id: string;
6
+ })[];
7
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,77 @@
1
+ 'use client';
2
+ import { useState, useRef, useMemo, useCallback, createElement } from 'react';
3
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
4
+ import { TransitionGroup } from 'react-transition-group';
5
+ import { breadcrumbClasses } from '@mezzanine-ui/core/breadcrumb';
6
+ import { DotHorizontalIcon } from '@mezzanine-ui/icons';
7
+ import { MOTION_EASING, MOTION_DURATION } from '@mezzanine-ui/system/motion';
8
+ import { useDocumentEvents } from '../hooks/useDocumentEvents.js';
9
+ import BreadcrumbOverflowMenuItem from './BreadcrumbOverflowMenuItem.js';
10
+ import Icon from '../Icon/Icon.js';
11
+ import Popper from '../Popper/Popper.js';
12
+ import Translate from '../Transition/Translate.js';
13
+ import cx from 'clsx';
14
+
15
+ const BreadcrumbOverflowMenu = (props) => {
16
+ const { onClick, className, collapsedProps, ...rest } = props;
17
+ const [menuOpen, setMenuOpen] = useState(false);
18
+ const targetRef = useRef(null);
19
+ const popperRef = useRef(null);
20
+ const translateProps = useMemo(() => ({
21
+ duration: {
22
+ enter: MOTION_DURATION.moderate,
23
+ exit: MOTION_DURATION.moderate,
24
+ },
25
+ easing: {
26
+ enter: MOTION_EASING.standard,
27
+ exit: MOTION_EASING.standard,
28
+ },
29
+ }), []);
30
+ useDocumentEvents(() => {
31
+ if (!menuOpen) {
32
+ return;
33
+ }
34
+ const handleClickAway = (event) => {
35
+ const target = event.target;
36
+ const anchor = targetRef.current;
37
+ const popper = popperRef.current;
38
+ if (!target)
39
+ return;
40
+ if (anchor &&
41
+ popper &&
42
+ !anchor.contains(target) &&
43
+ !popper.contains(target)) {
44
+ setMenuOpen(false);
45
+ }
46
+ };
47
+ return {
48
+ click: handleClickAway,
49
+ touchend: handleClickAway,
50
+ };
51
+ }, [menuOpen]);
52
+ const zIndexMiddleware = useMemo(() => {
53
+ const zIndexValue = 1;
54
+ return {
55
+ name: 'zIndex',
56
+ fn: ({ elements }) => {
57
+ const zIndexNum = zIndexValue
58
+ ;
59
+ Object.assign(elements.floating.style, {
60
+ zIndex: zIndexNum,
61
+ });
62
+ return {};
63
+ },
64
+ };
65
+ }, []);
66
+ const buttonOnClick = useCallback((e) => {
67
+ setMenuOpen(!menuOpen);
68
+ onClick === null || onClick === void 0 ? void 0 : onClick(e);
69
+ }, [menuOpen, onClick]);
70
+ return (jsxs(Fragment, { children: [jsx("button", { "aria-label": 'more options', type: "button", ...rest, ref: targetRef, className: cx(breadcrumbClasses.iconButton, className), onClick: buttonOnClick, children: jsx(Icon, { icon: DotHorizontalIcon, size: 14 }) }), jsx(Popper, { anchor: targetRef.current, disablePortal: true, open: menuOpen, options: {
71
+ middleware: [zIndexMiddleware],
72
+ placement: 'bottom-start',
73
+ }, ref: popperRef, children: jsx(TransitionGroup, { component: null, children: menuOpen && (createElement(Translate, { ...translateProps, from: 'bottom', in: true, key: "popper-list" },
74
+ jsx("span", { className: breadcrumbClasses.menu, children: jsx("span", { className: breadcrumbClasses.menuContent, children: collapsedProps.map((v) => (jsx(BreadcrumbOverflowMenuItem, { ...v }, v.id))) }) }))) }) })] }));
75
+ };
76
+
77
+ export { BreadcrumbOverflowMenu };
@@ -0,0 +1,11 @@
1
+ declare const BreadcrumbOverflowMenuDropdown: import("react").ForwardRefExoticComponent<Omit<import("../Dropdown").DropdownProps, "children"> & {
2
+ className?: string;
3
+ current?: boolean;
4
+ href?: never;
5
+ id?: string;
6
+ name: string;
7
+ onClick?: () => void;
8
+ open?: boolean;
9
+ target?: never;
10
+ } & import("react").RefAttributes<HTMLSpanElement>>;
11
+ export default BreadcrumbOverflowMenuDropdown;
@@ -0,0 +1,21 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { forwardRef, useState } from 'react';
3
+ import { breadcrumbOverflowMenuItemClasses } from '@mezzanine-ui/core/breadcrumb';
4
+ import { ChevronRightIcon } from '@mezzanine-ui/icons';
5
+ import Typography from '../Typography/Typography.js';
6
+ import Dropdown from '../Dropdown/Dropdown.js';
7
+ import Icon from '../Icon/Icon.js';
8
+ import cx from 'clsx';
9
+
10
+ const BreadcrumbOverflowMenuDropdown = forwardRef(function BreadcrumbOverflowMenuDropdown(props, ref) {
11
+ const { className, name, onClick, open: openProp, options, ...rest } = props;
12
+ const [_open, setOpen] = useState(false);
13
+ const open = openProp !== null && openProp !== void 0 ? openProp : _open;
14
+ const handleClick = () => {
15
+ setOpen(!open);
16
+ onClick === null || onClick === void 0 ? void 0 : onClick();
17
+ };
18
+ return (jsx("span", { className: cx(breadcrumbOverflowMenuItemClasses.host, open && breadcrumbOverflowMenuItemClasses.expanded, className), ref: ref, children: jsx(Dropdown, { onClose: () => setOpen(false), onOpen: () => handleClick(), options: options, placement: "right-start", ...rest, children: jsxs("button", { className: cx(breadcrumbOverflowMenuItemClasses.trigger), type: "button", children: [jsx(Typography, { variant: 'label-primary', children: name }), jsx(Icon, { className: breadcrumbOverflowMenuItemClasses.icon, icon: ChevronRightIcon, size: 16 })] }) }) }));
19
+ });
20
+
21
+ export { BreadcrumbOverflowMenuDropdown as default };
@@ -0,0 +1,3 @@
1
+ import type { BreadcrumbItemProps } from './typings';
2
+ declare const BreadcrumbOverflowMenuItem: import("react").ForwardRefExoticComponent<BreadcrumbItemProps & import("react").RefAttributes<HTMLSpanElement>>;
3
+ export default BreadcrumbOverflowMenuItem;