@sincpro/mobile-ui 3.0.1 → 3.2.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/dist/Actions/Actions.Button.d.ts +6 -6
- package/dist/Actions/Actions.Button.js +650 -180
- package/dist/Actions/Actions.Dock.d.ts +1 -1
- package/dist/Actions/Actions.Dock.js +297 -18
- package/dist/Actions/Actions.FAB.js +100 -12
- package/dist/Actions/Actions.FilterButton.d.ts +17 -0
- package/dist/Actions/Actions.FilterButton.js +263 -33
- package/dist/Actions/Actions.IconButton.d.ts +1 -0
- package/dist/Actions/Actions.IconButton.js +196 -33
- package/dist/Actions/index.js +13 -13
- package/dist/Dialog/Confirmation.context.js +82 -16
- package/dist/Dialog/Dialog.ActionSheet.js +200 -41
- package/dist/Dialog/Dialog.Confirmation.js +168 -31
- package/dist/Dialog/Dialog.EditValue.js +437 -62
- package/dist/Dialog/Dialog.Sheet.d.ts +7 -3
- package/dist/Dialog/Dialog.Sheet.js +267 -15
- package/dist/Dialog/OverlayHost.d.ts +24 -0
- package/dist/Dialog/OverlayHost.js +230 -0
- package/dist/Dialog/SheetSurface.d.ts +43 -0
- package/dist/Dialog/SheetSurface.js +495 -0
- package/dist/Dialog/dialog-actions.d.ts +17 -0
- package/dist/Dialog/dialog-actions.js +59 -0
- package/dist/Dialog/index.d.ts +4 -1
- package/dist/Dialog/index.js +8 -7
- package/dist/Dialog/overlay.store.d.ts +24 -0
- package/dist/Dialog/overlay.store.js +59 -0
- package/dist/Dialog/requestConfirmation.js +20 -10
- package/dist/Display/Display.Accordion.js +185 -13
- package/dist/Display/Display.AmountSummary.js +206 -15
- package/dist/Display/Display.Avatar.js +93 -31
- package/dist/Display/Display.AvatarGroup.js +132 -17
- package/dist/Display/Display.Badge.d.ts +18 -2
- package/dist/Display/Display.Badge.js +117 -49
- package/dist/Display/Display.Card.js +163 -26
- package/dist/Display/Display.Carousel.js +459 -105
- package/dist/Display/Display.Chip.d.ts +4 -1
- package/dist/Display/Display.Chip.js +165 -31
- package/dist/Display/Display.CircleButton.d.ts +1 -0
- package/dist/Display/Display.CircleButton.js +86 -27
- package/dist/Display/Display.CopyableText.js +289 -66
- package/dist/Display/Display.CountRecords.js +60 -3
- package/dist/Display/Display.DataTable.js +123 -13
- package/dist/Display/Display.Date.js +243 -33
- package/dist/Display/Display.Divider.d.ts +10 -10
- package/dist/Display/Display.Divider.js +67 -20
- package/dist/Display/Display.ExpoImage.js +97 -8
- package/dist/Display/Display.GradientSurface.d.ts +9 -4
- package/dist/Display/Display.GradientSurface.js +196 -46
- package/dist/Display/Display.Icon.js +129 -15
- package/dist/Display/Display.IconBadge.js +95 -25
- package/dist/Display/Display.Image.d.ts +7 -1
- package/dist/Display/Display.Image.js +344 -39
- package/dist/Display/Display.KeyValue.js +90 -5
- package/dist/Display/Display.ListGroup.js +181 -9
- package/dist/Display/Display.ListItem.js +324 -28
- package/dist/Display/Display.Logo.js +84 -29
- package/dist/Display/Display.MediaCard.js +125 -4
- package/dist/Display/Display.MediaEmbed.d.ts +0 -5
- package/dist/Display/Display.MediaEmbed.js +170 -26
- package/dist/Display/Display.MenuButton.d.ts +2 -2
- package/dist/Display/Display.MenuButton.js +380 -94
- package/dist/Display/Display.MenuCard.js +122 -18
- package/dist/Display/Display.MenuGrid.js +43 -3
- package/dist/Display/Display.Monetary.js +90 -5
- package/dist/Display/Display.Pattern.js +306 -47
- package/dist/Display/Display.PriceTag.js +117 -14
- package/dist/Display/Display.ProductCard.js +154 -4
- package/dist/Display/Display.Rating.js +92 -11
- package/dist/Display/Display.SearchHistory.js +132 -6
- package/dist/Display/Display.SectionHeader.d.ts +5 -1
- package/dist/Display/Display.SectionHeader.js +125 -12
- package/dist/Display/Display.Stat.js +62 -3
- package/dist/Display/Display.StatCard.js +131 -7
- package/dist/Display/Display.StatusBadge.d.ts +29 -0
- package/dist/Display/Display.StatusBadge.js +68 -0
- package/dist/Display/Display.StatusDot.js +93 -18
- package/dist/Display/Display.Story.js +285 -35
- package/dist/Display/Display.StoryTray.js +354 -34
- package/dist/Display/Display.StoryViewer.js +571 -72
- package/dist/Display/Display.SwipeableRow.js +148 -20
- package/dist/Display/Display.Tag.d.ts +4 -1
- package/dist/Display/Display.Tag.js +66 -4
- package/dist/Display/Display.Timeline.js +102 -13
- package/dist/Display/Display.Tooltip.js +122 -26
- package/dist/Display/chevron.d.ts +6 -0
- package/dist/Display/chevron.js +32 -0
- package/dist/Display/count-badge.d.ts +21 -0
- package/dist/Display/count-badge.js +124 -0
- package/dist/Display/group-title.d.ts +10 -0
- package/dist/Display/group-title.js +53 -0
- package/dist/Display/icon-font.d.ts +3 -0
- package/dist/Display/icon-font.ios.d.ts +3 -0
- package/dist/Display/icon-font.ios.js +4 -0
- package/dist/Display/icon-font.js +7 -0
- package/dist/Display/icon-glyphs.d.ts +2 -0
- package/dist/Display/icon-glyphs.js +87 -0
- package/dist/Display/icon-map.d.ts +15 -11
- package/dist/Display/icon-map.js +344 -84
- package/dist/Display/icon-registry.d.ts +21 -0
- package/dist/Display/icon-registry.js +21 -0
- package/dist/Display/index.d.ts +6 -1
- package/dist/Display/index.js +53 -48
- package/dist/Display/pill.d.ts +16 -0
- package/dist/Display/pill.js +47 -0
- package/dist/Feedback/ErrorBoundary.js +35 -23
- package/dist/Feedback/Feedback.Banner.js +202 -24
- package/dist/Feedback/Feedback.DomainSplashScreen.js +246 -70
- package/dist/Feedback/Feedback.Empty.js +54 -3
- package/dist/Feedback/Feedback.EmptyState.js +114 -5
- package/dist/Feedback/Feedback.Error.d.ts +1 -1
- package/dist/Feedback/Feedback.Error.js +130 -5
- package/dist/Feedback/Feedback.Loading.d.ts +1 -1
- package/dist/Feedback/Feedback.Loading.js +70 -3
- package/dist/Feedback/Feedback.PermissionCard.js +161 -5
- package/dist/Feedback/Feedback.Progress.js +199 -41
- package/dist/Feedback/Feedback.ProgressCircle.js +184 -12
- package/dist/Feedback/Feedback.Skeleton.js +149 -36
- package/dist/Feedback/Feedback.Spinner.js +407 -79
- package/dist/Feedback/Feedback.Splash.js +240 -33
- package/dist/Feedback/Feedback.State.d.ts +17 -0
- package/dist/Feedback/Feedback.State.js +104 -0
- package/dist/Feedback/Toast.context.js +883 -167
- package/dist/Feedback/index.d.ts +3 -0
- package/dist/Feedback/index.js +15 -13
- package/dist/Form/Form.Checkbox.js +212 -22
- package/dist/Form/Form.ControlledCheckbox.d.ts +1 -1
- package/dist/Form/Form.ControlledCheckbox.js +46 -4
- package/dist/Form/Form.ControlledDropdown.d.ts +1 -1
- package/dist/Form/Form.ControlledDropdown.js +62 -4
- package/dist/Form/Form.ControlledInput.d.ts +4 -3
- package/dist/Form/Form.ControlledInput.js +72 -4
- package/dist/Form/Form.ControlledMonetaryInput.d.ts +6 -3
- package/dist/Form/Form.ControlledMonetaryInput.js +50 -4
- package/dist/Form/Form.ControlledRadioButton.d.ts +2 -2
- package/dist/Form/Form.ControlledRadioButton.js +45 -4
- package/dist/Form/Form.DatePicker.js +507 -107
- package/dist/Form/Form.Dropdown.js +303 -52
- package/dist/Form/Form.ErrorSummary.js +236 -44
- package/dist/Form/Form.Field.d.ts +24 -0
- package/dist/Form/Form.Field.js +55 -0
- package/dist/Form/Form.FractionalQuantityInput.js +508 -96
- package/dist/Form/Form.Input.d.ts +17 -3
- package/dist/Form/Form.Input.js +497 -29
- package/dist/Form/Form.KeyboardForm.d.ts +22 -8
- package/dist/Form/Form.KeyboardForm.js +83 -8
- package/dist/Form/Form.KeyboardToolbarHost.d.ts +14 -0
- package/dist/Form/Form.KeyboardToolbarHost.js +223 -0
- package/dist/Form/Form.MonetaryInput.js +164 -17
- package/dist/Form/Form.PickerField.d.ts +31 -0
- package/dist/Form/Form.PickerField.js +539 -0
- package/dist/Form/Form.PinInput.js +150 -15
- package/dist/Form/Form.QuantitySelector.js +229 -25
- package/dist/Form/Form.RadioButton.d.ts +1 -0
- package/dist/Form/Form.RadioButton.js +26 -29
- package/dist/Form/Form.Select.d.ts +2 -1
- package/dist/Form/Form.Select.js +388 -60
- package/dist/Form/Form.Slider.js +133 -10
- package/dist/Form/Form.Switch.js +99 -4
- package/dist/Form/choice-row.d.ts +15 -0
- package/dist/Form/choice-row.js +236 -0
- package/dist/Form/index.d.ts +11 -6
- package/dist/Form/index.js +26 -27
- package/dist/Form/input-text.d.ts +7 -0
- package/dist/Form/input-text.js +18 -0
- package/dist/Navigation/Navigation.AppBar.d.ts +3 -4
- package/dist/Navigation/Navigation.AppBar.js +535 -99
- package/dist/Navigation/Navigation.BottomNav.js +363 -98
- package/dist/Navigation/Navigation.CollapsingHeader.d.ts +28 -13
- package/dist/Navigation/Navigation.CollapsingHeader.js +369 -36
- package/dist/Navigation/Navigation.FloatingBar.js +71 -11
- package/dist/Navigation/Navigation.Menu.js +309 -95
- package/dist/Navigation/Navigation.MenuSection.js +80 -11
- package/dist/Navigation/Navigation.RowItem.d.ts +4 -2
- package/dist/Navigation/Navigation.RowItem.js +93 -8
- package/dist/Navigation/Navigation.Search.js +241 -27
- package/dist/Navigation/Navigation.SearchBar.d.ts +7 -1
- package/dist/Navigation/Navigation.SearchBar.js +218 -29
- package/dist/Navigation/Navigation.SearchSuggestions.js +77 -3
- package/dist/Navigation/Navigation.SegmentedControl.js +152 -14
- package/dist/Navigation/Navigation.Steps.js +105 -11
- package/dist/Navigation/Navigation.Tabs.js +449 -41
- package/dist/Navigation/index.d.ts +9 -4
- package/dist/Navigation/index.js +13 -13
- package/dist/Typography/Typography.Heading.js +33 -3
- package/dist/Typography/Typography.SelectableText.js +95 -7
- package/dist/Typography/Typography.Text.d.ts +4 -2
- package/dist/Typography/Typography.Text.js +217 -7
- package/dist/Typography/index.js +3 -3
- package/dist/branding.js +29 -13
- package/dist/icons/AddItemIcon.js +76 -2
- package/dist/icons/ArrangeCircle.js +82 -2
- package/dist/icons/ArrowDownIcon.js +63 -3
- package/dist/icons/ArrowUpIcon.js +63 -3
- package/dist/icons/BoxIcon.js +64 -2
- package/dist/icons/BoxTimeIcon.js +63 -2
- package/dist/icons/CalendarIcon.js +145 -2
- package/dist/icons/CardIcon.js +80 -2
- package/dist/icons/CashierIcon.js +39 -2
- package/dist/icons/CreditIcon.js +76 -3
- package/dist/icons/DuoIcon.js +75 -2
- package/dist/icons/HomeIcon.js +39 -2
- package/dist/icons/HomeIconOutlined.js +53 -2
- package/dist/icons/LogoIcon.js +87 -2
- package/dist/icons/MoneyReceiveIcon.js +86 -2
- package/dist/icons/PinIcon.js +39 -2
- package/dist/icons/ProfileIcon.js +47 -2
- package/dist/icons/SettingsIcon.js +114 -2
- package/dist/icons/SinpeIcon.js +60 -2
- package/dist/icons/ToggleOffIcon.js +53 -2
- package/dist/icons/WalletMoneyIcon.js +81 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -2
- package/dist/layouts/AuthContainer.d.ts +4 -5
- package/dist/layouts/AuthContainer.js +231 -7
- package/dist/layouts/BottomInset.js +4 -1
- package/dist/layouts/Container.d.ts +2 -2
- package/dist/layouts/Container.js +45 -3
- package/dist/layouts/GradientContainer.js +37 -5
- package/dist/layouts/PlainLayout.js +19 -3
- package/dist/layouts/ScrollContainer.d.ts +14 -9
- package/dist/layouts/ScrollContainer.js +125 -4
- package/dist/layouts/edges.d.ts +2 -0
- package/dist/layouts/edges.js +1 -0
- package/dist/primitives/AspectRatio.js +75 -3
- package/dist/primitives/Box.js +45 -3
- package/dist/primitives/Pressable.js +95 -5
- package/dist/primitives/Row.js +84 -13
- package/dist/primitives/Spacer.js +42 -5
- package/dist/primitives/Stack.js +66 -7
- package/dist/primitives/index.js +1 -1
- package/dist/theme/active.d.ts +2 -0
- package/dist/theme/active.js +33 -18
- package/dist/theme/build.js +118 -87
- package/dist/theme/color.js +87 -87
- package/dist/theme/components/ThemedActivityIndicator.d.ts +2 -15
- package/dist/theme/components/ThemedActivityIndicator.js +35 -3
- package/dist/theme/components/index.js +1 -0
- package/dist/theme/contrast.js +32 -33
- package/dist/theme/css-vars.js +71 -75
- package/dist/theme/dark.js +116 -97
- package/dist/theme/default.js +116 -97
- package/dist/theme/define.js +16 -12
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.js +7 -6
- package/dist/theme/on-dark-surface.d.ts +12 -0
- package/dist/theme/on-dark-surface.js +13 -0
- package/dist/theme/theme.js +1 -0
- package/dist/theme/tw.js +3 -1
- package/dist/theme/types.js +0 -18
- package/dist/theme/typography.d.ts +1 -1
- package/dist/theme/typography.js +337 -303
- package/dist/theme/useTheme.d.ts +4 -0
- package/dist/theme/useTheme.js +7 -3
- package/dist/theme/useThemeVars.d.ts +9 -0
- package/dist/theme/useThemeVars.js +23 -0
- package/dist/theme/validate.js +175 -166
- package/dist/tokens/index.js +1 -1
- package/dist/tokens/motion.js +30 -13
- package/dist/utils/async.d.ts +14 -0
- package/dist/utils/async.js +22 -0
- package/dist/utils/criteria.js +66 -85
- package/dist/utils/date.d.ts +8 -2
- package/dist/utils/date.js +63 -50
- package/dist/utils/image.js +8 -8
- package/dist/utils/intl.d.ts +1 -0
- package/dist/utils/intl.js +13 -0
- package/dist/utils/keys.js +3 -5
- package/dist/utils/monetary.d.ts +1 -0
- package/dist/utils/monetary.js +28 -24
- package/dist/utils/progress.js +2 -3
- package/dist/utils/quantity.js +25 -26
- package/dist/utils/reorder.js +11 -20
- package/dist/utils/search.d.ts +4 -0
- package/dist/utils/search.js +12 -0
- package/dist/utils/serializer.js +38 -38
- package/dist/utils/useReducedMotion.js +32 -30
- package/dist/views/AppSplashView.js +117 -3
- package/dist/views/AuthFormView.d.ts +4 -5
- package/dist/views/AuthFormView.js +119 -11
- package/dist/views/FormViewV2.context.js +75 -23
- package/dist/views/FormViewV2.d.ts +4 -5
- package/dist/views/FormViewV2.js +658 -92
- package/dist/views/ListViewV2.context.js +91 -47
- package/dist/views/ListViewV2.d.ts +84 -43
- package/dist/views/ListViewV2.js +1350 -200
- package/dist/views/Wizard/Wizard.context.js +248 -84
- package/dist/views/Wizard/Wizard.js +260 -67
- package/dist/views/types/IListView.js +34 -31
- package/dist/widgets/CollectionOptions.js +557 -138
- package/dist/widgets/FilterBar.js +159 -7
- package/dist/widgets/FilterBuilder.js +375 -102
- package/dist/widgets/JSONViewer.js +275 -129
- package/dist/widgets/PromoBanner.js +336 -42
- package/dist/widgets/PromoModal.d.ts +2 -2
- package/dist/widgets/PromoModal.js +389 -62
- package/dist/widgets/QueryChoice.js +150 -8
- package/dist/widgets/QuickActions.js +120 -31
- package/dist/widgets/ReorderableList.js +399 -128
- package/dist/widgets/TimeZoneSelectorModal.js +458 -51
- package/dist/widgets/index.js +3 -3
- package/package.json +6 -1
- package/tailwind.preset.js +7 -5
- package/dist/Form/Form.InputField.d.ts +0 -10
- package/dist/Form/Form.InputField.js +0 -38
- package/dist/Form/Form.KeyboardToolbar.d.ts +0 -22
- package/dist/Form/Form.KeyboardToolbar.js +0 -66
- package/dist/Form/Form.PasswordInput.d.ts +0 -9
- package/dist/Form/Form.PasswordInput.js +0 -17
- package/dist/Form/Form.TextInput.d.ts +0 -8
- package/dist/Form/Form.TextInput.js +0 -8
- package/dist/primitives/BaseButton.d.ts +0 -150
- package/dist/primitives/BaseButton.js +0 -229
- package/dist/utils/useSheetTranslation.d.ts +0 -5
- package/dist/utils/useSheetTranslation.js +0 -23
package/dist/utils/criteria.js
CHANGED
|
@@ -1,99 +1,80 @@
|
|
|
1
1
|
export function parseCriteriaDate(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
return null;
|
|
7
|
-
return new Date(`${value}T12:00:00`);
|
|
2
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value)) return null;
|
|
3
|
+
const date = new Date(`${value}T00:00:00Z`);
|
|
4
|
+
if (!Number.isFinite(date.getTime()) || date.toISOString().slice(0, 10) !== value) return null;
|
|
5
|
+
return new Date(`${value}T12:00:00`);
|
|
8
6
|
}
|
|
9
7
|
export function criteriaAt(root, path) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return node;
|
|
8
|
+
let node = root;
|
|
9
|
+
for (const index of path) {
|
|
10
|
+
if (node.kind !== "group" || !node.children[index]) throw new Error("Invalid criteria path");
|
|
11
|
+
node = node.children[index];
|
|
12
|
+
}
|
|
13
|
+
return node;
|
|
17
14
|
}
|
|
18
15
|
export function replaceCriteria(root, path, replacement) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
: replacement;
|
|
33
|
-
return {
|
|
34
|
-
...root,
|
|
35
|
-
children: root.children.flatMap((item, position) => position !== index ? [item] : next ? [next] : []),
|
|
36
|
-
};
|
|
16
|
+
if (path.length === 0) {
|
|
17
|
+
if (replacement?.kind !== "group") throw new Error("Criteria root must remain a group");
|
|
18
|
+
return replacement;
|
|
19
|
+
}
|
|
20
|
+
const [index, ...rest] = path;
|
|
21
|
+
const child = root.children[index];
|
|
22
|
+
if (!child) throw new Error("Invalid criteria path");
|
|
23
|
+
if (rest.length && child.kind !== "group") throw new Error("Invalid criteria path");
|
|
24
|
+
const next = rest.length && child.kind === "group" ? replaceCriteria(child, rest, replacement) : replacement;
|
|
25
|
+
return {
|
|
26
|
+
...root,
|
|
27
|
+
children: root.children.flatMap((item, position) => position !== index ? [item] : next ? [next] : [])
|
|
28
|
+
};
|
|
37
29
|
}
|
|
38
30
|
export function describeCriteria(node, fields) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
31
|
+
if (node.kind === "group") {
|
|
32
|
+
if (!node.children.length) return "Sin condiciones";
|
|
33
|
+
const join = {
|
|
34
|
+
all: "Todas",
|
|
35
|
+
any: "Cualquiera",
|
|
36
|
+
none: "Ninguna"
|
|
37
|
+
}[node.join];
|
|
38
|
+
return `${join}: (${node.children.map(child => describeCriteria(child, fields)).join("; ")})`;
|
|
39
|
+
}
|
|
40
|
+
const field = fields.find(item => item.id === node.field);
|
|
41
|
+
const operator = field?.operators.find(item => item.id === node.operator);
|
|
42
|
+
const values = node.values.map(value => field?.options?.find(option => option.value === value)?.label ?? String(value));
|
|
43
|
+
return `${field?.label ?? node.field} ${operator?.label ?? node.operator}${values.length ? ` ${values.join(" — ")}` : ""}`;
|
|
49
44
|
}
|
|
50
45
|
export function validateCondition(condition, fields) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (operator.arity === "range" &&
|
|
71
|
-
field.type === "number" &&
|
|
72
|
-
Number(condition.values[0]) > Number(condition.values[1]))
|
|
73
|
-
return "El inicio no puede superar el final.";
|
|
74
|
-
if (operator.arity === "range" &&
|
|
75
|
-
field.type === "date" &&
|
|
76
|
-
String(condition.values[0]) > String(condition.values[1]))
|
|
77
|
-
return "El inicio no puede superar el final.";
|
|
78
|
-
return undefined;
|
|
46
|
+
const field = fields.find(item => item.id === condition.field);
|
|
47
|
+
if (!field) return "El campo ya no está disponible.";
|
|
48
|
+
const operator = field.operators.find(item => item.id === condition.operator);
|
|
49
|
+
if (!operator) return "El operador no está disponible para este campo.";
|
|
50
|
+
const count = {
|
|
51
|
+
none: 0,
|
|
52
|
+
one: 1,
|
|
53
|
+
range: 2
|
|
54
|
+
}[operator.arity];
|
|
55
|
+
if (condition.values.length !== count) return "Completa los valores de la condición.";
|
|
56
|
+
for (const value of condition.values) {
|
|
57
|
+
if (field.type === "number" && (typeof value !== "number" || !Number.isFinite(value))) return "Introduce un número válido.";
|
|
58
|
+
if (field.type === "text" && (typeof value !== "string" || !value.trim())) return "Introduce un texto.";
|
|
59
|
+
if (field.type === "date" && !parseCriteriaDate(value)) return "Introduce una fecha válida (AAAA-MM-DD).";
|
|
60
|
+
if (field.type === "choice" && !field.options?.some(option => option.value === value)) return "Selecciona un valor disponible.";
|
|
61
|
+
}
|
|
62
|
+
if (operator.arity === "range" && field.type === "number" && Number(condition.values[0]) > Number(condition.values[1])) return "El inicio no puede superar el final.";
|
|
63
|
+
if (operator.arity === "range" && field.type === "date" && String(condition.values[0]) > String(condition.values[1])) return "El inicio no puede superar el final.";
|
|
64
|
+
return undefined;
|
|
79
65
|
}
|
|
80
66
|
export function validateCriteria(group, fields) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (error)
|
|
88
|
-
return error;
|
|
89
|
-
}
|
|
90
|
-
return undefined;
|
|
67
|
+
for (const child of group.children) {
|
|
68
|
+
if (child.kind === "group" && !child.children.length) return "Completa o elimina el grupo vacío.";
|
|
69
|
+
const error = child.kind === "group" ? validateCriteria(child, fields) : validateCondition(child, fields);
|
|
70
|
+
if (error) return error;
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
91
73
|
}
|
|
92
74
|
export function moveCollectionEntry(items, index, direction) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return next;
|
|
75
|
+
const target = index + direction;
|
|
76
|
+
if (index < 0 || index >= items.length || target < 0 || target >= items.length) throw new Error("Invalid collection reorder");
|
|
77
|
+
const next = [...items];
|
|
78
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
79
|
+
return next;
|
|
99
80
|
}
|
package/dist/utils/date.d.ts
CHANGED
|
@@ -2,14 +2,20 @@ interface FormatDateOptions {
|
|
|
2
2
|
locale?: string | null;
|
|
3
3
|
showTime?: boolean;
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Reads ISO strings, SQLite `YYYY-MM-DD HH:mm:ss` and Date instances as one instant.
|
|
7
|
+
* A timestamp without a zone is UTC. A date-only value is UTC midnight.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseInstant(input: string | Date): Date | null;
|
|
5
10
|
/**
|
|
6
11
|
* Formats a date in the given timezone, respecting the granularity of the input.
|
|
7
12
|
*
|
|
8
13
|
* Detection rules:
|
|
9
14
|
* 1. If `input` is a 'YYYY-MM-DD' string (date only) => interpreted as midnight (00:00:00)
|
|
10
15
|
* in the target timezone and ONLY the date part is returned (no time).
|
|
11
|
-
* 2. If `input` includes a time component (
|
|
12
|
-
*
|
|
16
|
+
* 2. If `input` includes a time component (ISO, `YYYY-MM-DD HH:mm:ss`, or Date) => that
|
|
17
|
+
* instant is formatted in the target timezone as date + time (HH:MM) unless overridden
|
|
18
|
+
* via `options.showTime`. A value without a zone is read as UTC.
|
|
13
19
|
* 3. When `options.showTime` is `true` or `false` it overrides the auto-detection.
|
|
14
20
|
* 4. If `timezone` is null/undefined or invalid, the string "Error de formateo" is returned.
|
|
15
21
|
*
|
package/dist/utils/date.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { dateTimeFormat } from "./intl.js";
|
|
1
2
|
import dayjs from "dayjs";
|
|
2
3
|
import timezone from "dayjs/plugin/timezone";
|
|
3
4
|
import utc from "dayjs/plugin/utc";
|
|
@@ -6,14 +7,31 @@ const DEFAULT_TIMEZONE = "America/Costa_Rica";
|
|
|
6
7
|
const DEFAULT_LOCALE = "es-CR";
|
|
7
8
|
dayjs.extend(utc);
|
|
8
9
|
dayjs.extend(timezone);
|
|
10
|
+
/**
|
|
11
|
+
* Reads ISO strings, SQLite `YYYY-MM-DD HH:mm:ss` and Date instances as one instant.
|
|
12
|
+
* A timestamp without a zone is UTC. A date-only value is UTC midnight.
|
|
13
|
+
*/
|
|
14
|
+
export function parseInstant(input) {
|
|
15
|
+
if (input instanceof Date) {
|
|
16
|
+
return Number.isNaN(input.getTime()) ? null : input;
|
|
17
|
+
}
|
|
18
|
+
const trimmed = input.trim();
|
|
19
|
+
if (!trimmed) return null;
|
|
20
|
+
const withT = trimmed.replace(/^(\d{4}-\d{2}-\d{2}) /, "$1T");
|
|
21
|
+
const zoned = /(?:Z|[+-]\d{2}:?\d{2})$/.test(withT);
|
|
22
|
+
const parsed = new Date(zoned || !withT.includes("T") ? withT : `${withT}Z`);
|
|
23
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed;
|
|
24
|
+
}
|
|
25
|
+
|
|
9
26
|
/**
|
|
10
27
|
* Formats a date in the given timezone, respecting the granularity of the input.
|
|
11
28
|
*
|
|
12
29
|
* Detection rules:
|
|
13
30
|
* 1. If `input` is a 'YYYY-MM-DD' string (date only) => interpreted as midnight (00:00:00)
|
|
14
31
|
* in the target timezone and ONLY the date part is returned (no time).
|
|
15
|
-
* 2. If `input` includes a time component (
|
|
16
|
-
*
|
|
32
|
+
* 2. If `input` includes a time component (ISO, `YYYY-MM-DD HH:mm:ss`, or Date) => that
|
|
33
|
+
* instant is formatted in the target timezone as date + time (HH:MM) unless overridden
|
|
34
|
+
* via `options.showTime`. A value without a zone is read as UTC.
|
|
17
35
|
* 3. When `options.showTime` is `true` or `false` it overrides the auto-detection.
|
|
18
36
|
* 4. If `timezone` is null/undefined or invalid, the string "Error de formateo" is returned.
|
|
19
37
|
*
|
|
@@ -46,39 +64,34 @@ dayjs.extend(timezone);
|
|
|
46
64
|
* @returns Localized string, or "Error de formateo" if it can't be processed
|
|
47
65
|
*/
|
|
48
66
|
export function formatDate(input, timezone, options) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
};
|
|
71
|
-
if (effectiveShowTime) {
|
|
72
|
-
formatOptions.hour = "2-digit";
|
|
73
|
-
formatOptions.minute = "2-digit";
|
|
74
|
-
}
|
|
75
|
-
return new Intl.DateTimeFormat(usedLocale, formatOptions).format(dateInZone);
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
console.warn("Error formatting date:", error);
|
|
79
|
-
return "Error de formateo";
|
|
67
|
+
// Use the default timezone when none is provided
|
|
68
|
+
const effectiveTimezone = timezone || DEFAULT_TIMEZONE;
|
|
69
|
+
const fallbackLocale = DEFAULT_LOCALE.split("-")[0]; // "es" from "es-CR"
|
|
70
|
+
const deviceLocale = getLocales()?.[0]?.languageTag ?? fallbackLocale;
|
|
71
|
+
const usedLocale = options?.locale ?? deviceLocale;
|
|
72
|
+
const raw = typeof input === "string" ? input.trim() : input.toISOString();
|
|
73
|
+
const normalized = raw.replace(/^(\d{4}-\d{2}-\d{2}) /, "$1T");
|
|
74
|
+
const isDateOnly = /^\d{4}-\d{2}-\d{2}$/.test(normalized);
|
|
75
|
+
const effectiveShowTime = options?.showTime !== undefined ? options.showTime : !isDateOnly && /T\d{2}:\d{2}/.test(normalized);
|
|
76
|
+
try {
|
|
77
|
+
const date = isDateOnly ? dayjs.tz(`${normalized}T00:00:00`, effectiveTimezone).toDate() : parseInstant(input);
|
|
78
|
+
if (!date || Number.isNaN(date.getTime())) return "Error de formateo";
|
|
79
|
+
const formatOptions = {
|
|
80
|
+
year: "numeric",
|
|
81
|
+
month: "long",
|
|
82
|
+
day: "numeric",
|
|
83
|
+
timeZone: effectiveTimezone
|
|
84
|
+
};
|
|
85
|
+
if (effectiveShowTime) {
|
|
86
|
+
formatOptions.hour = "2-digit";
|
|
87
|
+
formatOptions.minute = "2-digit";
|
|
80
88
|
}
|
|
89
|
+
return dateTimeFormat(usedLocale, formatOptions).format(date);
|
|
90
|
+
} catch {
|
|
91
|
+
return "Error de formateo";
|
|
92
|
+
}
|
|
81
93
|
}
|
|
94
|
+
|
|
82
95
|
/**
|
|
83
96
|
* Formats a date using the default timezone automatically (Costa Rica).
|
|
84
97
|
* Useful when the user's timezone isn't available.
|
|
@@ -88,8 +101,9 @@ export function formatDate(input, timezone, options) {
|
|
|
88
101
|
* @returns Localized string in the Costa Rica timezone
|
|
89
102
|
*/
|
|
90
103
|
export function formatDateWithDefaultTimezone(input, options) {
|
|
91
|
-
|
|
104
|
+
return formatDate(input, DEFAULT_TIMEZONE, options);
|
|
92
105
|
}
|
|
106
|
+
|
|
93
107
|
/**
|
|
94
108
|
* Returns the current date as YYYY-MM-DD in the given timezone.
|
|
95
109
|
* Useful to build scheduling dates that respect the user's timezone.
|
|
@@ -98,15 +112,15 @@ export function formatDateWithDefaultTimezone(input, options) {
|
|
|
98
112
|
* @returns Current date as YYYY-MM-DD in the given timezone
|
|
99
113
|
*/
|
|
100
114
|
export function getCurrentDateInTimezone(timezone) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
115
|
+
const effectiveTimezone = timezone || DEFAULT_TIMEZONE;
|
|
116
|
+
try {
|
|
117
|
+
return dayjs().tz(effectiveTimezone).format("YYYY-MM-DD");
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.warn("Error getting current date in timezone:", error);
|
|
120
|
+
return dayjs().format("YYYY-MM-DD"); // Fallback to local
|
|
121
|
+
}
|
|
109
122
|
}
|
|
123
|
+
|
|
110
124
|
/**
|
|
111
125
|
* Returns the current date-time as an ISO string in the given timezone.
|
|
112
126
|
* Useful for timestamps that need to reflect the user's timezone.
|
|
@@ -115,12 +129,11 @@ export function getCurrentDateInTimezone(timezone) {
|
|
|
115
129
|
* @returns Current date-time as an ISO string in the given timezone
|
|
116
130
|
*/
|
|
117
131
|
export function getCurrentDateTimeInTimezone(timezone) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
132
|
+
const effectiveTimezone = timezone || DEFAULT_TIMEZONE;
|
|
133
|
+
try {
|
|
134
|
+
return dayjs().tz(effectiveTimezone).toISOString();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.warn("Error getting current date-time in timezone:", error);
|
|
137
|
+
return dayjs().toISOString(); // Fallback to local
|
|
138
|
+
}
|
|
126
139
|
}
|
package/dist/utils/image.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const sharedSourceKeys = new WeakMap();
|
|
2
2
|
let nextSharedSourceKey = 0;
|
|
3
3
|
export function imageSourceKey(source) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
return `shared-image-${key}`;
|
|
4
|
+
if (source && typeof source === "object" && "nativeRefType" in source) {
|
|
5
|
+
let key = sharedSourceKeys.get(source);
|
|
6
|
+
if (key === undefined) {
|
|
7
|
+
key = nextSharedSourceKey++;
|
|
8
|
+
sharedSourceKeys.set(source, key);
|
|
11
9
|
}
|
|
12
|
-
return
|
|
10
|
+
return `shared-image-${key}`;
|
|
11
|
+
}
|
|
12
|
+
return JSON.stringify(source);
|
|
13
13
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function dateTimeFormat(locale: string | undefined, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Building an Intl formatter resolves locale and time-zone data, which is the slow
|
|
2
|
+
// part; format() on an existing one is cheap. Lists format the same few shapes
|
|
3
|
+
// over and over, so formatters are shared per locale and options.
|
|
4
|
+
const dateFormats = new Map();
|
|
5
|
+
export function dateTimeFormat(locale, options) {
|
|
6
|
+
const key = `${locale ?? ""}|${JSON.stringify(options)}`;
|
|
7
|
+
let format = dateFormats.get(key);
|
|
8
|
+
if (!format) {
|
|
9
|
+
format = new Intl.DateTimeFormat(locale, options);
|
|
10
|
+
dateFormats.set(key, format);
|
|
11
|
+
}
|
|
12
|
+
return format;
|
|
13
|
+
}
|
package/dist/utils/keys.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
export function uniqueKeys(items, keyExtractor, component) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
throw new Error(`${component} requires unique, non-empty string keys.`);
|
|
6
|
-
return keys;
|
|
2
|
+
const keys = items.map(keyExtractor);
|
|
3
|
+
if (keys.some(key => typeof key !== "string" || !key.trim()) || new Set(keys).size !== keys.length) throw new Error(`${component} requires unique, non-empty string keys.`);
|
|
4
|
+
return keys;
|
|
7
5
|
}
|
package/dist/utils/monetary.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare function parseToMonetaryNumber(input?: string | number | null): number;
|
|
2
|
+
/** `1234.5` → `"1.234,50"`. Rounds half-up in decimal (Big), not in binary floating point. */
|
|
2
3
|
export declare function formatTwoDecimals(value?: number | string | null): string;
|
|
3
4
|
export declare function calculateDiscountedTotal(total: number, discount: number): number;
|
package/dist/utils/monetary.js
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
import { Big } from "big.js";
|
|
2
2
|
export function parseToMonetaryNumber(input) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
3
|
+
if (input == null) return 0;
|
|
4
|
+
// A finite number is already a number: skip the string round trip, which also
|
|
5
|
+
// misread exponent forms (1e21 → "121").
|
|
6
|
+
if (typeof input === "number") return Number.isFinite(input) ? input : 0;
|
|
7
|
+
const s = String(input).trim();
|
|
8
|
+
if (!/[0-9]/.test(s)) return 0;
|
|
9
|
+
const cleaned = s.replace(/[^0-9.-]+/g, "");
|
|
10
|
+
try {
|
|
11
|
+
return Number(new Big(cleaned).toString());
|
|
12
|
+
} catch {
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
// Building an Intl formatter is the expensive part (locale data lookup); format()
|
|
18
|
+
// is cheap. One shared instance for every amount the app renders.
|
|
19
|
+
const TWO_DECIMALS = new Intl.NumberFormat("de-DE", {
|
|
20
|
+
minimumFractionDigits: 2,
|
|
21
|
+
maximumFractionDigits: 2
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/** `1234.5` → `"1.234,50"`. Rounds half-up in decimal (Big), not in binary floating point. */
|
|
16
25
|
export function formatTwoDecimals(value) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const num = Number(rounded);
|
|
20
|
-
return new Intl.NumberFormat("de-DE", {
|
|
21
|
-
minimumFractionDigits: 2,
|
|
22
|
-
maximumFractionDigits: 2,
|
|
23
|
-
}).format(num);
|
|
26
|
+
const rounded = new Big(parseToMonetaryNumber(value)).toFixed(2);
|
|
27
|
+
return TWO_DECIMALS.format(Number(rounded));
|
|
24
28
|
}
|
|
25
29
|
export function calculateDiscountedTotal(total, discount) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
if (discount === 0) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
const result = parseToMonetaryNumber(total) * discount / 100;
|
|
34
|
+
return parseToMonetaryNumber(result);
|
|
31
35
|
}
|
package/dist/utils/progress.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export function normalizeProgress(value) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
return Math.max(0, Math.min(1, value));
|
|
2
|
+
if (!Number.isFinite(value)) throw new RangeError("Progress value must be a finite number");
|
|
3
|
+
return Math.max(0, Math.min(1, value));
|
|
5
4
|
}
|
package/dist/utils/quantity.js
CHANGED
|
@@ -1,44 +1,43 @@
|
|
|
1
1
|
import { Big } from "big.js";
|
|
2
|
+
|
|
2
3
|
/** Redondea a la precisión indicada usando round half up */
|
|
3
4
|
export function roundTo(value, precision) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
return Number(new Big(value).times(factor).round(0, 1).div(factor).toString());
|
|
5
|
+
if (isNaN(value)) return 0;
|
|
6
|
+
const factor = new Big(10).pow(precision);
|
|
7
|
+
return Number(new Big(value).times(factor).round(0, 1).div(factor).toString());
|
|
8
8
|
}
|
|
9
|
+
|
|
9
10
|
/** Normaliza la cantidad al múltiplo más cercano del incremento mínimo */
|
|
10
11
|
export function normalizeQuantity(value, minIncrement, precision) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const steps = Math.round(value / minIncrement);
|
|
18
|
-
const normalized = steps * minIncrement;
|
|
19
|
-
return roundTo(normalized, precision);
|
|
12
|
+
if (!isFinite(value)) return 0;
|
|
13
|
+
if (value < 0) value = 0;
|
|
14
|
+
if (minIncrement <= 0) return roundTo(value, precision);
|
|
15
|
+
const steps = Math.round(value / minIncrement);
|
|
16
|
+
const normalized = steps * minIncrement;
|
|
17
|
+
return roundTo(normalized, precision);
|
|
20
18
|
}
|
|
19
|
+
|
|
21
20
|
/** Convierte un valor a entero escalado según precisión para cálculos seguros */
|
|
22
21
|
export function toScaledInt(value, precision) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return Math.round(value * factor);
|
|
22
|
+
if (!isFinite(value)) return 0;
|
|
23
|
+
const factor = Math.pow(10, precision);
|
|
24
|
+
return Math.round(value * factor);
|
|
27
25
|
}
|
|
28
26
|
export function fromScaledInt(scaled, precision) {
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
const factor = Math.pow(10, precision);
|
|
28
|
+
return scaled / factor;
|
|
31
29
|
}
|
|
30
|
+
|
|
32
31
|
/** Multiplicación segura evitando errores binarios típicos */
|
|
33
32
|
export function safeMul(a, b, precision) {
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
const factor = Math.pow(10, precision);
|
|
34
|
+
return Math.round(a * factor) * Math.round(b * factor) / (factor * factor);
|
|
36
35
|
}
|
|
36
|
+
|
|
37
37
|
/** Valida si un valor es múltiplo del incremento mínimo dentro de la precisión */
|
|
38
38
|
export function isMultipleOfIncrement(value, minIncrement, precision) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return scaledValue % scaledInc === 0;
|
|
39
|
+
if (minIncrement <= 0) return true;
|
|
40
|
+
const scaledValue = toScaledInt(value, precision + 3); // extra precisión para reducir error
|
|
41
|
+
const scaledInc = toScaledInt(minIncrement, precision + 3);
|
|
42
|
+
return scaledValue % scaledInc === 0;
|
|
44
43
|
}
|
package/dist/utils/reorder.js
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
import { uniqueKeys } from "./keys.js";
|
|
2
2
|
export function reorderKeys(items, keyExtractor) {
|
|
3
|
-
|
|
3
|
+
return uniqueKeys(items, keyExtractor, "ReorderableList");
|
|
4
4
|
}
|
|
5
5
|
export function sameOrder(left, right) {
|
|
6
|
-
|
|
6
|
+
return left.length === right.length && left.every((key, index) => key === right[index]);
|
|
7
7
|
}
|
|
8
8
|
export function moveReorderItem(items, fromIndex, toIndex) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
toIndex >= items.length)
|
|
15
|
-
throw new Error("ReorderableList received an invalid move.");
|
|
16
|
-
const next = [...items];
|
|
17
|
-
const [item] = next.splice(fromIndex, 1);
|
|
18
|
-
next.splice(toIndex, 0, item);
|
|
19
|
-
return next;
|
|
9
|
+
if (!Number.isInteger(fromIndex) || !Number.isInteger(toIndex) || fromIndex < 0 || fromIndex >= items.length || toIndex < 0 || toIndex >= items.length) throw new Error("ReorderableList received an invalid move.");
|
|
10
|
+
const next = [...items];
|
|
11
|
+
const [item] = next.splice(fromIndex, 1);
|
|
12
|
+
next.splice(toIndex, 0, item);
|
|
13
|
+
return next;
|
|
20
14
|
}
|
|
21
15
|
export function applyReorder(items, keyExtractor, order) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
order.some((key) => !indices.has(key)))
|
|
27
|
-
throw new Error("ReorderableList received an order that does not match the current items.");
|
|
28
|
-
return order.map((key) => items[indices.get(key)]);
|
|
16
|
+
const keys = reorderKeys(items, keyExtractor);
|
|
17
|
+
const indices = new Map(keys.map((key, index) => [key, index]));
|
|
18
|
+
if (order.length !== keys.length || new Set(order).size !== order.length || order.some(key => !indices.has(key))) throw new Error("ReorderableList received an order that does not match the current items.");
|
|
19
|
+
return order.map(key => items[indices.get(key)]);
|
|
29
20
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Lowercase, no accents, single spaces: " Páez Núñez " -> "paez nunez". */
|
|
2
|
+
export declare function searchKey(text: string): string;
|
|
3
|
+
/** True when every word of the query appears in some field, ignoring accents and case. */
|
|
4
|
+
export declare function matchesSearch(query: string, ...fields: (string | null | undefined)[]): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Lowercase, no accents, single spaces: " Páez Núñez " -> "paez nunez". */
|
|
2
|
+
export function searchKey(text) {
|
|
3
|
+
return text.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/\s+/g, " ").trim();
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/** True when every word of the query appears in some field, ignoring accents and case. */
|
|
7
|
+
export function matchesSearch(query, ...fields) {
|
|
8
|
+
const words = searchKey(query).split(" ").filter(Boolean);
|
|
9
|
+
if (!words.length) return true;
|
|
10
|
+
const haystack = searchKey(fields.filter(Boolean).join(" "));
|
|
11
|
+
return words.every(word => haystack.includes(word));
|
|
12
|
+
}
|