@cloud-ru/ds-uikit-product-modal-predefined 1.0.0

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 (155) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/LICENSE +201 -0
  3. package/README.md +359 -0
  4. package/dist/cjs/components/DeleteModal/DeleteModal.d.ts +2 -0
  5. package/dist/cjs/components/DeleteModal/DeleteModal.js +39 -0
  6. package/dist/cjs/components/DeleteModal/index.d.ts +1 -0
  7. package/dist/cjs/components/DeleteModal/index.js +17 -0
  8. package/dist/cjs/components/DeleteModal/styles.module.css +33 -0
  9. package/dist/cjs/components/RecallModal/RecallModal.d.ts +2 -0
  10. package/dist/cjs/components/RecallModal/RecallModal.js +37 -0
  11. package/dist/cjs/components/RecallModal/index.d.ts +1 -0
  12. package/dist/cjs/components/RecallModal/index.js +17 -0
  13. package/dist/cjs/components/RecallModal/styles.module.css +33 -0
  14. package/dist/cjs/components/ReleaseNotes/ReleaseNotes.d.ts +7 -0
  15. package/dist/cjs/components/ReleaseNotes/ReleaseNotes.js +15 -0
  16. package/dist/cjs/components/ReleaseNotes/index.d.ts +1 -0
  17. package/dist/cjs/components/ReleaseNotes/index.js +17 -0
  18. package/dist/cjs/components/index.d.ts +3 -0
  19. package/dist/cjs/components/index.js +19 -0
  20. package/dist/cjs/constants.d.ts +27 -0
  21. package/dist/cjs/constants.js +30 -0
  22. package/dist/cjs/helperComponents/DesktopReleaseNotes/DesktopReleaseNotes.d.ts +2 -0
  23. package/dist/cjs/helperComponents/DesktopReleaseNotes/DesktopReleaseNotes.js +21 -0
  24. package/dist/cjs/helperComponents/DesktopReleaseNotes/index.d.ts +1 -0
  25. package/dist/cjs/helperComponents/DesktopReleaseNotes/index.js +17 -0
  26. package/dist/cjs/helperComponents/DesktopReleaseNotes/styles.module.css +19 -0
  27. package/dist/cjs/helperComponents/InputConfirm/InputConfirm.d.ts +48 -0
  28. package/dist/cjs/helperComponents/InputConfirm/InputConfirm.js +15 -0
  29. package/dist/cjs/helperComponents/InputConfirm/index.d.ts +1 -0
  30. package/dist/cjs/helperComponents/InputConfirm/index.js +17 -0
  31. package/dist/cjs/helperComponents/InputConfirm/styles.module.css +38 -0
  32. package/dist/cjs/helperComponents/MobileReleaseNotes/MobileReleaseNotes.d.ts +2 -0
  33. package/dist/cjs/helperComponents/MobileReleaseNotes/MobileReleaseNotes.js +26 -0
  34. package/dist/cjs/helperComponents/MobileReleaseNotes/index.d.ts +1 -0
  35. package/dist/cjs/helperComponents/MobileReleaseNotes/index.js +17 -0
  36. package/dist/cjs/helperComponents/NoteItem/NoteItem.d.ts +6 -0
  37. package/dist/cjs/helperComponents/NoteItem/NoteItem.js +20 -0
  38. package/dist/cjs/helperComponents/NoteItem/index.d.ts +1 -0
  39. package/dist/cjs/helperComponents/NoteItem/index.js +17 -0
  40. package/dist/cjs/helperComponents/NoteItem/styles.module.css +53 -0
  41. package/dist/cjs/helperComponents/ReleaseNotesContent/ReleaseNotesContent.d.ts +28 -0
  42. package/dist/cjs/helperComponents/ReleaseNotesContent/ReleaseNotesContent.js +30 -0
  43. package/dist/cjs/helperComponents/ReleaseNotesContent/index.d.ts +1 -0
  44. package/dist/cjs/helperComponents/ReleaseNotesContent/index.js +17 -0
  45. package/dist/cjs/helperComponents/ReleaseNotesContent/styles.module.css +40 -0
  46. package/dist/cjs/helperComponents/ReleaseNotesFooter/ReleaseNotesFooter.d.ts +25 -0
  47. package/dist/cjs/helperComponents/ReleaseNotesFooter/ReleaseNotesFooter.js +17 -0
  48. package/dist/cjs/helperComponents/ReleaseNotesFooter/index.d.ts +1 -0
  49. package/dist/cjs/helperComponents/ReleaseNotesFooter/index.js +17 -0
  50. package/dist/cjs/helperComponents/ReleaseNotesFooter/styles.module.css +27 -0
  51. package/dist/cjs/helperComponents/index.d.ts +6 -0
  52. package/dist/cjs/helperComponents/index.js +22 -0
  53. package/dist/cjs/hooks.d.ts +26 -0
  54. package/dist/cjs/hooks.js +59 -0
  55. package/dist/cjs/index.d.ts +4 -0
  56. package/dist/cjs/index.js +20 -0
  57. package/dist/cjs/locale/index.d.ts +143 -0
  58. package/dist/cjs/locale/index.js +76 -0
  59. package/dist/cjs/package.json +3 -0
  60. package/dist/cjs/style.css +243 -0
  61. package/dist/cjs/types.d.ts +67 -0
  62. package/dist/cjs/types.js +2 -0
  63. package/dist/esm/components/DeleteModal/DeleteModal.d.ts +2 -0
  64. package/dist/esm/components/DeleteModal/DeleteModal.js +33 -0
  65. package/dist/esm/components/DeleteModal/index.d.ts +1 -0
  66. package/dist/esm/components/DeleteModal/index.js +1 -0
  67. package/dist/esm/components/DeleteModal/styles.module.css +33 -0
  68. package/dist/esm/components/RecallModal/RecallModal.d.ts +2 -0
  69. package/dist/esm/components/RecallModal/RecallModal.js +31 -0
  70. package/dist/esm/components/RecallModal/index.d.ts +1 -0
  71. package/dist/esm/components/RecallModal/index.js +1 -0
  72. package/dist/esm/components/RecallModal/styles.module.css +33 -0
  73. package/dist/esm/components/ReleaseNotes/ReleaseNotes.d.ts +7 -0
  74. package/dist/esm/components/ReleaseNotes/ReleaseNotes.js +12 -0
  75. package/dist/esm/components/ReleaseNotes/index.d.ts +1 -0
  76. package/dist/esm/components/ReleaseNotes/index.js +1 -0
  77. package/dist/esm/components/index.d.ts +3 -0
  78. package/dist/esm/components/index.js +3 -0
  79. package/dist/esm/constants.d.ts +27 -0
  80. package/dist/esm/constants.js +27 -0
  81. package/dist/esm/helperComponents/DesktopReleaseNotes/DesktopReleaseNotes.d.ts +2 -0
  82. package/dist/esm/helperComponents/DesktopReleaseNotes/DesktopReleaseNotes.js +15 -0
  83. package/dist/esm/helperComponents/DesktopReleaseNotes/index.d.ts +1 -0
  84. package/dist/esm/helperComponents/DesktopReleaseNotes/index.js +1 -0
  85. package/dist/esm/helperComponents/DesktopReleaseNotes/styles.module.css +19 -0
  86. package/dist/esm/helperComponents/InputConfirm/InputConfirm.d.ts +48 -0
  87. package/dist/esm/helperComponents/InputConfirm/InputConfirm.js +9 -0
  88. package/dist/esm/helperComponents/InputConfirm/index.d.ts +1 -0
  89. package/dist/esm/helperComponents/InputConfirm/index.js +1 -0
  90. package/dist/esm/helperComponents/InputConfirm/styles.module.css +38 -0
  91. package/dist/esm/helperComponents/MobileReleaseNotes/MobileReleaseNotes.d.ts +2 -0
  92. package/dist/esm/helperComponents/MobileReleaseNotes/MobileReleaseNotes.js +23 -0
  93. package/dist/esm/helperComponents/MobileReleaseNotes/index.d.ts +1 -0
  94. package/dist/esm/helperComponents/MobileReleaseNotes/index.js +1 -0
  95. package/dist/esm/helperComponents/NoteItem/NoteItem.d.ts +6 -0
  96. package/dist/esm/helperComponents/NoteItem/NoteItem.js +14 -0
  97. package/dist/esm/helperComponents/NoteItem/index.d.ts +1 -0
  98. package/dist/esm/helperComponents/NoteItem/index.js +1 -0
  99. package/dist/esm/helperComponents/NoteItem/styles.module.css +53 -0
  100. package/dist/esm/helperComponents/ReleaseNotesContent/ReleaseNotesContent.d.ts +28 -0
  101. package/dist/esm/helperComponents/ReleaseNotesContent/ReleaseNotesContent.js +24 -0
  102. package/dist/esm/helperComponents/ReleaseNotesContent/index.d.ts +1 -0
  103. package/dist/esm/helperComponents/ReleaseNotesContent/index.js +1 -0
  104. package/dist/esm/helperComponents/ReleaseNotesContent/styles.module.css +40 -0
  105. package/dist/esm/helperComponents/ReleaseNotesFooter/ReleaseNotesFooter.d.ts +25 -0
  106. package/dist/esm/helperComponents/ReleaseNotesFooter/ReleaseNotesFooter.js +11 -0
  107. package/dist/esm/helperComponents/ReleaseNotesFooter/index.d.ts +1 -0
  108. package/dist/esm/helperComponents/ReleaseNotesFooter/index.js +1 -0
  109. package/dist/esm/helperComponents/ReleaseNotesFooter/styles.module.css +27 -0
  110. package/dist/esm/helperComponents/index.d.ts +6 -0
  111. package/dist/esm/helperComponents/index.js +6 -0
  112. package/dist/esm/hooks.d.ts +26 -0
  113. package/dist/esm/hooks.js +55 -0
  114. package/dist/esm/index.d.ts +4 -0
  115. package/dist/esm/index.js +4 -0
  116. package/dist/esm/locale/index.d.ts +143 -0
  117. package/dist/esm/locale/index.js +73 -0
  118. package/dist/esm/style.css +243 -0
  119. package/dist/esm/types.d.ts +67 -0
  120. package/dist/esm/types.js +1 -0
  121. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  122. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  123. package/package.json +63 -0
  124. package/src/components/DeleteModal/DeleteModal.tsx +116 -0
  125. package/src/components/DeleteModal/index.ts +1 -0
  126. package/src/components/DeleteModal/styles.module.scss +37 -0
  127. package/src/components/RecallModal/RecallModal.tsx +111 -0
  128. package/src/components/RecallModal/index.ts +1 -0
  129. package/src/components/RecallModal/styles.module.scss +37 -0
  130. package/src/components/ReleaseNotes/ReleaseNotes.tsx +15 -0
  131. package/src/components/ReleaseNotes/index.ts +1 -0
  132. package/src/components/index.ts +3 -0
  133. package/src/constants.ts +29 -0
  134. package/src/helperComponents/DesktopReleaseNotes/DesktopReleaseNotes.tsx +85 -0
  135. package/src/helperComponents/DesktopReleaseNotes/index.ts +1 -0
  136. package/src/helperComponents/DesktopReleaseNotes/styles.module.scss +24 -0
  137. package/src/helperComponents/InputConfirm/InputConfirm.tsx +72 -0
  138. package/src/helperComponents/InputConfirm/index.ts +1 -0
  139. package/src/helperComponents/InputConfirm/styles.module.scss +30 -0
  140. package/src/helperComponents/MobileReleaseNotes/MobileReleaseNotes.tsx +88 -0
  141. package/src/helperComponents/MobileReleaseNotes/index.ts +1 -0
  142. package/src/helperComponents/NoteItem/NoteItem.tsx +58 -0
  143. package/src/helperComponents/NoteItem/index.ts +1 -0
  144. package/src/helperComponents/NoteItem/styles.module.scss +54 -0
  145. package/src/helperComponents/ReleaseNotesContent/ReleaseNotesContent.tsx +119 -0
  146. package/src/helperComponents/ReleaseNotesContent/index.ts +1 -0
  147. package/src/helperComponents/ReleaseNotesContent/styles.module.scss +45 -0
  148. package/src/helperComponents/ReleaseNotesFooter/ReleaseNotesFooter.tsx +84 -0
  149. package/src/helperComponents/ReleaseNotesFooter/index.ts +1 -0
  150. package/src/helperComponents/ReleaseNotesFooter/styles.module.scss +25 -0
  151. package/src/helperComponents/index.ts +6 -0
  152. package/src/hooks.ts +89 -0
  153. package/src/index.ts +4 -0
  154. package/src/locale/index.ts +77 -0
  155. package/src/types.ts +80 -0
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@cloud-ru/ds-uikit-product-modal-predefined",
3
+ "version": "1.0.0",
4
+ "description": "Product preset-компоненты для delete, recall и release notes сценариев на базе Modal и BottomSheet.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/cloud-ru-tech/snack-v2.git",
8
+ "directory": "packages/uikit-product-modal-predefined"
9
+ },
10
+ "homepage": "https://github.com/cloud-ru-tech/snack-v2/tree/master/packages/uikit-product-modal-predefined",
11
+ "license": "Apache-2.0",
12
+ "author": "Robert Kuzhin <rikuzhin@cloud.ru>",
13
+ "type": "module",
14
+ "main": "./dist/cjs/index.js",
15
+ "module": "./dist/esm/index.js",
16
+ "types": "./dist/esm/index.d.ts",
17
+ "exports": {
18
+ ".": {
19
+ "source": "./src/index.ts",
20
+ "types": "./dist/esm/index.d.ts",
21
+ "import": "./dist/esm/index.js",
22
+ "require": "./dist/cjs/index.js"
23
+ },
24
+ "./locale": {
25
+ "source": "./src/locale/index.ts",
26
+ "types": "./dist/esm/locale/index.d.ts",
27
+ "import": "./dist/esm/locale/index.js",
28
+ "require": "./dist/cjs/locale/index.js"
29
+ }
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "src",
34
+ "./CHANGELOG.md",
35
+ "./LICENSE"
36
+ ],
37
+ "sideEffects": [
38
+ "*.css",
39
+ "**/*.css"
40
+ ],
41
+ "dependencies": {
42
+ "classnames": "^2.5.1",
43
+ "@cloud-ru/ds-adaptive": "^1.0.0",
44
+ "@cloud-ru/ds-button": "^1.0.0",
45
+ "@cloud-ru/ds-bottom-sheet": "^1.0.0",
46
+ "@cloud-ru/ds-carousel": "^1.0.0",
47
+ "@cloud-ru/ds-fields": "^1.0.0",
48
+ "@cloud-ru/ds-icons": "^1.0.0",
49
+ "@cloud-ru/ds-info-block": "^1.0.0",
50
+ "@cloud-ru/ds-locale": "^1.0.0",
51
+ "@cloud-ru/ds-markdown": "^1.0.0",
52
+ "@cloud-ru/ds-modal": "^1.0.0",
53
+ "@cloud-ru/ds-scroll": "^1.0.0",
54
+ "@cloud-ru/ds-skeleton": "^1.0.0",
55
+ "@cloud-ru/ds-tooltip": "^1.0.0",
56
+ "@cloud-ru/ds-typography": "^1.0.0",
57
+ "@cloud-ru/ds-utils": "^1.0.0",
58
+ "@cloud-ru/ds-uikit-product-copy": "^1.0.0"
59
+ },
60
+ "publishConfig": {
61
+ "access": "public"
62
+ }
63
+ }
@@ -0,0 +1,116 @@
1
+ import { APPEARANCE, Button, VIEW } from '@cloud-ru/ds-button';
2
+ import { ModalCustom, WIDTH } from '@cloud-ru/ds-modal';
3
+ import { QuestionTooltip } from '@cloud-ru/ds-tooltip';
4
+ import { useRef } from 'react';
5
+
6
+ import { CONFIRM_TEXT_VARIANT, TEST_IDS } from '../../constants';
7
+ import { InputConfirm } from '../../helperComponents';
8
+ import { useTextFieldValidation } from '../../hooks';
9
+ import { modalPredefinedLocale } from '../../locale';
10
+ import { DeleteModalProps } from '../../types';
11
+ import styles from './styles.module.scss';
12
+
13
+ export function DeleteModal({
14
+ open,
15
+ onClose,
16
+ mode,
17
+ closeOnPopstate,
18
+ objectType,
19
+ titleTooltip,
20
+ onDelete,
21
+ deleting,
22
+ content,
23
+ confirmable = false,
24
+ confirmText,
25
+ hideConfirmCopyButton,
26
+ subtitle,
27
+ confirmTextVariant = CONFIRM_TEXT_VARIANT.Name,
28
+ ...rest
29
+ }: DeleteModalProps) {
30
+ const { t } = modalPredefinedLocale.useTranslations();
31
+ const inputRef = useRef<HTMLInputElement>(null);
32
+ const { value, error, handleChange, reset, validate } = useTextFieldValidation({
33
+ target: confirmable ? confirmText : undefined,
34
+ errorText: t('confirm.error'),
35
+ });
36
+ const shouldShowConfirm = Boolean(confirmable && confirmText);
37
+ const title = objectType ? t('deleteModal.title', { objectType }) : t('deleteModal.fallbackTitle');
38
+ const confirmPlaceholder =
39
+ confirmTextVariant === CONFIRM_TEXT_VARIANT.Text ? t('confirm.textPlaceholder') : t('confirm.namePlaceholder');
40
+
41
+ const handleClose = () => {
42
+ reset();
43
+ onClose();
44
+ };
45
+
46
+ const handleApproveClick = () => {
47
+ if (!validate()) {
48
+ inputRef.current?.focus();
49
+ return;
50
+ }
51
+
52
+ onDelete(handleClose);
53
+ };
54
+
55
+ return (
56
+ <ModalCustom
57
+ open={open}
58
+ onClose={handleClose}
59
+ mode={mode}
60
+ closeOnPopstate={closeOnPopstate}
61
+ width={WIDTH.S}
62
+ data-test-id={TEST_IDS.deleteModal}
63
+ data-confirmable={confirmable || undefined}
64
+ {...rest}
65
+ >
66
+ <div className={styles.safeAreaTop} />
67
+ <ModalCustom.Header
68
+ title={title}
69
+ subtitle={subtitle}
70
+ slotAfterTitle={titleTooltip ? <QuestionTooltip size='s' tip={titleTooltip} /> : undefined}
71
+ />
72
+ <ModalCustom.Body
73
+ className={styles.body}
74
+ content={
75
+ <div className={styles.content}>
76
+ {content ?? t('deleteModal.content')}
77
+ {shouldShowConfirm && (
78
+ <InputConfirm
79
+ ref={inputRef}
80
+ confirmText={confirmText ?? ''}
81
+ hideConfirmCopyButton={hideConfirmCopyButton}
82
+ value={value}
83
+ error={error}
84
+ size='l'
85
+ copyLineAlign='start'
86
+ confirmLabel={t('deleteModal.confirmLabel')}
87
+ placeholder={confirmPlaceholder}
88
+ onChange={handleChange}
89
+ />
90
+ )}
91
+ </div>
92
+ }
93
+ />
94
+ <div className={styles.safeAreaBottom} />
95
+ <ModalCustom.Footer>
96
+ <div className={styles.footer}>
97
+ <Button
98
+ view={VIEW.Outline}
99
+ appearance={APPEARANCE.Neutral}
100
+ label={t('deleteModal.cancel')}
101
+ onClick={handleClose}
102
+ data-test-id={TEST_IDS.cancelButton}
103
+ />
104
+ <Button
105
+ view={VIEW.Filled}
106
+ appearance={APPEARANCE.Critical}
107
+ label={t('deleteModal.approve')}
108
+ loading={deleting}
109
+ onClick={handleApproveClick}
110
+ data-test-id={TEST_IDS.approveButton}
111
+ />
112
+ </div>
113
+ </ModalCustom.Footer>
114
+ </ModalCustom>
115
+ );
116
+ }
@@ -0,0 +1 @@
1
+ export * from './DeleteModal';
@@ -0,0 +1,37 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/modal.module' as modal;
3
+
4
+ .safeAreaTop {
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: flex-start;
8
+ align-self: stretch;
9
+
10
+ padding-top: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-top');
11
+ }
12
+
13
+ .safeAreaBottom {
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: flex-start;
17
+ align-self: stretch;
18
+
19
+ padding-bottom: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-bottom');
20
+ }
21
+
22
+ .body {
23
+ min-height: auto;
24
+ }
25
+
26
+ .content {
27
+ display: flex;
28
+ flex-direction: column;
29
+ row-gap: base.$sn-primitive-dimension-16;
30
+ }
31
+
32
+ .footer {
33
+ display: flex;
34
+ column-gap: base.$sn-primitive-dimension-8;
35
+ justify-content: flex-end;
36
+ width: 100%;
37
+ }
@@ -0,0 +1,111 @@
1
+ import { APPEARANCE, Button, VIEW } from '@cloud-ru/ds-button';
2
+ import { ModalCustom, WIDTH } from '@cloud-ru/ds-modal';
3
+ import { QuestionTooltip } from '@cloud-ru/ds-tooltip';
4
+ import { useRef } from 'react';
5
+
6
+ import { TEST_IDS } from '../../constants';
7
+ import { InputConfirm } from '../../helperComponents';
8
+ import { useTextFieldValidation } from '../../hooks';
9
+ import { modalPredefinedLocale } from '../../locale';
10
+ import { RecallModalProps } from '../../types';
11
+ import styles from './styles.module.scss';
12
+
13
+ export function RecallModal({
14
+ open,
15
+ onClose,
16
+ mode,
17
+ closeOnPopstate,
18
+ titleTooltip,
19
+ onRecall,
20
+ loading,
21
+ content,
22
+ confirmable = false,
23
+ confirmText,
24
+ hideConfirmCopyButton,
25
+ subtitle,
26
+ ...rest
27
+ }: RecallModalProps) {
28
+ const { t } = modalPredefinedLocale.useTranslations();
29
+ const inputRef = useRef<HTMLInputElement>(null);
30
+ const { value, error, handleChange, reset, validate } = useTextFieldValidation({
31
+ target: confirmable ? confirmText : undefined,
32
+ errorText: t('confirm.error'),
33
+ });
34
+ const shouldShowConfirm = Boolean(confirmable && confirmText);
35
+
36
+ const handleClose = () => {
37
+ reset();
38
+ onClose();
39
+ };
40
+
41
+ const handleApproveClick = () => {
42
+ if (!validate()) {
43
+ inputRef.current?.focus();
44
+ return;
45
+ }
46
+
47
+ onRecall(handleClose);
48
+ };
49
+
50
+ return (
51
+ <ModalCustom
52
+ open={open}
53
+ onClose={handleClose}
54
+ mode={mode}
55
+ closeOnPopstate={closeOnPopstate}
56
+ width={WIDTH.S}
57
+ data-test-id={TEST_IDS.recallModal}
58
+ data-confirmable={confirmable || undefined}
59
+ {...rest}
60
+ >
61
+ <div className={styles.safeAreaTop} />
62
+ <ModalCustom.Header
63
+ title={t('recallModal.title')}
64
+ subtitle={subtitle}
65
+ slotAfterTitle={titleTooltip ? <QuestionTooltip size='s' tip={titleTooltip} /> : undefined}
66
+ />
67
+ <ModalCustom.Body
68
+ className={styles.body}
69
+ content={
70
+ <div className={styles.content}>
71
+ {content ?? t('recallModal.content')}
72
+ {shouldShowConfirm && (
73
+ <InputConfirm
74
+ ref={inputRef}
75
+ confirmText={confirmText ?? ''}
76
+ confirmLabel={t('recallModal.confirmLabel')}
77
+ hideConfirmCopyButton={hideConfirmCopyButton}
78
+ value={value}
79
+ error={error}
80
+ size='l'
81
+ copyLineAlign='start'
82
+ placeholder={t('confirm.namePlaceholder')}
83
+ onChange={handleChange}
84
+ />
85
+ )}
86
+ </div>
87
+ }
88
+ />
89
+ <div className={styles.safeAreaBottom} />
90
+ <ModalCustom.Footer>
91
+ <div className={styles.footer}>
92
+ <Button
93
+ view={VIEW.Outline}
94
+ appearance={APPEARANCE.Neutral}
95
+ label={t('recallModal.cancel')}
96
+ onClick={handleClose}
97
+ data-test-id={TEST_IDS.cancelButton}
98
+ />
99
+ <Button
100
+ view={VIEW.Filled}
101
+ appearance={APPEARANCE.Critical}
102
+ label={t('recallModal.approve')}
103
+ loading={loading}
104
+ onClick={handleApproveClick}
105
+ data-test-id={TEST_IDS.approveButton}
106
+ />
107
+ </div>
108
+ </ModalCustom.Footer>
109
+ </ModalCustom>
110
+ );
111
+ }
@@ -0,0 +1 @@
1
+ export * from './RecallModal';
@@ -0,0 +1,37 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/modal.module' as modal;
3
+
4
+ .safeAreaTop {
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: flex-start;
8
+ align-self: stretch;
9
+
10
+ padding-top: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-top');
11
+ }
12
+
13
+ .safeAreaBottom {
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: flex-start;
17
+ align-self: stretch;
18
+
19
+ padding-bottom: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-bottom');
20
+ }
21
+
22
+ .body {
23
+ min-height: auto;
24
+ }
25
+
26
+ .content {
27
+ display: flex;
28
+ flex-direction: column;
29
+ row-gap: base.$sn-primitive-dimension-16;
30
+ }
31
+
32
+ .footer {
33
+ display: flex;
34
+ column-gap: base.$sn-primitive-dimension-8;
35
+ justify-content: flex-end;
36
+ width: 100%;
37
+ }
@@ -0,0 +1,15 @@
1
+ import { isMobileLayout, useAdaptiveLayout } from '@cloud-ru/ds-adaptive';
2
+
3
+ import { DesktopReleaseNotes, MobileReleaseNotes } from '../../helperComponents';
4
+ import { ReleaseNotesProps } from '../../types';
5
+
6
+ /**
7
+ * Адаптивный release-notes: на `mobile` — bottom sheet, иначе — модальное окно. Поверхность выбирается
8
+ * по `useAdaptiveLayout()` из `@cloud-ru/ds-adaptive` и пропом не задаётся. Форс раскладки — через
9
+ * `withLayoutType(ReleaseNotes, 'mobile')` либо `AdaptiveProvider` в поддереве.
10
+ */
11
+ export function ReleaseNotes(props: ReleaseNotesProps) {
12
+ const { layoutType } = useAdaptiveLayout();
13
+
14
+ return isMobileLayout(layoutType) ? <MobileReleaseNotes {...props} /> : <DesktopReleaseNotes {...props} />;
15
+ }
@@ -0,0 +1 @@
1
+ export * from './ReleaseNotes';
@@ -0,0 +1,3 @@
1
+ export * from './DeleteModal';
2
+ export * from './RecallModal';
3
+ export * from './ReleaseNotes';
@@ -0,0 +1,29 @@
1
+ export const CONTENT_STATE = {
2
+ Data: 'data',
3
+ NoData: 'noData',
4
+ Error: 'error',
5
+ } as const;
6
+
7
+ export const CONFIRM_TEXT_VARIANT = {
8
+ Name: 'name',
9
+ Text: 'text',
10
+ } as const;
11
+
12
+ export const TEST_IDS = {
13
+ deleteModal: 'delete-modal',
14
+ recallModal: 'recall-modal',
15
+ releaseNotes: 'release-notes',
16
+ approveButton: 'modal-predefined__approve-button',
17
+ cancelButton: 'modal-predefined__cancel-button',
18
+ confirmInput: 'modal-predefined__confirm-input',
19
+ confirmCopyButton: 'modal-predefined__confirm-copy-button',
20
+ releaseNotesItem: 'modal-predefined__release-notes-item',
21
+ releaseNotesMedia: 'modal-predefined__release-notes-media',
22
+ releaseNotesVideo: 'modal-predefined__release-notes-video',
23
+ releaseNotesError: 'modal-predefined__release-notes-error',
24
+ releaseNotesNoData: 'modal-predefined__release-notes-no-data',
25
+ releaseNotesRetryButton: 'modal-predefined__release-notes-retry-button',
26
+ releaseNotesReadLaterButton: 'modal-predefined__release-notes-read-later-button',
27
+ releaseNotesPrevButton: 'modal-predefined__release-notes-prev-button',
28
+ releaseNotesNextButton: 'modal-predefined__release-notes-next-button',
29
+ } as const;
@@ -0,0 +1,85 @@
1
+ import { ModalCustom, WIDTH } from '@cloud-ru/ds-modal';
2
+ import { extractSupportProps } from '@cloud-ru/ds-utils';
3
+
4
+ import { CONTENT_STATE } from '../../constants';
5
+ import { useReleaseNotesNavigation } from '../../hooks';
6
+ import { modalPredefinedLocale } from '../../locale';
7
+ import { ReleaseNotesProps } from '../../types';
8
+ import { ReleaseNotesContent } from '../ReleaseNotesContent';
9
+ import { ReleaseNotesFooter } from '../ReleaseNotesFooter';
10
+ import styles from './styles.module.scss';
11
+
12
+ export function DesktopReleaseNotes({
13
+ open,
14
+ onClose,
15
+ closeOnPopstate,
16
+ contentState = CONTENT_STATE.Data,
17
+ items,
18
+ loading,
19
+ onReadLaterClick,
20
+ onDataErrorRetryClick,
21
+ onSlideChange,
22
+ ...rest
23
+ }: ReleaseNotesProps) {
24
+ const { t } = modalPredefinedLocale.useTranslations();
25
+ const {
26
+ pageIndex,
27
+ readablePageNumber,
28
+ setPage,
29
+ handleClose,
30
+ handleReadLaterClick,
31
+ handleNextPageClick,
32
+ handlePrevPageClick,
33
+ } = useReleaseNotesNavigation({ onClose, onReadLaterClick, onSlideChange });
34
+ const shouldShowFooter = contentState === CONTENT_STATE.Data && (loading || items.length > 0);
35
+
36
+ return (
37
+ <ModalCustom
38
+ open={open}
39
+ onClose={handleClose}
40
+ closeOnPopstate={closeOnPopstate}
41
+ width={WIDTH.M}
42
+ data-content-state={contentState}
43
+ data-surface='modal'
44
+ {...extractSupportProps(rest)}
45
+ >
46
+ <div className={styles.safeAreaTop} />
47
+ <ModalCustom.Header title={t('releaseNotes.title')} />
48
+ <ModalCustom.Body
49
+ className={styles.body}
50
+ content={
51
+ <ReleaseNotesContent
52
+ contentState={contentState}
53
+ items={items}
54
+ loading={loading}
55
+ pageIndex={pageIndex}
56
+ surface='modal'
57
+ noDataTitle={t('releaseNotes.noDataTitle')}
58
+ noDataDescription={t('releaseNotes.noDataDescription')}
59
+ errorTitle={t('releaseNotes.errorTitle')}
60
+ errorDescription={t('releaseNotes.errorDescription')}
61
+ retryLabel={t('releaseNotes.retry')}
62
+ onPageChange={setPage}
63
+ onDataErrorRetryClick={onDataErrorRetryClick}
64
+ />
65
+ }
66
+ />
67
+ <div className={styles.safeAreaBottom} />
68
+ {shouldShowFooter && (
69
+ <ModalCustom.Footer>
70
+ <ReleaseNotesFooter
71
+ surface='modal'
72
+ total={items.length}
73
+ pageIndex={pageIndex}
74
+ readablePageNumber={readablePageNumber}
75
+ counterLabel={t('releaseNotes.counter', { page: readablePageNumber, total: items.length })}
76
+ readLaterLabel={t('releaseNotes.readLater')}
77
+ onReadLaterClick={handleReadLaterClick}
78
+ onPrevPageClick={handlePrevPageClick}
79
+ onNextPageClick={() => handleNextPageClick(items.length)}
80
+ />
81
+ </ModalCustom.Footer>
82
+ )}
83
+ </ModalCustom>
84
+ );
85
+ }
@@ -0,0 +1 @@
1
+ export * from './DesktopReleaseNotes';
@@ -0,0 +1,24 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+ @use '@cloud-ru/ds-figma-variables/build/scss/components/modal.module' as modal;
3
+
4
+ .safeAreaTop {
5
+ display: flex;
6
+ flex-direction: column;
7
+ align-items: flex-start;
8
+ align-self: stretch;
9
+
10
+ padding-top: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-top');
11
+ }
12
+
13
+ .safeAreaBottom {
14
+ display: flex;
15
+ flex-direction: column;
16
+ align-items: flex-start;
17
+ align-self: stretch;
18
+
19
+ padding-bottom: base.simple-var(modal.$modal, 'anatomy', 'container', 'safeArea', 'padding-bottom');
20
+ }
21
+
22
+ .body {
23
+ min-height: calc(6 * #{base.$sn-primitive-dimension-64});
24
+ }
@@ -0,0 +1,72 @@
1
+ import { FieldCombo, FieldComboProps, VALIDATION_STATE } from '@cloud-ru/ds-fields';
2
+ import { CopyButton } from '@cloud-ru/ds-uikit-product-copy';
3
+ import { WithSupportProps } from '@cloud-ru/ds-utils';
4
+ import { forwardRef } from 'react';
5
+
6
+ import { TEST_IDS } from '../../constants';
7
+ import styles from './styles.module.scss';
8
+
9
+ export type InputConfirmProps = WithSupportProps<{
10
+ /** Текст, который нужно ввести для подтверждения */
11
+ confirmText: string;
12
+ /** Инструкция над текстом подтверждения */
13
+ confirmLabel?: string;
14
+ /** Скрыть кнопку копирования */
15
+ hideConfirmCopyButton?: boolean;
16
+ /** Значение поля */
17
+ value: string;
18
+ /** Текст ошибки */
19
+ error?: string;
20
+ /** Label поля */
21
+ label?: string;
22
+ /** Размер поля */
23
+ size?: FieldComboProps['size'];
24
+ /** Выравнивание copy-line */
25
+ copyLineAlign?: 'start' | 'space-between';
26
+ /** Placeholder поля */
27
+ placeholder: string;
28
+ /** Колбэк изменения значения */
29
+ onChange(value: string): void;
30
+ }>;
31
+
32
+ export const InputConfirm = forwardRef<HTMLInputElement, InputConfirmProps>(function InputConfirm(
33
+ {
34
+ confirmText,
35
+ confirmLabel,
36
+ hideConfirmCopyButton,
37
+ value,
38
+ error,
39
+ label,
40
+ size = 'm',
41
+ copyLineAlign = 'space-between',
42
+ placeholder,
43
+ onChange,
44
+ ...rest
45
+ },
46
+ ref,
47
+ ) {
48
+ return (
49
+ <div className={styles.root}>
50
+ {confirmLabel && <span className={styles.confirmLabel}>{confirmLabel}</span>}
51
+ <div className={styles.confirmText} data-align={copyLineAlign}>
52
+ <span className={styles.confirmValue}>{confirmText}</span>
53
+ {!hideConfirmCopyButton && <CopyButton valueToCopy={confirmText} data-test-id={TEST_IDS.confirmCopyButton} />}
54
+ </div>
55
+
56
+ <FieldCombo
57
+ {...rest}
58
+ ref={ref}
59
+ inputMode='text'
60
+ label={label}
61
+ required={Boolean(label)}
62
+ size={size}
63
+ placeholder={placeholder}
64
+ value={value}
65
+ onChange={onChange}
66
+ hint={error}
67
+ validationState={error ? VALIDATION_STATE.Error : VALIDATION_STATE.Default}
68
+ data-test-id={TEST_IDS.confirmInput}
69
+ />
70
+ </div>
71
+ );
72
+ });
@@ -0,0 +1 @@
1
+ export * from './InputConfirm';
@@ -0,0 +1,30 @@
1
+ @use '@cloud-ru/ds-figma-variables/build/scss/styles/styles.module' as base;
2
+
3
+ .root {
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+
8
+ .confirmText {
9
+ display: flex;
10
+ column-gap: base.$sn-primitive-dimension-8;
11
+ align-items: center;
12
+ justify-content: space-between;
13
+
14
+ margin-bottom: base.$sn-primitive-dimension-8;
15
+ }
16
+
17
+ .confirmText[data-align='start'] {
18
+ column-gap: base.$sn-primitive-dimension-4;
19
+ justify-content: flex-start;
20
+ }
21
+
22
+ .confirmLabel {
23
+ @include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 'm');
24
+
25
+ color: base.$sn-theme-color-available-version-textSecondary;
26
+ }
27
+
28
+ .confirmValue {
29
+ @include base.composite-var(base.$base-styles, 'sn', 'regular', 'body', 'm');
30
+ }