@pushwoosh/dumb-components 4.2.0 → 4.3.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.
- package/FrequencyCapping/components/Condition/index.js +3 -19
- package/FrequencyCapping/helpers/getReadonlyCappingHelpers.js +4 -1
- package/FrequencyCapping/polyglot/messages_ar.js +2 -1
- package/FrequencyCapping/polyglot/messages_bn.js +2 -1
- package/FrequencyCapping/polyglot/messages_de.js +2 -1
- package/FrequencyCapping/polyglot/messages_en.js +2 -1
- package/FrequencyCapping/polyglot/messages_es.js +2 -1
- package/FrequencyCapping/polyglot/messages_fr.js +2 -1
- package/FrequencyCapping/polyglot/messages_he.js +2 -1
- package/FrequencyCapping/polyglot/messages_hi.js +2 -1
- package/FrequencyCapping/polyglot/messages_ja.js +2 -1
- package/FrequencyCapping/polyglot/messages_ko.js +2 -1
- package/FrequencyCapping/polyglot/messages_pt.js +2 -1
- package/FrequencyCapping/polyglot/messages_ru.js +2 -1
- package/FrequencyCapping/polyglot/messages_th.js +2 -1
- package/FrequencyCapping/polyglot/messages_zh.js +2 -1
- package/FrequencyCapping/polyglot/types.d.ts +1 -0
- package/PageHeader/components/PageHeader/PageHeader.js +29 -14
- package/PageHeader/components/PageHeader/styles.d.ts +16 -0
- package/PageHeader/components/PageHeader/styles.js +18 -3
- package/PageHeader/components/PageHeader/types.d.ts +2 -0
- package/PageHeader/constants.d.ts +2 -0
- package/PageHeader/constants.js +2 -0
- package/Steps/components/Step/Step.d.ts +3 -0
- package/Steps/components/Step/Step.js +48 -0
- package/Steps/components/Step/index.d.ts +1 -0
- package/Steps/components/Step/index.js +1 -0
- package/Steps/components/Step/styles.d.ts +6 -0
- package/Steps/components/Step/styles.js +30 -0
- package/Steps/components/Step/types.d.ts +10 -0
- package/Steps/components/Step/types.js +1 -0
- package/Steps/components/Steps/Steps.d.ts +4 -0
- package/Steps/components/Steps/Steps.js +35 -0
- package/Steps/components/Steps/index.d.ts +1 -0
- package/Steps/components/Steps/index.js +1 -0
- package/Steps/components/StepsSkeleton/StepsSkeleton.d.ts +3 -0
- package/Steps/components/StepsSkeleton/StepsSkeleton.js +37 -0
- package/Steps/components/StepsSkeleton/index.d.ts +1 -0
- package/Steps/components/StepsSkeleton/index.js +1 -0
- package/Steps/components/StepsSkeleton/types.d.ts +3 -0
- package/Steps/components/StepsSkeleton/types.js +1 -0
- package/Steps/constants.d.ts +4 -0
- package/Steps/constants.js +5 -0
- package/Steps/helpers/index.d.ts +1 -0
- package/Steps/helpers/index.js +1 -0
- package/Steps/helpers/progress.d.ts +3 -0
- package/Steps/helpers/progress.js +7 -0
- package/Steps/hooks/index.d.ts +1 -0
- package/Steps/hooks/index.js +1 -0
- package/Steps/hooks/useSteps.d.ts +3 -0
- package/Steps/hooks/useSteps.js +67 -0
- package/Steps/index.d.ts +3 -0
- package/Steps/index.js +2 -0
- package/Steps/types.d.ts +59 -0
- package/Steps/types.js +1 -0
- package/index.d.ts +2 -0
- package/index.js +1 -0
- package/package.json +2 -2
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import { Color } from '@pushwoosh/kit-constants';
|
|
3
|
-
import { HelpRoundIcon } from '@pushwoosh/kit-icons';
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
2
|
import { ChipWithinTextContainer } from './styles';
|
|
5
3
|
import { Chip } from '../../../Chip';
|
|
6
|
-
import { Tooltip } from '../../../Tooltip';
|
|
7
4
|
export function ChipFrequencyCapping({
|
|
8
5
|
text,
|
|
9
6
|
tooltip,
|
|
@@ -11,24 +8,11 @@ export function ChipFrequencyCapping({
|
|
|
11
8
|
}) {
|
|
12
9
|
return _jsx(ChipWithinTextContainer, {
|
|
13
10
|
"$inText": $inText,
|
|
14
|
-
children:
|
|
15
|
-
content: tooltip,
|
|
16
|
-
position: "top-middle",
|
|
17
|
-
children: _jsxs(Chip, {
|
|
18
|
-
"$variant": "primary",
|
|
19
|
-
"$readOnly": true,
|
|
20
|
-
as: "span",
|
|
21
|
-
children: [text, _jsx(HelpRoundIcon, {
|
|
22
|
-
as: "span",
|
|
23
|
-
size: "small",
|
|
24
|
-
view: "lined",
|
|
25
|
-
color: Color.PHANTOM
|
|
26
|
-
})]
|
|
27
|
-
})
|
|
28
|
-
}) : _jsx(Chip, {
|
|
11
|
+
children: _jsx(Chip, {
|
|
29
12
|
"$variant": "primary",
|
|
30
13
|
"$readOnly": true,
|
|
31
14
|
as: "span",
|
|
15
|
+
"$tooltip": tooltip,
|
|
32
16
|
children: text
|
|
33
17
|
})
|
|
34
18
|
});
|
|
@@ -49,7 +49,10 @@ export function getReadonlyCappingLabel(cappingOption, isGlobalCappingDisabled,
|
|
|
49
49
|
children: [lang({
|
|
50
50
|
message: 'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL'
|
|
51
51
|
}), _jsx(ChipFrequencyCapping, {
|
|
52
|
-
text: getCappingChipText(lang, 0, 0)
|
|
52
|
+
text: getCappingChipText(lang, 0, 0),
|
|
53
|
+
tooltip: lang({
|
|
54
|
+
message: 'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED'
|
|
55
|
+
})
|
|
53
56
|
}), lang({
|
|
54
57
|
message: 'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET'
|
|
55
58
|
})]
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'تحديد التكرار العام:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'لأنه لم يتم تعيين حد',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'إذا تجاوز المشترك حد الرسائل المستلمة، فلن يستلم هذه الرسالة{% if isInJourney == true %} وسينتقل إلى الخطوة التالية{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'سيستلم المستخدم هذه الرسالة على أي حال، حتى لو تجاوز الحدود المحددة للقناة'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'سيستلم المستخدم هذه الرسالة على أي حال، حتى لو تجاوز الحدود المحددة للقناة',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'لم يتم تعيين حد التكرار العام، لذلك لا يوجد حد لعدد الرسائل التي يتلقاها المشترك'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'গ্লোবাল ফ্রিকোয়েন্সি সীমা:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'কারণ সীমা নির্ধারণ করা হয়নি',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'সাবস্ক্রাইবার প্রাপ্ত বার্তার সীমা অতিক্রম করলে তিনি এই বার্তাটি পাবেন না{% if isInJourney == true %} এবং পরবর্তী ধাপে এগিয়ে যাবেন{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'ব্যবহারকারী চ্যানেলের জন্য নির্ধারিত সীমা অতিক্রম করলেও যেকোনো অবস্থায় এই বার্তাটি পাবেন'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'ব্যবহারকারী চ্যানেলের জন্য নির্ধারিত সীমা অতিক্রম করলেও যেকোনো অবস্থায় এই বার্তাটি পাবেন',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'গ্লোবাল ফ্রিকোয়েন্সি সীমা সেট করা নেই, তাই একজন সাবস্ক্রাইবার কতগুলি বার্তা পাবেন তা সীমিত নয়'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Globale Frequenzbegrenzung:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'da kein Limit festgelegt ist',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'Wenn der Abonnent das Limit empfangener Nachrichten überschreitet, erhält er diese Nachricht nicht{% if isInJourney == true %} und fährt mit dem nächsten Schritt fort{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'Der Benutzer erhält diese Nachricht in jedem Fall, auch wenn er die für den Kanal festgelegten Limits überschritten hat'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'Der Benutzer erhält diese Nachricht in jedem Fall, auch wenn er die für den Kanal festgelegten Limits überschritten hat',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'Es ist keine globale Frequenzbegrenzung festgelegt, daher ist die Anzahl der Nachrichten, die ein Abonnent erhält, nicht begrenzt'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Global frequency capping:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'because limit isn’t set',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'If the subscriber exceeds the limit of received messages, they will not receive this message{% if isInJourney == true %} and will proceed to the next step{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'The user will receive this message regardless, even if they have exceeded the set limits for the channel'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'The user will receive this message regardless, even if they have exceeded the set limits for the channel',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'Global frequency capping isn’t set, so the number of messages a subscriber receives isn’t limited'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Límite de frecuencia global:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'porque no se ha establecido un límite',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'Si el suscriptor supera el límite de mensajes recibidos, no recibirá este mensaje{% if isInJourney == true %} y pasará al siguiente paso{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'El usuario recibirá este mensaje de todos modos, incluso si ha superado los límites establecidos para el canal'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'El usuario recibirá este mensaje de todos modos, incluso si ha superado los límites establecidos para el canal',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'No hay un límite de frecuencia global, por lo que la cantidad de mensajes que recibe un suscriptor no está limitada'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Limitation de fréquence globale :',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'car aucune limite n’est définie',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'Si l’abonné dépasse la limite de messages reçus, il ne recevra pas ce message{% if isInJourney == true %} et passera à l’étape suivante{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'L’utilisateur recevra ce message quoi qu’il arrive, même s’il a dépassé les limites définies pour le canal'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'L’utilisateur recevra ce message quoi qu’il arrive, même s’il a dépassé les limites définies pour le canal',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'Aucune limite de fréquence globale n’est définie : le nombre de messages reçus par un abonné n’est donc pas limité'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'הגבלת תדירות גלובלית:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'מכיוון שלא הוגדרה מגבלה',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'אם המנוי יחרוג ממגבלת ההודעות שהתקבלו, הוא לא יקבל הודעה זו{% if isInJourney == true %} ויעבור לשלב הבא{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'המשתמש יקבל הודעה זו בכל מקרה, גם אם חרג מהמגבלות שהוגדרו לערוץ'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'המשתמש יקבל הודעה זו בכל מקרה, גם אם חרג מהמגבלות שהוגדרו לערוץ',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'לא הוגדרה הגבלת תדירות גלובלית, ולכן מספר ההודעות שמנוי מקבל אינו מוגבל'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'वैश्विक आवृत्ति सीमा:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'क्योंकि सीमा निर्धारित नहीं है',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'यदि सब्सक्राइबर प्राप्त संदेशों की सीमा पार कर लेता है, तो उसे यह संदेश प्राप्त नहीं होगा{% if isInJourney == true %} और वह अगले चरण पर चला जाएगा{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'उपयोगकर्ता को यह संदेश हर हाल में प्राप्त होगा, भले ही उसने चैनल के लिए निर्धारित सीमाएँ पार कर ली हों'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'उपयोगकर्ता को यह संदेश हर हाल में प्राप्त होगा, भले ही उसने चैनल के लिए निर्धारित सीमाएँ पार कर ली हों',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'ग्लोबल फ़्रीक्वेंसी सीमा सेट नहीं है, इसलिए सब्सक्राइबर को मिलने वाले संदेशों की संख्या सीमित नहीं है'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'グローバル頻度制限:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': '制限が設定されていないため',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': '購読者が受信メッセージの上限を超えた場合、このメッセージは届きません{% if isInJourney == true %}。そして次のステップに進みます{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'チャネルに設定された上限を超えていても、ユーザーはこのメッセージを必ず受信します'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'チャネルに設定された上限を超えていても、ユーザーはこのメッセージを必ず受信します',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'グローバルな頻度上限が設定されていないため、購読者が受け取るメッセージ数に制限はありません'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': '전역 빈도 제한:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': '제한이 설정되지 않았기 때문에',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': '구독자가 수신 메시지 제한을 초과하면 이 메시지를 받지 않습니다{% if isInJourney == true %} 그리고 다음 단계로 진행합니다{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': '사용자가 채널에 설정된 제한을 초과했더라도 이 메시지를 반드시 수신합니다'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': '사용자가 채널에 설정된 제한을 초과했더라도 이 메시지를 반드시 수신합니다',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': '전역 빈도 제한이 설정되지 않아 구독자가 받는 메시지 수에 제한이 없습니다'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Limite de frequência global:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'porque nenhum limite foi definido',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'Se o assinante exceder o limite de mensagens recebidas, ele não receberá esta mensagem{% if isInJourney == true %} e avançará para a próxima etapa{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'O usuário receberá esta mensagem de qualquer forma, mesmo que tenha excedido os limites definidos para o canal'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'O usuário receberá esta mensagem de qualquer forma, mesmo que tenha excedido os limites definidos para o canal',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'O limite de frequência global não está definido, então o número de mensagens que um assinante recebe não é limitado'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'Глобальное ограничение частоты:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'так как лимит не задан',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'Если подписчик превысит лимит полученных сообщений, он не получит это сообщение{% if isInJourney == true %} и перейдёт к следующему шагу{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'Пользователь получит это сообщение в любом случае, даже если он превысил установленные лимиты для канала'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'Пользователь получит это сообщение в любом случае, даже если он превысил установленные лимиты для канала',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'Глобальное ограничение частоты не задано, поэтому число сообщений, которые получает подписчик, не ограничено'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': 'การจำกัดความถี่ส่วนกลาง:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': 'เนื่องจากยังไม่ได้ตั้งค่าขีดจำกัด',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': 'หากผู้รับเกินขีดจำกัดของข้อความที่ได้รับ ผู้รับจะไม่ได้รับข้อความนี้{% if isInJourney == true %} และจะไปยังขั้นตอนถัดไป{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'ผู้ใช้จะได้รับข้อความนี้ไม่ว่าในกรณีใด แม้ว่าจะเกินขีดจำกัดที่ตั้งไว้สำหรับช่องทางแล้วก็ตาม'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': 'ผู้ใช้จะได้รับข้อความนี้ไม่ว่าในกรณีใด แม้ว่าจะเกินขีดจำกัดที่ตั้งไว้สำหรับช่องทางแล้วก็ตาม',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': 'ยังไม่ได้ตั้งค่าการจำกัดความถี่ทั่วไป จึงไม่มีการจำกัดจำนวนข้อความที่สมาชิกได้รับ'
|
|
43
44
|
};
|
|
@@ -39,5 +39,6 @@ export const messages = {
|
|
|
39
39
|
'DUMB.FREQUENCY_CAPPING.RO.GLOBAL_LABEL': '全局频率限制:',
|
|
40
40
|
'DUMB.FREQUENCY_CAPPING.RO.BECAUSE_UNSET': '因为未设置限制',
|
|
41
41
|
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_LIMIT': '如果订阅者超过接收消息的上限,将不会收到此消息{% if isInJourney == true %},并将进入下一步{% endif %}',
|
|
42
|
-
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': '无论用户是否超过该渠道设置的上限,都将收到此消息'
|
|
42
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_IGNORE': '无论用户是否超过该渠道设置的上限,都将收到此消息',
|
|
43
|
+
'DUMB.FREQUENCY_CAPPING.RO.TOOLTIP_UNLIMITED': '未设置全局频率上限,因此订阅者接收的消息数量不受限制'
|
|
43
44
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { UnitSize } from '@pushwoosh/kit-constants';
|
|
3
|
+
import { Columns, Horizontal } from '@pushwoosh/kit-helpers';
|
|
3
4
|
import { ArrowRoundIcon } from '@pushwoosh/kit-icons';
|
|
4
5
|
import { H1 } from '@pushwoosh/kit-typography';
|
|
5
6
|
import { Button } from '../../../Button';
|
|
6
7
|
import { PageHeaderError } from '../PageHeaderError';
|
|
7
|
-
import { RootBox, BackButton, TitleBox, DescriptionBox, ActionsBox, MoreActionsBox } from './styles';
|
|
8
|
+
import { RootBox, BackButton, TitleBox, TitleWithExtraBox, TitleWrapBox, TitleExtraBox, DescriptionBox, ActionsBox, MoreActionsBox } from './styles';
|
|
8
9
|
/**
|
|
9
10
|
* Page-level header with a title, optional back arrow, description, inline error bar
|
|
10
11
|
* and submit/cancel/extra actions.
|
|
@@ -15,6 +16,7 @@ import { RootBox, BackButton, TitleBox, DescriptionBox, ActionsBox, MoreActionsB
|
|
|
15
16
|
export function PageHeader(props) {
|
|
16
17
|
const {
|
|
17
18
|
title,
|
|
19
|
+
titleExtra,
|
|
18
20
|
description,
|
|
19
21
|
error,
|
|
20
22
|
resolveErrorText,
|
|
@@ -29,23 +31,36 @@ export function PageHeader(props) {
|
|
|
29
31
|
} = props;
|
|
30
32
|
const hasActions = Boolean(onSubmit || onCancel);
|
|
31
33
|
const hasActionsBox = hasActions || Boolean(moreActions);
|
|
34
|
+
const backButton = onBack && _jsx(BackButton, {
|
|
35
|
+
children: _jsx(Button, {
|
|
36
|
+
color: "primary",
|
|
37
|
+
view: "ghost",
|
|
38
|
+
onClick: onBack,
|
|
39
|
+
children: _jsx(ArrowRoundIcon, {
|
|
40
|
+
direction: "left",
|
|
41
|
+
size: "medium",
|
|
42
|
+
view: "filled"
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
});
|
|
32
46
|
return _jsxs(RootBox, {
|
|
33
47
|
children: [_jsxs(Columns, {
|
|
34
48
|
"$sizes": "minmax(0, 1fr) max-content",
|
|
35
49
|
"$gap": 24,
|
|
36
|
-
children: [_jsxs(
|
|
37
|
-
children: [
|
|
38
|
-
children: _jsx(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
direction: "left",
|
|
44
|
-
size: "medium",
|
|
45
|
-
view: "filled"
|
|
50
|
+
children: [titleExtra ? _jsxs(TitleWithExtraBox, {
|
|
51
|
+
children: [backButton, _jsxs(TitleWrapBox, {
|
|
52
|
+
children: [_jsx(Horizontal, {
|
|
53
|
+
"$minHeight": UnitSize.FIELD_HEIGHT,
|
|
54
|
+
"$alignItems": "center",
|
|
55
|
+
children: _jsx(H1, {
|
|
56
|
+
children: title
|
|
46
57
|
})
|
|
47
|
-
})
|
|
48
|
-
|
|
58
|
+
}), _jsx(TitleExtraBox, {
|
|
59
|
+
children: titleExtra
|
|
60
|
+
})]
|
|
61
|
+
})]
|
|
62
|
+
}) : _jsxs(TitleBox, {
|
|
63
|
+
children: [backButton, _jsx(H1, {
|
|
49
64
|
children: title
|
|
50
65
|
})]
|
|
51
66
|
}), hasActionsBox && _jsxs(ActionsBox, {
|
|
@@ -8,6 +8,22 @@ export declare const BackButton: import("styled-components/dist/types").IStyledC
|
|
|
8
8
|
export declare const TitleBox: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
9
9
|
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
10
10
|
}> & string;
|
|
11
|
+
export declare const TitleWithExtraBox: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("styled-components").FastOmit<Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
12
|
+
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
13
|
+
}, "as" | "forwardedAs"> & {
|
|
14
|
+
as?: import("styled-components").WebTarget | undefined;
|
|
15
|
+
forwardedAs?: import("styled-components").WebTarget | undefined;
|
|
16
|
+
}, "style"> & {
|
|
17
|
+
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | (import("react").CSSProperties & {
|
|
18
|
+
[key: `--${string}`]: string | number | undefined;
|
|
19
|
+
}) | undefined;
|
|
20
|
+
}> & string;
|
|
21
|
+
export declare const TitleWrapBox: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
22
|
+
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
23
|
+
}> & string;
|
|
24
|
+
export declare const TitleExtraBox: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
25
|
+
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
26
|
+
}> & string;
|
|
11
27
|
export declare const ActionsBox: import("styled-components/dist/types").IStyledComponentBase<"web", Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style"> & {
|
|
12
28
|
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
13
29
|
}> & string;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
|
+
import { FontSize, LineHeight, UnitSize } from '@pushwoosh/kit-constants';
|
|
2
3
|
import { Paragraph } from '@pushwoosh/kit-typography';
|
|
4
|
+
import { PAGE_HEADER_INSET_ATTRIBUTE, STEP_CELL_INSET } from '../../constants';
|
|
3
5
|
export const RootBox = styled.div.withConfig({
|
|
4
6
|
displayName: "RootBox",
|
|
5
7
|
componentId: "sc-1qwo99q-0"
|
|
@@ -12,17 +14,30 @@ export const TitleBox = styled.div.withConfig({
|
|
|
12
14
|
displayName: "TitleBox",
|
|
13
15
|
componentId: "sc-1qwo99q-2"
|
|
14
16
|
})(["display:flex;align-items:center;justify-content:start;flex-shrink:0;gap:8px;"]);
|
|
17
|
+
const TITLE_LINE_HEIGHT = `calc(${FontSize.HEADING1} * ${LineHeight.HEADING1})`;
|
|
18
|
+
export const TitleWithExtraBox = styled(TitleBox).withConfig({
|
|
19
|
+
displayName: "TitleWithExtraBox",
|
|
20
|
+
componentId: "sc-1qwo99q-3"
|
|
21
|
+
})(["align-items:flex-start;flex-shrink:1;min-width:0;"]);
|
|
22
|
+
export const TitleWrapBox = styled.div.withConfig({
|
|
23
|
+
displayName: "TitleWrapBox",
|
|
24
|
+
componentId: "sc-1qwo99q-4"
|
|
25
|
+
})(["display:flex;flex-wrap:wrap;align-items:center;column-gap:8px;row-gap:calc(8px - (", " - ", ") / 2);min-width:0;&:has([", "]){--page-header-extra-inset:", "px;}"], UnitSize.FIELD_HEIGHT, TITLE_LINE_HEIGHT, PAGE_HEADER_INSET_ATTRIBUTE, STEP_CELL_INSET);
|
|
26
|
+
export const TitleExtraBox = styled.div.withConfig({
|
|
27
|
+
displayName: "TitleExtraBox",
|
|
28
|
+
componentId: "sc-1qwo99q-5"
|
|
29
|
+
})(["display:flex;align-items:center;min-width:0;margin-left:calc(-1 * var(--page-header-extra-inset,0px));"]);
|
|
15
30
|
export const ActionsBox = styled.div.withConfig({
|
|
16
31
|
displayName: "ActionsBox",
|
|
17
|
-
componentId: "sc-1qwo99q-
|
|
32
|
+
componentId: "sc-1qwo99q-6"
|
|
18
33
|
})(["display:flex;justify-content:flex-end;gap:8px;"]);
|
|
19
34
|
export const MoreActionsBox = styled.div.withConfig({
|
|
20
35
|
displayName: "MoreActionsBox",
|
|
21
|
-
componentId: "sc-1qwo99q-
|
|
36
|
+
componentId: "sc-1qwo99q-7"
|
|
22
37
|
})(["display:flex;margin-right:", ";"], ({
|
|
23
38
|
$hasActions
|
|
24
39
|
}) => $hasActions ? '16px' : '0');
|
|
25
40
|
export const DescriptionBox = styled(Paragraph).withConfig({
|
|
26
41
|
displayName: "DescriptionBox",
|
|
27
|
-
componentId: "sc-1qwo99q-
|
|
42
|
+
componentId: "sc-1qwo99q-8"
|
|
28
43
|
})(["margin-top:16px;"]);
|
|
@@ -3,6 +3,8 @@ import type { ReactElement, ReactNode } from 'react';
|
|
|
3
3
|
export interface PageHeaderProps {
|
|
4
4
|
/** Page title. */
|
|
5
5
|
title: ReactNode;
|
|
6
|
+
/** Content next to the title, e.g. `Steps`; wraps under the title when the row is too narrow. */
|
|
7
|
+
titleExtra?: ReactNode;
|
|
6
8
|
/** Subtitle/description under the title. */
|
|
7
9
|
description?: ReactNode | string;
|
|
8
10
|
/** Error message shown in an inline error bar. */
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Color } from '@pushwoosh/kit-constants';
|
|
3
|
+
import { Horizontal } from '@pushwoosh/kit-helpers';
|
|
4
|
+
import { CheckRoundIcon } from '@pushwoosh/kit-icons';
|
|
5
|
+
import { Text } from '@pushwoosh/kit-typography';
|
|
6
|
+
import { StepBox } from './styles';
|
|
7
|
+
const TONES = {
|
|
8
|
+
passed: 'success',
|
|
9
|
+
current: 'primary',
|
|
10
|
+
'not-passed': 'muted'
|
|
11
|
+
};
|
|
12
|
+
const CELL_TYPES = {
|
|
13
|
+
passed: 'blank',
|
|
14
|
+
current: 'dot',
|
|
15
|
+
'not-passed': 'blank'
|
|
16
|
+
};
|
|
17
|
+
export function Step(props) {
|
|
18
|
+
const {
|
|
19
|
+
title,
|
|
20
|
+
progress,
|
|
21
|
+
hasError,
|
|
22
|
+
hasTail,
|
|
23
|
+
onClick
|
|
24
|
+
} = props;
|
|
25
|
+
const isChecked = progress === 'passed' && !hasError;
|
|
26
|
+
return _jsxs(_Fragment, {
|
|
27
|
+
children: [_jsxs(StepBox, {
|
|
28
|
+
as: onClick ? 'button' : 'span',
|
|
29
|
+
type: onClick ? 'button' : undefined,
|
|
30
|
+
"$tone": hasError ? 'danger' : TONES[progress],
|
|
31
|
+
"aria-current": progress === 'current' ? 'step' : undefined,
|
|
32
|
+
onClick: onClick,
|
|
33
|
+
children: [_jsx(CheckRoundIcon, {
|
|
34
|
+
as: "span",
|
|
35
|
+
size: "medium",
|
|
36
|
+
type: isChecked ? 'fill' : CELL_TYPES[progress],
|
|
37
|
+
view: progress === 'current' || isChecked ? 'filled' : 'lined'
|
|
38
|
+
}), _jsx(Text, {
|
|
39
|
+
"$variant": "h1",
|
|
40
|
+
children: title
|
|
41
|
+
})]
|
|
42
|
+
}), hasTail && _jsx(Horizontal, {
|
|
43
|
+
"$width": 16,
|
|
44
|
+
"$height": 2,
|
|
45
|
+
"$bgColor": Color.FORM
|
|
46
|
+
})]
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Step } from './Step';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Step } from './Step';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StepTone } from './types';
|
|
2
|
+
export declare const StepBox: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Merged<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "style"> & {
|
|
3
|
+
style?: import("react").CSSProperties | import("styled-components/dist/types").CSSPropertiesWithVars | undefined;
|
|
4
|
+
}, {
|
|
5
|
+
$tone: StepTone;
|
|
6
|
+
}>> & string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { Color } from '@pushwoosh/kit-constants';
|
|
3
|
+
const COLORS = {
|
|
4
|
+
muted: {
|
|
5
|
+
idle: Color.PHANTOM,
|
|
6
|
+
hover: Color.PRIMARY_HOVER
|
|
7
|
+
},
|
|
8
|
+
primary: {
|
|
9
|
+
idle: Color.PRIMARY,
|
|
10
|
+
hover: Color.PRIMARY_HOVER
|
|
11
|
+
},
|
|
12
|
+
success: {
|
|
13
|
+
idle: Color.SUCCESS,
|
|
14
|
+
hover: Color.SUCCESS_HOVER
|
|
15
|
+
},
|
|
16
|
+
danger: {
|
|
17
|
+
idle: Color.DANGER,
|
|
18
|
+
hover: Color.DANGER_HOVER
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
export const StepBox = styled.button.withConfig({
|
|
22
|
+
displayName: "StepBox",
|
|
23
|
+
componentId: "sc-goy1gs-0"
|
|
24
|
+
})(["display:flex;align-items:center;gap:6px;margin:0;padding:0;border:0;background:none;color:", ";white-space:nowrap;button&:hover{color:", ";cursor:pointer;}button&:active{color:", ";opacity:0.5;}&:focus-visible{outline:1px solid ", ";outline-offset:2px;}"], ({
|
|
25
|
+
$tone
|
|
26
|
+
}) => COLORS[$tone].idle, ({
|
|
27
|
+
$tone
|
|
28
|
+
}) => COLORS[$tone].hover, ({
|
|
29
|
+
$tone
|
|
30
|
+
}) => COLORS[$tone].hover, Color.BRIGHT);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { StepProgress } from '../../types';
|
|
3
|
+
export type StepTone = 'muted' | 'primary' | 'success' | 'danger';
|
|
4
|
+
export type StepProps = {
|
|
5
|
+
title: ReactNode;
|
|
6
|
+
progress: StepProgress;
|
|
7
|
+
hasError: boolean;
|
|
8
|
+
hasTail: boolean;
|
|
9
|
+
onClick?: () => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
|
+
import type { StepId, StepsProps } from '../../types';
|
|
3
|
+
/** Wizard progress for `PageHeader` `titleExtra`; spread `stepsProps` of {@link useSteps} into it. */
|
|
4
|
+
export declare function Steps<Id extends StepId>(props: StepsProps<Id>): ReactElement;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Horizontal } from '@pushwoosh/kit-helpers';
|
|
3
|
+
import { DEFAULT_SKELETON_COUNT, INSET_MARK } from '../../constants';
|
|
4
|
+
import { findStepIndex, getStepProgress } from '../../helpers';
|
|
5
|
+
import { Step } from '../Step';
|
|
6
|
+
import { StepsSkeleton } from '../StepsSkeleton';
|
|
7
|
+
/** Wizard progress for `PageHeader` `titleExtra`; spread `stepsProps` of {@link useSteps} into it. */
|
|
8
|
+
export function Steps(props) {
|
|
9
|
+
const {
|
|
10
|
+
items,
|
|
11
|
+
activeStep,
|
|
12
|
+
onStepClick,
|
|
13
|
+
isLoading = false,
|
|
14
|
+
skeletonCount = DEFAULT_SKELETON_COUNT
|
|
15
|
+
} = props;
|
|
16
|
+
const activeIndex = findStepIndex(items, activeStep);
|
|
17
|
+
if (isLoading) {
|
|
18
|
+
return _jsx(StepsSkeleton, {
|
|
19
|
+
count: items.length || skeletonCount
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return _jsx(Horizontal, {
|
|
23
|
+
"$gap": 6,
|
|
24
|
+
"$alignItems": "center",
|
|
25
|
+
"$justifyContent": "start",
|
|
26
|
+
...INSET_MARK,
|
|
27
|
+
children: items.map((item, index) => _jsx(Step, {
|
|
28
|
+
title: item.title,
|
|
29
|
+
progress: getStepProgress(index, activeIndex),
|
|
30
|
+
hasError: !!item.hasError,
|
|
31
|
+
hasTail: index < items.length - 1,
|
|
32
|
+
onClick: onStepClick && index < activeIndex ? () => onStepClick(item.id) : undefined
|
|
33
|
+
}, item.id))
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Steps } from './Steps';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Steps } from './Steps';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import { Color } from '@pushwoosh/kit-constants';
|
|
4
|
+
import { Horizontal } from '@pushwoosh/kit-helpers';
|
|
5
|
+
import { CircularSkeleton, RectangularSkeleton } from '../../../Skeleton';
|
|
6
|
+
import { INSET_MARK } from '../../constants';
|
|
7
|
+
export function StepsSkeleton({
|
|
8
|
+
count
|
|
9
|
+
}) {
|
|
10
|
+
return _jsx(Horizontal, {
|
|
11
|
+
"$gap": 6,
|
|
12
|
+
"$alignItems": "center",
|
|
13
|
+
"$justifyContent": "start",
|
|
14
|
+
"aria-busy": "true",
|
|
15
|
+
...INSET_MARK,
|
|
16
|
+
children: Array.from({
|
|
17
|
+
length: count
|
|
18
|
+
}, (_, index) => _jsxs(Fragment, {
|
|
19
|
+
children: [_jsx(Horizontal, {
|
|
20
|
+
"$padding": 3,
|
|
21
|
+
children: _jsx(CircularSkeleton, {
|
|
22
|
+
diameter: 18,
|
|
23
|
+
color: Color.SOFT_LIGHT
|
|
24
|
+
})
|
|
25
|
+
}), _jsx(RectangularSkeleton, {
|
|
26
|
+
width: 87,
|
|
27
|
+
height: 18,
|
|
28
|
+
borderRadius: 4,
|
|
29
|
+
color: Color.SOFT_LIGHT
|
|
30
|
+
}), index < count - 1 && _jsx(RectangularSkeleton, {
|
|
31
|
+
width: 16,
|
|
32
|
+
height: 2,
|
|
33
|
+
color: Color.SOFT_LIGHT
|
|
34
|
+
})]
|
|
35
|
+
}, index))
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StepsSkeleton } from './StepsSkeleton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StepsSkeleton } from './StepsSkeleton';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './progress';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './progress';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { StepId, StepItem, StepProgress } from '../types';
|
|
2
|
+
export declare const findStepIndex: <Id extends StepId>(items: ReadonlyArray<StepItem<Id>>, id: Id | undefined) => number;
|
|
3
|
+
export declare const getStepProgress: (index: number, activeIndex: number) => StepProgress;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const findStepIndex = (items, id) => id === undefined ? -1 : items.findIndex(item => item.id === id);
|
|
2
|
+
export const getStepProgress = (index, activeIndex) => {
|
|
3
|
+
if (activeIndex < 0 || index > activeIndex) {
|
|
4
|
+
return 'not-passed';
|
|
5
|
+
}
|
|
6
|
+
return index === activeIndex ? 'current' : 'passed';
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSteps';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useSteps';
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from 'react';
|
|
2
|
+
import { findStepIndex } from '../helpers';
|
|
3
|
+
/** Wizard state: a forward move passes `canLeave`, a backward move is never blocked. */
|
|
4
|
+
export function useSteps(options) {
|
|
5
|
+
const {
|
|
6
|
+
items,
|
|
7
|
+
activeStep,
|
|
8
|
+
onChange,
|
|
9
|
+
canLeave,
|
|
10
|
+
onBackward
|
|
11
|
+
} = options;
|
|
12
|
+
const activeIndex = findStepIndex(items, activeStep);
|
|
13
|
+
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
14
|
+
const isPendingRef = useRef(false);
|
|
15
|
+
const goTo = useCallback(async id => {
|
|
16
|
+
const toIndex = findStepIndex(items, id);
|
|
17
|
+
if (isPendingRef.current || activeIndex < 0 || toIndex < 0 || toIndex === activeIndex) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (toIndex < activeIndex) {
|
|
21
|
+
onBackward?.(activeStep, id);
|
|
22
|
+
onChange(id);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
isPendingRef.current = true;
|
|
26
|
+
setIsTransitioning(true);
|
|
27
|
+
try {
|
|
28
|
+
if (!canLeave || (await canLeave(activeStep, id))) {
|
|
29
|
+
onChange(id);
|
|
30
|
+
}
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('[useSteps]: canLeave threw, the move is refused.', error);
|
|
33
|
+
} finally {
|
|
34
|
+
isPendingRef.current = false;
|
|
35
|
+
setIsTransitioning(false);
|
|
36
|
+
}
|
|
37
|
+
}, [items, activeStep, activeIndex, onChange, canLeave, onBackward]);
|
|
38
|
+
const next = useCallback(async () => {
|
|
39
|
+
const nextItem = activeIndex >= 0 ? items[activeIndex + 1] : undefined;
|
|
40
|
+
if (nextItem) {
|
|
41
|
+
await goTo(nextItem.id);
|
|
42
|
+
}
|
|
43
|
+
}, [activeIndex, items, goTo]);
|
|
44
|
+
const prev = useCallback(() => {
|
|
45
|
+
const prevItem = activeIndex > 0 ? items[activeIndex - 1] : undefined;
|
|
46
|
+
if (prevItem) {
|
|
47
|
+
void goTo(prevItem.id);
|
|
48
|
+
}
|
|
49
|
+
}, [activeIndex, items, goTo]);
|
|
50
|
+
const onStepClick = useCallback(id => {
|
|
51
|
+
void goTo(id);
|
|
52
|
+
}, [goTo]);
|
|
53
|
+
return {
|
|
54
|
+
activeIndex,
|
|
55
|
+
isFirst: activeIndex === 0,
|
|
56
|
+
isLast: activeIndex >= 0 && activeIndex === items.length - 1,
|
|
57
|
+
goTo,
|
|
58
|
+
next,
|
|
59
|
+
prev,
|
|
60
|
+
isTransitioning,
|
|
61
|
+
stepsProps: {
|
|
62
|
+
items,
|
|
63
|
+
activeStep,
|
|
64
|
+
onStepClick
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
package/Steps/index.d.ts
ADDED
package/Steps/index.js
ADDED
package/Steps/types.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
/** Identifier of a step: the form's own key, a string or a number. */
|
|
3
|
+
export type StepId = string | number;
|
|
4
|
+
/** One step of a {@link Steps} indicator. */
|
|
5
|
+
export type StepItem<Id extends StepId = StepId> = {
|
|
6
|
+
/** Stable key of the step; progress is derived from its position in `items`. */
|
|
7
|
+
id: Id;
|
|
8
|
+
/** Label: one word or two short ones. */
|
|
9
|
+
title: ReactNode;
|
|
10
|
+
/** Paints the step as erroneous; a passed step with an error is shown as not passed. */
|
|
11
|
+
hasError?: boolean;
|
|
12
|
+
};
|
|
13
|
+
/** Where a step stands relative to the active one. */
|
|
14
|
+
export type StepProgress = 'passed' | 'current' | 'not-passed';
|
|
15
|
+
/** Props of {@link Steps}. */
|
|
16
|
+
export type StepsProps<Id extends StepId = StepId> = {
|
|
17
|
+
/** Steps in display order, 2 to 5 of them. */
|
|
18
|
+
items: ReadonlyArray<StepItem<Id>>;
|
|
19
|
+
/** Id of the current step. */
|
|
20
|
+
activeStep: Id;
|
|
21
|
+
/** Makes the steps before the current one clickable; without it no step reacts to clicks. */
|
|
22
|
+
onStepClick?: (id: Id) => void;
|
|
23
|
+
/** Shows the skeleton instead of the steps — meant for the first data load only. */
|
|
24
|
+
isLoading?: boolean;
|
|
25
|
+
/** Number of skeleton steps when `items` is empty; 3 by default. */
|
|
26
|
+
skeletonCount?: number;
|
|
27
|
+
};
|
|
28
|
+
/** Options of {@link useSteps}. */
|
|
29
|
+
export type UseStepsOptions<Id extends StepId = StepId> = {
|
|
30
|
+
/** Steps in display order. */
|
|
31
|
+
items: ReadonlyArray<StepItem<Id>>;
|
|
32
|
+
/** Current step, stored by the caller (a form field, a route). */
|
|
33
|
+
activeStep: Id;
|
|
34
|
+
/** Called with the step to move to. */
|
|
35
|
+
onChange: (id: Id) => void;
|
|
36
|
+
/** Gate of a forward move; a Promise holds the move, `false` or a throw refuses it. */
|
|
37
|
+
canLeave?: (from: Id, to: Id) => boolean | Promise<boolean>;
|
|
38
|
+
/** Called before every backward move, which is never blocked; forms clear their errors here. */
|
|
39
|
+
onBackward?: (from: Id, to: Id) => void;
|
|
40
|
+
};
|
|
41
|
+
/** Result of {@link useSteps}. */
|
|
42
|
+
export type UseStepsResult<Id extends StepId = StepId> = {
|
|
43
|
+
/** Index of the current step in `items`, -1 when it is not there. */
|
|
44
|
+
activeIndex: number;
|
|
45
|
+
/** The current step is the first one. */
|
|
46
|
+
isFirst: boolean;
|
|
47
|
+
/** The current step is the last one. */
|
|
48
|
+
isLast: boolean;
|
|
49
|
+
/** Moves to a step, through `canLeave` when moving forward; ignored while a move is pending. */
|
|
50
|
+
goTo: (id: Id) => Promise<void>;
|
|
51
|
+
/** Moves to the next step; no-op on the last one. */
|
|
52
|
+
next: () => Promise<void>;
|
|
53
|
+
/** Moves to the previous step; no-op on the first one. */
|
|
54
|
+
prev: () => void;
|
|
55
|
+
/** A forward move is waiting for `canLeave`. */
|
|
56
|
+
isTransitioning: boolean;
|
|
57
|
+
/** Ready props for {@link Steps}: `items`, `activeStep`, `onStepClick`. */
|
|
58
|
+
stepsProps: Pick<StepsProps<Id>, 'items' | 'activeStep' | 'onStepClick'>;
|
|
59
|
+
};
|
package/Steps/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/index.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export { WhatsAppPreview } from './WhatsAppPreview';
|
|
|
40
40
|
export type { WhatsAppAttachment, WhatsAppAttachmentKind, WhatsAppMessage, WhatsAppPreviewProps, } from './WhatsAppPreview';
|
|
41
41
|
export { Toast, ToastProvider, useToast } from './Toast';
|
|
42
42
|
export { AutosizeInput, PageHeader, PageHeaderEditable } from './PageHeader';
|
|
43
|
+
export { Steps, useSteps } from './Steps';
|
|
44
|
+
export type { StepId, StepItem, StepProgress, StepsProps, UseStepsOptions, UseStepsResult, } from './Steps';
|
|
43
45
|
export { ExportResult } from './ExportResult';
|
|
44
46
|
export { ExternalImagePreview } from './ExternalImagePreview';
|
|
45
47
|
export { NativeInput, NativeTextarea, NativeSelect, NativeTimeInput, } from './native';
|
package/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export { InboxPreview, resolveInboxLayout, MAX_CAROUSEL_SLIDES } from './InboxPr
|
|
|
39
39
|
export { WhatsAppPreview } from './WhatsAppPreview';
|
|
40
40
|
export { Toast, ToastProvider, useToast } from './Toast';
|
|
41
41
|
export { AutosizeInput, PageHeader, PageHeaderEditable } from './PageHeader';
|
|
42
|
+
export { Steps, useSteps } from './Steps';
|
|
42
43
|
export { ExportResult } from './ExportResult';
|
|
43
44
|
export { ExternalImagePreview } from './ExternalImagePreview';
|
|
44
45
|
export { NativeInput, NativeTextarea, NativeSelect, NativeTimeInput } from './native';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushwoosh/dumb-components",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "React components to build Pushwoosh products",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@lezer/highlight": "^1.2.1",
|
|
39
39
|
"@pushwoosh/kit-constants": "^3.0.0",
|
|
40
40
|
"@pushwoosh/kit-helpers": "^4.16.0",
|
|
41
|
-
"@pushwoosh/kit-icons": "^2.3.
|
|
41
|
+
"@pushwoosh/kit-icons": "^2.3.15",
|
|
42
42
|
"@pushwoosh/kit-typography": "^2.0.0",
|
|
43
43
|
"@tippyjs/react": "^4.2.6",
|
|
44
44
|
"@uiw/codemirror-themes": "^4.23.8",
|