@pushwoosh/dumb-components 4.6.0 → 4.7.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 (35) hide show
  1. package/Calendar/CalendarDropdown/CalendarDropdown.js +9 -4
  2. package/Calendar/CalendarSuperForm/components/CalendarRangePicker/CalendarRangePicker.js +5 -6
  3. package/Modal/components/ModalName/ModalName.d.ts +4 -0
  4. package/Modal/components/ModalName/ModalName.js +151 -0
  5. package/Modal/components/ModalName/index.d.ts +2 -0
  6. package/Modal/components/ModalName/index.js +1 -0
  7. package/Modal/components/ModalName/types.d.ts +39 -0
  8. package/Modal/components/ModalName/types.js +1 -0
  9. package/Modal/index.d.ts +1 -0
  10. package/Modal/index.js +1 -0
  11. package/Modal/polyglot/messages_ar.js +1 -0
  12. package/Modal/polyglot/messages_bn.js +1 -0
  13. package/Modal/polyglot/messages_de.js +1 -0
  14. package/Modal/polyglot/messages_en.js +1 -0
  15. package/Modal/polyglot/messages_es.js +1 -0
  16. package/Modal/polyglot/messages_fr.js +1 -0
  17. package/Modal/polyglot/messages_he.js +1 -0
  18. package/Modal/polyglot/messages_hi.js +1 -0
  19. package/Modal/polyglot/messages_ja.js +1 -0
  20. package/Modal/polyglot/messages_ko.js +1 -0
  21. package/Modal/polyglot/messages_pt.js +1 -0
  22. package/Modal/polyglot/messages_ru.js +1 -0
  23. package/Modal/polyglot/messages_th.js +1 -0
  24. package/Modal/polyglot/messages_zh.js +1 -0
  25. package/Modal/polyglot/types.d.ts +1 -0
  26. package/PageHeader/components/Rename/Rename.d.ts +1 -1
  27. package/PageHeader/components/Rename/Rename.js +1 -1
  28. package/hooks/useLayer.js +4 -2
  29. package/hooks/useThemeName.js +1 -1
  30. package/index.d.ts +1 -1
  31. package/index.js +1 -1
  32. package/native/Input.js +3 -1
  33. package/package.json +2 -2
  34. package/shared/dropdownField/useAsyncItems.js +4 -2
  35. package/shared/dropdownField/useFieldOpenEffects.js +3 -4
@@ -66,7 +66,12 @@ export const CalendarDropdown = props => {
66
66
  setIsOpen(true);
67
67
  };
