@octanejs/select 0.1.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.
@@ -0,0 +1,26 @@
1
+ export { useCreatable } from './use-creatable.tsrx';
2
+ export type { Accessors, CreatableAdditionalProps } from './use-creatable.tsrx';
3
+
4
+ import { Select, type SelectProps } from './select.tsrx';
5
+ import {
6
+ useCreatable,
7
+ type CreatableAdditionalProps,
8
+ type CreatableBaseProps,
9
+ } from './use-creatable.tsrx';
10
+ import { useStateManager, type StateManagerProps } from './use-state-manager.tsrx';
11
+ import type { GroupBase } from './types';
12
+
13
+ export type CreatableProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>> =
14
+ StateManagerProps<Option, IsMulti, Group> & CreatableAdditionalProps<Option, Group>;
15
+
16
+ function CreatableSelect<
17
+ Option = unknown,
18
+ IsMulti extends boolean = false,
19
+ Group extends GroupBase<Option> = GroupBase<Option>,
20
+ >(props: CreatableProps<Option, IsMulti, Group>) @{
21
+ const stateProps = useStateManager<Option, IsMulti, Group>(props);
22
+ const creatableProps = useCreatable(stateProps as CreatableBaseProps<Option, IsMulti, Group>);
23
+ <Select {...creatableProps as SelectProps<Option, IsMulti, Group>} />
24
+ }
25
+
26
+ export default CreatableSelect;
@@ -0,0 +1,445 @@
1
+ import type { CSSObjectWithLabel, Theme } from './types';
2
+
3
+ type Themed = { theme: Theme };
4
+ type Disabled = { isDisabled: boolean };
5
+ type Focused = { isFocused: boolean };
6
+
7
+ export const clearIndicatorCSS = indicatorCSS;
8
+
9
+ export function containerCSS(props: Disabled & { isRtl: boolean }): CSSObjectWithLabel {
10
+ return {
11
+ label: 'container',
12
+ direction: props.isRtl ? 'rtl' : undefined,
13
+ pointerEvents: props.isDisabled ? 'none' : undefined,
14
+ position: 'relative',
15
+ };
16
+ }
17
+
18
+ export function controlCSS(
19
+ props: Themed & Disabled & Focused,
20
+ unstyled: boolean,
21
+ ): CSSObjectWithLabel {
22
+ const { colors, borderRadius, spacing } = props.theme;
23
+ return {
24
+ label: 'control',
25
+ alignItems: 'center',
26
+ cursor: 'default',
27
+ display: 'flex',
28
+ flexWrap: 'wrap',
29
+ justifyContent: 'space-between',
30
+ minHeight: spacing.controlHeight,
31
+ outline: '0 !important',
32
+ position: 'relative',
33
+ transition: 'all 100ms',
34
+ ...(unstyled
35
+ ? {}
36
+ : {
37
+ backgroundColor: props.isDisabled ? colors.neutral5 : colors.neutral0,
38
+ borderColor: props.isDisabled
39
+ ? colors.neutral10
40
+ : props.isFocused
41
+ ? colors.primary
42
+ : colors.neutral20,
43
+ borderRadius,
44
+ borderStyle: 'solid',
45
+ borderWidth: 1,
46
+ boxShadow: props.isFocused ? `0 0 0 1px ${colors.primary}` : undefined,
47
+ '&:hover': {
48
+ borderColor: props.isFocused ? colors.primary : colors.neutral30,
49
+ },
50
+ }),
51
+ };
52
+ }
53
+
54
+ export const dropdownIndicatorCSS = indicatorCSS;
55
+
56
+ function indicatorCSS(props: Themed & Focused, unstyled: boolean): CSSObjectWithLabel {
57
+ const { baseUnit } = props.theme.spacing;
58
+ const { colors } = props.theme;
59
+ return {
60
+ label: 'indicatorContainer',
61
+ display: 'flex',
62
+ transition: 'color 150ms',
63
+ ...(unstyled
64
+ ? {}
65
+ : {
66
+ color: props.isFocused ? colors.neutral60 : colors.neutral20,
67
+ padding: baseUnit * 2,
68
+ ':hover': {
69
+ color: props.isFocused ? colors.neutral80 : colors.neutral40,
70
+ },
71
+ }),
72
+ };
73
+ }
74
+
75
+ export function groupCSS(props: Themed, unstyled: boolean): CSSObjectWithLabel {
76
+ return unstyled
77
+ ? {}
78
+ : {
79
+ paddingBottom: props.theme.spacing.baseUnit * 2,
80
+ paddingTop: props.theme.spacing.baseUnit * 2,
81
+ };
82
+ }
83
+
84
+ export function groupHeadingCSS(props: Themed, unstyled: boolean): CSSObjectWithLabel {
85
+ const { colors, spacing } = props.theme;
86
+ return {
87
+ label: 'group',
88
+ cursor: 'default',
89
+ display: 'block',
90
+ ...(unstyled
91
+ ? {}
92
+ : {
93
+ color: colors.neutral40,
94
+ fontSize: '75%',
95
+ fontWeight: 500,
96
+ marginBottom: '0.25em',
97
+ paddingLeft: spacing.baseUnit * 3,
98
+ paddingRight: spacing.baseUnit * 3,
99
+ textTransform: 'uppercase',
100
+ }),
101
+ };
102
+ }
103
+
104
+ export function indicatorsContainerCSS(): CSSObjectWithLabel {
105
+ return { alignItems: 'center', alignSelf: 'stretch', display: 'flex', flexShrink: 0 };
106
+ }
107
+
108
+ export function indicatorSeparatorCSS(
109
+ props: Themed & Disabled,
110
+ unstyled: boolean,
111
+ ): CSSObjectWithLabel {
112
+ const { baseUnit } = props.theme.spacing;
113
+ const { colors } = props.theme;
114
+ return {
115
+ label: 'indicatorSeparator',
116
+ alignSelf: 'stretch',
117
+ width: 1,
118
+ ...(unstyled
119
+ ? {}
120
+ : {
121
+ backgroundColor: props.isDisabled ? colors.neutral10 : colors.neutral20,
122
+ marginBottom: baseUnit * 2,
123
+ marginTop: baseUnit * 2,
124
+ }),
125
+ };
126
+ }
127
+
128
+ const spacingStyle = {
129
+ gridArea: '1 / 2',
130
+ font: 'inherit',
131
+ minWidth: '2px',
132
+ border: 0,
133
+ margin: 0,
134
+ outline: 0,
135
+ padding: 0,
136
+ } as const;
137
+
138
+ const inputContainerStyle = {
139
+ flex: '1 1 auto',
140
+ display: 'inline-grid',
141
+ gridArea: '1 / 1 / 2 / 3',
142
+ gridTemplateColumns: '0 min-content',
143
+ '&:after': {
144
+ content: 'attr(data-value) " "',
145
+ visibility: 'hidden',
146
+ whiteSpace: 'pre',
147
+ ...spacingStyle,
148
+ },
149
+ } as const;
150
+
151
+ export function inputCSS(
152
+ props: Themed & { isDisabled?: boolean; value?: unknown },
153
+ unstyled: boolean,
154
+ ): CSSObjectWithLabel {
155
+ const { spacing, colors } = props.theme;
156
+ return {
157
+ visibility: props.isDisabled ? 'hidden' : 'visible',
158
+ transform: props.value ? 'translateZ(0)' : '',
159
+ ...inputContainerStyle,
160
+ ...(unstyled
161
+ ? {}
162
+ : {
163
+ margin: spacing.baseUnit / 2,
164
+ paddingBottom: spacing.baseUnit / 2,
165
+ paddingTop: spacing.baseUnit / 2,
166
+ color: colors.neutral80,
167
+ }),
168
+ };
169
+ }
170
+
171
+ export function loadingIndicatorCSS(
172
+ props: Themed & Focused & { size: number },
173
+ unstyled: boolean,
174
+ ): CSSObjectWithLabel {
175
+ const { colors, spacing } = props.theme;
176
+ return {
177
+ label: 'loadingIndicator',
178
+ display: 'flex',
179
+ transition: 'color 150ms',
180
+ alignSelf: 'center',
181
+ fontSize: props.size,
182
+ lineHeight: 1,
183
+ marginRight: props.size,
184
+ textAlign: 'center',
185
+ verticalAlign: 'middle',
186
+ ...(unstyled
187
+ ? {}
188
+ : {
189
+ color: props.isFocused ? colors.neutral60 : colors.neutral20,
190
+ padding: spacing.baseUnit * 2,
191
+ }),
192
+ };
193
+ }
194
+
195
+ function noticeCSS(props: Themed, unstyled: boolean): CSSObjectWithLabel {
196
+ const { baseUnit } = props.theme.spacing;
197
+ return {
198
+ textAlign: 'center',
199
+ ...(unstyled
200
+ ? {}
201
+ : {
202
+ color: props.theme.colors.neutral40,
203
+ padding: `${baseUnit * 2}px ${baseUnit * 3}px`,
204
+ }),
205
+ };
206
+ }
207
+
208
+ export const loadingMessageCSS = noticeCSS;
209
+
210
+ export function menuCSS(
211
+ props: Themed & { placement: 'bottom' | 'top' },
212
+ unstyled: boolean,
213
+ ): CSSObjectWithLabel {
214
+ const { borderRadius, spacing, colors } = props.theme;
215
+ return {
216
+ label: 'menu',
217
+ [props.placement === 'bottom' ? 'top' : 'bottom']: '100%',
218
+ position: 'absolute',
219
+ width: '100%',
220
+ zIndex: 1,
221
+ ...(unstyled
222
+ ? {}
223
+ : {
224
+ backgroundColor: colors.neutral0,
225
+ borderRadius,
226
+ boxShadow: '0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1)',
227
+ marginBottom: spacing.menuGutter,
228
+ marginTop: spacing.menuGutter,
229
+ }),
230
+ };
231
+ }
232
+
233
+ export function menuListCSS(
234
+ props: Themed & { maxHeight: number },
235
+ unstyled: boolean,
236
+ ): CSSObjectWithLabel {
237
+ return {
238
+ maxHeight: props.maxHeight,
239
+ overflowY: 'auto',
240
+ position: 'relative',
241
+ WebkitOverflowScrolling: 'touch',
242
+ ...(unstyled
243
+ ? {}
244
+ : {
245
+ paddingBottom: props.theme.spacing.baseUnit,
246
+ paddingTop: props.theme.spacing.baseUnit,
247
+ }),
248
+ };
249
+ }
250
+
251
+ export function menuPortalCSS(props: {
252
+ offset: number;
253
+ position: 'absolute' | 'fixed';
254
+ rect: { left: number; width: number };
255
+ }): CSSObjectWithLabel {
256
+ return {
257
+ left: props.rect.left,
258
+ position: props.position,
259
+ top: props.offset,
260
+ width: props.rect.width,
261
+ zIndex: 1,
262
+ };
263
+ }
264
+
265
+ export function multiValueCSS(props: Themed, unstyled: boolean): CSSObjectWithLabel {
266
+ const { spacing, borderRadius, colors } = props.theme;
267
+ return {
268
+ label: 'multiValue',
269
+ display: 'flex',
270
+ minWidth: 0,
271
+ ...(unstyled
272
+ ? {}
273
+ : {
274
+ backgroundColor: colors.neutral10,
275
+ borderRadius: borderRadius / 2,
276
+ margin: spacing.baseUnit / 2,
277
+ }),
278
+ };
279
+ }
280
+
281
+ export function multiValueLabelCSS(
282
+ props: Themed & { cropWithEllipsis?: boolean },
283
+ unstyled: boolean,
284
+ ): CSSObjectWithLabel {
285
+ const { borderRadius, colors } = props.theme;
286
+ return {
287
+ overflow: 'hidden',
288
+ textOverflow:
289
+ props.cropWithEllipsis || props.cropWithEllipsis === undefined ? 'ellipsis' : undefined,
290
+ whiteSpace: 'nowrap',
291
+ ...(unstyled
292
+ ? {}
293
+ : {
294
+ borderRadius: borderRadius / 2,
295
+ color: colors.neutral80,
296
+ fontSize: '85%',
297
+ padding: 3,
298
+ paddingLeft: 6,
299
+ }),
300
+ };
301
+ }
302
+
303
+ export function multiValueRemoveCSS(
304
+ props: Themed & Focused,
305
+ unstyled: boolean,
306
+ ): CSSObjectWithLabel {
307
+ const { spacing, borderRadius, colors } = props.theme;
308
+ return {
309
+ alignItems: 'center',
310
+ display: 'flex',
311
+ ...(unstyled
312
+ ? {}
313
+ : {
314
+ borderRadius: borderRadius / 2,
315
+ backgroundColor: props.isFocused ? colors.dangerLight : undefined,
316
+ paddingLeft: spacing.baseUnit,
317
+ paddingRight: spacing.baseUnit,
318
+ ':hover': { backgroundColor: colors.dangerLight, color: colors.danger },
319
+ }),
320
+ };
321
+ }
322
+
323
+ export const noOptionsMessageCSS = noticeCSS;
324
+
325
+ export function optionCSS(
326
+ props: Themed & Disabled & Focused & { isSelected: boolean },
327
+ unstyled: boolean,
328
+ ): CSSObjectWithLabel {
329
+ const { spacing, colors } = props.theme;
330
+ return {
331
+ label: 'option',
332
+ cursor: 'default',
333
+ display: 'block',
334
+ fontSize: 'inherit',
335
+ width: '100%',
336
+ userSelect: 'none',
337
+ WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)',
338
+ ...(unstyled
339
+ ? {}
340
+ : {
341
+ backgroundColor: props.isSelected
342
+ ? colors.primary
343
+ : props.isFocused
344
+ ? colors.primary25
345
+ : 'transparent',
346
+ color: props.isDisabled
347
+ ? colors.neutral20
348
+ : props.isSelected
349
+ ? colors.neutral0
350
+ : 'inherit',
351
+ padding: `${spacing.baseUnit * 2}px ${spacing.baseUnit * 3}px`,
352
+ ':active': {
353
+ backgroundColor: !props.isDisabled
354
+ ? props.isSelected
355
+ ? colors.primary
356
+ : colors.primary50
357
+ : undefined,
358
+ },
359
+ }),
360
+ };
361
+ }
362
+
363
+ export function placeholderCSS(props: Themed, unstyled: boolean): CSSObjectWithLabel {
364
+ const { spacing, colors } = props.theme;
365
+ return {
366
+ label: 'placeholder',
367
+ gridArea: '1 / 1 / 2 / 3',
368
+ ...(unstyled
369
+ ? {}
370
+ : {
371
+ color: colors.neutral50,
372
+ marginLeft: spacing.baseUnit / 2,
373
+ marginRight: spacing.baseUnit / 2,
374
+ }),
375
+ };
376
+ }
377
+
378
+ export function singleValueCSS(props: Themed & Disabled, unstyled: boolean): CSSObjectWithLabel {
379
+ const { spacing, colors } = props.theme;
380
+ return {
381
+ label: 'singleValue',
382
+ gridArea: '1 / 1 / 2 / 3',
383
+ maxWidth: '100%',
384
+ overflow: 'hidden',
385
+ textOverflow: 'ellipsis',
386
+ whiteSpace: 'nowrap',
387
+ ...(unstyled
388
+ ? {}
389
+ : {
390
+ color: props.isDisabled ? colors.neutral40 : colors.neutral80,
391
+ marginLeft: spacing.baseUnit / 2,
392
+ marginRight: spacing.baseUnit / 2,
393
+ }),
394
+ };
395
+ }
396
+
397
+ export function valueContainerCSS(
398
+ props: Themed & {
399
+ isMulti: boolean;
400
+ hasValue: boolean;
401
+ selectProps: { controlShouldRenderValue: boolean };
402
+ },
403
+ unstyled: boolean,
404
+ ): CSSObjectWithLabel {
405
+ return {
406
+ alignItems: 'center',
407
+ display:
408
+ props.isMulti && props.hasValue && props.selectProps.controlShouldRenderValue
409
+ ? 'flex'
410
+ : 'grid',
411
+ flex: 1,
412
+ flexWrap: 'wrap',
413
+ WebkitOverflowScrolling: 'touch',
414
+ position: 'relative',
415
+ overflow: 'hidden',
416
+ ...(unstyled
417
+ ? {}
418
+ : { padding: `${props.theme.spacing.baseUnit / 2}px ${props.theme.spacing.baseUnit * 2}px` }),
419
+ };
420
+ }
421
+
422
+ export const defaultStyles = {
423
+ clearIndicator: clearIndicatorCSS,
424
+ container: containerCSS,
425
+ control: controlCSS,
426
+ dropdownIndicator: dropdownIndicatorCSS,
427
+ group: groupCSS,
428
+ groupHeading: groupHeadingCSS,
429
+ indicatorsContainer: indicatorsContainerCSS,
430
+ indicatorSeparator: indicatorSeparatorCSS,
431
+ input: inputCSS,
432
+ loadingIndicator: loadingIndicatorCSS,
433
+ loadingMessage: loadingMessageCSS,
434
+ menu: menuCSS,
435
+ menuList: menuListCSS,
436
+ menuPortal: menuPortalCSS,
437
+ multiValue: multiValueCSS,
438
+ multiValueLabel: multiValueLabelCSS,
439
+ multiValueRemove: multiValueRemoveCSS,
440
+ noOptionsMessage: noOptionsMessageCSS,
441
+ option: optionCSS,
442
+ placeholder: placeholderCSS,
443
+ singleValue: singleValueCSS,
444
+ valueContainer: valueContainerCSS,
445
+ };
@@ -0,0 +1,245 @@
1
+ const diacritics = [
2
+ {
3
+ base: 'A',
4
+ letters:
5
+ '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
6
+ },
7
+ { base: 'AA', letters: '\uA732' },
8
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
9
+ { base: 'AO', letters: '\uA734' },
10
+ { base: 'AU', letters: '\uA736' },
11
+ { base: 'AV', letters: '\uA738\uA73A' },
12
+ { base: 'AY', letters: '\uA73C' },
13
+ {
14
+ base: 'B',
15
+ letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
16
+ },
17
+ {
18
+ base: 'C',
19
+ letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
20
+ },
21
+ {
22
+ base: 'D',
23
+ letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779',
24
+ },
25
+ { base: 'DZ', letters: '\u01F1\u01C4' },
26
+ { base: 'Dz', letters: '\u01F2\u01C5' },
27
+ {
28
+ base: 'E',
29
+ letters:
30
+ '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
31
+ },
32
+ { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
33
+ {
34
+ base: 'G',
35
+ letters:
36
+ '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
37
+ },
38
+ {
39
+ base: 'H',
40
+ letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
41
+ },
42
+ {
43
+ base: 'I',
44
+ letters:
45
+ '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
46
+ },
47
+ { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
48
+ {
49
+ base: 'K',
50
+ letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
51
+ },
52
+ {
53
+ base: 'L',
54
+ letters:
55
+ '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
56
+ },
57
+ { base: 'LJ', letters: '\u01C7' },
58
+ { base: 'Lj', letters: '\u01C8' },
59
+ { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
60
+ {
61
+ base: 'N',
62
+ letters:
63
+ '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
64
+ },
65
+ { base: 'NJ', letters: '\u01CA' },
66
+ { base: 'Nj', letters: '\u01CB' },
67
+ {
68
+ base: 'O',
69
+ letters:
70
+ '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
71
+ },
72
+ { base: 'OI', letters: '\u01A2' },
73
+ { base: 'OO', letters: '\uA74E' },
74
+ { base: 'OU', letters: '\u0222' },
75
+ {
76
+ base: 'P',
77
+ letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
78
+ },
79
+ { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
80
+ {
81
+ base: 'R',
82
+ letters:
83
+ '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
84
+ },
85
+ {
86
+ base: 'S',
87
+ letters:
88
+ '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
89
+ },
90
+ {
91
+ base: 'T',
92
+ letters:
93
+ '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
94
+ },
95
+ { base: 'TZ', letters: '\uA728' },
96
+ {
97
+ base: 'U',
98
+ letters:
99
+ '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
100
+ },
101
+ { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
102
+ { base: 'VY', letters: '\uA760' },
103
+ {
104
+ base: 'W',
105
+ letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
106
+ },
107
+ { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
108
+ {
109
+ base: 'Y',
110
+ letters:
111
+ '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
112
+ },
113
+ {
114
+ base: 'Z',
115
+ letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
116
+ },
117
+ {
118
+ base: 'a',
119
+ letters:
120
+ '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
121
+ },
122
+ { base: 'aa', letters: '\uA733' },
123
+ { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
124
+ { base: 'ao', letters: '\uA735' },
125
+ { base: 'au', letters: '\uA737' },
126
+ { base: 'av', letters: '\uA739\uA73B' },
127
+ { base: 'ay', letters: '\uA73D' },
128
+ {
129
+ base: 'b',
130
+ letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
131
+ },
132
+ {
133
+ base: 'c',
134
+ letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
135
+ },
136
+ {
137
+ base: 'd',
138
+ letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
139
+ },
140
+ { base: 'dz', letters: '\u01F3\u01C6' },
141
+ {
142
+ base: 'e',
143
+ letters:
144
+ '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
145
+ },
146
+ { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
147
+ {
148
+ base: 'g',
149
+ letters:
150
+ '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
151
+ },
152
+ {
153
+ base: 'h',
154
+ letters:
155
+ '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
156
+ },
157
+ { base: 'hv', letters: '\u0195' },
158
+ {
159
+ base: 'i',
160
+ letters:
161
+ '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
162
+ },
163
+ { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
164
+ {
165
+ base: 'k',
166
+ letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
167
+ },
168
+ {
169
+ base: 'l',
170
+ letters:
171
+ '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
172
+ },
173
+ { base: 'lj', letters: '\u01C9' },
174
+ { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
175
+ {
176
+ base: 'n',
177
+ letters:
178
+ '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
179
+ },
180
+ { base: 'nj', letters: '\u01CC' },
181
+ {
182
+ base: 'o',
183
+ letters:
184
+ '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
185
+ },
186
+ { base: 'oi', letters: '\u01A3' },
187
+ { base: 'ou', letters: '\u0223' },
188
+ { base: 'oo', letters: '\uA74F' },
189
+ {
190
+ base: 'p',
191
+ letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
192
+ },
193
+ { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
194
+ {
195
+ base: 'r',
196
+ letters:
197
+ '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
198
+ },
199
+ {
200
+ base: 's',
201
+ letters:
202
+ '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
203
+ },
204
+ {
205
+ base: 't',
206
+ letters:
207
+ '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
208
+ },
209
+ { base: 'tz', letters: '\uA729' },
210
+ {
211
+ base: 'u',
212
+ letters:
213
+ '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
214
+ },
215
+ { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
216
+ { base: 'vy', letters: '\uA761' },
217
+ {
218
+ base: 'w',
219
+ letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
220
+ },
221
+ { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
222
+ {
223
+ base: 'y',
224
+ letters:
225
+ '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
226
+ },
227
+ {
228
+ base: 'z',
229
+ letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
230
+ },
231
+ ];
232
+
233
+ const anyDiacritic = new RegExp('[' + diacritics.map((d) => d.letters).join('') + ']', 'g');
234
+ const diacriticToBase: { [letters: string]: string } = {};
235
+
236
+ for (let i = 0; i < diacritics.length; i++) {
237
+ let diacritic = diacritics[i];
238
+ for (let j = 0; j < diacritic.letters.length; j++) {
239
+ diacriticToBase[diacritic.letters[j]] = diacritic.base;
240
+ }
241
+ }
242
+
243
+ export const stripDiacritics = (str: string) => {
244
+ return str.replace(anyDiacritic, (match) => diacriticToBase[match]);
245
+ };