@pushwoosh/dumb-components 2.8.2 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@ import { Horizontal, Vertical } from '@pushwoosh/kit-helpers';
3
3
  import { H4, Paragraph } from '@pushwoosh/kit-typography';
4
4
  import { Radio } from '../Radio';
5
5
  import { TooltipTrigger } from '../Tooltip';
6
- import { RootBox } from './styled';
6
+ import { RootBox } from './styles';
7
7
  /**
8
8
  * Selectable card with a title, optional description and a radio indicator — a richer
9
9
  * alternative to {@link Radio} for choosing one option among cards.
@@ -9,7 +9,7 @@ export const RootBox = styled(Vertical).attrs({
9
9
  $gap: 0
10
10
  }).withConfig({
11
11
  displayName: "RootBox",
12
- componentId: "sc-tkztr1-0"
12
+ componentId: "sc-1woucxa-0"
13
13
  })(["width:", ";height:100%;box-sizing:border-box;outline:", ";cursor:", ";opacity:", ";pointer-events:", ";&:hover{background:", ";}"], ({
14
14
  $width
15
15
  }) => toCssValue($width), ({
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useRef } from 'react';
3
- import { EditorEmojiPickerStyled } from './EditorEmojiPicker.styled';
3
+ import { EditorEmojiPickerStyled } from './EditorEmojiPicker.styles';
4
4
  import { EmojiPicker } from '../EmojiPicker';
5
5
  import { useThemeName } from '../hooks';
6
6
  export const EditorEmojiPicker = ({
@@ -3,7 +3,7 @@ import { Color, getThemeColors, Shadow, ShapeRadius } from '@pushwoosh/kit-const
3
3
  import { rgbChannels } from './EditorEmojiPicker.helpers';
4
4
  export const EditorEmojiPickerStyled = styled.div.withConfig({
5
5
  displayName: "EditorEmojiPickerStyled",
6
- componentId: "sc-sdjrip-0"
6
+ componentId: "sc-1jl3t23-0"
7
7
  })(["min-width:352px;em-emoji-picker{border:1px solid ", ";--border-radius:", ";--shadow:", ";background-color:", ";--rgb-background:", ";}"], Color.FORM, ShapeRadius.CONTROL, Shadow.REGULAR, Color.FROZEN, ({
8
8
  $theme
9
9
  }) => rgbChannels(getThemeColors($theme).FROZEN));
@@ -10,7 +10,7 @@ import EmojiIcon from './assets/EmojiIcon.svg';
10
10
  import PersonalizationIcon from './assets/PersonalizationIcon.svg';
11
11
  import { EditorEmojiPicker } from './EditorEmojiPicker';
12
12
  import { placementToDirection } from './RichMessageEditor.helpers';
13
- import { Arrow, DropArea, DropContent, ImSpan } from './RichMessageEditor.styled';
13
+ import { Arrow, DropArea, DropContent, ImSpan } from './RichMessageEditor.styles';
14
14
  import { getDcByPath } from './slate/helpers';
15
15
  import { SlateEditable, SlateEditor } from './slate/SlateEditor';
16
16
  /**
@@ -3,15 +3,15 @@ import { Color, Shadow, ShapeRadius } from '@pushwoosh/kit-constants';
3
3
  import { Horizontal } from '@pushwoosh/kit-helpers';
4
4
  export const ImSpan = styled.span.withConfig({
5
5
  displayName: "ImSpan",
6
- componentId: "sc-kdvgj9-0"
6
+ componentId: "sc-1l3r9n8-0"
7
7
  })(["color:", ";position:relative;padding-left:20px;font-size:12px;font-style:normal;font-weight:500;line-height:130%;text-transform:uppercase;cursor:pointer;> svg{position:absolute;left:0;top:-1px;}"], Color.SOFT);
8
8
  export const DropArea = styled.div.withConfig({
9
9
  displayName: "DropArea",
10
- componentId: "sc-kdvgj9-1"
10
+ componentId: "sc-1l3r9n8-1"
11
11
  })(["z-index:1000;"]);
12
12
  export const DropContent = styled.div.withConfig({
13
13
  displayName: "DropContent",
14
- componentId: "sc-kdvgj9-2"
14
+ componentId: "sc-1l3r9n8-2"
15
15
  })(["border:1px solid ", ";border-radius:", ";box-shadow:", ";background-color:", ";"], Color.FORM, ShapeRadius.CONTROL, Shadow.REGULAR, Color.FROZEN);
16
16
  const transforms = {
17
17
  left: 'scaleX(-1)',
@@ -23,7 +23,7 @@ export const Arrow = styled(Horizontal).attrs({
23
23
  $placeItems: 'center'
24
24
  }).withConfig({
25
25
  displayName: "Arrow",
26
- componentId: "sc-kdvgj9-3"
26
+ componentId: "sc-1l3r9n8-3"
27
27
  })(["position:absolute;width:20px;height:20px;transform:", " translateX(11px);", ":0;"], ({
28
28
  $direction
29
29
  }) => transforms[$direction], ({
@@ -4,7 +4,7 @@ import { Slate } from 'slate-react';
4
4
  import { usePersistentFunction } from '@pushwoosh/kit-helpers';
5
5
  import { renderElement } from './DynamicContentElement';
6
6
  import { content2string, string2content } from './helpers';
7
- import { EditableStyled } from './SlateEditor.styled';
7
+ import { EditableStyled } from './SlateEditor.styles';
8
8
  import { createMKEditor } from './SlateEditor.utils';
9
9
  export const SlateEditor = ({
10
10
  initialValue: initialValueString,
@@ -3,7 +3,7 @@ import styled from 'styled-components';
3
3
  import { Color, FontSize, FontWeight, ShapeRadius } from '@pushwoosh/kit-constants';
4
4
  export const EditableStyled = styled(Editable).withConfig({
5
5
  displayName: "EditableStyled",
6
- componentId: "sc-1frhl1f-0"
6
+ componentId: "sc-13jikil-0"
7
7
  })(["font-weight:", ";font-size:", ";line-height:140%;padding:8px;color:", ";background:", ";caret-color:", ";border:1px solid ", ";border-radius:", ";overflow-x:auto;& [data-slate-placeholder='true']{color:", ";opacity:1 !important;}&:focus{border-color:", ";outline:none;}& > p{position:relative;margin:4px 0;&:first-child{margin-top:0;}&:last-child{margin-bottom:0;}}"], FontWeight.REGULAR, FontSize.REGULAR, Color.MAIN, Color.CLEAR, Color.BRIGHT, ({
8
8
  $isErrored
9
9
  }) => $isErrored ? Color.DANGER : Color.FORM, ShapeRadius.CONTROL, Color.PHANTOM, Color.BRIGHT);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pushwoosh/dumb-components",
3
- "version": "2.8.2",
3
+ "version": "2.9.1",
4
4
  "description": "React components to build Pushwoosh products",
5
5
  "main": "index.js",
6
6
  "module": "index.js",
@@ -72,6 +72,35 @@ describe('filters', () => {
72
72
  expect(filters.pluralize('not a number', [scalar('a'), scalar('b')], createContext())).toBe('not a number');
73
73
  });
74
74
  });
75
+ describe('pluralize with CLDR forms', () => {
76
+ const arabic = ['صفر', 'صف', 'صفان', 'صفوف', 'صفًا', 'صف*'].map(scalar);
77
+ test('picks each of the six Arabic forms', () => {
78
+ const ctx = createContext('ar');
79
+ expect(filters.pluralize(0, arabic, ctx)).toBe('صفر');
80
+ expect(filters.pluralize(1, arabic, ctx)).toBe('صف');
81
+ expect(filters.pluralize(2, arabic, ctx)).toBe('صفان');
82
+ expect(filters.pluralize(3, arabic, ctx)).toBe('صفوف');
83
+ expect(filters.pluralize(10, arabic, ctx)).toBe('صفوف');
84
+ expect(filters.pluralize(11, arabic, ctx)).toBe('صفًا');
85
+ expect(filters.pluralize(99, arabic, ctx)).toBe('صفًا');
86
+ expect(filters.pluralize(100, arabic, ctx)).toBe('صف*');
87
+ expect(filters.pluralize(103, arabic, ctx)).toBe('صفوف');
88
+ });
89
+ test('keeps the legacy one/other split when fewer forms are given', () => {
90
+ const ctx = createContext('ar');
91
+ expect(filters.pluralize(1, [scalar('صف'), scalar('صفوف')], ctx)).toBe('صف');
92
+ expect(filters.pluralize(0, [scalar('صف'), scalar('صفوف')], ctx)).toBe('صفوف');
93
+ expect(filters.pluralize(2, [scalar('صف'), scalar('صفوف')], ctx)).toBe('صفوف');
94
+ });
95
+ test('Russian three-form rule matches CLDR one/few/many for integers', () => {
96
+ const ctx = createContext('ru');
97
+ const forms = [scalar('one'), scalar('few'), scalar('many')];
98
+ const rules = new Intl.PluralRules('ru');
99
+ for (let n = 0; n <= 1000; n += 1) {
100
+ expect(filters.pluralize(n, forms, ctx)).toBe(rules.select(n));
101
+ }
102
+ });
103
+ });
75
104
  describe('formatNumber', () => {
76
105
  test('formats integer with spaces', () => {
77
106
  expect(filters.formatNumber('1000000', [], createContext())).toBe('1 000 000');
@@ -15,6 +15,20 @@ const pluralizers = {
15
15
  de: universalPluralize,
16
16
  es: universalPluralize
17
17
  };
18
+ const CLDR_CATEGORY_ORDER = ['zero', 'one', 'two', 'few', 'many', 'other'];
19
+ const cldrPluralize = (language, num, plurals) => {
20
+ let rules;
21
+ try {
22
+ rules = new Intl.PluralRules(language);
23
+ } catch {
24
+ return undefined;
25
+ }
26
+ const categories = CLDR_CATEGORY_ORDER.filter(c => rules.resolvedOptions().pluralCategories.includes(c));
27
+ if (categories.length < 2 || plurals.length < categories.length) {
28
+ return undefined;
29
+ }
30
+ return plurals[categories.indexOf(rules.select(num))];
31
+ };
18
32
  export const filters = {
19
33
  capitalize: value => typeof value === 'string' ? value.charAt(0).toUpperCase() + value.slice(1) : value,
20
34
  upperCase: value => typeof value === 'string' ? value.toUpperCase() : value,
@@ -24,6 +38,10 @@ export const filters = {
24
38
  return value;
25
39
  }
26
40
  const variants = args.map(arg => unpackScalarOrValue(arg, context));
41
+ const cldr = cldrPluralize(context.language, value, variants);
42
+ if (cldr !== undefined) {
43
+ return cldr;
44
+ }
27
45
  const pluralizer = pluralizers[context.language] || universalPluralize;
28
46
  return pluralizer(value, variants);
29
47
  },
File without changes