68
68
  const {
69
- refs,
69
+ refs: {
70
+ reference,
71
+ floating,
72
+ setReference,
73
+ setFloating
74
+ },
70
75
  floatingStyles
71
76
  } = useFloating({
72
77
  open: isOpen,
@@ -84,7 +89,7 @@ export const CalendarDropdown = props => {
84
89
  isOpen,
85
90
  onClose: closePopover
86
91
  });
87
- useOnClickOutside([refs.reference, refs.floating], () => {
92
+ useOnClickOutside([reference, floating], () => {
88
93
  if (isOpen) closePopover();
89
94
  });
90
95
  const onChangeHandler = val => {
@@ -106,7 +111,7 @@ export const CalendarDropdown = props => {
106
111
  return _jsxs(Horizontal, {
107
112
  "$justifyContent": "start",
108
113
  children: [_jsx(Button, {
109
- boxRef: refs.setReference,
114
+ boxRef: setReference,
110
115
  type: "button",
111
116
  view: buttonView,
112
117
  size: buttonSize,
@@ -119,7 +124,7 @@ export const CalendarDropdown = props => {
119
124
  isOpen: isOpen,
120
125
  children: buttonTextCustom ?? buttonText
121
126
  }), isOpen && createPortal(_jsx(PopoverContent, {
122
- ref: refs.setFloating,
127
+ ref: setFloating,
123
128
  style: {
124
129
  ...floatingStyles,
125
130
  zIndex
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRef } from 'react';
2
+ import { useState } from 'react';
3
3
  import { getDisabledRanges } from './getDisabledRanges';
4
4
  import { CalendarMonthSlider } from '../../../CalendarMonthSlider/CalendarMonthSlider';
5
5
  import { compareStructs } from '../../../helpers';
@@ -18,17 +18,16 @@ export const CalendarRangePicker = ({
18
18
  firstDayOfWeek,
19
19
  initialVisibleMonth
20
20
  }) => {
21
- const startMonthRef = useRef(undefined);
22
- if (!startMonthRef.current) {
21
+ const [startMonth] = useState(() => {
23
22
  const d = new Date();
24
- startMonthRef.current = initialVisibleMonth ?? value[0] ?? {
23
+ return initialVisibleMonth ?? value[0] ?? {
25
24
  year: d.getFullYear(),
26
25
  month: d.getMonth() + 1,
27
26
  day: d.getDate()
28
27
  };
29
- }
28
+ });
30
29
  return _jsx(CalendarMonthSlider, {
31
- startMonth: startMonthRef.current,
30
+ startMonth: startMonth,
32
31
  visibleCount: visibleCount,
33
32
  monthWidth: monthWidth,
34
33
  gap: gap,
@@ -0,0 +1,4 @@
1
+ import { type ReactElement } from 'react';
2
+ import type { ModalNameProps } from './types';
3
+ /** Asks for an entity name on save, rename or with a suggestion; warnings and errors go under the field. */
4
+ export declare function ModalName({ isOpen, ...props }: ModalNameProps): ReactElement | null;
@@ -0,0 +1,151 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { Horizontal, Vertical } from '@pushwoosh/kit-helpers';
4
+ import { Paragraph } from '@pushwoosh/kit-typography';
5
+ import { Banner } from '../../../Banner';
6
+ import { Button } from '../../../Button';
7
+ import { FieldBox } from '../../../FieldBox';
8
+ import { NativeInput } from '../../../native';
9
+ import { useLang } from '../../polyglot';
10
+ import { Modal } from '../Modal';
11
+ import { ModalBody, ModalFooter, ModalHeader } from '../ModalContent';
12
+ import { ModalTitle } from '../ModalTitle';
13
+ function ModalNameDialog(props) {
14
+ const {
15
+ title,
16
+ description,
17
+ label,
18
+ placeholder,
19
+ initialName = '',
20
+ suggestedName,
21
+ initialWarning,
22
+ initialError,
23
+ maxLength,
24
+ submitText,
25
+ cancelText,
26
+ onSubmit,
27
+ onClose
28
+ } = props;
29
+ const lang = useLang();
30
+ const inputRef = useRef(null);
31
+ const [name, setName] = useState(suggestedName ?? initialName);
32
+ const [isEmptyError, setIsEmptyError] = useState(false);
33
+ const [error, setError] = useState(initialError);
34
+ const [warning, setWarning] = useState(initialWarning ? {
35
+ name: initialName.trim(),
36
+ content: initialWarning
37
+ } : undefined);
38
+ const [isSaving, setIsSaving] = useState(false);
39
+ const trimmedName = name.trim();
40
+ useEffect(() => {
41
+ const frame = requestAnimationFrame(() => inputRef.current?.select());
42
+ return () => cancelAnimationFrame(frame);
43
+ }, []);
44
+ const close = () => {
45
+ if (!isSaving) {
46
+ onClose();
47
+ }
48
+ };
49
+ const submit = async event => {
50
+ event.preventDefault();
51
+ if (isSaving) {
52
+ return;
53
+ }
54
+ if (!trimmedName) {
55
+ setIsEmptyError(true);
56
+ inputRef.current?.focus();
57
+ return;
58
+ }
59
+ if (!warning && !error && trimmedName === initialName.trim()) {
60
+ onClose();
61
+ return;
62
+ }
63
+ setIsSaving(true);
64
+ setError(undefined);
65
+ try {
66
+ const result = await onSubmit(trimmedName);
67
+ setWarning(result?.warning ? {
68
+ name: trimmedName,
69
+ content: result.warning
70
+ } : undefined);
71
+ setError(result?.error);
72
+ } catch (e) {
73
+ setWarning(undefined);
74
+ setError(e?.message || lang({
75
+ message: 'DUMB.MODAL.UNEXPECTED_ERROR'
76
+ }));
77
+ } finally {
78
+ setIsSaving(false);
79
+ requestAnimationFrame(() => inputRef.current?.focus());
80
+ }
81
+ };
82
+ return _jsx(Modal, {
83
+ size: "small",
84
+ isOpen: true,
85
+ onClose: close,
86
+ children: _jsxs("form", {
87
+ onSubmit: submit,
88
+ children: [_jsx(ModalHeader, {
89
+ children: _jsx(ModalTitle, {
90
+ children: title
91
+ })
92
+ }), _jsx(ModalBody, {
93
+ children: _jsxs(Vertical, {
94
+ "$gap": 16,
95
+ children: [description && _jsx(Paragraph, {
96
+ children: description
97
+ }), _jsx(FieldBox, {
98
+ title: label,
99
+ error: error,
100
+ children: _jsx(NativeInput, {
101
+ ref: inputRef,
102
+ type: "text",
103
+ value: name,
104
+ placeholder: placeholder,
105
+ maxLength: maxLength,
106
+ disabled: isSaving,
107
+ "$isErrored": isEmptyError || !!error,
108
+ "aria-invalid": isEmptyError || !!error,
109
+ onChange: event => {
110
+ setName(event.target.value);
111
+ setIsEmptyError(false);
112
+ }
113
+ })
114
+ }), warning && warning.name === trimmedName && _jsx(Banner, {
115
+ type: "warning",
116
+ title: warning.content
117
+ })]
118
+ })
119
+ }), _jsx(ModalFooter, {
120
+ children: _jsxs(Horizontal, {
121
+ "$justifyContent": "end",
122
+ "$gap": 8,
123
+ children: [_jsx(Button, {
124
+ color: "secondary",
125
+ isDisabled: isSaving,
126
+ onClick: close,
127
+ children: cancelText ?? lang({
128
+ message: 'DUMB.MODAL.CANCEL'
129
+ })
130
+ }), _jsx(Button, {
131
+ color: "primary",
132
+ type: "submit",
133
+ isLoading: isSaving,
134
+ children: submitText ?? lang({
135
+ message: 'DUMB.MODAL.SAVE'
136
+ })
137
+ })]
138
+ })
139
+ })]
140
+ })
141
+ });
142
+ }
143
+ /** Asks for an entity name on save, rename or with a suggestion; warnings and errors go under the field. */
144
+ export function ModalName({
145
+ isOpen,
146
+ ...props
147
+ }) {
148
+ return isOpen ? _jsx(ModalNameDialog, {
149
+ ...props
150
+ }) : null;
151
+ }
@@ -0,0 +1,2 @@
1
+ export { ModalName } from './ModalName';
2
+ export type { ModalNameProps, ModalNameResult } from './types';
@@ -0,0 +1 @@
1
+ export { ModalName } from './ModalName';
@@ -0,0 +1,39 @@
1
+ import type { ReactNode } from 'react';
2
+ /** What {@link ModalNameProps.onSubmit} reports back; nothing means the name was saved. */
3
+ export type ModalNameResult = void | {
4
+ /** Keeps the dialog open with an orange banner under the field, e.g. "name already taken". */
5
+ warning?: string;
6
+ /** Keeps the dialog open with the message under the field. */
7
+ error?: string;
8
+ };
9
+ /** Props of {@link ModalName}. */
10
+ export interface ModalNameProps {
11
+ /** Whether the dialog is open; every opening starts from `initialName`. */
12
+ isOpen: boolean;
13
+ /** Heading, e.g. "Save the segment". */
14
+ title: string;
15
+ /** Hint above the field. */
16
+ description?: ReactNode;
17
+ /** Caption of the field. */
18
+ label: string;
19
+ /** Example name ending with an ellipsis, e.g. "Active buyers in Germany…". */
20
+ placeholder?: string;
21
+ /** Value the field opens with, e.g. the current name when renaming; Save without changes just closes. */
22
+ initialName?: string;
23
+ /** Name proposed by the screen, e.g. the push title; the field opens with it selected and Save saves it as is. */
24
+ suggestedName?: string;
25
+ /** Banner shown on opening while the field still holds `initialName`. */
26
+ initialWarning?: string;
27
+ /** Error shown under the field on opening, e.g. the name typed in the header is too long. */
28
+ initialError?: string;
29
+ /** Field length limit. */
30
+ maxLength?: number;
31
+ /** Save button caption (defaults to localized "Save"). */
32
+ submitText?: string;
33
+ /** Cancel button caption (defaults to localized "Cancel"). */
34
+ cancelText?: string;
35
+ /** Called with the trimmed non-empty name; a throw is shown as an error. */
36
+ onSubmit: (name: string) => ModalNameResult | Promise<ModalNameResult>;
37
+ /** Called on Cancel or Escape. */
38
+ onClose: () => void;
39
+ }
@@ -0,0 +1 @@
1
+ export {};
package/Modal/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { Modal } from './components/Modal';
2
2
  export { ModalTitle } from './components/ModalTitle';
3
+ export { ModalName, type ModalNameProps, type ModalNameResult } from './components/ModalName';
3
4
  export { ModalConfirm, ModalConfirmProvider, useModalConfirm, } from './components/ModalConfirm';
4
5
  export { ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter, } from './components/ModalContent';
package/Modal/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { Modal } from './components/Modal';
2
2
  export { ModalTitle } from './components/ModalTitle';
3
+ export { ModalName } from './components/ModalName';
3
4
  export { ModalConfirm, ModalConfirmProvider, useModalConfirm } from './components/ModalConfirm';
4
5
  export { ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter } from './components/ModalContent';
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'تأكيد الإجراء',
4
4
  'DUMB.MODAL.CONFIRM': 'تأكيد',
5
5
  'DUMB.MODAL.CANCEL': 'إلغاء',
6
+ 'DUMB.MODAL.SAVE': 'حفظ',
6
7
  'DUMB.MODAL.CLOSE': 'إغلاق'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'ক্রিয়াটি নিশ্চিত করুন',
4
4
  'DUMB.MODAL.CONFIRM': 'নিশ্চিত করুন',
5
5
  'DUMB.MODAL.CANCEL': 'বাতিল করুন',
6
+ 'DUMB.MODAL.SAVE': 'সংরক্ষণ করুন',
6
7
  'DUMB.MODAL.CLOSE': 'বন্ধ করুন'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Aktion bestätigen',
4
4
  'DUMB.MODAL.CONFIRM': 'Bestätigen',
5
5
  'DUMB.MODAL.CANCEL': 'Abbrechen',
6
+ 'DUMB.MODAL.SAVE': 'Speichern',
6
7
  'DUMB.MODAL.CLOSE': 'Schließen'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Confirm action',
4
4
  'DUMB.MODAL.CONFIRM': 'Confirm',
5
5
  'DUMB.MODAL.CANCEL': 'Cancel',
6
+ 'DUMB.MODAL.SAVE': 'Save',
6
7
  'DUMB.MODAL.CLOSE': 'Close'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Confirmar acción',
4
4
  'DUMB.MODAL.CONFIRM': 'Confirmar',
5
5
  'DUMB.MODAL.CANCEL': 'Cancelar',
6
+ 'DUMB.MODAL.SAVE': 'Guardar',
6
7
  'DUMB.MODAL.CLOSE': 'Cerrar'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Confirmer l’action',
4
4
  'DUMB.MODAL.CONFIRM': 'Confirmer',
5
5
  'DUMB.MODAL.CANCEL': 'Annuler',
6
+ 'DUMB.MODAL.SAVE': 'Enregistrer',
6
7
  'DUMB.MODAL.CLOSE': 'Fermer'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'אישור פעולה',
4
4
  'DUMB.MODAL.CONFIRM': 'אישור',
5
5
  'DUMB.MODAL.CANCEL': 'ביטול',
6
+ 'DUMB.MODAL.SAVE': 'שמירה',
6
7
  'DUMB.MODAL.CLOSE': 'סגירה'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'कार्रवाई की पुष्टि करें',
4
4
  'DUMB.MODAL.CONFIRM': 'पुष्टि करें',
5
5
  'DUMB.MODAL.CANCEL': 'रद्द करें',
6
+ 'DUMB.MODAL.SAVE': 'सहेजें',
6
7
  'DUMB.MODAL.CLOSE': 'बंद करें'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': '操作の確認',
4
4
  'DUMB.MODAL.CONFIRM': '確認',
5
5
  'DUMB.MODAL.CANCEL': 'キャンセル',
6
+ 'DUMB.MODAL.SAVE': '保存',
6
7
  'DUMB.MODAL.CLOSE': '閉じる'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': '작업 확인',
4
4
  'DUMB.MODAL.CONFIRM': '확인',
5
5
  'DUMB.MODAL.CANCEL': '취소',
6
+ 'DUMB.MODAL.SAVE': '저장',
6
7
  'DUMB.MODAL.CLOSE': '닫기'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Confirmar ação',
4
4
  'DUMB.MODAL.CONFIRM': 'Confirmar',
5
5
  'DUMB.MODAL.CANCEL': 'Cancelar',
6
+ 'DUMB.MODAL.SAVE': 'Salvar',
6
7
  'DUMB.MODAL.CLOSE': 'Fechar'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'Подтвердите действие',
4
4
  'DUMB.MODAL.CONFIRM': 'Подтвердить',
5
5
  'DUMB.MODAL.CANCEL': 'Отмена',
6
+ 'DUMB.MODAL.SAVE': 'Сохранить',
6
7
  'DUMB.MODAL.CLOSE': 'Закрыть'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': 'ยืนยันการดำเนินการ',
4
4
  'DUMB.MODAL.CONFIRM': 'ยืนยัน',
5
5
  'DUMB.MODAL.CANCEL': 'ยกเลิก',
6
+ 'DUMB.MODAL.SAVE': 'บันทึก',
6
7
  'DUMB.MODAL.CLOSE': 'ปิด'
7
8
  };
@@ -3,5 +3,6 @@ export const messages = {
3
3
  'DUMB.MODAL.CONFIRM_TITLE': '确认操作',
4
4
  'DUMB.MODAL.CONFIRM': '确认',
5
5
  'DUMB.MODAL.CANCEL': '取消',
6
+ 'DUMB.MODAL.SAVE': '保存',
6
7
  'DUMB.MODAL.CLOSE': '关闭'
7
8
  };
@@ -4,5 +4,6 @@ export type ModalMessages = {
4
4
  'DUMB.MODAL.CONFIRM_TITLE': NoParams;
5
5
  'DUMB.MODAL.CONFIRM': NoParams;
6
6
  'DUMB.MODAL.CANCEL': NoParams;
7
+ 'DUMB.MODAL.SAVE': NoParams;
7
8
  'DUMB.MODAL.CLOSE': NoParams;
8
9
  };
@@ -1,4 +1,4 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { RenameProps } from './types';
3
- /** Editable name for `PageHeader` `titleExtra`: click to edit in place, Enter or blur commits, Escape reverts. */
3
+ /** Editable name for `PageHeader` `titleExtra`: click to edit, Enter or blur commits, Escape reverts; pairs with `ModalName`. */
4
4
  export declare function Rename(props: RenameProps): ReactElement;
@@ -6,7 +6,7 @@ import { PAGE_HEADER_RENAME_ATTRIBUTE } from '../../constants';
6
6
  const RENAME_MARK = {
7
7
  [PAGE_HEADER_RENAME_ATTRIBUTE]: true
8
8
  };
9
- /** Editable name for `PageHeader` `titleExtra`: click to edit in place, Enter or blur commits, Escape reverts. */
9
+ /** Editable name for `PageHeader` `titleExtra`: click to edit, Enter or blur commits, Escape reverts; pairs with `ModalName`. */
10
10
  export function Rename(props) {
11
11
  const {
12
12
  value,
package/hooks/useLayer.js CHANGED
@@ -100,9 +100,11 @@ export function useLayer({
100
100
  }) {
101
101
  const id = useId();
102
102
  const onCloseRef = useRef(onClose);
103
- onCloseRef.current = onClose;
104
103
  const zIndexRef = useRef(zIndex);
105
- zIndexRef.current = zIndex;
104
+ useLayoutEffect(() => {
105
+ onCloseRef.current = onClose;
106
+ zIndexRef.current = zIndex;
107
+ });
106
108
  useLayoutEffect(() => {
107
109
  if (!isOpen) {
108
110
  return undefined;
@@ -11,7 +11,7 @@ function readThemeName(element) {
11
11
  * @param ref - element inside the theme scope, so a light island wins over the document theme
12
12
  * @param isEnabled - pass `false` when the caller already knows the theme and needs no observer */
13
13
  export function useThemeName(ref, isEnabled = true) {
14
- const [themeName, setThemeName] = useState(() => readThemeName(ref?.current ?? null));
14
+ const [themeName, setThemeName] = useState(() => readThemeName(null));
15
15
  useLayoutEffect(() => {
16
16
  if (!isEnabled) {
17
17
  return undefined;
package/index.d.ts CHANGED
@@ -13,7 +13,7 @@ export { GetStartedPage, type GetStartedPageCheckListView, type GetStartedPagePr
13
13
  export { EditableField } from './EditableField';
14
14
  export { EmojiPicker } from './EmojiPicker';
15
15
  export { InputFile } from './InputFile';
16
- export { Modal, ModalTitle, ModalConfirm, ModalConfirmProvider, useModalConfirm, ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter, } from './Modal';
16
+ export { Modal, ModalTitle, ModalConfirm, ModalConfirmProvider, useModalConfirm, ModalName, type ModalNameProps, type ModalNameResult, ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter, } from './Modal';
17
17
  export { Pagination } from './Pagination';
18
18
  export { ProgressBar } from './ProgressBar';
19
19
  export { Popover } from './Popover';
package/index.js CHANGED
@@ -13,7 +13,7 @@ export { GetStartedPage } from './GetStartedPage';
13
13
  export { EditableField } from './EditableField';
14
14
  export { EmojiPicker } from './EmojiPicker';
15
15
  export { InputFile } from './InputFile';
16
- export { Modal, ModalTitle, ModalConfirm, ModalConfirmProvider, useModalConfirm, ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter } from './Modal';
16
+ export { Modal, ModalTitle, ModalConfirm, ModalConfirmProvider, useModalConfirm, ModalName, ModalHeader, ModalBodyGroup, ModalBodyItem, ModalBody, ModalFooter } from './Modal';
17
17
  export { Pagination } from './Pagination';
18
18
  export { ProgressBar } from './ProgressBar';
19
19
  export { Popover } from './Popover';
package/native/Input.js CHANGED
@@ -6,4 +6,6 @@ export const NativeInput = styled.input.withConfig({
6
6
  componentId: "sc-oqkcxd-0"
7
7
  })(["height:", ";padding:0 calc(12px - 1px);border:1px solid ", ";border-radius:", ";font-size:", ";line-height:", ";color:", ";-webkit-text-fill-color:", ";background-color:", ";&:focus{outline:none;border-color:", ";}&:disabled{background-color:", ";-webkit-text-fill-color:", ";}&::placeholder{color:", ";-webkit-text-fill-color:", ";}"], UnitSize.FIELD_HEIGHT, ({
8
8
  $isErrored
9
- }) => $isErrored ? Color.DANGER : Color.FORM, ShapeRadius.CONTROL, FontSize.REGULAR, LineHeight.REGULAR, Color.MAIN, Color.MAIN, Color.CLEAR, Color.BRIGHT, Color.FROZEN, Color.LOCKED, Color.PHANTOM, Color.PHANTOM);
9
+ }) => $isErrored ? Color.DANGER : Color.FORM, ShapeRadius.CONTROL, FontSize.REGULAR, LineHeight.REGULAR, Color.MAIN, Color.MAIN, Color.CLEAR, ({
10
+ $isErrored
11
+ }) => $isErrored ? Color.DANGER : Color.BRIGHT, Color.FROZEN, Color.LOCKED, Color.PHANTOM, Color.PHANTOM);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/dumb-components",
3
- "version": "4.6.0",
3
+ "version": "4.7.1",
4
4
  "description": "React components to build Pushwoosh products",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -37,7 +37,7 @@
37
37
  "@floating-ui/react-dom": "^2.1.2",
38
38
  "@lezer/highlight": "^1.2.1",
39
39
  "@pushwoosh/kit-constants": "^3.0.0",
40
- "@pushwoosh/kit-helpers": "^4.16.0",
40
+ "@pushwoosh/kit-helpers": "^4.16.1",
41
41
  "@pushwoosh/kit-icons": "^2.3.15",
42
42
  "@pushwoosh/kit-typography": "^2.0.0",
43
43
  "@tippyjs/react": "^4.2.6",
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
1
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
2
2
  import { DEFAULT_DEBOUNCE_MS } from './constants';
3
3
  import { useDebouncedValue } from './useDebouncedValue';
4
4
  /**
@@ -20,7 +20,9 @@ export function useAsyncItems({
20
20
  });
21
21
  const debouncedQuery = useDebouncedValue(query, debounceMs);
22
22
  const loadItemsRef = useRef(loadItems);
23
- loadItemsRef.current = loadItems;
23
+ useLayoutEffect(() => {
24
+ loadItemsRef.current = loadItems;
25
+ });
24
26
  const sessionRef = useRef(0);
25
27
  const pageRef = useRef(0);
26
28
  const queryRef = useRef('');
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef } from 'react';
1
+ import { useEffect, useEffectEvent, useRef } from 'react';
2
2
  /**
3
3
  * Side effects tied to a Combobox field's open state: optional autofocus on mount
4
4
  * and firing `onClose` when the field closes.
@@ -11,11 +11,10 @@ export function useFieldOpenEffects({
11
11
  disabled,
12
12
  inputRef
13
13
  }) {
14
- const onCloseRef = useRef(onClose);
15
- onCloseRef.current = onClose;
14
+ const onCloseEvent = useEffectEvent(() => onClose?.());
16
15
  const wasOpenRef = useRef(isOpen);
17
16
  useEffect(() => {
18
- if (wasOpenRef.current && !isOpen) onCloseRef.current?.();
17
+ if (wasOpenRef.current && !isOpen) onCloseEvent();
19
18
  wasOpenRef.current = isOpen;
20
19
  }, [isOpen]);
21
20
  const didAutoFocusRef = useRef(false);